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

Commit

Permalink
Merge branch 'release/v0.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
DerAndereAndi committed Apr 7, 2023
2 parents dcbf0e3 + 5738468 commit bc63a7e
Show file tree
Hide file tree
Showing 52 changed files with 6,212 additions and 367 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ jobs:

- name: Test
run: go test -race -v -coverprofile=coverage.out -covermode=atomic ./...

- name: Send coverage
uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: coverage.out
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# cemd

[![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)
[![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)
[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4)](https://godoc.org/github.com/enbility/cemd)
[![Coverage Status](https://coveralls.io/repos/github/enbility/cemd/badge.svg?branch=dev)](https://coveralls.io/github/enbility/cemd?branch=dev)
[![Go report](https://goreportcard.com/badge/github.com/enbility/cemd)](https://goreportcard.com/report/github.com/enbility/cemd)

The goal is to provide an EEBUS CEM implementation
Expand Down
91 changes: 77 additions & 14 deletions cem/cem.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,29 @@ package cem

import (
"github.com/enbility/cemd/emobility"
"github.com/enbility/cemd/grid"
"github.com/enbility/cemd/inverterbatteryvis"
"github.com/enbility/cemd/inverterpvvis"
"github.com/enbility/cemd/scenarios"
"github.com/enbility/eebus-go/logging"
"github.com/enbility/eebus-go/service"
"github.com/enbility/eebus-go/spine"
"github.com/enbility/eebus-go/spine/model"
)

// Generic CEM implementation
type CemImpl struct {
service *service.EEBUSService
emobilityScenario *emobility.EmobilityScenarioImpl
service *service.EEBUSService

emobilityScenario, gridScenario, inverterBatteryVisScenario, inverterPVVisScenario scenarios.ScenariosI

Currency model.CurrencyType
}

func NewCEM(serviceDescription *service.Configuration, serviceHandler service.EEBUSServiceHandler, log logging.Logging) *CemImpl {
cem := &CemImpl{
service: service.NewEEBUSService(serviceDescription, serviceHandler),
service: service.NewEEBUSService(serviceDescription, serviceHandler),
Currency: model.CurrencyTypeEur,
}

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

// Set up the supported usecases and features
func (h *CemImpl) Setup(enableEmobility bool) error {
func (h *CemImpl) Setup() error {
if err := h.service.Setup(); err != nil {
return err
}

spine.Events.Subscribe(h)

// Setup the supported usecases and features
if enableEmobility {
h.emobilityScenario = emobility.NewEMobilityScenario(h.service)
h.emobilityScenario.AddFeatures()
h.emobilityScenario.AddUseCases()
}

return nil
}

// Enable the supported usecases and features

func (h *CemImpl) EnableEmobility(configuration emobility.EmobilityConfiguration) {
h.emobilityScenario = emobility.NewEMobilityScenario(h.service, h.Currency, configuration)
h.emobilityScenario.AddFeatures()
h.emobilityScenario.AddUseCases()
}

func (h *CemImpl) EnableGrid() {
h.gridScenario = grid.NewGridScenario(h.service)
h.gridScenario.AddFeatures()
h.gridScenario.AddUseCases()
}

func (h *CemImpl) EnableBatteryVisualization() {
h.inverterBatteryVisScenario = inverterbatteryvis.NewInverterVisScenario(h.service)
h.inverterBatteryVisScenario.AddFeatures()
h.inverterBatteryVisScenario.AddUseCases()
}

func (h *CemImpl) EnablePVVisualization() {
h.inverterPVVisScenario = inverterpvvis.NewInverterVisScenario(h.service)
h.inverterPVVisScenario.AddFeatures()
h.inverterPVVisScenario.AddUseCases()
}

func (h *CemImpl) Start() {
h.service.Start()
}
Expand All @@ -49,10 +77,45 @@ func (h *CemImpl) Shutdown() {
h.service.Shutdown()
}

func (h *CemImpl) RegisterEmobilityRemoteDevice(details *service.ServiceDetails) *emobility.EMobilityImpl {
return h.emobilityScenario.RegisterEmobilityRemoteDevice(details)
func (h *CemImpl) RegisterEmobilityRemoteDevice(details *service.ServiceDetails, dataProvider emobility.EmobilityDataProvider) *emobility.EMobilityImpl {
var impl any

if dataProvider != nil {
impl = h.emobilityScenario.RegisterRemoteDevice(details, dataProvider)
} else {
impl = h.emobilityScenario.RegisterRemoteDevice(details, nil)
}

return impl.(*emobility.EMobilityImpl)
}

func (h *CemImpl) UnRegisterEmobilityRemoteDevice(remoteDeviceSki string) error {
return h.emobilityScenario.UnRegisterEmobilityRemoteDevice(remoteDeviceSki)
return h.emobilityScenario.UnRegisterRemoteDevice(remoteDeviceSki)
}

func (h *CemImpl) RegisterGridRemoteDevice(details *service.ServiceDetails) *grid.GridImpl {
impl := h.gridScenario.RegisterRemoteDevice(details, nil)
return impl.(*grid.GridImpl)
}

func (h *CemImpl) UnRegisterGridRemoteDevice(remoteDeviceSki string) error {
return h.gridScenario.UnRegisterRemoteDevice(remoteDeviceSki)
}

func (h *CemImpl) RegisterInverterBatteryVisRemoteDevice(details *service.ServiceDetails) *grid.GridImpl {
impl := h.inverterBatteryVisScenario.RegisterRemoteDevice(details, nil)
return impl.(*grid.GridImpl)
}

func (h *CemImpl) UnRegisterInverterBatteryVisRemoteDevice(remoteDeviceSki string) error {
return h.inverterBatteryVisScenario.UnRegisterRemoteDevice(remoteDeviceSki)
}

func (h *CemImpl) RegisterInverterPVVisRemoteDevice(details *service.ServiceDetails) *grid.GridImpl {
impl := h.inverterPVVisScenario.RegisterRemoteDevice(details, nil)
return impl.(*grid.GridImpl)
}

func (h *CemImpl) UnRegisterInverterPVVisRemoteDevice(remoteDeviceSki string) error {
return h.inverterPVVisScenario.UnRegisterRemoteDevice(remoteDeviceSki)
}
16 changes: 14 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/enbility/cemd/cem"
"github.com/enbility/cemd/emobility"
"github.com/enbility/eebus-go/logging"
"github.com/enbility/eebus-go/service"
"github.com/enbility/eebus-go/spine/model"
Expand All @@ -28,7 +29,18 @@ func NewDemoCem(configuration *service.Configuration) *DemoCem {
}

func (d *DemoCem) Setup() error {
return d.cem.Setup(true)
if err := d.cem.Setup(); err != nil {
return err
}

d.cem.EnableEmobility(emobility.EmobilityConfiguration{
CoordinatedChargingEnabled: true,
})
d.cem.EnableGrid()
d.cem.EnableBatteryVisualization()
d.cem.EnablePVVisualization()

return nil
}

// report the Ship ID of a newly trusted connection
Expand Down Expand Up @@ -135,7 +147,7 @@ func main() {
}

remoteService := service.NewServiceDetails(os.Args[2])
demo.cem.RegisterEmobilityRemoteDevice(remoteService)
demo.cem.RegisterEmobilityRemoteDevice(remoteService, nil)

// Clean exit to make sure mdns shutdown is invoked
sig := make(chan os.Signal, 1)
Expand Down
98 changes: 93 additions & 5 deletions emobility/emobility.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,40 @@ import (
"github.com/enbility/eebus-go/features"
"github.com/enbility/eebus-go/service"
"github.com/enbility/eebus-go/spine"
"github.com/enbility/eebus-go/spine/model"
"github.com/enbility/eebus-go/util"
)

// used by emobility and implemented by the CEM
type EmobilityDataProvider interface {
// The EV provided a charge strategy
EVProvidedChargeStrategy(strategy EVChargeStrategyType)

// Energy demand and duration is provided by the EV which requires the CEM
// to respond with time slots containing power limits for each slot
//
// `EVWritePowerLimits` must be invoked within <55s, idealy <15s, after receiving this call
//
// Parameters:
// - demand: Contains details about the actual demands from the EV
// - constraints: Contains details about the time slot constraints
EVRequestPowerLimits(demand EVDemand, constraints EVTimeSlotConstraints)

// Energy demand and duration is provided by the EV which requires the CEM
// to respond with time slots containing incentives for each slot
//
// `EVWriteIncentives` must be invoked within <20s after receiving this call
//
// Parameters:
// - demand: Contains details about the actual demands from the EV
// - constraints: Contains details about the incentive slot constraints
EVRequestIncentives(demand EVDemand, constraints EVIncentiveSlotConstraints)

// The EV provided a charge plan
EVProvidedChargePlan(data []EVDurationSlotValue)
}

// used by the CEM and implemented by emobility
type EmobilityI interface {
// return the current charge sate of the EV
EVCurrentChargeState() (EVChargeStateType, error)
Expand Down Expand Up @@ -42,6 +73,13 @@ type EmobilityI interface {
// - and others
EVCurrentLimits() ([]float64, []float64, []float64, error)

// return the current loadcontrol obligation limits
//
// possible errors:
// - ErrDataNotAvailable if no such measurement is (yet) available
// - and others
EVLoadControlObligationLimits() ([]float64, error)

// send new LoadControlLimits to the remote EV
//
// parameters:
Expand Down Expand Up @@ -131,6 +169,44 @@ type EmobilityI interface {
// - ErrDataNotAvailable if that information is not (yet) available
// - and others
EVCoordinatedChargingSupported() (bool, error)

// returns the current charging stratey
//
// returns EVChargeStrategyTypeUnknown if it could not be determined, e.g.
// if the vehicle communication is via IEC61851 or the EV doesn't provide
// any information about its charging mode or plan
EVChargeStrategy() EVChargeStrategyType

// returns the current energy demand
// - EVDemand: details about the actual demands from the EV
// - error: if no data is available
//
// if duration is 0, direct charging is active, otherwise timed charging is active
EVEnergyDemand() (EVDemand, error)

// returns the constraints for the power slots
// - EVTimeSlotConstraints: details about the time slot constraints
EVGetPowerConstraints() EVTimeSlotConstraints

// send power limits data to the EV
//
// returns an error if sending failed or charge slot count do not meet requirements
//
// this needs to be invoked either <55s, idealy <15s, of receiving a call to EVRequestPowerLimits
// or if the CEM requires the EV to change its charge plan
EVWritePowerLimits(data []EVDurationSlotValue) error

// returns the constraints for incentive slots
// - EVIncentiveConstraints: details about the incentive slot constraints
EVGetIncentiveConstraints() EVIncentiveSlotConstraints

// send price slots data to the EV
//
// returns an error if sending failed or charge slot count do not meet requirements
//
// this needs to be invoked either within 20s of receiving a call to EVRequestIncentives
// or if the CEM requires the EV to change its charge plan
EVWriteIncentives(data []EVDurationSlotValue) error
}

type EMobilityImpl struct {
Expand All @@ -151,20 +227,32 @@ type EMobilityImpl struct {
evMeasurement *features.Measurement
evIdentification *features.Identification
evLoadControl *features.LoadControl
evTimeSeries *features.TimeSeries
evIncentiveTable *features.IncentiveTable

evCurrentChargeStrategy EVChargeStrategyType

ski string
currency model.CurrencyType

ski string
configuration EmobilityConfiguration
dataProvider EmobilityDataProvider
}

var _ EmobilityI = (*EMobilityImpl)(nil)

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

emobility := &EMobilityImpl{
service: service,
entity: service.LocalEntity(),
ski: ski,
service: service,
entity: service.LocalEntity(),
ski: ski,
currency: currency,
dataProvider: dataProvider,
evCurrentChargeStrategy: EVChargeStrategyTypeUnknown,
configuration: configuration,
}
spine.Events.Subscribe(emobility)

Expand Down
Loading

0 comments on commit bc63a7e

Please sign in to comment.