1414import requests
1515import tenacity
1616from dotenv import load_dotenv
17- from tesla_powerwall import Powerwall , MeterType
17+ from tesla_powerwall .powerwall import Powerwall
18+ from tesla_powerwall .const import MeterType
1819
1920
2021##### environment variables
2122# load environment variables from a file if they're there
2223load_dotenv ('env.list' , override = False )
2324
24- # this script expects five environment variables to be set
25+ # this script expects these environment variables to be set
2526# New Relic key
2627INSIGHTS_API_KEY = os .environ .get ('INSIGHTS_API_KEY' )
2728
28- # ZIPSTRING is for the wether API. In the US it takes the form '<ZIPCODE>, us'
29- ZIPSTRING = f"{ os .environ .get ('ZIP' )} ,us"
30- WEATHER_KEY = os .environ .get ("WEATHER_KEY" )
29+ # Weather lat/long and key
30+ WEATHER_LAT = os .environ .get ('WEATHER_LAT' )
31+ WEATHER_LON = os .environ .get ('WEATHER_LON' )
32+ WEATHER_KEY = os .environ .get ('WEATHER_KEY' )
33+
34+ # powerwall username
35+ PW_USER = os .environ .get ('PW_USER' )
3136
3237# powerwall password
33- PW_PASS = os .environ .get (" PW_PASS" )
38+ PW_PASS = os .environ .get (' PW_PASS' )
3439
3540# Am I running as a service? Part of a hack to let me run via CLI.
3641AS_SERVICE = os .environ .get ('AS_SERVICE' )
37- ##### end environment variables
38-
3942
40-
41- ##### constants
4243# How often does the script poll when run as a service?
43- # this is not an environment variable
44- POLL_INTERVAL = 60
44+ POLL_INTERVAL = int (os .environ .get ('POLL_INTERVAL' ))
4545
4646# powerwall hostname or IP.
4747# The powerwall's self-signed certificate only responds to
4848# hostnamnes "powerwall", "teg", or "powerpack", and of course you have to have DNS set up properly.
4949# IP addresses work, too.
50- PW_ADDR = 'powerwall'
50+ PW_ADDR = os . environ . get ( "PW_ADDR" )
5151
52+ ##### end environment variables
53+
54+ ##### constants
5255# URL to post to
5356URL = 'https://metric-api.newrelic.com/metric/v1'
5457
@@ -81,13 +84,12 @@ def post_metrics(data):
8184# because the gateway is very slow to respond
8285# and it has some absurdly low rate limit
8386
84-
8587@tenacity .retry (stop = tenacity .stop_after_attempt (7 ),
8688 wait = tenacity .wait_random (min = 3 , max = 7 ))
8789def get_pw ():
8890 """Return a Powerwall connection object."""
8991 pw = Powerwall (PW_ADDR )
90- pw .login (PW_PASS )
92+ loginResult = pw .login (PW_PASS , PW_USER )
9193 return pw
9294
9395
@@ -100,9 +102,10 @@ def connect():
100102@tenacity .retry (stop = tenacity .stop_after_attempt (7 ),
101103 wait = tenacity .wait_random (min = 3 , max = 7 ))
102104def get_weather ():
103- """Return weather for a given zipstring ."""
105+ """Return weather for a given lat/lon ."""
104106 params = {
105- 'zip' : ZIPSTRING ,
107+ 'lat' : WEATHER_LAT ,
108+ 'lon' : WEATHER_LON ,
106109 'appid' : WEATHER_KEY ,
107110 'units' : 'imperial' ,
108111 }
@@ -120,11 +123,11 @@ def get_data():
120123 # worth it.
121124 pw , m = connect ()
122125
123- # # WHY DO I NEED TO DO THIS? I SWEAR THIS USED TO WORK.
124- m . battery = m .get_meter (MeterType .BATTERY )
125- m . load = m .get_meter (MeterType .LOAD )
126- m . site = m .get_meter (MeterType .SITE )
127- m . solar = m .get_meter (MeterType .SOLAR )
126+ # Get a copy of each meter
127+ batteryMeter = m .get_meter (MeterType .BATTERY )
128+ loadMeter = m .get_meter (MeterType .LOAD )
129+ siteMeter = m .get_meter (MeterType .SITE )
130+ solarMeter = m .get_meter (MeterType .SOLAR )
128131
129132 weather = get_weather ()
130133
@@ -149,27 +152,27 @@ def get_data():
149152 weather ['sys' ]['sunrise' ] *= 1000
150153 weather ['sys' ]['sunset' ] *= 1000
151154 if now > weather ['sys' ]['sunrise' ] and now < weather ['sys' ]['sunset' ]:
152- is_sun_up = True
155+ is_daytime = True
153156 else :
154- is_sun_up = False
157+ is_daytime = False
155158
156159 metric_data = {
157160 'solar' : [
158161 ('battery_charge_pct' , round (pw .get_charge (), 1 )),
159- ('battery.imported' , m . battery .energy_imported ),
160- ('battery.exported' , m . battery .energy_exported ),
161- ('house.imported' , m . load .energy_imported ),
162- ('house.exported' , m . load .energy_exported ),
163- ('grid.imported' , m . site .energy_imported ),
164- ('grid.exported' , m . site .energy_exported ),
165- ('solar.imported' , m . solar .energy_imported ),
166- ('solar.exported' , m . solar .energy_exported ),
162+ ('battery.imported' , batteryMeter .energy_imported ),
163+ ('battery.exported' , batteryMeter .energy_exported ),
164+ ('house.imported' , loadMeter .energy_imported ),
165+ ('house.exported' , loadMeter .energy_exported ),
166+ ('grid.imported' , siteMeter .energy_imported ),
167+ ('grid.exported' , siteMeter .energy_exported ),
168+ ('solar.imported' , solarMeter .energy_imported ),
169+ ('solar.exported' , solarMeter .energy_exported ),
167170 ],
168171 'weather' : [
169172 ('cloud_coverage_pct' , weather ['clouds' ]['all' ]),
170173 ('visibility' , weather ['visibility' ]),
171174 ('temperature' , weather ['main' ]['temp' ]),
172- ('is_sun_up ' , is_sun_up ),
175+ ('is_daytime ' , is_daytime ),
173176 ]
174177 }
175178
@@ -195,45 +198,45 @@ def get_data():
195198 to_solar = make_gauge ('solar.to_solar' , 0 )
196199 from_solar = make_gauge ('solar.from_solar' , 0 )
197200
198- if m . solar .instant_power > 0 :
199- from_solar = make_gauge ('solar.from_solar' , m . solar .instant_power )
200- elif m . solar .instant_power < 0 :
201- to_solar = make_gauge ('solar.to_solar' , abs (m . solar .instant_power ))
201+ if solarMeter .instant_power > 0 :
202+ from_solar = make_gauge ('solar.from_solar' , solarMeter .instant_power )
203+ elif solarMeter .instant_power < 0 :
204+ to_solar = make_gauge ('solar.to_solar' , abs (solarMeter .instant_power ))
202205 data ['metrics' ].append (to_solar )
203206 data ['metrics' ].append (from_solar )
204207
205208 # 'to_grid',
206209 # 'from_grid',
207210 to_grid = make_gauge ('solar.to_grid' , 0 )
208211 from_grid = make_gauge ('solar.from_grid' , 0 )
209- if m . site .instant_power > 0 :
210- from_grid = make_gauge ('solar.from_grid' , m . site .instant_power )
211- elif m . site .instant_power < 0 :
212- to_grid = make_gauge ('solar.to_grid' , abs (m . site .instant_power ))
212+ if siteMeter .instant_power > 0 :
213+ from_grid = make_gauge ('solar.from_grid' , siteMeter .instant_power )
214+ elif siteMeter .instant_power < 0 :
215+ to_grid = make_gauge ('solar.to_grid' , abs (siteMeter .instant_power ))
213216 data ['metrics' ].append (to_grid )
214217 data ['metrics' ].append (from_grid )
215218
216219 # 'to_house',
217220 # 'from_house',
218221 to_house = make_gauge ('solar.to_house' , 0 )
219222 from_house = make_gauge ('solar.from_house' , 0 )
220- if m . load .instant_power > 0 :
221- to_house = make_gauge ('solar.to_house' , m . load .instant_power )
222- elif m . load .instant_power < 0 :
223- from_house = make_gauge ('solar.from_house' , abs (m . load .instant_power ))
223+ if loadMeter .instant_power > 0 :
224+ to_house = make_gauge ('solar.to_house' , loadMeter .instant_power )
225+ elif loadMeter .instant_power < 0 :
226+ from_house = make_gauge ('solar.from_house' , abs (loadMeter .instant_power ))
224227 data ['metrics' ].append (to_house )
225228 data ['metrics' ].append (from_house )
226229
227230 # 'to_battery',
228231 # 'from_battery',
229232 to_battery = make_gauge ('solar.to_battery' , 0 )
230233 from_battery = make_gauge ('solar.from_battery' , 0 )
231- if m . battery .instant_power > 0 :
234+ if batteryMeter .instant_power > 0 :
232235 from_battery = make_gauge (
233- 'solar.from_battery' , m . battery .instant_power )
234- elif m . battery .instant_power < 0 :
236+ 'solar.from_battery' , batteryMeter .instant_power )
237+ elif batteryMeter .instant_power < 0 :
235238 to_battery = make_gauge (
236- 'solar.to_battery' , abs (m . battery .instant_power ))
239+ 'solar.to_battery' , abs (batteryMeter .instant_power ))
237240 data ['metrics' ].append (to_battery )
238241 data ['metrics' ].append (from_battery )
239242
@@ -275,4 +278,4 @@ def run_from_cli():
275278 print ('submitted at' , dt .now (), "return code" , ret )
276279 if not AS_SERVICE :
277280 run_from_cli ()
278- time .sleep (60 )
281+ time .sleep (POLL_INTERVAL )
0 commit comments