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

fix: fix water heater error & some type error #684

Merged
merged 3 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 38 additions & 38 deletions custom_components/xiaomi_home/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,39 +295,37 @@ async def async_set_humidity(self, humidity):
async def async_set_swing_mode(self, swing_mode):
"""Set new target swing operation."""
if swing_mode == SWING_BOTH:
if await self.set_property_async(
prop=self._prop_horizontal_swing, value=True, update=False):
self.set_prop_value(self._prop_horizontal_swing, value=True)
if await self.set_property_async(
prop=self._prop_vertical_swing, value=True, update=False):
self.set_prop_value(self._prop_vertical_swing, value=True)
await self.set_property_async(
prop=self._prop_horizontal_swing, value=True,
write_ha_state=False)
await self.set_property_async(
prop=self._prop_vertical_swing, value=True)
elif swing_mode == SWING_HORIZONTAL:
if await self.set_property_async(
prop=self._prop_horizontal_swing, value=True, update=False):
self.set_prop_value(self._prop_horizontal_swing, value=True)
await self.set_property_async(
prop=self._prop_horizontal_swing, value=True)
elif swing_mode == SWING_VERTICAL:
if await self.set_property_async(
prop=self._prop_vertical_swing, value=True, update=False):
self.set_prop_value(self._prop_vertical_swing, value=True)
await self.set_property_async(
prop=self._prop_vertical_swing, value=True)
elif swing_mode == SWING_ON:
if await self.set_property_async(
prop=self._prop_fan_on, value=True, update=False):
self.set_prop_value(self._prop_fan_on, value=True)
await self.set_property_async(
prop=self._prop_fan_on, value=True)
elif swing_mode == SWING_OFF:
if self._prop_fan_on and await self.set_property_async(
prop=self._prop_fan_on, value=False, update=False):
self.set_prop_value(self._prop_fan_on, value=False)
if self._prop_horizontal_swing and await self.set_property_async(
if self._prop_fan_on:
await self.set_property_async(
prop=self._prop_fan_on, value=False,
write_ha_state=False)
if self._prop_horizontal_swing:
await self.set_property_async(
prop=self._prop_horizontal_swing, value=False,
update=False):
self.set_prop_value(self._prop_horizontal_swing, value=False)
if self._prop_vertical_swing and await self.set_property_async(
prop=self._prop_vertical_swing, value=False, update=False):
self.set_prop_value(self._prop_vertical_swing, value=False)
write_ha_state=False)
if self._prop_vertical_swing:
await self.set_property_async(
prop=self._prop_vertical_swing, value=False,
write_ha_state=False)
self.async_write_ha_state()
else:
raise RuntimeError(
f'unknown swing_mode, {swing_mode}, {self.entity_id}')
self.async_write_ha_state()

async def async_set_fan_mode(self, fan_mode):
"""Set new target fan mode."""
Expand Down Expand Up @@ -368,9 +366,9 @@ 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_key(
return self.get_map_value(
map_=self._hvac_mode_map,
value=self.get_prop_value(prop=self._prop_mode))
key=self.get_prop_value(prop=self._prop_mode))

@property
def fan_mode(self) -> Optional[str]:
Expand All @@ -388,12 +386,10 @@ def swing_mode(self) -> Optional[str]:

