Skip to content

Commit

Permalink
Read grid and charge meter currents (evcc-io#272)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig authored Aug 9, 2020
1 parent 12cb576 commit 0922bc7
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 15 deletions.
26 changes: 16 additions & 10 deletions core/loadpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,21 @@ func (lp *LoadPoint) updateChargerStatus() error {

// detectPhases uses MeterCurrent interface to count phases with current >=1A
func (lp *LoadPoint) detectPhases() {
if phaseMeter, ok := lp.chargeMeter.(api.MeterCurrent); ok {
i1, i2, i3, err := phaseMeter.Currents()
if err != nil {
lp.log.ERROR.Printf("charge meter error: %v", err)
return
}
phaseMeter, ok := lp.chargeMeter.(api.MeterCurrent)
if !ok {
return
}

i1, i2, i3, err := phaseMeter.Currents()
if err != nil {
lp.log.ERROR.Printf("charge meter error: %v", err)
return
}

lp.log.TRACE.Printf("charge currents: %vA", []float64{i1, i2, i3})
lp.publish("chargeCurrents", []float64{i1, i2, i3})

if lp.charging {
var phases int64
for _, i := range []float64{i1, i2, i3} {
if i >= minActiveCurrent {
Expand Down Expand Up @@ -630,10 +638,8 @@ func (lp *LoadPoint) Update(sitePower float64) {
lp.handler.SyncEnabled()
}

// phase detection - run only when actually charging
if lp.charging {
lp.detectPhases()
}
// phase detection
lp.detectPhases()

// check if car connected and ready for charging
var err error
Expand Down
9 changes: 9 additions & 0 deletions core/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,15 @@ func (site *Site) updateMeters() error {
err = retryMeter("battery", site.batteryMeter, &site.batteryPower)
}

// currents
if phaseMeter, ok := site.gridMeter.(api.MeterCurrent); err == nil && ok {
i1, i2, i3, err := phaseMeter.Currents()
if err == nil {
site.log.TRACE.Printf("grid currents: %vA", []float64{i1, i2, i3})
site.publish("gridCurrents", []float64{i1, i2, i3})
}
}

return err
}

Expand Down
43 changes: 39 additions & 4 deletions server/influxdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ func NewInfluxClient(url, token, org, user, password, database string) *Influx {
}
}

// supportedType checks if type can be written as influx value
func (m *Influx) supportedType(p util.Param) bool {
if p.Val == nil {
return true
}

switch val := p.Val.(type) {
case float64:
return true
case [3]float64:
return true
case []float64:
return len(val) == 3
default:
return false
}
}

// Run Influx publisher
func (m *Influx) Run(loadPoints []*core.LoadPoint, in <-chan util.Param) {
writer := m.client.WriteApi(m.org, m.database)
Expand All @@ -62,8 +80,7 @@ func (m *Influx) Run(loadPoints []*core.LoadPoint, in <-chan util.Param) {

// add points to batch for async writing
for param := range in {
// allow nil value to be written as series gaps
if _, ok := param.Val.(float64); param.Val != nil && !ok {
if !m.supportedType(param) {
continue
}

Expand All @@ -72,10 +89,28 @@ func (m *Influx) Run(loadPoints []*core.LoadPoint, in <-chan util.Param) {
tags["loadpoint"] = loadPoints[*param.LoadPoint].Name()
}

fields := map[string]interface{}{
"value": param.Val,
fields := map[string]interface{}{}

// array to slice
val := param.Val
if v, ok := val.([3]float64); ok {
val = v[:]
}

// add slice as phase values
if phases, ok := val.([]float64); ok {
var total float64
for i, v := range phases {
total += v
fields[fmt.Sprintf("l%d", i+1)] = v
}

// add total as "value"
val = total
}

fields["value"] = val

// write asynchronously
m.log.TRACE.Printf("write %s=%v (%v)", param.Key, param.Val, tags)
p := influxdb2.NewPoint(param.Key, tags, fields, time.Now())
Expand Down
18 changes: 17 additions & 1 deletion server/mqtt.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,27 @@ func (m *MQTT) encode(v interface{}) string {
return s
}

func (m *MQTT) publish(topic string, retained bool, payload interface{}) {
func (m *MQTT) publishSingleValue(topic string, retained bool, payload interface{}) {
token := m.Handler.Client.Publish(topic, m.Handler.Qos, retained, m.encode(payload))
go m.Handler.WaitForToken(token)
}

func (m *MQTT) publish(topic string, retained bool, payload interface{}) {
if slice, ok := payload.([]float64); ok && len(slice) == 3 {
// publish phase values
var total float64
for i, v := range slice {
total += v
m.publishSingleValue(fmt.Sprintf("%s/l%d", topic, i+1), retained, v)
}

// publish sum value
payload = total
}

m.publishSingleValue(topic, retained, payload)
}

type apiHandler interface {
SetMode(api.ChargeMode)
SetTargetSoC(int)
Expand Down

0 comments on commit 0922bc7

Please sign in to comment.