Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: refactor miot device and spec #592

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
95 changes: 41 additions & 54 deletions custom_components/xiaomi_home/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,64 +156,56 @@ def __init__(
_LOGGER.error(
'unknown on property, %s', self.entity_id)
elif prop.name == 'mode':
if (
not isinstance(prop.value_list, list)
or not prop.value_list
):
if not prop.value_list:
_LOGGER.error(
'invalid mode value_list, %s', self.entity_id)
continue
self._hvac_mode_map = {}
for item in prop.value_list:
if item['name'].lower() in {'off', 'idle'}:
self._hvac_mode_map[item['value']] = HVACMode.OFF
elif item['name'].lower() in {'auto'}:
self._hvac_mode_map[item['value']] = HVACMode.AUTO
elif item['name'].lower() in {'cool'}:
self._hvac_mode_map[item['value']] = HVACMode.COOL
elif item['name'].lower() in {'heat'}:
self._hvac_mode_map[item['value']] = HVACMode.HEAT
elif item['name'].lower() in {'dry'}:
self._hvac_mode_map[item['value']] = HVACMode.DRY
elif item['name'].lower() in {'fan'}:
self._hvac_mode_map[item['value']] = HVACMode.FAN_ONLY
for item in prop.value_list.items:
if item.name in {'off', 'idle'}:
self._hvac_mode_map[item.value] = HVACMode.OFF
elif item.name in {'auto'}:
self._hvac_mode_map[item.value] = HVACMode.AUTO
elif item.name in {'cool'}:
self._hvac_mode_map[item.value] = HVACMode.COOL
elif item.name in {'heat'}:
self._hvac_mode_map[item.value] = HVACMode.HEAT
elif item.name in {'dry'}:
self._hvac_mode_map[item.value] = HVACMode.DRY
elif item.name in {'fan'}:
self._hvac_mode_map[item.value] = HVACMode.FAN_ONLY
self._attr_hvac_modes = list(self._hvac_mode_map.values())
self._prop_mode = prop
elif prop.name == 'target-temperature':
if not isinstance(prop.value_range, dict):
if not prop.value_range:
_LOGGER.error(
'invalid target-temperature value_range format, %s',
self.entity_id)
continue
self._attr_min_temp = prop.value_range['min']
self._attr_max_temp = prop.value_range['max']
self._attr_target_temperature_step = prop.value_range['step']
self._attr_min_temp = prop.value_range.min_
self._attr_max_temp = prop.value_range.max_
self._attr_target_temperature_step = prop.value_range.step
self._attr_temperature_unit = prop.external_unit
self._attr_supported_features |= (
ClimateEntityFeature.TARGET_TEMPERATURE)
self._prop_target_temp = prop
elif prop.name == 'target-humidity':
if not isinstance(prop.value_range, dict):
if not prop.value_range:
_LOGGER.error(
'invalid target-humidity value_range format, %s',
self.entity_id)
continue
self._attr_min_humidity = prop.value_range['min']
self._attr_max_humidity = prop.value_range['max']
self._attr_min_humidity = prop.value_range.min_
self._attr_max_humidity = prop.value_range.max_
self._attr_supported_features |= (
ClimateEntityFeature.TARGET_HUMIDITY)
self._prop_target_humi = prop
elif prop.name == 'fan-level':
if (
not isinstance(prop.value_list, list)
or not prop.value_list
):
if not prop.value_list:
_LOGGER.error(
'invalid fan-level value_list, %s', self.entity_id)
continue
self._fan_mode_map = {
item['value']: item['description']
for item in prop.value_list}
self._fan_mode_map = prop.value_list.to_map()
self._attr_fan_modes = list(self._fan_mode_map.values())
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
self._prop_fan_level = prop
Expand Down Expand Up @@ -269,8 +261,8 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
elif self.get_prop_value(prop=self._prop_on) is False:
await self.set_property_async(prop=self._prop_on, value=True)
# set mode
mode_value = self.get_map_value(
map_=self._hvac_mode_map, description=hvac_mode)
mode_value = self.get_map_key(
map_=self._hvac_mode_map, value=hvac_mode)
if (
mode_value is None or
not await self.set_property_async(
Expand Down Expand Up @@ -339,8 +331,8 @@ async def async_set_swing_mode(self, swing_mode):

async def async_set_fan_mode(self, fan_mode):
"""Set new target fan mode."""
mode_value = self.get_map_value(
map_=self._fan_mode_map, description=fan_mode)
mode_value = self.get_map_key(
map_=self._fan_mode_map, value=fan_mode)
if mode_value is None or not await self.set_property_async(
prop=self._prop_fan_level, value=mode_value):
raise RuntimeError(
Expand Down Expand Up @@ -376,17 +368,17 @@ def hvac_mode(self) -> Optional[HVACMode]:
"""Return the hvac mode. e.g., heat, cool mode."""
if self.get_prop_value(prop=self._prop_on) is False:
return HVACMode.OFF
return self.get_map_description(
return self.get_map_key(
map_=self._hvac_mode_map,
key=self.get_prop_value(prop=self._prop_mode))
value=self.get_prop_value(prop=self._prop_mode))

@property
def fan_mode(self) -> Optional[str]:
"""Return the fan mode.

Requires ClimateEntityFeature.FAN_MODE.
"""
return self.get_map_description(
return self.get_map_value(
map_=self._fan_mode_map,
key=self.get_prop_value(prop=self._prop_fan_level))

Expand Down Expand Up @@ -446,8 +438,8 @@ def __ac_state_changed(self, prop: MIoTSpecProperty, value: Any) -> None:
}.get(v_ac_state['M'], None)
if mode:
self.set_prop_value(
prop=self._prop_mode, value=self.get_map_value(
map_=self._hvac_mode_map, description=mode))
prop=self._prop_mode, value=self.get_map_key(
map_=self._hvac_mode_map, value=mode))
# T: target temperature
if 'T' in v_ac_state and self._prop_target_temp:
self.set_prop_value(prop=self._prop_target_temp,
Expand Down Expand Up @@ -517,29 +509,24 @@ def __init__(
ClimateEntityFeature.TURN_OFF)
self._prop_on = prop
elif prop.name == 'target-temperature':
if not isinstance(prop.value_range, dict):
if not prop.value_range:
_LOGGER.error(
'invalid target-temperature value_range format, %s',
self.entity_id)
continue
self._attr_min_temp = prop.value_range['min']
self._attr_max_temp = prop.value_range['max']
self._attr_target_temperature_step = prop.value_range['step']
self._attr_min_temp = prop.value_range.min_
self._attr_max_temp = prop.value_range.max_
self._attr_target_temperature_step = prop.value_range.step
self._attr_temperature_unit = prop.external_unit
self._attr_supported_features |= (
ClimateEntityFeature.TARGET_TEMPERATURE)
self._prop_target_temp = prop
elif prop.name == 'heat-level':
if (
not isinstance(prop.value_list, list)
or not prop.value_list
):
if not prop.value_list:
_LOGGER.error(
'invalid heat-level value_list, %s', self.entity_id)
continue
self._heat_level_map = {
item['value']: item['description']
for item in prop.value_list}
self._heat_level_map = prop.value_list.to_map()
self._attr_preset_modes = list(self._heat_level_map.values())
self._attr_supported_features |= (
ClimateEntityFeature.PRESET_MODE)
Expand Down Expand Up @@ -582,8 +569,8 @@ async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the preset mode."""
await self.set_property_async(
self._prop_heat_level,
value=self.get_map_value(
map_=self._heat_level_map, description=preset_mode))
value=self.get_map_key(
map_=self._heat_level_map, value=preset_mode))

@property
def target_temperature(self) -> Optional[float]:
Expand Down Expand Up @@ -613,7 +600,7 @@ def hvac_mode(self) -> Optional[HVACMode]:
@property
def preset_mode(self) -> Optional[str]:
return (
self.get_map_description(
self.get_map_value(
map_=self._heat_level_map,
key=self.get_prop_value(prop=self._prop_heat_level))
if self._prop_heat_level else None)
7 changes: 4 additions & 3 deletions custom_components/xiaomi_home/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ async def async_step_oauth(
await self._miot_oauth.deinit_async()
self._miot_oauth = None
return self.async_show_progress_done(next_step_id='homes_select')
# pylint: disable=unexpected-keyword-arg
return self.async_show_progress(
step_id='oauth',
progress_action='oauth',
Expand All @@ -481,7 +482,7 @@ async def async_step_oauth(
f'<a href="{self._cc_oauth_auth_url}" target="_blank">',
'link_right': '</a>'
},
progress_task=self._cc_task_oauth,
progress_task=self._cc_task_oauth, # type: ignore
)

async def __check_oauth_async(self) -> None:
Expand Down Expand Up @@ -1196,7 +1197,7 @@ async def async_step_oauth(self, user_input=None):
err, traceback.format_exc())
self._cc_config_rc = str(err)
return self.async_show_progress_done(next_step_id='oauth_error')

# pylint: disable=unexpected-keyword-arg
return self.async_show_progress(
step_id='oauth',
progress_action='oauth',
Expand All @@ -1205,7 +1206,7 @@ async def async_step_oauth(self, user_input=None):
f'<a href="{self._cc_oauth_auth_url}" target="_blank">',
'link_right': '</a>'
},
progress_task=self._cc_task_oauth,
progress_task=self._cc_task_oauth, # type: ignore
)

async def __check_oauth_async(self) -> None:
Expand Down
44 changes: 19 additions & 25 deletions custom_components/xiaomi_home/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,53 +132,47 @@ def __init__(
# properties
for prop in entity_data.props:
if prop.name == 'motor-control':
if (
not isinstance(prop.value_list, list)
or not prop.value_list
):
if not prop.value_list:
_LOGGER.error(
'motor-control value_list is None, %s', self.entity_id)
continue
for item in prop.value_list:
if item['name'].lower() in ['open']:
for item in prop.value_list.items:
if item.name in {'open'}:
self._attr_supported_features |= (
CoverEntityFeature.OPEN)
self._prop_motor_value_open = item['value']
elif item['name'].lower() in ['close']:
self._prop_motor_value_open = item.value
elif item.name in {'close'}:
self._attr_supported_features |= (
CoverEntityFeature.CLOSE)
self._prop_motor_value_close = item['value']
elif item['name'].lower() in ['pause']:
self._prop_motor_value_close = item.value
elif item.name in {'pause'}:
self._attr_supported_features |= (
CoverEntityFeature.STOP)
self._prop_motor_value_pause = item['value']
self._prop_motor_value_pause = item.value
self._prop_motor_control = prop
elif prop.name == 'status':
if (
not isinstance(prop.value_list, list)
or not prop.value_list
):
if not prop.value_list:
_LOGGER.error(
'status value_list is None, %s', self.entity_id)
continue
for item in prop.value_list:
if item['name'].lower() in ['opening', 'open']:
self._prop_status_opening = item['value']
elif item['name'].lower() in ['closing', 'close']:
self._prop_status_closing = item['value']
elif item['name'].lower() in ['stop', 'pause']:
self._prop_status_stop = item['value']
for item in prop.value_list.items:
if item.name in {'opening', 'open'}:
self._prop_status_opening = item.value
elif item.name in {'closing', 'close'}:
self._prop_status_closing = item.value
elif item.name in {'stop', 'pause'}:
self._prop_status_stop = item.value
self._prop_status = prop
elif prop.name == 'current-position':
self._prop_current_position = prop
elif prop.name == 'target-position':
if not isinstance(prop.value_range, dict):
if not prop.value_range:
_LOGGER.error(
'invalid target-position value_range format, %s',
self.entity_id)
continue
self._prop_position_value_min = prop.value_range['min']
self._prop_position_value_max = prop.value_range['max']
self._prop_position_value_min = prop.value_range.min_
self._prop_position_value_max = prop.value_range.max_
self._prop_position_value_range = (
self._prop_position_value_max -
self._prop_position_value_min)
Expand Down
Loading
Loading