Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions ariston/ariston_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@
devices = self._get(f"{self.__api_url}{ARISTON_REMOTE}/{ARISTON_PLANTS}")
if devices is not None:
return list(devices)
return list()

Check warning on line 88 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaG-&open=AZ4HSeXkmg9FVhWvNaG-&pullRequest=182

def get_detailed_velis_devices(self) -> list[Any]:
"""Get detailed cloud devices"""
devices = self._get(f"{self.__api_url}{ARISTON_VELIS}/{ARISTON_PLANTS}")
if devices is not None:
return list(devices)
return list()

Check warning on line 95 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaG_&open=AZ4HSeXkmg9FVhWvNaG_&pullRequest=182

def get_devices(self) -> list[Any]:
"""Get cloud devices"""
Expand All @@ -101,7 +101,7 @@
)
if devices is not None:
return list(devices)
return list()

Check warning on line 104 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHA&open=AZ4HSeXkmg9FVhWvNaHA&pullRequest=182

def get_features_for_device(self, gw_id: str) -> dict[str, Any]:
"""Get features for the device"""
Expand All @@ -110,7 +110,7 @@
)
if features is not None:
return features
return dict()

Check warning on line 113 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHB&open=AZ4HSeXkmg9FVhWvNaHB&pullRequest=182

def get_energy_account(self, gw_id: str) -> dict[str, Any]:
"""Get energy account for the device"""
Expand All @@ -119,7 +119,7 @@
)
if energy_account is not None:
return energy_account
return dict()

Check warning on line 122 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHC&open=AZ4HSeXkmg9FVhWvNaHC&pullRequest=182

def get_consumptions_sequences(self, gw_id: str, usages: str) -> list[Any]:
"""Get consumption sequences for the device"""
Expand All @@ -128,7 +128,7 @@
)
if consumptions_sequences is not None:
return list(consumptions_sequences)
return list()

Check warning on line 131 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHD&open=AZ4HSeXkmg9FVhWvNaHD&pullRequest=182

def get_consumptions_settings(self, gw_id: str) -> dict[str, Any]:
"""Get consumption settings"""
Expand All @@ -138,7 +138,7 @@
)
if consumptions_settings is not None:
return consumptions_settings
return dict()

Check warning on line 141 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHE&open=AZ4HSeXkmg9FVhWvNaHE&pullRequest=182

def set_consumptions_settings(
self,
Expand Down Expand Up @@ -174,7 +174,7 @@
)
if properties is not None:
return properties
return dict()

Check warning on line 177 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHF&open=AZ4HSeXkmg9FVhWvNaHF&pullRequest=182

def get_bsb_plant_data(self, gw_id: str) -> dict[str, Any]:
"""Get BSB plant data."""
Expand All @@ -183,14 +183,14 @@
)
if data is not None:
return data
return dict()

Check warning on line 186 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHG&open=AZ4HSeXkmg9FVhWvNaHG&pullRequest=182

def get_velis_plant_data(self, plant_data: PlantData, gw_id: str) -> dict[str, Any]:
"""Get Velis properties"""
data = self._get(f"{self.__api_url}{ARISTON_VELIS}/{plant_data.value}/{gw_id}")
if data is not None:
return data
return dict()

Check warning on line 193 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHH&open=AZ4HSeXkmg9FVhWvNaHH&pullRequest=182

def get_velis_plant_settings(
self, plant_data: PlantData, gw_id: str
Expand All @@ -201,7 +201,7 @@
)
if settings is not None:
return settings
return dict()

Check warning on line 204 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHI&open=AZ4HSeXkmg9FVhWvNaHI&pullRequest=182

def get_menu_items(self, gw_id: str) -> list[dict[str, Any]]:
"""Get menu items"""
Expand All @@ -210,7 +210,7 @@
)
if items is not None:
return items
return list()

Check warning on line 213 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHJ&open=AZ4HSeXkmg9FVhWvNaHJ&pullRequest=182

def set_property(
self,
Expand Down Expand Up @@ -437,7 +437,7 @@
)
if thermostat_time_progs is not None:
return thermostat_time_progs
return dict()

