From ce8a754b75105b0f9c77e2c2dc3658329a97bba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Tue, 15 Sep 2026 09:14:44 +0200 Subject: [PATCH] GREE Controller 0.14.2 --- custom_components/gree_controller/climate.py | 50 ++++++++++++++++--- .../gree_controller/manifest.json | 2 +- gree-controller/CHANGELOG.md | 9 ++++ gree-controller/config.yaml | 2 +- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/custom_components/gree_controller/climate.py b/custom_components/gree_controller/climate.py index 79f58a0..6c06b2a 100644 --- a/custom_components/gree_controller/climate.py +++ b/custom_components/gree_controller/climate.py @@ -266,12 +266,8 @@ class GreeControllerZoneClimate(CoordinatorEntity[GreeControllerCoordinator], Cl _attr_target_temperature_step = 0.5 _attr_hvac_modes = [HVACMode.OFF, HVACMode.AUTO, HVACMode.COOL, HVACMode.HEAT] _attr_preset_modes = ["auto", "comfort", "sleep", "away"] - _attr_supported_features = ( - ClimateEntityFeature.TARGET_TEMPERATURE - | ClimateEntityFeature.PRESET_MODE - | ClimateEntityFeature.TURN_ON - | ClimateEntityFeature.TURN_OFF - ) + _attr_swing_modes = [SWING_OFF, SWING_ON] + _attr_swing_horizontal_modes = [SWING_OFF, SWING_ON] def __init__(self, coordinator: GreeControllerCoordinator, zone_id: str) -> None: super().__init__(coordinator) @@ -285,10 +281,30 @@ class GreeControllerZoneClimate(CoordinatorEntity[GreeControllerCoordinator], Cl return zone return {} + @property + def _device(self) -> dict[str, Any]: + device_id = str(self._zone.get("device_id") or "").strip() + return self.coordinator.data.get(device_id, {}) if device_id else {} + @property def available(self) -> bool: return super().available and bool(self._zone) + @property + def supported_features(self) -> ClimateEntityFeature: + features = ( + ClimateEntityFeature.TARGET_TEMPERATURE + | ClimateEntityFeature.PRESET_MODE + | ClimateEntityFeature.TURN_ON + | ClimateEntityFeature.TURN_OFF + ) + capabilities = self._device.get("capabilities") or {} + if capabilities.get("vertical_swing", True) is not False: + features |= ClimateEntityFeature.SWING_MODE + if capabilities.get("horizontal_swing", True) is not False: + features |= ClimateEntityFeature.SWING_HORIZONTAL_MODE + return features + @property def device_info(self) -> DeviceInfo: zone = self._zone @@ -325,6 +341,14 @@ class GreeControllerZoneClimate(CoordinatorEntity[GreeControllerCoordinator], Cl def preset_mode(self) -> str: return str(self._zone.get("preset_override") or "auto") + @property + def swing_mode(self) -> str: + return SWING_ON if self._device.get("swing_vertical", False) else SWING_OFF + + @property + def swing_horizontal_mode(self) -> str: + return SWING_ON if self._device.get("swing_horizontal", False) else SWING_OFF + @property def extra_state_attributes(self) -> dict[str, Any]: zone = self._zone @@ -380,6 +404,20 @@ class GreeControllerZoneClimate(CoordinatorEntity[GreeControllerCoordinator], Cl return await self.coordinator.async_zone_control(self._zone_id, {"preset": preset_mode}) + async def async_set_swing_mode(self, swing_mode: str) -> None: + device_id = str(self._zone.get("device_id") or "").strip() + if device_id: + await self.coordinator.async_device_command( + device_id, {"swing_vertical": swing_mode == SWING_ON} + ) + + async def async_set_swing_horizontal_mode(self, swing_horizontal_mode: str) -> None: + device_id = str(self._zone.get("device_id") or "").strip() + if device_id: + await self.coordinator.async_device_command( + device_id, {"swing_horizontal": swing_horizontal_mode == SWING_ON} + ) + async def async_turn_on(self) -> None: await self.coordinator.async_zone_control(self._zone_id, {"power": True}) diff --git a/custom_components/gree_controller/manifest.json b/custom_components/gree_controller/manifest.json index 92b6c62..d87e256 100644 --- a/custom_components/gree_controller/manifest.json +++ b/custom_components/gree_controller/manifest.json @@ -1,7 +1,7 @@ { "domain": "gree_controller", "name": "GREE Controller", - "version": "0.14.1", + "version": "0.14.2", "config_flow": true, "integration_type": "hub", "iot_class": "local_polling", diff --git a/gree-controller/CHANGELOG.md b/gree-controller/CHANGELOG.md index 1af6db1..52396bd 100644 --- a/gree-controller/CHANGELOG.md +++ b/gree-controller/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.14.2 + +- Adds separate vertical and horizontal swing controls for local units in Manual Control, respecting per-device capabilities. +- Adds vertical and horizontal swing controls to thermostat zone cards without switching the zone into manual device ownership. +- Adds optional `swing_vertical` and `swing_horizontal` actions to legacy direct-device automations. +- Extends Visual Flow so both `device_action` and `zone_thermostat` can control vertical/horizontal swing, and device-state selectors use readable swing labels. +- Prevents swing-enabled thermostat Flows from being reduced to native schedules, preserving the auxiliary swing action at runtime. +- Exposes vertical and horizontal swing on Home Assistant zone thermostat climate entities when supported by the assigned unit. + ## 0.14.1 - Adds split and multisplit installation groups in the Devices section, including assignment of indoor units to a shared outdoor installation. diff --git a/gree-controller/config.yaml b/gree-controller/config.yaml index b527e7e..325367b 100644 --- a/gree-controller/config.yaml +++ b/gree-controller/config.yaml @@ -1,5 +1,5 @@ name: "GREE Controller" -version: "0.14.1" +version: "0.14.2" slug: "gree_controller" description: "Local GREE HVAC controller with Web UI and Home Assistant integration" url: "https://git.linuxiarz.pl/gru/gree-controller-ha-addon/"