Skip to content

wifievangelist/goodwe-local-monitor

Repository files navigation

goodwe-local-monitor

A fully local, cloud-independent monitoring system for GoodWe GW9.99K-EH solar inverters with Lynx F G2 battery storage and myenergi Zappi EV charger.

Polls 145+ inverter sensors every 30 seconds via Modbus TCP, stores data in InfluxDB, and serves a production-grade React dashboard over HTTPS — with no dependency on GoodWe SEMS cloud.

Screenshots

Live PowerFlow Live Stat Cards
Live — PowerFlow & stats panel Live — Sensor stat cards
History Energy
History — 7-day power chart Energy — kWh totals & self-sufficiency
Battery Warranty Sankey Flow
Energy — Battery warranty tracker Flow — Sankey energy diagram
Bill Schedule
Bill — ZeroHero VPP breakdown Schedule — Inverter scheduling
AI Chat Alarms
AI Chat — Gemini with live data Alarms — System health monitoring

Features

  • Real-time power flow — animated diagram with solar, grid, battery, house, and EV
  • 145+ live sensors — PV strings, battery cells, grid/AC, temperatures
  • Configurable poll interval — 1s to 60min, changed in UI without restart
  • ZeroHero VPP billing — GloBird ZEROCHARGE free window, Super Export 6–9pm tracker, $1/day credit monitor
  • TOU billing — per-tier kWh and cost breakdown with CT meter accuracy
  • Battery scheduling with:
    • SOC conditions (min/max to start)
    • kWh energy limits with per-day reset
    • Dynamic discharge — auto-adjusts power % to pace toward target SOC at window end
    • Immediate charge — uses inverter immediate charge registers to force grid charging regardless of solar
  • AI Chat — Gemini 2.5 Flash with function calling (optional)
  • Sankey flow diagram, historical charts, bill calculator
  • Battery warranty tracker — MWh throughput vs warranty ceiling
  • HTTPS — Let's Encrypt DNS-01 via AWS Route 53, auto-renewing

Hardware Compatibility

Component Tested Model Notes
Inverter GoodWe GW9.99K-EH (EHB-AU-G11) Firmware 050531. Other GoodWe Modbus inverters may work.
Battery Lynx F G2 — 38.4 kWh (2×6×3.2 kWh)
EV Charger myenergi Zappi Via myenergi cloud API
Protocol Modbus TCP port 502, slave 0xF7 (247)

Note: goodwe Python library is version-locked at 0.4.9. Do not upgrade.


Stack

Service Technology Port
Database InfluxDB 2.7 8086 (internal)
Collector Python + goodwe==0.4.9
Backend FastAPI 8000 (internal)
Frontend React + Vite + Tailwind + nginx 80 → 443
TLS Certbot + Route 53 DNS-01

Prerequisites

  • Linux VM (Ubuntu 22.04+), 2 GB RAM minimum
  • Docker + Docker Compose
  • Domain hosted on AWS Route 53 (for Let's Encrypt DNS-01)
  • GoodWe inverter reachable on port 502

Install Docker (Ubuntu)

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER && newgrp docker

Setup

1. Clone

git clone https://github.com/yourusername/goodwe-local-monitor.git
cd goodwe-local-monitor

2. Configure

cp .env.example .env
nano .env
Variable Description
INFLUX_TOKEN Random secret — openssl rand -hex 32
DOMAIN Your domain e.g. goodwe.yourdomain.com
CERTBOT_EMAIL Email for Let's Encrypt
AWS_ACCESS_KEY_ID Route 53 IAM key
AWS_SECRET_ACCESS_KEY Route 53 IAM secret
AUTH_USER Dashboard username (default: admin)
AUTH_PASS_SHA SHA-256 of password — echo -n "pass" | sha256sum
SESSION_SECRET Random secret — openssl rand -hex 32
GEMINI_API_KEY Optional — enables AI Chat tab

3. DNS

Create an A record: goodwe.yourdomain.com → <VM local IP>

Let's Encrypt verifies via DNS TXT record — VM does not need to be internet-reachable.

4. AWS IAM Policy

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "route53:GetChange",
      "route53:ChangeResourceRecordSets",
      "route53:ListHostedZones",
      "route53:ListResourceRecordSets"
    ],
    "Resource": "*"
  }]
}

