Power Management (Generic Energy Dashboard)
GEM talks to many power devices — battery gateways (Tesla Powerwall, Enphase Encharge, SPAN), solar inverters (Enphase, SolarEdge, Fronius, Sol-Ark), whole-home and circuit meters (Emporia Vue, Sense, Meross EM), UPS/PDUs (CyberPower, WattBox, Panamax) and EV chargers (OpenEVSE, Tesla Wall Connector). Each driver reports power data under its own attribute names and units. To make a single dashboard work across all of them without a per-site build, GEM normalizes that vocabulary in the attribute registry and exposes it through the Power Flow widget.
The Power Flow widget
Add it to any UI page like any other widget (UIs → Pages → add widget → Power Flow). It renders a live energy-flow diagram: a central Home node with Solar, Grid and Battery around it. Flow lines animate in the direction power is moving and speed up under load; the battery node fills from the bottom to show state of charge and shows a bolt overlay while it is charging. Nodes a device doesn't report (e.g. a solar-only inverter with no battery) are simply omitted.
Settings:
| Setting | Purpose |
|---|---|
| Power Device | The inverter / gateway / battery to visualize (e.g. a Tesla Powerwall device). |
| Aggregate All Power Devices | Ignore the device above and sum every power-reporting device on the site into one flow. |
| Refresh (ms) | Poll interval for the flow snapshot (default 5000). |
| Show Battery SOC | Render battery state of charge as the battery fill level. |
How it works — canonical metric roles
The attribute registry tags each power attribute with a metric_role and a source
unit. A generic consumer reads the role, not the driver-specific name — so production_now_w
(Enphase), pv_power (SolarEdge), pv_power_w (Fronius) and solar_power_w (Tesla) all resolve
to the same power.solar concept. Driver attribute names are never renamed; normalization lives
entirely in the registry plus the server resolver.
Instantaneous flow roles are normalized to watts with one fixed sign convention:
| Role | Meaning | Sign convention |
|---|---|---|
power.solar | Solar/PV generation | ≥ 0 |
power.load | Site/home consumption | ≥ 0 |
power.grid | Grid power | + import, − export |
power.battery | Battery power | + discharge, − charge |
power.generator | Generator output | ≥ 0 |
Storage/status roles: battery.soc (%), battery.energy_remaining / battery.capacity (kWh),
power.grid_status, power.mode.
When a driver's native attribute uses the opposite sign for its role, its seed row carries
metric_sign: 'inverted' and the resolver negates it (e.g. Enphase net_power_w, which the
driver reports as positive-for-export). When a driver's load attribute is missing or its sign is
unreliable (e.g. Fronius reports consumption as negative), the resolver derives load from the
energy balance: load = solar + grid + battery.
Drivers currently tagged
| Driver | Solar | Grid | Battery | Load | SOC | Notes |
|---|---|---|---|---|---|---|
| Tesla Powerwall | ✓ | ✓ | ✓ | ✓ | ✓ | Verified against live firmware 26.10.3. |
| Enphase Envoy/IQ | ✓ | ✓ | ✓ | ✓ | ✓ | Grid sign inverted in registry; battery sign should be field-verified. |
| SolarEdge | ✓ | ✓ | ✓ | ✓ | ✓ | Requires the power-flow API (consumption/storage meter). Values in kW. |
| Fronius | ✓ | ✓ | ✓ | derived | — | Load derived (Fronius P_Load sign convention). |
| SPAN | — | — | — | — | ✓ | Battery SOC only for now. |
Metered-only drivers (Emporia Vue, Sense, Meross EM) and UPS/PDUs are not yet tagged for the flow diagram; their per-circuit power lives at the zone level and is a planned follow-on.
Adding a new driver to the dashboard
No widget or server code is needed — tag the driver's attributes in
lib/attribute_registry_seed.js:
{name: 'pv_power_w', system_target: 'device', value_type: 'float', category: 'state',
context: 'my_inverter', history: true, unit: 'W',
description: 'PV production.', metric_role: 'power.solar'},
Pick the attribute whose native sign already matches the convention above; if none does, add
metric_sign: 'inverted'. Units are W (default), kW or MW. On the next boot the seeder
applies the tags and the Power Flow widget picks the device up automatically.
API — get_energy_flow
Socket event (and GemApp.getEnergyFlow(params) on the client):
params:{device_id}for a single device, or omit for a site-wide aggregate.- Returns
{devices: [...], totals: {...}}where each device is{device_id, device_name, driver, solar_w, grid_w, battery_w, load_w, battery_soc, grid_status, mode}with flows in watts following the sign convention above.
The resolver reads live values straight from the in-memory device objects, so it reflects the latest poll without a database round-trip.