diff --git a/charger/abb.go b/charger/abb.go index f8c43380a..7707d4ac9 100644 --- a/charger/abb.go +++ b/charger/abb.go @@ -2,7 +2,7 @@ package charger // LICENSE -// Copyright (c) 2022 premultiply +// Copyright (c) 2022 premultiply, andig // This module is NOT covered by the MIT license. All rights reserved. @@ -45,7 +45,10 @@ const ( abbRegPower = 0x401C // Active power 2 1 W unsigned RO available abbRegEnergy = 0x401E // Energy delivered in charging session 2 1 Wh unsigned RO available abbRegSetCurrent = 0x4100 // Set charging current limit 2 0.001 A unsigned WO available - abbRegPhases = 0x4102 // Set charging phase 1 unsigned WO Not support + // abbRegSession = 0x4105 // Start/Stop Charging Session 1 unsigned WO available + // abbRegPhases = 0x4102 // Set charging phase 1 unsigned WO Not supported + + abbMinCurrent = 0x1AE0 // 5920 mA ) func init() { @@ -84,21 +87,40 @@ func NewABB(uri, device, comset string, baudrate int, slaveID uint8) (api.Charge wb := &ABB{ log: log, conn: conn, - curr: 6000, // assume min current + curr: abbMinCurrent, // assume min current } return wb, err } +func (wb *ABB) status() (byte, error) { + b, err := wb.conn.ReadHoldingRegisters(abbRegStatus, 2) + if err != nil { + return 0, err + } + + wb.log.DEBUG.Printf("status: %d", b[2]&0x7f) + + return b[2] & 0x7f, nil +} + +func (wb *ABB) session() (bool, error) { + s, err := wb.status() + if err != nil || s == 0 || s == 5 { // ToDo: check if 1 is active/inactive/unknown + return false, err + } + + return true, err +} + // Status implements the api.Charger interface func (wb *ABB) Status() (api.ChargeStatus, error) { - b, err := wb.conn.ReadHoldingRegisters(abbRegStatus, 2) + s, err := wb.status() if err != nil { return api.StatusNone, err } - // A1 - Charging - switch s := b[2] & 0x7f; s { + switch s { case 0: // State A: Idle return api.StatusA, nil case 1: // State B1: EV Plug in, pending authorization @@ -109,6 +131,8 @@ func (wb *ABB) Status() (api.ChargeStatus, error) { return api.StatusB, nil case 4: // State C2: Charging Contact closed, energy delivering return api.StatusC, nil + case 5: // Other: Session stopped + return api.StatusA, nil default: // Other return api.StatusNone, fmt.Errorf("invalid status: %0x", s) } @@ -116,31 +140,34 @@ func (wb *ABB) Status() (api.ChargeStatus, error) { // Enabled implements the api.Charger interface func (wb *ABB) Enabled() (bool, error) { + s, err := wb.session() + if err != nil || !s { + return false, err + } + b, err := wb.conn.ReadHoldingRegisters(abbRegGetCurrent, 2) if err != nil { return false, err } - return binary.BigEndian.Uint32(b) != 0, nil + return binary.BigEndian.Uint32(b) >= abbMinCurrent, nil } // Enable implements the api.Charger interface func (wb *ABB) Enable(enable bool) error { - var curr uint32 - if enable { - curr = wb.curr + s, err := wb.session() + if err != nil || !s { + return err } - return wb.setCurrent(curr) -} + var current uint32 + if enable { + current = wb.curr + } -// MaxCurrent implements the api.Charger interface -func (wb *ABB) MaxCurrent(current int64) error { - return wb.MaxCurrentMillis(float64(current)) + return wb.setCurrent(current) } -var _ api.ChargerEx = (*ABB)(nil) - // setCurrent writes the current limit in mA func (wb *ABB) setCurrent(current uint32) error { b := make([]byte, 4) @@ -150,16 +177,27 @@ func (wb *ABB) setCurrent(current uint32) error { return err } +// MaxCurrent implements the api.Charger interface +func (wb *ABB) MaxCurrent(current int64) error { + return wb.MaxCurrentMillis(float64(current)) +} + +var _ api.ChargerEx = (*ABB)(nil) + // MaxCurrent implements the api.ChargerEx interface func (wb *ABB) MaxCurrentMillis(current float64) error { - curr := uint32(current * 1e3) - - err := wb.setCurrent(curr) - if err == nil { - wb.curr = curr + if current < 6 { + return fmt.Errorf("invalid current %.1f", current) } - return err + s, err := wb.session() + if err != nil || !s { + return err + } + + wb.curr = uint32(current * 1e3) + + return wb.setCurrent(wb.curr) } var _ api.Meter = (*ABB)(nil) @@ -197,24 +235,24 @@ func (wb *ABB) Currents() (float64, float64, float64, error) { var curr [3]float64 for l := 0; l < 3; l++ { - curr[l] = float64(binary.BigEndian.Uint32(b[4*l:4*(l+1)])) / 1e3 + curr[l] = float64(binary.BigEndian.Uint32(b[4*l:])) / 1e3 } return curr[0], curr[1], curr[2], nil } -var _ api.ChargePhases = (*ABB)(nil) +// var _ api.ChargePhases = (*ABB)(nil) -// Phases1p3p implements the api.ChargePhases interface -func (wb *ABB) Phases1p3p(phases int) error { - var b uint16 = 1 - if phases != 1 { - b = 2 // 3p - } +// // Phases1p3p implements the api.ChargePhases interface +// func (wb *ABB) Phases1p3p(phases int) error { +// var b uint16 = 1 +// if phases != 1 { +// b = 2 // 3p +// } - _, err := wb.conn.WriteSingleRegister(abbRegPhases, b) - return err -} +// _, err := wb.conn.WriteSingleRegister(abbRegPhases, b) +// return err +// } var _ api.Diagnosis = (*ABB)(nil) @@ -229,6 +267,12 @@ func (wb *ABB) Diagnose() { if b, err := wb.conn.ReadHoldingRegisters(abbRegMaxRated, 2); err == nil { fmt.Printf("\tMax rated current:\t%.1fA\n", float32(binary.BigEndian.Uint32(b))/1e3) } + if b, err := wb.conn.ReadHoldingRegisters(abbRegGetCurrent, 2); err == nil { + fmt.Printf("\tCharging current limit:\t%.1fA\n", float32(binary.BigEndian.Uint32(b))/1e3) + } + if b, err := wb.conn.ReadHoldingRegisters(abbRegStatus, 2); err == nil { + fmt.Printf("\tStatus:\t%x\n", b) + } if b, err := wb.conn.ReadHoldingRegisters(abbRegErrorCode, 2); err == nil { fmt.Printf("\tError code:\t%x\n", binary.BigEndian.Uint32(b)) } diff --git a/templates/definition/charger/abb.yaml b/templates/definition/charger/abb.yaml index d602afdda..10da68936 100644 --- a/templates/definition/charger/abb.yaml +++ b/templates/definition/charger/abb.yaml @@ -3,7 +3,7 @@ products: - brand: ABB description: generic: Terra AC -capabilities: ["1p3p", "mA"] +capabilities: ["mA"] requirements: evcc: ["sponsorship"] params: diff --git a/templates/docs/charger/abb_0.yaml b/templates/docs/charger/abb_0.yaml index a5fee146f..ce4c9f301 100644 --- a/templates/docs/charger/abb_0.yaml +++ b/templates/docs/charger/abb_0.yaml @@ -1,7 +1,7 @@ product: brand: ABB description: Terra AC -capabilities: ["1p3p", "mA"] +capabilities: ["mA"] requirements: ["sponsorship"] render: - default: |