Check warning on line 440 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHK&open=AZ4HSeXkmg9FVhWvNaHK&pullRequest=182

def set_holiday(
self,
Expand All @@ -452,6 +452,23 @@
},
)

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(
Expand Down Expand Up @@ -544,7 +561,7 @@
)
if detailed_devices is not None:
return list(detailed_devices)
return list()

Check warning on line 564 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHL&open=AZ4HSeXkmg9FVhWvNaHL&pullRequest=182

async def async_get_detailed_velis_devices(self) -> list[Any]:
"""Async get detailed cloud devices"""
Expand All @@ -553,7 +570,7 @@
)
if detailed_velis_devices is not None:
return list(detailed_velis_devices)
return list()

Check warning on line 573 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHM&open=AZ4HSeXkmg9FVhWvNaHM&pullRequest=182

async def async_get_devices(self) -> list[Any]:
"""Async get cloud devices"""
Expand All @@ -562,7 +579,7 @@
)
if devices is not None:
return list(devices)
return list()

Check warning on line 582 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHN&open=AZ4HSeXkmg9FVhWvNaHN&pullRequest=182

async def async_get_features_for_device(
self, gw_id: str
Expand All @@ -579,7 +596,7 @@
)
if energy_account is not None:
return energy_account
return dict()

Check warning on line 599 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHO&open=AZ4HSeXkmg9FVhWvNaHO&pullRequest=182

async def async_get_consumptions_sequences(
self, gw_id: str, usages: str
Expand All @@ -590,7 +607,7 @@
)
if consumptions_sequences is not None:
return list(consumptions_sequences)
return list()

Check warning on line 610 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHP&open=AZ4HSeXkmg9FVhWvNaHP&pullRequest=182

async def async_get_consumptions_settings(self, gw_id: str) -> dict[str, Any]:
"""Async get consumption settings"""
Expand All @@ -600,7 +617,7 @@
)
if consumptions_settings is not None:
return consumptions_settings
return dict()

Check warning on line 620 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHQ&open=AZ4HSeXkmg9FVhWvNaHQ&pullRequest=182

async def async_set_consumptions_settings(
self,
Expand Down Expand Up @@ -628,7 +645,7 @@
)
if properties is not None:
return properties
return dict()

Check warning on line 648 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHR&open=AZ4HSeXkmg9FVhWvNaHR&pullRequest=182

async def async_get_bsb_plant_data(self, gw_id: str) -> dict[str, Any]:
"""Get BSB plant data."""
Expand All @@ -637,7 +654,7 @@
)
if data is not None:
return data
return dict()

Check warning on line 657 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHS&open=AZ4HSeXkmg9FVhWvNaHS&pullRequest=182

async def async_get_velis_plant_data(
self, plant_data: PlantData, gw_id: str
Expand All @@ -648,7 +665,7 @@
)
if med_plant_data is not None:
return med_plant_data
return dict()

Check warning on line 668 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHT&open=AZ4HSeXkmg9FVhWvNaHT&pullRequest=182

async def async_get_velis_plant_settings(
self, plant_data: PlantData, gw_id: str
Expand All @@ -659,7 +676,7 @@
)
if med_plant_settings is not None:
return med_plant_settings
return dict()

Check warning on line 679 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHU&open=AZ4HSeXkmg9FVhWvNaHU&pullRequest=182

async def async_get_menu_items(self, gw_id: str) -> list[dict[str, Any]]:
"""Async get menu items"""
Expand All @@ -668,7 +685,7 @@
)
if items is not None:
return items
return list()

Check warning on line 688 in ariston/ariston_api.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=fustom_python-ariston-api&issues=AZ4HSeXkmg9FVhWvNaHV&open=AZ4HSeXkmg9FVhWvNaHV&pullRequest=182

async def async_set_property(
self,
Expand Down Expand Up @@ -914,6 +931,23 @@
},
)

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(
Expand Down
1 change: 1 addition & 0 deletions ariston/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
54 changes: 54 additions & 0 deletions ariston/nuos_split_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import annotations

import logging
from datetime import date
from typing import Optional

from .velis_device import AristonVelisDevice
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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