Skip to content
This repository was archived by the owner on Jun 29, 2024. It is now read-only.

Commit bc63a7e

Browse files
committed
Merge branch 'release/v0.2.0'
2 parents dcbf0e3 + 5738468 commit bc63a7e

52 files changed

Lines changed: 6212 additions & 367 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/default.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,8 @@ jobs:
3434

3535
- name: Test
3636
run: go test -race -v -coverprofile=coverage.out -covermode=atomic ./...
37+
38+
- name: Send coverage
39+
uses: shogo82148/actions-goveralls@v1
40+
with:
41+
path-to-profile: coverage.out

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# cemd
22

3-
[![Build Status](https://github.com/enbility/cemd/actions/workflows/default.yml/badge.svg?branch=main)](https://github.com/enbility/cemd/actions/workflows/default.yml/badge.svg?branch=main)
3+
[![Build Status](https://github.com/enbility/cemd/actions/workflows/default.yml/badge.svg?branch=dev)](https://github.com/enbility/cemd/actions/workflows/default.yml/badge.svg?branch=dev)
44
[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4)](https://godoc.org/github.com/enbility/cemd)
5+
[![Coverage Status](https://coveralls.io/repos/github/enbility/cemd/badge.svg?branch=dev)](https://coveralls.io/github/enbility/cemd?branch=dev)
56
[![Go report](https://goreportcard.com/badge/github.com/enbility/cemd)](https://goreportcard.com/report/github.com/enbility/cemd)
67

78
The goal is to provide an EEBUS CEM implementation

cem/cem.go

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,29 @@ package cem
22

33
import (
44
"github.com/enbility/cemd/emobility"
5+
"github.com/enbility/cemd/grid"
6+
"github.com/enbility/cemd/inverterbatteryvis"
7+
"github.com/enbility/cemd/inverterpvvis"
8+
"github.com/enbility/cemd/scenarios"
59
"github.com/enbility/eebus-go/logging"
610
"github.com/enbility/eebus-go/service"
711
"github.com/enbility/eebus-go/spine"
12+
"github.com/enbility/eebus-go/spine/model"
813
)
914

1015
// Generic CEM implementation
1116
type CemImpl struct {
12-
service *service.EEBUSService
13-
emobilityScenario *emobility.EmobilityScenarioImpl
17+
service *service.EEBUSService
18+
19+
emobilityScenario, gridScenario, inverterBatteryVisScenario, inverterPVVisScenario scenarios.ScenariosI
20+
21+
Currency model.CurrencyType
1422
}
1523

1624
func NewCEM(serviceDescription *service.Configuration, serviceHandler service.EEBUSServiceHandler, log logging.Logging) *CemImpl {
1725
cem := &CemImpl{
18-
service: service.NewEEBUSService(serviceDescription, serviceHandler),
26+
service: service.NewEEBUSService(serviceDescription, serviceHandler),
27+
Currency: model.CurrencyTypeEur,
1928
}
2029

2130
cem.service.SetLogging(log)
@@ -24,23 +33,42 @@ func NewCEM(serviceDescription *service.Configuration, serviceHandler service.EE
2433
}
2534

2635
// Set up the supported usecases and features
27-
func (h *CemImpl) Setup(enableEmobility bool) error {
36+
func (h *CemImpl) Setup() error {
2837
if err := h.service.Setup(); err != nil {
2938
return err
3039
}
3140

3241
spine.Events.Subscribe(h)
3342

34-
// Setup the supported usecases and features
35-
if enableEmobility {
36-
h.emobilityScenario = emobility.NewEMobilityScenario(h.service)
37-
h.emobilityScenario.AddFeatures()
38-
h.emobilityScenario.AddUseCases()
39-
}
40-
4143
return nil
4244
}
4345

46+
// Enable the supported usecases and features
47+
48+
func (h *CemImpl) EnableEmobility(configuration emobility.EmobilityConfiguration) {
49+
h.emobilityScenario = emobility.NewEMobilityScenario(h.service, h.Currency, configuration)
50+
h.emobilityScenario.AddFeatures()
51+
h.emobilityScenario.AddUseCases()
52+
}
53+
54+
func (h *CemImpl) EnableGrid() {
55+
h.gridScenario = grid.NewGridScenario(h.service)
56+
h.gridScenario.AddFeatures()
57+
h.gridScenario.AddUseCases()
58+
}
59+
60+
func (h *CemImpl) EnableBatteryVisualization() {
61+
h.inverterBatteryVisScenario = inverterbatteryvis.NewInverterVisScenario(h.service)
62+
h.inverterBatteryVisScenario.AddFeatures()
63+
h.inverterBatteryVisScenario.AddUseCases()
64+
}
65+
66+
func (h *CemImpl) EnablePVVisualization() {
67+
h.inverterPVVisScenario = inverterpvvis.NewInverterVisScenario(h.service)
68+
h.inverterPVVisScenario.AddFeatures()
69+
h.inverterPVVisScenario.AddUseCases()
70+
}
71+
4472
func (h *CemImpl) Start() {
4573
h.service.Start()
4674
}
@@ -49,10 +77,45 @@ func (h *CemImpl) Shutdown() {
4977
h.service.Shutdown()
5078
}
5179

52-
func (h *CemImpl) RegisterEmobilityRemoteDevice(details *service.ServiceDetails) *emobility.EMobilityImpl {
53-
return h.emobilityScenario.RegisterEmobilityRemoteDevice(details)
80+
func (h *CemImpl) RegisterEmobilityRemoteDevice(details *service.ServiceDetails, dataProvider emobility.EmobilityDataProvider) *emobility.EMobilityImpl {
81+
var impl any
82+
83+
if dataProvider != nil {
84+
impl = h.emobilityScenario.RegisterRemoteDevice(details, dataProvider)
85+
} else {
86+
impl = h.emobilityScenario.RegisterRemoteDevice(details, nil)
87+
}
88+
89+
return impl.(*emobility.EMobilityImpl)
5490
}
5591

5692
func (h *CemImpl) UnRegisterEmobilityRemoteDevice(remoteDeviceSki string) error {
57-
return h.emobilityScenario.UnRegisterEmobilityRemoteDevice(remoteDeviceSki)
93+
return h.emobilityScenario.UnRegisterRemoteDevice(remoteDeviceSki)
94+
}
95+
96+
func (h *CemImpl) RegisterGridRemoteDevice(details *service.ServiceDetails) *grid.GridImpl {
97+
impl := h.gridScenario.RegisterRemoteDevice(details, nil)
98+
return impl.(*grid.GridImpl)
99+
}
100+
101+
func (h *CemImpl) UnRegisterGridRemoteDevice(remoteDeviceSki string) error {
102+
return h.gridScenario.UnRegisterRemoteDevice(remoteDeviceSki)
103+
}
104+
105+
func (h *CemImpl) RegisterInverterBatteryVisRemoteDevice(details *service.ServiceDetails) *grid.GridImpl {
106+
impl := h.inverterBatteryVisScenario.RegisterRemoteDevice(details, nil)
107+
return impl.(*grid.GridImpl)
108+
}
109+
110+
func (h *CemImpl) UnRegisterInverterBatteryVisRemoteDevice(remoteDeviceSki string) error {
111+
return h.inverterBatteryVisScenario.UnRegisterRemoteDevice(remoteDeviceSki)
112+
}
113+
114+
func (h *CemImpl) RegisterInverterPVVisRemoteDevice(details *service.ServiceDetails) *grid.GridImpl {
115+
impl := h.inverterPVVisScenario.RegisterRemoteDevice(details, nil)
116+
return impl.(*grid.GridImpl)
117+
}
118+
119+
func (h *CemImpl) UnRegisterInverterPVVisRemoteDevice(remoteDeviceSki string) error {
120+
return h.inverterPVVisScenario.UnRegisterRemoteDevice(remoteDeviceSki)
58121
}

cmd/main.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
"github.com/enbility/cemd/cem"
13+
"github.com/enbility/cemd/emobility"
1314
"github.com/enbility/eebus-go/logging"
1415
"github.com/enbility/eebus-go/service"
1516
"github.com/enbility/eebus-go/spine/model"
@@ -28,7 +29,18 @@ func NewDemoCem(configuration *service.Configuration) *DemoCem {
2829
}
2930

3031
func (d *DemoCem) Setup() error {
31-
return d.cem.Setup(true)
32+
if err := d.cem.Setup(); err != nil {
33+
return err
34+
}
35+
36+
d.cem.EnableEmobility(emobility.EmobilityConfiguration{
37+
CoordinatedChargingEnabled: true,
38+
})
39+
d.cem.EnableGrid()
40+
d.cem.EnableBatteryVisualization()
41+
d.cem.EnablePVVisualization()
42+
43+
return nil
3244
}
3345

3446
// report the Ship ID of a newly trusted connection
@@ -135,7 +147,7 @@ func main() {
135147
}
136148

137149
remoteService := service.NewServiceDetails(os.Args[2])
138-
demo.cem.RegisterEmobilityRemoteDevice(remoteService)
150+
demo.cem.RegisterEmobilityRemoteDevice(remoteService, nil)
139151

140152
// Clean exit to make sure mdns shutdown is invoked
141153
sig := make(chan os.Signal, 1)

emobility/emobility.go

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,40 @@ import (
44
"github.com/enbility/eebus-go/features"
55
"github.com/enbility/eebus-go/service"
66
"github.com/enbility/eebus-go/spine"
7+
"github.com/enbility/eebus-go/spine/model"
78
"github.com/enbility/eebus-go/util"
89
)
910

11+
// used by emobility and implemented by the CEM
12+
type EmobilityDataProvider interface {
13+
// The EV provided a charge strategy
14+
EVProvidedChargeStrategy(strategy EVChargeStrategyType)
15+
16+
// Energy demand and duration is provided by the EV which requires the CEM
17+
// to respond with time slots containing power limits for each slot
18+
//
19+
// `EVWritePowerLimits` must be invoked within <55s, idealy <15s, after receiving this call
20+
//
21+
// Parameters:
22+
// - demand: Contains details about the actual demands from the EV
23+
// - constraints: Contains details about the time slot constraints
24+
EVRequestPowerLimits(demand EVDemand, constraints EVTimeSlotConstraints)
25+
26+
// Energy demand and duration is provided by the EV which requires the CEM
27+
// to respond with time slots containing incentives for each slot
28+
//
29+
// `EVWriteIncentives` must be invoked within <20s after receiving this call
30+
//
31+
// Parameters:
32+
// - demand: Contains details about the actual demands from the EV
33+
// - constraints: Contains details about the incentive slot constraints
34+
EVRequestIncentives(demand EVDemand, constraints EVIncentiveSlotConstraints)
35+
36+
// The EV provided a charge plan
37+
EVProvidedChargePlan(data []EVDurationSlotValue)
38+
}
39+
40+
// used by the CEM and implemented by emobility
1041
type EmobilityI interface {
1142
// return the current charge sate of the EV
1243
EVCurrentChargeState() (EVChargeStateType, error)
@@ -42,6 +73,13 @@ type EmobilityI interface {
4273
// - and others
4374
EVCurrentLimits() ([]float64, []float64, []float64, error)
4475

76+
// return the current loadcontrol obligation limits
77+
//
78+
// possible errors:
79+
// - ErrDataNotAvailable if no such measurement is (yet) available
80+
// - and others
81+
EVLoadControlObligationLimits() ([]float64, error)
82+
4583
// send new LoadControlLimits to the remote EV
4684
//
4785
// parameters:
@@ -131,6 +169,44 @@ type EmobilityI interface {
131169
// - ErrDataNotAvailable if that information is not (yet) available
132170
// - and others
133171
EVCoordinatedChargingSupported() (bool, error)
172+
173+
// returns the current charging stratey
174+
//
175+
// returns EVChargeStrategyTypeUnknown if it could not be determined, e.g.
176+
// if the vehicle communication is via IEC61851 or the EV doesn't provide
177+
// any information about its charging mode or plan
178+
EVChargeStrategy() EVChargeStrategyType
179+
180+
// returns the current energy demand
181+
// - EVDemand: details about the actual demands from the EV
182+
// - error: if no data is available
183+
//
184+
// if duration is 0, direct charging is active, otherwise timed charging is active
185+
EVEnergyDemand() (EVDemand, error)
186+
187+
// returns the constraints for the power slots
188+
// - EVTimeSlotConstraints: details about the time slot constraints
189+
EVGetPowerConstraints() EVTimeSlotConstraints
190+
191+
// send power limits data to the EV
192+
//
193+
// returns an error if sending failed or charge slot count do not meet requirements
194+
//
195+
// this needs to be invoked either <55s, idealy <15s, of receiving a call to EVRequestPowerLimits
196+
// or if the CEM requires the EV to change its charge plan
197+
EVWritePowerLimits(data []EVDurationSlotValue) error
198+
199+
// returns the constraints for incentive slots
200+
// - EVIncentiveConstraints: details about the incentive slot constraints
201+
EVGetIncentiveConstraints() EVIncentiveSlotConstraints
202+
203+
// send price slots data to the EV
204+
//
205+
// returns an error if sending failed or charge slot count do not meet requirements
206+
//
207+
// this needs to be invoked either within 20s of receiving a call to EVRequestIncentives
208+
// or if the CEM requires the EV to change its charge plan
209+
EVWriteIncentives(data []EVDurationSlotValue) error
134210
}
135211

136212
type EMobilityImpl struct {
@@ -151,20 +227,32 @@ type EMobilityImpl struct {
151227
evMeasurement *features.Measurement
152228
evIdentification *features.Identification
153229
evLoadControl *features.LoadControl
230+
evTimeSeries *features.TimeSeries
231+
evIncentiveTable *features.IncentiveTable
232+
233+
evCurrentChargeStrategy EVChargeStrategyType
234+
235+
ski string
236+
currency model.CurrencyType
154237

155-
ski string
238+
configuration EmobilityConfiguration
239+
dataProvider EmobilityDataProvider
156240
}
157241

158242
var _ EmobilityI = (*EMobilityImpl)(nil)
159243

160244
// Add E-Mobility support
161-
func NewEMobility(service *service.EEBUSService, details *service.ServiceDetails) *EMobilityImpl {
245+
func NewEMobility(service *service.EEBUSService, details *service.ServiceDetails, currency model.CurrencyType, configuration EmobilityConfiguration, dataProvider EmobilityDataProvider) *EMobilityImpl {
162246
ski := util.NormalizeSKI(details.SKI())
163247

164248
emobility := &EMobilityImpl{
165-
service: service,
166-
entity: service.LocalEntity(),
167-
ski: ski,
249+
service: service,
250+
entity: service.LocalEntity(),
251+
ski: ski,
252+
currency: currency,
253+
dataProvider: dataProvider,
254+
evCurrentChargeStrategy: EVChargeStrategyTypeUnknown,
255+
configuration: configuration,
168256
}
169257
spine.Events.Subscribe(emobility)
170258

0 commit comments

Comments
 (0)