Add OSO Energy sensors (#108226)
* Add OSO Energy sensors * Fix comments * Fixes after review * Fix sensor names and translations * Fixes after review * Fix validation errors * Fixes after review * Remove profile sensor
This commit is contained in:
parent
d8cca482b3
commit
44208a5be0
5 changed files with 241 additions and 36 deletions
|
@ -986,6 +986,7 @@ omit =
|
|||
homeassistant/components/orvibo/switch.py
|
||||
homeassistant/components/osoenergy/__init__.py
|
||||
homeassistant/components/osoenergy/const.py
|
||||
homeassistant/components/osoenergy/sensor.py
|
||||
homeassistant/components/osoenergy/water_heater.py
|
||||
homeassistant/components/osramlightify/light.py
|
||||
homeassistant/components/otp/sensor.py
|
||||
|
|
|
@ -16,18 +16,25 @@ from homeassistant.const import CONF_API_KEY, Platform
|
|||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_T = TypeVar(
|
||||
"_T", OSOEnergyBinarySensorData, OSOEnergySensorData, OSOEnergyWaterHeaterData
|
||||
_OSOEnergyT = TypeVar(
|
||||
"_OSOEnergyT",
|
||||
OSOEnergyBinarySensorData,
|
||||
OSOEnergySensorData,
|
||||
OSOEnergyWaterHeaterData,
|
||||
)
|
||||
|
||||
MANUFACTURER = "OSO Energy"
|
||||
PLATFORMS = [
|
||||
Platform.SENSOR,
|
||||
Platform.WATER_HEATER,
|
||||
]
|
||||
PLATFORM_LOOKUP = {
|
||||
Platform.SENSOR: "sensor",
|
||||
Platform.WATER_HEATER: "water_heater",
|
||||
}
|
||||
|
||||
|
@ -70,13 +77,18 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
return unload_ok
|
||||
|
||||
|
||||
class OSOEnergyEntity(Entity, Generic[_T]):
|
||||
class OSOEnergyEntity(Entity, Generic[_OSOEnergyT]):
|
||||
"""Initiate OSO Energy Base Class."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(self, osoenergy: OSOEnergy, osoenergy_device: _T) -> None:
|
||||
def __init__(self, osoenergy: OSOEnergy, entity_data: _OSOEnergyT) -> None:
|
||||
"""Initialize the instance."""
|
||||
self.osoenergy = osoenergy
|
||||
self.device = osoenergy_device
|
||||
self._attr_unique_id = osoenergy_device.device_id
|
||||
self.entity_data = entity_data
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, entity_data.device_id)},
|
||||
manufacturer=MANUFACTURER,
|
||||
model=entity_data.device_type,
|
||||
name=entity_data.device_name,
|
||||
)
|
||||
|
|
151
homeassistant/components/osoenergy/sensor.py
Normal file
151
homeassistant/components/osoenergy/sensor.py
Normal file
|
@ -0,0 +1,151 @@
|
|||
"""Support for OSO Energy sensors."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from apyosoenergyapi import OSOEnergy
|
||||
from apyosoenergyapi.helper.const import OSOEnergySensorData
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import UnitOfEnergy, UnitOfPower, UnitOfVolume
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import OSOEnergyEntity
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class OSOEnergySensorEntityDescription(SensorEntityDescription):
|
||||
"""Class describing OSO Energy heater sensor entities."""
|
||||
|
||||
value_fn: Callable[[OSOEnergy], StateType]
|
||||
|
||||
|
||||
SENSOR_TYPES: dict[str, OSOEnergySensorEntityDescription] = {
|
||||
"heater_mode": OSOEnergySensorEntityDescription(
|
||||
key="heater_mode",
|
||||
translation_key="heater_mode",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=[
|
||||
"auto",
|
||||
"manual",
|
||||
"off",
|
||||
"legionella",
|
||||
"powersave",
|
||||
"extraenergy",
|
||||
"voltage",
|
||||
"ffr",
|
||||
],
|
||||
value_fn=lambda entity_data: entity_data.state.lower(),
|
||||
),
|
||||
"optimization_mode": OSOEnergySensorEntityDescription(
|
||||
key="optimization_mode",
|
||||
translation_key="optimization_mode",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["off", "oso", "gridcompany", "smartcompany", "advanced"],
|
||||
value_fn=lambda entity_data: entity_data.state.lower(),
|
||||
),
|
||||
"power_load": OSOEnergySensorEntityDescription(
|
||||
key="power_load",
|
||||
device_class=SensorDeviceClass.POWER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfPower.KILO_WATT,
|
||||
value_fn=lambda entity_data: entity_data.state,
|
||||
),
|
||||
"tapping_capacity": OSOEnergySensorEntityDescription(
|
||||
key="tapping_capacity",
|
||||
translation_key="tapping_capacity",
|
||||
device_class=SensorDeviceClass.ENERGY,
|
||||
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
|
||||
value_fn=lambda entity_data: entity_data.state,
|
||||
),
|
||||
"capacity_mixed_water_40": OSOEnergySensorEntityDescription(
|
||||
key="capacity_mixed_water_40",
|
||||
translation_key="capacity_mixed_water_40",
|
||||
device_class=SensorDeviceClass.VOLUME,
|
||||
native_unit_of_measurement=UnitOfVolume.LITERS,
|
||||
value_fn=lambda entity_data: entity_data.state,
|
||||
),
|
||||
"v40_min": OSOEnergySensorEntityDescription(
|
||||
key="v40_min",
|
||||
translation_key="v40_min",
|
||||
device_class=SensorDeviceClass.VOLUME,
|
||||
native_unit_of_measurement=UnitOfVolume.LITERS,
|
||||
value_fn=lambda entity_data: entity_data.state,
|
||||
),
|
||||
"v40_level_min": OSOEnergySensorEntityDescription(
|
||||
key="v40_level_min",
|
||||
translation_key="v40_level_min",
|
||||
device_class=SensorDeviceClass.VOLUME,
|
||||
native_unit_of_measurement=UnitOfVolume.LITERS,
|
||||
value_fn=lambda entity_data: entity_data.state,
|
||||
),
|
||||
"v40_level_max": OSOEnergySensorEntityDescription(
|
||||
key="v40_level_max",
|
||||
translation_key="v40_level_max",
|
||||
device_class=SensorDeviceClass.VOLUME,
|
||||
native_unit_of_measurement=UnitOfVolume.LITERS,
|
||||
value_fn=lambda entity_data: entity_data.state,
|
||||
),
|
||||
"volume": OSOEnergySensorEntityDescription(
|
||||
key="volume",
|
||||
device_class=SensorDeviceClass.VOLUME,
|
||||
native_unit_of_measurement=UnitOfVolume.LITERS,
|
||||
value_fn=lambda entity_data: entity_data.state,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up OSO Energy sensor."""
|
||||
osoenergy = hass.data[DOMAIN][entry.entry_id]
|
||||
devices = osoenergy.session.device_list.get("sensor")
|
||||
entities = []
|
||||
if devices:
|
||||
for dev in devices:
|
||||
sensor_type = dev.osoEnergyType.lower()
|
||||
if sensor_type in SENSOR_TYPES:
|
||||
entities.append(
|
||||
OSOEnergySensor(osoenergy, SENSOR_TYPES[sensor_type], dev)
|
||||
)
|
||||
|
||||
async_add_entities(entities, True)
|
||||
|
||||
|
||||
class OSOEnergySensor(OSOEnergyEntity[OSOEnergySensorData], SensorEntity):
|
||||
"""OSO Energy Sensor Entity."""
|
||||
|
||||
entity_description: OSOEnergySensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
instance: OSOEnergy,
|
||||
description: OSOEnergySensorEntityDescription,
|
||||
entity_data: OSOEnergySensorData,
|
||||
) -> None:
|
||||
"""Initialize the OSO Energy sensor."""
|
||||
super().__init__(instance, entity_data)
|
||||
|
||||
device_id = entity_data.device_id
|
||||
self._attr_unique_id = f"{device_id}_{description.key}"
|
||||
self.entity_description = description
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the state of the sensor."""
|
||||
return self.entity_description.value_fn(self.entity_data)
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Update all data for OSO Energy."""
|
||||
await self.osoenergy.session.update_data()
|
||||
self.entity_data = await self.osoenergy.sensor.get_sensor(self.entity_data)
|
|
@ -17,13 +17,56 @@
|
|||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"tapping_capacity": {
|
||||
"name": "Tapping capacity"
|
||||
},
|
||||
"capacity_mixed_water_40": {
|
||||
"name": "Capacity mixed water 40°C"
|
||||
},
|
||||
"v40_min": {
|
||||
"name": "Mixed water at 40°C"
|
||||
},
|
||||
"v40_level_min": {
|
||||
"name": "Minimum level of mixed water at 40°C"
|
||||
},
|
||||
"v40_level_max": {
|
||||
"name": "Maximum level of mixed water at 40°C"
|
||||
},
|
||||
"heater_mode": {
|
||||
"name": "Heater mode",
|
||||
"state": {
|
||||
"auto": "Auto",
|
||||
"extraenergy": "Extra energy",
|
||||
"ffr": "Fast frequency reserve",
|
||||
"legionella": "Legionella",
|
||||
"manual": "Manual",
|
||||
"off": "Off",
|
||||
"powersave": "Power save",
|
||||
"voltage": "Voltage"
|
||||
}
|
||||
},
|
||||
"optimization_mode": {
|
||||
"name": "Optimization mode",
|
||||
"state": {
|
||||
"advanced": "Advanced",
|
||||
"gridcompany": "Grid company",
|
||||
"off": "Off",
|
||||
"oso": "OSO",
|
||||
"smartcompany": "Smart company"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"name": "Profile local"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from typing import Any
|
||||
|
||||
from apyosoenergyapi import OSOEnergy
|
||||
from apyosoenergyapi.helper.const import OSOEnergyWaterHeaterData
|
||||
|
||||
from homeassistant.components.water_heater import (
|
||||
|
@ -15,7 +16,6 @@ from homeassistant.components.water_heater import (
|
|||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import OSOEnergyEntity
|
||||
|
@ -34,9 +34,6 @@ CURRENT_OPERATION_MAP: dict[str, Any] = {
|
|||
"extraenergy": STATE_HIGH_DEMAND,
|
||||
},
|
||||
}
|
||||
HEATER_MIN_TEMP = 10
|
||||
HEATER_MAX_TEMP = 80
|
||||
MANUFACTURER = "OSO Energy"
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -59,30 +56,29 @@ class OSOEnergyWaterHeater(
|
|||
_attr_supported_features = WaterHeaterEntityFeature.TARGET_TEMPERATURE
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information."""
|
||||
return DeviceInfo(
|
||||
identifiers={(DOMAIN, self.device.device_id)},
|
||||
manufacturer=MANUFACTURER,
|
||||
model=self.device.device_type,
|
||||
name=self.device.device_name,
|
||||
)
|
||||
def __init__(
|
||||
self,
|
||||
instance: OSOEnergy,
|
||||
entity_data: OSOEnergyWaterHeaterData,
|
||||
) -> None:
|
||||
"""Initialize the OSO Energy water heater."""
|
||||
super().__init__(instance, entity_data)
|
||||
self._attr_unique_id = entity_data.device_id
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if the device is available."""
|
||||
return self.device.available
|
||||
return self.entity_data.available
|
||||
|
||||
@property
|
||||
def current_operation(self) -> str:
|
||||
"""Return current operation."""
|
||||
status = self.device.current_operation
|
||||
status = self.entity_data.current_operation
|
||||
if status == "off":
|
||||
return STATE_OFF
|
||||
|
||||
optimization_mode = self.device.optimization_mode.lower()
|
||||
heater_mode = self.device.heater_mode.lower()
|
||||
optimization_mode = self.entity_data.optimization_mode.lower()
|
||||
heater_mode = self.entity_data.heater_mode.lower()
|
||||
if optimization_mode in CURRENT_OPERATION_MAP:
|
||||
return CURRENT_OPERATION_MAP[optimization_mode].get(
|
||||
heater_mode, STATE_ELECTRIC
|
||||
|
@ -93,49 +89,51 @@ class OSOEnergyWaterHeater(
|
|||
@property
|
||||
def current_temperature(self) -> float:
|
||||
"""Return the current temperature of the heater."""
|
||||
return self.device.current_temperature
|
||||
return self.entity_data.current_temperature
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> float:
|
||||
"""Return the temperature we try to reach."""
|
||||
return self.device.target_temperature
|
||||
return self.entity_data.target_temperature
|
||||
|
||||
@property
|
||||
def target_temperature_high(self) -> float:
|
||||
"""Return the temperature we try to reach."""
|
||||
return self.device.target_temperature_high
|
||||
return self.entity_data.target_temperature_high
|
||||
|
||||
@property
|
||||
def target_temperature_low(self) -> float:
|
||||
"""Return the temperature we try to reach."""
|
||||
return self.device.target_temperature_low
|
||||
return self.entity_data.target_temperature_low
|
||||
|
||||
@property
|
||||
def min_temp(self) -> float:
|
||||
"""Return the minimum temperature."""
|
||||
return self.device.min_temperature
|
||||
return self.entity_data.min_temperature
|
||||
|
||||
@property
|
||||
def max_temp(self) -> float:
|
||||
"""Return the maximum temperature."""
|
||||
return self.device.max_temperature
|
||||
return self.entity_data.max_temperature
|
||||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Turn on hotwater."""
|
||||
await self.osoenergy.hotwater.turn_on(self.device, True)
|
||||
await self.osoenergy.hotwater.turn_on(self.entity_data, True)
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn off hotwater."""
|
||||
await self.osoenergy.hotwater.turn_off(self.device, True)
|
||||
await self.osoenergy.hotwater.turn_off(self.entity_data, True)
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperature."""
|
||||
target_temperature = int(kwargs.get("temperature", self.target_temperature))
|
||||
profile = [target_temperature] * 24
|
||||
|
||||
await self.osoenergy.hotwater.set_profile(self.device, profile)
|
||||
await self.osoenergy.hotwater.set_profile(self.entity_data, profile)
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Update all Node data from Hive."""
|
||||
await self.osoenergy.session.update_data()
|
||||
self.device = await self.osoenergy.hotwater.get_water_heater(self.device)
|
||||
self.entity_data = await self.osoenergy.hotwater.get_water_heater(
|
||||
self.entity_data
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue