mostly comments and formatting + 2 sensors

This commit is contained in:
Yordan Suarez
2022-01-22 11:54:54 -05:00
parent d99ea36427
commit 3be969883a
10 changed files with 220 additions and 53 deletions

View File

@@ -2,6 +2,10 @@
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.pythonPath": "/usr/local/bin/python",
"python.linting.pylintArgs": [
"--disable=C0103",
"--max-line-length=200"
],
"files.associations": {
"*.yaml": "home-assistant"
}

View File

@@ -1,13 +1,15 @@
"""Data Update Coordinator"""
import logging
from datetime import timedelta
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.core import HomeAssistant
from datetime import timedelta
from .fplapi import FplApi
from .const import DOMAIN
SCAN_INTERVAL = timedelta(seconds=7200)
SCAN_INTERVAL = timedelta(seconds=1200)
_LOGGER: logging.Logger = logging.getLogger(__package__)

View File

@@ -58,8 +58,8 @@ class FplEntity(CoordinatorEntity, SensorEntity):
return attributes
def getData(self, field):
"""method is called to update sensor data"""
return self.coordinator.data.get(self.account).get(field)
"""call this method to retrieve sensor data"""
return self.coordinator.data.get(self.account).get(field, None)
class FplEnergyEntity(FplEntity):
@@ -123,3 +123,21 @@ class FplDateEntity(FplEntity):
@property
def icon(self):
return "mdi:calendar"
class FplDayEntity(FplEntity):
"""Represents a date or days"""
# @property
# def device_class(self) -> str:
# """Return the class of this device, from component DEVICE_CLASSES."""
# return DEVICE_CLASS_DATE
@property
def icon(self):
return "mdi:calendar"
@property
def unit_of_measurement(self) -> str:
"""Return the unit of measurement of this entity, if any."""
return "days"

View File

@@ -1,5 +1,4 @@
"""Custom FPl api client"""
from asyncio import exceptions as asyncio_exceptions
import logging
from datetime import datetime
@@ -17,7 +16,7 @@ LOGIN_RESULT_UNAUTHORIZED = "UNAUTHORIZED"
LOGIN_RESULT_FAILURE = "FAILURE"
_LOGGER = logging.getLogger(__package__)
TIMEOUT = 30
TIMEOUT = 5
API_HOST = "https://www.fpl.com"
@@ -98,7 +97,7 @@ class FplApi:
if json_data["messageCode"] == LOGIN_RESULT_INVALIDPASSWORD:
return LOGIN_RESULT_INVALIDPASSWORD
except asyncio_exceptions as exception:
except Exception as exception:
_LOGGER.error("Error %s : %s", exception, sys.exc_info()[0])
return LOGIN_RESULT_FAILURE
@@ -110,7 +109,7 @@ class FplApi:
try:
async with async_timeout.timeout(TIMEOUT):
await self._session.get(URL_LOGOUT)
except asyncio_exceptions:
except Exception:
pass
async def async_get_open_accounts(self):
@@ -129,8 +128,8 @@ class FplApi:
if account["statusCategory"] == STATUS_CATEGORY_OPEN:
result.append(account["accountNumber"])
except asyncio_exceptions as exception:
_LOGGER.error("Getting accounts %s", exception)
except Exception:
_LOGGER.error("Getting accounts %s", sys.exc_info())
return result
@@ -186,11 +185,13 @@ class FplApi:
def hasProgram(programName) -> bool:
return programName in programs.keys() and programs[programName]
# Budget Billing program
if hasProgram("BBL"):
# budget billing
data["budget_bill"] = True
bbl_data = await self.__getBBL_async(account, data)
data.update(bbl_data)
else:
data["budget_bill"] = False
data.update(
await self.__getDataFromEnergyService(account, premise, currentBillDate)
@@ -227,7 +228,7 @@ class FplApi:
data["daily_avg"] = dailyAvg
data["avg_high_temp"] = avgHighTemp
except asyncio_exceptions:
except Exception:
pass
return data
@@ -267,7 +268,7 @@ class FplApi:
data["budget_billing_bill_to_date"] = bbAsOfDateAmt
data["budget_billing_projected_bill"] = float(projectedBudgetBill)
except asyncio_exceptions:
except Exception:
pass
try:
@@ -279,7 +280,7 @@ class FplApi:
r = (await response.json())["data"]
data["bill_to_date"] = float(r["eleAmt"])
data["defered_amount"] = float(r["defAmt"])
except asyncio_exceptions:
except Exception:
pass
return data
@@ -329,8 +330,15 @@ class FplApi:
{
"usage": daily["kwhUsed"],
"cost": daily["billingCharge"],
"date": daily["date"],
# "date": daily["date"],
"max_temperature": daily["averageHighTemperature"],
"netDeliveredKwh": daily["netDeliveredKwh"]
if "netDeliveredKwh" in daily.keys()
else 0,
"netReceivedKwh": daily["netReceivedKwh"]
if "netReceivedKwh" in daily.keys()
else 0,
"readTime": daily["readTime"],
}
)
# totalPowerUsage += int(daily["kwhUsed"])
@@ -343,6 +351,7 @@ class FplApi:
data["billToDateKWH"] = r["CurrentUsage"]["billToDateKWH"]
data["recMtrReading"] = r["CurrentUsage"]["recMtrReading"]
data["delMtrReading"] = r["CurrentUsage"]["delMtrReading"]
data["billStartDate"] = r["CurrentUsage"]["billStartDate"]
return data
async def __getDataFromApplianceUsage(self, account, lastBilledDate) -> dict:
@@ -368,7 +377,7 @@ class FplApi:
rr = full
data[e["category"].replace(" ", "_")] = rr
except asyncio_exceptions:
except Exception:
pass
return {"energy_percent_by_applicance": data}

