Skip to content

Commit

Permalink
Merge pull request #49 from jabetcha/master
Browse files Browse the repository at this point in the history
RE:  Support for new Home Assistant Energy Managment and Stats #16
  • Loading branch information
dotKrad authored Apr 22, 2024
2 parents baa8ade + 1276bf7 commit ce36020
Show file tree
Hide file tree
Showing 6 changed files with 380 additions and 11 deletions.
106 changes: 98 additions & 8 deletions custom_components/fpl/FplMainRegionApiClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import json
import logging
from datetime import datetime
from datetime import datetime, timedelta
import aiohttp
import async_timeout

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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")

Expand All @@ -286,6 +284,7 @@ async def __getDataFromEnergyService(
"accountType": "RESIDENTIAL",
"revCode": "1",
"premiseNumber": premise,
"meterNo": meterno,
"projectedBillFlag": True,
"billComparisionFlag": True,
"monthlyFlag": True,
Expand Down Expand Up @@ -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"
Expand All @@ -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")
Expand Down
10 changes: 10 additions & 0 deletions custom_components/fpl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
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

from .fplapi import FplApi
from .const import (
DOMAIN,
DOMAIN_DATA,
NAME,
PLATFORMS,
STARTUP_MESSAGE,
)
Expand All @@ -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."""
Expand Down
18 changes: 18 additions & 0 deletions custom_components/fpl/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,16 @@
FplDailyUsageSensor,
FplDailyDeliveredKWHSensor,
FplDailyReceivedKWHSensor,
FplDailyDeliveredReading,
FplDailyReceivedReading,
)
#from .sensor_HourlyUsageSensor import (
# FplHourlyUsageSensor,
# FplHourlyUsageKWHSensor,
# FplHourlyReceivedKWHSensor,
# FplHourlyDeliveredKWHSensor,
# FplHourlyReadingKWHSensor
#)

from .sensor_BalanceSensor import BalanceSensor

Expand Down Expand Up @@ -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)
Expand Down
68 changes: 65 additions & 3 deletions custom_components/fpl/sensor_DailyUsageSensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
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
Expand Down Expand Up @@ -39,7 +40,7 @@ class FplDailyUsageKWHSensor(FplEnergyEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Daily Usage KWH")

_attr_state_class = STATE_CLASS_TOTAL_INCREASING
_attr_state_class = STATE_CLASS_TOTAL
_attr_device_class = DEVICE_CLASS_ENERGY

@property
Expand Down Expand Up @@ -81,7 +82,8 @@ class FplDailyReceivedKWHSensor(FplEnergyEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Daily Received KWH")

# _attr_state_class = STATE_CLASS_TOTAL_INCREASING
_attr_state_class = STATE_CLASS_TOTAL
_attr_device_class = DEVICE_CLASS_ENERGY

@property
def native_value(self):
Expand All @@ -92,6 +94,17 @@ def native_value(self):

return self._attr_native_value

@property
def last_reset(self) -> datetime | None:
data = self.getData("daily_usage")
if data is not None and len(data) > 0 and "netReceivedKwh" in data[-1].keys():
date = data[-1]["readTime"]
_attr_last_reset = date - timedelta(days=1)
else:
_attr_last_reset = None

return _attr_last_reset

def customAttributes(self):
"""Return the state attributes."""
data = self.getData("daily_usage")
Expand All @@ -108,7 +121,8 @@ def customAttributes(self):
class FplDailyDeliveredKWHSensor(FplEnergyEntity):
"""daily delivered Kwh sensor"""

# _attr_state_class = STATE_CLASS_TOTAL_INCREASING
_attr_state_class = STATE_CLASS_TOTAL
_attr_device_class = DEVICE_CLASS_ENERGY

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

return self._attr_native_value

@property
def last_reset(self) -> datetime | None:
data = self.getData("daily_usage")
if data is not None and len(data) > 0 and "netDeliveredKwh" in data[-1].keys():
date = data[-1]["readTime"]
_attr_last_reset = date - timedelta(days=1)
else:
_attr_last_reset = None

return _attr_last_reset

def customAttributes(self):
"""Return the state attributes."""
Expand All @@ -132,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
Loading

0 comments on commit ce36020

Please sign in to comment.