Skip to content

Commit

Permalink
Merge 50b769c into 8e9c451
Browse files Browse the repository at this point in the history
  • Loading branch information
DerAndereAndi committed Jun 18, 2024
2 parents 8e9c451 + 50b769c commit 5650818
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 25 deletions.
25 changes: 23 additions & 2 deletions cmd/controlbox/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/enbility/eebus-go/service"
ucapi "github.com/enbility/eebus-go/usecases/api"
"github.com/enbility/eebus-go/usecases/eg/lpc"
"github.com/enbility/eebus-go/usecases/eg/lpp"
shipapi "github.com/enbility/ship-go/api"
"github.com/enbility/ship-go/cert"
spineapi "github.com/enbility/spine-go/api"
Expand All @@ -30,6 +31,7 @@ type controlbox struct {
myService *service.Service

uclpc ucapi.EgLPCInterface
uclpp ucapi.EgLPPInterface

isConnected bool
}
Expand Down Expand Up @@ -94,6 +96,9 @@ func (h *controlbox) run() {
h.uclpc = lpc.NewLPC(localEntity, h.OnLPCEvent)
h.myService.AddUseCase(h.uclpc)

h.uclpp = lpp.NewLPP(localEntity, h.OnLPPEvent)
h.myService.AddUseCase(h.uclpp)

if len(remoteSki) == 0 {
os.Exit(0)
}
Expand Down Expand Up @@ -154,7 +159,7 @@ func (h *controlbox) sendLimit(entity spineapi.EntityRemoteInterface) {
if *msg.ErrorNumber == model.ErrorNumberTypeNoError {
fmt.Println("Limit accepted.")
} else {
fmt.Println("Limit rejected. Code", msg.ErrorNumber, "Description", msg.Description)
fmt.Println("Limit rejected. Code", *msg.ErrorNumber, "Description", *msg.Description)
}
}
msgCounter, err := h.uclpc.WriteConsumptionLimit(entity, limit, resultCB)
Expand All @@ -165,7 +170,6 @@ func (h *controlbox) sendLimit(entity spineapi.EntityRemoteInterface) {
fmt.Println("Sent limit to", entity.Device().Ski(), "with msgCounter", msgCounter)
})
}

