Skip to content

Commit e52d62d

Browse files
Ports existing functionality to v4 API (#3)
Closes #2
1 parent 260a94f commit e52d62d

8 files changed

Lines changed: 443 additions & 190 deletions
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
{
2+
"info": {
3+
"_postman_id": "274a5c9b-df54-48b1-a24e-25405890f016",
4+
"name": "Enpahse Enlighten v4",
5+
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6+
},
7+
"item": [
8+
{
9+
"name": "Fetch systems",
10+
"request": {
11+
"auth": {
12+
"type": "bearer",
13+
"bearer": [
14+
{
15+
"key": "token",
16+
"value": "{{access_token}}",
17+
"type": "string"
18+
}
19+
]
20+
},
21+
"method": "GET",
22+
"header": [
23+
{
24+
"key": "Host",
25+
"value": "api.enphaseenergy.com",
26+
"type": "text"
27+
}
28+
],
29+
"url": {
30+
"raw": "https://api.enphaseenergy.com/api/v4/systems?key={{app_api_key}}",
31+
"protocol": "https",
32+
"host": [
33+
"api",
34+
"enphaseenergy",
35+
"com"
36+
],
37+
"path": [
38+
"api",
39+
"v4",
40+
"systems"
41+
],
42+
"query": [
43+
{
44+
"key": "key",
45+
"value": "{{app_api_key}}"
46+
}
47+
]
48+
}
49+
},
50+
"response": []
51+
},
52+
{
53+
"name": "Generate OAuth2 access_token",
54+
"request": {
55+
"auth": {
56+
"type": "basic",
57+
"basic": [
58+
{
59+
"key": "password",
60+
"value": "{{client_secret}}",
61+
"type": "string"
62+
},
63+
{
64+
"key": "username",
65+
"value": "{{client_id}}",
66+
"type": "string"
67+
}
68+
]
69+
},
70+
"method": "POST",
71+
"header": [],
72+
"url": {
73+
"raw": "https://api.enphaseenergy.com/oauth/token?grant_type=authorization_code&redirect_uri=https://api.enphaseenergy.com/oauth/redirect_uri&code={{auth_code}}",
74+
"protocol": "https",
75+
"host": [
76+
"api",
77+
"enphaseenergy",
78+
"com"
79+
],
80+
"path": [
81+
"oauth",
82+
"token"
83+
],
84+
"query": [
85+
{
86+
"key": "grant_type",
87+
"value": "authorization_code"
88+
},
89+
{
90+
"key": "redirect_uri",
91+
"value": "https://api.enphaseenergy.com/oauth/redirect_uri"
92+
},
93+
{
94+
"key": "code",
95+
"value": "{{auth_code}}"
96+
}
97+
]
98+
}
99+
},
100+
"response": []
101+
},
102+
{
103+
"name": "Refresh access_token",
104+
"event": [
105+
{
106+
"listen": "test",
107+
"script": {
108+
"exec": [
109+
""
110+
],
111+
"type": "text/javascript"
112+
}
113+
}
114+
],
115+
"request": {
116+
"auth": {
117+
"type": "basic",
118+
"basic": [
119+
{
120+
"key": "password",
121+
"value": "{{client_secret}}",
122+
"type": "string"
123+
},
124+
{
125+
"key": "username",
126+
"value": "{{client_id}}",
127+
"type": "string"
128+
}
129+
]
130+
},
131+
"method": "POST",
132+
"header": [],
133+
"url": {
134+
"raw": "https://api.enphaseenergy.com/oauth/token?grant_type=refresh_token&refresh_token={{refresh_token}}",
135+
"protocol": "https",
136+
"host": [
137+
"api",
138+
"enphaseenergy",
139+
"com"
140+
],
141+
"path": [
142+
"oauth",
143+
"token"
144+
],
145+
"query": [
146+
{
147+
"key": "grant_type",
148+
"value": "refresh_token"
149+
},
150+
{
151+
"key": "refresh_token",
152+
"value": "{{refresh_token}}"
153+
}
154+
]
155+
}
156+
},
157+
"response": []
158+
},
159+
{
160+
"name": "inverters_summary_by_envoy_or_site",
161+
"request": {
162+
"auth": {
163+
"type": "bearer",
164+
"bearer": [
165+
{
166+
"key": "token",
167+
"value": "{{access_token}}",
168+
"type": "string"
169+
}
170+
]
171+
},
172+
"method": "GET",
173+
"header": [
174+
{
175+
"key": "Host",
176+
"value": "api.enphaseenergy.com",
177+
"type": "text"
178+
}
179+
],
180+
"url": {
181+
"raw": "https://api.enphaseenergy.com/api/v4/systems/inverters_summary_by_envoy_or_site?key={{app_api_key}}&site_id={{system_id}}",
182+
"protocol": "https",
183+
"host": [
184+
"api",
185+
"enphaseenergy",
186+
"com"
187+
],
188+
"path": [
189+
"api",
190+
"v4",
191+
"systems",
192+
"inverters_summary_by_envoy_or_site"
193+
],
194+
"query": [
195+
{
196+
"key": "key",
197+
"value": "{{app_api_key}}"
198+
},
199+
{
200+
"key": "site_id",
201+
"value": "{{system_id}}"
202+
}
203+
]
204+
}
205+
},
206+
"response": []
207+
}
208+
]
209+
}

README.md

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
# python_enlighten_api
1+
# python_enlighten_api (v4)
2+
3+
_Note: this repository has been updated to include using the new Enphase Enlighten v4 API (https://developer-v4.enphase.com/aboutproduct.html)._
4+
25
Enphase Enlighten API & Google Sheets application to pull data and monitor panel performance and populate a Google Sheet with historical and visual data. This allows tracking individual panel performance over the lifetime of the system. Most of the functionlaity provided here is also provided by the Enphase Enlighten website and app, but this allows for granular panel tracking and performance over time.
36

47
For example: the panel underperforming (red) is partially blocked by a neighbor's tree during the morning hours. So it's reporting performance outside a few standard deviations.
@@ -7,42 +10,68 @@ For example: the panel underperforming (red) is partially blocked by a neighbor'
710
<img src="solar_performance_example.png" width="500">
811
</p>
912

13+
14+
## Known Limitations
15+
1. Token Expiration:
16+
* The Enlighten v4 API does not provide any documentation on what happens whe `refresh_token` expires (1 week validity) and how a new one is generated. The step to generate the original `access_token` and `refresh_token` in [Generate OAuth2 access_token and refresh_token](https://developer-v4.enphase.com/docs/quickstart.html#step_8) seems to only allow the route to be used a single time for an authorization code (auth_code).
17+
* As such, _the enlightenAPI_v4_ constructor provided in this repository will refresh the tokens using the [Generate new access_token and refresh_token using refresh_token](https://developer-v4.enphase.com/docs/quickstart.html#step_10) and update the _enlighten_v4_config.json_ to contain the new tokens. This ensures that each day when the script is run, the tokens are refreshed and kept well within the refresh_token's 1 week validity.
18+
2. Inverter Telemetry Reporting:
19+
* It appears there's a new v4 route (/api/v4/systems/{System_id}/devices/micros/{serial_no}/telemetry) that can get microinverter data based on a date range. This seems the more ideal way to get daily inverter data than my current way of having to get the current lifetime data minus the stored value. But unfortunately I have not been able to successfully call this route using the Enlighten API v4 docs. So maybe this route doesn't do what I think it does, and their docs don't make it very clear what it does. I always get a 401 - Not Authorized. If someone is able to get that figured out, please feel free to let me know.
20+
1021
## Requirements
1122
Requires Python 3.6.8 or later installed. Much effort has been taken to ensure this application does not require additional modules besides what is included standard with Python.
1223

13-
pip install requests
14-
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
24+
pip install -r requirements.txt
25+
26+
This will install the following:
27+
1. requests
28+
2. google-api-python-client
29+
3. google-auth-httplib2
30+
4. google-auth-oauthlib
1531

1632
## Getting Started
1733

34+
### Postman Scripts
35+
The _Enpahse Enlighten v4.postman_collection.json_ is provided to assist setting up the `access_token` and `refresh_token`. In addition, you can use the GET routes to test your API connectivity and configuration.
36+
1837
### Script/API Setup
19-
1. Allow app access to your Enlighten Account:
20-
* Follow the instructions here to add a new application to your developer account: https://developer.enphase.com/docs/quickstart.html
21-
2. Open run_inverter_daily_stats.py and set the following in the User Settings section:
22-
* user_id: within MyEnlighten go to your account Settings and find the API Settings user ID
23-
* site_id: within MyEnlighten the Site ID should be displayed (or if using the web browser should be in the URL [https://enlighten.enphaseenergy.com/pv/systems/:SITE_ID/overview]
24-
* api_url: The Enphase API, most likely: https://api.enphaseenergy.com/api/v2/systems
25-
* api_key: within the https://developer.enphase.com/admin/applications page copy your app's API Key
26-
* spreadsheet_id: The SpreadSheet ID from Google Sheets. See step 5.
27-
4. Setup a Google API key for your python script and put the following files in your main working script directory: credentials.json, token.pickle.
28-
* https://developers.google.com/sheets/api/quickstart/python
38+
1. [Enlighten API] Allow app access to your Enlighten Account:
39+
* Follow the Enlighten [Quickstart instructions Steps 1-4](https://developer-v4.enphase.com/docs/quickstart.html#step_1) to add a new application to your developer account
40+
2. [Enlighten API] Open the _enlighten_v4_config.json_ and set the following:
41+
* `name`: a generic name to identify this system.
42+
* `system_id`: (previously known as `Site ID`) Within MyEnlighten the System ID should be displayed (or if using the web browser should be in the URL [https://enlighten.enphaseenergy.com/web/:SYSTEM_ID/today/graph/hours].
43+
* `app_api_key`: Within the [Enlighten API App Page](https://developer-v4.enphase.com/admin/applications) page, copy your app's API key.
44+
* `app_client_id`: Within the [Enlighten API App Page](https://developer-v4.enphase.com/admin/applications) page, copy your app's Client ID.
45+
* `app_client_secret`: Within the [Enlighten API App Page](https://developer-v4.enphase.com/admin/applications) page, copy your app's Client Secret.
46+
* `access/refresh_token`: See step 3 below.
47+
* `spreadsheet_id`: The SpreadSheet ID from Google Sheets. See step 5.
48+
3. [Enlighten API] Generate access_token and refresh_token (this condenses some of the Enlighten API [Quickstart Guide](https://developer-v4.enphase.com/docs/quickstart.html)
49+
* Follow the Enlighten [Quickstart instructions Steps 6-7](https://developer-v4.enphase.com/docs/quickstart.html#step_6), generate the auth_code for your application
50+
* Using the _Enpahse Enlighten v4.postman_collection.json_ open the _Generate OAuth2 access_token_ request:
51+
* Update the Postman environment variables to set the: auth_code, client_id, and client_secret
52+
* Run the request. The resulting access_token and refresh_token should be added to your enlighten_v4_config.json
53+
* _Note: it appears that you can only run this request ONCE per app authorization code (auth_code). Once you have the tokens generated for this auth_code, it appears you will be unable to run this route again. So make sure to save them. The Enlighten v4 API does not provide any details on this, but this appears to be the case._
54+
* You can call the Postman _Fetech Systems_ request using your new tokens to ensure proper configuration of your application and API tokens.
55+
4. [Google Sheets] Setup a Google API key for your python script and put the following files in your main working script directory: credentials.json, token.pickle.
56+
* Follow the [Google Python Quickstart Guide](https://developers.google.com/sheets/api/quickstart/python)
2957
* Allow your API token to access your Google Sheets account: https://console.developers.google.com/apis/api/sheets.googleapis.com/overview?
30-
5. Google Sheet Setup
31-
* The google sheet can be accessed from: https://docs.google.com/spreadsheets/d/1JPnT5T4xvDIKaefL8Z7AoxRNFv6HnVBF7SH-J9Yqfdk. It is a working copy of an example system setup. You may need to manually clear and remove data to use.
32-
How to Setup:
58+
5. [Google Sheets] Google Sheet Setup
59+
* The _'Solar Performance'_ Google sheet can be accessed from the [Solar Performance (Template)](https://docs.google.com/spreadsheets/d/1JPnT5T4xvDIKaefL8Z7AoxRNFv6HnVBF7SH-J9Yqfdk). It is a working copy of an example system setup. You will need to manually clear and remove the demo data to use.
60+
* How to Setup the _'Solar Perforance'_ Sheet:
3361
1. You'll need to make a copy of this sheet to your personal Google Drive.
34-
2. Populate each of your inverter serial numbers into the 'Panel Data-Template' Sheet.
35-
3. Copy and Paste, using values and transpose, your inverter serial numbers into the 'Last 7 Days' sheet.
36-
4. Update the 'Dashboard' Sheet panel layout to match your panels.
37-
5. Update the 'Dashboard' Sheet panel numbers and serial numbers to match your panel data
38-
* Note: Enphase Enlighten did not provide a good way to do this. So I manually had to match up each inverter serial number with the panel number in the layout by tracking panel energy produced over a few days on the 'Panel Data-<Year>' sheet vs the Enphase Enlighten website/app. After a few days each panel's historical data output allowed me to match up each panel on the Dashboard/Panel Data Sheet with the layout of the Enphase app.
62+
2. Populate each of your inverter serial numbers into the _'Panel Data-Template'_ Sheet.
63+
* This template sheet will automatically be created into a _'Panel Data-<YEAR>'_ sheet where the historical data for each panel per day will be stored.
64+
3. Copy and Paste, using values and transpose, your inverter serial numbers into the 'Last 7 Days' sheet from the _'Panel Data-Template'_ sheet.
65+
4. Update the _'Dashboard'_ Sheet panel layout to match your panels.
66+
5. Update the _'Dashboard'_ Sheet panel numbers and serial numbers to match your panel data
67+
* Note: Enphase Enlighten did not provide a good way to do this. So I manually had to match up each inverter serial number with the panel number in the layout by tracking panel energy produced over a few days on the _'Panel Data-<Year>'_ sheet vs the Enphase Enlighten website/app. After a few days each panel's historical data output allowed me to match up each panel on the Dashboard/Panel Data Sheet with the layout of the Enphase app.
3968

4069
### Running
4170
The Enlighten API has a long lag time between when data is updated on their end. If you run these scripts once a day after the Enlighten data updates AND before your solar is producing power (e.g.: 4am) you get the total lifetime power produced by each inverter, including the previous day.
4271

4372
Run with run_inverter_daily_stats.sh or copy the logic this script is using.
4473

45-
#### Setting Automated Cron Jobs
74+
#### Linux: Setting Automated Cron Jobs
4675
If you're using Linux, you can add these scripts to crontab jobs to run automatically at night by:
4776

4877
Run:
@@ -53,17 +82,22 @@ Add a crontab job:
5382
# At 4am local time run the python script via shell script to ensure we're in the right directory
5483
0 4 * * * /home/<user>/python_enlighten_api/run_inverter_daily_stats.sh >> /home/<user>/python_enlighten_api/cron.log 2>&1
5584

85+
#### Windows: Scheduled Task
86+
If you're using Windows, you can automate running this by doing similar to what the Linux job is doing:
87+
1. Add a new Windows scheduled task to run at 4am
88+
2. Create and have the scheduled task run a .bat file that performs the directory change and python call from `run_inverter_daily_stats.sh`
89+
5690
## Enphase Enlighten API Documentation
5791

58-
* https://developer.enphase.com/docs
92+
* https://developer-v4.enphase.com/docs.html
5993

6094
## Scripts Explanation
6195

6296
This repository contains a few scripts used to hit the Enphase Enlighten API and collect data. The scripts inclide:
6397

6498
### run_inverter_daily_stats.py
6599

66-
Runs the Enlighten API route 'inverters_summary_by_envoy_or_site' to collect the lifetime energy produced by each inverter. The Enphase API lacks the granulatiry of seeing per inveter daily states (documented here: https://developer.enphase.com/forum/topics/per-inverter-stats). So this script provides a means to do that. If you call this route once a day before your solar is producing power (e.g.: 4am) you get the total lifetime power produced by each inverter, including the previous day. If you track this total lifetime energy value every day, you can then subtract the current day's total from the previous day lifetime total. That gives you the daily production value for that inverter. Note: if your Envoy is connected via low bandwidth Cellular, data only refreshes to Enlighten every 6 hours. So perform this route the next day in the early morning to ensure you get complete data.
100+
Runs the Enlighten API route 'inverters_summary_by_envoy_or_site' to collect the lifetime energy produced by each inverter. The Enphase API lacks the granulatiry of seeing per inveter daily stats. So this script provides a means to do that. If you call this route once a day before your solar is producing power (e.g.: 4am) you get the total lifetime power produced by each inverter, including the previous day. If you track this total lifetime energy value every day, you can then subtract the current day's total from the previous day lifetime total. That gives you the daily production value for that inverter. Note: if your Envoy is connected via low bandwidth Cellular, data only refreshes to Enlighten every 6 hours. So perform this route the next day in the early morning to ensure you get complete data.
67101

68102
The resulting data is stashed in a .json file. The file organizes the data by microinverter (by ID), then by day. So you can easily parse this historical data for daily production values.
69103
For example:

enlighten_v4_config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "<some name>",
3+
"system_id": "<system/site_id",
4+
"api_url": "https://api.enphaseenergy.com/",
5+
"app_api_key": "<your app's api_key>",
6+
"app_client_id": "<your app's client ID>",
7+
"app_client_secret": "<your app's client secret>",
8+
"access_token": "<your access_token from running 'Enpahse Enlighten v4.postman_collection' -> 'Generate OAuth2 access_token'>",
9+
"refresh_token": "<your refresh_token from running 'Enpahse Enlighten v4.postman_collection' -> 'Generate OAuth2 access_token'>",
10+
"spreadsheet_id": "<google sheet_id>"
11+
}

populate_google_sheet.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Author: Daniel Patenaude
2+
# Date: 12/02/2022
3+
# Desc: Populate the enphase data into the google sheet template
4+
15
import datetime
26
import json
37
import os
@@ -20,7 +24,7 @@ def run(config):
2024

2125
# Grab the historical data from the data store
2226
inverter_historical_data = {}
23-
datafile = f'data/inverter_daily_data-{config["site_id"]}.json'
27+
datafile = f'data/inverter_daily_data-{config["system_id"]}.json'
2428
if os.path.isfile(datafile) and os.access(datafile, os.R_OK):
2529
with open(datafile) as json_file:
2630
inverter_historical_data = json.load(json_file)

requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
requests==2.24.0
2+
google-api-python-client==1.12.3
3+
google-auth-httplib2==0.0.4
4+
google-auth-oauthlib==0.4.1

0 commit comments

Comments
 (0)