Skip to content

Commit

Permalink
ABL: Add wakeup (evcc-io#2883)
Browse files Browse the repository at this point in the history
  • Loading branch information
premultiply authored Mar 15, 2022
1 parent 3d9be7b commit e6b3162
Showing 1 changed file with 65 additions and 29 deletions.
94 changes: 65 additions & 29 deletions charger/abl.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package charger
// LICENSE

// Copyright (c) 2019-2022 andig
// Copyright (c) 2022 premultiply

// This module is NOT covered by the MIT license. All rights reserved.

Expand All @@ -20,6 +21,7 @@ package charger
import (
"encoding/binary"
"fmt"
"time"

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
Expand All @@ -34,14 +36,16 @@ type ABLeMH struct {
}

const (
ablRegFirmware = 0x01
ablRegStatus = 0x04
ablRegEnabled = 0x0F
ablRegAmpsConfig = 0x14
ablRegStatusLong = 0x2E

ablAmpsDisabled uint16 = 0x03E8
ablSensorPresent = 1 << 5
ablRegFirmware = 0x01
ablRegStatus = 0x04
ablRegModifyState = 0x05
ablRegEnabled = 0x0F
ablRegAmpsConfig = 0x14
ablRegStatusLong = 0x2E

ablAmpsDisabled uint16 = 0x03E8

ablSensorPresent = 1 << 5
)

var ablStatus = map[byte]string{
Expand Down Expand Up @@ -108,8 +112,7 @@ func NewABLeMH(uri, device, comset string, baudrate int, slaveID uint8) (api.Cha
curr: uint16(6 / 0.06),
}

_, _ = wb.conn.ReadHoldingRegisters(ablRegFirmware, 2)
b, err := wb.conn.ReadHoldingRegisters(ablRegFirmware, 2)
b, err := wb.get(ablRegFirmware, 2)

// check presence of current sensor
if err == nil && (b[3]&ablSensorPresent != 0) {
Expand All @@ -119,10 +122,28 @@ func NewABLeMH(uri, device, comset string, baudrate int, slaveID uint8) (api.Cha
return wb, err
}

func (wb *ABLeMH) set(reg, val uint16) error {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, val)

//write two times
_, _ = wb.conn.WriteMultipleRegisters(reg, 1, b)
_, err := wb.conn.WriteMultipleRegisters(reg, 1, b)

return err
}

func (wb *ABLeMH) get(reg, count uint16) ([]byte, error) {
//read two times
_, _ = wb.conn.ReadHoldingRegisters(reg, count)
b, err := wb.conn.ReadHoldingRegisters(reg, count)

return b, err
}

// Status implements the api.Charger interface
func (wb *ABLeMH) Status() (api.ChargeStatus, error) {
_, _ = wb.conn.ReadHoldingRegisters(ablRegStatus, 1)
b, err := wb.conn.ReadHoldingRegisters(ablRegStatus, 1)
b, err := wb.get(ablRegStatus, 1)
if err != nil {
return api.StatusNone, err
}
Expand All @@ -144,8 +165,7 @@ func (wb *ABLeMH) Status() (api.ChargeStatus, error) {

// Enabled implements the api.Charger interface
func (wb *ABLeMH) Enabled() (bool, error) {
_, _ = wb.conn.ReadHoldingRegisters(ablRegEnabled, 5)
b, err := wb.conn.ReadHoldingRegisters(ablRegEnabled, 5)
b, err := wb.get(ablRegEnabled, 5)
if err != nil {
return false, err
}
Expand All @@ -161,32 +181,35 @@ func (wb *ABLeMH) Enable(enable bool) error {
u = wb.curr
}

b := make([]byte, 2)
binary.BigEndian.PutUint16(b, u)

_, _ = wb.conn.WriteMultipleRegisters(ablRegAmpsConfig, 1, b)
_, err := wb.conn.WriteMultipleRegisters(ablRegAmpsConfig, 1, b)
err := wb.set(ablRegAmpsConfig, u)

return err
}

// MaxCurrent implements the api.Charger interface
func (wb *ABLeMH) MaxCurrent(current int64) error {
if current < 6 {
return fmt.Errorf("invalid current %d", current)
}

return wb.MaxCurrentMillis(float64(current))
}

var _ api.ChargerEx = (*ABLeMH)(nil)

// MaxCurrent implements the api.ChargerEx interface
func (wb *ABLeMH) MaxCurrentMillis(current float64) error {
// calculate duty cycle according to https://www.goingelectric.de/forum/viewtopic.php?p=1575287#p1575287
wb.curr = uint16(current / 0.06)
if current < 6 {
return fmt.Errorf("invalid current %.1f", current)
}

b := make([]byte, 2)
binary.BigEndian.PutUint16(b, wb.curr)
// calculate duty cycle according to https://www.goingelectric.de/forum/viewtopic.php?p=1575287#p1575287
cur := uint16(current / 0.06)

_, _ = wb.conn.WriteMultipleRegisters(ablRegAmpsConfig, 1, b)
_, err := wb.conn.WriteMultipleRegisters(ablRegAmpsConfig, 1, b)
err := wb.set(ablRegAmpsConfig, cur)
if err == nil {
wb.curr = cur
}

return err
}
Expand All @@ -199,8 +222,7 @@ func (wb *ABLeMH) currentPower() (float64, error) {

// Currents implements the api.MeterCurrent interface
func (wb *ABLeMH) currents() (float64, float64, float64, error) {
_, _ = wb.conn.ReadHoldingRegisters(ablRegStatusLong, 5)
b, err := wb.conn.ReadHoldingRegisters(ablRegStatusLong, 5)
b, err := wb.get(ablRegStatusLong, 5)
if err != nil {
return 0, 0, 0, err
}
Expand All @@ -222,9 +244,23 @@ var _ api.Diagnosis = (*ABLeMH)(nil)

// Diagnose implements the api.Diagnosis interface
func (wb *ABLeMH) Diagnose() {
_, _ = wb.conn.ReadHoldingRegisters(ablRegFirmware, 2)
b, err := wb.conn.ReadHoldingRegisters(ablRegFirmware, 2)
b, err := wb.get(ablRegFirmware, 2)
if err == nil {
fmt.Printf("Firmware: %0 x\n", b)
}
}

var _ api.AlarmClock = (*ABLeMH)(nil)

// WakeUp implements the api.AlarmClock interface
func (wb *ABLeMH) WakeUp() error {
// temporary jump to status E0 (Outlet disabled)
err := wb.set(ablRegModifyState, 0xE0E0)
if err == nil {
time.Sleep(3 * time.Second)
// jump back to state A1 (Waiting for EV)
err = wb.set(ablRegModifyState, 0xA1A1)
}

return err
}

0 comments on commit e6b3162

Please sign in to comment.