5. Start

sudo docker compose up -d
sudo docker compose logs -f certbot   # watch cert issuance (~60s)

Open https://goodwe.yourdomain.com — setup wizard will guide you through inverter IP and tariff configuration.


Scheduling

Example: ZeroHero Super Export 6–9pm

bat_power_percent: 100
dynamic_discharge: true
target_end_soc: 60
min_soc_to_start: 60
grid_export: Enable
export_kwh_limit: 15.5

Example: Free Charge during ZEROCHARGE window (11am–2pm)

bat_power_percent: -100
immediate_charge: true
immediate_charge_power: 20

⚠️ immediate_charge_power is non-linear on GW9.99K-EH firmware. With a 40A single-phase breaker (9.2 kW max), 20% ≈ 7 kW battery charge — safe with typical 4–6 kW house load. Adjust for your breaker.


Modbus Register Reference

Confirmed on firmware 04094-02-S10:

Register Name Values
47000 Operation Mode 0=General, 3=Eco, 5=Eco Charge, 6=Eco Discharge
47509 Grid Export Enabled 0=off, 1=on
47510 Grid Export Limit 0–10000 W
47511 EMS Mode 0=Self-Consumption, 1=Forced
47512 EMS Power Limit 0–10000 W
47515–47518 Eco Slot 1 Start, End, Power%, WorkWeek
47519–47530 Eco Slots 2–4 Clear to 0x0000
47603 Immediate Charge Power % 0–100 (non-linear, actual control register)
47604 Immediate Charge Enable 0=off, 1=on (primary)
47545 Immediate Charge Enable 0=off, 1=on (secondary)

WorkWeek: 0xFF7F = all days, 0xFF1F = weekdays, 0x007F = disabled.

Firmware Quirks

Quirk Impact
pbattery1 sign inverted (+ = discharging) All direction logic must account for this
PV total register sentinel 0xFFFFFFFF Sum 4 string registers individually
GridExport=0 does NOT stop solar export Only controls battery-to-grid
OpMode=5 (Eco Charge) does NOT force grid charging on this firmware Use immediate charge registers instead
Reg 47546 is read-only Use reg 47603 for immediate charge power

Useful Commands

# Logs
sudo docker compose logs backend --tail=50
sudo docker compose logs collector --tail=50

# Hot-swap backend only
sudo docker cp backend/main.py goodwe_backend:/app/main.py
sudo docker compose restart backend

# Full rebuild
sudo docker compose down frontend backend
sudo docker compose build --no-cache frontend backend
sudo docker compose up -d

# Force cert renewal
sudo docker compose restart certbot

Troubleshooting

Symptom Fix
502 Bad Gateway after rebuild sudo docker compose restart frontend
Certbot fails Check AWS credentials and IAM policy
Schedule not firing docker compose logs backend | grep scheduler
Schedule stuck on "Activating" Restart backend to reset limit tracker
EV shows 0W during grid charge Ensure sta==3 and sta==4 both handled (fixed v44)

Project Structure

goodwe-local-monitor/
├── backend/main.py        # FastAPI — endpoints, scheduler, auth
├── collector/collector.py # Modbus polling → InfluxDB
├── frontend/src/          # React dashboard
├── certbot/               # Let's Encrypt DNS-01
├── docker-compose.yml
├── .env.example
└── README.md

Roadmap

  • Dynamic immediate charge power — calculate safe % from live house load and solar
  • Local DNS / self-signed cert option (no Route 53 requirement)
  • Home Assistant MQTT publish
  • Multi-inverter support

License

MIT — see LICENSE


Acknowledgements

About

Local monitoring dashboard for GoodWe EHB inverter + Lynx battery + Zappi EV. Modbus TCP → InfluxDB → React. No SEMS cloud dependency.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors