bug fixes

This commit is contained in:
Yordan Suarez
2021-06-05 18:37:17 -04:00
parent edff06c22d
commit dc2a97e404
17 changed files with 698 additions and 192 deletions

View File

@@ -1,5 +1,5 @@
default_config:
logger:
default: info
default: error
logs:
custom_components.fpl: debug

View File

@@ -0,0 +1,28 @@
from .fplEntity import FplEntity
import pprint
class TestSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Test Sensor")
@property
def state(self):
pprint.pprint(self.coordinator.data)
return self.getData("projected_bill")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
try:
if self.getData("budget_bill"):
attributes["budget_bill"] = self.getData("budget_bill")
except:
pass
return attributes
@property
def icon(self):
return "mdi:currency-usd"

View File

@@ -1,18 +1,29 @@
""" FPL Component """
import logging
import asyncio
from datetime import timedelta
from homeassistant.core import Config, HomeAssistant
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.util import Throttle
from .fplapi import FplApi
from .const import DOMAIN_DATA, CONF_USERNAME, CONF_PASSWORD
from .const import (
DOMAIN,
DOMAIN_DATA,
CONF_USERNAME,
CONF_PASSWORD,
PLATFORMS,
STARTUP_MESSAGE,
)
from .fplDataUpdateCoordinator import FplDataUpdateCoordinator
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
_LOGGER = logging.getLogger(__name__)
from .config_flow import FplFlowHandler
from .const import DOMAIN
_LOGGER = logging.getLogger(__package__)
class FplData:
@@ -39,32 +50,58 @@ async def async_setup(hass: HomeAssistant, config: Config) -> bool:
return True
async def async_setup_entry(hass, config_entry):
async def async_setup_entry(hass, entry):
"""Set up this integration using UI."""
if hass.data.get(DOMAIN) is None:
hass.data.setdefault(DOMAIN, {})
_LOGGER.info(STARTUP_MESSAGE)
# Get "global" configuration.
username = config_entry.data.get(CONF_USERNAME)
password = config_entry.data.get(CONF_PASSWORD)
# Create DATA dict
hass.data[DOMAIN_DATA] = {}
username = entry.data.get(CONF_USERNAME)
password = entry.data.get(CONF_PASSWORD)
# Configure the client.
_LOGGER.info(f"Configuring the client")
client = FplApi(username, password, hass.loop)
fplData = FplData(hass, client)
session = async_get_clientsession(hass)
client = FplApi(username, password, session)
await fplData.update_data()
coordinator = FplDataUpdateCoordinator(hass, client=client)
await coordinator.async_refresh()
hass.data[DOMAIN_DATA]["client"] = fplData
hass.data[DOMAIN][entry.entry_id] = coordinator
for platform in PLATFORMS:
if entry.options.get(platform, True):
coordinator.platforms.append(platform)
hass.async_add_job(
hass.config_entries.async_forward_entry_setup(entry, platform)
)
"""Set up Fpl as config entry."""
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, "sensor")
entry.add_update_listener(async_reload_entry)
return True
async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Reload config entry."""
await async_unload_entry(hass, entry)
await async_setup_entry(hass, entry)
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Handle removal of an entry."""
coordinator = hass.data[DOMAIN][entry.entry_id]
unloaded = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(entry, platform)
for platform in PLATFORMS
if platform in coordinator.platforms
]
)
)
return True
if unloaded:
hass.data[DOMAIN].pop(entry.entry_id)
async def async_unload_entry(hass, config_entry):
"""Unload a config entry."""
await hass.config_entries.async_forward_entry_unload(config_entry, "sensor")
return True
return unloaded

View File

