Skip to content

Commit

Permalink
Move humidifier from climate to separate entity
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexxIT committed Jan 14, 2024
1 parent 8e7aed5 commit 51ceb94
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 219 deletions.
1 change: 1 addition & 0 deletions custom_components/yandex_station/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
SUB_DOMAINS = [
"climate",
"light",
"humidifier",
"number",
"remote",
"switch",
Expand Down
3 changes: 0 additions & 3 deletions custom_components/yandex_station/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
_LOGGER = logging.getLogger(__name__)

INCLUDE_TYPES = [
"devices.types.humidifier",
"devices.types.purifier",
"devices.types.thermostat",
"devices.types.thermostat.ac",
Expand Down Expand Up @@ -74,8 +73,6 @@ def internal_init(self, capabilities: dict, properties: dict):

if item := capabilities.get(self.hvac_instance):
self._attr_hvac_modes = [HVACMode(i["value"]) for i in item["modes"]]
elif self.device["type"] == "devices.types.humidifier":
self._attr_hvac_modes = [HVACMode.DRY]
elif self.device["type"] == "devices.types.purifier":
self._attr_hvac_modes = [HVACMode.FAN_ONLY]
elif "heat" in capabilities:
Expand Down
82 changes: 82 additions & 0 deletions custom_components/yandex_station/humidifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import logging

from homeassistant.components.humidifier import (
HumidifierEntity,
HumidifierEntityFeature,
)
from homeassistant.const import CONF_INCLUDE
from homeassistant.helpers.template import Template

from .core import utils
from .core.const import DATA_CONFIG, DOMAIN
from .core.entity import YandexEntity
from .core.yandex_quasar import YandexQuasar

_LOGGER = logging.getLogger(__name__)

INCLUDE_TYPES = ["devices.types.humidifier"]


async def async_setup_entry(hass, entry, async_add_entities):
include = hass.data[DOMAIN][DATA_CONFIG][CONF_INCLUDE]
quasar = hass.data[DOMAIN][entry.unique_id]
entities = [
YandexHumidifier(quasar, device, config)
for device in quasar.devices
if (config := utils.device_include(device, include, INCLUDE_TYPES))
]
async_add_entities(entities)


# noinspection PyAbstractClass
class YandexHumidifier(HumidifierEntity, YandexEntity):
humidity_template: Template = None
mode_instance: str = None

def __init__(self, quasar: YandexQuasar, device: dict, config: dict):
super().__init__(quasar, device)
self.config = config

def internal_init(self, capabilities: dict, properties: dict):
candidates = ["fan_speed", "work_speed"]

self.mode_instance = next((i for i in candidates if i in capabilities), None)

if item := capabilities.get("humidity"):
self._attr_min_humidity = item["range"]["min"]
self._attr_max_humidity = item["range"]["max"]

if item := capabilities.get(self.mode_instance):
self._attr_supported_features |= HumidifierEntityFeature.MODES
self._attr_available_modes = [i["value"] for i in item["modes"]]

def internal_update(self, capabilities: dict, properties: dict):
if "on" in capabilities:
self._attr_is_on = capabilities["on"]

if "humidity" in capabilities:
self._attr_target_humidity = capabilities["humidity"]

if self.mode_instance in capabilities:
self._attr_mode = capabilities[self.mode_instance]

if self.humidity_template:
self._attr_current_humidity = self.humidity_template.async_render()
elif "humidity" in properties:
self._attr_current_humidity = properties["humidity"]

async def async_added_to_hass(self):
if item := self.config.get("current_humidity"):
self.humidity_template = Template(item, self.hass)

async def async_set_humidity(self, humidity: int) -> None:
await self.quasar.device_action(self.device["id"], "humidity", humidity)

async def async_set_mode(self, mode: str) -> None:
await self.quasar.device_action(self.device["id"], self.mode_instance, mode)

async def async_turn_on(self, **kwargs):
await self.quasar.device_action(self.device["id"], "on", True)

async def async_turn_off(self, **kwargs):
await self.quasar.device_action(self.device["id"], "on", False)
216 changes: 0 additions & 216 deletions tests/test_climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,219 +748,3 @@ def test_purifier_xiaomi():
"min_temp": 7,
"supported_features": 0,
}


def test_humidifier_deerma():
device = {
"id": "xxx",
"name": "Увлажнитель",
"type": "devices.types.humidifier",
"icon_url": "https://avatars.mds.yandex.net/get-iot/icons-devices-devices.types.humidifier.svg/orig",
"capabilities": [
{
"retrievable": true,
"type": "devices.capabilities.on_off",
"state": {"instance": "on", "value": true},
"parameters": {"split": false},
},
{
"retrievable": true,
"type": "devices.capabilities.mode",
"state": {"instance": "fan_speed", "value": "high"},
"parameters": {
"instance": "fan_speed",
"name": "скорость вентиляции",
"modes": [
{"value": "low", "name": "Низкая"},
{"value": "medium", "name": "Средняя"},
{"value": "high", "name": "Высокая"},
],
},
},
],
"properties": [
{
"type": "devices.properties.float",
"retrievable": true,
"reportable": true,
"parameters": {
"instance": "humidity",
"name": "влажность",
"unit": "unit.percent",
},
"state": {"percent": 52, "status": "normal", "value": 52},
"state_changed_at": "2024-01-07T08:04:20Z",
"last_updated": "2024-01-07T08:05:35Z",
},
{
"type": "devices.properties.float",
"retrievable": true,
"reportable": true,
"parameters": {
"instance": "temperature",
"name": "температура",
"unit": "unit.temperature.celsius",
},
"state": {"percent": null, "status": null, "value": 21},
"state_changed_at": "2024-01-07T07:56:38Z",
"last_updated": "2024-01-07T08:05:35Z",
},
],
"item_type": "device",
"skill_id": "ad26f8c2-fc31-4928-a653-d829fda7e6c2",
"room_name": "Спальня",
"state": "online",
"created": "2024-01-07T07:47:34Z",
"parameters": {
"device_info": {
"manufacturer": "deerma",
"model": "deerma.humidifier.jsqs",
"sw_version": "2.1.3.0025",
}
},
}

state = update_ha_state(YandexClimate, device, config={})
assert state.state == "dry"
assert state.attributes == {
"current_humidity": 52,
"current_temperature": 21,
"fan_mode": "high",
"fan_modes": ["low", "medium", "high"],
"friendly_name": "Увлажнитель",
"hvac_modes": [HVACMode.DRY, HVACMode.OFF],
"max_temp": 35,
"min_temp": 7,
"supported_features": ClimateEntityFeature.FAN_MODE,
}


def test_humidifier_polaris():
# https://github.com/AlexxIT/YandexStation/pull/205
device = {
"id": "xxx",
"name": "Увлажнитель",
"type": "devices.types.humidifier",
"icon_url": "https://avatars.mds.yandex.net/get-iot/icons-devices-devices.types.humidifier.svg/orig",
"capabilities": [
{
"retrievable": true,
"type": "devices.capabilities.on_off",
"state": {"instance": "on", "value": true},
"parameters": {"split": false},
},
{
"retrievable": true,
"type": "devices.capabilities.range",
"state": {"instance": "humidity", "value": 40},
"parameters": {
"instance": "humidity",
"name": "влажность",
"unit": "unit.percent",
"random_access": true,
"looped": false,
"range": {"min": 30, "max": 75, "precision": 5},
},
},
{
"retrievable": true,
"type": "devices.capabilities.mode",
"state": {"instance": "work_speed", "value": "auto"},
"parameters": {
"instance": "work_speed",
"name": "скорость работы",
"modes": [
{"value": "auto", "name": "Авто"},
{"value": "low", "name": "Низкая"},
{"value": "medium", "name": "Средняя"},
{"value": "high", "name": "Высокая"},
{"value": "turbo", "name": "Турбо"},
],
},
},
{
"retrievable": true,
"type": "devices.capabilities.toggle",
"state": {"instance": "mute", "value": false},
"parameters": {"instance": "mute", "name": "без звука"},
},
{
"retrievable": true,
"type": "devices.capabilities.toggle",
"state": {"instance": "controls_locked", "value": false},
"parameters": {
"instance": "controls_locked",
"name": "блокировка управления",
},
},
{
"retrievable": true,
"type": "devices.capabilities.toggle",
"state": {"instance": "ionization", "value": false},
"parameters": {"instance": "ionization", "name": "ионизация"},
},
{
"retrievable": true,
"type": "devices.capabilities.toggle",
"state": {"instance": "backlight", "value": false},
"parameters": {"instance": "backlight", "name": "подсветка"},
},
],
"properties": [
{
"type": "devices.properties.float",
"retrievable": true,
"reportable": true,
"parameters": {
"instance": "temperature",
"name": "температура",
"unit": "unit.temperature.celsius",
},
"state": {"percent": null, "status": null, "value": 0},
"last_updated": "2024-01-11T13:58:58Z",
},
{
"type": "devices.properties.float",
"retrievable": true,
"reportable": true,
"parameters": {
"instance": "humidity",
"name": "влажность",
"unit": "unit.percent",
},
"state": {"percent": 0, "status": "danger", "value": 0},
"last_updated": "2024-01-11T13:58:58Z",
},
],
"item_type": "device",
"room_name": "Дача",
"state": "online",
"created": "2024-01-11T13:58:58Z",
"parameters": {
"device_info": {
"manufacturer": "polaris",
"model": "PUH-9105",
"hw_version": "",
"sw_version": "",
}
},
}

state = update_ha_state(YandexClimate, device, config={})
assert state.state == "dry"
assert state.attributes == {
"current_humidity": 0,
"current_temperature": 0,
"friendly_name": "Увлажнитель",
"humidity": 40,
"hvac_modes": [HVACMode.DRY, HVACMode.OFF],
"max_humidity": 75,
"max_temp": 35,
"min_humidity": 30,
"min_temp": 7,
"preset_mode": "auto",
"preset_modes": ["auto", "low", "medium", "high", "turbo"],
"supported_features": (
ClimateEntityFeature.TARGET_HUMIDITY | ClimateEntityFeature.PRESET_MODE
),
}
Loading

0 comments on commit 51ceb94

Please sign in to comment.