EEBus: add heating brands (BC) (#31344)

This commit is contained in:
andig 2026-06-30 13:45:49 +02:00 • committed by GitHub
parent 6fb096f61f
commit 7e9195d0e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 120 additions and 14 deletions

View file

@ -49,7 +49,7 @@ type EEBus struct {
}
func init() {
registry.AddCtx("eebus", NewEEBusFromConfig)
registry.AddCtx("eebus-evse", NewEEBusFromConfig)
}
// NewEEBusFromConfig creates an EEBus charger from generic config

View file

@ -10,6 +10,7 @@ import (
eebusapi "github.com/enbility/eebus-go/api"
ucapi "github.com/enbility/eebus-go/usecases/api"
"github.com/enbility/eebus-go/usecases/cem/ohpcf"
"github.com/enbility/eebus-go/usecases/eg/lpc"
"github.com/enbility/eebus-go/usecases/ma/mdt"
"github.com/enbility/eebus-go/usecases/ma/mpc"
spineapi "github.com/enbility/spine-go/api"
@ -30,17 +31,19 @@ type EEBusOHPCF struct {
*embed
cem *eebus.CustomerEnergyManagement
ma *eebus.MonitoringAppliance
eg *eebus.EnergyGuard
ctx context.Context
reboost time.Duration
mu sync.RWMutex
log *util.Logger
compressor spineapi.EntityRemoteInterface
mpcEntity spineapi.EntityRemoteInterface
dhwEntity spineapi.EntityRemoteInterface
enabled bool
reboosting bool
mu sync.RWMutex
log *util.Logger
compressor spineapi.EntityRemoteInterface
mpcEntity spineapi.EntityRemoteInterface
dhwEntity spineapi.EntityRemoteInterface
egLpcEntity spineapi.EntityRemoteInterface
enabled bool
reboosting bool
connector *eebus.Connector
}
@ -86,6 +89,7 @@ func NewEEBusOHPCF(ctx context.Context, embed *embed, ski, ip string, reboost ti
log: util.NewLogger("eebus-ohpcf"),
cem: inst.CustomerEnergyManagement(),
ma: inst.MonitoringAppliance(),
eg: inst.EnergyGuard(),
connector: eebus.NewConnector(),
ctx: ctx,
reboost: reboost,
@ -125,6 +129,7 @@ func (c *EEBusOHPCF) Connect(connected bool) {
c.compressor = nil
c.mpcEntity = nil
c.dhwEntity = nil
c.egLpcEntity = nil
}
// UseCaseEvent implements the eebus.Device interface
@ -162,6 +167,15 @@ func (c *EEBusOHPCF) UseCaseEvent(_ spineapi.DeviceRemoteInterface, entity spine
c.mu.Lock()
c.dhwEntity = entity
c.mu.Unlock()
// Energy Guard LPC carries the §14a/LPC consumption limit
case lpc.UseCaseSupportUpdate:
c.mu.Lock()
// use most specific selector
if c.egLpcEntity == nil || len(entity.Address().Entity) < len(c.egLpcEntity.Address().Entity) {
c.egLpcEntity = entity
}
c.mu.Unlock()
}
}
@ -360,6 +374,50 @@ func (c *EEBusOHPCF) MaxCurrent(int64) error {
return c.apply()
}
var _ api.Dimmer = (*EEBusOHPCF)(nil)
// Dimmed implements the api.Dimmer interface, reporting whether a §14a/LPC
// consumption limit is currently active on the heat pump.
func (c *EEBusOHPCF) Dimmed() (bool, error) {
c.mu.RLock()
entity := c.egLpcEntity
c.mu.RUnlock()
if entity == nil || !c.eg.EgLPCInterface.IsScenarioAvailableAtEntity(entity, eebus.LPCLimit) {
return false, api.ErrNotAvailable
}
limit, err := c.eg.EgLPCInterface.ConsumptionLimit(entity)
if err != nil {
// scenario announced but no usable value yet
if errors.Is(err, eebusapi.ErrDataNotAvailable) ||
errors.Is(err, eebusapi.ErrMetadataNotAvailable) ||
errors.Is(err, eebusapi.ErrDataInvalid) {
return false, api.ErrNotAvailable
}
return false, err
}
return limit.IsActive && limit.Value > 0, nil
}
// Dim implements the api.Dimmer interface. It writes a §14a/LPC consumption
// limit (fixed 0W safe limit) to the heat pump while dimmed, releasing it otherwise.
func (c *EEBusOHPCF) Dim(dim bool) error {
c.mu.RLock()
entity := c.egLpcEntity
c.mu.RUnlock()
if entity == nil || !c.eg.EgLPCInterface.IsScenarioAvailableAtEntity(entity, eebus.LPCLimit) {
return api.ErrNotAvailable
}
// TODO: change api.Dimmer to make the limit configurable; use a fixed 0W safe limit for now
return c.await(func(cb func(model.ResultDataType)) (*model.MsgCounterType, error) {
return c.eg.EgLPCInterface.WriteConsumptionLimit(entity, ucapi.LoadLimit{Value: 0, IsActive: dim}, cb)
})
}
// apply issues the command to align the optional consumption with the on/off
// intent. It is idempotent: ohpcfControlAction only acts on a state transition.
func (c *EEBusOHPCF) apply() error {

View file

@ -23,6 +23,9 @@ func TestEEBusOHPCFNotConnected(t *testing.T) {
require.ErrorIs(t, c.Enable(true), errNotConnected)
require.ErrorIs(t, c.MaxCurrent(16), errNotConnected)
// dimming uses EG LPC, which is unavailable without an LPC entity
require.ErrorIs(t, c.Dim(true), api.ErrNotAvailable)
}
// status mapping: running is C, every other connected state (incl. completed

View file

@ -1,4 +1,5 @@
template: eebus
template: eebus-evse
covers: ["eebus"]
products:
- description:
de: EEBUS kompatibel
@ -8,5 +9,6 @@ capabilities: ["mA", "meter", "dim"]
params:
- preset: eebus
render: |
type: eebus-evse
{{ include "eebus" . }}
meter: true

View file

@ -0,0 +1,38 @@
template: eebus-ohpcf-wolfvaillant
products:
- brand: Wolf
description:
generic: CHA-Monoblock (07, 10, 16/20, 20/24 with EEBus)
- brand: Wolf
description:
generic: FHA-Monoblock (EEBus)
- brand: Wolf
description:
generic: EEBus
- brand: Vaillant
description:
generic: aroTHERM plus (EEBus)
- brand: Vaillant
description:
generic: EEBus
group: heating
capabilities: ["meter", "dim"]
params:
- preset: eebus
- name: reboost
type: duration
default: 10m
advanced: true
description:
de: Reboost-Intervall
en: Reboost interval
help:
de: Wartezeit, nach der eine neu angekündigte optionale Leistungsaufnahme erneut eingeplant wird.
en: Wait time after which a newly announced optional power consumption is scheduled again.
render: |
type: eebus-ohpcf
{{ include "eebus" . }}
reboost: {{ .reboost }}
features:
- heating
- integrateddevice

View file

@ -3,8 +3,8 @@ products:
- description:
de: EEBUS Wärmepumpe (OHPCF)
en: EEBUS heat pump (OHPCF)
group: heating
capabilities: ["meter"]
group: heatinggeneric
capabilities: ["meter", "dim"]
params:
- preset: eebus
- name: reboost
@ -19,8 +19,7 @@ params:
en: Wait time after which a newly announced optional power consumption is scheduled again.
render: |
type: eebus-ohpcf
ski: {{ .ski }}
{{ if .ip }}ip: {{ .ip }}{{ end }}
{{ include "eebus" . }}
reboost: {{ .reboost }}
features:
- heating

View file

@ -43,4 +43,5 @@ params:
- preset: eebus
- name: ip
render: |
type: eebus-evse
{{ include "eebus" . }}

View file

@ -39,6 +39,7 @@ params:
- preset: eebus
- name: ip
render: |
type: eebus-evse
{{ include "eebus" . }}
meter: true
chargedEnergy: false

View file

@ -11,4 +11,5 @@ requirements:
params:
- preset: eebus
render: |
type: eebus-evse
{{ include "eebus" . }}

View file

@ -7,5 +7,6 @@ capabilities: ["iso151182", "mA", "meter", "dim"]
params:
- preset: eebus
render: |
type: eebus-evse
{{ include "eebus" . }}
meter: true

View file

@ -7,5 +7,6 @@ capabilities: ["meter", "dim"]
params:
- preset: eebus
render: |
type: eebus-evse
{{ include "eebus" . }}
meter: true

View file

@ -14,5 +14,6 @@ params:
choice: ["grid"]
- preset: eebus
render: |
type: eebus
{{ include "eebus" . }}
usage: {{ .usage }}

View file

@ -15,5 +15,6 @@ params:
choice: ["charge"]
- preset: eebus
render: |
type: eebus
{{ include "eebus" . }}
usage: {{ .usage }}

View file

@ -1,5 +1,4 @@
{{ define "eebus" }}
type: eebus
ski: {{ .ski }}
{{ if .ip }}ip: {{ .ip }}{{ end }}
{{- end}}