Skip to content

Commit

Permalink
feat(sensor): added current gas rate sensor
Browse files Browse the repository at this point in the history
  • Loading branch information
BottlecapDave committed Jan 9, 2022
1 parent 1520cab commit ecfe774
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 24 deletions.
16 changes: 8 additions & 8 deletions custom_components/octopus_energy/__init__.py
Expand Up @@ -12,9 +12,9 @@
CONFIG_TARGET_NAME,

DATA_CLIENT,
DATA_COORDINATOR,
DATA_ELECTRICITY_RATES_COORDINATOR,
DATA_RATES,
DATA_TARIFF_CODE
DATA_ELECTRICITY_TARIFF_CODE
)

from .api_client import OctopusEnergyApiClient
Expand Down Expand Up @@ -50,7 +50,7 @@ async def async_setup_entry(hass, entry):

return True

async def async_get_current_agreement_tariff_code(client, config):
async def async_get_current_electricity_agreement_tariff_code(client, config):
account_info = await client.async_get_account(config[CONFIG_MAIN_ACCOUNT_ID])

all_agreements = []
Expand All @@ -70,13 +70,13 @@ def setup_dependencies(hass, config):
client = OctopusEnergyApiClient(config[CONFIG_MAIN_API_KEY])
hass.data[DOMAIN][DATA_CLIENT] = client

async def async_update_data():
async def async_update_electricity_rates_data():
"""Fetch data from API endpoint."""
# Only get data every half hour or if we don't have any data
if (DATA_RATES not in hass.data[DOMAIN] or (utcnow().minute % 30) == 0 or len(hass.data[DOMAIN][DATA_RATES]) == 0):

tariff_code = await async_get_current_agreement_tariff_code(client, config)
hass.data[DOMAIN][DATA_TARIFF_CODE] = tariff_code
tariff_code = await async_get_current_electricity_agreement_tariff_code(client, config)
hass.data[DOMAIN][DATA_ELECTRICITY_TARIFF_CODE] = tariff_code
_LOGGER.info(f'tariff_code: {tariff_code}')

utc_now = utcnow()
Expand All @@ -87,11 +87,11 @@ async def async_update_data():

return hass.data[DOMAIN][DATA_RATES]

hass.data[DOMAIN][DATA_COORDINATOR] = DataUpdateCoordinator(
hass.data[DOMAIN][DATA_ELECTRICITY_RATES_COORDINATOR] = DataUpdateCoordinator(
hass,
_LOGGER,
name="rates",
update_method=async_update_data,
update_method=async_update_electricity_rates_data,
# Because of how we're using the data, we'll update every minute, but we will only actually retrieve
# data every 30 minutes
update_interval=timedelta(minutes=1),
Expand Down
6 changes: 3 additions & 3 deletions custom_components/octopus_energy/binary_sensor.py
Expand Up @@ -19,7 +19,7 @@
CONFIG_TARGET_START_TIME,
CONFIG_TARGET_END_TIME,

DATA_COORDINATOR
DATA_ELECTRICITY_RATES_COORDINATOR
)

_LOGGER = logging.getLogger(__name__)
Expand All @@ -30,7 +30,7 @@ async def async_setup_entry(hass, entry, async_add_entities):
"""Setup sensors based on our entry"""

if CONFIG_TARGET_NAME in entry.data:
if DOMAIN not in hass.data or DATA_COORDINATOR not in hass.data[DOMAIN]:
if DOMAIN not in hass.data or DATA_ELECTRICITY_RATES_COORDINATOR not in hass.data[DOMAIN]:
raise ConfigEntryNotReady

await async_setup_target_sensors(hass, entry, async_add_entities)
Expand All @@ -40,7 +40,7 @@ async def async_setup_entry(hass, entry, async_add_entities):
async def async_setup_target_sensors(hass, entry, async_add_entities):
config = entry.data

coordinator = hass.data[DOMAIN][DATA_COORDINATOR]
coordinator = hass.data[DOMAIN][DATA_ELECTRICITY_RATES_COORDINATOR]

async_add_entities([OctopusEnergyTargetRate(coordinator, config)], True)

Expand Down
5 changes: 3 additions & 2 deletions custom_components/octopus_energy/const.py
Expand Up @@ -13,10 +13,11 @@
CONFIG_TARGET_END_TIME = "End time"

DATA_CONFIG = "CONFIG"
DATA_COORDINATOR = "COORDINATOR"
DATA_ELECTRICITY_RATES_COORDINATOR = "ELECTRICITY_RATES_COORDINATOR"
DATA_CLIENT = "CLIENT"
DATA_RATES = "RATES"
DATA_TARIFF_CODE = "TARIFF_CODE"
DATA_ELECTRICITY_TARIFF_CODE = "ELECTRICITY_TARIFF_CODE"
DATA_GAS_TARIFF_CODE = "GAS_TARIFF_CODE"

REGEX_HOURS = "^[0-9]+(\.[0-9]+)*$"
REGEX_TIME = "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$"
Expand Down
110 changes: 99 additions & 11 deletions custom_components/octopus_energy/sensor.py
Expand Up @@ -29,9 +29,8 @@

CONFIG_SMETS1,

DATA_COORDINATOR,
DATA_CLIENT,
DATA_TARIFF_CODE
DATA_ELECTRICITY_RATES_COORDINATOR,
DATA_CLIENT
)

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -102,33 +101,46 @@ async def async_setup_default_sensors(hass, entry, async_add_entities):

