diff --git a/charger/eebus-ohpcf.go b/charger/eebus-ohpcf.go index 4a3360268f..5e99d8d4e9 100644 --- a/charger/eebus-ohpcf.go +++ b/charger/eebus-ohpcf.go @@ -40,6 +40,7 @@ type EEBusOHPCF struct { mpcEntity spineapi.EntityRemoteInterface dhwEntity spineapi.EntityRemoteInterface enabled bool + dimmed bool reboosting bool connector *eebus.Connector @@ -186,6 +187,14 @@ func (c *EEBusOHPCF) lastEnabled() bool { return c.enabled } +// controlEnable is the effective on/off intent: a §14a/LPC dim overrides enable. +func (c *EEBusOHPCF) controlEnable() bool { + c.mu.RLock() + defer c.mu.RUnlock() + + return c.enabled && !c.dimmed +} + // ohpcfStatus maps the compressor process state to a charge status: running is // consuming (C), any other connected state is standby (B). Disconnected (A) is handled in Status. func ohpcfStatus(state ucapi.CompressorPowerConsumptionStateType) api.ChargeStatus { @@ -360,6 +369,26 @@ func (c *EEBusOHPCF) MaxCurrent(int64) error { return c.apply() } +var _ api.Dimmer = (*EEBusOHPCF)(nil) + +// Dimmed implements the api.Dimmer interface, reporting the active §14a/LPC dim state. +func (c *EEBusOHPCF) Dimmed() (bool, error) { + c.mu.RLock() + defer c.mu.RUnlock() + + return c.dimmed, nil +} + +// Dim implements the api.Dimmer interface. A §14a/LPC consumption limit pauses +// or aborts the optional consumption; releasing it resumes per the on/off intent. +func (c *EEBusOHPCF) Dim(dim bool) error { + c.mu.Lock() + c.dimmed = dim + c.mu.Unlock() + + return c.apply() +} + // 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 { @@ -374,7 +403,7 @@ func (c *EEBusOHPCF) apply() error { return nil } - switch ohpcfControlAction(state, c.lastEnabled()) { + switch ohpcfControlAction(state, c.controlEnable()) { case ohpcfSchedule: return c.await(func(cb func(model.ResultDataType)) (*model.MsgCounterType, error) { // 0 = start immediately (relative schedule, see SchedulePowerConsumptionProcess) diff --git a/charger/eebus-ohpcf_test.go b/charger/eebus-ohpcf_test.go index 7f34c53035..346ae68f06 100644 --- a/charger/eebus-ohpcf_test.go +++ b/charger/eebus-ohpcf_test.go @@ -23,6 +23,21 @@ func TestEEBusOHPCFNotConnected(t *testing.T) { require.ErrorIs(t, c.Enable(true), errNotConnected) require.ErrorIs(t, c.MaxCurrent(16), errNotConnected) + require.ErrorIs(t, c.Dim(true), errNotConnected) +} + +// a §14a/LPC dim overrides the on/off intent: the compressor is only driven on +// when enabled and not dimmed. +func TestOHPCFDimGate(t *testing.T) { + c := &EEBusOHPCF{enabled: true} + assert.True(t, c.controlEnable()) + + c.dimmed = true + assert.False(t, c.controlEnable(), "dim overrides enable") + + dimmed, err := c.Dimmed() + require.NoError(t, err) + assert.True(t, dimmed) } // status mapping: running is C, every other connected state (incl. completed diff --git a/templates/definition/charger/eebus-ohpcf.yaml b/templates/definition/charger/eebus-ohpcf.yaml index e933432d62..1252e97cc9 100644 --- a/templates/definition/charger/eebus-ohpcf.yaml +++ b/templates/definition/charger/eebus-ohpcf.yaml @@ -4,7 +4,7 @@ products: de: EEBUS Wärmepumpe (OHPCF) en: EEBUS heat pump (OHPCF) group: heating -capabilities: ["meter"] +capabilities: ["meter", "dim"] params: - preset: eebus - name: reboost