modelRT/model/measurement_model.go

272 lines
7.8 KiB
Go
Raw Normal View History

2025-09-02 16:38:03 +08:00
// Package model define model struct of model runtime service
package model
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"modelRT/constants"
)
// MeasurementDataSource define measurement data source struct
type MeasurementDataSource struct {
Type int `json:"type"`
IOAddress IOAddress `json:"io_address"`
}
// IOAddress define interface of IO address
2025-11-10 17:32:18 +08:00
type IOAddress any
2025-09-02 16:38:03 +08:00
// CL3611Address define CL3611 protol struct
type CL3611Address struct {
Station string `json:"station"`
Device string `json:"device"`
Channel string `json:"channel"`
}
// Power104Address define electricity 104 protol struct
type Power104Address struct {
Station string `json:"station"`
Packet int `json:"packet"`
Offset int `json:"offset"`
}
// NewCL3611DataSource define func of create CL3611 data source
func NewCL3611DataSource(station, device, channel string) (*MeasurementDataSource, error) {
return &MeasurementDataSource{
Type: constants.DataSourceTypeCL3611,
IOAddress: CL3611Address{
Station: station,
Device: device,
Channel: channel,
},
}, nil
}
// NewPower104DataSource define func of create Power104 data source
func NewPower104DataSource(station string, packet, offset int) (*MeasurementDataSource, error) {
return &MeasurementDataSource{
Type: constants.DataSourceTypePower104,
IOAddress: Power104Address{
Station: station,
Packet: packet,
Offset: offset,
},
}, nil
}
func generateChannelName(prefix string, number int, suffix string) (string, error) {
switch prefix {
case constants.ChannelPrefixTelemetry:
if number > 10 {
return "", constants.ErrExceedsLimitType
}
var builder strings.Builder
numberStr := strconv.Itoa(number)
builder.Grow(len(prefix) + len(numberStr) + len(suffix))
builder.WriteString(prefix)
builder.WriteString(numberStr)
builder.WriteString(suffix)
channelName := builder.String()
return channelName, nil
case constants.ChannelPrefixTelesignal:
var numberStr string
if number < 10 {
numberStr = "0" + strconv.Itoa(number)
}
numberStr = strconv.Itoa(number)
var builder strings.Builder
builder.Grow(len(prefix) + len(numberStr) + len(suffix))
builder.WriteString(prefix)
builder.WriteString(numberStr)
builder.WriteString(suffix)
channelName := builder.String()
return channelName, nil
default:
return "", constants.ErrUnsupportedChannelPrefixType
}
}
// NewTelemetryChannel define func of generate telemetry channel CL3611 data source
func NewTelemetryChannel(station, device, channelNameSuffix string, channelNumber int) (*MeasurementDataSource, error) {
channelName, err := generateChannelName(constants.ChannelPrefixTelemetry, channelNumber, channelNameSuffix)
if err != nil {
return nil, fmt.Errorf("failed to generate channel name: %w", err)
}
return NewCL3611DataSource(station, device, channelName)
}
// NewTelesignalChannel define func of generate telesignal channel CL3611 data source
func NewTelesignalChannel(station, device, channelNameSuffix string, channelNumber int) (*MeasurementDataSource, error) {
channelName, err := generateChannelName(constants.ChannelPrefixTelesignal, channelNumber, channelNameSuffix)
if err != nil {
return nil, fmt.Errorf("failed to generate channel name: %w", err)
}
return NewCL3611DataSource(station, device, channelName)
}
// NewStandardChannel define func of generate standard channel CL3611 data source
func NewStandardChannel(station, device, channelType string) (*MeasurementDataSource, error) {
return NewCL3611DataSource(station, device, channelType)
}
// ParseDataSourceFromJSON define func of parse data source from json string
func ParseDataSourceFromJSON(jsonStr string) (MeasurementDataSource, error) {
var data struct {
Type int `json:"type"`
IOAddress json.RawMessage `json:"io_address"`
}
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
return MeasurementDataSource{}, err
}
var source MeasurementDataSource
source.Type = data.Type
switch data.Type {
case constants.DataSourceTypeCL3611:
var addr CL3611Address
if err := json.Unmarshal(data.IOAddress, &addr); err != nil {
return MeasurementDataSource{}, err
}
source.IOAddress = addr
case constants.DataSourceTypePower104:
var addr Power104Address
if err := json.Unmarshal(data.IOAddress, &addr); err != nil {
return MeasurementDataSource{}, err
}
source.IOAddress = addr
default:
// 对于未知类型保持原始JSON数据
source.IOAddress = data.IOAddress
}
return source, nil
}
// ToJSON define func of convert data source to json string
func (m MeasurementDataSource) ToJSON() (string, error) {
bytes, err := json.Marshal(m)
if err != nil {
return "", err
}
return string(bytes), nil
}
// GetIOAddress define func of get IO address with correct type
func (m MeasurementDataSource) GetIOAddress() (IOAddress, error) {
switch m.Type {
case constants.DataSourceTypeCL3611:
if addr, ok := m.IOAddress.(CL3611Address); ok {
return addr, nil
}
return nil, constants.ErrInvalidAddressType
case constants.DataSourceTypePower104:
if addr, ok := m.IOAddress.(Power104Address); ok {
return addr, nil
}
return nil, constants.ErrInvalidAddressType
default:
return nil, constants.ErrUnknownDataType
}
}
2025-11-10 17:32:18 +08:00
// GenerateMeasureIdentifier define func of generate measurement identifier
func GenerateMeasureIdentifier(source map[string]any) (string, error) {
regTypeVal, ok := source["type"]
if !ok {
return "", fmt.Errorf("can not find type in datasource field")
}
var regType int
switch v := regTypeVal.(type) {
case int:
regType = v
case float32:
if v != float32(int(v)) {
return "", fmt.Errorf("invalid type format in datasource field, expected integer value, got float: %f", v)
}
regType = int(v)
case float64:
if v != float64(int(v)) {
return "", fmt.Errorf("invalid type format in datasource field, expected integer value, got float: %f", v)
}
regType = int(v)
2025-11-10 17:32:18 +08:00
default:
return "", fmt.Errorf("invalid type format in datasource field,%T", v)
2025-11-10 17:32:18 +08:00
}
ioAddrVal, ok := source["io_address"]
if !ok {
return "", fmt.Errorf("can not find io_address from datasource field")
}
ioAddress, ok := ioAddrVal.(map[string]any)
if !ok {
return "", fmt.Errorf("io_address field is not a valid map")
}
switch regType {
case constants.DataSourceTypeCL3611:
station, ok := ioAddress["station"].(string)
if !ok {
return "", fmt.Errorf("CL3611:invalid or missing station field")
}
device, ok := ioAddress["device"].(string)
if !ok {
return "", fmt.Errorf("CL3611:invalid or missing device field")
}
// 提取 channel (string)
channel, ok := ioAddress["channel"].(string)
if !ok {
return "", fmt.Errorf("CL3611:invalid or missing channel field")
}
return concatCL361WithPlus(station, device, channel), nil
2025-11-10 17:32:18 +08:00
case constants.DataSourceTypePower104:
station, ok := ioAddress["station"].(string)
if !ok {
return "", fmt.Errorf("Power104:invalid or missing station field")
}
packetVal, ok := ioAddress["packet"]
if !ok {
return "", fmt.Errorf("Power104: missing packet field")
}
var packet int
switch v := packetVal.(type) {
case int:
packet = v
default:
return "", fmt.Errorf("Power104:invalid packet format")
}
offsetVal, ok := ioAddress["offset"]
if !ok {
return "", fmt.Errorf("Power104:missing offset field")
}
var offset int
switch v := offsetVal.(type) {
case int:
offset = v
default:
return "", fmt.Errorf("Power104:invalid offset format")
}
return concatP104WithPlus(station, packet, offset), nil
2025-11-10 17:32:18 +08:00
default:
return "", fmt.Errorf("unsupport regulation type %d into datasource field", regType)
}
}
func concatP104WithPlus(station string, packet int, offset int) string {
packetStr := strconv.Itoa(packet)
offsetStr := strconv.Itoa(offset)
return station + ":" + packetStr + ":" + offsetStr
}
func concatCL361WithPlus(station, device, channel string) string {
return station + ":" + device + ":" + "phasor" + ":" + channel
}