HomeAssistant: add phase switching (#27896)
This commit is contained in:
parent
3967594b79
commit
c785c54bbe
4 changed files with 75 additions and 3 deletions
|
|
@ -1,11 +1,12 @@
|
|||
package charger
|
||||
|
||||
//go:generate go tool decorate -f decorateHomeAssistant -b *HomeAssistant -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages
|
||||
//go:generate go tool decorate -f decorateHomeAssistant -b *HomeAssistant -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages,api.PhaseSwitcher,api.PhaseGetter
|
||||
// -t api.CurrentGetter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -39,6 +40,7 @@ func NewHomeAssistantFromConfig(other map[string]any) (api.Charger, error) {
|
|||
Energy string // optional - energy sensor
|
||||
Currents []string // optional - current sensors for L1, L2, L3
|
||||
Voltages []string // optional - voltage sensors for L1, L2, L3
|
||||
Phases string // optional - select entity for 1p/3p phase switching
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
|
|
@ -76,6 +78,8 @@ func NewHomeAssistantFromConfig(other map[string]any) (api.Charger, error) {
|
|||
// decorators for optional interfaces
|
||||
var power, energy func() (float64, error)
|
||||
var currents, voltages func() (float64, float64, float64, error)
|
||||
var phases1p3p func(int) error
|
||||
var phasesG func() (int, error)
|
||||
|
||||
if cc.Power != "" {
|
||||
power = func() (float64, error) { return conn.GetFloatState(cc.Power) }
|
||||
|
|
@ -98,7 +102,22 @@ func NewHomeAssistantFromConfig(other map[string]any) (api.Charger, error) {
|
|||
return nil, fmt.Errorf("voltages: %w", err)
|
||||
}
|
||||
|
||||
return decorateHomeAssistant(c, power, energy, currents, voltages), nil
|
||||
// phase switching (optional)
|
||||
if cc.Phases != "" {
|
||||
phases1p3p = func(phases int) error {
|
||||
return conn.CallSelectService(cc.Phases, strconv.Itoa(phases))
|
||||
}
|
||||
|
||||
phasesG = func() (int, error) {
|
||||
val, err := conn.GetIntState(cc.Phases)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(val), nil
|
||||
}
|
||||
}
|
||||
|
||||
return decorateHomeAssistant(c, power, energy, currents, voltages, phases1p3p, phasesG), nil
|
||||
}
|
||||
|
||||
var _ api.Charger = (*HomeAssistant)(nil)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateHomeAssistant(base *HomeAssistant, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error)) api.Charger {
|
||||
func decorateHomeAssistant(base *HomeAssistant, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
|
|
@ -27,6 +27,14 @@ func decorateHomeAssistant(base *HomeAssistant, meter func() (float64, error), m
|
|||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateHomeAssistantPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateHomeAssistantPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateHomeAssistantPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
|
@ -68,6 +76,22 @@ func (impl *decorateHomeAssistantPhaseCurrentsImpl) Currents() (float64, float64
|
|||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateHomeAssistantPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHomeAssistantPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateHomeAssistantPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateHomeAssistantPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
||||
type decorateHomeAssistantPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,17 @@ params:
|
|||
help:
|
||||
en: Entity ID for L3 voltage measurement in volts
|
||||
de: Entitäts-ID für L3 Spannungsmessung in Volt
|
||||
|
||||
- name: phases
|
||||
description:
|
||||
de: Phasenumschaltungs-Entität
|
||||
en: Phase switching entity
|
||||
service: homeassistant/entities?uri={uri}&domain=select,input_select
|
||||
example: "select.charger_phases"
|
||||
advanced: true
|
||||
help:
|
||||
en: Entity ID for 1p/3p phase switching (select entity with options "1" and "3")
|
||||
de: Entitäts-ID für 1p/3p Phasenumschaltung (Select-Entität mit Optionen "1" und "3")
|
||||
render: |
|
||||
type: homeassistant
|
||||
uri: {{ .uri }}
|
||||
|
|
@ -163,3 +174,6 @@ render: |
|
|||
- {{ .voltageL2 }}
|
||||
- {{ .voltageL3 }}
|
||||
{{- end }}
|
||||
{{- if .phases }}
|
||||
phases: {{ .phases }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -267,6 +267,21 @@ func (c *Connection) CallNumberService(entity string, value float64) error {
|
|||
return c.CallService(domain, "set_value", data)
|
||||
}
|
||||
|
||||
// CallSelectService is a convenience method for setting select entity options.
|
||||
func (c *Connection) CallSelectService(entity, option string) error {
|
||||
domain, err := domain(entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := map[string]any{
|
||||
"entity_id": entity,
|
||||
"option": option,
|
||||
}
|
||||
|
||||
return c.CallService(domain, "select_option", data)
|
||||
}
|
||||
|
||||
// GetPhaseFloatStates retrieves three phase values (currents, voltages, etc.)
|
||||
func (c *Connection) GetPhaseFloatStates(entities []string) (float64, float64, float64, error) {
|
||||
if len(entities) != 3 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue