This commit is contained in:
Mateusz Gruszczyński
2026-08-25 19:44:12 +02:00
parent 62d071c972
commit 0d65a6a946
15 changed files with 464 additions and 38 deletions
@@ -1,4 +1,4 @@
"""Automation-plan sensors exposed by GREE Controller."""
"""House, zone and climate-group plan sensors exposed by GREE Controller."""
from __future__ import annotations
@@ -27,6 +27,8 @@ async def async_setup_entry(
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)
@@ -55,6 +57,7 @@ class GreeControllerHousePlanSensor(CoordinatorEntity[GreeControllerCoordinator]
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"),
@@ -63,6 +66,9 @@ class GreeControllerHousePlanSensor(CoordinatorEntity[GreeControllerCoordinator]
"master_power": bool(plan.get("house_power", False)),
"enabled_zones": sum(bool(zone.get("enabled")) for zone in zones),
"demanding_zones": sum(bool(zone.get("enabled")) and 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", []),
}
@@ -126,3 +132,69 @@ class GreeControllerZonePlanSensor(CoordinatorEntity[GreeControllerCoordinator],
"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 not group.get("effective_power", False):
return "master_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", []),
}