diff --git a/custom_components/mypyllant/binary_sensor.py b/custom_components/mypyllant/binary_sensor.py index 7556258..c34d053 100644 --- a/custom_components/mypyllant/binary_sensor.py +++ b/custom_components/mypyllant/binary_sensor.py @@ -13,11 +13,11 @@ from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity -from myPyllant.models import Circuit, System +from myPyllant.models import System from . import SystemCoordinator from .const import DOMAIN -from .utils import EntityList, ZoneCoordinatorEntity +from .utils import EntityList, ZoneCoordinatorEntity, CircuitEntity _LOGGER = logging.getLogger(__name__) @@ -242,51 +242,7 @@ def unique_id(self) -> str: return f"{DOMAIN}_{self.id_infix}_eebus_enabled" -class CircuitEntity(CoordinatorEntity, BinarySensorEntity): - def __init__( - self, - system_index: int, - circuit_index: int, - coordinator: SystemCoordinator, - ): - super().__init__(coordinator) - self.system_index = system_index - self.circuit_index = circuit_index - - @property - def system(self) -> System: - return self.coordinator.data[self.system_index] - - @property - def circuit(self) -> Circuit: - return self.coordinator.data[self.system_index].circuits[self.circuit_index] - - @property - def name_prefix(self) -> str: - return f"{self.system.home.home_name or self.system.home.nomenclature} Circuit {self.circuit_index}" - - @property - def id_infix(self) -> str: - return f"{self.system.id}_circuit_{self.circuit.index}" - - @property - def device_info(self) -> DeviceInfo | None: - return DeviceInfo( - identifiers={(DOMAIN, self.id_infix)}, - name=self.name_prefix, - manufacturer=self.system.brand_name, - ) - - -class CircuitIsCoolingAllowed(CircuitEntity): - def __init__( - self, - system_index: int, - circuit_index: int, - coordinator: SystemCoordinator, - ): - super().__init__(system_index, circuit_index, coordinator) - +class CircuitIsCoolingAllowed(CircuitEntity, BinarySensorEntity): @property def is_on(self) -> bool | None: return self.circuit.is_cooling_allowed diff --git a/custom_components/mypyllant/number.py b/custom_components/mypyllant/number.py index f5a5dc6..8253fda 100644 --- a/custom_components/mypyllant/number.py +++ b/custom_components/mypyllant/number.py @@ -5,7 +5,7 @@ from homeassistant.components.number import NumberEntity from homeassistant.config_entries import ConfigEntry -from homeassistant.const import UnitOfTime +from homeassistant.const import UnitOfTime, UnitOfTemperature from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -16,6 +16,7 @@ SystemCoordinatorEntity, ZoneCoordinatorEntity, EntityList, + CircuitEntity, ) _LOGGER = logging.getLogger(__name__) @@ -42,6 +43,20 @@ async def async_setup_entry( sensors.append( lambda: ZoneQuickVetoDurationNumber(index, zone_index, coordinator) ) + for circuit_index, circuit in enumerate(system.circuits): + sensors.append( + lambda: CircuitHeatingCurve(index, circuit_index, coordinator) + ) + sensors.append( + lambda: CircuitHeatDemandLimitedByOutsideTemperature( + index, circuit_index, coordinator + ) + ) + sensors.append( + lambda: CircuitMinFlowTemperatureSetpoint( + index, circuit_index, coordinator + ) + ) async_add_entities(sensors) # type: ignore @@ -180,3 +195,80 @@ def unique_id(self) -> str: @property def available(self) -> bool: return self.zone.quick_veto_ongoing + + +class CircuitHeatingCurve(CircuitEntity, NumberEntity): + _attr_native_min_value = 0.1 + _attr_native_max_value = 5.0 + _attr_native_step = 0.0000001 + _attr_icon = "mdi:chart-line" + + @property + def native_value(self): + return self.circuit.heating_curve + + async def async_set_native_value(self, value: float) -> None: + await self.coordinator.api.set_circuit_heating_curve(self.circuit, value) + await self.coordinator.async_request_refresh_delayed() + + @property + def name(self) -> str: + return f"{self.name_prefix} Heating Curve" + + @property + def unique_id(self) -> str: + return f"{DOMAIN} {self.id_infix}_heating_curve" + + +class CircuitHeatDemandLimitedByOutsideTemperature(CircuitEntity, NumberEntity): + _attr_native_min_value = 0.0 + _attr_native_max_value = 100.0 + _attr_native_step = 0.1 + _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS + _attr_icon = "mdi:home-thermometer" + + @property + def native_value(self): + return self.circuit.heat_demand_limited_by_outside_temperature + + async def async_set_native_value(self, value: float) -> None: + await ( + self.coordinator.api.set_circuit_heat_demand_limited_by_outside_temperature( + self.circuit, value + ) + ) + await self.coordinator.async_request_refresh_delayed() + + @property + def name(self) -> str: + return f"{self.name_prefix} Heat Demand Limited by Outside Temperature" + + @property + def unique_id(self) -> str: + return f"{DOMAIN} {self.id_infix}_heat_demand_limited_by_outside_temperature" + + +class CircuitMinFlowTemperatureSetpoint(CircuitEntity, NumberEntity): + _attr_native_min_value = 0.0 + _attr_native_max_value = 100.0 + _attr_native_step = 0.1 + _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS + _attr_icon = "mdi:thermometer-water" + + @property + def native_value(self): + return self.circuit.heating_flow_temperature_minimum_setpoint + + async def async_set_native_value(self, value: float) -> None: + await self.coordinator.api.set_circuit_min_flow_temperature_setpoint( + self.circuit, value + ) + await self.coordinator.async_request_refresh_delayed() + + @property + def name(self) -> str: + return f"{self.name_prefix} Min Flow Temperature Setpoint" + + @property + def unique_id(self) -> str: + return f"{DOMAIN} {self.id_infix}_min_flow_temperature_setpoint" diff --git a/custom_components/mypyllant/utils.py b/custom_components/mypyllant/utils.py index 758227e..d19c519 100644 --- a/custom_components/mypyllant/utils.py +++ b/custom_components/mypyllant/utils.py @@ -21,7 +21,7 @@ if typing.TYPE_CHECKING: from custom_components.mypyllant.coordinator import SystemCoordinator - from myPyllant.models import System, DomesticHotWater, Zone, AmbisenseRoom + from myPyllant.models import System, DomesticHotWater, Zone, AmbisenseRoom, Circuit logger = logging.getLogger(__name__) @@ -348,3 +348,39 @@ def device_info(self): @property def unique_id(self) -> str: return f"{DOMAIN}_{self.id_infix}_climate" + + +class CircuitEntity(CoordinatorEntity): + def __init__( + self, + system_index: int, + circuit_index: int, + coordinator: SystemCoordinator, + ): + super().__init__(coordinator) + self.system_index = system_index + self.circuit_index = circuit_index + + @property + def system(self) -> System: + return self.coordinator.data[self.system_index] + + @property + def circuit(self) -> Circuit: + return self.coordinator.data[self.system_index].circuits[self.circuit_index] + + @property + def name_prefix(self) -> str: + return f"{self.system.home.home_name or self.system.home.nomenclature} Circuit {self.circuit_index}" + + @property + def id_infix(self) -> str: + return f"{self.system.id}_circuit_{self.circuit.index}" + + @property + def device_info(self) -> DeviceInfo | None: + return DeviceInfo( + identifiers={(DOMAIN, self.id_infix)}, + name=self.name_prefix, + manufacturer=self.system.brand_name, + ) diff --git a/tests/test_binary_sensor.py b/tests/test_binary_sensor.py index 65c018a..dd2d1a2 100644 --- a/tests/test_binary_sensor.py +++ b/tests/test_binary_sensor.py @@ -11,7 +11,6 @@ from myPyllant.tests.utils import list_test_data, load_test_data from custom_components.mypyllant.binary_sensor import ( - CircuitEntity, CircuitIsCoolingAllowed, ControlError, ControlOnline, @@ -19,6 +18,7 @@ async_setup_entry, ZoneIsManualCoolingActive, ) +from custom_components.mypyllant.utils import CircuitEntity from custom_components.mypyllant.const import DOMAIN from tests.conftest import MockConfigEntry, TEST_OPTIONS from tests.test_init import test_user_input