Skip to content

Commit

Permalink
enable humidfier to control power and change humidifying function to …
Browse files Browse the repository at this point in the history
…mode
  • Loading branch information
kongo09 committed Nov 24, 2024
1 parent 6a5997c commit 8e8e7a9
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 35 deletions.
87 changes: 63 additions & 24 deletions custom_components/philips_airpurifier_coap/humidifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
HumidifierAction,
HumidifierDeviceClass,
HumidifierEntity,
HumidifierEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity

from .config_entry_data import ConfigEntryData
from .const import ATTR_ICON, DOMAIN, HUMIDIFIER_TYPES, FanAttributes
from .philips import PhilipsEntity, model_to_class
from .philips import PhilipsGenericControlBase, model_to_class

_LOGGER = logging.getLogger(__name__)

Expand All @@ -36,13 +37,21 @@ async def async_setup_entry(
model_class = model_to_class.get(model)
if model_class:
available_humidifiers = []
available_preset_modes = {}

for cls in reversed(model_class.__mro__):
# Get the available humidifiers from the base classes
cls_available_humidifiers = getattr(cls, "AVAILABLE_HUMIDIFIERS", [])
available_humidifiers.extend(cls_available_humidifiers)

# Get the available preset modes from the base classes
cls_available_preset_modes = getattr(cls, "AVAILABLE_PRESET_MODES", [])
available_preset_modes.update(cls_available_preset_modes)

humidifiers = [
PhilipsHumidifier(hass, entry, config_entry_data, humidifier)
PhilipsHumidifier(
hass, entry, config_entry_data, humidifier, available_preset_modes
)
for humidifier in HUMIDIFIER_TYPES
if humidifier in available_humidifiers
]
Expand All @@ -54,7 +63,7 @@ async def async_setup_entry(
return


class PhilipsHumidifier(PhilipsEntity, HumidifierEntity):
class PhilipsHumidifier(PhilipsGenericControlBase, HumidifierEntity):
"""Define a Philips AirPurifier humidifier."""

_attr_is_on: bool | None = False
Expand All @@ -65,6 +74,7 @@ def __init__(
config: ConfigEntry,
config_entry_data: ConfigEntryData,
humidifier: str,
available_preset_modes: list[str],
) -> None:
"""Initialize the select."""

Expand All @@ -80,9 +90,10 @@ def __init__(
f"{name} {self._description[FanAttributes.LABEL].replace('_', ' ').title()}"
)

model = config_entry_data.device_information.model
device_id = config_entry_data.device_information.device_id
self._attr_unique_id = f"{model}-{device_id}-{humidifier.lower()}"
self._attr_unique_id = f"{self._model}-{device_id}-{humidifier.lower()}"

self._available_preset_modes = available_preset_modes

self._power_key = self._description[FanAttributes.POWER]
self._function_key = self._description[FanAttributes.FUNCTION]
Expand All @@ -96,6 +107,11 @@ def __init__(
self._description[FanAttributes.HUMIDITY]
)

# not all humidifiers can set a mode
if self._switch:
self._attr_supported_features = HumidifierEntityFeature.MODES
self._attr_available_modes = {FanAttributes.IDLE, FanAttributes.HUMIDIFYING}

@property
def action(self) -> str:
"""Return the current action."""
Expand All @@ -117,46 +133,69 @@ def target_humidity(self) -> int | None:
"""Return the target humidity."""
return self._device_status.get(self._humidity_target_key)

@property
def mode(self) -> str | None:
"""Return the current mode."""

# not all humidifiers can set a mode
if not self._switch:
return None

function_status = self._device_status.get(self._function_key)
if function_status == self._description[FanAttributes.HUMIDIFYING]:
return FanAttributes.HUMIDIFYING

return FanAttributes.IDLE

async def async_set_mode(self, mode: str) -> None:
"""Set the mode of the humidifier."""
if mode not in self._attr_available_modes:
return

if mode == FanAttributes.IDLE:
function_value = self._description[FanAttributes.IDLE]
else:
function_value = self._description[FanAttributes.HUMIDIFYING]

await self.coordinator.client.set_control_values(
data={
self._power_key: self._description[FanAttributes.ON],
self._function_key: function_value,
}
)
self._device_status[self._power_key] = self._description[FanAttributes.ON]
self._device_status[self._function_key] = function_value
self._handle_coordinator_update()

@property
def is_on(self) -> bool | None:
"""Return the humidifying state. True if humidifying, False if off or fan mode."""
"""Return the device state independent of the humidifier function."""
if (
self._device_status.get(self._power_key)
== self._description[FanAttributes.OFF]
):
return False

if self.action == HumidifierAction.HUMIDIFYING:
return True

return False
return True

async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the humidifier and enable the humidifying function."""
if not self._switch:
return

"""Turn on the device."""
await self.coordinator.client.set_control_values(
data={
self._power_key: self._description[FanAttributes.ON],
self._function_key: self._description[FanAttributes.HUMIDIFYING],
}
)
self._device_status[self._power_key] = self._description[FanAttributes.ON]
self._device_status[self._function_key] = self._description[
FanAttributes.HUMIDIFYING
]
self._handle_coordinator_update()

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the humidifier function. This does not turn off the fan."""
if not self._switch:
return

"""Turn off the device."""
await self.coordinator.client.set_control_values(
data={self._function_key: self._description[FanAttributes.IDLE]}
data={
self._power_key: self._description[FanAttributes.OFF],
}
)
self._device_status[self._function_key] = self._description[FanAttributes.IDLE]
self._device_status[self._power_key] = self._description[FanAttributes.ON]
self._handle_coordinator_update()

async def async_set_humidity(self, humidity: str) -> None:
Expand Down
13 changes: 2 additions & 11 deletions custom_components/philips_airpurifier_coap/philips.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

import asyncio
from collections.abc import Callable
from collections.abc import Callable, Mapping
from datetime import timedelta
import logging
from typing import Any
Expand Down Expand Up @@ -154,7 +154,7 @@ def _collect_available_preset_modes(self):
self._preset_modes = list(self._available_preset_modes.keys())

@property
def extra_state_attributes(self) -> dict[str, Any] | None:
def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return the extra state attributes."""

def append(
Expand Down Expand Up @@ -425,9 +425,6 @@ def icon(self) -> str:
class PhilipsGenericFan(PhilipsGenericFanBase):
"""Class to manage a generic Philips fan."""

AVAILABLE_PRESET_MODES = {}
AVAILABLE_SPEEDS = {}

AVAILABLE_ATTRIBUTES = [
# device information
(FanAttributes.NAME, PhilipsApi.NAME),
Expand Down Expand Up @@ -463,9 +460,6 @@ class PhilipsGenericFan(PhilipsGenericFanBase):
class PhilipsNewGenericFan(PhilipsGenericFanBase):
"""Class to manage a new generic fan."""

AVAILABLE_PRESET_MODES = {}
AVAILABLE_SPEEDS = {}

AVAILABLE_ATTRIBUTES = [
# device information
(FanAttributes.NAME, PhilipsApi.NEW_NAME),
Expand Down Expand Up @@ -501,9 +495,6 @@ class PhilipsNewGenericFan(PhilipsGenericFanBase):
class PhilipsNew2GenericFan(PhilipsGenericFanBase):
"""Class to manage another new generic fan."""

AVAILABLE_PRESET_MODES = {}
AVAILABLE_SPEEDS = {}

AVAILABLE_ATTRIBUTES = [
# device information
(FanAttributes.NAME, PhilipsApi.NEW2_NAME),
Expand Down

0 comments on commit 8e8e7a9

Please sign in to comment.