func (h *controlbox) OnLPCEvent(ski string, device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event api.EventType) {
if !h.isConnected {
return
Expand All @@ -183,6 +187,23 @@ func (h *controlbox) OnLPCEvent(ski string, device spineapi.DeviceRemoteInterfac
}
}

func (h *controlbox) OnLPPEvent(ski string, device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event api.EventType) {
if !h.isConnected {
return
}

switch event {
case lpc.UseCaseSupportUpdate:
h.sendLimit(entity)
case lpc.DataUpdateLimit:
if currentLimit, err := h.uclpc.ConsumptionLimit(entity); err == nil {
fmt.Println("New Limit received", currentLimit.Value, "W")
}
default:
return
}
}

// main app
func usage() {
fmt.Println("First Run:")
Expand Down
81 changes: 71 additions & 10 deletions cmd/hems/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,27 @@ import (

"github.com/enbility/eebus-go/api"
"github.com/enbility/eebus-go/service"
"github.com/enbility/eebus-go/usecases/eg/lpc"
ucapi "github.com/enbility/eebus-go/usecases/api"
"github.com/enbility/eebus-go/usecases/cs/lpc"
cslpc "github.com/enbility/eebus-go/usecases/cs/lpc"
cslpp "github.com/enbility/eebus-go/usecases/cs/lpp"
eglpc "github.com/enbility/eebus-go/usecases/eg/lpc"
eglpp "github.com/enbility/eebus-go/usecases/eg/lpp"
shipapi "github.com/enbility/ship-go/api"
"github.com/enbility/ship-go/cert"
spineapi "github.com/enbility/spine-go/api"
"github.com/enbility/spine-go/model"
)

var remoteSki string

type hems struct {
myService *service.Service

uccslpc ucapi.CsLPCInterface
uccslpp ucapi.CsLPPInterface
uceglpc ucapi.EgLPCInterface
uceglpp ucapi.EgLPPInterface
}

func (h *hems) run() {
Expand Down Expand Up @@ -84,8 +95,14 @@ func (h *hems) run() {
}

localEntity := h.myService.LocalDevice().EntityForType(model.EntityTypeTypeCEM)
uclpc := lpc.NewLPC(localEntity, nil)
h.myService.AddUseCase(uclpc)
h.uccslpc = cslpc.NewLPC(localEntity, h.OnLPCEvent)
h.myService.AddUseCase(h.uccslpc)
h.uccslpp = cslpp.NewLPP(localEntity, h.OnLPPEvent)
h.myService.AddUseCase(h.uccslpp)
h.uceglpc = eglpc.NewLPC(localEntity, nil)
h.myService.AddUseCase(h.uceglpc)
h.uceglpp = eglpp.NewLPP(localEntity, nil)
h.myService.AddUseCase(h.uceglpp)

if len(remoteSki) == 0 {
os.Exit(0)
Expand All @@ -97,6 +114,54 @@ func (h *hems) run() {
// defer h.myService.Shutdown()
}

// Controllable System LPC Event Handler

func (h *hems) OnLPCEvent(ski string, device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event api.EventType) {
if entity.EntityType() != model.EntityTypeTypeGridGuard {
return
}

switch event {
case lpc.WriteApprovalRequired:
// get pending writes
pendingWrites := h.uccslpc.PendingConsumptionLimits()

// approve any write
for msgCounter, write := range pendingWrites {
fmt.Println("Approving LPC write with msgCounter", msgCounter, "and limit", write.Value, "W")
h.uccslpc.ApproveOrDenyConsumptionLimit(msgCounter, true, "")
}
case lpc.DataUpdateLimit:
if currentLimit, err := h.uccslpc.ConsumptionLimit(); err != nil {
fmt.Println("New LPC Limit set to", currentLimit.Value, "W")
}
}
}

// Controllable System LPP Event Handler

func (h *hems) OnLPPEvent(ski string, device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event api.EventType) {
if entity.EntityType() != model.EntityTypeTypeGridGuard {
return
}

switch event {
case lpc.WriteApprovalRequired:
// get pending writes
pendingWrites := h.uccslpp.PendingProductionLimits()

// approve any write
for msgCounter, write := range pendingWrites {
fmt.Println("Approving LPP write with msgCounter", msgCounter, "and limit", write.Value, "W")
h.uccslpp.ApproveOrDenyProductionLimit(msgCounter, true, "")
}
case lpc.DataUpdateLimit:
if currentLimit, err := h.uccslpp.ProductionLimit(); err != nil {
fmt.Println("New LPP Limit set to", currentLimit.Value, "W")
}
}
}

// EEBUSServiceHandler

func (h *hems) RemoteSKIConnected(service api.ServiceInterface, ski string) {}
Expand Down Expand Up @@ -158,22 +223,18 @@ func main() {

func (h *hems) Trace(args ...interface{}) {
// h.print("TRACE", args...)
h.print("TRACE", args...)
}

func (h *hems) Tracef(format string, args ...interface{}) {
// h.print("TRACE", args...)
h.printFormat("TRACE", format, args...)
// h.printFormat("TRACE", format, args...)
}

func (h *hems) Debug(args ...interface{}) {
// h.print("TRACE", args...)
h.print("DEBUG", args...)
// h.print("DEBUG", args...)
}

func (h *hems) Debugf(format string, args ...interface{}) {
// h.print("TRACE", args...)
h.printFormat("DEBUG", format, args...)
// h.printFormat("DEBUG", format, args...)
}

func (h *hems) Info(args ...interface{}) {
Expand Down
23 changes: 17 additions & 6 deletions usecases/cs/lpc/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/enbility/eebus-go/api"
"github.com/enbility/eebus-go/features/server"
ucapi "github.com/enbility/eebus-go/usecases/api"
spineapi "github.com/enbility/spine-go/api"
"github.com/enbility/spine-go/model"
"github.com/enbility/spine-go/util"
)
Expand Down Expand Up @@ -94,7 +95,7 @@ func (e *LPC) PendingConsumptionLimits() map[model.MsgCounterType]ucapi.LoadLimi
data := msg.Cmd.LoadControlLimitListData

// elements are only added to the map if all required fields exist
// therefor not check for these are needed here
// therefor no checks for these are needed here

// find the item which contains the limit for this usecase
for _, item := range data.LoadControlLimitData {
Expand Down Expand Up @@ -133,21 +134,31 @@ func (e *LPC) ApproveOrDenyConsumptionLimit(msgCounter model.MsgCounterType, app
e.pendingMux.Lock()
defer e.pendingMux.Unlock()

msg, ok := e.pendingLimits[msgCounter]
if !ok {
return
}

f := e.LocalEntity.FeatureOfTypeAndRole(model.FeatureTypeTypeLoadControl, model.RoleTypeServer)

result := model.ErrorType{
ErrorNumber: model.ErrorNumberType(0),
}

msg, ok := e.pendingLimits[msgCounter]
if !ok {
// it is not a limit of this usecase, so approve it
newMsg := &spineapi.Message{
RequestHeader: &model.HeaderType{
MsgCounter: &msgCounter,
},
}
f.ApproveOrDenyWrite(newMsg, result)
return
}

if !approve {
result.ErrorNumber = model.ErrorNumberType(7)
result.Description = util.Ptr(model.DescriptionType(reason))
}
f.ApproveOrDenyWrite(msg, result)

delete(e.pendingLimits, msgCounter)
}

// Scenario 2
Expand Down
12 changes: 12 additions & 0 deletions usecases/cs/lpc/public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ func (s *CsLPCSuite) Test_PendingConsumptionLimits() {
Value: model.NewScaledNumberType(1000),
TimePeriod: model.NewTimePeriodTypeWithRelativeEndTime(time.Minute * 2),
},
{
LimitId: util.Ptr(model.LoadControlLimitIdType(1)),
IsLimitActive: util.Ptr(true),
Value: model.NewScaledNumberType(1000),
TimePeriod: model.NewTimePeriodTypeWithRelativeEndTime(time.Minute * 2),
},
},
},
},
Expand All @@ -63,7 +69,13 @@ func (s *CsLPCSuite) Test_PendingConsumptionLimits() {

s.sut.ApproveOrDenyConsumptionLimit(model.MsgCounterType(499), true, "")

data = s.sut.PendingConsumptionLimits()
assert.Equal(s.T(), 1, len(data))

s.sut.ApproveOrDenyConsumptionLimit(msgCounter, false, "leave me alone")

data = s.sut.PendingConsumptionLimits()
assert.Equal(s.T(), 0, len(data))
}

func (s *CsLPCSuite) Test_Failsafe() {
Expand Down
23 changes: 17 additions & 6 deletions usecases/cs/lpp/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/enbility/eebus-go/api"
"github.com/enbility/eebus-go/features/server"
ucapi "github.com/enbility/eebus-go/usecases/api"
spineapi "github.com/enbility/spine-go/api"
"github.com/enbility/spine-go/model"
"github.com/enbility/spine-go/util"
)
Expand Down Expand Up @@ -94,7 +95,7 @@ func (e *LPP) PendingProductionLimits() map[model.MsgCounterType]ucapi.LoadLimit
data := msg.Cmd.LoadControlLimitListData

// elements are only added to the map if all required fields exist
// therefor not check for these are needed here
// therefor no checks for these are needed here

// find the item which contains the limit for this usecase
for _, item := range data.LoadControlLimitData {
Expand Down Expand Up @@ -133,21 +134,31 @@ func (e *LPP) ApproveOrDenyProductionLimit(msgCounter model.MsgCounterType, appr
e.pendingMux.Lock()
defer e.pendingMux.Unlock()

msg, ok := e.pendingLimits[msgCounter]
if !ok {
return
}

f := e.LocalEntity.FeatureOfTypeAndRole(model.FeatureTypeTypeLoadControl, model.RoleTypeServer)

result := model.ErrorType{
ErrorNumber: model.ErrorNumberType(0),
}

msg, ok := e.pendingLimits[msgCounter]
if !ok {
// it is not a limit of this usecase, so approve it
newMsg := &spineapi.Message{
RequestHeader: &model.HeaderType{
MsgCounter: &msgCounter,
},
}
f.ApproveOrDenyWrite(newMsg, result)
return
}

if !approve {
result.ErrorNumber = model.ErrorNumberType(7)
result.Description = util.Ptr(model.DescriptionType(reason))
}
f.ApproveOrDenyWrite(msg, result)

delete(e.pendingLimits, msgCounter)
}

// Scenario 2
Expand Down
13 changes: 12 additions & 1 deletion usecases/cs/lpp/public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ func (s *CsLPPSuite) Test_PendingProductionLimits() {
Value: model.NewScaledNumberType(1000),
TimePeriod: model.NewTimePeriodTypeWithRelativeEndTime(time.Minute * 2),
},
},
{
LimitId: util.Ptr(model.LoadControlLimitIdType(1)),
IsLimitActive: util.Ptr(true),
Value: model.NewScaledNumberType(1000),
TimePeriod: model.NewTimePeriodTypeWithRelativeEndTime(time.Minute * 2),
}},
},
},
DeviceRemote: s.remoteDevice,
Expand All @@ -63,7 +68,13 @@ func (s *CsLPPSuite) Test_PendingProductionLimits() {

s.sut.ApproveOrDenyProductionLimit(model.MsgCounterType(499), true, "")

data = s.sut.PendingProductionLimits()
assert.Equal(s.T(), 1, len(data))

s.sut.ApproveOrDenyProductionLimit(msgCounter, false, "leave me alone")

data = s.sut.PendingProductionLimits()
assert.Equal(s.T(), 0, len(data))
}

