Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various maintenance updates #136

Merged
merged 12 commits into from
Nov 18, 2024
46 changes: 46 additions & 0 deletions api/usecases_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
3 changes: 2 additions & 1 deletion usecases/cem/cevc/public_scen2.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
},
Expand Down
6 changes: 6 additions & 0 deletions usecases/cem/cevc/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions usecases/cem/evcc/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 12 additions & 1 deletion usecases/cem/evcem/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
6 changes: 6 additions & 0 deletions usecases/cem/evsecc/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
11 changes: 10 additions & 1 deletion usecases/cem/evsoc/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}
7 changes: 7 additions & 0 deletions usecases/cem/opev/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion usecases/cem/opev/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion usecases/cem/opev/public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions usecases/cem/opev/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion usecases/cem/oscev/public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions usecases/cem/oscev/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions usecases/cem/vabd/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions usecases/cem/vapd/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions usecases/cs/lpc/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 1 addition & 1 deletion usecases/cs/lpp/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
6 changes: 6 additions & 0 deletions usecases/cs/lpp/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 1 addition & 1 deletion usecases/eg/lpc/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
6 changes: 6 additions & 0 deletions usecases/eg/lpc/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 1 addition & 1 deletion usecases/eg/lpp/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
11 changes: 10 additions & 1 deletion usecases/eg/lpp/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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)
}
10 changes: 9 additions & 1 deletion usecases/internal/loadcontrol.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
}

Expand All @@ -105,6 +109,10 @@ func LoadControlLimits(
result = append(result, newLimit)
}

if len(result) == 0 {
return nil, api.ErrDataNotAvailable
}

return result, nil
}

Expand Down
Loading