1818
1919STATUS_CATEGORY_OPEN = "OPEN"
2020
21+
22+ def _parse_daily_read_time (read_time ):
23+ if not read_time :
24+ return None
25+ if isinstance (read_time , datetime ):
26+ return read_time
27+ try :
28+ return datetime .fromisoformat (read_time )
29+ except (TypeError , ValueError ):
30+ return None
31+
32+
33+ def _find_daily_usage_row (daily_usage ):
34+ daily_rows = daily_usage .get ("data" ) or []
35+ if not daily_rows :
36+ return None
37+ end_date = daily_usage .get ("endDate" )
38+ if end_date :
39+ for day_usage in daily_rows :
40+ if day_usage .get ("date" ) == end_date :
41+ return day_usage
42+ return daily_rows [- 1 ]
43+
44+
45+ def _usage_block_ok (block ):
46+ if not isinstance (block , dict ):
47+ return False
48+ exception = block .get ("exceptionDetails" )
49+ if isinstance (exception , dict ) and exception .get ("requestStatus" ) == "Failed" :
50+ return False
51+ return True
52+
53+
2154# URL_LOGIN = API_HOST + "/api/resources/login"
2255URL_LOGIN = (
2356 API_HOST
@@ -292,10 +325,12 @@ async def get_energy_usage(self, account, premise, lastBilledDate, meterno) -> d
292325
293326 # Tested using MITM proxy and iOS app.
294327 # This is the payload and url used by the iOS app.
328+ # iOS app: status "2" = active/open account, "4" = closed/inactive.
295329 json = {
296330 "status" : "2" ,
297331 "accountType" : "RESIDENTIAL" ,
298332 "premiseNumber" : premise ,
333+ # account select `currentBillDate` is sent as `lastBilledDate` (MMDDYYYY).
299334 "lastBilledDate" : lastBilledDate .strftime ("%m%d%Y" ),
300335 "amrFlag" : "Y" ,
301336 "revCode" : "1" ,
@@ -319,56 +354,67 @@ async def get_energy_usage(self, account, premise, lastBilledDate, meterno) -> d
319354 )
320355 if response .status == 200 :
321356 response_data = await response .json ()
322- json_data = response_data ["data" ]
323-
324- current_usage = json_data ["CurrentUsage" ]
325- data ["projectedKWH" ] = int (current_usage .get ("projectedKWH" ))
326- data ["dailyAverageKWH" ] = float (
327- current_usage .get ("dailyAverageKWH" )
328- )
329- data ["billToDate" ] = float (current_usage .get ("billToDate" ))
330- data ["projectedBill" ] = float (current_usage .get ("projectedBill" ))
331- data ["dailyAvg" ] = float (current_usage .get ("dailyAvg" ))
332- data ["avgHighTemp" ] = int (current_usage .get ("avgHighTemp" ))
333- data ["billToDateKWH" ] = float (current_usage .get ("billToDateKWH" ))
334- data ["recMtrReading" ] = int (current_usage .get ("recMtrReading" ) or 0 )
335- data ["delMtrReading" ] = int (current_usage .get ("delMtrReading" ) or 0 )
336- data ["billStartDate" ] = datetime .strptime (
337- current_usage .get ("billStartDate" ), "%m-%d-%Y"
338- ).date ()
339- data ["billEndDate" ] = datetime .strptime (
340- current_usage .get ("billEndDate" ), "%m-%d-%Y"
341- ).date ()
342-
343- daily_usage = json_data ["DailyUsage" ]
344- last_day_usage = daily_usage ["endDate" ]
345-
346- data ["DailyUsage" ] = {}
347- for day_usage in daily_usage ["data" ]:
348- # We want to get the last day's usage and use that as the sensor information.
349- # Given that this sensor should reset every day to the previous day's usage.
350- if day_usage ["date" ] == last_day_usage :
351- data ["DailyUsage" ]["kwhActual" ] = float (
352- day_usage .get ("kwhActual" ) or 0
353- )
354- data ["DailyUsage" ]["billingCharge" ] = float (
355- day_usage .get ("billingCharge" ) or 0
356- )
357- data ["DailyUsage" ]["readTime" ] = datetime .fromisoformat (
358- day_usage .get ("readTime" )
357+ json_data = response_data .get ("data" ) or {}
358+
359+ current_usage = json_data .get ("CurrentUsage" ) or {}
360+ if _usage_block_ok (current_usage ):
361+ if current_usage .get ("projectedKWH" ) is not None :
362+ data ["projectedKWH" ] = int (current_usage ["projectedKWH" ])
363+ if current_usage .get ("dailyAverageKWH" ) is not None :
364+ data ["dailyAverageKWH" ] = float (
365+ current_usage ["dailyAverageKWH" ]
359366 )
360- data ["DailyUsage" ]["reading" ] = float (
361- day_usage .get ("reading" )
367+ if current_usage .get ("billToDate" ) is not None :
368+ data ["billToDate" ] = float (current_usage ["billToDate" ])
369+ if current_usage .get ("projectedBill" ) is not None :
370+ data ["projectedBill" ] = float (
371+ current_usage ["projectedBill" ]
362372 )
363-
364- # This is most likely not going to work, as this endpoint does not give any information related to delivery metrics.
365- # TODO: Figure out where the delivery metrics can be grabbed from.
366- data ["DailyUsage" ]["netDeliveredKwh" ] = float (
367- day_usage .get ("netDeliveredKwh" ) or 0
373+ if current_usage .get ("dailyAvg" ) is not None :
374+ data ["dailyAvg" ] = float (current_usage ["dailyAvg" ])
375+ if current_usage .get ("avgHighTemp" ) is not None :
376+ data ["avgHighTemp" ] = int (current_usage ["avgHighTemp" ])
377+ if current_usage .get ("billToDateKWH" ) is not None :
378+ data ["billToDateKWH" ] = float (
379+ current_usage ["billToDateKWH" ]
368380 )
369- data ["DailyUsage" ]["netDeliveredReading" ] = float (
370- day_usage .get ("netDeliveredReading" ) or 0
381+ data ["recMtrReading" ] = int (
382+ current_usage .get ("recMtrReading" ) or 0
383+ )
384+ data ["delMtrReading" ] = int (
385+ current_usage .get ("delMtrReading" ) or 0
386+ )
387+ if current_usage .get ("billStartDate" ):
388+ data ["billStartDate" ] = datetime .strptime (
389+ current_usage ["billStartDate" ], "%m-%d-%Y"
390+ ).date ()
391+ if current_usage .get ("billEndDate" ):
392+ data ["billEndDate" ] = datetime .strptime (
393+ current_usage ["billEndDate" ], "%m-%d-%Y"
394+ ).date ()
395+
396+ daily_usage = json_data .get ("DailyUsage" ) or {}
397+ if _usage_block_ok (daily_usage ):
398+ day_usage = _find_daily_usage_row (daily_usage )
399+ if day_usage :
400+ read_time = _parse_daily_read_time (
401+ day_usage .get ("readTime" )
371402 )
403+ if read_time is not None :
404+ data ["DailyUsage" ] = {
405+ "kwhActual" : float (day_usage .get ("kwhActual" ) or 0 ),
406+ "billingCharge" : float (
407+ day_usage .get ("billingCharge" ) or 0
408+ ),
409+ "readTime" : read_time ,
410+ "reading" : float (day_usage .get ("reading" ) or 0 ),
411+ "netDeliveredKwh" : float (
412+ day_usage .get ("netDeliveredKwh" ) or 0
413+ ),
414+ "netDeliveredReading" : float (
415+ day_usage .get ("netDeliveredReading" ) or 0
416+ ),
417+ }
372418
373419 except Exception as e :
374420 _LOGGER .error (e )
0 commit comments