"""A representation of a single Roth TouchlineSL zone. In most cases, a Zone represents a specific room in a building. Zones can report on both temperature and humidity. Each zone can either be set with a constant target temperature, set to a specific global schedule, or set onto a local schedule. Typical Usage: import os from pytouchlinesl import TouchlineSL tsl = TouchlineSL(username"foo@bar.com", password="deadbeef") # Get the module from the account module = await tsl.modules() module = modules[0] # Get a specific zone from the module zone = await module.zone_by_name("Kitchen") temp = zone.temperature # Set the zone to a constant target temp of 22.5 await zone.set_temperature(22.5) # Set the zone onto a specific global schedule schedule = module.schedule_by_name("Living Spaces") await zone.set_schedule(schedule.id) """ from typing import TYPE_CHECKING, Literal from .client import BaseClient from .client.models import GlobalScheduleModel, LocalScheduleModel, ZoneModel if TYPE_CHECKING: from .module import Module class Zone: """A representation of a single Roth TouchlineSL zone.""" def __init__( self, module: "Module", client: BaseClient, zone_data: ZoneModel, schedule: GlobalScheduleModel | LocalScheduleModel | None, ): """Construct an instance of a zone. Args: module: The Module this Zone belongs to. client: The underlying API client to use for fetching data. zone_data: A raw representation of the Zone returned from a client instance. schedule: None if Zone is set to constant temp, otherwise instance of the global schedule assigned to the zone """ self._module = module self._client = client self._raw_data = zone_data self._schedule = schedule @property def name(self) -> str: """Return the configured name of the zone.""" return self._raw_data.description.name @property def id(self) -> int: """Return the ID of the zone.""" return self._raw_data.zone.id @property def battery_level(self) -> int | None: """Return the battery level of the zone.""" return self._raw_data.zone.battery_level @property def temperature(self) -> float | None: """Return the current temperature of the zone, if it's enabled, otherwise None.""" if self._raw_data.zone.current_temperature: return float(int(self._raw_data.zone.current_temperature) / 10) return None @property def target_temperature(self) -> float: """Return the target temperature of the zone.""" return float(int(self._raw_data.zone.set_temperature) / 10) @property def humidity(self) -> float: """Return the humidity of the zone.""" return float(int(self._raw_data.zone.humidity)) @property def mode(self) -> Literal["constantTemp", "globalSchedule", "localSchedule", "timeLimit"]: """Return the mode of the zone.""" return self._raw_data.mode.mode @property def enabled(self) -> bool: """Return whether or not the zone is enabled.""" return self._raw_data.zone.zone_state != "zoneOff" @property def schedule(self) -> GlobalScheduleModel | LocalScheduleModel | None: """Return the zone's current schedule. If a constant temp is set, returns None.""" if self.mode == "constantTemp": return None return self._schedule @property def relay_on(self) -> bool: """Return whether or not the zone's relay is on.""" return self._raw_data.zone.flags.relay_state == "on" @property def algorithm(self) -> Literal["heating", "cooling"]: """Return the zone's current algorithm, either `heating` or `cooling`.""" return self._raw_data.zone.flags.algorithm @property def signal_strength(self) -> int | None: """Return the signal strength of the zone.""" return self._raw_data.zone.signal_strength @property def alarm(self) -> Literal["sensor_damaged", "no_communication"] | None: """Return the alarm state of the zone.""" state = self._raw_data.zone.zone_state if state == "sensorDamaged": return "sensor_damaged" elif state == "noCommunication": return "no_communication" return None async def set_temperature(self, temperature: float): """Set a constant target temperature for the zone.""" await self._client.set_zone_temperature( module_id=self._module.id, zone_id=self.id, mode_id=self._raw_data.mode.id, temperature=temperature, ) self._module.invalidate_cache() async def set_schedule(self, schedule_id: int): """Assign the zone to a specific global schedule.""" await self._client.set_zone_schedule(self._module.id, self.id, schedule_id) self._module.invalidate_cache()