diff --git a/ariston/ariston_api.py b/ariston/ariston_api.py index 465e078..5fe446f 100644 --- a/ariston/ariston_api.py +++ b/ariston/ariston_api.py @@ -452,6 +452,23 @@ def set_holiday( }, ) + def set_velis_slp_holiday( + self, + gw_id: str, + holiday_end_date: Optional[str], + ) -> None: + """Set holiday on a Velis Slp (Nuos) device. + + Pass an ISO-formatted end date string to schedule the holiday, or + ``None`` to clear it. + """ + self._post( + f"{self.__api_url}{ARISTON_VELIS}/{PlantData.Slp.value}/{gw_id}/holiday", + { + "new": holiday_end_date, + }, + ) + def get_bus_errors(self, gw_id: str) -> list[Any]: """Get bus errors""" bus_errors = self._get( @@ -914,6 +931,23 @@ async def async_set_holiday( }, ) + async def async_set_velis_slp_holiday( + self, + gw_id: str, + holiday_end_date: Optional[str], + ) -> None: + """Async set holiday on a Velis Slp (Nuos) device. + + Pass an ISO-formatted end date string to schedule the holiday, or + ``None`` to clear it. + """ + await self._async_post( + f"{self.__api_url}{ARISTON_VELIS}/{PlantData.Slp.value}/{gw_id}/holiday", + { + "new": holiday_end_date, + }, + ) + async def async_get_bus_errors(self, gw_id: str) -> list[Any]: """Async get bus errors""" bus_errors = await self._async_get( diff --git a/ariston/const.py b/ariston/const.py index 13f9b09..20bd24e 100644 --- a/ariston/const.py +++ b/ariston/const.py @@ -427,6 +427,7 @@ class NuosSplitProperties(VelisDeviceProperties): OP_MODE: Final[str] = "opMode" BOOST_ON: Final[str] = "boostOn" HP_STATE: Final[str] = "hpState" + HOLIDAY_UNTIL: Final[str] = "holidayUntil" class EvoLydosDeviceProperties(VelisDeviceProperties): diff --git a/ariston/nuos_split_device.py b/ariston/nuos_split_device.py index bfc6fe7..f7efc79 100644 --- a/ariston/nuos_split_device.py +++ b/ariston/nuos_split_device.py @@ -2,6 +2,7 @@ from __future__ import annotations import logging +from datetime import date from typing import Optional from .velis_device import AristonVelisDevice @@ -112,6 +113,26 @@ def water_heater_mode_value(self) -> Optional[int]: """Get water heater mode value""" return self.data.get(NuosSplitProperties.OP_MODE, None) + @property + def holiday_end_date(self) -> Optional[str]: + """Get the holiday end date. + + Returns the ISO-formatted end date the cloud has on file + (e.g. ``"2026-08-15T00:00:00"``) when a holiday is scheduled, or + ``None`` when no holiday is active. + """ + return self.data.get(NuosSplitProperties.HOLIDAY_UNTIL, None) + + @property + def holiday_active(self) -> bool: + """Whether a holiday is currently scheduled. + + The Slp payload does not expose a dedicated boolean: an active + holiday is signalled by `holidayUntil` being a non-null string, + and an inactive holiday by `holidayUntil` being ``null``. + """ + return self.data.get(NuosSplitProperties.HOLIDAY_UNTIL) is not None + def set_water_heater_boost(self, boost: bool): """Set water heater boost""" self.api.set_nous_boost(self.gw, boost) @@ -257,3 +278,36 @@ async def async_set_heating_rate(self, heating_rate: float): self.plant_settings[SlpDeviceSettings.SLP_HEATING_RATE], ) self.plant_settings[SlpDeviceSettings.SLP_HEATING_RATE] = heating_rate + + @staticmethod + def _create_holiday_end_date(holiday_end: Optional[date]) -> Optional[str]: + """Format a holiday end date for the cloud payload. + + Returns ``None`` when ``holiday_end`` is ``None``, which the cloud + interprets as "clear the holiday". + """ + return ( + None + if holiday_end is None + else holiday_end.strftime("%Y-%m-%dT00:00:00") + ) + + def set_holiday(self, holiday_end: Optional[date]) -> None: + """Set or clear the holiday on this Nuos device. + + Pass a ``datetime.date`` to schedule the holiday end, or ``None`` to + clear an active holiday. + """ + holiday_end_date = self._create_holiday_end_date(holiday_end) + self.api.set_velis_slp_holiday(self.gw, holiday_end_date) + self.data[NuosSplitProperties.HOLIDAY_UNTIL] = holiday_end_date + + async def async_set_holiday(self, holiday_end: Optional[date]) -> None: + """Async set or clear the holiday on this Nuos device. + + Pass a ``datetime.date`` to schedule the holiday end, or ``None`` to + clear an active holiday. + """ + holiday_end_date = self._create_holiday_end_date(holiday_end) + await self.api.async_set_velis_slp_holiday(self.gw, holiday_end_date) + self.data[NuosSplitProperties.HOLIDAY_UNTIL] = holiday_end_date