Add go-e wallbox charger integration

- 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>
This commit is contained in:
2026-04-18 11:30:59 +02:00
parent 8295d1cf47
commit 62ffd06444
5 changed files with 135 additions and 16 deletions

37
main.go
View File

@@ -44,7 +44,7 @@ func main() {
defer meters.Close()
interval := time.Duration(cfg.SampleRate) * time.Second
go runPollLoop(ctx, alpha, meters, db, interval)
go runPollLoop(ctx, alpha, meters, cfg.Charger.Host, db, interval)
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
@@ -52,7 +52,7 @@ func main() {
logger.Println("shutting down")
}
func runPollLoop(ctx context.Context, alpha *AlphaEss, meters *MeterPoller, db *DB, interval time.Duration) {
func runPollLoop(ctx context.Context, alpha *AlphaEss, meters *MeterPoller, chargerHost string, db *DB, interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
@@ -60,22 +60,22 @@ func runPollLoop(ctx context.Context, alpha *AlphaEss, meters *MeterPoller, db *
case <-ctx.Done():
return
case <-ticker.C:
poll(ctx, alpha, meters, db)
poll(ctx, alpha, meters, chargerHost, db)
}
}
}
func poll(ctx context.Context, alpha *AlphaEss, meters *MeterPoller, db *DB) {
func poll(ctx context.Context, alpha *AlphaEss, meters *MeterPoller, chargerHost string, db *DB) {
t := time.Now()
// Poll AlphaEss and all SDM630 meters in parallel.
var (
inverterData *InverterData
meterData []MeterReading
wg sync.WaitGroup
inverterData *InverterData
meterData []MeterReading
chargerData *ChargerReading
wg sync.WaitGroup
)
wg.Add(2)
wg.Add(3)
go func() {
defer wg.Done()
d, err := alpha.Poll()
@@ -89,9 +89,21 @@ func poll(ctx context.Context, alpha *AlphaEss, meters *MeterPoller, db *DB) {
defer wg.Done()
meterData = meters.PollAll()
}()
go func() {
defer wg.Done()
if chargerHost == "" {
return
}
r, err := PollCharger(chargerHost)
if err != nil {
logger.Printf("charger: %v", err)
return
}
r.Time = t
chargerData = &r
}()
wg.Wait()
// Write everything with the same timestamp t.
if inverterData != nil {
if err := db.WriteInverter(ctx, t, inverterData); err != nil {
logger.Printf("write inverter: %v", err)
@@ -102,4 +114,9 @@ func poll(ctx context.Context, alpha *AlphaEss, meters *MeterPoller, db *DB) {
logger.Printf("write meter %s: %v", r.Device, err)
}
}
if chargerData != nil {
if err := db.WriteCharger(ctx, *chargerData); err != nil {
logger.Printf("write charger: %v", err)
}
}
}