UNPKG

homebridge-enlighten-power

Version:

Homebridge dynamic platform plugin that exposes Enphase Envoy solar production and consumption as HomeKit sensors. Supports local HTTPS access (firmware D8+, Bearer token) and the Enphase Cloud API v4 (OAuth 2.0 refresh_token). Multiple accessories share

369 lines (266 loc) β€’ 14.5 kB
<p align="center"> <a href="https://github.com/homebridge/homebridge"><img src="https://raw.githubusercontent.com/homebridge/branding/master/logos/homebridge-color-round-stylized.png" height="140"></a> </p> <span align="center"> # homebridge-enlighten-power [![npm](https://img.shields.io/npm/v/homebridge-enlighten-power.svg)](https://www.npmjs.com/package/homebridge-enlighten-power) [![npm](https://img.shields.io/npm/dt/homebridge-enlighten-power.svg)](https://www.npmjs.com/package/homebridge-enlighten-power) [![Homebridge v2 Ready](https://img.shields.io/badge/Homebridge-v2%20Ready-purple)](https://github.com/homebridge/homebridge/wiki/Updating-To-Homebridge-v2.0) </span> > 🌐 **English** Β· [Version franΓ§aise](README.fr.md) > ⚠️ **Upgrading from 2.x?** Version 3.0.0 is a breaking release β€” the plugin is now a **dynamic platform**. See the [migration guide](#migrating-from-2x) below. ## Description This Homebridge plugin exposes your Enphase Envoy solar system to HomeKit as one or more sensors. Each accessory monitors either **production** (solar generation) or **consumption** (net grid exchange), and switches to its triggered state when the value crosses a configurable threshold β€” useful as an event source for HomeKit automations. All accessories share a single Envoy connection and a single authentication token. Three connection methods are supported. The repository also ships three standalone [Python scripts](#companion-python-scripts) that drive a Piface2 relay from a Raspberry Pi β€” **completely independent of Homebridge**. --- ## The Homebridge plugin ### Installation - **Recommended:** install through the Homebridge UI β€” *Plugins* tab β†’ search **Homebridge Enlighten Power** β†’ *Install*. - **Manual:** `npm install -g homebridge-enlighten-power`. ### Choose a connection method | # | Method | Pros | Cons | | - | --- | --- | --- | | **1** | [Local + **static token**](#method-1--local--static-token) | Simple, fastest setup. | Manual token rotation ~once a year. | | **2** | [Local + **auto-refreshed token**](#method-2--local--auto-refresh) | No manual rotation ever. | Your Enlighten password sits in `config.json`. | | **3** | [**Cloud API v4** (OAuth 2.0)](#method-3--cloud-api-v4) | Works without LAN access to the Envoy. Production + consumption. | 1 000 req/month quota; 60 min interval recommended; one-time OAuth setup. | > In the Homebridge UI, the *Connection* dropdown handles method 3 vs. the local methods, and an *Authentication method* dropdown handles method 1 vs. method 2. If you edit `config.json` by hand you can skip `auth_method` and just fill the fields you need β€” the plugin infers the method (`token` wins if both groups are set). --- ### Method 1 β€” Local + static token Local HTTPS access using a long-lived JWT that you generate yourself, **once**. #### 1. Generate the token 1. Open <https://entrez.enphaseenergy.com> and log in. 2. Generate a token for your Envoy (the tool asks for the Envoy serial number). 3. Copy the JWT into `config.json` (see below). It expires after ~1 year β€” repeat the process when that happens. #### 2. config.json ```json { "platforms": [ { "platform": "EnlightenPower", "name": "Enlighten Power", "connection": "bonjour", "token": "eyJraWQiOiI......biQETMEQ", "update_interval": 1, "accessories": [ { "name": "> 6000 W production", "measurement": "production", "power_threshold": 6000 } ] } ] } ``` Custom URL (reach Envoy by IP): ```json { "platforms": [ { "platform": "EnlightenPower", "name": "Enlighten Power", "connection": "url", "url": "https://192.168.1.x", "token": "eyJraWQiOiI......biQETMEQ", "update_interval": 1, "accessories": [ { "name": "> 6000 W production", "measurement": "production", "power_threshold": 6000 }, { "name": "Export > 4500 W", "measurement": "consumption", "power_threshold": 4500 } ] } ] } ``` > **About the local API.** `envoy.localdomain` is the mDNS hostname used by firmware D8+. The Envoy ships a self-signed certificate β€” the plugin disables strict TLS verification on local connections only. At startup the plugin calls `/ivp/meters` to map each meter's `eid` to its `measurementType` (`"production"` or `"net-consumption"`). Each polling cycle it calls `/ivp/meters/readings` and looks up entries by `eid` β€” not by array position. --- ### Method 2 β€” Local + auto-refresh Same local Envoy access as Method 1, but the plugin **obtains and renews the JWT for you**, transparently. ```json { "platforms": [ { "platform": "EnlightenPower", "name": "Enlighten Power", "connection": "bonjour", "auth_method": "auto_refresh", "enlighten_user": "you@example.com", "enlighten_pass": "MY_ENLIGHTEN_PASSWORD", "envoy_serial": "1234XXXXXXXX", "update_interval": 1, "accessories": [ { "name": "> 6000 W production", "measurement": "production", "power_threshold": 6000 } ] } ] } ``` What happens at runtime: 1. On startup the plugin logs in to `enlighten.enphaseenergy.com` with your credentials. 2. It asks `entrez.enphaseenergy.com` for a fresh JWT bound to your Envoy serial. 3. The JWT is cached in memory and re-used on every poll. 4. When the JWT gets within 7 days of expiry β€” or after a `401` from the Envoy β€” a new JWT is fetched automatically. --- ### Method 3 β€” Cloud API v4 OAuth 2.0 access to the Enphase developer API. Use this when Homebridge cannot reach the Envoy on the local network. Both `production` and `consumption` measurements are available via the `latest_telemetry` endpoint. Plans: <https://developer-v4.enphase.com/plans>. The free tier quota was **reduced from 10 000 to 1 000 requests/month** by Enphase. Set `update_interval` to **60** (1 request/hour = 720/month) to stay within budget. The plugin polls once immediately on startup, then aligns subsequent polls to clock boundaries β€” with `update_interval: 60` the data refreshes at the top of every hour (10:00, 11:00, …). #### Step 1 β€” Create the application On <https://developer-v4.enphase.com>, create an application. The page exposes: - **API Key** Β· **Client ID** Β· **Client Secret** - **Authorization URL** of the form `https://api.enphaseenergy.com/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID` You also need your **System ID** (numeric Enlighten system ID, formerly *site_id*). #### Step 2 β€” Get an authorization code > ⚠️ The Authorization URL in the portal is **incomplete** β€” it lacks `redirect_uri`. Append `&redirect_uri=https://api.enphaseenergy.com/oauth/redirect_uri`, otherwise you get `OAuth Error: A redirect_uri must be supplied.` Full URL: ```text https://api.enphaseenergy.com/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=https://api.enphaseenergy.com/oauth/redirect_uri ``` Open it, log in to Enlighten, approve. The redirect page shows a short, one-time code (e.g. `2TJk7M`), valid only a few minutes. #### Step 3 β€” Exchange the code for a refresh_token ```bash curl -X POST \ -u "CLIENT_ID:CLIENT_SECRET" \ "https://api.enphaseenergy.com/oauth/token?grant_type=authorization_code&redirect_uri=https://api.enphaseenergy.com/oauth/redirect_uri&code=AUTH_CODE" ``` Or with [`examples/get_refresh_token.py`](examples/get_refresh_token.py): ```bash python3 examples/get_refresh_token.py 2TJk7M ``` Copy the `refresh_token` from the response β€” valid ~1 month. The plugin renews the 24h access token automatically. #### Step 4 β€” config.json ```json { "platforms": [ { "platform": "EnlightenPower", "name": "Enlighten Power", "connection": "api", "api_key": "API_KEY", "client_id": "CLIENT_ID", "client_secret": "CLIENT_SECRET", "system_id": "SYSTEM_ID", "refresh_token": "REFRESH_TOKEN", "update_interval": 60, "accessories": [ { "name": "> 6000 W production", "measurement": "production", "power_threshold": 6000 } ] } ] } ``` --- ### Accessories Each accessory in the `accessories` array is an independent HomeKit sensor. All share the platform's connection and authentication. | Field | Required | Default | Description | | --- | --- | --- | --- | | `name` | βœ… | β€” | Display name in HomeKit. Must be unique. | | `measurement` | | `production` | `production` (solar generation) or `consumption` (net grid exchange). Available for all connection types. | | `power_threshold` | | `1000` | Trigger level in W. See below for per-measurement logic. | | `accessory_type` | | `co2sensor` | HomeKit sensor type β€” see [HomeKit accessory type](#homekit-accessory-type). | **Production mode** β€” triggers when `production β‰₯ threshold`; resets below. **Consumption mode** β€” mirrors the hysteresis of the Piface scripts: - `detected β†’ 1` when `net ≀ βˆ’threshold` (house is exporting more than threshold to the grid). - `detected β†’ 0` when `net β‰₯ 0` (house is importing from the grid). - The displayed level is the absolute grid exchange value in W. > The `consumption` measurement is available for all connection types, including the Cloud API (via the `latest_telemetry` endpoint). --- ### HomeKit accessory type | Value | HomeKit service | Behaviour | | --- | --- | --- | | `co2sensor` (default) | Carbon Dioxide sensor | Power in ppm + Detected flag above threshold. | | `motion` | Motion sensor | Motion detected above threshold. | | `occupancy` | Occupancy sensor | Occupied above threshold. | | `contact` | Contact sensor | Open above threshold. | | `lightsensor` | Light sensor | Power in lux (capped at 100 000). | --- ### Quick test from a shell Local Envoy β€” meter readings: ```bash curl -sk -H "Authorization: Bearer TOKEN" "https://envoy.localdomain/ivp/meters/readings" \ | python3 -c "import sys, json; d=json.load(sys.stdin); print('prod', d[0]['activePower'], 'W net', d[1]['activePower'], 'W')" ``` --- ## Migrating from 2.x > ⚠️ **Clean uninstall required.** Because the plugin type changed from `accessory` to `platform`, Homebridge generates UUIDs differently and the old cached accessory data will conflict. **Do not just update in place** β€” follow the steps below. ### Migration steps β€” via Homebridge UI 1. **Plugins tab β†’ Homebridge Enlighten Power β†’ Uninstall.** Confirm. This stops the child bridge and removes the plugin. 2. **Accessories tab** β€” if the old accessory is still listed, click the βš™οΈ icon β†’ *Remove accessory*. If the tab is empty or the accessory is gone, skip this step. 3. **Settings β†’ Config** (JSON editor) β€” make sure the `"accessories"` array no longer contains any `"accessory": "enlighten-power"` block. Save. 4. **Settings β†’ Homebridge Settings β†’ Restart Homebridge** once to flush the accessory cache. 5. **Plugins tab β†’ search "Homebridge Enlighten Power" β†’ Install**, or from a terminal: `npm install -g homebridge-enlighten-power`. 6. **Configure** the plugin via its settings GUI or by editing `config.json` as shown below. 7. **Remove from HomeKit** if the accessory still appears as unresponsive in the Home app: long-press β†’ *Remove accessory*. ### Migration steps β€” via terminal (advanced) ```bash # 1. Uninstall npm uninstall -g homebridge-enlighten-power # 2. Clear the accessory cache rm /homebridge/accessories/cachedAccessories rm /homebridge/accessories/cachedAccessories.*.json 2>/dev/null # 3. Reinstall npm install -g homebridge-enlighten-power # stable # 4. Edit config.json, then restart Homebridge ``` ### Config changes The plugin is now a **platform** (`"platform": "EnlightenPower"`) instead of an accessory (`"accessory": "enlighten-power"`). Config must be moved from the `accessories` section to the `platforms` section. **Before** (`config.json` β€” v2.x): ```json { "accessories": [ { "accessory": "enlighten-power", "name": "> 6000 W", "connection": "bonjour", "token": "...", "power_threshold": 6000, "accessory_type": "motion" } ] } ``` **After** (`config.json` β€” v3.x): ```json { "platforms": [ { "platform": "EnlightenPower", "name": "Enlighten Power", "connection": "bonjour", "token": "...", "accessories": [ { "name": "> 6000 W", "measurement": "production", "power_threshold": 6000, "accessory_type": "motion" } ] } ] } ``` --- ## Companion Python scripts The repository also ships three standalone Python scripts under [`examples/`](examples/). They are **independent of Homebridge** β€” they exist for users who want to drive a **Piface2 relay** directly from a Raspberry Pi based on Envoy data. ### Install pifacedigitalio Thanks to @rfennel who [got it working](https://github.com/piface/pifacedigitalio/issues/39#issuecomment-633291166) under Buster: ```bash sudo apt-get install python3-pip sudo pip3 install pifacedigitalio pifacecommon sudo sed -i 's/#dtparam=spi=on/dtparam=spi=on/' /boot/config.txt sudo reboot ``` ### [`examples/check_power_local.py`](examples/check_power_local.py) Local Envoy access (HTTPS + Bearer token). Reads production and consumption from `/ivp/meters/readings` and drives one or both Piface2 relays. - `--mode production --value <W>` β€” relay ON when production β‰₯ value, OFF otherwise. - `--mode consumption --value <W>` β€” relay ON when house exports more than value to the grid; OFF as soon as it imports (hysteresis). - `--relay {0,1} [{0,1} ...]` β€” relay index(es). Default: `0`. Pass `--relay 0 1` to mirror both. ### [`examples/check_power_api.py`](examples/check_power_api.py) Cloud API v4 β€” self-sufficient. Handles the full OAuth flow, stores the refresh token in `refresh_token.txt`, and renews the access token automatically. ### [`examples/get_refresh_token.py`](examples/get_refresh_token.py) Standalone helper for the OAuth exchange. ```bash python3 examples/get_refresh_token.py <AUTH_CODE> ``` ### cron example ```cron # Production mode β€” relay 0 ON when production β‰₯ 6000 W * * * * * python3 /home/pi/check_power_local.py --mode production --value 6000 # Consumption mode β€” relay 1 ON when exporting more than 4500 W * * * * * python3 /home/pi/check_power_local.py --mode consumption --value 4500 --relay 1 # Mirror both relays * * * * * python3 /home/pi/check_power_local.py --mode consumption --value 4500 --relay 0 1 ```