From e2f760913517d139abed4f18a4061cfa456e6471 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 1 Nov 2024 20:21:05 +0100 Subject: [PATCH 01/10] Various maintenance updates - Fix a G115 linter warning - Add documentation/comments to all usecase NewABC implementations --- usecases/cem/cevc/public_scen2.go | 3 ++- usecases/cem/cevc/usecase.go | 6 ++++++ usecases/cem/evcc/usecase.go | 6 ++++++ usecases/cem/evcem/usecase.go | 7 +++++++ usecases/cem/evsecc/usecase.go | 6 ++++++ usecases/cem/evsoc/usecase.go | 6 ++++++ usecases/cem/opev/usecase.go | 6 ++++++ usecases/cem/oscev/usecase.go | 6 ++++++ usecases/cem/vabd/usecase.go | 6 ++++++ usecases/cem/vapd/usecase.go | 6 ++++++ usecases/cs/lpc/usecase.go | 6 ++++++ usecases/cs/lpp/usecase.go | 6 ++++++ usecases/eg/lpc/usecase.go | 6 ++++++ usecases/eg/lpp/usecase.go | 6 ++++++ usecases/ma/mgcp/usecase.go | 6 ++++++ usecases/ma/mpc/usecase.go | 6 ++++++ 16 files changed, 93 insertions(+), 1 deletion(-) 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..37b819ec 100644 --- a/usecases/cem/evcc/usecase.go +++ b/usecases/cem/evcc/usecase.go @@ -17,6 +17,12 @@ type EVCC struct { var _ ucapi.CemEVCCInterface = (*EVCC)(nil) +// Add support for the EV Commissioning and Configuration (EVCEM) 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 NewEVCC( service api.ServiceInterface, localEntity spineapi.EntityLocalInterface, diff --git a/usecases/cem/evcem/usecase.go b/usecases/cem/evcem/usecase.go index c87a9438..35bbc11b 100644 --- a/usecases/cem/evcem/usecase.go +++ b/usecases/cem/evcem/usecase.go @@ -17,6 +17,13 @@ type EVCEM struct { var _ ucapi.CemEVCEMInterface = (*EVCEM)(nil) +// 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..b4204fce 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, 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/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/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/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/usecase.go b/usecases/eg/lpp/usecase.go index 6d7108f6..647e7aec 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{ 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{ From 708761d06038da15b5fbc915fc931aa301c8373d Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 1 Nov 2024 20:23:50 +0100 Subject: [PATCH 02/10] MInor updates --- usecases/cem/evcc/usecase.go | 1 + usecases/cem/evcem/usecase.go | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/usecases/cem/evcc/usecase.go b/usecases/cem/evcc/usecase.go index 37b819ec..1612522f 100644 --- a/usecases/cem/evcc/usecase.go +++ b/usecases/cem/evcc/usecase.go @@ -21,6 +21,7 @@ var _ ucapi.CemEVCCInterface = (*EVCC)(nil) // 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( diff --git a/usecases/cem/evcem/usecase.go b/usecases/cem/evcem/usecase.go index 35bbc11b..42491c4a 100644 --- a/usecases/cem/evcem/usecase.go +++ b/usecases/cem/evcem/usecase.go @@ -24,7 +24,11 @@ var _ ucapi.CemEVCEMInterface = (*EVCEM)(nil) // - 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 { +func NewEVCEM( + service api.ServiceInterface, + localEntity spineapi.EntityLocalInterface, + eventCB api.EntityEventCallback, +) *EVCEM { validActorTypes := []model.UseCaseActorType{ model.UseCaseActorTypeEV, } From f14275a5a7c31d68daa55d17b62ba93f62a699f5 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 4 Nov 2024 11:13:09 +0100 Subject: [PATCH 03/10] Add comments to NewUseCaseBase --- usecases/usecase/usecase.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/usecases/usecase/usecase.go b/usecases/usecase/usecase.go index 863f7b05..ffcc134f 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, From 6f64d634ad82af905423105d4c97105d8e5c34be Mon Sep 17 00:00:00 2001 From: Simon Thelen Date: Mon, 11 Nov 2024 10:51:29 +0100 Subject: [PATCH 04/10] Make DataUpdateHeartbeat event names more consistent This also allows differentiating between eglpc.DataUpdateHeartbeat and cslpc.DataUpdateHeartbeat events. --- usecases/cs/lpp/types.go | 2 +- usecases/eg/lpc/types.go | 2 +- usecases/eg/lpp/types.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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/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/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" ) From 40955772669f3b9f4aefc980db4190a18c13e237 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 18 Nov 2024 15:36:16 +0100 Subject: [PATCH 05/10] Update SHIP and SPINE to latest dev --- go.mod | 6 ++++-- go.sum | 6 ++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 8434cc01..78c5b4a5 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-20241118140853-3ca32da90271 + github.com/enbility/spine-go v0.0.0-20241111100323-fb7dc01d0064 github.com/stretchr/testify v1.9.0 golang.org/x/exp/jsonrpc2 v0.0.0-20240909161429-701f63a606c0 ) @@ -38,3 +38,5 @@ retract ( v0.2.2 // Contains retractions only. v0.2.1 // Published accidentally. ) + +replace github.com/enbility/spine-go => ../spine-go diff --git a/go.sum b/go.sum index e3f10f02..5c30642f 100644 --- a/go.sum +++ b/go.sum @@ -4,10 +4,8 @@ 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-20241118140853-3ca32da90271 h1:TXbRV5W/KMLJ1K2+WixmmNDh8GHzC1jZRc9gQbtbrHY= +github.com/enbility/ship-go v0.0.0-20241118140853-3ca32da90271/go.mod h1:JJp8EQcJhUhTpZ2LSEU4rpdaM3E2n08tswWFWtmm/wU= 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= From 2ceb1ba712542c8f1fcdc2c211eef7669acbdefe Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 18 Nov 2024 15:36:51 +0100 Subject: [PATCH 06/10] Add tests for RemoteEntityScenarios --- api/usecases_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 api/usecases_test.go 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)) +} From 99b6519f033f29c62837e71413e57a40b2aad3dd Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 18 Nov 2024 16:07:30 +0100 Subject: [PATCH 07/10] Updaet SHIP and SPINE --- go.mod | 6 ++---- go.sum | 6 ++++-- usecases/cem/evsoc/usecase.go | 5 ++++- usecases/eg/lpp/usecase.go | 5 ++++- usecases/usecase/usecase.go | 14 ++++++++++++-- usecases/usecase/usecase_test.go | 12 ++++++++---- 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 78c5b4a5..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-20241118140853-3ca32da90271 - github.com/enbility/spine-go v0.0.0-20241111100323-fb7dc01d0064 + 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 ) @@ -38,5 +38,3 @@ retract ( v0.2.2 // Contains retractions only. v0.2.1 // Published accidentally. ) - -replace github.com/enbility/spine-go => ../spine-go diff --git a/go.sum b/go.sum index 5c30642f..20322b35 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +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-20241118140853-3ca32da90271 h1:TXbRV5W/KMLJ1K2+WixmmNDh8GHzC1jZRc9gQbtbrHY= -github.com/enbility/ship-go v0.0.0-20241118140853-3ca32da90271/go.mod h1:JJp8EQcJhUhTpZ2LSEU4rpdaM3E2n08tswWFWtmm/wU= +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/evsoc/usecase.go b/usecases/cem/evsoc/usecase.go index b4204fce..32df9b0c 100644 --- a/usecases/cem/evsoc/usecase.go +++ b/usecases/cem/evsoc/usecase.go @@ -70,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/eg/lpp/usecase.go b/usecases/eg/lpp/usecase.go index 647e7aec..c68a5b74 100644 --- a/usecases/eg/lpp/usecase.go +++ b/usecases/eg/lpp/usecase.go @@ -92,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/usecase/usecase.go b/usecases/usecase/usecase.go index ffcc134f..17d58e36 100644 --- a/usecases/usecase/usecase.go +++ b/usecases/usecase/usecase.go @@ -92,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) } From 76c28c1dae082c569dcea5e475b484f675958124 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 18 Nov 2024 16:08:32 +0100 Subject: [PATCH 08/10] Update comments --- usecases/cem/opev/events.go | 7 +++++++ usecases/cem/opev/public.go | 6 +++++- usecases/cem/opev/public_test.go | 2 +- usecases/cem/oscev/public_test.go | 2 +- usecases/internal/loadcontrol.go | 6 +++++- 5 files changed, 19 insertions(+), 4 deletions(-) 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/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/internal/loadcontrol.go b/usecases/internal/loadcontrol.go index a8238a10..24c59580 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 } From c33ba90b1816238eedc58ee439b364f0298aa819 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 18 Nov 2024 16:08:55 +0100 Subject: [PATCH 09/10] Return an error of no data was found --- usecases/internal/loadcontrol.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/usecases/internal/loadcontrol.go b/usecases/internal/loadcontrol.go index 24c59580..a89fcb34 100644 --- a/usecases/internal/loadcontrol.go +++ b/usecases/internal/loadcontrol.go @@ -109,6 +109,10 @@ func LoadControlLimits( result = append(result, newLimit) } + if len(result) == 0 { + return nil, api.ErrDataNotAvailable + } + return result, nil } From 90a5c1f9e91feb2283805952897a72659233934c Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 18 Nov 2024 16:16:21 +0100 Subject: [PATCH 10/10] Fix tests --- usecases/internal/loadcontrol_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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) }