Files

235 lines
8.0 KiB
Python

"""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:
devices = [device for device in self.coordinator.data.values() if device.get("enabled", True)]
return bool(devices) and all(bool(device.get("power")) for device in devices)
@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):
"""Power a controller climate group on or off."""
_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.async_zone_control(self._zone_id, {"enabled": True})
async def async_turn_off(self, **kwargs: Any) -> None:
await self.coordinator.async_zone_control(self._zone_id, {"enabled": False})
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.async_device_command(self._device_id, {self._field: value})
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)