mirror of
https://github.com/XiaoMi/ha_xiaomi_home.git
synced 2026-01-18 16:10:44 +08:00
Compare commits
31 Commits
7a8884ace3
...
aeef5dca2f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aeef5dca2f | ||
|
|
d659d13e49 | ||
|
|
3402587b1c | ||
|
|
f15247384a | ||
|
|
473a33ea76 | ||
|
|
c9f588d7ab | ||
|
|
e42a3a5997 | ||
|
|
8580942225 | ||
|
|
0335b382cc | ||
|
|
83ce6c251e | ||
|
|
e7a96e3464 | ||
|
|
1bc6ca5e19 | ||
|
|
f96f6470b4 | ||
|
|
9d88e609ca | ||
|
|
db30e4d275 | ||
|
|
02963a7f06 | ||
|
|
ade18deb7e | ||
|
|
4e1185f4e5 | ||
|
|
6ad8da42be | ||
|
|
4aa6bb579f | ||
|
|
e83aa9367e | ||
|
|
04c44f36b1 | ||
|
|
a40363d3e6 | ||
|
|
13e6863678 | ||
|
|
b0d0d6b107 | ||
|
|
085caff660 | ||
|
|
fe3756db9b | ||
|
|
bf33f0c60d | ||
|
|
72f3a5df3e | ||
|
|
f452611b87 | ||
|
|
36d5a3e4de |
14
CHANGELOG.md
14
CHANGELOG.md
@ -1,4 +1,18 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
## v0.3.3
|
||||||
|
### Changed
|
||||||
|
- Change the log level of error "mips unsub internal error, 4, None". [#1135](https://github.com/XiaoMi/ha_xiaomi_home/pull/1135)
|
||||||
|
- Add necessary logs for distinguishing the set_properties command source. [#1160](https://github.com/XiaoMi/ha_xiaomi_home/pull/1160)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fix tofan.airrtc.wk01 thermostat and air conditioner service. [#1160](https://github.com/XiaoMi/ha_xiaomi_home/pull/1160)
|
||||||
|
- Fix mrbond.airer.m1t closing status. [#1134](https://github.com/XiaoMi/ha_xiaomi_home/pull/1134)
|
||||||
|
- Fix the MIoT-Spec-V2 of xiaomi.fan.p69 fan service, ainice.sensor_occupy.3b people number, cykj.hood.jyj22 ventilation switch status, xiaomi.fan.p43 fan level, zhimi.airp.ua1a pm10 density, 090615.switch.x1tpm switch status, dmaker.fan.p33 fan-level. [#1132](https://github.com/XiaoMi/ha_xiaomi_home/pull/1132)
|
||||||
|
- Fix cubee.airrtc.th123e and cubee.airrtc.th123w MIoT-Spec-V2 instance descriptions in Russian.
|
||||||
|
- Fix ijai.vacuum.v1 suction-state value-list descriptions in Chinese.
|
||||||
|
- Fix the misuse of Chinese brackets in multi_lang.json.
|
||||||
|
- The unit of the humidity-range property of xiaomi.aircondition.mt0, xiaomi.aircondition.c35, xiaomi.aircondition.c24 and xiaomi.aircondition.c20 is "none". [#1187](https://github.com/XiaoMi/ha_xiaomi_home/pull/1187)
|
||||||
|
|
||||||
## v0.3.2
|
## v0.3.2
|
||||||
> Xiaomi Home has been added to the Home Assistant Community Store (HACS) as a default since May 8, 2025.
|
> Xiaomi Home has been added to the Home Assistant Community Store (HACS) as a default since May 8, 2025.
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
"cryptography",
|
"cryptography",
|
||||||
"psutil"
|
"psutil"
|
||||||
],
|
],
|
||||||
"version": "v0.3.2",
|
"version": "v0.3.3",
|
||||||
"zeroconf": [
|
"zeroconf": [
|
||||||
"_miot-central._tcp.local."
|
"_miot-central._tcp.local."
|
||||||
]
|
]
|
||||||
|
|||||||
@ -181,6 +181,13 @@
|
|||||||
"service:002:property:003": "光照强度"
|
"service:002:property:003": "光照强度"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"urn:miot-spec-v2:device:switch:0000A003:090615-x1tpm": {
|
||||||
|
"en": {
|
||||||
|
"service:027:property:001": "Fan Switch",
|
||||||
|
"service:027:property:003": "Light Switch",
|
||||||
|
"service:027:property:004": "Fan and Light Switch"
|
||||||
|
}
|
||||||
|
},
|
||||||
"urn:miot-spec-v2:device:switch:0000A003:lumi-acn040": {
|
"urn:miot-spec-v2:device:switch:0000A003:lumi-acn040": {
|
||||||
"en": {
|
"en": {
|
||||||
"service:011": "Right Button On and Off",
|
"service:011": "Right Button On and Off",
|
||||||
|
|||||||
@ -1,6 +1,18 @@
|
|||||||
urn:miot-spec-v2:device:air-condition-outlet:0000A045:lumi-mcn04:1:
|
urn:miot-spec-v2:device:air-condition-outlet:0000A045:lumi-mcn04:1:
|
||||||
prop.3.4:
|
prop.3.4:
|
||||||
format: uint8
|
format: uint8
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c20:1:
|
||||||
|
prop.10.6:
|
||||||
|
unit: none
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c20:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c20:1
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c24:1:
|
||||||
|
prop.10.6:
|
||||||
|
unit: none
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c24:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c24:1
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c35:1:
|
||||||
|
prop.10.6:
|
||||||
|
unit: none
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c35:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c35:1
|
||||||
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: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: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:3: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||||
@ -9,6 +21,11 @@ urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:5: urn:miot-spec-v2:d
|
|||||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6:
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6:
|
||||||
prop.10.6:
|
prop.10.6:
|
||||||
unit: none
|
unit: none
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:7: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-mt0:1:
|
||||||
|
prop.10.6:
|
||||||
|
unit: none
|
||||||
|
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-mt0:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-mt0:1
|
||||||
urn:miot-spec-v2:device:air-monitor:0000A008:cgllc-s1:1:
|
urn:miot-spec-v2:device:air-monitor:0000A008:cgllc-s1:1:
|
||||||
prop.2.5:
|
prop.2.5:
|
||||||
name: voc-density
|
name: voc-density
|
||||||
@ -58,6 +75,15 @@ urn:miot-spec-v2:device:bath-heater:0000A028:opple-acmoto:1:
|
|||||||
urn:miot-spec-v2:device:bath-heater:0000A028:xiaomi-s1:1:
|
urn:miot-spec-v2:device:bath-heater:0000A028:xiaomi-s1:1:
|
||||||
prop.4.4:
|
prop.4.4:
|
||||||
name: fan-level-ventilation
|
name: fan-level-ventilation
|
||||||
|
urn:miot-spec-v2:device:fan:0000A005:dmaker-p33:1:
|
||||||
|
prop.2.2:
|
||||||
|
name: fan-level-a
|
||||||
|
prop.2.6:
|
||||||
|
name: fan-level
|
||||||
|
access:
|
||||||
|
- read
|
||||||
|
- write
|
||||||
|
- notify
|
||||||
urn:miot-spec-v2:device:fan:0000A005:dmaker-p5:1:
|
urn:miot-spec-v2:device:fan:0000A005:dmaker-p5:1:
|
||||||
prop.2.4:
|
prop.2.4:
|
||||||
name: fan-level-a
|
name: fan-level-a
|
||||||
|
|||||||
@ -47,29 +47,26 @@ Vacuum entities for Xiaomi Home.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
import re
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.components.vacuum import (
|
from homeassistant.components.vacuum import (StateVacuumEntity,
|
||||||
StateVacuumEntity,
|
VacuumEntityFeature)
|
||||||
VacuumEntityFeature
|
|
||||||
)
|
|
||||||
|
|
||||||
from .miot.const import DOMAIN
|
from .miot.const import DOMAIN
|
||||||
from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData
|
from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData
|
||||||
from .miot.miot_spec import (
|
from .miot.miot_spec import (MIoTSpecAction, MIoTSpecProperty)
|
||||||
MIoTSpecAction,
|
|
||||||
MIoTSpecProperty)
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||||
config_entry.entry_id]
|
config_entry.entry_id]
|
||||||
@ -99,10 +96,12 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
|||||||
_status_map: Optional[dict[int, str]]
|
_status_map: Optional[dict[int, str]]
|
||||||
_fan_level_map: Optional[dict[int, str]]
|
_fan_level_map: Optional[dict[int, str]]
|
||||||
|
|
||||||
def __init__(
|
_device_name: str
|
||||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
|
|
||||||
) -> None:
|
def __init__(self, miot_device: MIoTDevice,
|
||||||
|
entity_data: MIoTEntityData) -> None:
|
||||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||||
|
self._device_name = miot_device.name
|
||||||
self._attr_supported_features = VacuumEntityFeature(0)
|
self._attr_supported_features = VacuumEntityFeature(0)
|
||||||
|
|
||||||
self._prop_status = None
|
self._prop_status = None
|
||||||
@ -121,21 +120,21 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
|||||||
for prop in entity_data.props:
|
for prop in entity_data.props:
|
||||||
if prop.name == 'status':
|
if prop.name == 'status':
|
||||||
if not prop.value_list:
|
if not prop.value_list:
|
||||||
_LOGGER.error(
|
_LOGGER.error('invalid status value_list, %s',
|
||||||
'invalid status value_list, %s', self.entity_id)
|
self.entity_id)
|
||||||
continue
|
continue
|
||||||
self._status_map = prop.value_list.to_map()
|
self._status_map = prop.value_list.to_map()
|
||||||
|
self._attr_supported_features |= VacuumEntityFeature.STATE
|
||||||
self._prop_status = prop
|
self._prop_status = prop
|
||||||
elif prop.name == 'fan-level':
|
elif prop.name == 'fan-level':
|
||||||
if not prop.value_list:
|
if not prop.value_list:
|
||||||
_LOGGER.error(
|
_LOGGER.error('invalid fan-level value_list, %s',
|
||||||
'invalid fan-level value_list, %s', self.entity_id)
|
self.entity_id)
|
||||||
continue
|
continue
|
||||||
self._fan_level_map = prop.value_list.to_map()
|
self._fan_level_map = prop.value_list.to_map()
|
||||||
self._attr_fan_speed_list = list(self._fan_level_map.values())
|
self._attr_fan_speed_list = list(self._fan_level_map.values())
|
||||||
self._attr_supported_features |= VacuumEntityFeature.FAN_SPEED
|
self._attr_supported_features |= VacuumEntityFeature.FAN_SPEED
|
||||||
self._prop_fan_level = prop
|
self._prop_fan_level = prop
|
||||||
|
|
||||||
elif prop.name == 'battery-level':
|
elif prop.name == 'battery-level':
|
||||||
self._attr_supported_features |= VacuumEntityFeature.BATTERY
|
self._attr_supported_features |= VacuumEntityFeature.BATTERY
|
||||||
self._prop_battery_level = prop
|
self._prop_battery_level = prop
|
||||||
@ -155,16 +154,24 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
|||||||
elif action.name == 'stop-and-gocharge':
|
elif action.name == 'stop-and-gocharge':
|
||||||
self._attr_supported_features |= VacuumEntityFeature.RETURN_HOME
|
self._attr_supported_features |= VacuumEntityFeature.RETURN_HOME
|
||||||
self._action_stop_and_gocharge = action
|
self._action_stop_and_gocharge = action
|
||||||
|
|
||||||
elif action.name == 'identify':
|
elif action.name == 'identify':
|
||||||
self._attr_supported_features |= VacuumEntityFeature.LOCATE
|
self._attr_supported_features |= VacuumEntityFeature.LOCATE
|
||||||
self._action_identify = action
|
self._action_identify = action
|
||||||
|
|
||||||
async def async_start(self) -> None:
|
async def async_start(self) -> None:
|
||||||
"""Start or resume the cleaning task."""
|
"""Start or resume the cleaning task."""
|
||||||
if self.state.lower() in ['paused', '暂停中']:
|
try: # VacuumActivity is introduced in HA core 2025.1.0
|
||||||
await self.action_async(action=self._action_continue_sweep)
|
# pylint: disable=import-outside-toplevel
|
||||||
return
|
from homeassistant.components.vacuum import VacuumActivity
|
||||||
|
if (self.activity
|
||||||
|
== VacuumActivity.PAUSED) and self._action_continue_sweep:
|
||||||
|
await self.action_async(action=self._action_continue_sweep)
|
||||||
|
return
|
||||||
|
except ImportError:
|
||||||
|
if self.state and (self.state in {'paused', 'pause'
|
||||||
|
}) and self._action_continue_sweep:
|
||||||
|
await self.action_async(action=self._action_continue_sweep)
|
||||||
|
return
|
||||||
await self.action_async(action=self._action_start_sweep)
|
await self.action_async(action=self._action_start_sweep)
|
||||||
|
|
||||||
async def async_stop(self, **kwargs: Any) -> None:
|
async def async_stop(self, **kwargs: Any) -> None:
|
||||||
@ -179,31 +186,92 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
|||||||
"""Set the vacuum cleaner to return to the dock."""
|
"""Set the vacuum cleaner to return to the dock."""
|
||||||
await self.action_async(action=self._action_stop_and_gocharge)
|
await self.action_async(action=self._action_stop_and_gocharge)
|
||||||
|
|
||||||
async def async_clean_spot(self, **kwargs: Any) -> None:
|
|
||||||
"""Perform a spot clean-up."""
|
|
||||||
|
|
||||||
async def async_locate(self, **kwargs: Any) -> None:
|
async def async_locate(self, **kwargs: Any) -> None:
|
||||||
"""Locate the vacuum cleaner."""
|
"""Locate the vacuum cleaner."""
|
||||||
await self.action_async(action=self._action_identify)
|
await self.action_async(action=self._action_identify)
|
||||||
|
|
||||||
async def async_set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
|
async def async_set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
|
||||||
"""Set fan speed."""
|
"""Set fan speed."""
|
||||||
|
fan_level_value = self.get_map_key(map_=self._fan_level_map,
|
||||||
|
value=fan_speed)
|
||||||
|
await self.set_property_async(prop=self._prop_fan_level,
|
||||||
|
value=fan_level_value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> Optional[str]:
|
||||||
|
"""Name of the vacuum entity."""
|
||||||
|
return self._device_name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self) -> Optional[str]:
|
def state(self) -> Optional[str]:
|
||||||
"""Return the current state of the vacuum cleaner."""
|
"""Return the current state of the vacuum cleaner.
|
||||||
return self.get_map_value(
|
|
||||||
map_=self._status_map,
|
To fix the HA warning below:
|
||||||
key=self.get_prop_value(prop=self._prop_status))
|
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.
|
||||||
|
"""
|
||||||
|
return self.activity
|
||||||
|
|
||||||
|
@property
|
||||||
|
def activity(self) -> Optional[str]:
|
||||||
|
"""The current vacuum activity."""
|
||||||
|
status = self.get_prop_value(prop=self._prop_status)
|
||||||
|
if status is None:
|
||||||
|
return None
|
||||||
|
status_value = self.get_map_value(map_=self._status_map, key=status)
|
||||||
|
if status_value is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
# pylint: disable=import-outside-toplevel
|
||||||
|
from homeassistant.components.vacuum import VacuumActivity
|
||||||
|
status_value = status_value.lower()
|
||||||
|
status_str = re.sub(r'[^a-z]', '', status_value)
|
||||||
|
if status_str in {
|
||||||
|
'charging', 'charged', 'chargingcompleted', 'fullcharge',
|
||||||
|
'fullpower', 'findchargerpause', 'drying', 'washing',
|
||||||
|
'wash', 'inthewash', 'inthedry', 'stationworking',
|
||||||
|
'dustcollecting', 'upgrade', 'upgrading', 'updating'
|
||||||
|
}:
|
||||||
|
return VacuumActivity.DOCKED
|
||||||
|
if status_str in {'paused', 'pause'}:
|
||||||
|
return VacuumActivity.PAUSED
|
||||||
|
if status_str in {
|
||||||
|
'gocharging', 'cleancompletegocharging', 'findchargewash',
|
||||||
|
'backtowashmop', 'gowash', 'gowashing', 'summon'
|
||||||
|
}:
|
||||||
|
return VacuumActivity.RETURNING
|
||||||
|
if (status_str.find('sweeping')
|
||||||
|
!= -1) or (status_str.find('mopping')
|
||||||
|
!= -1) or (status_str in {
|
||||||
|
'cleaning', 'remoteclean', 'continuesweep',
|
||||||
|
'busy', 'building', 'buildingmap', 'mapping'
|
||||||
|
}):
|
||||||
|
return VacuumActivity.CLEANING
|
||||||
|
if status_str in {'error', 'breakcharging', 'gochargebreak'}:
|
||||||
|
return VacuumActivity.ERROR
|
||||||
|
return VacuumActivity.IDLE
|
||||||
|
except ImportError:
|
||||||
|
return status_value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def battery_level(self) -> Optional[int]:
|
def battery_level(self) -> Optional[int]:
|
||||||
"""Return the current battery level of the vacuum cleaner."""
|
"""The current battery level of the vacuum cleaner."""
|
||||||
return self.get_prop_value(prop=self._prop_battery_level)
|
return self.get_prop_value(prop=self._prop_battery_level)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fan_speed(self) -> Optional[str]:
|
def fan_speed(self) -> Optional[str]:
|
||||||
"""Return the current fan speed of the vacuum cleaner."""
|
"""The current fan speed of the vacuum cleaner."""
|
||||||
return self.get_map_value(
|
return self.get_map_value(
|
||||||
map_=self._fan_level_map,
|
map_=self._fan_level_map,
|
||||||
key=self.get_prop_value(prop=self._prop_fan_level))
|
key=self.get_prop_value(prop=self._prop_fan_level))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user