diff --git a/api/usecases_test.go b/api/usecases_test.go new file mode 100644 index 00000000..d8fc765b --- /dev/null +++ b/api/usecases_test.go @@ -0,0 +1,46 @@ +package api + +import ( + "encoding/json" + "testing" + + "github.com/enbility/spine-go/mocks" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" + + "github.com/stretchr/testify/assert" +) + +func Test_RemoteEntityScenarios_Marshal(t *testing.T) { + item := RemoteEntityScenarios{ + Entity: nil, + Scenarios: nil, + } + value, err := json.Marshal(item) + assert.Nil(t, err) + assert.NotNil(t, value) + assert.Equal(t, `{"Entity":null,"Scenarios":null}`, string(value)) + + item = RemoteEntityScenarios{ + Entity: nil, + Scenarios: []uint{1, 2, 3}, + } + value, err = json.Marshal(item) + assert.Nil(t, err) + assert.NotNil(t, value) + assert.Equal(t, `{"Entity":null,"Scenarios":[1,2,3]}`, string(value)) + + device := mocks.NewDeviceRemoteInterface(t) + deviceAddress := model.AddressDeviceType("test") + device.EXPECT().Address().Return(&deviceAddress).Times(1) + entity := spine.NewEntityRemote(device, model.EntityTypeTypeCEM, []model.AddressEntityType{1, 1}) + + item = RemoteEntityScenarios{ + Entity: entity, + Scenarios: []uint{1, 2, 3}, + } + value, err = json.Marshal(item) + assert.Nil(t, err) + assert.NotNil(t, value) + assert.Equal(t, `{"Entity":{"Device":"test","Entity":[1,1]},"Scenarios":[1,2,3]}`, string(value)) +} diff --git a/go.mod b/go.mod index 8434cc01..39fb7ab7 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/enbility/eebus-go go 1.22.0 require ( - github.com/enbility/ship-go v0.0.0-20241006160314-3a4325a1a6d6 - github.com/enbility/spine-go v0.0.0-20241007182100-30ee8bc405a7 + github.com/enbility/ship-go v0.0.0-20241118145930-d68708c5f1c0 + github.com/enbility/spine-go v0.0.0-20241118145803-0589320ceced github.com/stretchr/testify v1.9.0 golang.org/x/exp/jsonrpc2 v0.0.0-20240909161429-701f63a606c0 ) diff --git a/go.sum b/go.sum index e3f10f02..20322b35 100644 --- a/go.sum +++ b/go.sum @@ -4,10 +4,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a h1:foChWb8lhzqa6lWDRs6COYMdp649YlUirFP8GqoT0JQ= github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a/go.mod h1:H64mhYcAQUGUUnVqMdZQf93kPecH4M79xwH95Lddt3U= -github.com/enbility/ship-go v0.0.0-20241006160314-3a4325a1a6d6 h1:bjrcJ4wxEsG5rXHlXnedRzqAV9JYglj82S14Nf1oLvs= -github.com/enbility/ship-go v0.0.0-20241006160314-3a4325a1a6d6/go.mod h1:JJp8EQcJhUhTpZ2LSEU4rpdaM3E2n08tswWFWtmm/wU= -github.com/enbility/spine-go v0.0.0-20241007182100-30ee8bc405a7 h1:n6tv+YUMncSR9qxUs6k7d/YsKD9ujHHp5pUspIvM6sc= -github.com/enbility/spine-go v0.0.0-20241007182100-30ee8bc405a7/go.mod h1:ZoI9TaJO/So/677uknrli8sc6iryD7wC5iWhVIre+MI= +github.com/enbility/ship-go v0.0.0-20241118145930-d68708c5f1c0 h1:Z8j/N4DgUL8T8mINkHdq0bUbKcWtwDpno0bsKOGahPo= +github.com/enbility/ship-go v0.0.0-20241118145930-d68708c5f1c0/go.mod h1:JJp8EQcJhUhTpZ2LSEU4rpdaM3E2n08tswWFWtmm/wU= +github.com/enbility/spine-go v0.0.0-20241118145803-0589320ceced h1:Z2WrJ+ku7lPZqJ+uzqvIqdMpXqvAZRB3J3xW592pDXI= +github.com/enbility/spine-go v0.0.0-20241118145803-0589320ceced/go.mod h1:ZoI9TaJO/So/677uknrli8sc6iryD7wC5iWhVIre+MI= github.com/enbility/zeroconf/v2 v2.0.0-20240920094356-be1cae74fda6 h1:XOYvxKtT1oxT37w/5oEiRLuPbm9FuJPt3fiYhX0h8Po= github.com/enbility/zeroconf/v2 v2.0.0-20240920094356-be1cae74fda6/go.mod h1:BszP9qFV14mPXgyIREbgIdQtWxbAj3OKqvK02HihMoM= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= diff --git a/usecases/cem/cevc/public_scen2.go b/usecases/cem/cevc/public_scen2.go index 566c7fdf..5bad06e9 100644 --- a/usecases/cem/cevc/public_scen2.go +++ b/usecases/cem/cevc/public_scen2.go @@ -104,8 +104,9 @@ func (e *CEVC) WritePowerLimits(entity spineapi.EntityRemoteInterface, data []uc for index, slot := range data { relativeStart := totalDuration + slotid := uint(index) //nolint:gosec // disable G115 timeSeriesSlot := model.TimeSeriesSlotType{ - TimeSeriesSlotId: util.Ptr(model.TimeSeriesSlotIdType(index)), + TimeSeriesSlotId: util.Ptr(model.TimeSeriesSlotIdType(slotid)), TimePeriod: &model.TimePeriodType{ StartTime: model.NewAbsoluteOrRelativeTimeTypeFromDuration(relativeStart), }, diff --git a/usecases/cem/cevc/usecase.go b/usecases/cem/cevc/usecase.go index 4996c0f8..56c61c81 100644 --- a/usecases/cem/cevc/usecase.go +++ b/usecases/cem/cevc/usecase.go @@ -15,6 +15,12 @@ type CEVC struct { var _ ucapi.CemCEVCInterface = (*CEVC)(nil) +// Add support for the Coordinated EV Charging (CEVC) use case +// as a CEM actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewCEVC(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *CEVC { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypeEV, diff --git a/usecases/cem/evcc/usecase.go b/usecases/cem/evcc/usecase.go index 0fcdbad6..1612522f 100644 --- a/usecases/cem/evcc/usecase.go +++ b/usecases/cem/evcc/usecase.go @@ -17,6 +17,13 @@ type EVCC struct { var _ ucapi.CemEVCCInterface = (*EVCC)(nil) +// Add support for the EV Commissioning and Configuration (EVCEM) use case +// as a CEM actor +// +// Parameters: +// - service: The service implementation +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewEVCC( service api.ServiceInterface, localEntity spineapi.EntityLocalInterface, diff --git a/usecases/cem/evcem/usecase.go b/usecases/cem/evcem/usecase.go index c87a9438..42491c4a 100644 --- a/usecases/cem/evcem/usecase.go +++ b/usecases/cem/evcem/usecase.go @@ -17,7 +17,18 @@ type EVCEM struct { var _ ucapi.CemEVCEMInterface = (*EVCEM)(nil) -func NewEVCEM(service api.ServiceInterface, localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *EVCEM { +// Add support for the Measurement of Electricity during EV Charging (EVCEM) use case +// as a CEM actor +// +// Parameters: +// - service: The service implementation +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) +func NewEVCEM( + service api.ServiceInterface, + localEntity spineapi.EntityLocalInterface, + eventCB api.EntityEventCallback, +) *EVCEM { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypeEV, } diff --git a/usecases/cem/evsecc/usecase.go b/usecases/cem/evsecc/usecase.go index 9a5423a8..d96ee92b 100644 --- a/usecases/cem/evsecc/usecase.go +++ b/usecases/cem/evsecc/usecase.go @@ -15,6 +15,12 @@ type EVSECC struct { var _ ucapi.CemEVSECCInterface = (*EVSECC)(nil) +// Add support for the EVSE Commmissioning and Configuration (EVSECC) use case +// as a CEM actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewEVSECC(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *EVSECC { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypeEVSE, diff --git a/usecases/cem/evsoc/usecase.go b/usecases/cem/evsoc/usecase.go index 996c4409..32df9b0c 100644 --- a/usecases/cem/evsoc/usecase.go +++ b/usecases/cem/evsoc/usecase.go @@ -15,6 +15,12 @@ type EVSOC struct { var _ ucapi.CemEVSOCInterface = (*EVSOC)(nil) +// Add support for the EV State of Charge (EVSOC) use case +// as a CEM actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewEVSOC(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *EVSOC { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypeEV, @@ -64,5 +70,8 @@ func (e *EVSOC) AddFeatures() { } func (e *EVSOC) UpdateUseCaseAvailability(available bool) { - e.LocalEntity.SetUseCaseAvailability(model.UseCaseActorTypeCEM, e.UseCaseName, available) + e.LocalEntity.SetUseCaseAvailability(model.UseCaseFilterType{ + Actor: model.UseCaseActorTypeCEM, + UseCaseName: e.UseCaseName, + }, available) } diff --git a/usecases/cem/opev/events.go b/usecases/cem/opev/events.go index 05a33405..d0ab328a 100644 --- a/usecases/cem/opev/events.go +++ b/usecases/cem/opev/events.go @@ -39,6 +39,13 @@ func (e *OPEV) HandleEvent(payload spineapi.EventPayload) { } } +// TODOS: +// - wie gehen wir damit um, wenn subscriptions nicht erfolgreich sind +// - wie gehen wir damit um, wenn bindings nicht erfolgreich sind, z.b. write implementierungen müssen prüfen ob ein binding exisiteirt +// könnte prüfen ob ein binding exisitert, wenn nicht gleich einen fehler zurückliefern +// - wie gehen wir damit um, wenn descriptions nicht abgefragt werden können +// - wie, wenn die einen Fehler zurückgeben + // an EV was connected func (e *OPEV) evConnected(entity spineapi.EntityRemoteInterface) { // initialise features, e.g. subscriptions, descriptions diff --git a/usecases/cem/opev/public.go b/usecases/cem/opev/public.go index 48baf2b4..9cffbdd5 100644 --- a/usecases/cem/opev/public.go +++ b/usecases/cem/opev/public.go @@ -54,8 +54,12 @@ func (e *OPEV) CurrentLimits(entity spineapi.EntityRemoteInterface) ([]float64, // - limits: per phase data // // possible errors: -// - ErrDataNotAvailable if no such limit is (yet) available +// - ErrDataNotAvailable if none such limit is (yet) available // - and others +// +// Notes: +// - If a limit of phase is not active, the value returned is set to the maximum permitted value (if available), otherwise the phase value is not returned +// - If at least one phase value is available, no error is returned func (e *OPEV) LoadControlLimits(entity spineapi.EntityRemoteInterface) ( limits []ucapi.LoadLimitsPhase, resultErr error) { if !e.IsCompatibleEntityType(entity) { diff --git a/usecases/cem/opev/public_test.go b/usecases/cem/opev/public_test.go index bbccf6ff..644e0f6a 100644 --- a/usecases/cem/opev/public_test.go +++ b/usecases/cem/opev/public_test.go @@ -8,7 +8,7 @@ import ( ) func (s *CemOPEVSuite) Test_Public() { - // The actual tests of the functionality is located in the util package + // The actual tests of the functionality is located in the internal package _, _, _, err := s.sut.CurrentLimits(s.mockRemoteEntity) assert.NotNil(s.T(), err) diff --git a/usecases/cem/opev/usecase.go b/usecases/cem/opev/usecase.go index 2ad79d95..40937b25 100644 --- a/usecases/cem/opev/usecase.go +++ b/usecases/cem/opev/usecase.go @@ -15,6 +15,12 @@ type OPEV struct { var _ ucapi.CemOPEVInterface = (*OPEV)(nil) +// Add support for the Overload Protection by EV Charging Current Curtailment (OPEV) use case +// as a CEM actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewOPEV(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *OPEV { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypeEV, diff --git a/usecases/cem/oscev/public_test.go b/usecases/cem/oscev/public_test.go index 50de4cb8..1f6d8ed5 100644 --- a/usecases/cem/oscev/public_test.go +++ b/usecases/cem/oscev/public_test.go @@ -8,7 +8,7 @@ import ( ) func (s *CemOSCEVSuite) Test_Public() { - // The actual tests of the functionality is located in the util package + // The actual tests of the functionality is located in the internal package _, _, _, err := s.sut.CurrentLimits(s.mockRemoteEntity) assert.NotNil(s.T(), err) diff --git a/usecases/cem/oscev/usecase.go b/usecases/cem/oscev/usecase.go index c74a5887..75fc3e2a 100644 --- a/usecases/cem/oscev/usecase.go +++ b/usecases/cem/oscev/usecase.go @@ -15,6 +15,12 @@ type OSCEV struct { var _ ucapi.CemOSCEVInterface = (*OSCEV)(nil) +// Add support for the Optimization of Self-Consumption during EV Charging (OSCEV) use case +// as a CEM actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewOSCEV(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *OSCEV { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypeEV, diff --git a/usecases/cem/vabd/usecase.go b/usecases/cem/vabd/usecase.go index 44cbf044..c28ed5d3 100644 --- a/usecases/cem/vabd/usecase.go +++ b/usecases/cem/vabd/usecase.go @@ -15,6 +15,12 @@ type VABD struct { var _ ucapi.CemVABDInterface = (*VABD)(nil) +// Add support for the Visualization of Aggregated Battery Data (VABD) use case +// as a CEM actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewVABD(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *VABD { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypeBatterySystem, diff --git a/usecases/cem/vapd/usecase.go b/usecases/cem/vapd/usecase.go index 5e901a76..50578d1b 100644 --- a/usecases/cem/vapd/usecase.go +++ b/usecases/cem/vapd/usecase.go @@ -15,6 +15,12 @@ type VAPD struct { var _ ucapi.CemVAPDInterface = (*VAPD)(nil) +// Add support for the Visualization of Aggregated Photovoltaic Data (VAPD) use case +// as a CEM actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewVAPD(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *VAPD { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypePVSystem, diff --git a/usecases/cs/lpc/usecase.go b/usecases/cs/lpc/usecase.go index 0626740f..5b6d3608 100644 --- a/usecases/cs/lpc/usecase.go +++ b/usecases/cs/lpc/usecase.go @@ -28,6 +28,12 @@ type LPC struct { var _ ucapi.CsLPCInterface = (*LPC)(nil) +// Add support for the Limitation of Power Consumption (LPC) use case +// as a Controllable System actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewLPC(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *LPC { validActorTypes := []model.UseCaseActorType{model.UseCaseActorTypeEnergyGuard} validEntityTypes := []model.EntityTypeType{ diff --git a/usecases/cs/lpp/types.go b/usecases/cs/lpp/types.go index 9379b677..0776d631 100644 --- a/usecases/cs/lpp/types.go +++ b/usecases/cs/lpp/types.go @@ -43,5 +43,5 @@ const ( // E.g. going into or out of the Failsafe state // // Use Case LPP, Scenario 3 - DataUpdateHeartbeat api.EventType = "uclppserver-DataUpdateHeartbeat" + DataUpdateHeartbeat api.EventType = "cs-lpp-DataUpdateHeartbeat" ) diff --git a/usecases/cs/lpp/usecase.go b/usecases/cs/lpp/usecase.go index 9adb0e82..8b859f98 100644 --- a/usecases/cs/lpp/usecase.go +++ b/usecases/cs/lpp/usecase.go @@ -28,6 +28,12 @@ type LPP struct { var _ ucapi.CsLPPInterface = (*LPP)(nil) +// Add support for the Limitation of Power Production (LPC) use case +// as a Controllable System actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewLPP(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *LPP { validActorTypes := []model.UseCaseActorType{model.UseCaseActorTypeEnergyGuard} validEntityTypes := []model.EntityTypeType{ diff --git a/usecases/eg/lpc/types.go b/usecases/eg/lpc/types.go index 455b2bd4..e2a507f9 100644 --- a/usecases/eg/lpc/types.go +++ b/usecases/eg/lpc/types.go @@ -35,5 +35,5 @@ const ( // E.g. going into or out of the Failsafe state // // Use Case LPC, Scenario 3 - DataUpdateHeartbeat api.EventType = "cs-lpc-DataUpdateHeartbeat" + DataUpdateHeartbeat api.EventType = "eg-lpc-DataUpdateHeartbeat" ) diff --git a/usecases/eg/lpc/usecase.go b/usecases/eg/lpc/usecase.go index b2727628..84c3c5d3 100644 --- a/usecases/eg/lpc/usecase.go +++ b/usecases/eg/lpc/usecase.go @@ -15,6 +15,12 @@ type LPC struct { var _ ucapi.EgLPCInterface = (*LPC)(nil) +// Add support for the Limitation of Power Consumption (LPC) use case +// as a Energy Guard actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewLPC(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *LPC { validActorTypes := []model.UseCaseActorType{model.UseCaseActorTypeControllableSystem} validEntityTypes := []model.EntityTypeType{ diff --git a/usecases/eg/lpp/types.go b/usecases/eg/lpp/types.go index d6998d56..d2ed9452 100644 --- a/usecases/eg/lpp/types.go +++ b/usecases/eg/lpp/types.go @@ -35,5 +35,5 @@ const ( // E.g. going into or out of the Failsafe state // // Use Case LPP, Scenario 3 - DataUpdateHeartbeat api.EventType = "cs-lpp-DataUpdateHeartbeat" + DataUpdateHeartbeat api.EventType = "eg-lpp-DataUpdateHeartbeat" ) diff --git a/usecases/eg/lpp/usecase.go b/usecases/eg/lpp/usecase.go index 6d7108f6..c68a5b74 100644 --- a/usecases/eg/lpp/usecase.go +++ b/usecases/eg/lpp/usecase.go @@ -15,6 +15,12 @@ type LPP struct { var _ ucapi.EgLPPInterface = (*LPP)(nil) +// Add support for the Limitation of Power Production (LPC) use case +// as a Energy Guard actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewLPP(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *LPP { validActorTypes := []model.UseCaseActorType{model.UseCaseActorTypeControllableSystem} validEntityTypes := []model.EntityTypeType{ @@ -86,5 +92,8 @@ func (e *LPP) AddFeatures() { } func (e *LPP) UpdateUseCaseAvailability(available bool) { - e.LocalEntity.SetUseCaseAvailability(model.UseCaseActorTypeEnergyGuard, e.UseCaseName, available) + e.LocalEntity.SetUseCaseAvailability(model.UseCaseFilterType{ + Actor: model.UseCaseActorTypeEnergyGuard, + UseCaseName: e.UseCaseName, + }, available) } diff --git a/usecases/internal/loadcontrol.go b/usecases/internal/loadcontrol.go index a8238a10..a89fcb34 100644 --- a/usecases/internal/loadcontrol.go +++ b/usecases/internal/loadcontrol.go @@ -15,6 +15,10 @@ import ( // possible errors: // - ErrDataNotAvailable if no such measurement is (yet) available // - and others +// +// Notes: +// - If a limit of phase is not active, the value returned is set to the maximum permitted value (if available), otherwise the phase value is not returned +// - If at least one phase value is available, no error is returned func LoadControlLimits( localEntity spineapi.EntityLocalInterface, remoteEntity spineapi.EntityRemoteInterface, @@ -86,7 +90,7 @@ func LoadControlLimits( // which is not the case for all elements for this EVSE setup // but we have to ignore this case and continue with the next phase - // In addition Elli Conenct/Pro (Gen1) returns no or empty PermittedValueSet data + // In addition Elli Connect/Pro (Gen1) returns no or empty PermittedValueSet data continue } @@ -105,6 +109,10 @@ func LoadControlLimits( result = append(result, newLimit) } + if len(result) == 0 { + return nil, api.ErrDataNotAvailable + } + return result, nil } diff --git a/usecases/internal/loadcontrol_test.go b/usecases/internal/loadcontrol_test.go index 1fc1f60a..bbd94786 100644 --- a/usecases/internal/loadcontrol_test.go +++ b/usecases/internal/loadcontrol_test.go @@ -66,7 +66,7 @@ func (s *InternalSuite) Test_LoadControlLimits() { assert.Nil(s.T(), fErr) data, err = LoadControlLimits(s.localEntity, s.monitoredEntity, filter) - assert.Nil(s.T(), err) + assert.NotNil(s.T(), err) assert.Equal(s.T(), 0, len(data)) paramData := &model.ElectricalConnectionParameterDescriptionListDataType{ @@ -210,7 +210,7 @@ func (s *InternalSuite) Test_LoadControlLimits_AudiMobileConnect_1Phase() { assert.Nil(s.T(), fErr) data, err = LoadControlLimits(s.localEntity, s.monitoredEntity, filter) - assert.Nil(s.T(), err) + assert.NotNil(s.T(), err) assert.Equal(s.T(), 0, len(data)) paramData := &model.ElectricalConnectionParameterDescriptionListDataType{ @@ -283,7 +283,7 @@ func (s *InternalSuite) Test_LoadControlLimits_AudiMobileConnect_1Phase() { assert.Nil(s.T(), fErr) data, err = LoadControlLimits(s.localEntity, s.monitoredEntity, filter) - assert.Nil(s.T(), err) + assert.NotNil(s.T(), err) assert.Equal(s.T(), 0, len(data)) permData := &model.ElectricalConnectionPermittedValueSetListDataType{ @@ -393,7 +393,7 @@ func (s *InternalSuite) Test_LoadControlLimits_Bender_1Phase() { assert.Nil(s.T(), fErr) data, err = LoadControlLimits(s.localEntity, s.monitoredEntity, filter) - assert.Nil(s.T(), err) + assert.NotNil(s.T(), err) assert.Nil(s.T(), data) paramData := &model.ElectricalConnectionParameterDescriptionListDataType{ @@ -480,7 +480,7 @@ func (s *InternalSuite) Test_LoadControlLimits_Bender_1Phase() { assert.Nil(s.T(), fErr) data, err = LoadControlLimits(s.localEntity, s.monitoredEntity, filter) - assert.Nil(s.T(), err) + assert.NotNil(s.T(), err) assert.Nil(s.T(), data) // according to OpEV Spec 1.0.1b, page 30: "At least one set of permitted values SHALL be stated." @@ -622,7 +622,7 @@ func (s *InternalSuite) Test_LoadControlLimits_Elli_1Phase() { assert.Nil(s.T(), fErr) data, err = LoadControlLimits(s.localEntity, s.monitoredEntity, filter) - assert.Nil(s.T(), err) + assert.NotNil(s.T(), err) assert.Nil(s.T(), data) paramData := &model.ElectricalConnectionParameterDescriptionListDataType{ @@ -718,7 +718,7 @@ func (s *InternalSuite) Test_LoadControlLimits_Elli_1Phase() { assert.Nil(s.T(), fErr) data, err = LoadControlLimits(s.localEntity, s.monitoredEntity, filter) - assert.Nil(s.T(), err) + assert.NotNil(s.T(), err) assert.Nil(s.T(), data) // according to OpEV Spec 1.0.1b, page 30: "At least one set of permitted values SHALL be stated." @@ -749,7 +749,7 @@ func (s *InternalSuite) Test_LoadControlLimits_Elli_1Phase() { assert.Nil(s.T(), fErr) data, err = LoadControlLimits(s.localEntity, s.monitoredEntity, filter) - assert.Nil(s.T(), err) + assert.NotNil(s.T(), err) assert.Nil(s.T(), data) } diff --git a/usecases/ma/mgcp/usecase.go b/usecases/ma/mgcp/usecase.go index 8fcfa782..6f6988d2 100644 --- a/usecases/ma/mgcp/usecase.go +++ b/usecases/ma/mgcp/usecase.go @@ -15,6 +15,12 @@ type MGCP struct { var _ ucapi.MaMGCPInterface = (*MGCP)(nil) +// Add support for the Monitoring of Grid Connection Point (MGCP) use case +// as a Monitoring Appliance actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewMGCP(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *MGCP { validActorTypes := []model.UseCaseActorType{model.UseCaseActorTypeGridConnectionPoint} validEntityTypes := []model.EntityTypeType{ diff --git a/usecases/ma/mpc/usecase.go b/usecases/ma/mpc/usecase.go index 69a420cf..8e23395b 100644 --- a/usecases/ma/mpc/usecase.go +++ b/usecases/ma/mpc/usecase.go @@ -15,6 +15,12 @@ type MPC struct { var _ ucapi.MaMPCInterface = (*MPC)(nil) +// Add support for the Monitoring of Monitoring Power Consumption (MPC) use case +// as a Monitoring Appliance actor +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - eventCB: The callback to be called when an event is triggered (optional, can be nil) func NewMPC(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *MPC { validActorTypes := []model.UseCaseActorType{model.UseCaseActorTypeMonitoredUnit} validEntityTypes := []model.EntityTypeType{ diff --git a/usecases/usecase/usecase.go b/usecases/usecase/usecase.go index 863f7b05..17d58e36 100644 --- a/usecases/usecase/usecase.go +++ b/usecases/usecase/usecase.go @@ -33,6 +33,19 @@ type UseCaseBase struct { var _ api.UseCaseBaseInterface = (*UseCaseBase)(nil) +// Adds a new use case to an entity +// +// Parameters: +// - localEntity: The local entity which should support the use case +// - usecaseActor: The actor type of the use case +// - usecaseName: The name of the use case +// - useCaseVersion: The version of the use case +// - useCaseDocumentSubVersion: The sub version of the use case document +// - useCaseScenarios: The supported scenarios of the use case +// - eventCB: The callback to be called when an usecase update event of a remote entity is triggered (optional, can be nil) +// - useCaseUpdateEvent: The event type of the use case update event for the eventCB +// - validActorTypes: The valid actor types for the use case in a remote entity +// - validEntityTypes: The valid entity types for the use case in a remote entity func NewUseCaseBase( localEntity spineapi.EntityLocalInterface, usecaseActor model.UseCaseActorType, @@ -79,11 +92,21 @@ func (u *UseCaseBase) AddUseCase() { } func (u *UseCaseBase) RemoveUseCase() { - u.LocalEntity.RemoveUseCaseSupport(u.UseCaseActor, u.UseCaseName) + u.LocalEntity.RemoveUseCaseSupports( + []model.UseCaseFilterType{ + { + Actor: u.UseCaseActor, + UseCaseName: u.UseCaseName, + }, + }) } func (u *UseCaseBase) UpdateUseCaseAvailability(available bool) { - u.LocalEntity.SetUseCaseAvailability(u.UseCaseActor, u.UseCaseName, available) + u.LocalEntity.SetUseCaseAvailability( + model.UseCaseFilterType{ + Actor: u.UseCaseActor, + UseCaseName: u.UseCaseName, + }, available) } func (u *UseCaseBase) IsCompatibleEntityType(entity spineapi.EntityRemoteInterface) bool { diff --git a/usecases/usecase/usecase_test.go b/usecases/usecase/usecase_test.go index 511efa9d..7a7c9a16 100644 --- a/usecases/usecase/usecase_test.go +++ b/usecases/usecase/usecase_test.go @@ -23,19 +23,23 @@ func (s *UseCaseSuite) Test() { result = s.uc.IsCompatibleEntityType(payload.Entity) assert.True(s.T(), result) - result = s.localEntity.HasUseCaseSupport(useCaseActor, useCaseName) + usecaseFilter := model.UseCaseFilterType{ + Actor: useCaseActor, + UseCaseName: useCaseName, + } + result = s.localEntity.HasUseCaseSupport(usecaseFilter) assert.False(s.T(), result) s.uc.AddUseCase() - result = s.localEntity.HasUseCaseSupport(useCaseActor, useCaseName) + result = s.localEntity.HasUseCaseSupport(usecaseFilter) assert.True(s.T(), result) s.uc.UpdateUseCaseAvailability(false) - result = s.localEntity.HasUseCaseSupport(useCaseActor, useCaseName) + result = s.localEntity.HasUseCaseSupport(usecaseFilter) assert.True(s.T(), result) s.uc.RemoveUseCase() - result = s.localEntity.HasUseCaseSupport(useCaseActor, useCaseName) + result = s.localEntity.HasUseCaseSupport(usecaseFilter) assert.False(s.T(), result) }