Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion features/internal/deviceconfiguration.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (d *DeviceConfigurationCommon) CheckEventPayloadDataForFilter(payloadData a

for _, item := range data.DeviceConfigurationKeyValueData {
if item.KeyId != nil &&
*item.KeyId == *desc.KeyId ||
*item.KeyId == *desc.KeyId &&
item.Value != nil {
return true
}
Expand Down
21 changes: 15 additions & 6 deletions usecases/eg/lpc/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ func (e *LPC) loadControlLimitDataUpdate(payload spineapi.EventPayload) {
LimitDirection: util.Ptr(model.EnergyDirectionTypeConsume),
ScopeType: util.Ptr(model.ScopeTypeTypeActivePowerLimit),
}
if lc.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateLimit)
if lc.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.ConsumptionLimit(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateLimit)
}
}
}
}
Expand All @@ -155,12 +158,18 @@ func (e *LPC) configurationDataUpdate(payload spineapi.EventPayload) {
filter := model.DeviceConfigurationKeyValueDescriptionDataType{
KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeFailsafeConsumptionActivePowerLimit),
}
if dc.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateFailsafeConsumptionActivePowerLimit)
if dc.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.FailsafeConsumptionActivePowerLimit(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateFailsafeConsumptionActivePowerLimit)
}
}
filter.KeyName = util.Ptr(model.DeviceConfigurationKeyNameTypeFailsafeDurationMinimum)
if dc.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateFailsafeDurationMinimum)
if dc.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.FailsafeDurationMinimum(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateFailsafeDurationMinimum)
}
}
}
}
37 changes: 29 additions & 8 deletions usecases/eg/lpc/events_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package lpc

import (
"time"

spineapi "github.com/enbility/spine-go/api"
"github.com/enbility/spine-go/model"
"github.com/enbility/spine-go/util"
Expand Down Expand Up @@ -124,14 +126,23 @@ func (s *EgLPCSuite) Test_loadControlLimitDataUpdate() {
data = &model.LoadControlLimitListDataType{
LoadControlLimitData: []model.LoadControlLimitDataType{
{
LimitId: util.Ptr(model.LoadControlLimitIdType(0)),
Value: model.NewScaledNumberType(16),
LimitId: util.Ptr(model.LoadControlLimitIdType(0)),
IsLimitChangeable: util.Ptr(true),
IsLimitActive: util.Ptr(false),
Value: model.NewScaledNumberType(6000),
TimePeriod: &model.TimePeriodType{
EndTime: model.NewAbsoluteOrRelativeTimeType("PT2H"),
},
},
},
}

payload.Data = data

// Update the feature with the data so it's actually stored
_, fErr = rFeature.UpdateData(true, model.FunctionTypeLoadControlLimitListData, data, nil, nil)
assert.Nil(s.T(), fErr)

s.sut.loadControlLimitDataUpdate(payload)
assert.True(s.T(), s.eventCalled)
}
Expand All @@ -148,12 +159,14 @@ func (s *EgLPCSuite) Test_configurationDataUpdate() {
descData := &model.DeviceConfigurationKeyValueDescriptionListDataType{
DeviceConfigurationKeyValueDescriptionData: []model.DeviceConfigurationKeyValueDescriptionDataType{
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)),
KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeFailsafeConsumptionActivePowerLimit),
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)),
KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeFailsafeConsumptionActivePowerLimit),
ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeScaledNumber),
},
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(2)),
KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeFailsafeDurationMinimum),
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(2)),
KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeFailsafeDurationMinimum),
ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeDuration),
},
},
}
Expand All @@ -178,17 +191,25 @@ func (s *EgLPCSuite) Test_configurationDataUpdate() {
DeviceConfigurationKeyValueData: []model.DeviceConfigurationKeyValueDataType{
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)),
Value: &model.DeviceConfigurationKeyValueValueType{},
Value: &model.DeviceConfigurationKeyValueValueType{
ScaledNumber: model.NewScaledNumberType(6000),
},
},
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(2)),
Value: &model.DeviceConfigurationKeyValueValueType{},
Value: &model.DeviceConfigurationKeyValueValueType{
Duration: model.NewDurationType(time.Hour * 10),
},
},
},
}

payload.Data = data

// Update the feature with the data so it's actually stored
_, fErr = rFeature.UpdateData(true, model.FunctionTypeDeviceConfigurationKeyValueListData, data, nil, nil)
assert.Nil(s.T(), fErr)

s.sut.configurationDataUpdate(payload)
assert.True(s.T(), s.eventCalled)
}
49 changes: 35 additions & 14 deletions usecases/ma/mgcp/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,11 @@ func (e *MGCP) gridConfigurationDataUpdate(payload spineapi.EventPayload) {
filter := model.DeviceConfigurationKeyValueDescriptionDataType{
KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypePvCurtailmentLimitFactor),
}
if dc.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdatePowerLimitationFactor)
if dc.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.PowerLimitationFactor(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdatePowerLimitationFactor)
}
}
}
}
Expand All @@ -131,38 +134,56 @@ func (e *MGCP) gridMeasurementDataUpdate(payload spineapi.EventPayload) {
filter := model.MeasurementDescriptionDataType{
ScopeType: util.Ptr(model.ScopeTypeTypeACPowerTotal),
}
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdatePower)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.Power(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdatePower)
}
}

// Scenario 3
filter.ScopeType = util.Ptr(model.ScopeTypeTypeGridFeedIn)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateEnergyFeedIn)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.EnergyFeedIn(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateEnergyFeedIn)
}
}

// Scenario 4
filter.ScopeType = util.Ptr(model.ScopeTypeTypeGridConsumption)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateEnergyConsumed)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.EnergyConsumed(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateEnergyConsumed)
}
}

// Scenario 5
filter.ScopeType = util.Ptr(model.ScopeTypeTypeACCurrent)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateCurrentPerPhase)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.CurrentPerPhase(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateCurrentPerPhase)
}
}

// Scenario 6
filter.ScopeType = util.Ptr(model.ScopeTypeTypeACVoltage)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateVoltagePerPhase)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.VoltagePerPhase(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateVoltagePerPhase)
}
}

// Scenario 7
filter.ScopeType = util.Ptr(model.ScopeTypeTypeACFrequency)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateFrequency)
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) {
// Only fire event if public method succeeds (data is valid and retrievable)
if _, err := e.Frequency(payload.Entity); err == nil && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateFrequency)
}
}
}
}
102 changes: 90 additions & 12 deletions usecases/ma/mgcp/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ func (s *GcpMGCPSuite) Test_gridConfigurationDataUpdate() {

payload.Data = keyData

// Update the feature with the data so it's actually stored
_, fErr = rFeature.UpdateData(true, model.FunctionTypeDeviceConfigurationKeyValueListData, keyData, nil, nil)
assert.Nil(s.T(), fErr)

s.sut.gridConfigurationDataUpdate(payload)
assert.True(s.T(), s.eventCalled)
}
Expand All @@ -105,28 +109,40 @@ func (s *GcpMGCPSuite) Test_gridMeasurementDataUpdate() {
descData := &model.MeasurementDescriptionListDataType{
MeasurementDescriptionData: []model.MeasurementDescriptionDataType{
{
MeasurementId: util.Ptr(model.MeasurementIdType(0)),
ScopeType: util.Ptr(model.ScopeTypeTypeACPowerTotal),
MeasurementId: util.Ptr(model.MeasurementIdType(0)),
MeasurementType: util.Ptr(model.MeasurementTypeTypePower),
CommodityType: util.Ptr(model.CommodityTypeTypeElectricity),
ScopeType: util.Ptr(model.ScopeTypeTypeACPowerTotal),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(1)),
ScopeType: util.Ptr(model.ScopeTypeTypeGridFeedIn),
MeasurementId: util.Ptr(model.MeasurementIdType(1)),
MeasurementType: util.Ptr(model.MeasurementTypeTypeEnergy),
CommodityType: util.Ptr(model.CommodityTypeTypeElectricity),
ScopeType: util.Ptr(model.ScopeTypeTypeGridFeedIn),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(2)),
ScopeType: util.Ptr(model.ScopeTypeTypeGridConsumption),
MeasurementId: util.Ptr(model.MeasurementIdType(2)),
MeasurementType: util.Ptr(model.MeasurementTypeTypeEnergy),
CommodityType: util.Ptr(model.CommodityTypeTypeElectricity),
ScopeType: util.Ptr(model.ScopeTypeTypeGridConsumption),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(3)),
ScopeType: util.Ptr(model.ScopeTypeTypeACCurrent),
MeasurementId: util.Ptr(model.MeasurementIdType(3)),
MeasurementType: util.Ptr(model.MeasurementTypeTypeCurrent),
CommodityType: util.Ptr(model.CommodityTypeTypeElectricity),
ScopeType: util.Ptr(model.ScopeTypeTypeACCurrent),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(4)),
ScopeType: util.Ptr(model.ScopeTypeTypeACVoltage),
MeasurementId: util.Ptr(model.MeasurementIdType(4)),
MeasurementType: util.Ptr(model.MeasurementTypeTypeVoltage),
CommodityType: util.Ptr(model.CommodityTypeTypeElectricity),
ScopeType: util.Ptr(model.ScopeTypeTypeACVoltage),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(5)),
ScopeType: util.Ptr(model.ScopeTypeTypeACFrequency),
MeasurementId: util.Ptr(model.MeasurementIdType(5)),
MeasurementType: util.Ptr(model.MeasurementTypeTypeFrequency),
CommodityType: util.Ptr(model.CommodityTypeTypeElectricity),
ScopeType: util.Ptr(model.ScopeTypeTypeACFrequency),
},
},
}
Expand All @@ -135,40 +151,102 @@ func (s *GcpMGCPSuite) Test_gridMeasurementDataUpdate() {
_, fErr := rFeature.UpdateData(true, model.FunctionTypeMeasurementDescriptionListData, descData, nil, nil)
assert.Nil(s.T(), fErr)

// Add electrical connection setup for complete validation
elDescData := &model.ElectricalConnectionDescriptionListDataType{
ElectricalConnectionDescriptionData: []model.ElectricalConnectionDescriptionDataType{
{
ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)),
PositiveEnergyDirection: util.Ptr(model.EnergyDirectionTypeConsume),
},
},
}

rElFeature := s.remoteDevice.FeatureByEntityTypeAndRole(s.smgwEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeServer)
_, fErr = rElFeature.UpdateData(true, model.FunctionTypeElectricalConnectionDescriptionListData, elDescData, nil, nil)
assert.Nil(s.T(), fErr)

elParamData := &model.ElectricalConnectionParameterDescriptionListDataType{
ElectricalConnectionParameterDescriptionData: []model.ElectricalConnectionParameterDescriptionDataType{
{
ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)),
MeasurementId: util.Ptr(model.MeasurementIdType(0)),
},
{
ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)),
MeasurementId: util.Ptr(model.MeasurementIdType(1)),
},
{
ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)),
MeasurementId: util.Ptr(model.MeasurementIdType(2)),
},
{
ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)),
MeasurementId: util.Ptr(model.MeasurementIdType(3)),
},
{
ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)),
MeasurementId: util.Ptr(model.MeasurementIdType(4)),
},
{
ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)),
MeasurementId: util.Ptr(model.MeasurementIdType(5)),
},
},
}

_, fErr = rElFeature.UpdateData(true, model.FunctionTypeElectricalConnectionParameterDescriptionListData, elParamData, nil, nil)
assert.Nil(s.T(), fErr)

s.sut.gridMeasurementDataUpdate(payload)
assert.False(s.T(), s.eventCalled)

data := &model.MeasurementListDataType{
MeasurementData: []model.MeasurementDataType{
{
MeasurementId: util.Ptr(model.MeasurementIdType(0)),
ValueType: util.Ptr(model.MeasurementValueTypeTypeValue),
Value: model.NewScaledNumberType(10),
ValueSource: util.Ptr(model.MeasurementValueSourceTypeMeasuredValue),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(1)),
ValueType: util.Ptr(model.MeasurementValueTypeTypeValue),
Value: model.NewScaledNumberType(10),
ValueSource: util.Ptr(model.MeasurementValueSourceTypeMeasuredValue),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(2)),
ValueType: util.Ptr(model.MeasurementValueTypeTypeValue),
Value: model.NewScaledNumberType(10),
ValueSource: util.Ptr(model.MeasurementValueSourceTypeMeasuredValue),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(3)),
ValueType: util.Ptr(model.MeasurementValueTypeTypeValue),
Value: model.NewScaledNumberType(10),
ValueSource: util.Ptr(model.MeasurementValueSourceTypeMeasuredValue),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(4)),
ValueType: util.Ptr(model.MeasurementValueTypeTypeValue),
Value: model.NewScaledNumberType(10),
ValueSource: util.Ptr(model.MeasurementValueSourceTypeMeasuredValue),
},
{
MeasurementId: util.Ptr(model.MeasurementIdType(5)),
ValueType: util.Ptr(model.MeasurementValueTypeTypeValue),
Value: model.NewScaledNumberType(10),
ValueSource: util.Ptr(model.MeasurementValueSourceTypeMeasuredValue),
},
},
}

payload.Data = data

// Update the feature with the data so it's actually stored
_, fErr = rFeature.UpdateData(true, model.FunctionTypeMeasurementListData, data, nil, nil)
assert.Nil(s.T(), fErr)

s.sut.gridMeasurementDataUpdate(payload)
assert.True(s.T(), s.eventCalled)
}
Loading
Loading