func (s *CsLPPSuite) Test_Failsafe() {
Expand Down
4 changes: 4 additions & 0 deletions usecases/eg/lpc/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ func (e *LPC) connected(entity spineapi.EntityRemoteInterface) {
if _, err := deviceDiagnosis.Subscribe(); err != nil {
logging.Log().Debug(err)
}

if _, err := deviceDiagnosis.RequestHeartbeat(); err != nil {
logging.Log().Debug(err)
}
}
}

Expand Down
1 change: 1 addition & 0 deletions usecases/eg/lpc/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var _ ucapi.EgLPCInterface = (*LPC)(nil)
func NewLPC(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *LPC {
validActorTypes := []model.UseCaseActorType{model.UseCaseActorTypeControllableSystem}
validEntityTypes := []model.EntityTypeType{
model.EntityTypeTypeCEM,
model.EntityTypeTypeCompressor,
model.EntityTypeTypeEVSE,
model.EntityTypeTypeHeatPumpAppliance,
Expand Down
4 changes: 4 additions & 0 deletions usecases/eg/lpp/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ func (e *LPP) connected(entity spineapi.EntityRemoteInterface) {
if _, err := deviceDiagnosis.Subscribe(); err != nil {
logging.Log().Debug(err)
}

if _, err := deviceDiagnosis.RequestHeartbeat(); err != nil {
logging.Log().Debug(err)
}
}
}

Expand Down
1 change: 1 addition & 0 deletions usecases/eg/lpp/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var _ ucapi.EgLPPInterface = (*LPP)(nil)
func NewLPP(localEntity spineapi.EntityLocalInterface, eventCB api.EntityEventCallback) *LPP {
validActorTypes := []model.UseCaseActorType{model.UseCaseActorTypeControllableSystem}
validEntityTypes := []model.EntityTypeType{
model.EntityTypeTypeCEM,
model.EntityTypeTypeEVSE,
model.EntityTypeTypeInverter,
model.EntityTypeTypeSmartEnergyAppliance,
Expand Down

0 comments on commit 5650818

Please sign in to comment.