View File

@@ -21,14 +21,19 @@ from .sensor_ProjectedBillSensor import (
DeferedAmountSensor,
)
from .sensor_AverageDailySensor import (
FplAverageDailySensor,
DailyAverageSensor,
BudgetDailyAverageSensor,
ActualDailyAverageSensor,
)
from .sensor_DailyUsageSensor import FplDailyUsageKWHSensor, FplDailyUsageSensor
from .sensor_DailyUsageSensor import (
FplDailyUsageKWHSensor,
FplDailyUsageSensor,
FplDailyDeliveredKWHSensor,
FplDailyReceivedKWHSensor,
)
from .const import DOMAIN
from .TestSensor import TestSensor
# from .TestSensor import TestSensor
async def async_setup_entry(hass, entry, async_add_devices):
@@ -49,7 +54,7 @@ async def async_setup_entry(hass, entry, async_add_devices):
fpl_accounts.append(DeferedAmountSensor(coordinator, entry, account))
# usage sensors
fpl_accounts.append(FplAverageDailySensor(coordinator, entry, account))
fpl_accounts.append(DailyAverageSensor(coordinator, entry, account))
fpl_accounts.append(BudgetDailyAverageSensor(coordinator, entry, account))
fpl_accounts.append(ActualDailyAverageSensor(coordinator, entry, account))
@@ -71,4 +76,7 @@ async def async_setup_entry(hass, entry, async_add_devices):
fpl_accounts.append(NetReceivedKWHSensor(coordinator, entry, account))
fpl_accounts.append(NetDeliveredKWHSensor(coordinator, entry, account))
fpl_accounts.append(FplDailyReceivedKWHSensor(coordinator, entry, account))
fpl_accounts.append(FplDailyDeliveredKWHSensor(coordinator, entry, account))
async_add_devices(fpl_accounts)

View File

