Add support for Xiaomi Miio pedestal fans (#55114)
Co-authored-by: Teemu R. <tpr@iki.fi>pull/55222/head
parent
b167e05a56
commit
b97d131fb3
|
@ -585,7 +585,7 @@ homeassistant/components/worldclock/* @fabaff
|
|||
homeassistant/components/xbox/* @hunterjm
|
||||
homeassistant/components/xbox_live/* @MartinHjelmare
|
||||
homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi
|
||||
homeassistant/components/xiaomi_miio/* @rytilahti @syssi @starkillerOG
|
||||
homeassistant/components/xiaomi_miio/* @rytilahti @syssi @starkillerOG @bieniu
|
||||
homeassistant/components/xiaomi_tv/* @simse
|
||||
homeassistant/components/xmpp/* @fabaff @flowolf
|
||||
homeassistant/components/yale_smart_alarm/* @gjohansson-ST
|
||||
|
|
|
@ -11,6 +11,8 @@ from miio import (
|
|||
AirPurifier,
|
||||
AirPurifierMiot,
|
||||
DeviceException,
|
||||
Fan,
|
||||
FanP5,
|
||||
)
|
||||
from miio.gateway.gateway import GatewayException
|
||||
|
||||
|
@ -29,8 +31,10 @@ from .const import (
|
|||
DOMAIN,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_FAN_P5,
|
||||
MODELS_AIR_MONITOR,
|
||||
MODELS_FAN,
|
||||
MODELS_FAN_MIIO,
|
||||
MODELS_HUMIDIFIER,
|
||||
MODELS_HUMIDIFIER_MIIO,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
|
@ -141,6 +145,11 @@ async def async_create_miio_device_and_coordinator(
|
|||
device = AirPurifier(host, token)
|
||||
elif model.startswith("zhimi.airfresh."):
|
||||
device = AirFresh(host, token)
|
||||
# Pedestal fans
|
||||
elif model == MODEL_FAN_P5:
|
||||
device = FanP5(host, token)
|
||||
elif model in MODELS_FAN_MIIO:
|
||||
device = Fan(host, token, model=model)
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Unsupported device found! Please create an issue at "
|
||||
|
|
|
@ -58,6 +58,24 @@ MODEL_AIRHUMIDIFIER_MJJSQ = "deerma.humidifier.mjjsq"
|
|||
|
||||
MODEL_AIRFRESH_VA2 = "zhimi.airfresh.va2"
|
||||
|
||||
MODEL_FAN_P5 = "dmaker.fan.p5"
|
||||
MODEL_FAN_SA1 = "zhimi.fan.sa1"
|
||||
MODEL_FAN_V2 = "zhimi.fan.v2"
|
||||
MODEL_FAN_V3 = "zhimi.fan.v3"
|
||||
MODEL_FAN_ZA1 = "zhimi.fan.za1"
|
||||
MODEL_FAN_ZA3 = "zhimi.fan.za3"
|
||||
MODEL_FAN_ZA4 = "zhimi.fan.za4"
|
||||
|
||||
MODELS_FAN_MIIO = [
|
||||
MODEL_FAN_P5,
|
||||
MODEL_FAN_SA1,
|
||||
MODEL_FAN_V2,
|
||||
MODEL_FAN_V3,
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
]
|
||||
|
||||
MODELS_PURIFIER_MIOT = [
|
||||
MODEL_AIRPURIFIER_3,
|
||||
MODEL_AIRPURIFIER_3H,
|
||||
|
@ -124,7 +142,7 @@ MODELS_SWITCH = [
|
|||
"chuangmi.plug.hmi205",
|
||||
"chuangmi.plug.hmi206",
|
||||
]
|
||||
MODELS_FAN = MODELS_PURIFIER_MIIO + MODELS_PURIFIER_MIOT
|
||||
MODELS_FAN = MODELS_PURIFIER_MIIO + MODELS_PURIFIER_MIOT + MODELS_FAN_MIIO
|
||||
MODELS_HUMIDIFIER = (
|
||||
MODELS_HUMIDIFIER_MIOT + MODELS_HUMIDIFIER_MIIO + MODELS_HUMIDIFIER_MJJSQ
|
||||
)
|
||||
|
@ -208,6 +226,9 @@ FEATURE_SET_DRY = 2048
|
|||
FEATURE_SET_FAN_LEVEL = 4096
|
||||
FEATURE_SET_MOTOR_SPEED = 8192
|
||||
FEATURE_SET_CLEAN = 16384
|
||||
FEATURE_SET_OSCILLATION_ANGLE = 32768
|
||||
FEATURE_SET_OSCILLATION_ANGLE_MAX_140 = 65536
|
||||
FEATURE_SET_DELAY_OFF_COUNTDOWN = 131072
|
||||
|
||||
FEATURE_FLAGS_AIRPURIFIER_MIIO = (
|
||||
FEATURE_SET_BUZZER
|
||||
|
@ -281,3 +302,19 @@ FEATURE_FLAGS_AIRFRESH = (
|
|||
| FEATURE_RESET_FILTER
|
||||
| FEATURE_SET_EXTRA_FEATURES
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_FAN_P5 = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
| FEATURE_SET_OSCILLATION_ANGLE_MAX_140
|
||||
| FEATURE_SET_LED
|
||||
| FEATURE_SET_DELAY_OFF_COUNTDOWN
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_FAN = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
| FEATURE_SET_OSCILLATION_ANGLE
|
||||
| FEATURE_SET_LED_BRIGHTNESS
|
||||
| FEATURE_SET_DELAY_OFF_COUNTDOWN
|
||||
)
|
||||
|
|
|
@ -7,9 +7,15 @@ import math
|
|||
from miio.airfresh import OperationMode as AirfreshOperationMode
|
||||
from miio.airpurifier import OperationMode as AirpurifierOperationMode
|
||||
from miio.airpurifier_miot import OperationMode as AirpurifierMiotOperationMode
|
||||
from miio.fan import (
|
||||
MoveDirection as FanMoveDirection,
|
||||
OperationMode as FanOperationMode,
|
||||
)
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
SUPPORT_DIRECTION,
|
||||
SUPPORT_OSCILLATE,
|
||||
SUPPORT_PRESET_MODE,
|
||||
SUPPORT_SET_SPEED,
|
||||
FanEntity,
|
||||
|
@ -33,6 +39,8 @@ from .const import (
|
|||
FEATURE_FLAGS_AIRPURIFIER_PRO,
|
||||
FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
|
||||
FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
FEATURE_FLAGS_FAN,
|
||||
FEATURE_FLAGS_FAN_P5,
|
||||
FEATURE_RESET_FILTER,
|
||||
FEATURE_SET_EXTRA_FEATURES,
|
||||
KEY_COORDINATOR,
|
||||
|
@ -42,6 +50,8 @@ from .const import (
|
|||
MODEL_AIRPURIFIER_PRO,
|
||||
MODEL_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V3,
|
||||
MODEL_FAN_P5,
|
||||
MODELS_FAN_MIIO,
|
||||
MODELS_PURIFIER_MIOT,
|
||||
SERVICE_RESET_FILTER,
|
||||
SERVICE_SET_EXTRA_FEATURES,
|
||||
|
@ -57,6 +67,9 @@ CONF_MODEL = "model"
|
|||
|
||||
ATTR_MODEL = "model"
|
||||
|
||||
ATTR_MODE_NATURE = "Nature"
|
||||
ATTR_MODE_NORMAL = "Normal"
|
||||
|
||||
# Air Purifier
|
||||
ATTR_BRIGHTNESS = "brightness"
|
||||
ATTR_FAN_LEVEL = "fan_level"
|
||||
|
@ -159,6 +172,11 @@ SERVICE_TO_METHOD = {
|
|||
},
|
||||
}
|
||||
|
||||
FAN_DIRECTIONS_MAP = {
|
||||
"forward": "right",
|
||||
"reverse": "left",
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the Fan from a config entry."""
|
||||
|
@ -187,6 +205,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
entity = XiaomiAirPurifier(name, device, config_entry, unique_id, coordinator)
|
||||
elif model.startswith("zhimi.airfresh."):
|
||||
entity = XiaomiAirFresh(name, device, config_entry, unique_id, coordinator)
|
||||
elif model == MODEL_FAN_P5:
|
||||
entity = XiaomiFanP5(name, device, config_entry, unique_id, coordinator)
|
||||
elif model in MODELS_FAN_MIIO:
|
||||
entity = XiaomiFan(name, device, config_entry, unique_id, coordinator)
|
||||
else:
|
||||
return
|
||||
|
||||
|
@ -669,3 +691,184 @@ class XiaomiAirFresh(XiaomiGenericDevice):
|
|||
"Resetting the filter lifetime of the miio device failed.",
|
||||
self._device.reset_filter,
|
||||
)
|
||||
|
||||
|
||||
class XiaomiFan(XiaomiGenericDevice):
|
||||
"""Representation of a Xiaomi Fan."""
|
||||
|
||||
def __init__(self, name, device, entry, unique_id, coordinator):
|
||||
"""Initialize the plug switch."""
|
||||
super().__init__(name, device, entry, unique_id, coordinator)
|
||||
|
||||
if self._model == MODEL_FAN_P5:
|
||||
self._device_features = FEATURE_FLAGS_FAN_P5
|
||||
self._preset_modes = [mode.name for mode in FanOperationMode]
|
||||
else:
|
||||
self._device_features = FEATURE_FLAGS_FAN
|
||||
self._preset_modes = [ATTR_MODE_NATURE, ATTR_MODE_NORMAL]
|
||||
self._nature_mode = False
|
||||
self._supported_features = (
|
||||
SUPPORT_SET_SPEED
|
||||
| SUPPORT_OSCILLATE
|
||||
| SUPPORT_PRESET_MODE
|
||||
| SUPPORT_DIRECTION
|
||||
)
|
||||
self._preset_mode = None
|
||||
self._oscillating = None
|
||||
self._percentage = None
|
||||
|
||||
@property
|
||||
def preset_mode(self):
|
||||
"""Get the active preset mode."""
|
||||
return ATTR_MODE_NATURE if self._nature_mode else ATTR_MODE_NORMAL
|
||||
|
||||
@property
|
||||
def percentage(self):
|
||||
"""Return the current speed as a percentage."""
|
||||
return self._percentage
|
||||
|
||||
@property
|
||||
def oscillating(self):
|
||||
"""Return whether or not the fan is currently oscillating."""
|
||||
return self._oscillating
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self):
|
||||
"""Fetch state from the device."""
|
||||
self._available = True
|
||||
self._state = self.coordinator.data.is_on
|
||||
self._oscillating = self.coordinator.data.oscillate
|
||||
self._nature_mode = self.coordinator.data.natural_speed != 0
|
||||
if self.coordinator.data.is_on:
|
||||
if self._nature_mode:
|
||||
self._percentage = self.coordinator.data.natural_speed
|
||||
else:
|
||||
self._percentage = self.coordinator.data.direct_speed
|
||||
else:
|
||||
self._percentage = 0
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode of the fan."""
|
||||
if preset_mode not in self.preset_modes:
|
||||
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
|
||||
return
|
||||
|
||||
if preset_mode == ATTR_MODE_NATURE:
|
||||
await self._try_command(
|
||||
"Setting natural fan speed percentage of the miio device failed.",
|
||||
self._device.set_natural_speed,
|
||||
self._percentage,
|
||||
)
|
||||
else:
|
||||
await self._try_command(
|
||||
"Setting direct fan speed percentage of the miio device failed.",
|
||||
self._device.set_direct_speed,
|
||||
self._percentage,
|
||||
)
|
||||
|
||||
self._preset_mode = preset_mode
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the percentage of the fan."""
|
||||
if percentage == 0:
|
||||
self._percentage = 0
|
||||
await self.async_turn_off()
|
||||
return
|
||||
|
||||
if self._nature_mode:
|
||||
await self._try_command(
|
||||
"Setting fan speed percentage of the miio device failed.",
|
||||
self._device.set_natural_speed,
|
||||
percentage,
|
||||
)
|
||||
else:
|
||||
await self._try_command(
|
||||
"Setting fan speed percentage of the miio device failed.",
|
||||
self._device.set_direct_speed,
|
||||
percentage,
|
||||
)
|
||||
self._percentage = percentage
|
||||
|
||||
if not self.is_on:
|
||||
await self.async_turn_on()
|
||||
else:
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_oscillate(self, oscillating: bool) -> None:
|
||||
"""Set oscillation."""
|
||||
await self._try_command(
|
||||
"Setting oscillate on/off of the miio device failed.",
|
||||
self._device.set_oscillate,
|
||||
oscillating,
|
||||
)
|
||||
self._oscillating = oscillating
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_direction(self, direction: str) -> None:
|
||||
"""Set the direction of the fan."""
|
||||
if self._oscillating:
|
||||
await self.async_oscillate(oscillating=False)
|
||||
|
||||
await self._try_command(
|
||||
"Setting move direction of the miio device failed.",
|
||||
self._device.set_rotate,
|
||||
FanMoveDirection(FAN_DIRECTIONS_MAP[direction]),
|
||||
)
|
||||
|
||||
|
||||
class XiaomiFanP5(XiaomiFan):
|
||||
"""Representation of a Xiaomi Fan P5."""
|
||||
|
||||
@property
|
||||
def preset_mode(self):
|
||||
"""Get the active preset mode."""
|
||||
return self._preset_mode
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self):
|
||||
"""Fetch state from the device."""
|
||||
self._available = True
|
||||
self._state = self.coordinator.data.is_on
|
||||
self._preset_mode = self.coordinator.data.mode.name
|
||||
self._oscillating = self.coordinator.data.oscillate
|
||||
if self.coordinator.data.is_on:
|
||||
self._percentage = self.coordinator.data.speed
|
||||
else:
|
||||
self._percentage = 0
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode of the fan."""
|
||||
if preset_mode not in self.preset_modes:
|
||||
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
|
||||
return
|
||||
await self._try_command(
|
||||
"Setting operation mode of the miio device failed.",
|
||||
self._device.set_mode,
|
||||
FanOperationMode[preset_mode],
|
||||
)
|
||||
self._preset_mode = preset_mode
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the percentage of the fan."""
|
||||
if percentage == 0:
|
||||
self._percentage = 0
|
||||
await self.async_turn_off()
|
||||
return
|
||||
|
||||
await self._try_command(
|
||||
"Setting fan speed percentage of the miio device failed.",
|
||||
self._device.set_speed,
|
||||
percentage,
|
||||
)
|
||||
self._percentage = percentage
|
||||
|
||||
if not self.is_on:
|
||||
await self.async_turn_on()
|
||||
else:
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/xiaomi_miio",
|
||||
"requirements": ["construct==2.10.56", "micloud==0.3", "python-miio==0.5.7"],
|
||||
"codeowners": ["@rytilahti", "@syssi", "@starkillerOG"],
|
||||
"codeowners": ["@rytilahti", "@syssi", "@starkillerOG", "@bieniu"],
|
||||
"zeroconf": ["_miio._udp.local."],
|
||||
"iot_class": "local_polling"
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ from dataclasses import dataclass
|
|||
from enum import Enum
|
||||
|
||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||
from homeassistant.const import DEGREE, TIME_MINUTES
|
||||
from homeassistant.core import callback
|
||||
|
||||
from .const import (
|
||||
|
@ -22,9 +23,14 @@ from .const import (
|
|||
FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
|
||||
FEATURE_FLAGS_AIRPURIFIER_V1,
|
||||
FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
FEATURE_FLAGS_FAN,
|
||||
FEATURE_FLAGS_FAN_P5,
|
||||
FEATURE_SET_DELAY_OFF_COUNTDOWN,
|
||||
FEATURE_SET_FAN_LEVEL,
|
||||
FEATURE_SET_FAVORITE_LEVEL,
|
||||
FEATURE_SET_MOTOR_SPEED,
|
||||
FEATURE_SET_OSCILLATION_ANGLE,
|
||||
FEATURE_SET_OSCILLATION_ANGLE_MAX_140,
|
||||
FEATURE_SET_VOLUME,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
|
@ -37,14 +43,23 @@ from .const import (
|
|||
MODEL_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V3,
|
||||
MODEL_FAN_P5,
|
||||
MODEL_FAN_SA1,
|
||||
MODEL_FAN_V2,
|
||||
MODEL_FAN_V3,
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODELS_PURIFIER_MIIO,
|
||||
MODELS_PURIFIER_MIOT,
|
||||
)
|
||||
from .device import XiaomiCoordinatedMiioEntity
|
||||
|
||||
ATTR_DELAY_OFF_COUNTDOWN = "delay_off_countdown"
|
||||
ATTR_FAN_LEVEL = "fan_level"
|
||||
ATTR_FAVORITE_LEVEL = "favorite_level"
|
||||
ATTR_MOTOR_SPEED = "motor_speed"
|
||||
ATTR_OSCILLATION_ANGLE = "angle"
|
||||
ATTR_VOLUME = "volume"
|
||||
|
||||
|
||||
|
@ -98,9 +113,40 @@ NUMBER_TYPES = {
|
|||
step=1,
|
||||
method="async_set_volume",
|
||||
),
|
||||
FEATURE_SET_OSCILLATION_ANGLE: XiaomiMiioNumberDescription(
|
||||
key=ATTR_OSCILLATION_ANGLE,
|
||||
name="Oscillation Angle",
|
||||
icon="mdi:angle-acute",
|
||||
unit_of_measurement=DEGREE,
|
||||
min_value=1,
|
||||
max_value=120,
|
||||
step=1,
|
||||
method="async_set_oscillation_angle",
|
||||
),
|
||||
FEATURE_SET_OSCILLATION_ANGLE_MAX_140: XiaomiMiioNumberDescription(
|
||||
key=ATTR_OSCILLATION_ANGLE,
|
||||
name="Oscillation Angle",
|
||||
icon="mdi:angle-acute",
|
||||
unit_of_measurement=DEGREE,
|
||||
min_value=30,
|
||||
max_value=140,
|
||||
step=30,
|
||||
method="async_set_oscillation_angle",
|
||||
),
|
||||
FEATURE_SET_DELAY_OFF_COUNTDOWN: XiaomiMiioNumberDescription(
|
||||
key=ATTR_DELAY_OFF_COUNTDOWN,
|
||||
name="Delay Off Countdown",
|
||||
icon="mdi:fan-off",
|
||||
unit_of_measurement=TIME_MINUTES,
|
||||
min_value=0,
|
||||
max_value=480,
|
||||
step=1,
|
||||
method="async_set_delay_off_countdown",
|
||||
),
|
||||
}
|
||||
|
||||
MODEL_TO_FEATURES_MAP = {
|
||||
MODEL_AIRFRESH_VA2: FEATURE_FLAGS_AIRFRESH,
|
||||
MODEL_AIRHUMIDIFIER_CA1: FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB,
|
||||
MODEL_AIRHUMIDIFIER_CA4: FEATURE_FLAGS_AIRHUMIDIFIER_CA4,
|
||||
MODEL_AIRHUMIDIFIER_CB1: FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB,
|
||||
|
@ -109,7 +155,13 @@ MODEL_TO_FEATURES_MAP = {
|
|||
MODEL_AIRPURIFIER_PRO_V7: FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V1: FEATURE_FLAGS_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V3: FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
MODEL_AIRFRESH_VA2: FEATURE_FLAGS_AIRFRESH,
|
||||
MODEL_FAN_P5: FEATURE_FLAGS_FAN_P5,
|
||||
MODEL_FAN_SA1: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_V2: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_V3: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA1: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA3: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA4: FEATURE_FLAGS_FAN,
|
||||
}
|
||||
|
||||
|
||||
|
@ -227,3 +279,17 @@ class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
|
|||
self._device.set_volume,
|
||||
volume,
|
||||
)
|
||||
|
||||
async def async_set_oscillation_angle(self, angle: int):
|
||||
"""Set the volume."""
|
||||
return await self._try_command(
|
||||
"Setting angle of the miio device failed.", self._device.set_angle, angle
|
||||
)
|
||||
|
||||
async def async_set_delay_off_countdown(self, delay_off_countdown: int):
|
||||
"""Set the delay off countdown."""
|
||||
return await self._try_command(
|
||||
"Setting delay off miio device failed.",
|
||||
self._device.delay_off,
|
||||
delay_off_countdown * 60,
|
||||
)
|
||||
|
|
|
@ -9,6 +9,7 @@ from miio.airhumidifier import LedBrightness as AirhumidifierLedBrightness
|
|||
from miio.airhumidifier_miot import LedBrightness as AirhumidifierMiotLedBrightness
|
||||
from miio.airpurifier import LedBrightness as AirpurifierLedBrightness
|
||||
from miio.airpurifier_miot import LedBrightness as AirpurifierMiotLedBrightness
|
||||
from miio.fan import LedBrightness as FanLedBrightness
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.core import callback
|
||||
|
@ -24,6 +25,12 @@ from .const import (
|
|||
MODEL_AIRFRESH_VA2,
|
||||
MODEL_AIRPURIFIER_M1,
|
||||
MODEL_AIRPURIFIER_M2,
|
||||
MODEL_FAN_SA1,
|
||||
MODEL_FAN_V2,
|
||||
MODEL_FAN_V3,
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODELS_HUMIDIFIER_MIIO,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
MODELS_PURIFIER_MIOT,
|
||||
|
@ -78,6 +85,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
entity_class = XiaomiAirPurifierMiotSelector
|
||||
elif model == MODEL_AIRFRESH_VA2:
|
||||
entity_class = XiaomiAirFreshSelector
|
||||
elif model in (
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODEL_FAN_SA1,
|
||||
MODEL_FAN_V2,
|
||||
MODEL_FAN_V3,
|
||||
):
|
||||
entity_class = XiaomiFanSelector
|
||||
else:
|
||||
return
|
||||
|
||||
|
@ -210,6 +226,20 @@ class XiaomiAirPurifierMiotSelector(XiaomiAirHumidifierSelector):
|
|||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class XiaomiFanSelector(XiaomiAirHumidifierSelector):
|
||||
"""Representation of a Xiaomi Fan (MIIO protocol) selector."""
|
||||
|
||||
async def async_set_led_brightness(self, brightness: str) -> None:
|
||||
"""Set the led brightness."""
|
||||
if await self._try_command(
|
||||
"Setting the led brightness of the miio device failed.",
|
||||
self._device.set_led_brightness,
|
||||
FanLedBrightness(LED_BRIGHTNESS_MAP[brightness]),
|
||||
):
|
||||
self._current_led_brightness = LED_BRIGHTNESS_MAP[brightness]
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class XiaomiAirFreshSelector(XiaomiAirHumidifierSelector):
|
||||
"""Representation of a Xiaomi Air Fresh selector."""
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ from homeassistant.const import (
|
|||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_HOST,
|
||||
CONF_TOKEN,
|
||||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_CO2,
|
||||
DEVICE_CLASS_GAS,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
|
@ -59,6 +60,12 @@ from .const import (
|
|||
MODEL_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V2,
|
||||
MODEL_AIRPURIFIER_V3,
|
||||
MODEL_FAN_P5,
|
||||
MODEL_FAN_V2,
|
||||
MODEL_FAN_V3,
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODELS_HUMIDIFIER_MIIO,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
|
@ -76,6 +83,7 @@ UNIT_LUMEN = "lm"
|
|||
ATTR_ACTUAL_SPEED = "actual_speed"
|
||||
ATTR_AIR_QUALITY = "air_quality"
|
||||
ATTR_AQI = "aqi"
|
||||
ATTR_BATTERY = "battery"
|
||||
ATTR_CARBON_DIOXIDE = "co2"
|
||||
ATTR_CHARGING = "charging"
|
||||
ATTR_DISPLAY_CLOCK = "display_clock"
|
||||
|
@ -219,6 +227,13 @@ SENSOR_TYPES = {
|
|||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ATTR_BATTERY: XiaomiMiioSensorDescription(
|
||||
key=ATTR_BATTERY,
|
||||
name="Battery",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=DEVICE_CLASS_BATTERY,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
HUMIDIFIER_MIIO_SENSORS = (ATTR_HUMIDITY, ATTR_TEMPERATURE, ATTR_WATER_LEVEL)
|
||||
|
@ -301,15 +316,22 @@ AIRFRESH_SENSORS = (
|
|||
ATTR_PM25,
|
||||
ATTR_TEMPERATURE,
|
||||
)
|
||||
FAN_V2_V3_SENSORS = (
|
||||
ATTR_BATTERY,
|
||||
ATTR_HUMIDITY,
|
||||
ATTR_TEMPERATURE,
|
||||
)
|
||||
|
||||
MODEL_TO_SENSORS_MAP = {
|
||||
MODEL_AIRFRESH_VA2: AIRFRESH_SENSORS,
|
||||
MODEL_AIRHUMIDIFIER_CA1: HUMIDIFIER_CA1_CB1_SENSORS,
|
||||
MODEL_AIRHUMIDIFIER_CB1: HUMIDIFIER_CA1_CB1_SENSORS,
|
||||
MODEL_AIRPURIFIER_PRO: PURIFIER_PRO_SENSORS,
|
||||
MODEL_AIRPURIFIER_PRO_V7: PURIFIER_PRO_V7_SENSORS,
|
||||
MODEL_AIRPURIFIER_V2: PURIFIER_V2_SENSORS,
|
||||
MODEL_AIRPURIFIER_V3: PURIFIER_V3_SENSORS,
|
||||
MODEL_AIRPURIFIER_PRO_V7: PURIFIER_PRO_V7_SENSORS,
|
||||
MODEL_AIRPURIFIER_PRO: PURIFIER_PRO_SENSORS,
|
||||
MODEL_AIRFRESH_VA2: AIRFRESH_SENSORS,
|
||||
MODEL_FAN_V2: FAN_V2_V3_SENSORS,
|
||||
MODEL_FAN_V3: FAN_V2_V3_SENSORS,
|
||||
}
|
||||
|
||||
|
||||
|
@ -351,6 +373,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
model = config_entry.data[CONF_MODEL]
|
||||
device = hass.data[DOMAIN][config_entry.entry_id].get(KEY_DEVICE)
|
||||
sensors = []
|
||||
if model in (MODEL_FAN_ZA1, MODEL_FAN_ZA3, MODEL_FAN_ZA4, MODEL_FAN_P5):
|
||||
return
|
||||
if model in MODEL_TO_SENSORS_MAP:
|
||||
sensors = MODEL_TO_SENSORS_MAP[model]
|
||||
elif model in MODELS_HUMIDIFIER_MIOT:
|
||||
|
|
|
@ -44,6 +44,8 @@ from .const import (
|
|||
FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
|
||||
FEATURE_FLAGS_AIRPURIFIER_V1,
|
||||
FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
FEATURE_FLAGS_FAN,
|
||||
FEATURE_FLAGS_FAN_P5,
|
||||
FEATURE_SET_AUTO_DETECT,
|
||||
FEATURE_SET_BUZZER,
|
||||
FEATURE_SET_CHILD_LOCK,
|
||||
|
@ -63,6 +65,10 @@ from .const import (
|
|||
MODEL_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V3,
|
||||
MODEL_FAN_P5,
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODELS_FAN,
|
||||
MODELS_HUMIDIFIER,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
|
@ -156,6 +162,10 @@ MODEL_TO_FEATURES_MAP = {
|
|||
MODEL_AIRPURIFIER_PRO_V7: FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V1: FEATURE_FLAGS_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V3: FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
MODEL_FAN_P5: FEATURE_FLAGS_FAN_P5,
|
||||
MODEL_FAN_ZA1: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA3: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA4: FEATURE_FLAGS_FAN,
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue