初始化config文件
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
"""Support for Xiaomi fans."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
DOMAIN as ENTITY_DOMAIN,
|
||||
FanEntity as BaseEntity,
|
||||
FanEntityFeature,
|
||||
)
|
||||
|
||||
from . import (
|
||||
DOMAIN,
|
||||
CONF_MODEL,
|
||||
XIAOMI_CONFIG_SCHEMA as PLATFORM_SCHEMA, # noqa: F401
|
||||
HassEntry,
|
||||
XEntity,
|
||||
MiirToggleEntity,
|
||||
async_setup_config_entry,
|
||||
bind_services_to_entries,
|
||||
)
|
||||
from .core.miot_spec import (
|
||||
MiotSpec,
|
||||
MiotService,
|
||||
MiotProperty,
|
||||
)
|
||||
from homeassistant.util.percentage import (
|
||||
ordered_list_item_to_percentage,
|
||||
percentage_to_ordered_list_item,
|
||||
ranged_value_to_percentage,
|
||||
percentage_to_ranged_value,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
DATA_KEY = f'{ENTITY_DOMAIN}.{DOMAIN}'
|
||||
SERVICE_TO_METHOD = {}
|
||||
|
||||
SPEED_OFF = 'off'
|
||||
OFF_SPEED_VALUES = [SPEED_OFF, None]
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
HassEntry.init(hass, config_entry).new_adder(ENTITY_DOMAIN, async_add_entities)
|
||||
await async_setup_config_entry(hass, config_entry, async_setup_platform, async_add_entities, ENTITY_DOMAIN)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
hass.data.setdefault(DATA_KEY, {})
|
||||
hass.data[DOMAIN]['add_entities'][ENTITY_DOMAIN] = async_add_entities
|
||||
config['hass'] = hass
|
||||
model = str(config.get(CONF_MODEL) or '')
|
||||
spec = hass.data[DOMAIN]['miot_specs'].get(model)
|
||||
entities = []
|
||||
if isinstance(spec, MiotSpec):
|
||||
for srv in spec.get_services('ir_fan_control'):
|
||||
entities.append(MiirFanEntity(config, srv))
|
||||
for entity in entities:
|
||||
hass.data[DOMAIN]['entities'][entity.unique_id] = entity
|
||||
async_add_entities(entities, update_before_add=True)
|
||||
bind_services_to_entries(hass, SERVICE_TO_METHOD)
|
||||
|
||||
|
||||
class FanEntity(XEntity, BaseEntity):
|
||||
_attr_device_class = None
|
||||
_conv_power = None
|
||||
_conv_mode = None
|
||||
_conv_speed = None
|
||||
_speed_list = None
|
||||
_speed_range = None
|
||||
_conv_oscillate = None
|
||||
_prop_speed = None
|
||||
_prop_percentage = None
|
||||
|
||||
def on_init(self):
|
||||
speed_property = self.custom_config('speed_property', 'speed')
|
||||
percentage_property = self.custom_config('percentage_property', 'fan_percent')
|
||||
for attr in self.conv.attrs:
|
||||
conv = self.device.find_converter(attr)
|
||||
prop = getattr(conv, 'prop', None) if conv else None
|
||||
if not isinstance(prop, MiotProperty):
|
||||
continue
|
||||
elif prop.in_list(['on']):
|
||||
self._conv_power = conv
|
||||
if hasattr(FanEntityFeature, 'TURN_ON'): # v2024.8
|
||||
self._attr_supported_features |= FanEntityFeature.TURN_ON
|
||||
if hasattr(FanEntityFeature, 'TURN_OFF'):
|
||||
self._attr_supported_features |= FanEntityFeature.TURN_OFF
|
||||
elif prop.in_list(['mode']):
|
||||
self._conv_mode = conv
|
||||
self._attr_preset_modes = prop.list_descriptions()
|
||||
self._attr_supported_features |= FanEntityFeature.PRESET_MODE
|
||||
elif prop.in_list(['fan_level', 'speed_level', 'stepless_fan_level', speed_property, percentage_property]):
|
||||
if prop.value_range:
|
||||
self.set_percentage_property(prop)
|
||||
elif prop.value_list and not self._conv_speed:
|
||||
self.set_speeds_property(prop)
|
||||
else:
|
||||
continue
|
||||
self._conv_speed = conv
|
||||
elif prop.in_list(['horizontal_swing', 'vertical_swing']) and not self._conv_oscillate:
|
||||
self._conv_oscillate = conv
|
||||
self._attr_supported_features |= FanEntityFeature.OSCILLATE
|
||||
|
||||
# issues/617
|
||||
if self.custom_config_bool('disable_preset_modes'):
|
||||
self._attr_supported_features &= ~FanEntityFeature.PRESET_MODE
|
||||
self._attr_preset_modes = []
|
||||
elif dpm := self.custom_config_list('disable_preset_modes'):
|
||||
self._attr_preset_modes = [
|
||||
mode
|
||||
for mode in self._attr_preset_modes
|
||||
if mode not in dpm
|
||||
]
|
||||
|
||||
def set_percentage_property(self, prop):
|
||||
if not prop or not prop.value_range:
|
||||
return
|
||||
self._prop_percentage = prop
|
||||
_min = prop.range_min()
|
||||
_max = prop.range_max()
|
||||
_stp = prop.range_step()
|
||||
self._speed_range = (_min, _max)
|
||||
self._attr_speed_count = (_max - _min) / _stp + 1
|
||||
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
||||
|
||||
def set_speeds_property(self, prop):
|
||||
if not prop:
|
||||
return
|
||||
self._speed_list = prop.list_descriptions()
|
||||
self._attr_speed_count = len(self._speed_list)
|
||||
self._attr_extra_state_attributes['speed_list'] = self._speed_list
|
||||
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
||||
|
||||
def set_state(self, data: dict):
|
||||
if self._conv_speed:
|
||||
val = self._conv_speed.value_from_dict(data)
|
||||
if val is not None:
|
||||
des = self._conv_speed.prop.list_description(val)
|
||||
if self._speed_range:
|
||||
self._attr_percentage = ranged_value_to_percentage(self._speed_range, float(val))
|
||||
if self._speed_list and val in self._speed_list:
|
||||
self._attr_percentage = ordered_list_item_to_percentage(self._speed_list, val)
|
||||
elif self._speed_list and des in self._speed_list:
|
||||
self._attr_percentage = ordered_list_item_to_percentage(self._speed_list, des)
|
||||
if self._conv_power:
|
||||
val = self._conv_power.value_from_dict(data)
|
||||
if val is not None:
|
||||
self._attr_is_on = bool(val)
|
||||
if not self._attr_is_on:
|
||||
self._attr_percentage = 0
|
||||
if self._conv_mode:
|
||||
val = self._conv_mode.value_from_dict(data)
|
||||
if val is not None:
|
||||
self._attr_preset_mode = val
|
||||
if self._conv_oscillate:
|
||||
val = self._conv_oscillate.value_from_dict(data)
|
||||
if val is not None:
|
||||
self._attr_oscillating = bool(val)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
if self._conv_power:
|
||||
return self._attr_is_on
|
||||
return self.percentage is not None and self.percentage > 0
|
||||
|
||||
async def async_turn_on(self, percentage=None, preset_mode=None, **kwargs):
|
||||
dat = {}
|
||||
if self._conv_power and not self.is_on:
|
||||
dat[self._conv_power.full_name] = True
|
||||
if percentage is not None:
|
||||
if self._speed_range:
|
||||
dat[self._conv_speed.full_name] = percentage_to_ranged_value(self._speed_range, percentage)
|
||||
elif self._speed_list:
|
||||
des = percentage_to_ordered_list_item(self._speed_list, percentage)
|
||||
dat[self._conv_speed.full_name] = des
|
||||
if preset_mode is not None:
|
||||
dat[self._conv_mode.full_name] = preset_mode
|
||||
if dat:
|
||||
await self.device.async_write(dat)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
if not self._conv_power:
|
||||
return
|
||||
await self.device.async_write({self._conv_power.full_name: False})
|
||||
|
||||
async def async_set_percentage(self, percentage: int):
|
||||
if percentage == 0 and self._conv_power:
|
||||
await self.async_turn_off()
|
||||
return
|
||||
await self.async_turn_on(percentage=percentage)
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str):
|
||||
if not self._conv_mode:
|
||||
return
|
||||
await self.device.async_write({self._conv_mode.full_name: preset_mode})
|
||||
|
||||
async def async_oscillate(self, oscillating: bool):
|
||||
if not self._conv_oscillate:
|
||||
return
|
||||
await self.device.async_write({self._conv_oscillate.full_name: oscillating})
|
||||
|
||||
|
||||
XEntity.CLS[ENTITY_DOMAIN] = FanEntity
|
||||
|
||||
|
||||
class MiirFanEntity(MiirToggleEntity, FanEntity):
|
||||
def __init__(self, config: dict, miot_service: MiotService):
|
||||
super().__init__(miot_service, config=config, logger=_LOGGER)
|
||||
|
||||
if self._act_turn_on and hasattr(FanEntityFeature, 'TURN_ON'): # v2024.8
|
||||
self._supported_features |= FanEntityFeature.TURN_ON
|
||||
if self._act_turn_off and hasattr(FanEntityFeature, 'TURN_OFF'):
|
||||
self._supported_features |= FanEntityFeature.TURN_OFF
|
||||
|
||||
self._attr_percentage = 50
|
||||
self._act_speed_up = miot_service.get_action('fan_speed_up')
|
||||
self._act_speed_dn = miot_service.get_action('fan_speed_down')
|
||||
if self._act_speed_up or self._act_speed_dn:
|
||||
self._supported_features |= FanEntityFeature.SET_SPEED
|
||||
|
||||
self._act_swing_on = miot_service.get_action('horizontal_swing_on')
|
||||
self._act_swing_off = miot_service.get_action('horizontal_swing_off')
|
||||
if self._act_swing_on or self._act_swing_off:
|
||||
self._supported_features |= FanEntityFeature.OSCILLATE
|
||||
|
||||
self._supported_features |= FanEntityFeature.PRESET_MODE
|
||||
self._attr_preset_mode = None
|
||||
self._attr_preset_modes = []
|
||||
for a in miot_service.actions.values():
|
||||
if a.ins:
|
||||
continue
|
||||
self._attr_preset_modes.append(a.friendly_desc)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
await super().async_added_to_hass()
|
||||
# issues/617
|
||||
if self.custom_config_bool('disable_preset_modes'):
|
||||
self._supported_features &= ~FanEntityFeature.PRESET_MODE
|
||||
self._attr_preset_modes = []
|
||||
elif dpm := self.custom_config_list('disable_preset_modes'):
|
||||
self._attr_preset_modes = [
|
||||
mode
|
||||
for mode in self._attr_preset_modes
|
||||
if mode not in dpm
|
||||
]
|
||||
|
||||
async def async_turn_on(self, percentage=None, preset_mode=None, **kwargs):
|
||||
"""Turn the entity on."""
|
||||
if percentage is None:
|
||||
pass
|
||||
elif percentage > self._attr_percentage and self._act_speed_up:
|
||||
return await self.async_call_action(self._act_speed_up)
|
||||
elif percentage < self._attr_percentage and self._act_speed_dn:
|
||||
return await self.async_call_action(self._act_speed_dn)
|
||||
|
||||
if preset_mode is None:
|
||||
pass
|
||||
elif act := self._miot_service.get_action(preset_mode):
|
||||
return await self.async_call_action(act)
|
||||
|
||||
return await super().async_turn_on(**kwargs)
|
||||
|
||||
async def async_set_percentage(self, percentage: int):
|
||||
"""Set the speed of the fan, as a percentage."""
|
||||
return await self.async_turn_on(percentage=percentage)
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode):
|
||||
"""Set new preset mode."""
|
||||
return await self.async_turn_on(preset_mode=preset_mode)
|
||||
|
||||
async def async_oscillate(self, oscillating):
|
||||
"""Oscillate the fan."""
|
||||
ret = None
|
||||
if not oscillating and self._act_swing_off:
|
||||
ret = await self.async_call_action(self._act_swing_off)
|
||||
elif oscillating and self._act_swing_on:
|
||||
ret = await self.async_call_action(self._act_swing_on)
|
||||
if ret:
|
||||
self._attr_oscillating = oscillating
|
||||
return ret
|
||||
Reference in New Issue
Block a user