From 37d4b92cadcd64bd8826a0bd1f0238e5ea51712e Mon Sep 17 00:00:00 2001 From: G Johansson Date: Tue, 16 Jul 2024 14:43:38 +0000 Subject: [PATCH] Add comments and update model --- pysensibo/__init__.py | 37 +++++++++++++++------------ pysensibo/model.py | 58 +++++++++++++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 35 deletions(-) diff --git a/pysensibo/__init__.py b/pysensibo/__init__.py index 0d6286b..08ab819 100644 --- a/pysensibo/__init__.py +++ b/pysensibo/__init__.py @@ -87,7 +87,7 @@ async def async_get_devices_data(self) -> SensiboData: # noqa: C901 iaq = measure.get("iaq") rcda = measure.get("rcda") - # Add AntiMold + # Add AntiMold (premium feature) anti_mold: dict[str, Any] | None = dev["antiMoldConfig"] anti_mold_running = ( anti_mold.get("anti_mold_running") if anti_mold else None @@ -101,6 +101,18 @@ async def async_get_devices_data(self) -> SensiboData: # noqa: C901 target_temperature = ac_states.get("targetTemperature") hvac_mode = ac_states.get("mode") running = ac_states.get("on") + available = dev["connectionStatus"].get("isAlive", True) + + capabilities: dict[str, Any] = dev.get("remoteCapabilities", {}) or {} + hvac_modes = list(capabilities.get("modes", {}) or {}) + if not hvac_modes: + LOGGER.warning( + "Device %s not correctly registered with remote on Sensibo cloud.", + name, + ) + hvac_modes.append("off") + state = hvac_mode if hvac_mode else "off" + fan_mode: str | None = ac_states.get("fanLevel") if fan_mode: fan_mode = fan_mode.lower() @@ -113,15 +125,7 @@ async def async_get_devices_data(self) -> SensiboData: # noqa: C901 light_mode: str | None = ac_states.get("light") if light_mode: light_mode = light_mode.lower() - available = dev["connectionStatus"].get("isAlive", True) - capabilities: dict[str, Any] = dev.get("remoteCapabilities", {}) or {} - hvac_modes = list(capabilities.get("modes", {}) or {}) - if not hvac_modes: - LOGGER.warning( - "Device %s not correctly registered with remote on Sensibo cloud.", - name, - ) - hvac_modes.append("off") + current_capabilities: dict[str, Any] = capabilities.get("modes", {}).get( ac_states.get("mode"), {} ) @@ -188,29 +192,30 @@ async def async_get_devices_data(self) -> SensiboData: # noqa: C901 if "light" in _capabilities[mode]: full_features.add("light") - state = hvac_mode if hvac_mode else "off" - fw_ver = dev["firmwareVersion"] fw_ver_available = dev.get("currentlyAvailableFirmwareVersion") fw_type = dev["firmwareType"] model = dev["productModel"] + # Calibration for temperature and humidity, always available keys calibration: dict[str, float] = dev["sensorsCalibration"] calibration_temp = calibration.get("temperature") calibration_hum = calibration.get("humidity") # Sky plus supports functionality to use motion sensor as sensor for temp and humidity + # In that case the user has it as main sensor we will use those temperature and humidity values if main_sensor := dev["mainMeasurementsSensor"]: measurements = main_sensor["measurements"] temperature = measurements.get("temperature") humidity = measurements.get("humidity") motion_sensors: dict[str, MotionSensor] = {} - if dev["motionSensors"]: + if dev["motionSensors"]: # Key is always present sensor: dict[str, Any] for sensor in dev["motionSensors"]: measurement: dict[str, Any] = sensor["measurements"] connection: dict[str, Any] = sensor["connectionStatus"] + # All keys should be present motion_sensors[sensor["id"]] = MotionSensor( id=sensor["id"], alive=connection.get("isAlive"), @@ -278,7 +283,7 @@ async def async_get_devices_data(self) -> SensiboData: # noqa: C901 timer_id = None timer_state_on = None timer_time = None - if dev["productModel"] != "pure": + if dev["productModel"] != "pure": # No timer for Pure devices timer_on = timer.get("isEnabled", False) timer_id = timer.get("id") timer_state: dict[str, Any] | None = timer.get("acState") @@ -292,10 +297,10 @@ async def async_get_devices_data(self) -> SensiboData: # noqa: C901 else None ) - # Smartmode + # Smartmode (climate react) smart: dict[str, Any] = dev["smartMode"] if dev["smartMode"] else {} smart_on = None - if dev["productModel"] != "pure": + if dev["productModel"] != "pure": # No smartmode for Pure devices smart_on = smart.get("enabled", False) smart_type: str | None = smart.get("type") if smart_type: diff --git a/pysensibo/model.py b/pysensibo/model.py index 9f81bbf..534d1a5 100644 --- a/pysensibo/model.py +++ b/pysensibo/model.py @@ -27,8 +27,13 @@ class SensiboDevice: temp: float | None feelslike: float | None humidity: int | None + pm25: float | None + pm25_pure: int | None tvoc: int | None co2: int | None + etoh: float | None + iaq: int | None + rcda: float | None target_temp: int | None hvac_mode: str | None device_on: bool | None @@ -38,6 +43,10 @@ class SensiboDevice: light_mode: str | None available: bool hvac_modes: list[str] | None + + state: str # hvac state + + # Translated modes are lowercase to case for matching api fan_modes: list[str] | None fan_modes_translated: dict[str, str] | None swing_modes: list[str] | None @@ -46,25 +55,32 @@ class SensiboDevice: horizontal_swing_modes_translated: dict[str, str] | None light_modes: list[str] | None light_modes_translated: dict[str, str] | None + temp_unit: str | None temp_list: list[int] temp_step: int + active_features: list[str] full_features: set[str] - state: str + full_capabilities: dict[str, Any] + fw_ver: str fw_ver_available: str | None fw_type: str + update_available: bool model: str + calibration_temp: float | None calibration_hum: float | None - full_capabilities: dict[str, Any] + + # Motion sensors are their own dataclasses motion_sensors: dict[str, MotionSensor] | None - pm25: float | None - pm25_pure: int | None - room_occupied: bool - update_available: bool + room_occupied: bool # Only available if motion sensors are present + + # Schedule data is its own dataclasses schedules: dict[str, Schedules] | None + + # Pure only data pure_boost_enabled: bool | None pure_sensitivity: str | None pure_ac_integration: bool | None @@ -72,23 +88,27 @@ class SensiboDevice: pure_measure_integration: bool | None pure_prime_integration: bool | None pure_conf: dict[str, Any] | None + + # Timer only data timer_on: bool | None timer_id: str | None timer_state_on: bool | None timer_time: datetime | None + + # Climate react only data smart_on: bool | None smart_type: str | None smart_low_temp_threshold: float | None smart_high_temp_threshold: float | None smart_low_state: dict[str, Any] | None smart_high_state: dict[str, Any] | None + filter_clean: bool filter_last_reset: datetime | None - etoh: float | None - iaq: int | None - rcda: float | None + location_id: str location_name: str + anti_mold_running: bool | None anti_mold_enabled: bool | None anti_mold_fan_time: int | None @@ -101,16 +121,16 @@ class MotionSensor: """Dataclass for motionsensors.""" id: str - alive: bool | None = None - motion: bool | None = None - fw_ver: str | None = None - fw_type: str | None = None - is_main_sensor: bool | None = None - battery_voltage: int | None = None - humidity: int | None = None - temperature: float | None = None - model: str | None = None - rssi: int | None = None + alive: bool | None + motion: bool | None + fw_ver: str | None + fw_type: str | None + is_main_sensor: bool | None + battery_voltage: int | None + humidity: int | None + temperature: float | None + model: str | None + rssi: int | None @dataclass