Skip to content

Commit

Permalink
Add RFID support to enable charging on KEBA (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed May 17, 2020
1 parent 4a1c029 commit fe334e8
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 6 deletions.
5 changes: 5 additions & 0 deletions api/api.go
Expand Up @@ -50,6 +50,11 @@ type Charger interface {
MaxCurrent(current int64) error
}

// Diagnosis is a helper interface that allows to dump diagnostic data to console
type Diagnosis interface {
Diagnosis()
}

// ChargeTimer provides current charge cycle duration
type ChargeTimer interface {
ChargingTime() (time.Duration, error)
Expand Down
51 changes: 47 additions & 4 deletions charger/keba.go
Expand Up @@ -22,10 +22,16 @@ const (
kebaPort = "7090"
)

// RFID contains access credentials
type RFID struct {
Tag, Class string
}

// Keba is an api.Charger implementation with configurable getters and setters.
type Keba struct {
log *util.Logger
conn string
rfid RFID
timeout time.Duration
recv chan keba.UDPMsg
}
Expand All @@ -35,14 +41,17 @@ func NewKebaFromConfig(log *util.Logger, other map[string]interface{}) api.Charg
cc := struct {
URI string
Timeout time.Duration
}{}
RFID RFID
}{
RFID: RFID{Class: "00000000000000000000"}, // default class
}
util.DecodeOther(log, other, &cc)

return NewKeba(cc.URI, cc.Timeout)
return NewKeba(cc.URI, cc.RFID, cc.Timeout)
}

// NewKeba creates a new charger
func NewKeba(conn string, timeout time.Duration) api.Charger {
func NewKeba(conn string, rfid RFID, timeout time.Duration) api.Charger {
log := util.NewLogger("keba")

if keba.Instance == nil {
Expand All @@ -61,6 +70,7 @@ func NewKeba(conn string, timeout time.Duration) api.Charger {
c := &Keba{
log: log,
conn: conn,
rfid: rfid,
timeout: timeout,
recv: make(chan keba.UDPMsg),
}
Expand Down Expand Up @@ -152,10 +162,14 @@ func (c *Keba) Status() (api.ChargeStatus, error) {
return api.StatusA, err
}

if kr.AuthON == 1 && c.rfid.Tag == "" {
c.log.WARN.Println("missing credentials for RFID authorization")
}

if kr.Plug < 5 {
return api.StatusA, nil
}
if kr.State == 2 {
if kr.State == 2 || kr.State == 5 {
return api.StatusB, nil
}
if kr.State == 3 {
Expand All @@ -176,8 +190,29 @@ func (c *Keba) Enabled() (bool, error) {
return kr.EnableSys == 1 || kr.EnableUser == 1, nil
}

// enableRFID sends RFID credentials to enable charge
func (c *Keba) enableRFID() error {
var resp string
err := c.roundtrip(fmt.Sprintf("start %s %s", c.rfid.Tag, c.rfid.Class), 0, &resp)
if err != nil {
return err
}

if resp == keba.OK {
return nil
}

return fmt.Errorf("start unexpected response: %s", resp)
}

// Enable implements the Charger.Enable interface
func (c *Keba) Enable(enable bool) error {
if enable && c.rfid.Tag != "" {
if err := c.enableRFID(); err != nil {
return err
}
}

var d int
if enable {
d = 1
Expand Down Expand Up @@ -246,3 +281,11 @@ func (c *Keba) Currents() (float64, float64, float64, error) {
// 1mA to A
return float64(kr.I1) / 1e3, float64(kr.I2) / 1e3, float64(kr.I3) / 1e3, err
}

// Diagnosis implements the Diagnosis interface
func (c *Keba) Diagnosis() {
var kr keba.Report100
if err := c.roundtrip("report 100", 100, &kr); err == nil {
fmt.Printf("%+v\n", kr)
}
}
19 changes: 19 additions & 0 deletions charger/keba/reports.go
Expand Up @@ -58,3 +58,22 @@ type Report3 struct {
ETotal int64 `json:"E total"`
Sec int64 `json:"Sec"`
}

// Report100 is the report 100 command answer
type Report100 struct {
ID int `json:"ID,string"`
Serial string `json:"Serial"`
SessionID int64 `json:"SessionID"`
CurrHW int `json:"Curr HW"`
EStart int64 `json:"E start"`
EPres int64 `json:"E pres"`
Started string `json:"started"`
Ended string `json:"ended"`
StartedS int64 `json:"started[s]"`
EndedS int64 `json:"ended[s]"`
Reason int `json:"reason"`
TimeQ int `json:"timeQ"`
RFIDTag string `json:"RFID tag"`
RFIDClass string `json:"RFID class"`
Sec int64 `json:"Sec"`
}
5 changes: 5 additions & 0 deletions cmd/dump.go
Expand Up @@ -48,4 +48,9 @@ func dumpAPIs(v interface{}) {
fmt.Printf("Duration: %v\n", duration)
}
}

if v, ok := v.(api.Diagnosis); ok {
fmt.Println("Diagnostic dump:")
v.Diagnosis()
}
}
10 changes: 8 additions & 2 deletions evcc.dist.yaml
Expand Up @@ -110,17 +110,23 @@ chargers:
- name: evsewifi
type: evsewifi # Charger with Phoenix Contact controller
uri: http://192.168.1.4 # SimpleEVSE-Wifi address
- name: nrg
type: nrg # NRGKick charger
- name: nrg-1
type: nrgkick-connect # NRGKick Connect charger
ip: 192.168.1.4 # IP
macaddress: 00:99:22 # MAC address
password: # password
# - name: nrg-2
# type: nrgkick-bluetooth # NRGKick charger with Bluetooth
# macaddress: 00:99:22 # MAC address
# pin: # pin
- name: go-e
type: go-e # go-eCharger
uri: http://192.168.1.4 # go-e address
- name: keba
type: keba # KEBA charger
uri: 192.168.1.4:7090 # KEBA address
rfid:
tag: 765765348 # RFID tag, see `evcc charger` to show tag
- name: mcc
type: mcc # Mobile Charger Connect (Audi, Bentley, Porsche)
uri: https://192.168.1.4 # Mobile Charger Connect address
Expand Down

0 comments on commit fe334e8

Please sign in to comment.