diff --git a/README.md b/README.md index a5c6b2f..f9b6f3e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ## Introduction -This library provides an implementation of SPINE 1.3 in [go](https://golang.org), which is part of the [EEBUS](https://eebus.org) specification. +This library provides an implementation of SPINE 1.4 in [go](https://golang.org), which is part of the [EEBUS](https://eebus.org) specification. Basic understanding of the EEBUS concepts SHIP and SPINE to use this library is required. Please check the corresponding specifications on the [EEBUS downloads website](https://www.eebus.org/media-downloads/). diff --git a/model/commandframe.go b/model/commandframe.go index 537e207..8fc3477 100644 --- a/model/commandframe.go +++ b/model/commandframe.go @@ -98,6 +98,7 @@ type FilterType struct { SupplyConditionDescriptionListDataSelectors *SupplyConditionDescriptionListDataSelectorsType `json:"supplyConditionDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:supplyConditionDescriptionListData"` SupplyConditionListDataSelectors *SupplyConditionListDataSelectorsType `json:"supplyConditionListDataSelectors,omitempty" eebus:"typ:selector,fct:supplyConditionListData"` SupplyConditionThresholdRelationListDataSelectors *SupplyConditionThresholdRelationListDataSelectorsType `json:"supplyConditionThresholdRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:supplyConditionThresholdRelationListData"` + SurrogateDescriptionListDataSelectors *SurrogateDescriptionListDataSelectorsType `json:"surrogateDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:surrogateDescriptionListData"` TariffBoundaryRelationListDataSelectors *TariffBoundaryRelationListDataSelectorsType `json:"tariffBoundaryRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:tariffBoundaryRelationListData"` TariffDescriptionListDataSelectors *TariffDescriptionListDataSelectorsType `json:"tariffDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:tariffDescriptionListData"` TariffListDataSelectors *TariffListDataSelectorsType `json:"tariffListDataSelectors,omitempty" eebus:"typ:selector,fct:tariffListData"` @@ -235,6 +236,7 @@ type FilterType struct { SupplyConditionDataElements *SupplyConditionDataElementsType `json:"supplyConditionDataElements,omitempty" eebus:"typ:elements,fct:supplyConditionListData"` SupplyConditionDescriptionDataElements *SupplyConditionDescriptionDataElementsType `json:"supplyConditionDescriptionDataElements,omitempty" eebus:"typ:elements,fct:supplyConditionDescriptionListData"` SupplyConditionThresholdRelationDataElements *SupplyConditionThresholdRelationDataElementsType `json:"supplyConditionThresholdRelationDataElements,omitempty" eebus:"typ:elements,fct:supplyConditionThresholdRelationListData"` + SurrogateDescriptionDataElements *SurrogateDescriptionDataElementsType `json:"surrogateDescriptionDataElements,omitempty" eebus:"typ:elements,fct:surrogateDescriptionListData"` TariffBoundaryRelationDataElements *TariffBoundaryRelationDataElementsType `json:"tariffBoundaryRelationDataElements,omitempty" eebus:"typ:elements,fct:tariffBoundaryRelationListData"` TariffDataElements *TariffDataElementsType `json:"tariffDataElements,omitempty" eebus:"typ:elements,fct:tariffListData"` TariffDescriptionDataElements *TariffDescriptionDataElementsType `json:"tariffDescriptionDataElements,omitempty" eebus:"typ:elements,fct:tariffDescriptionListData"` @@ -391,6 +393,7 @@ type CmdType struct { SupplyConditionDescriptionListData *SupplyConditionDescriptionListDataType `json:"supplyConditionDescriptionListData,omitempty" eebus:"fct:supplyConditionDescriptionListData"` SupplyConditionListData *SupplyConditionListDataType `json:"supplyConditionListData,omitempty" eebus:"fct:supplyConditionListData"` SupplyConditionThresholdRelationListData *SupplyConditionThresholdRelationListDataType `json:"supplyConditionThresholdRelationListData,omitempty" eebus:"fct:supplyConditionThresholdRelationListData"` + SurrogateDescriptionListData *SurrogateDescriptionListDataType `json:"surrogateDescriptionListData,omitempty" eebus:"fct:surrogateDescriptionListData"` TariffBoundaryRelationListData *TariffBoundaryRelationListDataType `json:"tariffBoundaryRelationListData,omitempty" eebus:"fct:tariffBoundaryRelationListData"` TariffDescriptionListData *TariffDescriptionListDataType `json:"tariffDescriptionListData,omitempty" eebus:"fct:tariffDescriptionListData"` TariffListData *TariffListDataType `json:"tariffListData,omitempty" eebus:"fct:tariffListData"` diff --git a/model/commondatatypes.go b/model/commondatatypes.go index 966c017..b8542ef 100644 --- a/model/commondatatypes.go +++ b/model/commondatatypes.go @@ -611,6 +611,11 @@ const ( ScopeTypeTypeIncentiveTableEnConsWithTF ScopeTypeType = "incentiveTableEnConsWithTF" ScopeTypeTypeIncentiveTableEnProdWithTF ScopeTypeType = "incentiveTableEnProdWithTF" ScopeTypeTypeActivePowerForecast ScopeTypeType = "activePowerForecast" + ScopeTypeTypeACEnergyPossibleConsumption ScopeTypeType = "acEnergyPossibleConsumption" + ScopeTypeTypeExtraPowerRequest ScopeTypeType = "extraPowerRequest" + ScopeTypeTypeTimeToMinimumSoC ScopeTypeType = "timeToMinimumSoC" + ScopeTypeTypeTimeToMaximumSoC ScopeTypeType = "timeToMaximumSoC" + ScopeTypeTypeTimeToTargetSoC ScopeTypeType = "timeToTargetSoC" ) type RoleType string @@ -693,6 +698,7 @@ const ( EntityTypeTypePVString EntityTypeType = "PVString" EntityTypeTypeGridGuard EntityTypeType = "GridGuard" EntityTypeTypeControllableSystem EntityTypeType = "ControllableSystem" + EntityTypeTypeSurrogate EntityTypeType = "Surrogate" ) type FeatureTypeType string @@ -730,6 +736,7 @@ const ( FeatureTypeTypeBill FeatureTypeType = "Bill" FeatureTypeTypeIdentification FeatureTypeType = "Identification" FeatureTypeTypeStateInformation FeatureTypeType = "StateInformation" + FeatureTypeTypeSurrogate FeatureTypeType = "Surrogate" ) type FeatureSpecificUsageType string @@ -901,6 +908,7 @@ const ( FunctionTypeSupplyConditionDescriptionListData FunctionType = "supplyConditionDescriptionListData" FunctionTypeSupplyConditionListData FunctionType = "supplyConditionListData" FunctionTypeSupplyConditionThresholdRelationListData FunctionType = "supplyConditionThresholdRelationListData" + FunctionTypeSurrogateDescriptionListData FunctionType = "surrogateDescriptionListData" FunctionTypeTaskManagementJobDescriptionListData FunctionType = "taskManagementJobDescriptionListData" FunctionTypeTaskManagementJobListData FunctionType = "taskManagementJobListData" FunctionTypeTaskManagementJobRelationListData FunctionType = "taskManagementJobRelationListData" diff --git a/model/deviceconfiguration.go b/model/deviceconfiguration.go index 2da9d70..40780f5 100644 --- a/model/deviceconfiguration.go +++ b/model/deviceconfiguration.go @@ -50,6 +50,16 @@ const ( DeviceConfigurationKeyNameTypeIncentivesSimulationConcurrent DeviceConfigurationKeyNameType = "incentivesSimulationConcurrent" DeviceConfigurationKeyNameTypeIncentivesTimeoutIncentiveRequest DeviceConfigurationKeyNameType = "incentivesTimeoutIncentiveRequest" DeviceConfigurationKeyNameTypeIncentivesWaitIncentiveWriteable DeviceConfigurationKeyNameType = "incentivesWaitIncentiveWriteable" + DeviceConfigurationKeyNameTypePowerSetpointDeviation DeviceConfigurationKeyNameType = "powerSetpointDeviation" + DeviceConfigurationKeyNameTypePowerSetpointDeviationTypes DeviceConfigurationKeyNameType = "powerSetpointDeviationTypes" + DeviceConfigurationKeyNameTypeRemainingExtraPowerRequests DeviceConfigurationKeyNameType = "remainingExtraPowerRequests" + DeviceConfigurationKeyNameTypePvChargeMode DeviceConfigurationKeyNameType = "pvChargeMode" + DeviceConfigurationKeyNameTypeSurplusWithThresholdValue DeviceConfigurationKeyNameType = "surplusWithThresholdValue" + DeviceConfigurationKeyNameTypeStartDelay DeviceConfigurationKeyNameType = "startDelay" + DeviceConfigurationKeyNameTypeStopDelay DeviceConfigurationKeyNameType = "stopDelay" + DeviceConfigurationKeyNameTypeMinimumStateOfCharge DeviceConfigurationKeyNameType = "minimumStateOfCharge" + DeviceConfigurationKeyNameTypeTargetStateOfCharge DeviceConfigurationKeyNameType = "targetStateOfCharge" + DeviceConfigurationKeyNameTypePhaseRotation DeviceConfigurationKeyNameType = "phaseRotation" ) type DeviceConfigurationKeyValueTypeType string diff --git a/model/identification.go b/model/identification.go index 6e84329..817d684 100644 --- a/model/identification.go +++ b/model/identification.go @@ -8,6 +8,8 @@ const ( IdentificationTypeTypeEui48 IdentificationTypeType = "eui48" IdentificationTypeTypeEui64 IdentificationTypeType = "eui64" IdentificationTypeTypeUserrfidtag IdentificationTypeType = "userRfidTag" + IdentificationTypeTypePcId IdentificationTypeType = "pcid" + IdentificationTypeTypeEmaId IdentificationTypeType = "emaid" ) type IdentificationValueType string diff --git a/model/setpoint.go b/model/setpoint.go index 5650f9f..d57af47 100644 --- a/model/setpoint.go +++ b/model/setpoint.go @@ -9,6 +9,14 @@ const ( SetpointTypeTypeValueRelative SetpointTypeType = "valueRelative" ) +type SetpointValuesType struct { + Value []ScaledNumberType `json:"value,omitempty"` +} + +type SetpointValuesElementsType struct { + Value []ScaledNumberElementsType `json:"value,omitempty"` +} + type SetpointDataType struct { SetpointId *SetpointIdType `json:"setpointId,omitempty" eebus:"key"` Value *ScaledNumberType `json:"value,omitempty"` @@ -42,17 +50,19 @@ type SetpointListDataSelectorsType struct { } type SetpointConstraintsDataType struct { - SetpointId *SetpointIdType `json:"setpointId,omitempty" eebus:"key"` - SetpointRangeMin *ScaledNumberType `json:"setpointRangeMin,omitempty"` - SetpointRangeMax *ScaledNumberType `json:"setpointRangeMax,omitempty"` - SetpointStepSize *ScaledNumberType `json:"setpointStepSize,omitempty"` + SetpointId *SetpointIdType `json:"setpointId,omitempty" eebus:"key"` + SetpointRangeMin *ScaledNumberType `json:"setpointRangeMin,omitempty"` + SetpointRangeMax *ScaledNumberType `json:"setpointRangeMax,omitempty"` + SetpointStepSize *ScaledNumberType `json:"setpointStepSize,omitempty"` + SetpointValues *SetpointValuesType `json:"setpointValues,omitempty"` } type SetpointConstraintsDataElementsType struct { - SetpointId *ElementTagType `json:"setpointId,omitempty"` - SetpointRangeMin *ScaledNumberElementsType `json:"setpointRangeMin,omitempty"` - SetpointRangeMax *ScaledNumberElementsType `json:"setpointRangeMax,omitempty"` - SetpointStepSize *ScaledNumberElementsType `json:"setpointStepSize,omitempty"` + SetpointId *ElementTagType `json:"setpointId,omitempty"` + SetpointRangeMin *ScaledNumberElementsType `json:"setpointRangeMin,omitempty"` + SetpointRangeMax *ScaledNumberElementsType `json:"setpointRangeMax,omitempty"` + SetpointStepSize *ScaledNumberElementsType `json:"setpointStepSize,omitempty"` + SetpointValues *SetpointValuesElementsType `json:"setpointValues,omitempty"` } type SetpointConstraintsListDataType struct { diff --git a/model/surrogate.go b/model/surrogate.go new file mode 100644 index 0000000..4cddc97 --- /dev/null +++ b/model/surrogate.go @@ -0,0 +1,50 @@ +package model + +type SurrogateIdType uint + +type SurrogateScopeEnumType string + +type SurrogateScopeType string + +type SurrogateOtherSourceType string + +type SurrogateSourcesType struct { + SpineSource []EntityAddressType `json:"spineSource,omitempty"` + OtherSource []SurrogateOtherSourceType `json:"otherSource,omitempty"` +} + +type SurrogateDescriptionDataType struct { + SurrogateId *SurrogateIdType `json:"surrogateId,omitempty" eebus:"key"` + SurrogateScope *SurrogateScopeType `json:"surrogateScope,omitempty"` + SurrogateSources *SurrogateSourcesType `json:"surrogateSources,omitempty"` + Label *LabelType `json:"label,omitempty"` + Description *DescriptionType `json:"description,omitempty"` +} + +type SurrogateSourcesElementsType struct { + SpineSource *EntityAddressElementsType `json:"spineSource,omitempty"` + OtherSource *ElementTagType `json:"otherSource,omitempty"` +} + +type SurrogateDescriptionDataElementsType struct { + SurrogateId *ElementTagType `json:"surrogateId,omitempty"` + SurrogateScope *ElementTagType `json:"surrogateScope,omitempty"` + SurrogateSources *SurrogateSourcesElementsType `json:"surrogateSources,omitempty"` + Label *ElementTagType `json:"label,omitempty"` + Description *ElementTagType `json:"description,omitempty"` +} + +type SurrogateDescriptionListDataType struct { + SurrogateDescriptionData []SurrogateDescriptionDataType `json:"surrogateDescriptionData,omitempty"` +} + +type SurrogateDescriptionListDataSelectorsSourcesType struct { + SpineSource *EntityAddressType `json:"spineSource,omitempty"` + OtherSource *string `json:"otherSource,omitempty"` +} + +type SurrogateDescriptionListDataSelectorsType struct { + SurrogateId *SurrogateIdType `json:"surrogateId,omitempty"` + SurrogateScope *SurrogateScopeType `json:"surrogateScope,omitempty"` + SurrogateSources *SurrogateDescriptionListDataSelectorsSourcesType `json:"surrogateSources,omitempty"` +} diff --git a/model/surrogate_additions.go b/model/surrogate_additions.go new file mode 100644 index 0000000..5f3fb32 --- /dev/null +++ b/model/surrogate_additions.go @@ -0,0 +1,20 @@ +package model + +// SurrogateDescriptionListDataType + +var _ Updater = (*SurrogateDescriptionListDataType)(nil) + +func (r *SurrogateDescriptionListDataType) UpdateList(remoteWrite, persist bool, newList any, filterPartial, filterDelete *FilterType) (any, bool) { + var newData []SurrogateDescriptionDataType + if newList != nil { + newData = newList.(*SurrogateDescriptionListDataType).SurrogateDescriptionData + } + + data, success := UpdateList(remoteWrite, r.SurrogateDescriptionData, newData, filterPartial, filterDelete) + + if success && persist { + r.SurrogateDescriptionData = data + } + + return data, success +} diff --git a/model/surrogate_additions_test.go b/model/surrogate_additions_test.go new file mode 100644 index 0000000..bfde38e --- /dev/null +++ b/model/surrogate_additions_test.go @@ -0,0 +1,47 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestSurrogateDescriptionListDataType_Update(t *testing.T) { + sut := SurrogateDescriptionListDataType{ + SurrogateDescriptionData: []SurrogateDescriptionDataType{ + { + SurrogateId: util.Ptr(SurrogateIdType(0)), + SurrogateScope: util.Ptr(SurrogateScopeType("old")), + }, + { + SurrogateId: util.Ptr(SurrogateIdType(1)), + SurrogateScope: util.Ptr(SurrogateScopeType("test")), + }, + }, + } + + newData := SurrogateDescriptionListDataType{ + SurrogateDescriptionData: []SurrogateDescriptionDataType{ + { + SurrogateId: util.Ptr(SurrogateIdType(1)), + SurrogateScope: util.Ptr(SurrogateScopeType("new")), + }, + }, + } + + // Act + _, success := sut.UpdateList(false, true, &newData, NewFilterTypePartial(), nil) + assert.True(t, success) + + data := sut.SurrogateDescriptionData + // check the non changing items + assert.Equal(t, 2, len(data)) + item1 := data[0] + assert.Equal(t, 0, int(*item1.SurrogateId)) + assert.Equal(t, "old", string(*item1.SurrogateScope)) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.SurrogateId)) + assert.Equal(t, "new", string(*item2.SurrogateScope)) +} diff --git a/model/timeseries.go b/model/timeseries.go index 91cae18..67fbb1d 100644 --- a/model/timeseries.go +++ b/model/timeseries.go @@ -9,13 +9,28 @@ type TimeSeriesSlotCountType TimeSeriesSlotIdType type TimeSeriesTypeType string const ( - TimeSeriesTypeTypePlan TimeSeriesTypeType = "plan" - TimeSeriesTypeTypeSingleDemand TimeSeriesTypeType = "singleDemand" - TimeSeriesTypeTypeConstraints TimeSeriesTypeType = "constraints" - TimeSeriesTypeTypeEnergyRequest TimeSeriesTypeType = "energyRequest" - TimeSeriesTypeTypeDischargingEnergyRequest TimeSeriesTypeType = "dischargingEnergyRequest" - TimeSeriesTypeTypeConsumptionLimitCurve TimeSeriesTypeType = "consumptionLimitCurve" - TimeSeriesTypeTypeProductionLimitCurve TimeSeriesTypeType = "productionLimitCurve" + TimeSeriesTypeTypePlan TimeSeriesTypeType = "plan" + TimeSeriesTypeTypeSingleDemand TimeSeriesTypeType = "singleDemand" + TimeSeriesTypeTypeConstraints TimeSeriesTypeType = "constraints" + TimeSeriesTypeTypeEnergyRequest TimeSeriesTypeType = "energyRequest" + TimeSeriesTypeTypeDischargingEnergyRequest TimeSeriesTypeType = "dischargingEnergyRequest" + TimeSeriesTypeTypeConsumptionLimitCurve TimeSeriesTypeType = "consumptionLimitCurve" + TimeSeriesTypeTypeProductionLimitCurve TimeSeriesTypeType = "productionLimitCurve" + TimeSeriesTypeTypeFallbackConsumptionLimitCurve TimeSeriesTypeType = "fallbackConsumptionLimitCurve" + TimeSeriesTypeTypeFallbackProductionLimitCurve TimeSeriesTypeType = "fallbackProductionLimitCurve" + TimeSeriesTypeTypePowerRequest TimeSeriesTypeType = "powerRequest" +) + +type TimeSeriesStateType string + +const ( + TimeSeriesStateTypeRequest TimeSeriesStateType = "request" + TimeSeriesStateTypeRequestAccepted TimeSeriesStateType = "requestAccepted" + TimeSeriesStateTypeRequestRejected TimeSeriesStateType = "requestRejected" + TimeSeriesStateTypeCancelRequest TimeSeriesStateType = "cancelRequest" + TimeSeriesStateTypeCancelRequestAccepted TimeSeriesStateType = "cancelRequestAccepted" + TimeSeriesStateTypeCancelRequestRejected TimeSeriesStateType = "cancelRequestRejected" + TimeSeriesStateTypeRequestCancelled TimeSeriesStateType = "requestCancelled" ) type TimeSeriesSlotType struct { @@ -39,15 +54,17 @@ type TimeSeriesSlotElementsType struct { } type TimeSeriesDataType struct { - TimeSeriesId *TimeSeriesIdType `json:"timeSeriesId,omitempty" eebus:"key"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - TimeSeriesSlot []TimeSeriesSlotType `json:"timeSeriesSlot"` + TimeSeriesId *TimeSeriesIdType `json:"timeSeriesId,omitempty" eebus:"key"` + TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` + TimeSeriesSlot []TimeSeriesSlotType `json:"timeSeriesSlot"` + TimeSeriesState *TimeSeriesStateType `json:"timeSeriesState,omitempty"` } type TimeSeriesDataElementsType struct { - TimeSeriesId *ElementTagType `json:"timeSeriesId,omitempty"` - TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` - TimeSeriesSlot *TimeSeriesSlotElementsType `json:"timeSeriesSlot"` + TimeSeriesId *ElementTagType `json:"timeSeriesId,omitempty"` + TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` + TimeSeriesSlot *TimeSeriesSlotElementsType `json:"timeSeriesSlot"` + TimeSeriesState *ElementTagType `json:"timeSeriesState,omitempty"` } type TimeSeriesListDataType struct { diff --git a/spine/const.go b/spine/const.go index 9f527e3..ed03c60 100644 --- a/spine/const.go +++ b/spine/const.go @@ -2,4 +2,4 @@ package spine import "github.com/enbility/spine-go/model" -var SpecificationVersion model.SpecificationVersionType = "1.3.0" +var SpecificationVersion model.SpecificationVersionType = "1.4.0" diff --git a/spine/device_local_test.go b/spine/device_local_test.go index 397ad50..45806c8 100644 --- a/spine/device_local_test.go +++ b/spine/device_local_test.go @@ -108,9 +108,10 @@ func (d *DeviceLocalTestSuite) Test_RemoteDevice() { f.AddFunctionType(model.FunctionTypeLoadControlLimitListData, true, true) newSubEntity.AddFeature(f) + specVersion := string(SpecificationVersion) sut.AddEntity(newSubEntity) // A notification should have been sent - expectedNotifyMsg := `{"datagram":{"header":{"specificationVersion":"1.3.0","addressSource":{"device":"address","entity":[0],"feature":0},"addressDestination":{"entity":[0],"feature":0},"msgCounter":2,"cmdClassifier":"notify"},"payload":{"cmd":[{"function":"nodeManagementDetailedDiscoveryData","filter":[{"cmdControl":{"partial":{}}}],"nodeManagementDetailedDiscoveryData":{"specificationVersionList":{"specificationVersion":["1.3.0"]},"deviceInformation":{"description":{"deviceAddress":{"device":"address"},"deviceType":"EnergyManagementSystem","networkFeatureSet":"smart"}},"entityInformation":[{"description":{"entityAddress":{"device":"address","entity":[1,1]},"entityType":"EV","lastStateChange":"added"}}],"featureInformation":[{"description":{"featureAddress":{"device":"address","entity":[1,1],"feature":1},"featureType":"LoadControl","role":"server","supportedFunction":[{"function":"loadControlLimitListData","possibleOperations":{"read":{},"write":{"partial":{}}}}]}}]}}]}}}` + expectedNotifyMsg := `{"datagram":{"header":{"specificationVersion":"` + specVersion + `","addressSource":{"device":"address","entity":[0],"feature":0},"addressDestination":{"entity":[0],"feature":0},"msgCounter":2,"cmdClassifier":"notify"},"payload":{"cmd":[{"function":"nodeManagementDetailedDiscoveryData","filter":[{"cmdControl":{"partial":{}}}],"nodeManagementDetailedDiscoveryData":{"specificationVersionList":{"specificationVersion":["` + specVersion + `"]},"deviceInformation":{"description":{"deviceAddress":{"device":"address"},"deviceType":"EnergyManagementSystem","networkFeatureSet":"smart"}},"entityInformation":[{"description":{"entityAddress":{"device":"address","entity":[1,1]},"entityType":"EV","lastStateChange":"added"}}],"featureInformation":[{"description":{"featureAddress":{"device":"address","entity":[1,1],"feature":1},"featureType":"LoadControl","role":"server","supportedFunction":[{"function":"loadControlLimitListData","possibleOperations":{"read":{},"write":{"partial":{}}}}]}}]}}]}}}` assert.Equal(d.T(), expectedNotifyMsg, d.lastMessage) entities = sut.Entities() @@ -118,7 +119,7 @@ func (d *DeviceLocalTestSuite) Test_RemoteDevice() { sut.RemoveEntity(newSubEntity) // A notification should have been sent - expectedNotifyMsg = `{"datagram":{"header":{"specificationVersion":"1.3.0","addressSource":{"device":"address","entity":[0],"feature":0},"addressDestination":{"entity":[0],"feature":0},"msgCounter":3,"cmdClassifier":"notify"},"payload":{"cmd":[{"function":"nodeManagementDetailedDiscoveryData","filter":[{"cmdControl":{"partial":{}}}],"nodeManagementDetailedDiscoveryData":{"specificationVersionList":{"specificationVersion":["1.3.0"]},"deviceInformation":{"description":{"deviceAddress":{"device":"address"},"deviceType":"EnergyManagementSystem","networkFeatureSet":"smart"}},"entityInformation":[{"description":{"entityAddress":{"device":"address","entity":[1,1]},"entityType":"EV","lastStateChange":"removed"}}]}}]}}}` + expectedNotifyMsg = `{"datagram":{"header":{"specificationVersion":"` + specVersion + `","addressSource":{"device":"address","entity":[0],"feature":0},"addressDestination":{"entity":[0],"feature":0},"msgCounter":3,"cmdClassifier":"notify"},"payload":{"cmd":[{"function":"nodeManagementDetailedDiscoveryData","filter":[{"cmdControl":{"partial":{}}}],"nodeManagementDetailedDiscoveryData":{"specificationVersionList":{"specificationVersion":["` + specVersion + `"]},"deviceInformation":{"description":{"deviceAddress":{"device":"address"},"deviceType":"EnergyManagementSystem","networkFeatureSet":"smart"}},"entityInformation":[{"description":{"entityAddress":{"device":"address","entity":[1,1]},"entityType":"EV","lastStateChange":"removed"}}]}}]}}}` assert.Equal(d.T(), expectedNotifyMsg, d.lastMessage) entities = sut.Entities() @@ -126,7 +127,7 @@ func (d *DeviceLocalTestSuite) Test_RemoteDevice() { sut.RemoveEntity(entity1) // A notification should have been sent - expectedNotifyMsg = `{"datagram":{"header":{"specificationVersion":"1.3.0","addressSource":{"device":"address","entity":[0],"feature":0},"addressDestination":{"entity":[0],"feature":0},"msgCounter":4,"cmdClassifier":"notify"},"payload":{"cmd":[{"function":"nodeManagementDetailedDiscoveryData","filter":[{"cmdControl":{"partial":{}}}],"nodeManagementDetailedDiscoveryData":{"specificationVersionList":{"specificationVersion":["1.3.0"]},"deviceInformation":{"description":{"deviceAddress":{"device":"address"},"deviceType":"EnergyManagementSystem","networkFeatureSet":"smart"}},"entityInformation":[{"description":{"entityAddress":{"device":"address","entity":[1]},"entityType":"CEM","lastStateChange":"removed"}}]}}]}}}` + expectedNotifyMsg = `{"datagram":{"header":{"specificationVersion":"` + specVersion + `","addressSource":{"device":"address","entity":[0],"feature":0},"addressDestination":{"entity":[0],"feature":0},"msgCounter":4,"cmdClassifier":"notify"},"payload":{"cmd":[{"function":"nodeManagementDetailedDiscoveryData","filter":[{"cmdControl":{"partial":{}}}],"nodeManagementDetailedDiscoveryData":{"specificationVersionList":{"specificationVersion":["` + specVersion + `"]},"deviceInformation":{"description":{"deviceAddress":{"device":"address"},"deviceType":"EnergyManagementSystem","networkFeatureSet":"smart"}},"entityInformation":[{"description":{"entityAddress":{"device":"address","entity":[1]},"entityType":"CEM","lastStateChange":"removed"}}]}}]}}}` assert.Equal(d.T(), expectedNotifyMsg, d.lastMessage) entities = sut.Entities() diff --git a/spine/function_data_factory.go b/spine/function_data_factory.go index 01c5330..029246b 100644 --- a/spine/function_data_factory.go +++ b/spine/function_data_factory.go @@ -240,6 +240,12 @@ func CreateFunctionData[F any](featureType model.FeatureTypeType) []F { }...) } + if featureType == model.FeatureTypeTypeSurrogate || featureType == model.FeatureTypeTypeGeneric { + result = append(result, []F{ + createFunctionData[model.SurrogateDescriptionListDataType, F](model.FunctionTypeSurrogateDescriptionListData), + }...) + } + if featureType == model.FeatureTypeTypeTariffInformation || featureType == model.FeatureTypeTypeGeneric { result = append(result, []F{ createFunctionData[model.IncentiveDescriptionListDataType, F](model.FunctionTypeIncentiveDescriptionListData), diff --git a/spine/function_data_factory_test.go b/spine/function_data_factory_test.go index ef9f67a..8306e20 100644 --- a/spine/function_data_factory_test.go +++ b/spine/function_data_factory_test.go @@ -76,7 +76,7 @@ func TestFunctionDataFactory_FunctionData(t *testing.T) { assert.IsType(t, &FunctionData[model.TimeSeriesListDataType]{}, result[2]) result = CreateFunctionData[api.FunctionDataInterface](model.FeatureTypeTypeGeneric) - assert.Equal(t, 124, len(result)) + assert.Equal(t, 125, len(result)) } func TestFunctionDataFactory_FunctionDataCmd(t *testing.T) { diff --git a/spine/testdata/nm_destinationListData_send_reply_expected.json b/spine/testdata/nm_destinationListData_send_reply_expected.json index f5c89a4..05e8c0e 100644 --- a/spine/testdata/nm_destinationListData_send_reply_expected.json +++ b/spine/testdata/nm_destinationListData_send_reply_expected.json @@ -1,7 +1,7 @@ { "datagram": { "header": { - "specificationVersion": "1.3.0", + "specificationVersion": "1.4.0", "addressSource": { "device": "TestDeviceAddress", "entity": [ diff --git a/spine/testdata/nm_detaileddiscoverydata_send_read_expected.json b/spine/testdata/nm_detaileddiscoverydata_send_read_expected.json index 02d814c..8ee190c 100644 --- a/spine/testdata/nm_detaileddiscoverydata_send_read_expected.json +++ b/spine/testdata/nm_detaileddiscoverydata_send_read_expected.json @@ -1,7 +1,7 @@ { "datagram": { "header": { - "specificationVersion": "1.3.0", + "specificationVersion": "1.4.0", "addressSource": { "device": "TestDeviceAddress", "entity": [ diff --git a/spine/testdata/nm_detaileddiscoverydata_send_reply_expected.json b/spine/testdata/nm_detaileddiscoverydata_send_reply_expected.json index bc36322..2c53934 100644 --- a/spine/testdata/nm_detaileddiscoverydata_send_reply_expected.json +++ b/spine/testdata/nm_detaileddiscoverydata_send_reply_expected.json @@ -1,7 +1,7 @@ { "datagram": { "header": { - "specificationVersion": "1.3.0", + "specificationVersion": "1.4.0", "addressSource": { "device": "TestDeviceAddress", "entity": [ @@ -26,7 +26,7 @@ "nodeManagementDetailedDiscoveryData": { "specificationVersionList": { "specificationVersion": [ - "1.3.0" + "1.4.0" ] }, "deviceInformation": { diff --git a/spine/testdata/nm_subscriptionRequestCall_send_result_expected.json b/spine/testdata/nm_subscriptionRequestCall_send_result_expected.json index 9c369b6..7654cbe 100644 --- a/spine/testdata/nm_subscriptionRequestCall_send_result_expected.json +++ b/spine/testdata/nm_subscriptionRequestCall_send_result_expected.json @@ -1,7 +1,7 @@ { "datagram": { "header": { - "specificationVersion": "1.3.0", + "specificationVersion": "1.4.0", "addressSource": { "device": "TestDeviceAddress", "entity": [