"""Writable house, group, zone and device switches for GREE Controller.""" from __future__ import annotations from typing import Any from homeassistant.components.switch import SwitchEntity 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 DEVICE_FEATURE_SWITCHES = [ ("light", "supports_light", "Panel light"), ("quiet", "supports_quiet", "Quiet"), ("turbo", "supports_turbo", "Turbo"), ("xfan", "supports_xfan", "X-FAN"), ("air", "supports_air", "Air"), ("health", "supports_health", "Health"), ("sleep", "supports_sleep", "Sleep"), ] async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Create one enabled switch per controller zone.""" runtime: GreeControllerRuntimeData = entry.runtime_data entities: list[SwitchEntity] = [ GreeControllerHousePowerSwitch(runtime.coordinator), *[ GreeControllerZoneEnabledSwitch(runtime.coordinator, str(zone["zone_id"])) for zone in runtime.coordinator.plan.get("zones", []) if zone.get("zone_id") ], *[ GreeControllerGroupPowerSwitch(runtime.coordinator, group_id) for group_id in runtime.coordinator.groups ], ] for device_id, device in runtime.coordinator.data.items(): for field, support_field, name in DEVICE_FEATURE_SWITCHES: if device.get(support_field) is True: entities.append(GreeControllerDeviceFeatureSwitch(runtime.coordinator, device_id, field, support_field, name)) async_add_entities(entities) class GreeControllerHousePowerSwitch(CoordinatorEntity[GreeControllerCoordinator], SwitchEntity): """Master power action for all enabled indoor units.""" _attr_has_entity_name = True _attr_name = "All air conditioners" _attr_unique_id = "house-power-all" @property def is_on(self) -> bool: return bool(self.coordinator.plan.get("house_power", False)) @property def device_info(self) -> DeviceInfo: return DeviceInfo( identifiers={(DOMAIN, "controller")}, name="GREE Controller", manufacturer="GREE Controller", model="Local controller", ) async def async_turn_on(self, **kwargs: Any) -> None: await self.coordinator.client.house_power(True) await self.coordinator.async_request_refresh() async def async_turn_off(self, **kwargs: Any) -> None: await self.coordinator.client.house_power(False) await self.coordinator.async_request_refresh() class GreeControllerGroupPowerSwitch(CoordinatorEntity[GreeControllerCoordinator], SwitchEntity): """Enable or disable one controller climate group.""" _attr_has_entity_name = True _attr_name = "Power" 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-power" @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 is_on(self) -> bool: return bool(self._group.get("power_enabled", False)) @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]: return { "effective_power": bool(self._group.get("effective_power", False)), "zone_count": self._group.get("zone_count"), } async def async_turn_on(self, **kwargs: Any) -> None: await self.coordinator.client.group_control(self._group_id, {"power": True}) await self.coordinator.async_request_refresh() async def async_turn_off(self, **kwargs: Any) -> None: await self.coordinator.client.group_control(self._group_id, {"power": False}) await self.coordinator.async_request_refresh() class GreeControllerZoneEnabledSwitch(CoordinatorEntity[GreeControllerCoordinator], SwitchEntity): """Enable or disable a controller thermostat zone.""" _attr_has_entity_name = True _attr_name = "Enabled" def __init__(self, coordinator: GreeControllerCoordinator, zone_id: str) -> None: super().__init__(coordinator) self._zone_id = zone_id self._attr_unique_id = f"{zone_id}-enabled" @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 is_on(self) -> bool: return bool(self._zone.get("enabled", False)) @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"), ) async def async_turn_on(self, **kwargs: Any) -> None: await self.coordinator.client.zone_control(self._zone_id, {"enabled": True}) await self.coordinator.async_request_refresh() async def async_turn_off(self, **kwargs: Any) -> None: await self.coordinator.client.zone_control(self._zone_id, {"enabled": False}) await self.coordinator.async_request_refresh() class GreeControllerDeviceFeatureSwitch(CoordinatorEntity[GreeControllerCoordinator], SwitchEntity): """Optional GREE unit feature exposed only when the controller detected it.""" _attr_has_entity_name = True def __init__( self, coordinator: GreeControllerCoordinator, device_id: str, field: str, support_field: str, name: str, ) -> None: super().__init__(coordinator) self._device_id = device_id self._field = field self._support_field = support_field self._attr_name = name self._attr_unique_id = f"{device_id}-{field}" @property def _device(self) -> dict[str, Any]: return self.coordinator.data.get(self._device_id, {}) @property def available(self) -> bool: return ( super().available and bool(self._device.get("online", False)) and self._device.get(self._support_field) is True ) @property def is_on(self) -> bool: return bool(self._device.get(self._field, False)) @property def device_info(self) -> DeviceInfo: device = self._device return DeviceInfo( identifiers={(DOMAIN, self._device_id)}, name=str(device.get("name") or self._device_id), manufacturer="GREE", model=str(device.get("model") or "GREE HVAC"), sw_version=str(device.get("firmware") or "") or None, ) async def _set(self, value: bool) -> None: await self.coordinator.client.command(self._device_id, {self._field: value}) await self.coordinator.async_request_refresh() async def async_turn_on(self, **kwargs: Any) -> None: await self._set(True) async def async_turn_off(self, **kwargs: Any) -> None: await self._set(False)