@@ -4,7 +4,8 @@ import voluptuous as vol
from .fplapi import FplApi
from homeassistant import config_entries
import aiohttp
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from .const import DOMAIN, CONF_USERNAME, CONF_PASSWORD, CONF_NAME
from .fplapi import (
@@ -40,26 +41,28 @@ class FplFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a flow initialized by the user."""
self._errors = {}
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
if self.hass.data.get(DOMAIN):
return self.async_abort(reason="single_instance_allowed")
# if self._async_current_entries():
# return self.async_abort(reason="single_instance_allowed")
# if self.hass.data.get(DOMAIN):
# return self.async_abort(reason="single_instance_allowed")
if user_input is not None:
username = user_input[CONF_USERNAME]
password = user_input[CONF_PASSWORD]
if username not in configured_instances(self.hass):
api = FplApi(username, password, None)
session = async_create_clientsession(self.hass)
api = FplApi(username, password, session)
result = await api.login()
if result == LOGIN_RESULT_OK:
fplData = await api.get_data()
fplData = await api.async_get_data()
accounts = fplData["accounts"]
user_input["accounts"] = accounts
return self.async_create_entry(title="", data=user_input)
return self.async_create_entry(title=username, data=user_input)
if result == LOGIN_RESULT_INVALIDUSER:
self._errors[CONF_USERNAME] = "invalid_username"
@@ -80,10 +83,6 @@ class FplFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def _show_config_form(self, user_input):
"""Show the configuration form to edit location data."""
# Defaults
username = ""
password = ""
if user_input is not None:
if CONF_USERNAME in user_input:
username = user_input[CONF_USERNAME]

View File

@@ -1,5 +1,6 @@
"""Constants for fpl."""
# Base component constants
NAME = "FPL Integration"
DOMAIN = "fpl"
DOMAIN_DATA = f"{DOMAIN}_data"
VERSION = "0.0.1"
@@ -14,7 +15,13 @@ REQUIRED_FILES = [
"switch.py",
]
ISSUE_URL = "https://github.com/dotKrad/hass-fpl/issues"
ATTRIBUTION = "Data from this is provided by FPL."
ATTRIBUTION = "This data is provided by FPL."
# Platforms
BINARY_SENSOR = "binary_sensor"
SENSOR = "sensor"
SWITCH = "switch"
PLATFORMS = [SENSOR]
# Device classes
BINARY_SENSOR_DEVICE_CLASS = "connectivity"
@@ -30,3 +37,14 @@ CONF_PASSWORD = "password"
# Defaults
DEFAULT_NAME = DOMAIN
STARTUP_MESSAGE = f"""
-------------------------------------------------------------------
{NAME}
Version: {VERSION}
This is a custom integration!
If you have any issues with this you need to open an issue here:
{ISSUE_URL}
-------------------------------------------------------------------
"""

View File

@@ -0,0 +1,30 @@
import logging
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)
_LOGGER: logging.Logger = logging.getLogger(__package__)
class FplDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the API."""
def __init__(self, hass: HomeAssistant, client: FplApi) -> None:
"""Initialize."""
self.api = client
self.platforms = []
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)
async def _async_update_data(self):
"""Update data via library."""
try:
return await self.api.async_get_data()
except Exception as exception:
raise UpdateFailed() from exception

View File

@@ -0,0 +1,49 @@
"""BlueprintEntity class"""
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN, VERSION, ATTRIBUTION
class FplEntity(CoordinatorEntity):
def __init__(self, coordinator, config_entry, account, sensorName):
super().__init__(coordinator)
self.config_entry = config_entry
self.account = account
self.sensorName = sensorName
@property
def unique_id(self):
"""Return the ID of this device."""
id = "{}{}{}".format(
DOMAIN, self.account, self.sensorName.lower().replace(" ", "")
)
return id
@property
def name(self):
return f"{DOMAIN.upper()} {self.account} {self.sensorName}"
@property
def device_info(self):
return {
"identifiers": {(DOMAIN, self.account)},
"name": f"Account {self.account}",
"model": VERSION,
"manufacturer": "Florida Power & Light",
}
def defineAttributes(self):
return {}
@property
def device_state_attributes(self):
"""Return the state attributes."""
attributes = {
"attribution": ATTRIBUTION,
"integration": "FPL",
}
attributes.update(self.defineAttributes())
return attributes
def getData(self, field):
return self.coordinator.data.get(self.account).get(field)

View File

@@ -19,7 +19,7 @@ LOGIN_RESULT_INVALIDPASSWORD = "FAILEDPASSWORD"
LOGIN_RESULT_UNAUTHORIZED = "UNAUTHORIZED"
LOGIN_RESULT_FAILURE = "FAILURE"
_LOGGER = logging.getLogger(__name__)
_LOGGER = logging.getLogger(__package__)
TIMEOUT = 30
URL_LOGIN = "https://www.fpl.com/api/resources/login"
@@ -34,15 +34,14 @@ NOTENROLLED = "NOTENROLLED"
class FplApi(object):
"""A class for getting energy usage information from Florida Power & Light."""
def __init__(self, username, password, loop):
def __init__(self, username, password, session):
"""Initialize the data retrieval. Session should have BasicAuth flag set."""
self._username = username
self._password = password
self._loop = loop
self._session = None
self._session = session
async def get_data(self) -> dict:
self._session = aiohttp.ClientSession()
async def async_get_data(self) -> dict:
# self._session = aiohttp.ClientSession()
data = {}
data["accounts"] = []
if await self.login() == LOGIN_RESULT_OK:
@@ -53,24 +52,16 @@ class FplApi(object):
accountData = await self.__async_get_data(account)
data[account] = accountData
await self._session.close()
await self.logout()
return data
async def login(self):
if self._session is not None:
session = self._session
close = False
else:
session = aiohttp.ClientSession()
close = True
_LOGGER.info("Logging")
_LOGGER.info("Logging in")
"""login and get account information"""
result = LOGIN_RESULT_OK
try:
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
response = await session.get(
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
response = await self._session.get(
URL_LOGIN, auth=aiohttp.BasicAuth(self._username, self._password)
)
@@ -89,17 +80,19 @@ class FplApi(object):
_LOGGER.error(f"Error {e} : {sys.exc_info()[0]}")
result = LOGIN_RESULT_FAILURE
if close:
await session.close()
return result
async def logout(self):
_LOGGER.info("Logging out")
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
await self._session.get("https://www.fpl.com/api/resources/logout")
async def async_get_open_accounts(self):
_LOGGER.info(f"Getting accounts")
result = []
try:
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
response = await self._session.get(URL_RESOURCES_HEADER)
js = await response.json()
@@ -119,7 +112,7 @@ class FplApi(object):
_LOGGER.info(f"Getting Data")
data = {}
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
response = await self._session.get(
URL_RESOURCES_ACCOUNT.format(account=account)
)
@@ -182,7 +175,7 @@ class FplApi(object):
data = {}
try:
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
response = await self._session.get(
URL_RESOURCES_PROJECTED_BILL.format(
account=account,
@@ -215,7 +208,7 @@ class FplApi(object):
URL = "https://www.fpl.com/api/resources/account/{account}/budgetBillingGraph/premiseDetails"
try:
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
response = await self._session.get(URL.format(account=account))
if response.status == 200:
r = (await response.json())["data"]
@@ -249,7 +242,7 @@ class FplApi(object):
URL = "https://www.fpl.com/api/resources/account/{account}/budgetBillingGraph"
try:
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
response = await self._session.get(URL.format(account=account))
if response.status == 200:
r = (await response.json())["data"]
@@ -286,13 +279,13 @@ class FplApi(object):
data = {}
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
response = await self._session.post(URL.format(account=account), json=JSON)
if response.status == 200:
r = (await response.json())["data"]
dailyUsage = []
totalPowerUsage = 0
# totalPowerUsage = 0
if "data" in r["DailyUsage"]:
for daily in r["DailyUsage"]["data"]:
if (
@@ -309,11 +302,14 @@ class FplApi(object):
"max_temperature": daily["averageHighTemperature"],
}
)
totalPowerUsage += int(daily["kwhUsed"])
# totalPowerUsage += int(daily["kwhUsed"])
data["total_power_usage"] = totalPowerUsage
# data["total_power_usage"] = totalPowerUsage
data["daily_usage"] = dailyUsage
data["projectedKWH"] = r["CurrentUsage"]["projectedKWH"]
data["dailyAverageKWH"] = r["CurrentUsage"]["dailyAverageKWH"]
data["billToDateKWH"] = r["CurrentUsage"]["billToDateKWH"]
return data
async def __getDataFromApplianceUsage(self, account, lastBilledDate) -> dict:
@@ -322,7 +318,7 @@ class FplApi(object):
JSON = {"startDate": str(lastBilledDate.strftime("%m%d%Y"))}
data = {}
try:
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
response = await self._session.post(
URL.format(account=account), json=JSON
)

View File

@@ -2,6 +2,7 @@
"domain": "fpl",
"name": "FPL",
"documentation": "https://github.com/dotKrad/hass-fpl",
"iot_class": "cloud_polling",
"dependencies": [],
"config_flow": true,
"codeowners": [

View File

@@ -0,0 +1,123 @@
import logging
from datetime import datetime, timedelta
from .fplapi import FplApi
import aiohttp
import asyncio
from homeassistant.helpers.entity import Entity
from homeassistant import util
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.event import async_call_later
from homeassistant.const import (
CONF_NAME,
EVENT_CORE_CONFIG_UPDATE,
STATE_UNKNOWN,
CONF_USERNAME,
CONF_PASSWORD,
STATE_UNKNOWN,
ATTR_FRIENDLY_NAME,
)
from .const import DOMAIN, DOMAIN_DATA, ATTRIBUTION
from .DailyUsageSensor import FplDailyUsageSensor
from .AverageDailySensor import FplAverageDailySensor
from .ProjectedBillSensor import FplProjectedBillSensor
_LOGGER = logging.getLogger(__name__)
MIN_TIME_BETWEEN_SCANS = timedelta(minutes=30)
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=60)
def setup(hass, config):
return True
async def async_setup_entry(hass, config_entry, async_add_entities):
try:
accounts = config_entry.data.get("accounts")
fpl_accounts = []
for account in accounts:
_LOGGER.info(f"Adding fpl account: {account}")
fpl_accounts.append(FplSensor(hass, config_entry.data, account))
fpl_accounts.append(FplDailyUsageSensor(hass, config_entry.data, account))
fpl_accounts.append(FplAverageDailySensor(hass, config_entry.data, account))
fpl_accounts.append(
FplProjectedBillSensor(hass, config_entry.data, account)
)
async_add_entities(fpl_accounts)
except:
raise ConfigEntryNotReady
class FplSensor(Entity):
def __init__(self, hass, config, account):
self._config = config
self._state = None
self.loop = hass.loop
self._account = account
self._data = None
async def async_added_to_hass(self):
await self.async_update()
@property
def device_info(self):
return {
"identifiers": {(DOMAIN, self._account)},
"name": f"Account {self._account}",
"manufacturer": "Florida Power & Light",
}
@property
def unique_id(self):
"""Return the ID of this device."""
id = "{}{}".format(DOMAIN, self._account)
return id
@property
def name(self):
return f"{DOMAIN.upper()} {self._account}"
@property
def state(self):
data = self._data
if type(data) is dict:
if "budget_bill" in data.keys():
if data["budget_bill"]:
if "budget_billing_projected_bill" in data.keys():
self._state = data["budget_billing_projected_bill"]
else:
if "projected_bill" in data.keys():
self._state = data["projected_bill"]
return self._state
# @property
# def unit_of_measurement(self):
# return "$"
@property
def icon(self):
return "mdi:flash"
@property
def state_attributes(self):
return self._data
@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_UPDATES)
async def async_update(self):
# Send update "signal" to the component
# await self.hass.data[DOMAIN_DATA]["client"].update_data()
# Get new data (if any)
if "data" in self.hass.data[DOMAIN_DATA]:
data = self.hass.data[DOMAIN_DATA]["data"][self._account]
if data != {}:
self._data = data
self._data["attribution"] = ATTRIBUTION

View File

@@ -1,123 +1,71 @@
import logging
from datetime import datetime, timedelta
from .fplapi import FplApi
import aiohttp
import asyncio
from homeassistant.helpers.entity import Entity
from homeassistant import util
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.event import async_call_later
"""Sensor platform for integration_blueprint."""
from homeassistant.const import (
CONF_NAME,
EVENT_CORE_CONFIG_UPDATE,
STATE_UNKNOWN,
CONF_USERNAME,
CONF_PASSWORD,
STATE_UNKNOWN,
ATTR_FRIENDLY_NAME,
from .sensor_KWHSensor import (
ProjectedKWHSensor,
DailyAverageKWHSensor,
BillToDateKWHSensor,
)
from .const import DOMAIN, DOMAIN_DATA, ATTRIBUTION
from .DailyUsageSensor import FplDailyUsageSensor
from .AverageDailySensor import FplAverageDailySensor
from .ProjectedBillSensor import FplProjectedBillSensor
from .sensor_DatesSensor import (
CurrentBillDateSensor,
NextBillDateSensor,
ServiceDaysSensor,
AsOfDaysSensor,
RemainingDaysSensor,
)
from .sensor_ProjectedBillSensor import (
FplProjectedBillSensor,
ProjectedBudgetBillSensor,
ProjectedActualBillSensor,
DeferedAmountSensor,
)
from .sensor_AverageDailySensor import (
FplAverageDailySensor,
BudgetDailyAverageSensor,
ActualDailyAverageSensor,
)
from .sensor_DailyUsageSensor import FplDailyUsageSensor
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
MIN_TIME_BETWEEN_SCANS = timedelta(minutes=30)
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=60)
from .sensor_AllData import AllDataSensor
from .TestSensor import TestSensor
def setup(hass, config):
return True
async def async_setup_entry(hass, entry, async_add_devices):
"""Setup sensor platform."""
accounts = entry.data.get("accounts")
coordinator = hass.data[DOMAIN][entry.entry_id]
fpl_accounts = []
async def async_setup_entry(hass, config_entry, async_add_entities):
try:
accounts = config_entry.data.get("accounts")
for account in accounts:
# Test Sensor
# fpl_accounts.append(TestSensor(coordinator, entry, account))
# All data sensor
# fpl_accounts.append(AllDataSensor(coordinator, entry, account))
fpl_accounts = []
# bill sensors
fpl_accounts.append(FplProjectedBillSensor(coordinator, entry, account))
fpl_accounts.append(ProjectedBudgetBillSensor(coordinator, entry, account))
fpl_accounts.append(ProjectedActualBillSensor(coordinator, entry, account))
fpl_accounts.append(DeferedAmountSensor(coordinator, entry, account))
for account in accounts:
_LOGGER.info(f"Adding fpl account: {account}")
fpl_accounts.append(FplSensor(hass, config_entry.data, account))
fpl_accounts.append(FplDailyUsageSensor(hass, config_entry.data, account))
fpl_accounts.append(FplAverageDailySensor(hass, config_entry.data, account))
fpl_accounts.append(
FplProjectedBillSensor(hass, config_entry.data, account)
)
# usage sensors
fpl_accounts.append(FplAverageDailySensor(coordinator, entry, account))
fpl_accounts.append(BudgetDailyAverageSensor(coordinator, entry, account))
fpl_accounts.append(ActualDailyAverageSensor(coordinator, entry, account))
async_add_entities(fpl_accounts)
except:
raise ConfigEntryNotReady
fpl_accounts.append(FplDailyUsageSensor(coordinator, entry, account))
# date sensors
fpl_accounts.append(CurrentBillDateSensor(coordinator, entry, account))
fpl_accounts.append(NextBillDateSensor(coordinator, entry, account))
fpl_accounts.append(ServiceDaysSensor(coordinator, entry, account))
fpl_accounts.append(AsOfDaysSensor(coordinator, entry, account))
fpl_accounts.append(RemainingDaysSensor(coordinator, entry, account))
class FplSensor(Entity):
def __init__(self, hass, config, account):
self._config = config
self._state = None
self.loop = hass.loop
# KWH sensors
fpl_accounts.append(ProjectedKWHSensor(coordinator, entry, account))
fpl_accounts.append(DailyAverageKWHSensor(coordinator, entry, account))
fpl_accounts.append(BillToDateKWHSensor(coordinator, entry, account))
self._account = account
self._data = None
async def async_added_to_hass(self):
await self.async_update()
@property
def device_info(self):
return {
"identifiers": {(DOMAIN, self._account)},
"name": f"Account {self._account}",
"manufacturer": "Florida Power & Light",
}
@property
def unique_id(self):
"""Return the ID of this device."""
id = "{}{}".format(DOMAIN, self._account)
return id
@property
def name(self):
return f"{DOMAIN.upper()} {self._account}"
@property
def state(self):
data = self._data
if type(data) is dict:
if "budget_bill" in data.keys():
if data["budget_bill"]:
if "budget_billing_projected_bill" in data.keys():
self._state = data["budget_billing_projected_bill"]
else:
if "projected_bill" in data.keys():
self._state = data["projected_bill"]
return self._state
# @property
# def unit_of_measurement(self):
# return "$"
@property
def icon(self):
return "mdi:flash"
@property
def state_attributes(self):
return self._data
@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_UPDATES)
async def async_update(self):
# Send update "signal" to the component
# await self.hass.data[DOMAIN_DATA]["client"].update_data()
# Get new data (if any)
if "data" in self.hass.data[DOMAIN_DATA]:
data = self.hass.data[DOMAIN_DATA]["data"][self._account]
if data != {}:
self._data = data
self._data["attribution"] = ATTRIBUTION
async_add_devices(fpl_accounts)

View File

@@ -0,0 +1,24 @@
from .fplEntity import FplEntity
class AllDataSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "")
@property
def state(self):
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:
return self.getData("budget_billing_projected_bill")
return self.getData("projected_bill")
def defineAttributes(self):
"""Return the state attributes."""
return self.coordinator.data.get(self.account)
@property
def icon(self):
return "mdi:currency-usd"

View File

@@ -0,0 +1,46 @@
from .fplEntity import FplEntity
class FplAverageDailySensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Daily Average")
@property
def state(self):
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:
return self.getData("budget_billing_daily_avg")
return self.getData("daily_avg")
@property
def icon(self):
return "mdi:currency-usd"
class BudgetDailyAverageSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Budget Daily Average")
@property
def state(self):
return self.getData("budget_billing_daily_avg")
@property
def icon(self):
return "mdi:currency-usd"
class ActualDailyAverageSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Actual Daily Average")
@property
def state(self):
return self.getData("daily_avg")
@property
def icon(self):
return "mdi:currency-usd"

View File

@@ -0,0 +1,28 @@
from .fplEntity import FplEntity
class FplDailyUsageSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Daily Usage")
@property
def state(self):
data = self.getData("daily_usage")
if len(data) > 0:
return data[-1]["cost"]
return None
def defineAttributes(self):
"""Return the state attributes."""
data = self.getData("daily_usage")
if len(data) > 0:
return {"date": data[-1]["date"], "daily_usage": data}
return {}
@property
def icon(self):
return "mdi:currency-usd"

View File

@@ -0,0 +1,66 @@
from .fplEntity import FplEntity
class CurrentBillDateSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Current Bill Date")
@property
def state(self):
return self.getData("current_bill_date")
@property
def icon(self):
return "mdi:calendar"
class NextBillDateSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Next Bill Date")
@property
def state(self):
return self.getData("next_bill_date")
@property
def icon(self):
return "mdi:calendar"
class ServiceDaysSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Service Days")
@property
def state(self):
return self.getData("service_days")
@property
def icon(self):
return "mdi:calendar"
class AsOfDaysSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "As Of Days")
@property
def state(self):
return self.getData("as_of_days")
@property
def icon(self):
return "mdi:calendar"
class RemainingDaysSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Remaining Days")
@property
def state(self):
return self.getData("remaining_days")
@property
def icon(self):
return "mdi:calendar"

View File

@@ -0,0 +1,40 @@
from .fplEntity import FplEntity
class ProjectedKWHSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Projected KWH")
@property
def state(self):
return self.getData("projectedKWH")
@property
def icon(self):
return "mdi:flash"
class DailyAverageKWHSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Daily Average KWH")
@property
def state(self):
return self.getData("dailyAverageKWH")
@property
def icon(self):
return "mdi:flash"
class BillToDateKWHSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Bill To Date KWH")
@property
def state(self):
return self.getData("billToDateKWH")
@property
def icon(self):
return "mdi:flash"

View File

@@ -0,0 +1,73 @@
from .fplEntity import FplEntity
class FplProjectedBillSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Projected Bill")
@property
def state(self):
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:
return self.getData("budget_billing_projected_bill")
return self.getData("projected_bill")
def defineAttributes(self):
"""Return the state attributes."""
attributes = {}
try:
if self.getData("budget_bill") == True:
attributes["budget_bill"] = self.getData("budget_bill")
except:
pass
return attributes
@property
def icon(self):
return "mdi:currency-usd"
# Defered Amount
class DeferedAmountSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Defered Amount")
@property
def state(self):
if self.getData("budget_bill") == True:
return self.getData("defered_amount")
return 0
@property
def icon(self):
return "mdi:currency-usd"
class ProjectedBudgetBillSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Projected Budget Bill")
@property
def state(self):
return self.getData("budget_billing_projected_bill")
@property
def icon(self):
return "mdi:currency-usd"
class ProjectedActualBillSensor(FplEntity):
def __init__(self, coordinator, config, account):
super().__init__(coordinator, config, account, "Projected Actual Bill")
@property
def state(self):
return self.getData("projected_bill")
@property
def icon(self):
return "mdi:currency-usd"