Requires ClimateEntityFeature.SWING_MODE.
"""
horizontal: bool = (
self.get_prop_value(prop=self._prop_horizontal_swing)
if self._prop_horizontal_swing else None)
vertical: bool = (
self.get_prop_value(prop=self._prop_vertical_swing)
if self._prop_vertical_swing else None)
horizontal = (
self.get_prop_value(prop=self._prop_horizontal_swing))
vertical = (
self.get_prop_value(prop=self._prop_vertical_swing))
if horizontal and vertical:
return SWING_BOTH
if horizontal:
Expand Down Expand Up @@ -449,7 +445,11 @@ def __ac_state_changed(self, prop: MIoTSpecProperty, value: Any) -> None:
self.set_prop_value(prop=self._prop_fan_level,
value=v_ac_state['S'])
# D: swing mode. 0: on, 1: off
if 'D' in v_ac_state and len(self._attr_swing_modes) == 2:
if (
'D' in v_ac_state
and self._attr_swing_modes
and len(self._attr_swing_modes) == 2
):
if (
SWING_HORIZONTAL in self._attr_swing_modes
and self._prop_horizontal_swing
Expand All @@ -464,10 +464,10 @@ def __ac_state_changed(self, prop: MIoTSpecProperty, value: Any) -> None:
self.set_prop_value(
prop=self._prop_vertical_swing,
value=v_ac_state['D'] == 0)

self._value_ac_state.update(v_ac_state)
_LOGGER.debug(
'ac_state update, %s', self._value_ac_state)
if self._value_ac_state:
self._value_ac_state.update(v_ac_state)
_LOGGER.debug(
'ac_state update, %s', self._value_ac_state)


class Heater(MIoTServiceEntity, ClimateEntity):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/xiaomi_home/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ async def async_set_cover_position(self, **kwargs) -> None:
if pos is None:
return None
pos = round(pos*self._prop_position_value_range/100)
return await self.set_property_async(
await self.set_property_async(
prop=self._prop_target_position, value=pos)

@property
Expand Down
2 changes: 1 addition & 1 deletion custom_components/xiaomi_home/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def percentage(self) -> Optional[int]:
fan_level = self.get_prop_value(prop=self._prop_fan_level)
if fan_level is None:
return None
if self._speed_names:
if self._speed_names and self._speed_name_map:
return ordered_list_item_to_percentage(
self._speed_names, self._speed_name_map[fan_level])
else:
Expand Down
36 changes: 21 additions & 15 deletions custom_components/xiaomi_home/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class Light(MIoTServiceEntity, LightEntity):
"""Light entities for Xiaomi Home."""
# pylint: disable=unused-argument
_VALUE_RANGE_MODE_COUNT_MAX = 30
_prop_on: MIoTSpecProperty
_prop_on: Optional[MIoTSpecProperty]
_prop_brightness: Optional[MIoTSpecProperty]
_prop_color_temp: Optional[MIoTSpecProperty]
_prop_color: Optional[MIoTSpecProperty]
Expand Down Expand Up @@ -250,43 +250,49 @@ async def async_turn_on(self, **kwargs) -> None:

Shall set attributes in kwargs if applicable.
"""
result: bool = False
# on
# Dirty logic for lumi.gateway.mgl03 indicator light
value_on = True if self._prop_on.format_ == bool else 1
result = await self.set_property_async(
prop=self._prop_on, value=value_on)
if self._prop_on:
value_on = True if self._prop_on.format_ == bool else 1
await self.set_property_async(
prop=self._prop_on, value=value_on)
# brightness
if ATTR_BRIGHTNESS in kwargs:
brightness = brightness_to_value(
self._brightness_scale, kwargs[ATTR_BRIGHTNESS])
result = await self.set_property_async(
prop=self._prop_brightness, value=brightness)
await self.set_property_async(
prop=self._prop_brightness, value=brightness,
write_ha_state=False)
# color-temperature
if ATTR_COLOR_TEMP_KELVIN in kwargs:
result = await self.set_property_async(
await self.set_property_async(
prop=self._prop_color_temp,
value=kwargs[ATTR_COLOR_TEMP_KELVIN])
value=kwargs[ATTR_COLOR_TEMP_KELVIN],
write_ha_state=False)
self._attr_color_mode = ColorMode.COLOR_TEMP
# rgb color
if ATTR_RGB_COLOR in kwargs:
r = kwargs[ATTR_RGB_COLOR][0]
g = kwargs[ATTR_RGB_COLOR][1]
b = kwargs[ATTR_RGB_COLOR][2]
rgb = (r << 16) | (g << 8) | b
result = await self.set_property_async(
prop=self._prop_color, value=rgb)
await self.set_property_async(
prop=self._prop_color, value=rgb,
write_ha_state=False)
self._attr_color_mode = ColorMode.RGB
# mode
if ATTR_EFFECT in kwargs:
result = await self.set_property_async(
await self.set_property_async(
prop=self._prop_mode,
value=self.get_map_key(
map_=self._mode_map, value=kwargs[ATTR_EFFECT]))
return result
map_=self._mode_map, value=kwargs[ATTR_EFFECT]),
write_ha_state=False)
self.async_write_ha_state()

async def async_turn_off(self, **kwargs) -> None:
"""Turn the light off."""
if not self._prop_on:
return
# Dirty logic for lumi.gateway.mgl03 indicator light
value_on = False if self._prop_on.format_ == bool else 0
return await self.set_property_async(prop=self._prop_on, value=value_on)
await self.set_property_async(prop=self._prop_on, value=value_on)
18 changes: 11 additions & 7 deletions custom_components/xiaomi_home/miot/miot_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -903,14 +903,14 @@ async def async_will_remove_from_hass(self) -> None:
siid=event.service.iid, eiid=event.iid, sub_id=sub_id)

def get_map_value(
self, map_: dict[int, Any], key: int
self, map_: Optional[dict[int, Any]], key: int
) -> Any:
if map_ is None:
return None
return map_.get(key, None)

