bug fixes
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
default_config:
|
default_config:
|
||||||
logger:
|
logger:
|
||||||
default: info
|
default: error
|
||||||
logs:
|
logs:
|
||||||
custom_components.fpl: debug
|
custom_components.fpl: debug
|
||||||
28
custom_components/fpl/TestSensor.py
Normal file
28
custom_components/fpl/TestSensor.py
Normal 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"
|
||||||
@@ -1,18 +1,29 @@
|
|||||||
""" FPL Component """
|
""" FPL Component """
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import asyncio
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from homeassistant.core import Config, HomeAssistant
|
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 homeassistant.util import Throttle
|
||||||
|
|
||||||
from .fplapi import FplApi
|
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)
|
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
from .config_flow import FplFlowHandler
|
|
||||||
from .const import DOMAIN
|
|
||||||
|
|
||||||
|
|
||||||
class FplData:
|
class FplData:
|
||||||
@@ -39,32 +50,58 @@ async def async_setup(hass: HomeAssistant, config: Config) -> bool:
|
|||||||
return True
|
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.
|
# Get "global" configuration.
|
||||||
username = config_entry.data.get(CONF_USERNAME)
|
username = entry.data.get(CONF_USERNAME)
|
||||||
password = config_entry.data.get(CONF_PASSWORD)
|
password = entry.data.get(CONF_PASSWORD)
|
||||||
|
|
||||||
# Create DATA dict
|
|
||||||
hass.data[DOMAIN_DATA] = {}
|
|
||||||
|
|
||||||
# Configure the client.
|
# Configure the client.
|
||||||
_LOGGER.info(f"Configuring the client")
|
_LOGGER.info(f"Configuring the client")
|
||||||
client = FplApi(username, password, hass.loop)
|
session = async_get_clientsession(hass)
|
||||||
fplData = FplData(hass, client)
|
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."""
|
"""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)
|
||||||
|
|
||||||
|
return unloaded
|
||||||
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
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import voluptuous as vol
|
|||||||
from .fplapi import FplApi
|
from .fplapi import FplApi
|
||||||
|
|
||||||
from homeassistant import config_entries
|
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 .const import DOMAIN, CONF_USERNAME, CONF_PASSWORD, CONF_NAME
|
||||||
|
|
||||||
from .fplapi import (
|
from .fplapi import (
|
||||||
@@ -40,26 +41,28 @@ class FplFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
"""Handle a flow initialized by the user."""
|
"""Handle a flow initialized by the user."""
|
||||||
self._errors = {}
|
self._errors = {}
|
||||||
|
|
||||||
if self._async_current_entries():
|
# if self._async_current_entries():
|
||||||
return self.async_abort(reason="single_instance_allowed")
|
# return self.async_abort(reason="single_instance_allowed")
|
||||||
if self.hass.data.get(DOMAIN):
|
|
||||||
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:
|
if user_input is not None:
|
||||||
username = user_input[CONF_USERNAME]
|
username = user_input[CONF_USERNAME]
|
||||||
password = user_input[CONF_PASSWORD]
|
password = user_input[CONF_PASSWORD]
|
||||||
|
|
||||||
if username not in configured_instances(self.hass):
|
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()
|
result = await api.login()
|
||||||
|
|
||||||
if result == LOGIN_RESULT_OK:
|
if result == LOGIN_RESULT_OK:
|
||||||
fplData = await api.get_data()
|
fplData = await api.async_get_data()
|
||||||
accounts = fplData["accounts"]
|
accounts = fplData["accounts"]
|
||||||
|
|
||||||
user_input["accounts"] = 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:
|
if result == LOGIN_RESULT_INVALIDUSER:
|
||||||
self._errors[CONF_USERNAME] = "invalid_username"
|
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):
|
async def _show_config_form(self, user_input):
|
||||||
"""Show the configuration form to edit location data."""
|
"""Show the configuration form to edit location data."""
|
||||||
|
|
||||||
# Defaults
|
|
||||||
username = ""
|
|
||||||
password = ""
|
|
||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
if CONF_USERNAME in user_input:
|
if CONF_USERNAME in user_input:
|
||||||
username = user_input[CONF_USERNAME]
|
username = user_input[CONF_USERNAME]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"""Constants for fpl."""
|
"""Constants for fpl."""
|
||||||
# Base component constants
|
# Base component constants
|
||||||
|
NAME = "FPL Integration"
|
||||||
DOMAIN = "fpl"
|
DOMAIN = "fpl"
|
||||||
DOMAIN_DATA = f"{DOMAIN}_data"
|
DOMAIN_DATA = f"{DOMAIN}_data"
|
||||||
VERSION = "0.0.1"
|
VERSION = "0.0.1"
|
||||||
@@ -14,7 +15,13 @@ REQUIRED_FILES = [
|
|||||||
"switch.py",
|
"switch.py",
|
||||||
]
|
]
|
||||||
ISSUE_URL = "https://github.com/dotKrad/hass-fpl/issues"
|
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
|
# Device classes
|
||||||
BINARY_SENSOR_DEVICE_CLASS = "connectivity"
|
BINARY_SENSOR_DEVICE_CLASS = "connectivity"
|
||||||
@@ -30,3 +37,14 @@ CONF_PASSWORD = "password"
|
|||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
DEFAULT_NAME = DOMAIN
|
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}
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
"""
|
||||||
|
|||||||
30
custom_components/fpl/fplDataUpdateCoordinator.py
Normal file
30
custom_components/fpl/fplDataUpdateCoordinator.py
Normal 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
|
||||||
49
custom_components/fpl/fplEntity.py
Normal file
49
custom_components/fpl/fplEntity.py
Normal 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)
|
||||||
@@ -19,7 +19,7 @@ LOGIN_RESULT_INVALIDPASSWORD = "FAILEDPASSWORD"
|
|||||||
LOGIN_RESULT_UNAUTHORIZED = "UNAUTHORIZED"
|
LOGIN_RESULT_UNAUTHORIZED = "UNAUTHORIZED"
|
||||||
LOGIN_RESULT_FAILURE = "FAILURE"
|
LOGIN_RESULT_FAILURE = "FAILURE"
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__package__)
|
||||||
TIMEOUT = 30
|
TIMEOUT = 30
|
||||||
|
|
||||||
URL_LOGIN = "https://www.fpl.com/api/resources/login"
|
URL_LOGIN = "https://www.fpl.com/api/resources/login"
|
||||||
@@ -34,15 +34,14 @@ NOTENROLLED = "NOTENROLLED"
|
|||||||
class FplApi(object):
|
class FplApi(object):
|
||||||
"""A class for getting energy usage information from Florida Power & Light."""
|
"""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."""
|
"""Initialize the data retrieval. Session should have BasicAuth flag set."""
|
||||||
self._username = username
|
self._username = username
|
||||||
self._password = password
|
self._password = password
|
||||||
self._loop = loop
|
self._session = session
|
||||||
self._session = None
|
|
||||||
|
|
||||||
async def get_data(self) -> dict:
|
async def async_get_data(self) -> dict:
|
||||||
self._session = aiohttp.ClientSession()
|
# self._session = aiohttp.ClientSession()
|
||||||
data = {}
|
data = {}
|
||||||
data["accounts"] = []
|
data["accounts"] = []
|
||||||
if await self.login() == LOGIN_RESULT_OK:
|
if await self.login() == LOGIN_RESULT_OK:
|
||||||
@@ -53,24 +52,16 @@ class FplApi(object):
|
|||||||
accountData = await self.__async_get_data(account)
|
accountData = await self.__async_get_data(account)
|
||||||
data[account] = accountData
|
data[account] = accountData
|
||||||
|
|
||||||
await self._session.close()
|
await self.logout()
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
async def login(self):
|
async def login(self):
|
||||||
if self._session is not None:
|
_LOGGER.info("Logging in")
|
||||||
session = self._session
|
|
||||||
close = False
|
|
||||||
else:
|
|
||||||
session = aiohttp.ClientSession()
|
|
||||||
close = True
|
|
||||||
|
|
||||||
_LOGGER.info("Logging")
|
|
||||||
"""login and get account information"""
|
"""login and get account information"""
|
||||||
result = LOGIN_RESULT_OK
|
result = LOGIN_RESULT_OK
|
||||||
try:
|
try:
|
||||||
async with async_timeout.timeout(TIMEOUT, loop=self._loop):
|
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
|
||||||
response = await session.get(
|
response = await self._session.get(
|
||||||
URL_LOGIN, auth=aiohttp.BasicAuth(self._username, self._password)
|
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]}")
|
_LOGGER.error(f"Error {e} : {sys.exc_info()[0]}")
|
||||||
result = LOGIN_RESULT_FAILURE
|
result = LOGIN_RESULT_FAILURE
|
||||||
|
|
||||||
if close:
|
|
||||||
await session.close()
|
|
||||||
|
|
||||||
return result
|
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):
|
async def async_get_open_accounts(self):
|
||||||
_LOGGER.info(f"Getting accounts")
|
_LOGGER.info(f"Getting accounts")
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
try:
|
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)
|
response = await self._session.get(URL_RESOURCES_HEADER)
|
||||||
|
|
||||||
js = await response.json()
|
js = await response.json()
|
||||||
@@ -119,7 +112,7 @@ class FplApi(object):
|
|||||||
_LOGGER.info(f"Getting Data")
|
_LOGGER.info(f"Getting Data")
|
||||||
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(
|
response = await self._session.get(
|
||||||
URL_RESOURCES_ACCOUNT.format(account=account)
|
URL_RESOURCES_ACCOUNT.format(account=account)
|
||||||
)
|
)
|
||||||
@@ -182,7 +175,7 @@ class FplApi(object):
|
|||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
try:
|
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(
|
response = await self._session.get(
|
||||||
URL_RESOURCES_PROJECTED_BILL.format(
|
URL_RESOURCES_PROJECTED_BILL.format(
|
||||||
account=account,
|
account=account,
|
||||||
@@ -215,7 +208,7 @@ class FplApi(object):
|
|||||||
|
|
||||||
URL = "https://www.fpl.com/api/resources/account/{account}/budgetBillingGraph/premiseDetails"
|
URL = "https://www.fpl.com/api/resources/account/{account}/budgetBillingGraph/premiseDetails"
|
||||||
try:
|
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))
|
response = await self._session.get(URL.format(account=account))
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
r = (await response.json())["data"]
|
r = (await response.json())["data"]
|
||||||
@@ -249,7 +242,7 @@ class FplApi(object):
|
|||||||
URL = "https://www.fpl.com/api/resources/account/{account}/budgetBillingGraph"
|
URL = "https://www.fpl.com/api/resources/account/{account}/budgetBillingGraph"
|
||||||
|
|
||||||
try:
|
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))
|
response = await self._session.get(URL.format(account=account))
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
r = (await response.json())["data"]
|
r = (await response.json())["data"]
|
||||||
@@ -286,13 +279,13 @@ class FplApi(object):
|
|||||||
|
|
||||||
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.post(URL.format(account=account), json=JSON)
|
response = await self._session.post(URL.format(account=account), json=JSON)
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
r = (await response.json())["data"]
|
r = (await response.json())["data"]
|
||||||
dailyUsage = []
|
dailyUsage = []
|
||||||
|
|
||||||
totalPowerUsage = 0
|
# totalPowerUsage = 0
|
||||||
if "data" in r["DailyUsage"]:
|
if "data" in r["DailyUsage"]:
|
||||||
for daily in r["DailyUsage"]["data"]:
|
for daily in r["DailyUsage"]["data"]:
|
||||||
if (
|
if (
|
||||||
@@ -309,11 +302,14 @@ class FplApi(object):
|
|||||||
"max_temperature": daily["averageHighTemperature"],
|
"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["daily_usage"] = dailyUsage
|
||||||
|
|
||||||
|
data["projectedKWH"] = r["CurrentUsage"]["projectedKWH"]
|
||||||
|
data["dailyAverageKWH"] = r["CurrentUsage"]["dailyAverageKWH"]
|
||||||
|
data["billToDateKWH"] = r["CurrentUsage"]["billToDateKWH"]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
async def __getDataFromApplianceUsage(self, account, lastBilledDate) -> dict:
|
async def __getDataFromApplianceUsage(self, account, lastBilledDate) -> dict:
|
||||||
@@ -322,7 +318,7 @@ class FplApi(object):
|
|||||||
JSON = {"startDate": str(lastBilledDate.strftime("%m%d%Y"))}
|
JSON = {"startDate": str(lastBilledDate.strftime("%m%d%Y"))}
|
||||||
data = {}
|
data = {}
|
||||||
try:
|
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(
|
response = await self._session.post(
|
||||||
URL.format(account=account), json=JSON
|
URL.format(account=account), json=JSON
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"domain": "fpl",
|
"domain": "fpl",
|
||||||
"name": "FPL",
|
"name": "FPL",
|
||||||
"documentation": "https://github.com/dotKrad/hass-fpl",
|
"documentation": "https://github.com/dotKrad/hass-fpl",
|
||||||
|
"iot_class": "cloud_polling",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"codeowners": [
|
"codeowners": [
|
||||||
|
|||||||
123
custom_components/fpl/sensor.old.py
Normal file
123
custom_components/fpl/sensor.old.py
Normal 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
|
||||||
@@ -1,123 +1,71 @@
|
|||||||
import logging
|
"""Sensor platform for integration_blueprint."""
|
||||||
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 (
|
from .sensor_KWHSensor import (
|
||||||
CONF_NAME,
|
ProjectedKWHSensor,
|
||||||
EVENT_CORE_CONFIG_UPDATE,
|
DailyAverageKWHSensor,
|
||||||
STATE_UNKNOWN,
|
BillToDateKWHSensor,
|
||||||
CONF_USERNAME,
|
|
||||||
CONF_PASSWORD,
|
|
||||||
STATE_UNKNOWN,
|
|
||||||
ATTR_FRIENDLY_NAME,
|
|
||||||
)
|
)
|
||||||
from .const import DOMAIN, DOMAIN_DATA, ATTRIBUTION
|
from .sensor_DatesSensor import (
|
||||||
from .DailyUsageSensor import FplDailyUsageSensor
|
CurrentBillDateSensor,
|
||||||
from .AverageDailySensor import FplAverageDailySensor
|
NextBillDateSensor,
|
||||||
from .ProjectedBillSensor import FplProjectedBillSensor
|
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__)
|
from .sensor_AllData import AllDataSensor
|
||||||
|
from .TestSensor import TestSensor
|
||||||
MIN_TIME_BETWEEN_SCANS = timedelta(minutes=30)
|
|
||||||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=60)
|
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
async def async_setup_entry(hass, entry, async_add_devices):
|
||||||
return True
|
"""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):
|
for account in accounts:
|
||||||
try:
|
# Test Sensor
|
||||||
accounts = config_entry.data.get("accounts")
|
# 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:
|
# usage sensors
|
||||||
_LOGGER.info(f"Adding fpl account: {account}")
|
fpl_accounts.append(FplAverageDailySensor(coordinator, entry, account))
|
||||||
fpl_accounts.append(FplSensor(hass, config_entry.data, account))
|
fpl_accounts.append(BudgetDailyAverageSensor(coordinator, entry, account))
|
||||||
fpl_accounts.append(FplDailyUsageSensor(hass, config_entry.data, account))
|
fpl_accounts.append(ActualDailyAverageSensor(coordinator, entry, account))
|
||||||
fpl_accounts.append(FplAverageDailySensor(hass, config_entry.data, account))
|
|
||||||
fpl_accounts.append(
|
|
||||||
FplProjectedBillSensor(hass, config_entry.data, account)
|
|
||||||
)
|
|
||||||
|
|
||||||
async_add_entities(fpl_accounts)
|
fpl_accounts.append(FplDailyUsageSensor(coordinator, entry, account))
|
||||||
except:
|
|
||||||
raise ConfigEntryNotReady
|
|
||||||
|
|
||||||
|
# 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):
|
# KWH sensors
|
||||||
def __init__(self, hass, config, account):
|
fpl_accounts.append(ProjectedKWHSensor(coordinator, entry, account))
|
||||||
self._config = config
|
fpl_accounts.append(DailyAverageKWHSensor(coordinator, entry, account))
|
||||||
self._state = None
|
fpl_accounts.append(BillToDateKWHSensor(coordinator, entry, account))
|
||||||
self.loop = hass.loop
|
|
||||||
|
|
||||||
self._account = account
|
async_add_devices(fpl_accounts)
|
||||||
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
|
|
||||||
|
|||||||
24
custom_components/fpl/sensor_AllData.py
Normal file
24
custom_components/fpl/sensor_AllData.py
Normal 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"
|
||||||
46
custom_components/fpl/sensor_AverageDailySensor.py
Normal file
46
custom_components/fpl/sensor_AverageDailySensor.py
Normal 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"
|
||||||
28
custom_components/fpl/sensor_DailyUsageSensor.py
Normal file
28
custom_components/fpl/sensor_DailyUsageSensor.py
Normal 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"
|
||||||
66
custom_components/fpl/sensor_DatesSensor.py
Normal file
66
custom_components/fpl/sensor_DatesSensor.py
Normal 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"
|
||||||
40
custom_components/fpl/sensor_KWHSensor.py
Normal file
40
custom_components/fpl/sensor_KWHSensor.py
Normal 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"
|
||||||
73
custom_components/fpl/sensor_ProjectedBillSensor.py
Normal file
73
custom_components/fpl/sensor_ProjectedBillSensor.py
Normal 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"
|
||||||
Reference in New Issue
Block a user