Innogy eBox: add energy and voltages (#14098)
This commit is contained in:
parent
f6ba78cd16
commit
634c655ff9
2 changed files with 147 additions and 18 deletions
|
|
@ -29,23 +29,25 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
igyRegID = 0 // Input
|
||||
igyRegSerial = 25 // Input
|
||||
igyRegProtocol = 50 // Input
|
||||
igyRegManufacturer = 100 // Input
|
||||
igyRegFirmware = 200 // Input
|
||||
igyRegStatus = 275 // Input
|
||||
igyRegCurrents = 1006 // current readings per phase
|
||||
igyRegID = 0 // Input
|
||||
igyRegSerial = 25 // Input
|
||||
igyRegProtocol = 50 // Input
|
||||
igyRegManufacturer = 100 // Input
|
||||
igyRegModbusTableVersion = 175 // Input
|
||||
igyRegFirmware = 200 // Input
|
||||
igyRegStatus = 275 // Input
|
||||
igyRegVoltages = 301 // Input
|
||||
igyRegEnergy = 307 // Input
|
||||
igyRegCurrents = 1006 // Input
|
||||
)
|
||||
|
||||
var igyRegMaxCurrents = []uint16{1012, 1014, 1016} // max current per phase
|
||||
|
||||
// https://www.innogy-emobility.com/content/dam/revu-global/emobility-solutions/neue-website-feb-2021/downloadcenter/digital-services/eld_instman_modbustcpde.pdf
|
||||
|
||||
// Innogy is an api.Charger implementation for Innogy eBox wallboxes.
|
||||
type Innogy struct {
|
||||
conn *modbus.Connection
|
||||
current float64
|
||||
conn *modbus.Connection
|
||||
curr float64
|
||||
hasVoltages bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
@ -62,9 +64,26 @@ func NewInnogyFromConfig(other map[string]interface{}) (api.Charger, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return NewInnogy(cc.URI, cc.ID)
|
||||
wb, err := NewInnogy(cc.URI, cc.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var totalEnergy func() (float64, error)
|
||||
var voltages func() (float64, float64, float64, error)
|
||||
|
||||
// check presence of energy meter & voltages registers
|
||||
if b, err := wb.conn.ReadInputRegisters(igyRegModbusTableVersion, 1); err == nil && binary.BigEndian.Uint16(b) >= 6 {
|
||||
totalEnergy = wb.totalEnergy
|
||||
voltages = wb.voltages
|
||||
wb.hasVoltages = true
|
||||
}
|
||||
|
||||
return decorateInnogy(wb, totalEnergy, voltages), nil
|
||||
}
|
||||
|
||||
//go:generate go run ../cmd/tools/decorate.go -f decorateInnogy -b *Innogy -r api.Charger -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)"
|
||||
|
||||
// NewInnogy creates a Innogy charger
|
||||
func NewInnogy(uri string, id uint8) (*Innogy, error) {
|
||||
conn, err := modbus.NewConnection(uri, "", "", 0, modbus.Tcp, id)
|
||||
|
|
@ -80,8 +99,8 @@ func NewInnogy(uri string, id uint8) (*Innogy, error) {
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Innogy{
|
||||
conn: conn,
|
||||
current: 6,
|
||||
conn: conn,
|
||||
curr: 6,
|
||||
}
|
||||
|
||||
return wb, nil
|
||||
|
|
@ -111,7 +130,7 @@ func (wb *Innogy) Enabled() (bool, error) {
|
|||
func (wb *Innogy) Enable(enable bool) error {
|
||||
var current float64
|
||||
if enable {
|
||||
current = wb.current
|
||||
current = wb.curr
|
||||
}
|
||||
|
||||
return wb.setCurrent(current)
|
||||
|
|
@ -145,7 +164,7 @@ func (wb *Innogy) MaxCurrentMillis(current float64) error {
|
|||
|
||||
err := wb.setCurrent(current)
|
||||
if err == nil {
|
||||
wb.current = current
|
||||
wb.curr = current
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
@ -159,8 +178,17 @@ func (wb *Innogy) CurrentPower() (float64, error) {
|
|||
if status, err := wb.Status(); status != api.StatusC || err != nil {
|
||||
return 0, err
|
||||
}
|
||||
l1, l2, l3, err := wb.Currents()
|
||||
return 230 * (l1 + l2 + l3), err
|
||||
|
||||
u1, u2, u3, err := wb.voltages()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i1, i2, i3, err := wb.Currents()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return u1*i1 + u2*i2 + u3*i3, nil
|
||||
}
|
||||
|
||||
var _ api.PhaseCurrents = (*Innogy)(nil)
|
||||
|
|
@ -180,6 +208,35 @@ func (wb *Innogy) Currents() (float64, float64, float64, error) {
|
|||
return res[0], res[1], res[2], nil
|
||||
}
|
||||
|
||||
// voltages implements the api.PhaseVoltages interface
|
||||
func (wb *Innogy) voltages() (float64, float64, float64, error) {
|
||||
if !wb.hasVoltages {
|
||||
return 230, 230, 230, nil
|
||||
}
|
||||
|
||||
b, err := wb.conn.ReadInputRegisters(igyRegVoltages, 6)
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
||||
var res [3]float64
|
||||
for i := range res {
|
||||
res[i] = float64(math.Float32frombits(binary.BigEndian.Uint32(b[4*i:])))
|
||||
}
|
||||
|
||||
return res[0], res[1], res[2], nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Innogy) totalEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(igyRegEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return float64(math.Float32frombits(binary.BigEndian.Uint32(b))), nil
|
||||
}
|
||||
|
||||
var _ api.Diagnosis = (*Innogy)(nil)
|
||||
|
||||
// Diagnose implements the api.Diagnosis interface
|
||||
|
|
@ -199,4 +256,7 @@ func (wb *Innogy) Diagnose() {
|
|||
if b, err := wb.conn.ReadInputRegisters(igyRegFirmware, 25); err == nil {
|
||||
fmt.Printf("Firmware:\t%s\n", b)
|
||||
}
|
||||
if b, err := wb.conn.ReadInputRegisters(igyRegModbusTableVersion, 1); err == nil {
|
||||
fmt.Printf("Modbus Table Version:\t%d\n", binary.BigEndian.Uint16(b))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
69
charger/innogy_decorators.go
Normal file
69
charger/innogy_decorators.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateInnogy(base *Innogy, meterEnergy func() (float64, error), phaseVoltages func() (float64, float64, float64, error)) api.Charger {
|
||||
switch {
|
||||
case meterEnergy == nil && phaseVoltages == nil:
|
||||
return base
|
||||
|
||||
case meterEnergy != nil && phaseVoltages == nil:
|
||||
return &struct {
|
||||
*Innogy
|
||||
api.MeterEnergy
|
||||
}{
|
||||
Innogy: base,
|
||||
MeterEnergy: &decorateInnogyMeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
}
|
||||
|
||||
case meterEnergy == nil && phaseVoltages != nil:
|
||||
return &struct {
|
||||
*Innogy
|
||||
api.PhaseVoltages
|
||||
}{
|
||||
Innogy: base,
|
||||
PhaseVoltages: &decorateInnogyPhaseVoltagesImpl{
|
||||
phaseVoltages: phaseVoltages,
|
||||
},
|
||||
}
|
||||
|
||||
case meterEnergy != nil && phaseVoltages != nil:
|
||||
return &struct {
|
||||
*Innogy
|
||||
api.MeterEnergy
|
||||
api.PhaseVoltages
|
||||
}{
|
||||
Innogy: base,
|
||||
MeterEnergy: &decorateInnogyMeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseVoltages: &decorateInnogyPhaseVoltagesImpl{
|
||||
phaseVoltages: phaseVoltages,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type decorateInnogyMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateInnogyMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateInnogyPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateInnogyPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue