mirror of
https://github.com/micahqcade/custom_vesync.git
synced 2025-02-11 17:49:00 +01:00
Fix/fix fan discovery (#21)
* added LAP-C601S-WUS (Core 600s Air Purifier) * fix style * better fix to diagnostic. * fix preset mode * add a log line. * add another debug log * add some missing fan devices. * auto discover preset_modes * auto discover fan speed range * fix fan speed and preset modes * fix fan speed number * add some debug log. * merge fix from main * rename a key in diagnostics.
This commit is contained in:
parent
a87ff4cf29
commit
0afbef7f11
@ -41,8 +41,10 @@ def _setup_entities(devices, async_add_entities):
|
|||||||
entities = []
|
entities = []
|
||||||
for dev in devices:
|
for dev in devices:
|
||||||
if is_humidifier(dev.device_type):
|
if is_humidifier(dev.device_type):
|
||||||
entities.append(VeSyncOutOfWaterSensor(dev))
|
entities.extend(
|
||||||
entities.append(VeSyncWaterTankLiftedSensor(dev))
|
(VeSyncOutOfWaterSensor(dev), VeSyncWaterTankLiftedSensor(dev))
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"%s - Unknown device type - %s", dev.device_name, dev.device_type
|
"%s - Unknown device type - %s", dev.device_name, dev.device_type
|
||||||
|
@ -23,6 +23,11 @@ def is_humidifier(device_type: str) -> bool:
|
|||||||
return model_features(device_type)["module"].find("VeSyncHumid") > -1
|
return model_features(device_type)["module"].find("VeSyncHumid") > -1
|
||||||
|
|
||||||
|
|
||||||
|
def is_air_purifier(device_type: str) -> bool:
|
||||||
|
"""Return true if the device type is a an air purifier."""
|
||||||
|
return model_features(device_type)["module"].find("VeSyncAirBypass") > -1
|
||||||
|
|
||||||
|
|
||||||
async def async_process_devices(hass, manager):
|
async def async_process_devices(hass, manager):
|
||||||
"""Assign devices to proper component."""
|
"""Assign devices to proper component."""
|
||||||
devices = {
|
devices = {
|
||||||
@ -40,6 +45,7 @@ async def async_process_devices(hass, manager):
|
|||||||
if manager.fans:
|
if manager.fans:
|
||||||
for fan in manager.fans:
|
for fan in manager.fans:
|
||||||
# VeSync classifies humidifiers as fans
|
# VeSync classifies humidifiers as fans
|
||||||
|
_LOGGER.debug("Found a fan: %s", fan.__dict__)
|
||||||
if is_humidifier(fan.device_type):
|
if is_humidifier(fan.device_type):
|
||||||
devices[VS_HUMIDIFIERS].append(fan)
|
devices[VS_HUMIDIFIERS].append(fan)
|
||||||
devices[VS_NUMBERS].append(fan) # for night light and mist level
|
devices[VS_NUMBERS].append(fan) # for night light and mist level
|
||||||
@ -51,6 +57,8 @@ async def async_process_devices(hass, manager):
|
|||||||
if fan.night_light:
|
if fan.night_light:
|
||||||
devices[VS_LIGHTS].append(fan) # for night light
|
devices[VS_LIGHTS].append(fan) # for night light
|
||||||
else:
|
else:
|
||||||
|
if hasattr(fan, "config_dict"):
|
||||||
|
devices[VS_NUMBERS].append(fan)
|
||||||
devices[VS_FANS].append(fan)
|
devices[VS_FANS].append(fan)
|
||||||
_LOGGER.info("%d VeSync fans found", len(manager.fans))
|
_LOGGER.info("%d VeSync fans found", len(manager.fans))
|
||||||
|
|
||||||
|
@ -17,10 +17,14 @@ VS_MODE_AUTO = "auto"
|
|||||||
VS_MODE_MANUAL = "manual"
|
VS_MODE_MANUAL = "manual"
|
||||||
|
|
||||||
DEV_TYPE_TO_HA = {
|
DEV_TYPE_TO_HA = {
|
||||||
"LV-PUR131S": "fan",
|
|
||||||
"Core200S": "fan",
|
"Core200S": "fan",
|
||||||
"Core300S": "fan",
|
"Core300S": "fan",
|
||||||
"Core400S": "fan",
|
"Core400S": "fan",
|
||||||
|
"LAP-C201S-AUSR": "fan",
|
||||||
|
"LAP-C202S-WUSR": "fan",
|
||||||
|
"LAP-C401S-WUSR": "fan",
|
||||||
|
"LAP-C601S-WUS": "fan",
|
||||||
|
"LV-PUR131S": "fan",
|
||||||
"Classic300S": "humidifier",
|
"Classic300S": "humidifier",
|
||||||
"ESD16": "walldimmer",
|
"ESD16": "walldimmer",
|
||||||
"ESWD16": "walldimmer",
|
"ESWD16": "walldimmer",
|
||||||
|
@ -9,6 +9,10 @@ from homeassistant.core import HomeAssistant
|
|||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
|
def _if_has_attr_else_none(obj, attr):
|
||||||
|
return getattr(obj, attr) if hasattr(obj, attr) else None
|
||||||
|
|
||||||
|
|
||||||
async def async_get_config_entry_diagnostics(
|
async def async_get_config_entry_diagnostics(
|
||||||
hass: HomeAssistant, entry: ConfigEntry
|
hass: HomeAssistant, entry: ConfigEntry
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
@ -19,9 +23,9 @@ async def async_get_config_entry_diagnostics(
|
|||||||
for d in data["manager"]._dev_list[type]:
|
for d in data["manager"]._dev_list[type]:
|
||||||
devices[type].append(
|
devices[type].append(
|
||||||
{
|
{
|
||||||
"device": d.config_dict or {},
|
"config_dict": _if_has_attr_else_none(d, "config_dict") or {},
|
||||||
"config": d.config or {},
|
"config": _if_has_attr_else_none(d, "config") or {},
|
||||||
"details": d.details or {},
|
"details": _if_has_attr_else_none(d, "details") or {},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return devices
|
return devices
|
||||||
|
@ -20,14 +20,6 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
FAN_MODE_AUTO = "auto"
|
FAN_MODE_AUTO = "auto"
|
||||||
FAN_MODE_SLEEP = "sleep"
|
FAN_MODE_SLEEP = "sleep"
|
||||||
# Fixme add other models
|
|
||||||
PRESET_MODES = {
|
|
||||||
"Core200S": [FAN_MODE_SLEEP],
|
|
||||||
"Core300S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
|
||||||
"Core400S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
|
||||||
"LV-PUR131S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
|
||||||
}
|
|
||||||
SPEED_RANGE = (1, 3) # off is not included
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
@ -56,11 +48,12 @@ def _setup_entities(devices, async_add_entities):
|
|||||||
"""Check if device is online and add entity."""
|
"""Check if device is online and add entity."""
|
||||||
entities = []
|
entities = []
|
||||||
for dev in devices:
|
for dev in devices:
|
||||||
|
_LOGGER.debug("Adding device %s %s", dev.device_name, dev.device_type)
|
||||||
if DEV_TYPE_TO_HA.get(dev.device_type) == "fan":
|
if DEV_TYPE_TO_HA.get(dev.device_type) == "fan":
|
||||||
entities.append(VeSyncFanHA(dev))
|
entities.append(VeSyncFanHA(dev))
|
||||||
else:
|
else:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"%s - Unknown device type - %s", dev.device_name, dev.device_type
|
"Unknown device type %s %s", dev.device_name, dev.device_type
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -72,13 +65,25 @@ class VeSyncFanHA(VeSyncDevice, FanEntity):
|
|||||||
|
|
||||||
def __init__(self, fan):
|
def __init__(self, fan):
|
||||||
"""Initialize the VeSync fan device."""
|
"""Initialize the VeSync fan device."""
|
||||||
|
_LOGGER.debug("Initializing fan")
|
||||||
super().__init__(fan)
|
super().__init__(fan)
|
||||||
self.smartfan = fan
|
self.smartfan = fan
|
||||||
|
if hasattr(self.smartfan, "config_dict"):
|
||||||
|
self._speed_range = (1, max(self.smartfan.config_dict["levels"]))
|
||||||
|
self._attr_preset_modes = [
|
||||||
|
mode
|
||||||
|
for mode in ["auto", "sleep"]
|
||||||
|
if mode in self.smartfan.config_dict["modes"]
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self._speed_range = (1, 1)
|
||||||
|
self._attr_preset_modes = []
|
||||||
|
self._attr_preset_modes = [FAN_MODE_AUTO, FAN_MODE_SLEEP]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
return SUPPORT_SET_SPEED
|
return SUPPORT_SET_SPEED if self.speed_count > 1 else 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def percentage(self):
|
def percentage(self):
|
||||||
@ -87,25 +92,18 @@ class VeSyncFanHA(VeSyncDevice, FanEntity):
|
|||||||
self.smartfan.mode == "manual"
|
self.smartfan.mode == "manual"
|
||||||
and (current_level := self.smartfan.fan_level) is not None
|
and (current_level := self.smartfan.fan_level) is not None
|
||||||
):
|
):
|
||||||
return ranged_value_to_percentage(SPEED_RANGE, current_level)
|
return ranged_value_to_percentage(self._speed_range, current_level)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def speed_count(self) -> int:
|
def speed_count(self) -> int:
|
||||||
"""Return the number of speeds the fan supports."""
|
"""Return the number of speeds the fan supports."""
|
||||||
return int_states_in_range(SPEED_RANGE)
|
return int_states_in_range(self._speed_range)
|
||||||
|
|
||||||
@property
|
|
||||||
def preset_modes(self):
|
|
||||||
"""Get the list of available preset modes."""
|
|
||||||
return PRESET_MODES[self.device.device_type]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preset_mode(self):
|
def preset_mode(self):
|
||||||
"""Get the current preset mode."""
|
"""Get the current preset mode."""
|
||||||
if self.smartfan.mode in (FAN_MODE_AUTO, FAN_MODE_SLEEP):
|
return self.smartfan.mode
|
||||||
return self.smartfan.mode
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_info(self):
|
def unique_info(self):
|
||||||
@ -151,7 +149,7 @@ class VeSyncFanHA(VeSyncDevice, FanEntity):
|
|||||||
|
|
||||||
self.smartfan.manual_mode()
|
self.smartfan.manual_mode()
|
||||||
self.smartfan.change_fan_speed(
|
self.smartfan.change_fan_speed(
|
||||||
math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
|
math.ceil(percentage_to_ranged_value(self._speed_range, percentage))
|
||||||
)
|
)
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|||||||
from homeassistant.helpers.entity import EntityCategory
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .common import VeSyncBaseEntity, is_humidifier
|
from .common import VeSyncBaseEntity, is_air_purifier, is_humidifier
|
||||||
from .const import DOMAIN, VS_DISCOVERY, VS_NUMBERS
|
from .const import DOMAIN, VS_DISCOVERY, VS_NUMBERS
|
||||||
|
|
||||||
MAX_HUMIDITY = 80
|
MAX_HUMIDITY = 80
|
||||||
@ -50,7 +50,8 @@ def _setup_entities(devices, async_add_entities):
|
|||||||
VeSyncHumidifierTargetLevelHA(dev),
|
VeSyncHumidifierTargetLevelHA(dev),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
elif is_air_purifier(dev.device_type):
|
||||||
|
entities.extend((VeSyncFanSpeedLevelHA(dev),))
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"%s - Unknown device type - %s", dev.device_name, dev.device_type
|
"%s - Unknown device type - %s", dev.device_name, dev.device_type
|
||||||
@ -60,6 +61,63 @@ def _setup_entities(devices, async_add_entities):
|
|||||||
async_add_entities(entities, update_before_add=True)
|
async_add_entities(entities, update_before_add=True)
|
||||||
|
|
||||||
|
|
||||||
|
class VeSyncFanNumberEntity(VeSyncBaseEntity, NumberEntity):
|
||||||
|
"""Representation of a number for configuring a VeSync fan."""
|
||||||
|
|
||||||
|
def __init__(self, fan):
|
||||||
|
"""Initialize the VeSync fan device."""
|
||||||
|
super().__init__(fan)
|
||||||
|
self.smartfan = fan
|
||||||
|
|
||||||
|
@property
|
||||||
|
def entity_category(self):
|
||||||
|
"""Return the diagnostic entity category."""
|
||||||
|
return EntityCategory.CONFIG
|
||||||
|
|
||||||
|
|
||||||
|
class VeSyncFanSpeedLevelHA(VeSyncFanNumberEntity):
|
||||||
|
"""Representation of the fan speed level of a VeSync fan."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
"""Return the ID of this device."""
|
||||||
|
return f"{super().unique_id}-fan-speed-level"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the device."""
|
||||||
|
return f"{super().name} fan speed level"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
"""Return the fan speed level."""
|
||||||
|
return self.device.speed
|
||||||
|
|
||||||
|
@property
|
||||||
|
def min_value(self) -> float:
|
||||||
|
"""Return the minimum fan speed level."""
|
||||||
|
return self.device.config_dict["levels"][0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def max_value(self) -> float:
|
||||||
|
"""Return the maximum fan speed level."""
|
||||||
|
return self.device.config_dict["levels"][-1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def step(self) -> float:
|
||||||
|
"""Return the steps for the fan speed level."""
|
||||||
|
return 1.0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extra_state_attributes(self):
|
||||||
|
"""Return the state attributes of the humidifier."""
|
||||||
|
return {"fan speed levels": self.device.config_dict["levels"]}
|
||||||
|
|
||||||
|
def set_value(self, value):
|
||||||
|
"""Set the fan speed level."""
|
||||||
|
self.device.change_fan_speed(int(value))
|
||||||
|
|
||||||
|
|
||||||
class VeSyncHumidifierNumberEntity(VeSyncBaseEntity, NumberEntity):
|
class VeSyncHumidifierNumberEntity(VeSyncBaseEntity, NumberEntity):
|
||||||
"""Representation of a number for configuring a VeSync humidifier."""
|
"""Representation of a number for configuring a VeSync humidifier."""
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user