Skip to content

Commit ce36020

Browse files
authored
Merge pull request #49 from jabetcha/master
RE: Support for new Home Assistant Energy Managment and Stats #16
2 parents baa8ade + 1276bf7 commit ce36020

File tree

6 files changed

+380
-11
lines changed

6 files changed

+380
-11
lines changed

custom_components/fpl/FplMainRegionApiClient.py

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import json
44
import logging
5-
from datetime import datetime
5+
from datetime import datetime, timedelta
66
import aiohttp
77
import async_timeout
88

@@ -125,6 +125,8 @@ async def update(self, account) -> dict:
125125
premise = account_data.get("premiseNumber").zfill(9)
126126

127127
data["meterSerialNo"] = account_data["meterSerialNo"]
128+
#data["meterNo"] = account_data["meterNo"]
129+
meterno = account_data["meterNo"]
128130

129131
# currentBillDate
130132
currentBillDate = datetime.strptime(
@@ -175,15 +177,11 @@ def hasProgram(programName) -> bool:
175177

176178
# Get data from energy service
177179
data.update(
178-
await self.__getDataFromEnergyService(account, premise, currentBillDate)
180+
await self.__getDataFromEnergyService(account, premise, currentBillDate, meterno)
179181
)
180182

181183
# Get data from energy service ( hourly )
182-
# data.update(
183-
# await self.__getDataFromEnergyServiceHourly(
184-
# account, premise, currentBillDate
185-
# )
186-
# )
184+
# data.update(await self.__getDataFromEnergyServiceHourly(account, premise, meterno))
187185

188186
data.update(await self.__getDataFromApplianceUsage(account, currentBillDate))
189187
data.update(await self.__getDataFromBalance(account))
@@ -273,7 +271,7 @@ async def __getBBL_async(self, account, projectedBillData) -> dict:
273271
return data
274272

275273
async def __getDataFromEnergyService(
276-
self, account, premise, lastBilledDate
274+
self, account, premise, lastBilledDate, meterno
277275
) -> dict:
278276
_LOGGER.info("Getting energy service data")
279277

@@ -286,6 +284,7 @@ async def __getDataFromEnergyService(
286284
"accountType": "RESIDENTIAL",
287285
"revCode": "1",
288286
"premiseNumber": premise,
287+
"meterNo": meterno,
289288
"projectedBillFlag": True,
290289
"billComparisionFlag": True,
291290
"monthlyFlag": True,
@@ -341,6 +340,12 @@ async def __getDataFromEnergyService(
341340
"netReceivedKwh": daily["netReceivedKwh"]
342341
if "netReceivedKwh" in daily.keys()
343342
else 0,
343+
"netDeliveredReading": daily["netDeliveredReading"]
344+
if "netDeliveredReading" in daily.keys()
345+
else 0,
346+
"netReceivedReading": daily["netReceivedReading"]
347+
if "netReceivedReading" in daily.keys()
348+
else 0,
344349
"readTime": datetime.fromisoformat(
345350
daily[
346351
"readTime"
@@ -365,6 +370,91 @@ async def __getDataFromEnergyService(
365370

366371
return data
367372

373+
async def __getDataFromEnergyServiceHourly(account, premise, meterno) -> dict:
374+
_LOGGER.info("Getting energy service hourly data")
375+
376+
today = str(datetime.now().strftime("%m%d%Y"))
377+
JSON = {
378+
"status": 2,
379+
"channel": "WEB",
380+
"amrFlag": "Y",
381+
"accountType": "RESIDENTIAL",
382+
"revCode": "1",
383+
"premiseNumber": premise,
384+
"meterNo": meterno,
385+
"projectedBillFlag": False,
386+
"billComparisionFlag": False,
387+
"monthlyFlag": False,
388+
"frequencyType": "Hourly",
389+
"applicationPage": "resDashBoard",
390+
"startDate": today,
391+
"endDate":"",
392+
}
393+
394+
URL_ENERGY_SERVICE = (
395+
API_HOST
396+
+ "/dashboard-api/resources/account/{account}/energyService/{account}"
397+
)
398+
399+
data = {}
400+
try:
401+
async with async_timeout.timeout(TIMEOUT):
402+
response = await self.session.post(
403+
URL_ENERGY_SERVICE.format(account=account), json=JSON
404+
)
405+
if response.status == 200:
406+
rd = await response.json()
407+
if "data" not in rd.keys():
408+
return []
409+
410+
r = rd["data"]
411+
hourlyUsage = []
412+
413+
# totalPowerUsage = 0
414+
if (
415+
"data" in rd.keys()
416+
and "HourlyUsage" in rd["data"]
417+
and "data" in rd["data"]["HourlyUsage"]
418+
):
419+
hourlyData = rd["data"]["HourlyUsage"]["data"]
420+
for hourly in hourlyData:
421+
hourlyUsage.append(
422+
{
423+
"usage": hourly["kwhUsed"]
424+
if "kwhUsed" in hourly.keys()
425+
else None,
426+
"cost": hourly["billingCharged"]
427+
if "billingCharged" in hourly.keys()
428+
else None,
429+
"temperature": hourly["temperature"]
430+
if "temperature" in hourly.keys()
431+
else None,
432+
"netDelivered": hourly["netDelivered"]
433+
if "netDelivered" in hourly.keys()
434+
else 0,
435+
"netReceived": hourly["netReceived"]
436+
if "netReceived" in hourly.keys()
437+
else 0,
438+
"reading": hourly["reading"]
439+
if "reading" in hourly.keys()
440+
else 0,
441+
"kwhActual": hourly["kwhActual"]
442+
if "kwhActual" in hourly.keys()
443+
else 0,
444+
"readTime": datetime.fromisoformat(
445+
hourly[
446+
"readTime"
447+
] # 2022-02-25T00:00:00.000-05:00
448+
),
449+
}
450+
)
451+
452+
data["hourly_usage"] = hourlyUsage
453+
except Exception as e:
454+
_LOGGER.error(e)
455+
456+
return data
457+
368458
async def __getDataFromApplianceUsage(self, account, lastBilledDate) -> dict:
369459
"""get data from appliance usage"""
370460
_LOGGER.info("Getting appliance usage data")

custom_components/fpl/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
from homeassistant.core import Config, HomeAssistant
99
from homeassistant.config_entries import ConfigEntry
1010
from homeassistant.helpers.aiohttp_client import async_get_clientsession
11+
from homeassistant.helpers.entity import DeviceInfo
1112
from homeassistant.util import Throttle
1213
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD
1314

1415
from .fplapi import FplApi
1516
from .const import (
1617
DOMAIN,
1718
DOMAIN_DATA,
19+
NAME,
1820
PLATFORMS,
1921
STARTUP_MESSAGE,
2022
)
@@ -25,6 +27,14 @@
2527

2628
_LOGGER = logging.getLogger(__package__)
2729

30+
def get_device_info():
31+
return DeviceInfo(
32+
identifiers={
33+
("id", NAME),
34+
},
35+
name=NAME,
36+
manufacturer=NAME,
37+
)
2838

2939
class FplData:
3040
"""This class handle communication and stores the data."""

custom_components/fpl/sensor.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,16 @@
3131
FplDailyUsageSensor,
3232
FplDailyDeliveredKWHSensor,
3333
FplDailyReceivedKWHSensor,
34+
FplDailyDeliveredReading,
35+
FplDailyReceivedReading,
3436
)
37+
#from .sensor_HourlyUsageSensor import (
38+
# FplHourlyUsageSensor,
39+
# FplHourlyUsageKWHSensor,
40+
# FplHourlyReceivedKWHSensor,
41+
# FplHourlyDeliveredKWHSensor,
42+
# FplHourlyReadingKWHSensor
43+
#)
3544

3645
from .sensor_BalanceSensor import BalanceSensor
3746

@@ -85,6 +94,15 @@ def registerSensor(sensor, regions):
8594
registerSensor(NetDeliveredKWHSensor, ONLY_MAINREGION)
8695
registerSensor(FplDailyReceivedKWHSensor, ONLY_MAINREGION)
8796
registerSensor(FplDailyDeliveredKWHSensor, ONLY_MAINREGION)
97+
registerSensor(FplDailyDeliveredReading, ONLY_MAINREGION)
98+
registerSensor(FplDailyReceivedReading, ONLY_MAINREGION)
99+
100+
#hourly sensors
101+
# registerSensor(FplHourlyUsageSensor, ONLY_MAINREGION)
102+
# registerSensor(FplHourlyUsageKWHSensor, ONLY_MAINREGION)
103+
# registerSensor(FplHourlyReceivedKWHSensor, ONLY_MAINREGION)
104+
# registerSensor(FplHourlyDeliveredKWHSensor, ONLY_MAINREGION)
105+
# registerSensor(FplHourlyReadingKWHSensor, ONLY_MAINREGION)
88106

89107
# Balance sensors
90108
registerSensor(BalanceSensor, ONLY_MAINREGION)

custom_components/fpl/sensor_DailyUsageSensor.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from datetime import timedelta, datetime
33
from homeassistant.components.sensor import (
44
STATE_CLASS_TOTAL_INCREASING,
5+
STATE_CLASS_TOTAL,
56
DEVICE_CLASS_ENERGY,
67
)
78
from .fplEntity import FplEnergyEntity, FplMoneyEntity
@@ -39,7 +40,7 @@ class FplDailyUsageKWHSensor(FplEnergyEntity):
3940
def __init__(self, coordinator, config, account):
4041
super().__init__(coordinator, config, account, "Daily Usage KWH")
4142

42-
_attr_state_class = STATE_CLASS_TOTAL_INCREASING
43+
_attr_state_class = STATE_CLASS_TOTAL
4344
_attr_device_class = DEVICE_CLASS_ENERGY
4445

4546
@property
@@ -81,7 +82,8 @@ class FplDailyReceivedKWHSensor(FplEnergyEntity):
8182
def __init__(self, coordinator, config, account):
8283
super().__init__(coordinator, config, account, "Daily Received KWH")
8384

84-
# _attr_state_class = STATE_CLASS_TOTAL_INCREASING
85+
_attr_state_class = STATE_CLASS_TOTAL
86+
_attr_device_class = DEVICE_CLASS_ENERGY
8587

8688
@property
8789
def native_value(self):
@@ -92,6 +94,17 @@ def native_value(self):
9294

9395
return self._attr_native_value
9496

97+
@property
98+
def last_reset(self) -> datetime | None:
99+
data = self.getData("daily_usage")
100+
if data is not None and len(data) > 0 and "netReceivedKwh" in data[-1].keys():
101+
date = data[-1]["readTime"]
102+
_attr_last_reset = date - timedelta(days=1)
103+
else:
104+
_attr_last_reset = None
105+
106+
return _attr_last_reset
107+
95108
def customAttributes(self):
96109
"""Return the state attributes."""
97110
data = self.getData("daily_usage")
@@ -108,7 +121,8 @@ def customAttributes(self):
108121
class FplDailyDeliveredKWHSensor(FplEnergyEntity):
109122
"""daily delivered Kwh sensor"""
110123

111-
# _attr_state_class = STATE_CLASS_TOTAL_INCREASING
124+
_attr_state_class = STATE_CLASS_TOTAL
125+
_attr_device_class = DEVICE_CLASS_ENERGY
112126

113127
def __init__(self, coordinator, config, account):
114128
super().__init__(coordinator, config, account, "Daily Delivered KWH")
@@ -121,6 +135,17 @@ def native_value(self):
121135
self._attr_native_value = data[-1]["netDeliveredKwh"]
122136

123137
return self._attr_native_value
138+
139+
@property
140+
def last_reset(self) -> datetime | None:
141+
data = self.getData("daily_usage")
142+
if data is not None and len(data) > 0 and "netDeliveredKwh" in data[-1].keys():
143+
date = data[-1]["readTime"]
144+
_attr_last_reset = date - timedelta(days=1)
145+
else:
146+
_attr_last_reset = None
147+
148+
return _attr_last_reset
124149

125150
def customAttributes(self):
126151
"""Return the state attributes."""
@@ -132,3 +157,40 @@ def customAttributes(self):
132157
attributes["date"] = date
133158
# attributes["last_reset"] = last_reset
134159
return attributes
160+
161+
#jf changes below
162+
class FplDailyReceivedReading(FplEnergyEntity):
163+
"""daily received reading"""
164+
165+
_attr_state_class = STATE_CLASS_TOTAL_INCREASING
166+
_attr_device_class = DEVICE_CLASS_ENERGY
167+
168+
def __init__(self, coordinator, config, account):
169+
super().__init__(coordinator, config, account, "Daily Received reading")
170+
171+
@property
172+
def native_value(self):
173+
data = self.getData("daily_usage")
174+
175+
if data is not None and len(data) > 0 and "netReceivedReading" in data[-1].keys():
176+
self._attr_native_value = data[-1]["netReceivedReading"]
177+
178+
return self._attr_native_value
179+
180+
class FplDailyDeliveredReading(FplEnergyEntity):
181+
"""daily delivered reading"""
182+
183+
_attr_state_class = STATE_CLASS_TOTAL_INCREASING
184+
_attr_device_class = DEVICE_CLASS_ENERGY
185+
186+
def __init__(self, coordinator, config, account):
187+
super().__init__(coordinator, config, account, "Daily Delivered reading")
188+
189+
@property
190+
def native_value(self):
191+
data = self.getData("daily_usage")
192+
193+
if data is not None and len(data) > 0 and "netDeliveredReading" in data[-1].keys():
194+
self._attr_native_value = data[-1]["netDeliveredReading"]
195+
196+
return self._attr_native_value

0 commit comments

Comments
 (0)