mirror of
https://github.com/XiaoMi/ha_xiaomi_home.git
synced 2026-01-17 15:41:15 +08:00
Compare commits
18 Commits
4f4ff94ce9
...
50279d73c0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50279d73c0 | ||
|
|
0ef8cb6370 | ||
|
|
8f0a69c611 | ||
|
|
ade18deb7e | ||
|
|
4e1185f4e5 | ||
|
|
6ad8da42be | ||
|
|
4aa6bb579f | ||
|
|
e83aa9367e | ||
|
|
04c44f36b1 | ||
|
|
a40363d3e6 | ||
|
|
13e6863678 | ||
|
|
b0d0d6b107 | ||
|
|
085caff660 | ||
|
|
fe3756db9b | ||
|
|
bf33f0c60d | ||
|
|
72f3a5df3e | ||
|
|
f452611b87 | ||
|
|
36d5a3e4de |
@ -605,7 +605,7 @@ class AirConditioner(FeatureOnOff, FeatureTargetTemperature,
|
||||
|
||||
|
||||
class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature,
|
||||
FeatureFanMode, FeatureSwingMode):
|
||||
FeatureFanMode, FeatureSwingMode, FeaturePresetMode):
|
||||
"""Ptc bath heater"""
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
_hvac_mode_map: Optional[dict[int, HVACMode]]
|
||||
@ -626,26 +626,20 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature,
|
||||
continue
|
||||
self._hvac_mode_map = {}
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'off', 'idle'
|
||||
} and (HVACMode.OFF not in list(
|
||||
self._hvac_mode_map.values())):
|
||||
self._hvac_mode_map[item.value] = HVACMode.OFF
|
||||
elif item.name in {'auto'}:
|
||||
if item.name in {'off', 'idle'}:
|
||||
if (HVACMode.OFF
|
||||
not in list(self._hvac_mode_map.values())):
|
||||
self._hvac_mode_map[item.value] = HVACMode.OFF
|
||||
elif (HVACMode.AUTO
|
||||
not in list(self._hvac_mode_map.values())):
|
||||
self._hvac_mode_map[item.value] = HVACMode.AUTO
|
||||
elif item.name in {'ventilate'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.COOL
|
||||
elif item.name in {'heat', 'quick_heat'
|
||||
} and (HVACMode.HEAT not in list(
|
||||
self._hvac_mode_map.values())):
|
||||
self._hvac_mode_map[item.value] = HVACMode.HEAT
|
||||
elif item.name in {'defog'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.HEAT_COOL
|
||||
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
|
||||
if HVACMode.OFF in self._attr_hvac_modes:
|
||||
self._prop_mode = prop
|
||||
else:
|
||||
_LOGGER.error('no idle mode, %s', self.entity_id)
|
||||
# preset modes
|
||||
self._init_preset_modes('ptc-bath-heater', 'mode')
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the target hvac mode."""
|
||||
@ -655,15 +649,20 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature,
|
||||
if mode_value is None or not await self.set_property_async(
|
||||
prop=self._prop_mode, value=mode_value):
|
||||
raise RuntimeError(
|
||||
f'set climate prop.mode failed, {hvac_mode}, {self.entity_id}')
|
||||
f'set ptc-bath-heater {hvac_mode} failed, {self.entity_id}')
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""The current hvac mode."""
|
||||
return (self.get_map_value(map_=self._hvac_mode_map,
|
||||
key=self.get_prop_value(
|
||||
prop=self._prop_mode))
|
||||
if self._prop_mode else None)
|
||||
if self._prop_mode is None:
|
||||
return None
|
||||
mode_value = self.get_map_value(
|
||||
map_=self._hvac_mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_mode))
|
||||
if mode_value == HVACMode.OFF or mode_value is None:
|
||||
return mode_value
|
||||
return HVACMode.AUTO if (HVACMode.AUTO
|
||||
in self._attr_hvac_modes) else None
|
||||
|
||||
|
||||
class Thermostat(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature,
|
||||
|
||||
@ -213,6 +213,12 @@ class MIoTSpecValueList:
|
||||
return item.description
|
||||
return None
|
||||
|
||||
def get_name_by_value(self, value: Any) -> Optional[str]:
|
||||
for item in self.items:
|
||||
if item.value == value:
|
||||
return item.name
|
||||
return None
|
||||
|
||||
def dump(self) -> list:
|
||||
return [item.dump() for item in self.items]
|
||||
|
||||
|
||||
@ -68,3 +68,11 @@ urn:miot-spec-v2:device:bath-heater:0000A028:mike-2:1:
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p51:1:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:1: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:3: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:4: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:5: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
|
||||
@ -138,7 +138,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'optional': {
|
||||
'properties': {'mode', 'target-humidity'}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'environment': {
|
||||
@ -164,8 +164,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'continue-sweep',
|
||||
'stop-and-gocharge'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
@ -178,9 +177,9 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'required': {
|
||||
'properties': {
|
||||
'battery-level': {'read'}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
'entity': 'vacuum'
|
||||
},
|
||||
@ -196,7 +195,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'target-humidity'}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
@ -237,7 +236,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'properties': {
|
||||
'target-temperature', 'mode', 'fan-level',
|
||||
'temperature'}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
@ -246,7 +245,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'optional': {
|
||||
'properties': {'temperature', 'relative-humidity'}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
'entity': 'thermostat'
|
||||
},
|
||||
@ -260,7 +259,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'target-temperature', 'heat-level'}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
@ -269,20 +268,21 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'optional': {
|
||||
'properties': {'temperature', 'relative-humidity'}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
'entity': 'heater'
|
||||
},
|
||||
'bath-heater': {
|
||||
'required': {
|
||||
'ptc-bath-heater': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'target-temperature', 'heat-level',
|
||||
'temperature', 'mode'
|
||||
'mode':{'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'target-temperature', 'temperature'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
@ -292,7 +292,13 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'properties': {
|
||||
'on', 'fan-level', 'horizontal-swing', 'vertical-swing'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
'environment': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {'temperature'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'bath-heater',
|
||||
@ -308,7 +314,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mode', 'temperature'}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {},
|
||||
@ -400,7 +406,7 @@ SPEC_SERVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'motor-control', 'status', 'current-position', 'target-position'
|
||||
'status', 'current-position', 'target-position'
|
||||
}
|
||||
},
|
||||
'entity': 'cover'
|
||||
|
||||
@ -54,7 +54,8 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.vacuum import (
|
||||
StateVacuumEntity,
|
||||
VacuumEntityFeature
|
||||
VacuumEntityFeature,
|
||||
VacuumActivity
|
||||
)
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
@ -191,10 +192,47 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
||||
|
||||
@property
|
||||
def state(self) -> Optional[str]:
|
||||
"""Return the current state of the vacuum cleaner."""
|
||||
"""Return the current state of the vacuum cleaner.
|
||||
|
||||
To fix the HA warning below:
|
||||
Detected that custom integration 'xiaomi_home' is setting state
|
||||
directly.Entity XXX(<class 'custom_components.xiaomi_home.vacuum
|
||||
.Vacuum'>)should implement the 'activity' property and return
|
||||
its state using the VacuumActivity enum.This will stop working in
|
||||
Home Assistant 2026.1.
|
||||
|
||||
Refer to
|
||||
https://developers.home-assistant.io/blog/2024/12/08/new-vacuum-state-property
|
||||
|
||||
There are only 6 states in VacuumActivity enum. To be compatible with
|
||||
more constants, try get matching VacuumActivity enum first, return state
|
||||
string as before if there is no match. In Home Assistant 2026.1, every
|
||||
state should map to a VacuumActivity enum.
|
||||
"""
|
||||
if (activity := self.activity) is not None:
|
||||
return activity
|
||||
return self.get_map_value(
|
||||
map_=self._status_map,
|
||||
key=self.get_prop_value(prop=self._prop_status))
|
||||
key=self.get_prop_value(prop=self._prop_status)
|
||||
)
|
||||
|
||||
@property
|
||||
def activity(self) -> VacuumActivity | None:
|
||||
"""Return the current vacuum activity."""
|
||||
state_trans_map = {
|
||||
'Sleep': VacuumActivity.IDLE,
|
||||
'Idle': VacuumActivity.IDLE,
|
||||
'Paused': VacuumActivity.PAUSED,
|
||||
'Go Charging': VacuumActivity.RETURNING,
|
||||
'Charging': VacuumActivity.DOCKED,
|
||||
'Sweeping': VacuumActivity.CLEANING,
|
||||
'Sweeping and Mopping': VacuumActivity.CLEANING,
|
||||
'Mopping': VacuumActivity.CLEANING,
|
||||
'Error': VacuumActivity.ERROR,
|
||||
}
|
||||
prop_value = self.get_prop_value(prop=self._prop_status)
|
||||
state_name = self._prop_status.value_list.get_name_by_value(prop_value)
|
||||
return state_trans_map.get(state_name)
|
||||
|
||||
@property
|
||||
def battery_level(self) -> Optional[int]:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user