diff --git a/custom_components/fpl/FplMainRegionApiClient.py b/custom_components/fpl/FplMainRegionApiClient.py index 6fd1faf..1b8b01f 100644 --- a/custom_components/fpl/FplMainRegionApiClient.py +++ b/custom_components/fpl/FplMainRegionApiClient.py @@ -2,7 +2,7 @@ import json import logging -from datetime import datetime +from datetime import datetime, timedelta import aiohttp import async_timeout @@ -125,6 +125,8 @@ async def update(self, account) -> dict: premise = account_data.get("premiseNumber").zfill(9) data["meterSerialNo"] = account_data["meterSerialNo"] + #data["meterNo"] = account_data["meterNo"] + meterno = account_data["meterNo"] # currentBillDate currentBillDate = datetime.strptime( @@ -175,15 +177,11 @@ def hasProgram(programName) -> bool: # Get data from energy service data.update( - await self.__getDataFromEnergyService(account, premise, currentBillDate) + await self.__getDataFromEnergyService(account, premise, currentBillDate, meterno) ) # Get data from energy service ( hourly ) - # data.update( - # await self.__getDataFromEnergyServiceHourly( - # account, premise, currentBillDate - # ) - # ) + # data.update(await self.__getDataFromEnergyServiceHourly(account, premise, meterno)) data.update(await self.__getDataFromApplianceUsage(account, currentBillDate)) data.update(await self.__getDataFromBalance(account)) @@ -273,7 +271,7 @@ async def __getBBL_async(self, account, projectedBillData) -> dict: return data async def __getDataFromEnergyService( - self, account, premise, lastBilledDate + self, account, premise, lastBilledDate, meterno ) -> dict: _LOGGER.info("Getting energy service data") @@ -286,6 +284,7 @@ async def __getDataFromEnergyService( "accountType": "RESIDENTIAL", "revCode": "1", "premiseNumber": premise, + "meterNo": meterno, "projectedBillFlag": True, "billComparisionFlag": True, "monthlyFlag": True, @@ -341,6 +340,12 @@ async def __getDataFromEnergyService( "netReceivedKwh": daily["netReceivedKwh"] if "netReceivedKwh" in daily.keys() else 0, + "netDeliveredReading": daily["netDeliveredReading"] + if "netDeliveredReading" in daily.keys() + else 0, + "netReceivedReading": daily["netReceivedReading"] + if "netReceivedReading" in daily.keys() + else 0, "readTime": datetime.fromisoformat( daily[ "readTime" @@ -365,6 +370,91 @@ async def __getDataFromEnergyService( return data + async def __getDataFromEnergyServiceHourly(account, premise, meterno) -> dict: + _LOGGER.info("Getting energy service hourly data") + + today = str(datetime.now().strftime("%m%d%Y")) + JSON = { + "status": 2, + "channel": "WEB", + "amrFlag": "Y", + "accountType": "RESIDENTIAL", + "revCode": "1", + "premiseNumber": premise, + "meterNo": meterno, + "projectedBillFlag": False, + "billComparisionFlag": False, + "monthlyFlag": False, + "frequencyType": "Hourly", + "applicationPage": "resDashBoard", + "startDate": today, + "endDate":"", + } + + URL_ENERGY_SERVICE = ( + API_HOST + + "/dashboard-api/resources/account/{account}/energyService/{account}" + ) + + data = {} + try: + async with async_timeout.timeout(TIMEOUT): + response = await self.session.post( + URL_ENERGY_SERVICE.format(account=account), json=JSON + ) + if response.status == 200: + rd = await response.json() + if "data" not in rd.keys(): + return [] + + r = rd["data"] + hourlyUsage = [] + + # totalPowerUsage = 0 + if ( + "data" in rd.keys() + and "HourlyUsage" in rd["data"] + and "data" in rd["data"]["HourlyUsage"] + ): + hourlyData = rd["data"]["HourlyUsage"]["data"] + for hourly in hourlyData: + hourlyUsage.append( + { + "usage": hourly["kwhUsed"] + if "kwhUsed" in hourly.keys() + else None, + "cost": hourly["billingCharged"] + if "billingCharged" in hourly.keys() + else None, + "temperature": hourly["temperature"] + if "temperature" in hourly.keys() + else None, + "netDelivered": hourly["netDelivered"] + if "netDelivered" in hourly.keys() + else 0, + "netReceived": hourly["netReceived"] + if "netReceived" in hourly.keys() + else 0, + "reading": hourly["reading"] + if "reading" in hourly.keys() + else 0, + "kwhActual": hourly["kwhActual"] + if "kwhActual" in hourly.keys() + else 0, + "readTime": datetime.fromisoformat( + hourly[ + "readTime" + ] # 2022-02-25T00:00:00.000-05:00 + ), + } + ) + + data["hourly_usage"] = hourlyUsage + except Exception as e: + _LOGGER.error(e) + + return data + async def __getDataFromApplianceUsage(self, account, lastBilledDate) -> dict: """get data from appliance usage""" _LOGGER.info("Getting appliance usage data") diff --git a/custom_components/fpl/__init__.py b/custom_components/fpl/__init__.py index 1a7788e..5602936 100644 --- a/custom_components/fpl/__init__.py +++ b/custom_components/fpl/__init__.py @@ -8,6 +8,7 @@ from homeassistant.core import Config, HomeAssistant from homeassistant.config_entries import ConfigEntry from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.entity import DeviceInfo from homeassistant.util import Throttle from homeassistant.const import CONF_USERNAME, CONF_PASSWORD @@ -15,6 +16,7 @@ from .const import ( DOMAIN, DOMAIN_DATA, + NAME, PLATFORMS, STARTUP_MESSAGE, ) @@ -25,6 +27,14 @@ _LOGGER = logging.getLogger(__package__) +def get_device_info(): + return DeviceInfo( + identifiers={ + ("id", NAME), + }, + name=NAME, + manufacturer=NAME, + ) class FplData: """This class handle communication and stores the data.""" diff --git a/custom_components/fpl/sensor.py b/custom_components/fpl/sensor.py index b767919..77659b3 100644 --- a/custom_components/fpl/sensor.py +++ b/custom_components/fpl/sensor.py @@ -31,7 +31,16 @@ FplDailyUsageSensor, FplDailyDeliveredKWHSensor, FplDailyReceivedKWHSensor, + FplDailyDeliveredReading, + FplDailyReceivedReading, ) +#from .sensor_HourlyUsageSensor import ( +# FplHourlyUsageSensor, +# FplHourlyUsageKWHSensor, +# FplHourlyReceivedKWHSensor, +# FplHourlyDeliveredKWHSensor, +# FplHourlyReadingKWHSensor +#) from .sensor_BalanceSensor import BalanceSensor @@ -85,6 +94,15 @@ def registerSensor(sensor, regions): registerSensor(NetDeliveredKWHSensor, ONLY_MAINREGION) registerSensor(FplDailyReceivedKWHSensor, ONLY_MAINREGION) registerSensor(FplDailyDeliveredKWHSensor, ONLY_MAINREGION) +registerSensor(FplDailyDeliveredReading, ONLY_MAINREGION) +registerSensor(FplDailyReceivedReading, ONLY_MAINREGION) + +#hourly sensors +# registerSensor(FplHourlyUsageSensor, ONLY_MAINREGION) +# registerSensor(FplHourlyUsageKWHSensor, ONLY_MAINREGION) +# registerSensor(FplHourlyReceivedKWHSensor, ONLY_MAINREGION) +# registerSensor(FplHourlyDeliveredKWHSensor, ONLY_MAINREGION) +# registerSensor(FplHourlyReadingKWHSensor, ONLY_MAINREGION) # Balance sensors registerSensor(BalanceSensor, ONLY_MAINREGION) diff --git a/custom_components/fpl/sensor_DailyUsageSensor.py b/custom_components/fpl/sensor_DailyUsageSensor.py index ee7a0c5..af22fd4 100644 --- a/custom_components/fpl/sensor_DailyUsageSensor.py +++ b/custom_components/fpl/sensor_DailyUsageSensor.py @@ -157,3 +157,40 @@ def customAttributes(self): attributes["date"] = date # attributes["last_reset"] = last_reset return attributes + +#jf changes below +class FplDailyReceivedReading(FplEnergyEntity): + """daily received reading""" + + _attr_state_class = STATE_CLASS_TOTAL_INCREASING + _attr_device_class = DEVICE_CLASS_ENERGY + + def __init__(self, coordinator, config, account): + super().__init__(coordinator, config, account, "Daily Received reading") + + @property + def native_value(self): + data = self.getData("daily_usage") + + if data is not None and len(data) > 0 and "netReceivedReading" in data[-1].keys(): + self._attr_native_value = data[-1]["netReceivedReading"] + + return self._attr_native_value + +class FplDailyDeliveredReading(FplEnergyEntity): + """daily delivered reading""" + + _attr_state_class = STATE_CLASS_TOTAL_INCREASING + _attr_device_class = DEVICE_CLASS_ENERGY + + def __init__(self, coordinator, config, account): + super().__init__(coordinator, config, account, "Daily Delivered reading") + + @property + def native_value(self): + data = self.getData("daily_usage") + + if data is not None and len(data) > 0 and "netDeliveredReading" in data[-1].keys(): + self._attr_native_value = data[-1]["netDeliveredReading"] + + return self._attr_native_value diff --git a/custom_components/fpl/sensor_HourlyUsageSensor.py b/custom_components/fpl/sensor_HourlyUsageSensor.py new file mode 100644 index 0000000..0908546 --- /dev/null +++ b/custom_components/fpl/sensor_HourlyUsageSensor.py @@ -0,0 +1,183 @@ +"""Hourly Usage Sensors""" +from datetime import timedelta, datetime +from homeassistant.components.sensor import ( + STATE_CLASS_TOTAL_INCREASING, + STATE_CLASS_TOTAL, + DEVICE_CLASS_ENERGY, +) +from .fplEntity import FplEnergyEntity, FplMoneyEntity +#from homeassistant_historical_sensor import ( +# HistoricalSensor, HistoricalState, PollUpdateMixin, +#) + + +class FplHourlyUsageSensor(FplMoneyEntity): + """Hourly Usage Cost Sensor""" + + def __init__(self, coordinator, config, account): + super().__init__(coordinator, config, account, "Hourly Usage") + + @property + def native_value(self): + data = self.getData("hourly_usage") + + if data is not None and len(data) > 0 and "cost" in data[-1].keys(): + self._attr_native_value = data[-1]["cost"] + + return self._attr_native_value + + def customAttributes(self): + """Return the state attributes.""" + data = self.getData("hourly_usage") + attributes = {} + + if data is not None and len(data) > 0 and "readTime" in data[-1].keys(): + attributes["date"] = data[-1]["readTime"] + + return attributes + + +class FplHourlyUsageKWHSensor(FplEnergyEntity): + """Hourly Usage Kwh Sensor""" + + def __init__(self, coordinator, config, account): + super().__init__(coordinator, config, account, "Hourly Usage KWH") + + # _attr_state_class = STATE_CLASS_TOTAL + _attr_device_class = DEVICE_CLASS_ENERGY + + @property def statistic_id(self) -> str: + return self.entity_id + + #@property + #def native_value(self): + # data = self.getData("hourly_usage") + + # if data is not None and len(data) > 0 and "kwhActual" in data[-1].keys(): + # self._attr_native_value = data[-1]["kwhActual"] + + # return self._attr_native_value + + #@property + #def last_reset(self) -> datetime | None: + # data = self.getData("hourly_usage") + # if data is not None and len(data) > 0 and "readTime" in data[-1].keys(): + # date = data[-1]["readTime"] + # _attr_last_reset = date + # else: + # _attr_last_reset = None + + # return _attr_last_reset + + def customAttributes(self): + + attributes = {} + + return attributes + + +class FplHourlyReceivedKWHSensor(FplEnergyEntity): + """hourly received Kwh sensor""" + + def __init__(self, coordinator, config, account): + super().__init__(coordinator, config, account, "Hourly Received KWH") + + def get_statistic_metadata(self) -> StatisticMetaData: + meta = super().get_statistic_metadata() meta["has_sum"] = True + meta["has_mean"] = True + + return meta + + # _attr_state_class = STATE_CLASS_TOTAL + _attr_device_class = DEVICE_CLASS_ENERGY + + @property def statistic_id(self) -> str: + return self.entity_id + + + #@property + #def native_value(self): + # data = self.getData("hourly_usage") + + # if data is not None and len(data) > 0 and "netReceived" in data[-1].keys(): + # self._attr_native_value = data[-1]["netReceived"] + + # return self._attr_native_value + + #@property + #def last_reset(self) -> datetime | None: + # data = self.getData("hourly_usage") + # if data is not None and len(data) > 0 and "readTime" in data[-1].keys(): + # date = data[-1]["readTime"] + # _attr_last_reset = date + # else: + # _attr_last_reset = None + + # return _attr_last_reset + + def customAttributes(self): + + attributes = {} + + return attributes + + +class FplHourlyDeliveredKWHSensor(FplEnergyEntity): + """hourly delivered Kwh sensor""" + + #_attr_state_class = STATE_CLASS_TOTAL + _attr_device_class = DEVICE_CLASS_ENERGY + + def __init__(self, coordinator, config, account): + super().__init__(coordinator, config, account, "Hourly Delivered KWH") + + #@property + #def native_value(self): + # data = self.getData("hourly_usage") + + # if data is not None and len(data) > 0 and "netDelivered" in data[-1].keys(): + # self._attr_native_value = data[-1]["netDelivered"] + + # return self._attr_native_value + + #@property + #def last_reset(self) -> datetime | None: + # data = self.getData("hourly_usage") + # if data is not None and len(data) > 0 and "readTime" in data[-1].keys(): + # date = data[-1]["readTime"] + # _attr_last_reset = date + # else: + # _attr_last_reset = None + + # return _attr_last_reset + + def customAttributes(self): + + attributes = {} + + return attributes + +class FplHourlyReadingKWHSensor(FplEnergyEntity): + """hourly reading Kwh sensor""" + + #_attr_state_class = STATE_CLASS_TOTAL_INCREASING + _attr_device_class = DEVICE_CLASS_ENERGY + + def __init__(self, coordinator, config, account): + super().__init__(coordinator, config, account, "Hourly reading KWH") + + #@property + #def native_value(self): + # data = self.getData("hourly_usage") + + # if data is not None and len(data) > 0 and "reading" in data[-1].keys(): + # self._attr_native_value = data[-1]["reading"] + + # return self._attr_native_value + + + def customAttributes(self): + + attributes = {} + + return attributes \ No newline at end of file