Enphase Envoy / IQ Gateway
The Enphase Envoy driver polls a local Envoy / IQ Gateway over its LAN HTTPS API and surfaces production, consumption, and (where present) Encharge battery telemetry as device attributes. All telemetry traffic stays on the LAN; the only cloud round-trip is the one-time JWT mint at install time.
Status
Built against the public D7 firmware endpoints. Read paths (/info, /production.json, /api/v1/production, /api/v1/production/inverters, /ivp/ensemble/*) are implemented. Encharge storage-mode writes are stubbed (set_storage_mode returns not yet implemented). Older D5 session-cookie firmware is out of scope — upgrade in Enlighten.
Prerequisites
- Envoy / IQ Gateway on D7+ firmware. Verify in the Enlighten installer view under the gateway's Software tab.
- The gateway and the GEM controller share a LAN; TCP/443 reachable from the controller to the gateway IP.
- An Enlighten account (homeowner is fine for production-only telemetry; installer is required for per-inverter and battery endpoints).
- Gateway serial number — printed on the unit and visible in Enlighten under System > Devices > Gateway.
Setup
- Find the Envoy LAN IP. Easiest paths:
- Enlighten app → System > Devices > Gateway.
- The router's DHCP table (look for
Envoy-or the gateway serial). arp -a | grep <first 6 of MAC>from the controller.
- Mint a JWT bearer token.
- Sign in at https://entrez.enphaseenergy.com.
- Paste the gateway serial number when prompted.
- Click Generate Token and copy the long opaque JWT.
- Tokens are valid ~12 months for installer accounts; homeowner tokens are shorter-lived. Note the expiry — when polling starts logging
auth rejected (401), mint a fresh one.
- Create the device under System > Devices with driver
enphase_envoy. Set:ip— the Envoy LAN IP (e.g.,192.168.1.50)token— the JWT pasted from Entrez
- Verify. From the Script Console:
You should see a JSON response with aawait gem.command({device: <device_id>, action: 'get_status'});
productionarray. After ~30 s the device picks upproduction_now_w,production_today_wh, and friends as attributes. - (Optional) Per-microinverter zones. Run:
Create one zone per inverter you care about; setawait gem.command({device: <device_id>, action: 'get_inverters'});
zone.addressto the inverterserialNumber. The driver writeslast_wandmax_wzone attributes on each poll, and surfaceslast_was the zone state.
Attribute Reference
Required device attributes
| Name | Type | Description |
|---|---|---|
ip | string | Envoy LAN IP. |
token | string | JWT bearer minted from Entrez (stored encrypted). |
Optional device attributes
| Name | Type | Default | Description |
|---|---|---|---|
port | int | 443 | HTTPS port. Override only on non-standard installs. |
serial_number | str | — | Gateway serial. Auto-populated from /info on first connect. |
polling_interval | int | 30000 | Telemetry poll interval (ms). Hard floor 5000 ms. |
request_timeout | int | 10000 | Per-request HTTPS timeout (ms). |
Runtime device attributes (driver-populated)
| Name | Type | Notes |
|---|---|---|
production_now_w | int | Instantaneous PV production. Prefers EIM (CT-meter) value, falls back to inverter summary. |
production_today_wh | int | Today's production. |
production_lifetime_wh | int | Lifetime production. |
consumption_now_w | int | Whole-home load (CT meter required). |
consumption_today_wh | int | Today's consumption (CT meter required). |
consumption_lifetime_wh | int | Lifetime consumption (CT meter required). |
net_power_w | int | Net power; positive = export to grid, negative = import. (CT meter required.) |
inverter_count | int | Active microinverters reporting. |
last_report_time | string | ISO timestamp of the last EIM/inverter reading. |
battery_now_w | int | Encharge instantaneous power. Positive = discharging. |
battery_soc_percent | float | Encharge state-of-charge %. |
battery_capacity_wh | int | Encharge stored energy. |
battery_state | string | Encharge controller state (e.g., idle, charging, discharging). |
Per-zone attributes (optional)
| Name | Type | Notes |
|---|---|---|
last_w | int | Inverter's last-reported wattage. |
max_w | int | Inverter's lifetime max wattage. |
state | str | Mirrors last_w so dashboard widgets render the value. |
Zone Address Format
zone.address is the inverter serial number as reported by /api/v1/production/inverters (e.g., 122412345678). Leave blank to treat the Envoy as a single telemetry endpoint with no per-inverter breakdown.
Commands
| Command | Args | Notes |
|---|---|---|
get_status | — | Reads /production.json and refreshes device attributes. |
get_production | — | Raw /api/v1/production response. |
get_inverters | — | Per-microinverter wattage. Requires installer JWT. |
get_battery | — | Encharge inventory + storage controller state. Installer JWT. |
get_info | — | XML /info (firmware, model, MAC, serial). |
set_storage_mode | mode | TODO — returns not yet implemented. |
Known Limitations
- D5 firmware is not supported. The D5 line uses
installer/<password-from-serial>HTTP basic + session cookies; this driver only speaks the D7+ JWT flow. set_storage_modeis stubbed. Reverse-engineered Encharge profile payloads exist in the community but we have not validated them against a live battery — leaving the call to return an error rather than guess at the wire format.- Stream / live-data subscriptions are not used. Telemetry is polled every
polling_intervalms; the/stream/meterand/ivp/livedata/streamSSE endpoints are not subscribed. Polling at 30 s is enough for graphing and most automation; sub-second telemetry would need the stream. - No automatic JWT renewal. When the token expires, mint a fresh one in Enlighten and update the
tokenattribute. (A future revision could automate this with stored Enlighten credentials, similar toecobee.js.)
Troubleshooting
auth rejected (401)on every poll — JWT expired, was minted for a different gateway serial, or is a homeowner token hitting an installer-only endpoint. Mint a fresh installer JWT in Entrez.auth rejected (403)— Token is valid but lacks the scope for that endpoint./api/v1/production/invertersand/ivp/ensemble/*need installer-tier;/production.jsonworks with homeowner.- Connection refused on 443, works on 80 — Almost certainly D5 firmware. Upgrade in Enlighten or use a generic HTTP poller for now.
- Production reports 0 W during the day — Envoy lost contact with the inverters. Check
/infoin a browser and verify the gateway's network/cellular backhaul is up. - No
consumption_now_wattribute appears — System has no CT (current transformer) consumption meters. This is normal on production-only installs.