diff --git a/charger/eebus.go b/charger/eebus.go index e17560e1b9..00c8e61aba 100644 --- a/charger/eebus.go +++ b/charger/eebus.go @@ -8,11 +8,9 @@ import ( "sync" "time" - cemdapi "github.com/enbility/cemd/api" - cem "github.com/enbility/cemd/cem" - "github.com/enbility/cemd/ucevcc" - cemdutil "github.com/enbility/cemd/util" eebusapi "github.com/enbility/eebus-go/api" + ucapi "github.com/enbility/eebus-go/usecases/api" + "github.com/enbility/eebus-go/usecases/cem/evcc" spineapi "github.com/enbility/spine-go/api" "github.com/enbility/spine-go/model" "github.com/evcc-io/evcc/api" @@ -48,8 +46,6 @@ type EEBus struct { expectedEnableUnpluggedState bool current float64 - // connection tracking for api.CurrentGetter - evConnected bool currentLimit float64 lastIsChargingCheck time.Time @@ -153,28 +149,7 @@ func (c *EEBus) evEntity() spineapi.EntityRemoteInterface { // EEBUSDeviceInterface -// Device events -func (c *EEBus) DeviceConnect(device spineapi.DeviceRemoteInterface, event cemdapi.EventType) { - switch event { - case cem.DeviceConnected: - c.onConnect() - case cem.DeviceDisconnected: - c.onDisconnect() - } -} - -// UseCase specific events -func (c *EEBus) UseCaseEventCB(device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event cemdapi.EventType) { - switch event { - // EV - case ucevcc.EvConnected: - c.setEvEntity(entity) - case ucevcc.EvDisconnected: - c.setEvEntity(nil) - } -} - -func (c *EEBus) onConnect() { +func (c *EEBus) DeviceConnect() { c.log.TRACE.Println("connect ski:", c.ski) c.expectedEnableUnpluggedState = false @@ -182,7 +157,7 @@ func (c *EEBus) onConnect() { c.setConnected(true) } -func (c *EEBus) onDisconnect() { +func (c *EEBus) DeviceDisconnect() { c.log.TRACE.Println("disconnect ski:", c.ski) c.expectedEnableUnpluggedState = false @@ -190,12 +165,28 @@ func (c *EEBus) onDisconnect() { c.setDefaultValues() } +// UseCase specific events +func (c *EEBus) UseCaseEventCB(device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event eebusapi.EventType) { + switch event { + // EV + case evcc.EvConnected: + c.log.TRACE.Println("EV Connected") + c.setEvEntity(entity) + c.currentLimit = -1 + case evcc.EvDisconnected: + c.log.TRACE.Println("EV Disconnected") + c.setEvEntity(nil) + c.currentLimit = -1 + } +} + func (c *EEBus) setDefaultValues() { - c.communicationStandard = ucevcc.UCEVCCCommunicationStandardUnknown + c.communicationStandard = evcc.EVCCCommunicationStandardUnknown c.lastIsChargingCheck = time.Now().Add(-time.Hour * 1) c.lastIsChargingResult = false } +// set wether the EVSE is connected func (c *EEBus) setConnected(connected bool) { c.mux.Lock() defer c.mux.Unlock() @@ -222,11 +213,12 @@ func (c *EEBus) isConnected() bool { var _ api.CurrentLimiter = (*EEBus)(nil) func (c *EEBus) minMax() (minMax, error) { - if !c.uc.EvCC.EVConnected(c.evEntity()) { + evEntity := c.evEntity() + if !c.uc.EvCC.EVConnected(evEntity) { return minMax{}, errors.New("no ev connected") } - minLimits, maxLimits, _, err := c.uc.OpEV.CurrentLimits(c.evEntity()) + minLimits, maxLimits, _, err := c.uc.OpEV.CurrentLimits(evEntity) if err != nil { if err == eebusapi.ErrDataNotAvailable { err = api.ErrNotAvailable @@ -248,7 +240,8 @@ func (c *EEBus) GetMinMaxCurrent() (float64, float64, error) { // we assume that if any phase current value is > idleFactor * min Current, then charging is active and enabled is true func (c *EEBus) isCharging() bool { - if !c.uc.EvCC.EVConnected(c.evEntity()) { + evEntity := c.evEntity() + if !c.uc.EvCC.EVConnected(evEntity) { return false } @@ -271,11 +264,11 @@ func (c *EEBus) isCharging() bool { } // The above doesn't (yet) work for built in meters, so check the EEBUS measurements also - currents, err := c.uc.EvCem.CurrentPerPhase(c.evEntity()) + currents, err := c.uc.EvCem.CurrentPerPhase(evEntity) if err != nil { return false } - limitsMin, _, _, err := c.uc.OpEV.CurrentLimits(c.evEntity()) + limitsMin, _, _, err := c.uc.OpEV.CurrentLimits(evEntity) if err != nil || limitsMin == nil || len(limitsMin) == 0 { return false } @@ -294,38 +287,33 @@ func (c *EEBus) isCharging() bool { // Status implements the api.Charger interface func (c *EEBus) Status() (api.ChargeStatus, error) { + evEntity := c.evEntity() if !c.isConnected() { return api.StatusNone, api.ErrTimeout } - if !c.uc.EvCC.EVConnected(c.evEntity()) { + if !c.uc.EvCC.EVConnected(evEntity) { c.expectedEnableUnpluggedState = false - c.evConnected = false return api.StatusA, nil } - if !c.evConnected { - c.evConnected = true - c.currentLimit = -1 - } - - currentState, err := c.uc.EvCC.ChargeState(c.ev) + currentState, err := c.uc.EvCC.ChargeState(evEntity) if err != nil { return api.StatusNone, err } switch currentState { - case cemdapi.EVChargeStateTypeUnknown, cemdapi.EVChargeStateTypeUnplugged: // Unplugged + case ucapi.EVChargeStateTypeUnknown, ucapi.EVChargeStateTypeUnplugged: // Unplugged c.expectedEnableUnpluggedState = false return api.StatusA, nil - case cemdapi.EVChargeStateTypeFinished, cemdapi.EVChargeStateTypePaused: // Finished, Paused + case ucapi.EVChargeStateTypeFinished, ucapi.EVChargeStateTypePaused: // Finished, Paused return api.StatusB, nil - case cemdapi.EVChargeStateTypeActive: // Active + case ucapi.EVChargeStateTypeActive: // Active if c.isCharging() { return api.StatusC, nil } return api.StatusB, nil - case cemdapi.EVChargeStateTypeError: // Error + case ucapi.EVChargeStateTypeError: // Error return api.StatusF, nil default: return api.StatusNone, fmt.Errorf("%s properties unknown result: %s", c.ski, currentState) @@ -336,8 +324,9 @@ func (c *EEBus) Status() (api.ChargeStatus, error) { // should return true if the charger allows the EV to draw power func (c *EEBus) Enabled() (bool, error) { // when unplugged there is no overload limit data available + evEntity := c.evEntity() state, err := c.Status() - if err != nil || state == api.StatusA { + if err != nil || state == api.StatusA || evEntity == nil { return c.expectedEnableUnpluggedState, nil } @@ -346,9 +335,27 @@ func (c *EEBus) Enabled() (bool, error) { return true, nil } - limits, err := c.uc.OpEV.LoadControlLimits(c.evEntity()) + // if the VW VAS PV mode is active, use PV limits + if c.hasActiveVASVW() { + limits, err := c.uc.OscEV.LoadControlLimits(evEntity) + if err != nil { + // there are no limits available, e.g. because the data was not received yet + return true, nil + } + + for _, limit := range limits { + // check if there is an active limit set + if limit.IsActive && limit.Value >= 1 { + return true, nil + } + } + + return false, nil + } + + limits, err := c.uc.OpEV.LoadControlLimits(evEntity) if err != nil { - // there are no overload protection limits available, e.g. because the data was not received yet + // there are limits available, e.g. because the data was not received yet return true, nil } @@ -356,7 +363,9 @@ func (c *EEBus) Enabled() (bool, error) { // for IEC61851 the pause limit is 0A, for ISO15118-2 it is 0.1A // instead of checking for the actual data, hardcode this, so we might run into less // timing issues as the data might not be received yet - if limit.Value >= 1 { + // if the limit is not active, then the maximum possible current is permitted + if (limit.IsActive && limit.Value >= 1) || + !limit.IsActive { return true, nil } } @@ -376,7 +385,7 @@ func (c *EEBus) Enable(enable bool) error { // this would set allowed A value to be 0. And this would trigger ISO connections to switch to IEC! if !enable { comStandard, err := c.uc.EvCC.CommunicationStandard(c.evEntity()) - if err != nil || comStandard == ucevcc.UCEVCCCommunicationStandardUnknown { + if err != nil || comStandard == evcc.EVCCCommunicationStandardUnknown { return api.ErrMustRetry } } @@ -392,24 +401,25 @@ func (c *EEBus) Enable(enable bool) error { // send current charging power limits to the EV func (c *EEBus) writeCurrentLimitData(currents []float64) error { - if !c.uc.EvCC.EVConnected(c.evEntity()) { + evEntity := c.evEntity() + if !c.uc.EvCC.EVConnected(evEntity) { return errors.New("no ev connected") } - _, maxLimits, _, err := c.uc.OpEV.CurrentLimits(c.evEntity()) + _, maxLimits, _, err := c.uc.OpEV.CurrentLimits(evEntity) if err != nil { return errors.New("no limits available") } // setup the limit data structure - limits := []cemdapi.LoadLimitsPhase{} + limits := []ucapi.LoadLimitsPhase{} for phase, current := range currents { - if phase >= len(maxLimits) || phase >= len(cemdutil.PhaseNameMapping) { + if phase >= len(maxLimits) || phase >= len(ucapi.PhaseNameMapping) { continue } - limit := cemdapi.LoadLimitsPhase{ - Phase: cemdutil.PhaseNameMapping[phase], + limit := ucapi.LoadLimitsPhase{ + Phase: ucapi.PhaseNameMapping[phase], IsActive: true, Value: current, } @@ -428,20 +438,33 @@ func (c *EEBus) writeCurrentLimitData(currents []float64) error { return nil } + // make sure the recommendations are inactive, otherwise the EV won't go to sleep + if recommendations, err := c.uc.OscEV.LoadControlLimits(evEntity); err == nil { + writeNeeded := false + + for _, item := range recommendations { + if item.IsActive { + item.IsActive = false + writeNeeded = true + } + } + + if writeNeeded { + _, _ = c.uc.OscEV.WriteLoadControlLimits(evEntity, recommendations, nil) + } + } + // Set overload protection limits - if _, err = c.uc.OpEV.WriteLoadControlLimits(c.evEntity(), limits); err == nil { + if _, err = c.uc.OpEV.WriteLoadControlLimits(evEntity, limits, nil); err == nil { c.currentLimit = currents[0] } return err } -// provides support for the special VW VAS ISO15118-2 charging behaviour if supported -// will return false if it isn't supported or successful -// -// this functionality allows to fully control charging without the EV actually having a -// charging demand by itself -func (c *EEBus) writeLoadControlLimitsVASVW(limits []cemdapi.LoadLimitsPhase) bool { +// returns if the connected EV has an active VW PV mode +// in this mode, the EV does not have an active charging demand +func (c *EEBus) hasActiveVASVW() bool { // EVSE has to support VW VAS if !c.vasVW { return false @@ -465,7 +488,7 @@ func (c *EEBus) writeLoadControlLimitsVASVW(limits []cemdapi.LoadLimitsPhase) bo } // Optimization of self consumption use case support has to be available - if ok, err := c.uc.OscEV.IsUseCaseSupported(evEntity); err != nil || !ok { + if !c.uc.EVSoc.IsScenarioAvailableAtEntity(evEntity, 1) { return false } @@ -473,7 +496,6 @@ func (c *EEBus) writeLoadControlLimitsVASVW(limits []cemdapi.LoadLimitsPhase) bo // only then the EV has no active charging demand and will charge based on OSCEV recommendations // this is a workaround for EVSE changing isActive to false, even though they should // not announce the usecase at all in that case - isActive := false ucs := evEntity.Device().UseCases() for _, item := range ucs { // check if the referenced entity address is identical to the ev entity address @@ -489,20 +511,28 @@ func (c *EEBus) writeLoadControlLimitsVASVW(limits []cemdapi.LoadLimitsPhase) bo *uc.UseCaseName == model.UseCaseNameTypeOptimizationOfSelfConsumptionDuringEVCharging && uc.UseCaseAvailable != nil && *uc.UseCaseAvailable == true { - isActive = true - break + return true } } - - if isActive { - break - } } - if !isActive { + return false +} + +// provides support for the special VW VAS ISO15118-2 charging behaviour if supported +// will return false if it isn't supported or successful +// +// this functionality allows to fully control charging without the EV actually having a +// charging demand by itself +func (c *EEBus) writeLoadControlLimitsVASVW(limits []ucapi.LoadLimitsPhase) bool { + if !c.hasActiveVASVW() { return false } + evEntity := c.evEntity() + if evEntity == nil { + return false + } // on OSCEV all limits have to be active except they are set to the default value minLimit, _, _, err := c.uc.OscEV.CurrentLimits(evEntity) if err != nil { @@ -511,30 +541,31 @@ func (c *EEBus) writeLoadControlLimitsVASVW(limits []cemdapi.LoadLimitsPhase) bo for index, item := range limits { if item.Value >= minLimit[index] { - item.IsActive = true + limits[index].IsActive = true } else { - item.IsActive = false + limits[index].IsActive = false } } // send the write command - if _, err = c.uc.OscEV.WriteLoadControlLimits(evEntity, limits); err != nil { + if _, err = c.uc.OscEV.WriteLoadControlLimits(evEntity, limits, nil); err != nil { return false } + c.currentLimit = limits[0].Value // make sure the obligations are inactive, otherwise the EV won't go to sleep if obligations, err := c.uc.OpEV.LoadControlLimits(evEntity); err == nil { writeNeeded := false - for _, item := range obligations { + for index, item := range obligations { if item.IsActive { - item.IsActive = false + obligations[index].IsActive = false writeNeeded = true } } if writeNeeded { - _, _ = c.uc.OpEV.WriteLoadControlLimits(evEntity, obligations) + _, _ = c.uc.OpEV.WriteLoadControlLimits(evEntity, obligations, nil) } } @@ -567,21 +598,26 @@ var _ api.CurrentGetter = (*EEBus)(nil) // GetMaxCurrent implements the api.CurrentGetter interface func (c *EEBus) GetMaxCurrent() (float64, error) { + if c.currentLimit == -1 { + return 0, api.ErrNotAvailable + } + return c.currentLimit, nil } // CurrentPower implements the api.Meter interface func (c *EEBus) currentPower() (float64, error) { - if c.evEntity() == nil { + evEntity := c.evEntity() + if evEntity == nil { return 0, nil } - connectedPhases, err := c.uc.EvCem.PhasesConnected(c.evEntity()) + connectedPhases, err := c.uc.EvCem.PhasesConnected(evEntity) if err != nil { return 0, err } - powers, err := c.uc.EvCem.PowerPerPhase(c.evEntity()) + powers, err := c.uc.EvCem.PowerPerPhase(evEntity) if err != nil { return 0, err } @@ -599,11 +635,12 @@ func (c *EEBus) currentPower() (float64, error) { // ChargedEnergy implements the api.ChargeRater interface func (c *EEBus) chargedEnergy() (float64, error) { - if c.evEntity() == nil { + evEntity := c.evEntity() + if evEntity == nil { return 0, nil } - energy, err := c.uc.EvCem.EnergyCharged(c.evEntity()) + energy, err := c.uc.EvCem.EnergyCharged(evEntity) if err != nil { return 0, err } @@ -613,11 +650,12 @@ func (c *EEBus) chargedEnergy() (float64, error) { // Currents implements the api.PhaseCurrents interface func (c *EEBus) currents() (float64, float64, float64, error) { - if c.evEntity() == nil { + evEntity := c.evEntity() + if evEntity == nil { return 0, 0, 0, nil } - res, err := c.uc.EvCem.CurrentPerPhase(c.evEntity()) + res, err := c.uc.EvCem.CurrentPerPhase(evEntity) if err != nil { if err == eebusapi.ErrDataNotAvailable { err = api.ErrNotAvailable @@ -637,17 +675,18 @@ var _ api.Identifier = (*EEBus)(nil) // Identify implements the api.Identifier interface func (c *EEBus) Identify() (string, error) { - if !c.isConnected() || c.evEntity() == nil { + evEntity := c.evEntity() + if !c.isConnected() || evEntity == nil { return "", nil } - if identification, err := c.uc.EvCC.Identifications(c.evEntity()); err == nil && len(identification) > 0 { + if identification, err := c.uc.EvCC.Identifications(evEntity); err == nil && len(identification) > 0 { // return the first identification for now // later this could be multiple, e.g. MAC Address and PCID return identification[0].Value, nil } - if comStandard, _ := c.uc.EvCC.CommunicationStandard(c.evEntity()); comStandard == model.DeviceConfigurationKeyValueStringTypeIEC61851 { + if comStandard, _ := c.uc.EvCC.CommunicationStandard(evEntity); comStandard == model.DeviceConfigurationKeyValueStringTypeIEC61851 { return "", nil } @@ -662,11 +701,13 @@ var _ api.Battery = (*EEBus)(nil) // Soc implements the api.Vehicle interface func (c *EEBus) Soc() (float64, error) { - if ok, err := c.uc.EVSoc.IsUseCaseSupported(c.evEntity()); err != nil || !ok { + evEntity := c.evEntity() + + if !c.uc.EVSoc.IsScenarioAvailableAtEntity(evEntity, 1) { return 0, api.ErrNotAvailable } - soc, err := c.uc.EVSoc.StateOfCharge(c.evEntity()) + soc, err := c.uc.EVSoc.StateOfCharge(evEntity) if err != nil { return 0, api.ErrNotAvailable } diff --git a/charger/eebus/eebus.go b/charger/eebus/eebus.go index c7c3c6845f..9443a507d5 100644 --- a/charger/eebus/eebus.go +++ b/charger/eebus/eebus.go @@ -15,17 +15,18 @@ import ( "time" "dario.cat/mergo" - cemdapi "github.com/enbility/cemd/api" - "github.com/enbility/cemd/cem" - "github.com/enbility/cemd/ucevcc" - "github.com/enbility/cemd/ucevcem" - "github.com/enbility/cemd/ucevsecc" - "github.com/enbility/cemd/ucevsoc" - "github.com/enbility/cemd/ucopev" - "github.com/enbility/cemd/ucoscev" eebusapi "github.com/enbility/eebus-go/api" + service "github.com/enbility/eebus-go/service" + ucapi "github.com/enbility/eebus-go/usecases/api" + "github.com/enbility/eebus-go/usecases/cem/evcc" + "github.com/enbility/eebus-go/usecases/cem/evcem" + "github.com/enbility/eebus-go/usecases/cem/evsecc" + "github.com/enbility/eebus-go/usecases/cem/evsoc" + "github.com/enbility/eebus-go/usecases/cem/opev" + "github.com/enbility/eebus-go/usecases/cem/oscev" shipapi "github.com/enbility/ship-go/api" "github.com/enbility/ship-go/cert" + shiputil "github.com/enbility/ship-go/util" spineapi "github.com/enbility/spine-go/api" "github.com/enbility/spine-go/model" "github.com/evcc-io/evcc/util" @@ -53,22 +54,23 @@ func (c Config) Configured() bool { } type EEBUSDeviceInterface interface { - DeviceConnect(device spineapi.DeviceRemoteInterface, event cemdapi.EventType) - UseCaseEventCB(device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event cemdapi.EventType) + DeviceConnect() + DeviceDisconnect() + UseCaseEventCB(device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event eebusapi.EventType) } // EVSE UseCases type UseCasesEVSE struct { - EvseCC ucevsecc.UCEVSECCInterface - EvCC ucevcc.UCEVCCInterface - EvCem ucevcem.UCEVCEMInterface - EVSoc ucevsoc.UCEVSOCInterface - OpEV ucopev.UCOPEVInterface - OscEV ucoscev.UCOSCEVInterface + EvseCC ucapi.CemEVSECCInterface + EvCC ucapi.CemEVCCInterface + EvCem ucapi.CemEVCEMInterface + EVSoc ucapi.CemEVSOCInterface + OpEV ucapi.CemOPEVInterface + OscEV ucapi.CemOSCEVInterface } type EEBus struct { - Cem *cem.Cem + service eebusapi.ServiceInterface evseUC *UseCasesEVSE @@ -145,28 +147,30 @@ func NewServer(other Config) (*EEBus, error) { SKI: ski, } - c.Cem = cem.NewCEM(configuration, c, c.deviceEventCB, c) - if err := c.Cem.Setup(); err != nil { + c.service = service.NewService(configuration, c) + c.service.SetLogging(c) + if err := c.service.Setup(); err != nil { return nil, err } - evsecc := ucevsecc.NewUCEVSECC(c.Cem.Service, c.evseUsecaseCB) - c.Cem.AddUseCase(evsecc) + localEntity := c.service.LocalDevice().EntityForType(model.EntityTypeTypeCEM) + evsecc := evsecc.NewEVSECC(localEntity, c.evseUsecaseCB) + c.service.AddUseCase(evsecc) - evcc := ucevcc.NewUCEVCC(c.Cem.Service, c.evseUsecaseCB) - c.Cem.AddUseCase(evcc) + evcc := evcc.NewEVCC(c.service, localEntity, c.evseUsecaseCB) + c.service.AddUseCase(evcc) - evcem := ucevcem.NewUCEVCEM(c.Cem.Service, c.evseUsecaseCB) - c.Cem.AddUseCase(evcem) + evcem := evcem.NewEVCEM(c.service, localEntity, c.evseUsecaseCB) + c.service.AddUseCase(evcem) - opev := ucopev.NewUCOPEV(c.Cem.Service, c.evseUsecaseCB) - c.Cem.AddUseCase(opev) + opev := opev.NewOPEV(localEntity, c.evseUsecaseCB) + c.service.AddUseCase(opev) - oscev := ucoscev.NewUCOSCEV(c.Cem.Service, c.evseUsecaseCB) - c.Cem.AddUseCase(oscev) + oscev := oscev.NewOSCEV(localEntity, c.evseUsecaseCB) + c.service.AddUseCase(oscev) - evsoc := ucevsoc.NewUCEVSOC(c.Cem.Service, c.evseUsecaseCB) - c.Cem.AddUseCase(evsoc) + evsoc := evsoc.NewEVSOC(localEntity, c.evseUsecaseCB) + c.service.AddUseCase(evsoc) c.evseUC = &UseCasesEVSE{ EvseCC: evsecc, @@ -181,13 +185,14 @@ func NewServer(other Config) (*EEBus, error) { } func (c *EEBus) RegisterEVSE(ski string, device EEBUSDeviceInterface) *UseCasesEVSE { + ski = shiputil.NormalizeSKI(ski) c.log.TRACE.Printf("registering ski: %s", ski) if ski == c.SKI { c.log.FATAL.Fatal("The charger SKI can not be identical to the SKI of evcc!") } - c.Cem.Service.RegisterRemoteSKI(ski) + c.service.RegisterRemoteSKI(ski) c.mux.Lock() defer c.mux.Unlock() @@ -197,40 +202,44 @@ func (c *EEBus) RegisterEVSE(ski string, device EEBUSDeviceInterface) *UseCasesE } func (c *EEBus) Run() { - c.Cem.Start() + c.service.Start() } func (c *EEBus) Shutdown() { - c.Cem.Shutdown() + c.service.Shutdown() } -// CEMd Callbacks -func (c *EEBus) deviceEventCB(ski string, device spineapi.DeviceRemoteInterface, event cemdapi.EventType) { +// EVSE/EV UseCase CB +func (c *EEBus) evseUsecaseCB(ski string, device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event eebusapi.EventType) { c.mux.Lock() defer c.mux.Unlock() if client, ok := c.clients[ski]; ok { - client.DeviceConnect(device, event) + client.UseCaseEventCB(device, entity, event) } } -// EVSE/EV UseCase CB -func (c *EEBus) evseUsecaseCB(ski string, device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event cemdapi.EventType) { +// EEBUSServiceHandler + +// no implementation needed, handled in CEM events +func (c *EEBus) RemoteSKIConnected(service eebusapi.ServiceInterface, ski string) { c.mux.Lock() defer c.mux.Unlock() if client, ok := c.clients[ski]; ok { - client.UseCaseEventCB(device, entity, event) + client.DeviceConnect() } } -// EEBUSServiceHandler - // no implementation needed, handled in CEM events -func (c *EEBus) RemoteSKIConnected(service eebusapi.ServiceInterface, ski string) {} +func (c *EEBus) RemoteSKIDisconnected(service eebusapi.ServiceInterface, ski string) { + c.mux.Lock() + defer c.mux.Unlock() -// no implementation needed, handled in CEM events -func (c *EEBus) RemoteSKIDisconnected(service eebusapi.ServiceInterface, ski string) {} + if client, ok := c.clients[ski]; ok { + client.DeviceConnect() + } +} // report all currently visible EEBUS services // this is needed to provide an UI for pairing with other devices @@ -256,7 +265,7 @@ func (c *EEBus) ServicePairingDetailUpdate(ski string, detail *shipapi.Connectio if _, ok := c.clients[ski]; !ok { // this is an unknown SKI, so deny pairing - c.Cem.Service.CancelPairingWithSKI(ski) + c.service.CancelPairingWithSKI(ski) } } diff --git a/charger/eebus_test.go b/charger/eebus_test.go index bcccbc77c5..d352eeef03 100644 --- a/charger/eebus_test.go +++ b/charger/eebus_test.go @@ -3,7 +3,7 @@ package charger import ( "testing" - "github.com/enbility/cemd/mocks" + "github.com/enbility/eebus-go/usecases/mocks" spinemocks "github.com/enbility/spine-go/mocks" "github.com/evcc-io/evcc/charger/eebus" "go.uber.org/mock/gomock" @@ -119,9 +119,9 @@ func TestEEBusIsCharging(t *testing.T) { for index, m := range tc.measurements { ctrl := gomock.NewController(t) - evcc := mocks.NewUCEVCCInterface(t) - evcem := mocks.NewUCEVCEMInterface(t) - opev := mocks.NewUCOPEVInterface(t) + evcc := mocks.NewCemEVCCInterface(t) + evcem := mocks.NewCemEVCEMInterface(t) + opev := mocks.NewCemOPEVInterface(t) uc := &eebus.UseCasesEVSE{ EvCC: evcc, diff --git a/go.mod b/go.mod index eac32e9072..d3b3958c83 100644 --- a/go.mod +++ b/go.mod @@ -24,9 +24,9 @@ require ( github.com/dmarkham/enumer v1.5.10 github.com/dylanmei/iso8601 v0.1.0 github.com/eclipse/paho.mqtt.golang v1.4.3 - github.com/enbility/eebus-go v0.5.0 - github.com/enbility/ship-go v0.5.0 - github.com/enbility/spine-go v0.5.0 + github.com/enbility/eebus-go v0.6.0 + github.com/enbility/ship-go v0.5.1 + github.com/enbility/spine-go v0.6.0 github.com/evcc-io/tesla-proxy-client v0.0.0-20240221194046-4168b3759701 github.com/fatih/structs v1.1.0 github.com/glebarez/sqlite v1.11.0 @@ -120,8 +120,8 @@ require ( github.com/cstockton/go-conv v1.0.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fatih/color v1.17.0 // indirect github.com/enbility/zeroconf/v2 v2.0.0-20240210101930-d0004078577b // indirect + github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.4 // indirect @@ -133,11 +133,10 @@ require ( github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/golanguzb70/lrucache v1.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/holoplot/go-avahi v1.0.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect @@ -196,7 +195,3 @@ require ( ) replace gopkg.in/yaml.v3 => github.com/andig/yaml v0.0.0-20240531135838-1ff5761ab467 - -replace github.com/enbility/ship-go => ../../enbility/ship-go -replace github.com/enbility/spine-go => ../../enbility/spine-go -replace github.com/enbility/eebus-go => ../../enbility/eebus-go diff --git a/go.sum b/go.sum index 018db4f353..8efa18cce1 100644 --- a/go.sum +++ b/go.sum @@ -121,14 +121,12 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik= github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/enbility/cemd v0.5.0 h1:/RS88LxDuQ0Av/FVEcqIq7//WhN2H9hHLmckicjAIso= -github.com/enbility/cemd v0.5.0/go.mod h1:BBCUbQkxkU9VQ5pjs1g/kjGD7zb8/RE5wev4Z6CbDns= -github.com/enbility/eebus-go v0.5.0 h1:iC+CSc7eVGqls0GT4d4eWA0vrm1m9eMroG9rvEia06Y= -github.com/enbility/eebus-go v0.5.0/go.mod h1:JhLSoVxGiKSgOtxoGkA81vs+JRB4QHTa8P8LzHsq5WQ= -github.com/enbility/ship-go v0.5.0 h1:Uqol2XjzDOcvT8HUAE4B/59yqd3mxhpJJ/Q2eDHNGqc= -github.com/enbility/ship-go v0.5.0/go.mod h1:ovyrJE3oPnGT5+eQnOqWut80gFDQ0XHn3ZWU2fHV9xQ= -github.com/enbility/spine-go v0.5.0 h1:3OQBl8gQPW/iuWmwcabmCIXDcFCP0RsDw7uP8BYUmaY= -github.com/enbility/spine-go v0.5.0/go.mod h1:8rXOJ7nTa4qrSRK0PpfavBXMztxi6l+h/IFpIVmHviM= +github.com/enbility/eebus-go v0.6.0 h1:TiX397ON3bCPnn49BqkzEd+GTWI4rj0USmRuWxbdr5s= +github.com/enbility/eebus-go v0.6.0/go.mod h1:6ka3OsfqJDiXAWMMYO1LkKQa7xSIgqrhwOeP5kO/yao= +github.com/enbility/ship-go v0.5.1 h1:8Vax1MpyI/C+kQlMFAzQ7/h/xJ7fuumSLJy9FYgEkcE= +github.com/enbility/ship-go v0.5.1/go.mod h1:jewJWYQ10jNhsnhS1C4jESx3CNmDa5HNWZjBhkTug5Y= +github.com/enbility/spine-go v0.6.0 h1:sd5x9ZckvhI9b07HrdxKEZAcpF1Jt+xMC46o3VpuwoY= +github.com/enbility/spine-go v0.6.0/go.mod h1:1SJ6+ihCkjzVALXXbB3xdjDGp2ITqq9gnJQiPsF3fb0= github.com/enbility/zeroconf/v2 v2.0.0-20240210101930-d0004078577b h1:sg3c6LJ4eWffwtt9SW0lgcIX4Oh274vwdJnNFNNrDco= github.com/enbility/zeroconf/v2 v2.0.0-20240210101930-d0004078577b/go.mod h1:BjzRRiYX6mWdOgku1xxDE+NsV8PijTby7Q7BkYVdfDU= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= @@ -233,6 +231,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golanguzb70/lrucache v1.2.0 h1:VjpjmB4VTf9VXBtZTJGcgcN0CNFM5egDrrSjkGyQOlg= +github.com/golanguzb70/lrucache v1.2.0/go.mod h1:zc2GD26KwGEDdTHsCCTcJorv/11HyKwQVS9gqg2bizc= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -301,10 +301,6 @@ github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=