def get_map_key(
self, map_: dict[int, Any], value: Any
self, map_: Optional[dict[int, Any]], value: Any
) -> Optional[int]:
if map_ is None:
return None
Expand All @@ -919,15 +919,17 @@ def get_map_key(
return key
return None

def get_prop_value(self, prop: MIoTSpecProperty) -> Any:
def get_prop_value(self, prop: Optional[MIoTSpecProperty]) -> Any:
if not prop:
_LOGGER.error(
'get_prop_value error, property is None, %s, %s',
self._attr_name, self.entity_id)
return None
return self._prop_value_map.get(prop, None)

def set_prop_value(self, prop: MIoTSpecProperty, value: Any) -> None:
def set_prop_value(
self, prop: Optional[MIoTSpecProperty], value: Any
) -> None:
if not prop:
_LOGGER.error(
'set_prop_value error, property is None, %s, %s',
Expand All @@ -936,13 +938,14 @@ def set_prop_value(self, prop: MIoTSpecProperty, value: Any) -> None:
self._prop_value_map[prop] = value

async def set_property_async(
self, prop: MIoTSpecProperty, value: Any, update: bool = True
self, prop: Optional[MIoTSpecProperty], value: Any,
update_value: bool = True, write_ha_state: bool = True
) -> bool:
value = prop.value_format(value)
if not prop:
raise RuntimeError(
f'set property failed, property is None, '
f'{self.entity_id}, {self.name}')
value = prop.value_format(value)
if prop not in self.entity_data.props:
raise RuntimeError(
f'set property failed, unknown property, '
Expand All @@ -958,8 +961,9 @@ async def set_property_async(
except MIoTClientError as e:
raise RuntimeError(
f'{e}, {self.entity_id}, {self.name}, {prop.name}') from e
if update:
if update_value:
self._prop_value_map[prop] = value
if write_ha_state:
self.async_write_ha_state()
return True

Expand Down
35 changes: 17 additions & 18 deletions custom_components/xiaomi_home/water_heater.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def __init__(
) -> None:
"""Initialize the Water heater."""
super().__init__(miot_device=miot_device, entity_data=entity_data)
self._attr_temperature_unit = None
self._attr_temperature_unit = None # type: ignore
self._attr_supported_features = WaterHeaterEntityFeature(0)
self._prop_on = None
self._prop_temp = None
Expand All @@ -112,29 +112,29 @@ def __init__(
for prop in entity_data.props:
# on
if prop.name == 'on':
self._attr_supported_features |= WaterHeaterEntityFeature.ON_OFF
self._prop_on = prop
# temperature
if prop.name == 'temperature':
if prop.value_range:
if (
self._attr_temperature_unit is None
and prop.external_unit
):
self._attr_temperature_unit = prop.external_unit
self._prop_temp = prop
else:
if not prop.value_range:
_LOGGER.error(
'invalid temperature value_range format, %s',
self.entity_id)
continue
if prop.external_unit:
self._attr_temperature_unit = prop.external_unit
self._attr_min_temp = prop.value_range.min_
self._attr_max_temp = prop.value_range.max_
self._prop_temp = prop
# target-temperature
if prop.name == 'target-temperature':
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_low = prop.value_range.min_
self._attr_target_temperature_high = prop.value_range.max_
self._attr_precision = prop.value_range.step
if self._attr_temperature_unit is None and prop.external_unit:
self._attr_temperature_unit = prop.external_unit
Expand Down Expand Up @@ -166,6 +166,8 @@ async def async_turn_off(self) -> None:

async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the temperature the water heater should heat water to."""
if not self._prop_target_temp:
return
await self.set_property_async(
prop=self._prop_target_temp, value=kwargs[ATTR_TEMPERATURE])

Expand All @@ -181,16 +183,11 @@ async def async_set_operation_mode(self, operation_mode: str) -> None:
return
if self.get_prop_value(prop=self._prop_on) is False:
await self.set_property_async(
prop=self._prop_on, value=True, update=False)
prop=self._prop_on, value=True, write_ha_state=False)
await self.set_property_async(
prop=self._prop_mode,
value=self.get_map_key(
map_=self._mode_map,
value=operation_mode))

async def async_turn_away_mode_on(self) -> None:
"""Set the water heater to away mode."""
await self.hass.async_add_executor_job(self.turn_away_mode_on)
map_=self._mode_map, value=operation_mode))

@property
def current_temperature(self) -> Optional[float]:
Expand All @@ -200,6 +197,8 @@ def current_temperature(self) -> Optional[float]:
@property
def target_temperature(self) -> Optional[float]:
"""Return the target temperature."""
if not self._prop_target_temp:
return None
return self.get_prop_value(prop=self._prop_target_temp)

@property
Expand Down
Loading