// 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 type IOAddress any // 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 } } // 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) default: return "", fmt.Errorf("invalid type format in datasource field,%T", v) } 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 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 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 }