Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for EM2GO chargers #7099

Merged
merged 5 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 78 additions & 21 deletions charger/em2go.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,32 @@ type Em2Go struct {
}

const (
em2GoRegStatus = 0
em2GoRegCurrents = 6
em2GoRegPower = 12
em2GoRegEnergy = 28
em2GoRegCurrent = 32
em2GoRegSerial = 38
em2GoRegChargedEnergy = 72
em2GoRegChargeDuration = 78
em2GoRegChargeMode = 93
em2GoRegChargeCommand = 95
em2GoRegStatus = 0 // Uint16 RO ENUM
em2goRegConnectorState = 2 // Uint16 RO ENUM
em2goRegErrorCode = 4 // Uint16 RO ENUM
em2GoRegCurrents = 6 // 3xUint16 RO 0.1A
em2GoRegPower = 12 // Uint32 RO 1W
em2GoRegPowers = 16 // 3xUint16 RO 1W
em2GoRegEnergy = 28 // Uint16 RO 0.1KWh
em2GoRegMaxCurrent = 32 // Uint16 RO 0.1A
em2GoRegMinCurrent = 34 // Uint16 RO 0.1A
em2goRegCableMaxCurrent = 36 // Uint16 RO 0.1A
em2GoRegSerial = 38 // Chr[16] RO UTF16
em2GoRegChargedEnergy = 72 // Uint16 RO 0.1kWh
em2GoRegChargeDuration = 78 // Uint32 RO 1s
em2goRegSafeCurrent = 87 // Uint16 WR 0.1A
em2goRegCommTimeout = 89 // Uint16 WR 1s
em2goRegCurrentLimit = 91 // Uint16 WR 0.1A
em2GoRegChargeMode = 93 // Uint16 WR ENUM
em2GoRegChargeCommand = 95 // Uint16 WR ENUM
em2goRegVoltages = 109 // 3xUint16 RO 0.1V
)

func init() {
registry.Add("em2go", NewEm2GoFromConfig)
}

// NewEm2GoFromConfig creates a Mennekes Em2Go charger from generic config
// NewEm2GoFromConfig creates a Em2Go charger from generic config
func NewEm2GoFromConfig(other map[string]interface{}) (api.Charger, error) {
cc := modbus.TcpSettings{
ID: 0xff,
Expand Down Expand Up @@ -105,8 +114,10 @@ func (wb *Em2Go) Status() (api.ChargeStatus, error) {
return api.StatusA, nil
case 2, 3:
return api.StatusB, nil
case 4:
case 4, 6:
return api.StatusC, nil
case 5, 7:
return api.StatusF, nil
default:
return api.StatusNone, fmt.Errorf("invalid status: %0x", b[1])
}
Expand Down Expand Up @@ -145,7 +156,7 @@ func (wb *Em2Go) MaxCurrentMillis(current float64) error {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, uint16(10*current))

_, err := wb.conn.WriteMultipleRegisters(em2GoRegCurrent, 1, b)
_, err := wb.conn.WriteMultipleRegisters(em2goRegCurrentLimit, 1, b)
return err
}

Expand All @@ -170,21 +181,35 @@ func (wb *Em2Go) TotalEnergy() (float64, error) {
return 0, err
}

return rs485.RTUUint32ToFloat64(b) / 10, nil
return float64(binary.BigEndian.Uint16(b)) / 10, nil
}

var _ api.PhaseCurrents = (*Em2Go)(nil)

// Currents implements the api.MeterCurrent interface
// Currents implements the api.PhaseCurrents interface
func (wb *Em2Go) Currents() (float64, float64, float64, error) {
b, err := wb.conn.ReadHoldingRegisters(em2GoRegCurrents, 3)
b, err := wb.conn.ReadHoldingRegisters(em2GoRegCurrents, 6)
if err != nil {
return 0, 0, 0, err
}

return float64(binary.BigEndian.Uint16(b)) / 10,
float64(binary.BigEndian.Uint16(b[2:])) / 10,
float64(binary.BigEndian.Uint16(b[4:])) / 10, nil
float64(binary.BigEndian.Uint16(b[4:])) / 10,
float64(binary.BigEndian.Uint16(b[8:])) / 10, nil
}

var _ api.PhaseVoltages = (*Em2Go)(nil)

// Currents implements the api.PhaseVoltages interface
func (wb *Em2Go) Voltages() (float64, float64, float64, error) {
b, err := wb.conn.ReadHoldingRegisters(em2goRegVoltages, 6)
if err != nil {
return 0, 0, 0, err
}

return float64(binary.BigEndian.Uint16(b)) / 10,
float64(binary.BigEndian.Uint16(b[4:])) / 10,
float64(binary.BigEndian.Uint16(b[8:])) / 10, nil
}

var _ api.ChargeRater = (*Em2Go)(nil)
Expand All @@ -196,7 +221,7 @@ func (wb *Em2Go) ChargedEnergy() (float64, error) {
return 0, err
}

