KEBA: Add KeContact P40 models (#20860)

This commit is contained in:
Markus Breitenberger 2025-04-26 14:13:29 +02:00 • committed by GitHub
parent 142a3a5210
commit 7cd94aa187
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 45 additions and 14 deletions

View file

@ -34,12 +34,15 @@ import (
// https://www.keba.com/en/emobility/service-support/downloads/Downloads
// https://www.keba.com/download/x/dea7ae6b84/kecontactp30modbustcp_pgen.pdf
// https://www.keba.com/download/x/4a24e19f80/kecontactp40modbustcp_pgen.pdf
// Keba is an api.Charger implementation
type Keba struct {
*embed
log *util.Logger
conn *modbus.Connection
log *util.Logger
conn *modbus.Connection
current uint16
regEnable uint16
}
const (
@ -88,12 +91,14 @@ func NewKebaFromConfig(ctx context.Context, other map[string]interface{}) (api.C
return nil, err
}
// features
// optional features
var (
currentPower, totalEnergy func() (float64, error)
currents func() (float64, float64, float64, error)
identify func() (string, error)
reason func() (api.Reason, error)
phasesS func(int) error
phasesG func() (int, error)
)
b, err := wb.conn.ReadHoldingRegisters(kebaRegProduct, 2)
@ -101,22 +106,34 @@ func NewKebaFromConfig(ctx context.Context, other map[string]interface{}) (api.C
return nil, err
}
if features := binary.BigEndian.Uint32(b); (features/10)%10 > 0 {
productCodeStr := fmt.Sprintf("%d", binary.BigEndian.Uint32(b))
var hasEnergyMeter bool
var hasRFID bool
if len(productCodeStr) == 6 && productCodeStr[0] == '3' {
// P30
hasEnergyMeter = productCodeStr[4] != '0'
hasRFID = productCodeStr[5] == '1'
} else if len(productCodeStr) == 7 && productCodeStr[0] == '4' {
// P40
wb.regEnable = kebaRegMaxCurrent
hasEnergyMeter = productCodeStr[4] != '0'
hasRFID = productCodeStr[5] == '1'
}
if hasEnergyMeter {
currentPower = wb.currentPower
totalEnergy = wb.totalEnergy
currents = wb.currents
}
if features := binary.BigEndian.Uint32(b); features%10 > 0 {
if hasRFID {
identify = wb.identify
reason = wb.statusReason
}
// phases
var (
phasesS func(int) error
phasesG func() (int, error)
)
if b, err := wb.conn.ReadHoldingRegisters(kebaRegPhaseSource, 2); err == nil {
if source := binary.BigEndian.Uint32(b); source == 3 {
phasesS = wb.phases1p3p
@ -152,9 +169,10 @@ func NewKeba(ctx context.Context, embed embed, uri string, slaveID uint8) (*Keba
conn.Logger(log.TRACE)
wb := &Keba{
embed: &embed,
log: log,
conn: conn,
embed: &embed,
log: log,
conn: conn,
regEnable: kebaRegEnable,
}
return wb, err
@ -248,9 +266,14 @@ func (wb *Keba) Enabled() (bool, error) {
func (wb *Keba) Enable(enable bool) error {
var u uint16
if enable {
u = 1
if wb.regEnable == kebaRegMaxCurrent {
u = wb.current
} else {
u = 1
}
}
_, err := wb.conn.WriteSingleRegister(kebaRegEnable, u)
_, err := wb.conn.WriteSingleRegister(wb.regEnable, u)
return err
}
@ -265,6 +288,11 @@ var _ api.ChargerEx = (*Keba)(nil)
func (wb *Keba) MaxCurrentMillis(current float64) error {
u := uint16(current * 1000)
_, err := wb.conn.WriteSingleRegister(kebaRegMaxCurrent, u)
if err == nil {
wb.current = u
}
return err
}

View file

@ -3,6 +3,9 @@ products:
- brand: KEBA
description:
generic: KeContact P20, P30, C/X Series
- brand: KEBA
description:
generic: KeContact P40, P40 Pro
- brand: BMW
description:
generic: i Wallbox