diff --git a/api/api.go b/api/api.go index a6e4ab886c..3857f09ea6 100644 --- a/api/api.go +++ b/api/api.go @@ -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) diff --git a/charger/keba.go b/charger/keba.go index cb4f9d37b0..6c6b924edf 100644 --- a/charger/keba.go +++ b/charger/keba.go @@ -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 } @@ -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 { @@ -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), } @@ -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 { @@ -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 @@ -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) + } +} diff --git a/charger/keba/reports.go b/charger/keba/reports.go index 50ed4aeb3b..246f9e0857 100644 --- a/charger/keba/reports.go +++ b/charger/keba/reports.go @@ -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"` +} diff --git a/cmd/dump.go b/cmd/dump.go index 548c4f4a08..70d97f1573 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -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() + } } diff --git a/evcc.dist.yaml b/evcc.dist.yaml index 77bc62c129..4932271177 100644 --- a/evcc.dist.yaml +++ b/evcc.dist.yaml @@ -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