return rs485.RTUUint32ToFloat64(b) / 10, nil
return float64(binary.BigEndian.Uint16(b)) / 10, nil
}

var _ api.ChargeTimer = (*Em2Go)(nil)
Expand All @@ -215,6 +240,24 @@ var _ api.Diagnosis = (*Em2Go)(nil)

// Diagnose implements the api.Diagnosis interface
func (wb *Em2Go) Diagnose() {
if b, err := wb.conn.ReadHoldingRegisters(em2GoRegStatus, 1); err == nil {
fmt.Printf("\tCharging Station Status:\t%d\n", binary.BigEndian.Uint16(b))
}
if b, err := wb.conn.ReadHoldingRegisters(em2goRegConnectorState, 1); err == nil {
fmt.Printf("\tConnector State:\t%d\n", binary.BigEndian.Uint16(b))
}
if b, err := wb.conn.ReadHoldingRegisters(em2goRegErrorCode, 1); err == nil {
fmt.Printf("\tError Code:\t%d\n", binary.BigEndian.Uint16(b))
}
if b, err := wb.conn.ReadHoldingRegisters(em2GoRegMaxCurrent, 1); err == nil {
fmt.Printf("\tEVSE Max. Current:\t%.1fA\n", float64(binary.BigEndian.Uint16(b)/10))
}
if b, err := wb.conn.ReadHoldingRegisters(em2GoRegMaxCurrent, 1); err == nil {
fmt.Printf("\tEVSE Min. Current:\t%.1fA\n", float64(binary.BigEndian.Uint16(b)/10))
}
if b, err := wb.conn.ReadHoldingRegisters(em2goRegCableMaxCurrent, 1); err == nil {
fmt.Printf("\tCable Max. Current:\t%.1fA\n", float64(binary.BigEndian.Uint16(b)/10))
}
var serial []byte
for reg := 0; reg < 8; reg++ {
b, err := wb.conn.ReadHoldingRegisters(em2GoRegSerial+2*uint16(reg), 2)
Expand All @@ -223,6 +266,20 @@ func (wb *Em2Go) Diagnose() {
}
serial = append(serial, b...)
}

fmt.Printf("Serial: %s\n", string(serial))
fmt.Printf("\tSerial: %s\n", string(serial))
if b, err := wb.conn.ReadHoldingRegisters(em2goRegSafeCurrent, 1); err == nil {
fmt.Printf("\tSafe Current:\t%.1fA\n", float64(binary.BigEndian.Uint16(b)/10))
}
if b, err := wb.conn.ReadHoldingRegisters(em2goRegCommTimeout, 1); err == nil {
fmt.Printf("\tConnection Timeout:\t%d\n", binary.BigEndian.Uint16(b))
}
if b, err := wb.conn.ReadHoldingRegisters(em2goRegCurrentLimit, 1); err == nil {
fmt.Printf("\tCurrent Limit:\t%.1fA\n", float64(binary.BigEndian.Uint16(b)/10))
}
if b, err := wb.conn.ReadHoldingRegisters(em2GoRegChargeMode, 1); err == nil {
fmt.Printf("\tCharge Mode:\t%d\n", binary.BigEndian.Uint16(b))
}
if b, err := wb.conn.ReadHoldingRegisters(em2GoRegChargeCommand, 1); err == nil {
fmt.Printf("\tCharge Command:\t%d\n", binary.BigEndian.Uint16(b))
}
}
11 changes: 8 additions & 3 deletions templates/definition/charger/em2go.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
template: em2go
products:
- brand: D-Parts
- brand: EM2GO
description:
generic: Em2Go
generic: Pro Power/OCPP/ONC
capabilities: ["mA", "rfid"]
requirements:
description:
de: Für die Nutzung mit evcc muss die Wallbox mit einer aktuellen Firmware mit Modbus-Unterstützung betrieben werden. Bitte mit dem Hersteller abklären.
en: For use with evcc, the wallbox must be operated with a recent firmware including Modbus support. Please contact vendor.
params:
- name: modbus
choice: ["tcpip"]
id: 255
render: |
type: em2go
{{- include "modbus" . }}
{{- include "modbus" . }}
9 changes: 5 additions & 4 deletions templates/docs/charger/em2go_0.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
product:
brand: D-Parts
description: Em2Go
brand: EM2GO
description: Pro Power/OCPP/ONC
capabilities: ["mA", "rfid"]
render:
- default: |
type: template
template: em2go
template: em2go

# Modbus TCP
modbus: tcpip
id: 255
host: 192.0.2.2 # Hostname
port: 502 # Port
port: 502 # Port
2 changes: 1 addition & 1 deletion templates/evcc.io/brands.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
"Bender",
"BMW",
"cFos",
"D-Parts",
"Dadapower",
"DaheimLaden",
"E.ON Drive",
"Easee",
"Ebee",
"echarge",
"Elli",
"EM2GO",
"Ensto",
"Etrel",
"EVBox",
Expand Down