OVO Energy - Sensor Entity Descriptions (#54952)

This commit is contained in:
Aidan Timson 2021-08-24 11:53:32 +01:00 committed by GitHub
parent 17a7f7adeb
commit a5e498207d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 118 additions and 205 deletions

View File

@ -100,36 +100,11 @@ class OVOEnergyEntity(CoordinatorEntity):
coordinator: DataUpdateCoordinator, coordinator: DataUpdateCoordinator,
client: OVOEnergy, client: OVOEnergy,
key: str, key: str,
name: str,
icon: str,
) -> None: ) -> None:
"""Initialize the OVO Energy entity.""" """Initialize the OVO Energy entity."""
super().__init__(coordinator) super().__init__(coordinator)
self._client = client self._client = client
self._key = key self._attr_unique_id = key
self._name = name
self._icon = icon
self._available = True
@property
def unique_id(self) -> str:
"""Return the unique ID for this sensor."""
return self._key
@property
def name(self) -> str:
"""Return the name of the entity."""
return self._name
@property
def icon(self) -> str:
"""Return the mdi icon of the entity."""
return self._icon
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self.coordinator.last_update_success and self._available
class OVOEnergyDeviceEntity(OVOEnergyEntity): class OVOEnergyDeviceEntity(OVOEnergyEntity):

View File

@ -1,16 +1,30 @@
"""Support for OVO Energy sensors.""" """Support for OVO Energy sensors."""
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta from datetime import timedelta
from typing import Callable, Final
from ovoenergy import OVODailyUsage from ovoenergy import OVODailyUsage
from ovoenergy.ovoenergy import OVOEnergy from ovoenergy.ovoenergy import OVOEnergy
from homeassistant.components.sensor import STATE_CLASS_TOTAL_INCREASING, SensorEntity from homeassistant.components.sensor import (
STATE_CLASS_TOTAL_INCREASING,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import DEVICE_CLASS_ENERGY, DEVICE_CLASS_MONETARY from homeassistant.const import (
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_MONETARY,
DEVICE_CLASS_TIMESTAMP,
ENERGY_KILO_WATT_HOUR,
)
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.util import dt as dt_util
from . import OVOEnergyDeviceEntity from . import OVOEnergyDeviceEntity
from .const import DATA_CLIENT, DATA_COORDINATOR, DOMAIN from .const import DATA_CLIENT, DATA_COORDINATOR, DOMAIN
@ -18,9 +32,87 @@ from .const import DATA_CLIENT, DATA_COORDINATOR, DOMAIN
SCAN_INTERVAL = timedelta(seconds=300) SCAN_INTERVAL = timedelta(seconds=300)
PARALLEL_UPDATES = 4 PARALLEL_UPDATES = 4
KEY_LAST_ELECTRICITY_COST: Final = "last_electricity_cost"
KEY_LAST_GAS_COST: Final = "last_gas_cost"
@dataclass
class OVOEnergySensorEntityDescription(SensorEntityDescription):
"""Class describing System Bridge sensor entities."""
value: Callable[[OVODailyUsage], StateType] = round
SENSOR_TYPES_ELECTRICITY: tuple[OVOEnergySensorEntityDescription, ...] = (
OVOEnergySensorEntityDescription(
key="last_electricity_reading",
name="OVO Last Electricity Reading",
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
native_unit_of_measurement=ENERGY_KILO_WATT_HOUR,
value=lambda usage: usage.electricity[-1].consumption,
),
OVOEnergySensorEntityDescription(
key=KEY_LAST_ELECTRICITY_COST,
name="OVO Last Electricity Cost",
device_class=DEVICE_CLASS_MONETARY,
state_class=STATE_CLASS_TOTAL_INCREASING,
icon="mdi:cash-multiple",
value=lambda usage: usage.electricity[-1].consumption,
),
OVOEnergySensorEntityDescription(
key="last_electricity_start_time",
name="OVO Last Electricity Start Time",
entity_registry_enabled_default=False,
device_class=DEVICE_CLASS_TIMESTAMP,
value=lambda usage: dt_util.as_utc(usage.electricity[-1].interval.start),
),
OVOEnergySensorEntityDescription(
key="last_electricity_end_time",
name="OVO Last Electricity End Time",
entity_registry_enabled_default=False,
device_class=DEVICE_CLASS_TIMESTAMP,
value=lambda usage: dt_util.as_utc(usage.electricity[-1].interval.end),
),
)
SENSOR_TYPES_GAS: tuple[OVOEnergySensorEntityDescription, ...] = (
OVOEnergySensorEntityDescription(
key="last_gas_reading",
name="OVO Last Gas Reading",
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
native_unit_of_measurement=ENERGY_KILO_WATT_HOUR,
icon="mdi:gas-cylinder",
value=lambda usage: usage.gas[-1].consumption,
),
OVOEnergySensorEntityDescription(
key=KEY_LAST_GAS_COST,
name="OVO Last Gas Cost",
device_class=DEVICE_CLASS_MONETARY,
state_class=STATE_CLASS_TOTAL_INCREASING,
icon="mdi:cash-multiple",
value=lambda usage: usage.gas[-1].consumption,
),
OVOEnergySensorEntityDescription(
key="last_gas_start_time",
name="OVO Last Gas Start Time",
entity_registry_enabled_default=False,
device_class=DEVICE_CLASS_TIMESTAMP,
value=lambda usage: dt_util.as_utc(usage.gas[-1].interval.start),
),
OVOEnergySensorEntityDescription(
key="last_gas_end_time",
name="OVO Last Gas End Time",
entity_registry_enabled_default=False,
device_class=DEVICE_CLASS_TIMESTAMP,
value=lambda usage: dt_util.as_utc(usage.gas[-1].interval.end),
),
)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None: ) -> None:
"""Set up OVO Energy sensor based on a config entry.""" """Set up OVO Energy sensor based on a config entry."""
coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id][ coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id][
@ -32,199 +124,45 @@ async def async_setup_entry(
if coordinator.data: if coordinator.data:
if coordinator.data.electricity: if coordinator.data.electricity:
entities.append(OVOEnergyLastElectricityReading(coordinator, client)) for description in SENSOR_TYPES_ELECTRICITY:
entities.append( if description.key == KEY_LAST_ELECTRICITY_COST:
OVOEnergyLastElectricityCost( description.native_unit_of_measurement = (
coordinator, coordinator.data.electricity[-1].cost.currency_unit
client, )
coordinator.data.electricity[ entities.append(OVOEnergySensor(coordinator, description, client))
len(coordinator.data.electricity) - 1
].cost.currency_unit,
)
)
if coordinator.data.gas: if coordinator.data.gas:
entities.append(OVOEnergyLastGasReading(coordinator, client)) for description in SENSOR_TYPES_GAS:
entities.append( if description.key == KEY_LAST_GAS_COST:
OVOEnergyLastGasCost( description.native_unit_of_measurement = coordinator.data.gas[
coordinator, -1
client, ].cost.currency_unit
coordinator.data.gas[ entities.append(OVOEnergySensor(coordinator, description, client))
len(coordinator.data.gas) - 1
].cost.currency_unit,
)
)
async_add_entities(entities, True) async_add_entities(entities, True)
class OVOEnergySensor(OVOEnergyDeviceEntity, SensorEntity): class OVOEnergySensor(OVOEnergyDeviceEntity, SensorEntity):
"""Defines a OVO Energy sensor.""" """Define a OVO Energy sensor."""
_attr_state_class = STATE_CLASS_TOTAL_INCREASING coordinator: DataUpdateCoordinator
entity_description: OVOEnergySensorEntityDescription
def __init__( def __init__(
self, self,
coordinator: DataUpdateCoordinator, coordinator: DataUpdateCoordinator,
description: OVOEnergySensorEntityDescription,
client: OVOEnergy, client: OVOEnergy,
key: str,
name: str,
icon: str,
device_class: str | None,
unit_of_measurement: str | None,
) -> None: ) -> None:
"""Initialize OVO Energy sensor.""" """Initialize."""
self._attr_device_class = device_class
self._unit_of_measurement = unit_of_measurement
super().__init__(coordinator, client, key, name, icon)
@property
def native_unit_of_measurement(self) -> str | None:
"""Return the unit this state is expressed in."""
return self._unit_of_measurement
class OVOEnergyLastElectricityReading(OVOEnergySensor):
"""Defines a OVO Energy last reading sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, client: OVOEnergy) -> None:
"""Initialize OVO Energy sensor."""
super().__init__( super().__init__(
coordinator, coordinator,
client, client,
f"{client.account_id}_last_electricity_reading", f"{DOMAIN}_{client.account_id}_{description.key}",
"OVO Last Electricity Reading",
"mdi:flash",
DEVICE_CLASS_ENERGY,
"kWh",
) )
self.entity_description = description
@property @property
def native_value(self) -> str: def native_value(self) -> StateType:
"""Return the state of the sensor.""" """Return the state."""
usage: OVODailyUsage = self.coordinator.data usage: OVODailyUsage = self.coordinator.data
if usage is None or not usage.electricity: return self.entity_description.value(usage)
return None
return usage.electricity[-1].consumption
@property
def extra_state_attributes(self) -> object:
"""Return the attributes of the sensor."""
usage: OVODailyUsage = self.coordinator.data
if usage is None or not usage.electricity:
return None
return {
"start_time": usage.electricity[-1].interval.start,
"end_time": usage.electricity[-1].interval.end,
}
class OVOEnergyLastGasReading(OVOEnergySensor):
"""Defines a OVO Energy last reading sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, client: OVOEnergy) -> None:
"""Initialize OVO Energy sensor."""
super().__init__(
coordinator,
client,
f"{DOMAIN}_{client.account_id}_last_gas_reading",
"OVO Last Gas Reading",
"mdi:gas-cylinder",
DEVICE_CLASS_ENERGY,
"kWh",
)
@property
def native_value(self) -> str:
"""Return the state of the sensor."""
usage: OVODailyUsage = self.coordinator.data
if usage is None or not usage.gas:
return None
return usage.gas[-1].consumption
@property
def extra_state_attributes(self) -> object:
"""Return the attributes of the sensor."""
usage: OVODailyUsage = self.coordinator.data
if usage is None or not usage.gas:
return None
return {
"start_time": usage.gas[-1].interval.start,
"end_time": usage.gas[-1].interval.end,
}
class OVOEnergyLastElectricityCost(OVOEnergySensor):
"""Defines a OVO Energy last cost sensor."""
def __init__(
self, coordinator: DataUpdateCoordinator, client: OVOEnergy, currency: str
) -> None:
"""Initialize OVO Energy sensor."""
super().__init__(
coordinator,
client,
f"{DOMAIN}_{client.account_id}_last_electricity_cost",
"OVO Last Electricity Cost",
"mdi:cash-multiple",
DEVICE_CLASS_MONETARY,
currency,
)
@property
def native_value(self) -> str:
"""Return the state of the sensor."""
usage: OVODailyUsage = self.coordinator.data
if usage is None or not usage.electricity:
return None
return usage.electricity[-1].cost.amount
@property
def extra_state_attributes(self) -> object:
"""Return the attributes of the sensor."""
usage: OVODailyUsage = self.coordinator.data
if usage is None or not usage.electricity:
return None
return {
"start_time": usage.electricity[-1].interval.start,
"end_time": usage.electricity[-1].interval.end,
}
class OVOEnergyLastGasCost(OVOEnergySensor):
"""Defines a OVO Energy last cost sensor."""
def __init__(
self, coordinator: DataUpdateCoordinator, client: OVOEnergy, currency: str
) -> None:
"""Initialize OVO Energy sensor."""
super().__init__(
coordinator,
client,
f"{DOMAIN}_{client.account_id}_last_gas_cost",
"OVO Last Gas Cost",
"mdi:cash-multiple",
DEVICE_CLASS_MONETARY,
currency,
)
@property
def native_value(self) -> str:
"""Return the state of the sensor."""
usage: OVODailyUsage = self.coordinator.data
if usage is None or not usage.gas:
return None
return usage.gas[-1].cost.amount
@property
def extra_state_attributes(self) -> object:
"""Return the attributes of the sensor."""
usage: OVODailyUsage = self.coordinator.data
if usage is None or not usage.gas:
return None
return {
"start_time": usage.gas[-1].interval.start,
"end_time": usage.gas[-1].interval.end,
}