@@ -1,7 +1,10 @@
"""Average daily sensors"""
from .fplEntity import FplMoneyEntity
class FplAverageDailySensor(FplMoneyEntity):
class DailyAverageSensor(FplMoneyEntity):
"""average daily sensor, use budget value if available, otherwise use actual daily values"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Daily Average")
@@ -10,13 +13,21 @@ class FplAverageDailySensor(FplMoneyEntity):
budget = self.getData("budget_bill")
budget_billing_projected_bill = self.getData("budget_billing_daily_avg")
if budget == True and budget_billing_projected_bill is not None:
if budget and budget_billing_projected_bill is not None:
return self.getData("budget_billing_daily_avg")
return self.getData("daily_avg")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = "total"
return attributes
class BudgetDailyAverageSensor(FplMoneyEntity):
"""budget daily average sensor"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Budget Daily Average")
@@ -24,11 +35,25 @@ class BudgetDailyAverageSensor(FplMoneyEntity):
def state(self):
return self.getData("budget_billing_daily_avg")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = "total"
return attributes
class ActualDailyAverageSensor(FplMoneyEntity):
"""Actual daily average sensor"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Actual Daily Average")
@property
def state(self):
return self.getData("daily_avg")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = "total"
return attributes

View File

@@ -20,11 +20,12 @@ class FplDailyUsageSensor(FplMoneyEntity):
def defineAttributes(self):
"""Return the state attributes."""
data = self.getData("daily_usage")
attributes = {}
attributes["state_class"] = "total_increasing"
if data is not None and len(data) > 0 and "readTime" in data[-1].keys():
attributes["date"] = data[-1]["readTime"]
if data is not None and len(data) > 0 and "date" in data[-1].keys():
return {"date": data[-1]["date"]}
return {}
return attributes
class FplDailyUsageKWHSensor(FplEnergyEntity):
@@ -45,8 +46,61 @@ class FplDailyUsageKWHSensor(FplEnergyEntity):
def defineAttributes(self):
"""Return the state attributes."""
data = self.getData("daily_usage")
attributes = {}
attributes["state_class"] = "total_increasing"
if data is not None and len(data) > 0 and "date" in data[-1].keys():
return {"date": data[-1]["date"]}
if data is not None:
if data[-1] is not None and "readTime" in data[-1].keys():
attributes["date"] = data[-1]["readTime"]
if data[-2] is not None and "readTime" in data[-2].keys():
attributes["last_reset"] = data[-2]["readTime"]
return {}
return attributes
class FplDailyReceivedKWHSensor(FplEnergyEntity):
"""daily received Kwh sensor"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Daily Received KWH")
@property
def state(self):
data = self.getData("daily_usage")
if data is not None and len(data) > 0 and "netReceivedKwh" in data[-1].keys():
return data[-1]["netReceivedKwh"]
return 0
def defineAttributes(self):
"""Return the state attributes."""
data = self.getData("daily_usage")
attributes = {}
attributes["state_class"] = "total_increasing"
attributes["date"] = data[-1]["readTime"]
attributes["last_reset"] = data[-2]["readTime"]
return attributes
class FplDailyDeliveredKWHSensor(FplEnergyEntity):
"""daily delivered Kwh sensor"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Daily Delivered KWH")
@property
def state(self):
data = self.getData("daily_usage")
if data is not None and len(data) > 0 and "netDeliveredKwh" in data[-1].keys():
return data[-1]["netDeliveredKwh"]
return 0
def defineAttributes(self):
"""Return the state attributes."""
data = self.getData("daily_usage")
attributes = {}
attributes["state_class"] = "total_increasing"
attributes["date"] = data[-1]["readTime"]
attributes["last_reset"] = data[-2]["readTime"]
return attributes

View File

@@ -1,4 +1,6 @@
from .fplEntity import FplDateEntity
"""dates sensors"""
import datetime
from .fplEntity import FplDateEntity, FplDayEntity
class CurrentBillDateSensor(FplDateEntity):
@@ -7,7 +9,7 @@ class CurrentBillDateSensor(FplDateEntity):
@property
def state(self):
return self.getData("current_bill_date")
return datetime.date.fromisoformat(self.getData("current_bill_date"))
class NextBillDateSensor(FplDateEntity):
@@ -16,10 +18,10 @@ class NextBillDateSensor(FplDateEntity):
@property
def state(self):
return self.getData("next_bill_date")
return datetime.date.fromisoformat(self.getData("next_bill_date"))
class ServiceDaysSensor(FplDateEntity):
class ServiceDaysSensor(FplDayEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Service Days")
@@ -28,7 +30,7 @@ class ServiceDaysSensor(FplDateEntity):
return self.getData("service_days")
class AsOfDaysSensor(FplDateEntity):
class AsOfDaysSensor(FplDayEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "As Of Days")
@@ -37,7 +39,7 @@ class AsOfDaysSensor(FplDateEntity):
return self.getData("as_of_days")
class RemainingDaysSensor(FplDateEntity):
class RemainingDaysSensor(FplDayEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Remaining Days")

View File

@@ -1,4 +1,8 @@
from homeassistant.components.sensor import STATE_CLASS_TOTAL_INCREASING
"""energy sensors"""
from homeassistant.components.sensor import (
STATE_CLASS_TOTAL_INCREASING,
STATE_CLASS_TOTAL,
)
from .fplEntity import FplEnergyEntity
@@ -10,6 +14,12 @@ class ProjectedKWHSensor(FplEnergyEntity):
def state(self):
return self.getData("projectedKWH")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = STATE_CLASS_TOTAL
return attributes
class DailyAverageKWHSensor(FplEnergyEntity):
def __init__(self, coordinator, config, account):
@@ -19,6 +29,12 @@ class DailyAverageKWHSensor(FplEnergyEntity):
def state(self):
return self.getData("dailyAverageKWH")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = STATE_CLASS_TOTAL
return attributes
class BillToDateKWHSensor(FplEnergyEntity):
def __init__(self, coordinator, config, account):
@@ -28,9 +44,11 @@ class BillToDateKWHSensor(FplEnergyEntity):
def state(self):
return self.getData("billToDateKWH")
@property
def state_class(self) -> str:
"""Return the state class of this entity, from STATE_CLASSES, if any."""
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = STATE_CLASS_TOTAL_INCREASING
return attributes
class NetReceivedKWHSensor(FplEnergyEntity):
@@ -41,9 +59,11 @@ class NetReceivedKWHSensor(FplEnergyEntity):
def state(self):
return self.getData("recMtrReading")
@property
def icon(self):
return "mdi:flash"
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = STATE_CLASS_TOTAL_INCREASING
return attributes
class NetDeliveredKWHSensor(FplEnergyEntity):
@@ -54,6 +74,8 @@ class NetDeliveredKWHSensor(FplEnergyEntity):
def state(self):
return self.getData("delMtrReading")
@property
def icon(self):
return "mdi:flash"
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = STATE_CLASS_TOTAL_INCREASING
return attributes

View File

@@ -1,7 +1,10 @@
"""Projected bill sensors"""
from .fplEntity import FplMoneyEntity
class FplProjectedBillSensor(FplMoneyEntity):
"""projected bill sensor"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Projected Bill")
@@ -10,7 +13,7 @@ class FplProjectedBillSensor(FplMoneyEntity):
budget = self.getData("budget_bill")
budget_billing_projected_bill = self.getData("budget_billing_projected_bill")
if budget == True and budget_billing_projected_bill is not None:
if budget and budget_billing_projected_bill is not None:
return self.getData("budget_billing_projected_bill")
return self.getData("projected_bill")
@@ -18,28 +21,34 @@ class FplProjectedBillSensor(FplMoneyEntity):
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
try:
if self.getData("budget_bill") == True:
attributes["state_class"] = "total"
attributes["budget_bill"] = self.getData("budget_bill")
except:
pass
return attributes
# Defered Amount
class DeferedAmountSensor(FplMoneyEntity):
"""Defered amount sensor"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Defered Amount")
@property
def state(self):
if self.getData("budget_bill") == True:
if self.getData("budget_bill"):
return self.getData("defered_amount")
return 0
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = "total"
return attributes
class ProjectedBudgetBillSensor(FplMoneyEntity):
"""projected budget bill sensor"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Projected Budget Bill")
@@ -47,11 +56,25 @@ class ProjectedBudgetBillSensor(FplMoneyEntity):
def state(self):
return self.getData("budget_billing_projected_bill")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = "total"
return attributes
class ProjectedActualBillSensor(FplMoneyEntity):
"""projeted actual bill sensor"""
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Projected Actual Bill")
@property
def state(self):
return self.getData("projected_bill")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
attributes["state_class"] = "total"
return attributes