- charger.go: polls go-e /api/status?filter=nrg,eto every 10 s - db.go: WriteCharger() inserts into charger hypertable - config.go: ChargerConf with host field - main.go: polls charger in parallel with inverter and meters - schema.sql: charger table + charger_10m/1h/daily aggregates + policies Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
44 lines
989 B
Go
44 lines
989 B
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
type ChargerReading struct {
|
|
Time time.Time
|
|
Power float32 // W total
|
|
EtoWh int64 // Wh cumulative
|
|
}
|
|
|
|
type chargerStatus struct {
|
|
Nrg []float64 `json:"nrg"` // [0..15] voltages/currents/powers; [11] = total W
|
|
Eto int64 `json:"eto"` // cumulative Wh
|
|
}
|
|
|
|
var chargerClient = &http.Client{Timeout: 5 * time.Second}
|
|
|
|
func PollCharger(host string) (ChargerReading, error) {
|
|
url := "http://" + host + "/api/status?filter=nrg,eto"
|
|
resp, err := chargerClient.Get(url)
|
|
if err != nil {
|
|
return ChargerReading{}, fmt.Errorf("get: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var s chargerStatus
|
|
if err := json.NewDecoder(resp.Body).Decode(&s); err != nil {
|
|
return ChargerReading{}, fmt.Errorf("decode: %w", err)
|
|
}
|
|
if len(s.Nrg) < 12 {
|
|
return ChargerReading{}, fmt.Errorf("nrg array too short (%d)", len(s.Nrg))
|
|
}
|
|
return ChargerReading{
|
|
Time: time.Now(),
|
|
Power: float32(s.Nrg[11]),
|
|
EtoWh: s.Eto,
|
|
}, nil
|
|
}
|