"""House, zone and climate-group plan sensors exposed by GREE Controller.""" from __future__ import annotations from typing import Any from homeassistant.components.sensor import SensorEntity from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity from . import GreeControllerRuntimeData from .const import DOMAIN from .coordinator import GreeControllerCoordinator async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Create whole-house and per-zone automation-plan sensors.""" runtime: GreeControllerRuntimeData = entry.runtime_data entities: list[SensorEntity] = [GreeControllerHousePlanSensor(runtime.coordinator)] for zone in runtime.coordinator.plan.get("zones", []): if zone.get("zone_id"): entities.append(GreeControllerZonePlanSensor(runtime.coordinator, str(zone["zone_id"]))) for group_id in runtime.coordinator.groups: entities.append(GreeControllerGroupPlanSensor(runtime.coordinator, group_id)) async_add_entities(entities) class GreeControllerHousePlanSensor(CoordinatorEntity[GreeControllerCoordinator], SensorEntity): """Summary of the current whole-house control plan.""" _attr_has_entity_name = True _attr_name = "Automation plan" _attr_unique_id = "house-control-plan" _unrecorded_attributes = frozenset({"next_events", "rules"}) @property def native_value(self) -> str: return str(self.coordinator.plan.get("house_mode") or "unknown") @property def device_info(self) -> DeviceInfo: return DeviceInfo( identifiers={(DOMAIN, "controller")}, name="GREE Controller", manufacturer="GREE Controller", model="Local controller", ) @property def extra_state_attributes(self) -> dict[str, Any]: plan = self.coordinator.plan zones = plan.get("zones", []) groups = list(self.coordinator.groups.values()) return { "generated_at": plan.get("generated_at"), "outdoor_temperature": plan.get("outdoor_temperature"), "control_strategy": plan.get("control_strategy"), "work_profile": plan.get("house_preset"), "all_units_powered": bool(self.coordinator.data) and all( bool(device.get("power")) for device in self.coordinator.data.values() if device.get("enabled", True) ), "enabled_zones": sum(bool(zone.get("enabled")) for zone in zones), "effective_enabled_zones": sum(bool(zone.get("effective_enabled", zone.get("enabled"))) for zone in zones), "demanding_zones": sum(bool(zone.get("demand")) for zone in zones), "groups": len(groups), "enabled_groups": sum(bool(group.get("power_enabled")) for group in groups), "demanding_groups": sum(int(group.get("demanding_zones") or 0) > 0 for group in groups), "next_events": plan.get("next_events", []), "rules": plan.get("rules", []), } class GreeControllerZonePlanSensor(CoordinatorEntity[GreeControllerCoordinator], SensorEntity): """Readable automation plan for one controller zone.""" _attr_has_entity_name = True _attr_name = "Control plan" _unrecorded_attributes = frozenset({"next_events"}) def __init__(self, coordinator: GreeControllerCoordinator, zone_id: str) -> None: super().__init__(coordinator) self._zone_id = zone_id self._attr_unique_id = f"{zone_id}-control-plan" @property def _zone(self) -> dict[str, Any]: for zone in self.coordinator.plan.get("zones", []): if str(zone.get("zone_id")) == self._zone_id: return zone return {} @property def available(self) -> bool: return super().available and bool(self._zone) @property def native_value(self) -> str: zone = self._zone if not zone.get("enabled", False): return "disabled" if not zone.get("effective_enabled", True): return "blocked" return "requesting" if zone.get("demand", False) else "satisfied" @property def device_info(self) -> DeviceInfo: zone = self._zone return DeviceInfo( identifiers={(DOMAIN, f"zone:{self._zone_id}")}, name=str(zone.get("zone_name") or self._zone_id), manufacturer="GREE Controller", model="Zone thermostat", via_device=(DOMAIN, "controller"), ) @property def extra_state_attributes(self) -> dict[str, Any]: zone = self._zone return { "zone_id": self._zone_id, "device_id": zone.get("device_id"), "device_name": zone.get("device_name"), "enabled": bool(zone.get("enabled", False)), "effective_enabled": bool(zone.get("effective_enabled", zone.get("enabled", False))), "mode": zone.get("mode"), "preset": zone.get("preset"), "preset_override": zone.get("preset_override"), "current_temperature": zone.get("current_temperature"), "target_temperature": zone.get("target_temperature"), "device_setpoint": zone.get("device_setpoint"), "control_source": zone.get("control_source"), "manual_override_until": zone.get("manual_override_until"), "current_schedule": zone.get("current_schedule_name"), "next_events": zone.get("next_events", []), } class GreeControllerGroupPlanSensor(CoordinatorEntity[GreeControllerCoordinator], SensorEntity): """Readable status and automation plan for one climate group.""" _attr_has_entity_name = True _attr_name = "Control plan" _unrecorded_attributes = frozenset({"next_events", "zone_ids", "zone_names", "members"}) def __init__(self, coordinator: GreeControllerCoordinator, group_id: str) -> None: super().__init__(coordinator) self._group_id = group_id self._attr_unique_id = f"{group_id}-group-control-plan" @property def _group(self) -> dict[str, Any]: return self.coordinator.groups.get(self._group_id, {}) @property def available(self) -> bool: return super().available and bool(self._group) @property def native_value(self) -> str: group = self._group if not group.get("power_enabled", False): return "off" if group.get("mode") == "house" and group.get("house_mode") == "off": return "paused" return "requesting" if int(group.get("demanding_zones") or 0) > 0 else "satisfied" @property def device_info(self) -> DeviceInfo: group = self._group return DeviceInfo( identifiers={(DOMAIN, f"group:{self._group_id}")}, name=str(group.get("name") or self._group_id), manufacturer="GREE Controller", model="Climate group", via_device=(DOMAIN, "controller"), ) @property def extra_state_attributes(self) -> dict[str, Any]: group = self._group return { "group_id": self._group_id, "power_enabled": bool(group.get("power_enabled", False)), "effective_power": bool(group.get("effective_power", False)), "mode": group.get("mode"), "global_house_mode": group.get("house_mode"), "work_profile": group.get("preset"), "zone_count": group.get("zone_count"), "enabled_zones": group.get("enabled_zones"), "active_zones": group.get("active_zones"), "demanding_zones": group.get("demanding_zones"), "device_count": group.get("device_count"), "online_devices": group.get("online_devices"), "current_temperature": group.get("current_temperature"), "zone_ids": group.get("zone_ids", []), "zone_names": group.get("zone_names", []), "members": group.get("members", []), "next_events": group.get("next_events", []), }