client = hass.data[DOMAIN][DATA_CLIENT]

rate_coordinator = hass.data[DOMAIN][DATA_COORDINATOR]
rate_coordinator = hass.data[DOMAIN][DATA_ELECTRICITY_RATES_COORDINATOR]

await rate_coordinator.async_config_entry_first_refresh()

tariff_code = hass.data[DOMAIN][DATA_TARIFF_CODE]

entities = [OctopusEnergyElectricityCurrentRate(rate_coordinator), OctopusEnergyElectricityPreviousRate(rate_coordinator)]
entities = []

account_info = await client.async_get_account(config[CONFIG_MAIN_ACCOUNT_ID])

if len(account_info["electricity_meter_points"]) > 0:
has_electricity_sensors = False

for point in account_info["electricity_meter_points"]:
# We only care about points that have active agreements
if get_active_tariff_code(point["agreements"]) != None:
electricity_tariff_code = get_active_tariff_code(point["agreements"])
if electricity_tariff_code != None:
has_electricity_sensors = True
for meter in point["meters"]:
coordinator = create_reading_coordinator(hass, client, True, point["mpan"], meter["serial_number"])
entities.append(OctopusEnergyPreviousAccumulativeElectricityReading(coordinator, point["mpan"], meter["serial_number"]))
entities.append(OctopusEnergyPreviousAccumulativeElectricityCost(coordinator, client, tariff_code, point["mpan"], meter["serial_number"]))
entities.append(OctopusEnergyPreviousAccumulativeElectricityCost(coordinator, client, electricity_tariff_code, point["mpan"], meter["serial_number"]))

if has_electricity_sensors == True:
entities.append(OctopusEnergyElectricityCurrentRate(rate_coordinator))
entities.append(OctopusEnergyElectricityPreviousRate(rate_coordinator))

if len(account_info["gas_meter_points"]) > 0:
has_gas_sensors = False

for point in account_info["gas_meter_points"]:
# We only care about points that have active agreements
if get_active_tariff_code(point["agreements"]) != None:
gas_tariff_code = get_active_tariff_code(point["agreements"])
if gas_tariff_code != None:
has_gas_sensors = True
for meter in point["meters"]:
coordinator = create_reading_coordinator(hass, client, False, point["mprn"], meter["serial_number"])
entities.append(OctopusEnergyPreviousAccumulativeGasReading(coordinator, point["mprn"], meter["serial_number"], is_smets1))
entities.append(OctopusEnergyPreviousAccumulativeGasCost(coordinator, client, tariff_code, point["mprn"], meter["serial_number"], is_smets1))
entities.append(OctopusEnergyPreviousAccumulativeGasCost(coordinator, client, gas_tariff_code, point["mprn"], meter["serial_number"], is_smets1))

if has_gas_sensors == True:
entities.append(OctopusEnergyGasCurrentRate(client, gas_tariff_code))

async_add_entities(entities, True)

Expand Down Expand Up @@ -447,7 +459,83 @@ async def async_update(self):
"Total Cost Without Standard Charge": f'£{total_cost}',
"Charges": charges
}

class OctopusEnergyGasCurrentRate(SensorEntity):
"""Sensor for displaying the current rate."""

def __init__(self, client, tariff_code):
"""Init sensor."""

self._client = client
self._tariff_code = tariff_code

self._attributes = {}
self._state = None
self._latest_date = None

@property
def unique_id(self):
"""The id of the sensor."""
return "octopus_energy_gas_current_rate"

@property
def name(self):
"""Name of the sensor."""
return "Octopus Energy Gas Current Rate"

@property
def device_class(self):
"""The type of sensor"""
return DEVICE_CLASS_MONETARY

@property
def icon(self):
"""Icon of the sensor."""
return "mdi:currency-usd"

@property
def unit_of_measurement(self):
"""Unit of measurement of the sensor."""
return "GBP/kWh"

@property
def extra_state_attributes(self):
"""Attributes of the sensor."""
return self._attributes

@property
def state(self):
"""Retrieve the latest gas price"""
return self._state

async def async_update(self):
"""Get the current price."""
# Find the current rate. We only need to do this every half an hour

utc_now = utcnow()
if (self._latest_date == None or (self._latest_date + timedelta(days=1)) < utc_now):
_LOGGER.info('Updating OctopusEnergyGasCurrentRate')

period_from = as_utc(parse_datetime(utc_now.strftime("%Y-%m-%dT00:00:00Z")))
period_to = as_utc(parse_datetime((utc_now + timedelta(days=1)).strftime("%Y-%m-%dT00:00:00Z")))

rates = await self._client.async_get_gas_rates(self._tariff_code, period_from, period_to)

current_rate = None
if rates != None:
for period in rates:
if utc_now >= period["valid_from"] and utc_now <= period["valid_to"]:
current_rate = period
break

if current_rate != None:
self._attributes = current_rate
self._state = current_rate["value_inc_vat"] / 100
else:
self._state = 0

self._latest_date = period_from

class OctopusEnergyPreviousAccumulativeGasReading(CoordinatorEntity, SensorEntity):
"""Sensor for displaying the previous days accumulative gas reading."""

Expand Down

0 comments on commit ecfe774

Please sign in to comment.