mirror of
https://github.com/XiaoMi/ha_xiaomi_home.git
synced 2025-11-21 03:28:57 +08:00
Compare commits
67 Commits
zhimi.fan.
...
v0.4.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7abc20dcb5 | ||
|
|
3e33804477 | ||
|
|
551b5cc938 | ||
|
|
f49e76937c | ||
|
|
a1a216aea6 | ||
|
|
1ec325c9c7 | ||
|
|
c04fa542a3 | ||
|
|
fbddaf80a7 | ||
|
|
a11c3e2fda | ||
|
|
739998211e | ||
|
|
ec833b6539 | ||
|
|
f2200ba003 | ||
|
|
073cdf2dcb | ||
|
|
0f65635342 | ||
|
|
947169f18d | ||
|
|
65a7a6d22a | ||
|
|
c29f7eecbd | ||
|
|
58c671483e | ||
|
|
7c97b85f02 | ||
|
|
3f2c2a648b | ||
|
|
f11b2f2f68 | ||
|
|
f3abbef94c | ||
|
|
dae63657d7 | ||
|
|
3cc66450bd | ||
|
|
8cbb451153 | ||
|
|
0fee02ae5c | ||
|
|
580ff87e7f | ||
|
|
94583a23d1 | ||
|
|
925cf3b90f | ||
|
|
836bd01ead | ||
|
|
4ad040d2ea | ||
|
|
981429670a | ||
|
|
a82fd86c60 | ||
|
|
df3faea257 | ||
|
|
e09676661c | ||
|
|
aebeaf0245 | ||
|
|
4c2e10038c | ||
|
|
9afc62f39a | ||
|
|
b46805b92c | ||
|
|
a43447ef61 | ||
|
|
e5165f34da | ||
|
|
9fbbb26d33 | ||
|
|
5b1d003bb2 | ||
|
|
6069eaaba8 | ||
|
|
fd57e7c565 | ||
|
|
096b33f3c9 | ||
|
|
664787ca58 | ||
|
|
d659d13e49 | ||
|
|
3402587b1c | ||
|
|
028399c0b1 | ||
|
|
5179e97e38 | ||
|
|
9fdbf3dff2 | ||
|
|
d0508ead25 | ||
|
|
d05bdcbba9 | ||
|
|
a4f9c29b6b | ||
|
|
62dd32a132 | ||
|
|
1bd338639b | ||
|
|
6a2534934c | ||
|
|
d06a564917 | ||
|
|
23cc1130fe | ||
|
|
a83ad60b38 | ||
|
|
00f24bd3e1 | ||
|
|
f384034854 | ||
|
|
b0204ad9b7 | ||
|
|
b4ece958ac | ||
|
|
db77af8a13 | ||
|
|
a9f1fc630d |
4
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -5,8 +5,8 @@ body:
|
||||
attributes:
|
||||
label: Describe the Bug / 描述问题
|
||||
description: |
|
||||
> A clear and concise description of what the bug is.
|
||||
> 清晰且简明地描述问题。
|
||||
> A clear and concise description of what the bug is. Please include the device model information (Like xiaomi.gateway.hub1 which can be found in Device info page).
|
||||
> 清晰且简明地描述问题。请注明设备 model 信息(例如 xiaomi.gateway.hub1,可在设备详情页查询)。
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
107
CHANGELOG.md
107
CHANGELOG.md
@@ -1,4 +1,110 @@
|
||||
# CHANGELOG
|
||||
## v0.4.4
|
||||
### Added
|
||||
- Add Turkish language support. [#1468](https://github.com/XiaoMi/ha_xiaomi_home/pull/1468)
|
||||
### Fixed
|
||||
- Stop MQTT internal loop immediately when main loop is closed. [#1465](https://github.com/XiaoMi/ha_xiaomi_home/pull/1465)
|
||||
- Fix the float value precision. [#1485](https://github.com/XiaoMi/ha_xiaomi_home/pull/1485)
|
||||
- Fix the climate entity swing mode setting. [#1486](https://github.com/XiaoMi/ha_xiaomi_home/pull/1486)
|
||||
- Fix the MIoT-Spec-V2 of cykj.hood.jyj22 urn version 4, lumi.motion.bmgl01 siid=2 piid=2 value-list, ykcn.valve.cbcs power property value unit, ainice.sensor_occupy.3b people-number property and qdhkl.airc.a42 hvac mode. [#1496](https://github.com/XiaoMi/ha_xiaomi_home/pull/1496)
|
||||
|
||||
## v0.4.3
|
||||
### Changed
|
||||
- Remove `VacuumEntityFeature.BATTERY` from the vacuum entity. [#1433](https://github.com/XiaoMi/ha_xiaomi_home/pull/1433)
|
||||
- Subscribe the proxy gateway child device up messages even though the device is offline. [#1393](https://github.com/XiaoMi/ha_xiaomi_home/pull/1393)
|
||||
### Fixed
|
||||
- Fix the integer value step. [#1388](https://github.com/XiaoMi/ha_xiaomi_home/pull/1388)
|
||||
- Fix the contact-state property value format. [#1387](https://github.com/XiaoMi/ha_xiaomi_home/pull/1387)
|
||||
- Fix the MIoT-Spec-V2 of xiaomi.airc.rr0r00 swing mode and hyd.airer.lyjpro current-position. [#1394](https://github.com/XiaoMi/ha_xiaomi_home/pull/1394)
|
||||
- Fix roidmi.vacuum.v60 siid=2 aiid=3 out field format.
|
||||
- Ignore unsupported properties of xiaomi.wifispeaker.l15a and 759413.aircondition.iez.
|
||||
- Add an alongside button entity for xiaomi.wifispeaker.l05b play action.
|
||||
- Add zhimi.fan.za1 fan mode description in zh_Hans.
|
||||
- Fix the error reported by pylint-4.0.0. [#1455](https://github.com/XiaoMi/ha_xiaomi_home/pull/1455)
|
||||
|
||||
## v0.4.2
|
||||
### Changed
|
||||
- Set the battery service's start-charge action as the fallback action to support RETURN_HOME feature of the vacuum entity. [#1344](https://github.com/XiaoMi/ha_xiaomi_home/pull/1344)
|
||||
### Fixed
|
||||
- Correct the property value format after expression calculation. [#1366](https://github.com/XiaoMi/ha_xiaomi_home/pull/1366)
|
||||
- Fix the MIoT-Spec-V2 of xiaomi.fan.p70 and xiaomi.fan.p76 fan level, xiaomi.airc.rr0r00 and xiaomi.airc.h43h00 humidity-range, and zhimi.humidifier.ca4 water level. [#1367](https://github.com/XiaoMi/ha_xiaomi_home/pull/1367)
|
||||
- Ignore the unsupported model hmpace.motion.v6nfc.
|
||||
- Delete all unsupported MIoT-Spec-V2 instances of narwa.vacuum.001 and narwa.vacuum.ax11. [#1355](https://github.com/XiaoMi/ha_xiaomi_home/pull/1355)
|
||||
|
||||
## v0.4.1
|
||||
### Changed
|
||||
- The setting option "Cover closed position" in CONFIGURE is changed to "Cover dead zone width". [#1301](https://github.com/XiaoMi/ha_xiaomi_home/pull/1301)
|
||||
- Add an alongside switch entity for 090615.aircondition.ktf and juhl.aircondition.hvac. [#1303](https://github.com/XiaoMi/ha_xiaomi_home/pull/1303)
|
||||
### Fixed
|
||||
- Fix the vacuum status so that the vacuum activity will not always be idle. [#1299](https://github.com/XiaoMi/ha_xiaomi_home/pull/1299)
|
||||
- Set the device on when the switch status is False or None. [#1303](https://github.com/XiaoMi/ha_xiaomi_home/pull/1303)
|
||||
- Hide sensitive info in printing logs. [#1328](https://github.com/XiaoMi/ha_xiaomi_home/pull/1328)
|
||||
- Fix the MIoT-Spec-V2 of cuco.plug.cp2d electric current, xiaomi.fan.p45 fan level, sanmei.valve.s1 power consumption, current and voltage, xiaomi.aircondition.c17, xiaomi.aircondition.m16 and xiaomi.airc.h40h00 humidity-range unit. [#1329](https://github.com/XiaoMi/ha_xiaomi_home/pull/1329)
|
||||
|
||||
## v0.4.0
|
||||
### Added
|
||||
- Add the watch as the device tracker entity. [#1189](https://github.com/XiaoMi/ha_xiaomi_home/pull/1189)
|
||||
- Add the wifi speaker and the television as the media player entity. [#706](https://github.com/XiaoMi/ha_xiaomi_home/pull/706)
|
||||
- Add an option in CONFIGURE to set the cover closed position. [#1242](https://github.com/XiaoMi/ha_xiaomi_home/pull/1242)
|
||||
- Add notifications to show the status of the local connection to the central hub gateway. [#1280](https://github.com/XiaoMi/ha_xiaomi_home/pull/1280)
|
||||
- Import the device from the third party cloud. [#1258](https://github.com/XiaoMi/ha_xiaomi_home/pull/1258)
|
||||
### Changed
|
||||
- Add an alongside switch entity for viomi.waterheater.m1. [#1255](https://github.com/XiaoMi/ha_xiaomi_home/pull/1255)
|
||||
- Do not subscribe BLE device online/offline state message. [#1264](https://github.com/XiaoMi/ha_xiaomi_home/pull/1264)
|
||||
### Fixed
|
||||
- Keep the first element of the discovered ip address list as the recently added address when getting mdns result. [#1250](https://github.com/XiaoMi/ha_xiaomi_home/pull/1250)
|
||||
- Subscribe local topics every time when connected to the central hub gateway. [#1266](https://github.com/XiaoMi/ha_xiaomi_home/pull/1266)
|
||||
- Record the "closing" and "closed" status that occur frequently in the motor-controller, the window-opener and the curtain service. [#1262](https://github.com/XiaoMi/ha_xiaomi_home/pull/1262)
|
||||
- Fix xiaomi.aircondition.c24 total power consumption unit, adp.motor.adswb4 motor switch, cgllc.airm.cgd1st environment temperature, and shhf.light.sflt11 fan switch status. [#1256](https://github.com/XiaoMi/ha_xiaomi_home/pull/1256)
|
||||
|
||||
## v0.3.4
|
||||
### Added
|
||||
- Exclude the unsupported device models. [#1205](https://github.com/XiaoMi/ha_xiaomi_home/pull/1205)
|
||||
### Changed
|
||||
- Subscribe the BLE device upstream messages even though the device is offline. [#1207](https://github.com/XiaoMi/ha_xiaomi_home/pull/1207)
|
||||
- Record "opening", "closing" and "closed" status of the airer service that occur frequently and do not record "stop" status for the cover entity. [#1235](https://github.com/XiaoMi/ha_xiaomi_home/pull/1235)
|
||||
- Modify README about spec_filter.yaml and the event attributes. [#1237](https://github.com/XiaoMi/ha_xiaomi_home/pull/1237)
|
||||
### Fixed
|
||||
- Fix the reconnect delay time to be reset when the client is connected to the broker. [#1200](https://github.com/XiaoMi/ha_xiaomi_home/pull/1200)
|
||||
- Fix the HA warning in the logs related to vacuum state setting. [#694](https://github.com/XiaoMi/ha_xiaomi_home/pull/694)
|
||||
- Fix the operation mode when the device does not have a mode property. [#1199](https://github.com/XiaoMi/ha_xiaomi_home/pull/1199)
|
||||
- Fix 090615.aircondition.ktf environment temperature. [#1210](https://github.com/XiaoMi/ha_xiaomi_home/pull/1210)
|
||||
- Fix a missing variable in translation it.json. [#1215](https://github.com/XiaoMi/ha_xiaomi_home/pull/1215)
|
||||
- Fix yutai.plug.fsov8m power consumption and ignore bjkcz.curtain.kczble curtain status. [#1236](https://github.com/XiaoMi/ha_xiaomi_home/pull/1236)
|
||||
|
||||
## 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
|
||||
> Xiaomi Home has been added to the Home Assistant Community Store (HACS) as a default since May 8, 2025.
|
||||
### Added
|
||||
- Modify MIoT-Spec-V2 property format by spec_modify.yaml. [#1111](https://github.com/XiaoMi/ha_xiaomi_home/pull/1111)
|
||||
### Changed
|
||||
- Update the instructions of Xiaomi Home integration installation from HACS. [#102](https://github.com/XiaoMi/ha_xiaomi_home/pull/102) [#1088](https://github.com/XiaoMi/ha_xiaomi_home/pull/1088)
|
||||
- Add an alongside switch entity for zimi.waterheater.h03 and xiaomi.waterheater.yms2. [#1115](https://github.com/XiaoMi/ha_xiaomi_home/pull/1115)
|
||||
### Fixed
|
||||
- Fix Chinese encoding in LAN Control. [#1114](https://github.com/XiaoMi/ha_xiaomi_home/pull/1114)
|
||||
- Fix the MIoT-Spec-V2 of lxzn.switch.jcbcsm power consumption, voltage and current, shhf.light.sfla10 fan direction, zhimi.fan.za4 fan-level, zhimi.fan.sa1 fan-level. [#1110](https://github.com/XiaoMi/ha_xiaomi_home/pull/1110)
|
||||
- Revise the Chinese descriptions of loock.lock.t2pv1 door state value-list. [#1110](https://github.com/XiaoMi/ha_xiaomi_home/pull/1110)
|
||||
|
||||
## v0.3.1
|
||||
### Changed
|
||||
- Setting the fan speed level when the fan is off will turning the fan on first. [#1031](https://github.com/XiaoMi/ha_xiaomi_home/pull/1031)
|
||||
### Fixed
|
||||
- Fix update device list error when there is no shared devices. [#1024](https://github.com/XiaoMi/ha_xiaomi_home/pull/1024)
|
||||
- Fix the humidifier get_prop_value error when the property is None. [#1035](https://github.com/XiaoMi/ha_xiaomi_home/pull/1035)
|
||||
- Fix the MIoT-Spec-V2 of zhimi.fan.v3 fan-level, cuco.plug.cp1md voltage and current, zimi.plug.zncz01 electric-power, giot.plug.v8icm power-consumption unit, yunmi.kettle.r3 tds unit, and dmaker.fan.p5 fan-level. [#1037](https://github.com/XiaoMi/ha_xiaomi_home/pull/1037)
|
||||
|
||||
## v0.3.0
|
||||
注意:v0.3.0 变更了部分实体 unique_id 的生成规则,如果勾选 xiaomi_home > 配置 > 更新实体转换规则,会导致部分实体已配置的自动化失效。如果想要避免重新配置大量自动化,可使用这个[补丁](https://github.com/XiaoMi/ha_xiaomi_home/pull/972)。
|
||||
|
||||
@@ -7,7 +113,6 @@ CAUTION: v0.3.0 changes the unique_id of some entities. If you check the option
|
||||
- Import the devices in the shared homes and the separated shared devices. [#1021](https://github.com/XiaoMi/ha_xiaomi_home/pull/1021)
|
||||
- Support _attr_hvac_action of the climate entity. [#956](https://github.com/XiaoMi/ha_xiaomi_home/pull/956)
|
||||
- Add custom defined MIoT-Spec-V2 instance via spec_add.json. [#953](https://github.com/XiaoMi/ha_xiaomi_home/pull/953)
|
||||
|
||||
### Fixed
|
||||
- Ignore 'Event loop is closed' when unsub a closed event loop. [#991](https://github.com/XiaoMi/ha_xiaomi_home/pull/991)
|
||||
- Fix contact-state for linp.magnet.m1 and loock.safe.v1. [#977](https://github.com/XiaoMi/ha_xiaomi_home/pull/977)
|
||||
|
||||
192
CLAUDE.md
Normal file
192
CLAUDE.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Xiaomi Home Integration is an official Home Assistant integration for controlling Xiaomi IoT smart devices. It connects to devices via Xiaomi Cloud (MQTT) or locally through Xiaomi Central Hub Gateway. The integration converts MIoT-Spec-V2 device specifications into Home Assistant entities.
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Installation & Setup
|
||||
```bash
|
||||
# Install to Home Assistant config directory
|
||||
./install.sh /path/to/config
|
||||
|
||||
# Install test dependencies
|
||||
pip install pytest pytest-asyncio pytest-dependency zeroconf paho.mqtt psutil cryptography slugify
|
||||
```
|
||||
|
||||
### Testing
|
||||
```bash
|
||||
# Run all tests
|
||||
pytest -v -s -m github ./test/
|
||||
|
||||
# Run specific test files
|
||||
pytest -v -s ./test/test_spec.py
|
||||
pytest -v -s ./test/test_cloud.py
|
||||
pytest -v -s ./test/test_lan.py
|
||||
|
||||
# Check rule format
|
||||
pytest -v -s -m github ./test/check_rule_format.py
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
# Run pylint (follows Google Python Style Guide)
|
||||
pylint $(git ls-files '*.py')
|
||||
|
||||
# Lint specific files
|
||||
pylint custom_components/xiaomi_home/*.py
|
||||
```
|
||||
|
||||
### Validation
|
||||
```bash
|
||||
# HACS validation (run by GitHub Actions)
|
||||
# Uses: hacs/action@main
|
||||
|
||||
# Hassfest validation (run by GitHub Actions)
|
||||
# Uses: home-assistant/actions/hassfest@master
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Core Components (miot/)
|
||||
|
||||
The integration is built around the `miot/` core package:
|
||||
|
||||
**miot_client.py**: Top-level client instance representing a logged-in Xiaomi user. Each user login creates one MIoTClient. Manages authentication, device list, and message routing.
|
||||
|
||||
**miot_cloud.py**: OAuth 2.0 authentication and HTTP API calls to Xiaomi Cloud. Handles token refresh, user info, device control commands, and spec downloads.
|
||||
|
||||
**miot_mips.py**: Message bus (MQTT) for subscribing to device property changes and events. Implements both cloud (MipsCloudClient) and local (MipsLocalClient) message handling.
|
||||
|
||||
**miot_device.py**: Device entity class. Each MIoT device creates multiple MIoTDevice instances (one per Home Assistant entity). Handles property updates, action execution, and event processing.
|
||||
|
||||
**miot_spec.py**: MIoT-Spec-V2 parser. Parses device specifications (URN-based type system) from cloud or local cache. Each spec defines services, properties, events, and actions.
|
||||
|
||||
**miot_lan.py**: Local LAN control for IP devices in same network. Discovery and control without cloud (optional).
|
||||
|
||||
**miot_mdns.py**: mDNS discovery for Xiaomi Central Hub Gateway services.
|
||||
|
||||
**miot_storage.py**: File storage for certificates, device specs, translations, and cached data.
|
||||
|
||||
**miot_network.py**: Network status monitoring and IP address detection.
|
||||
|
||||
**miot_i18n.py**: Multi-language support (13 languages). Manages translations for entity names.
|
||||
|
||||
### Entity Conversion (specs/specv2entity.py)
|
||||
|
||||
MIoT-Spec-V2 instances are converted to Home Assistant entities using three mapping dictionaries:
|
||||
|
||||
- **SPEC_DEVICE_TRANS_MAP**: Whole-device patterns (e.g., vacuum, humidifier, climate)
|
||||
- **SPEC_SERVICE_TRANS_MAP**: Service-level patterns (e.g., battery, air-purifier)
|
||||
- **SPEC_PROP_TRANS_MAP**: Property-level patterns (e.g., temperature, humidity)
|
||||
|
||||
Conversion priority: Device > Service > Property > General rules
|
||||
|
||||
### Spec Customization Files (miot/specs/)
|
||||
|
||||
**spec_filter.yaml**: Filters out MIoT-Spec-V2 instances that should NOT be converted to entities. Uses device URN keys and supports wildcard matching for service/property/event/action IIDs.
|
||||
|
||||
**spec_modify.yaml**: Modifies spec instances before conversion (e.g., changing value ranges, access modes).
|
||||
|
||||
**multi_lang.json**: Local translation overrides with higher priority than cloud translations. Keyed by device URN (without version).
|
||||
|
||||
**spec_add.json**: Additional spec definitions for devices not in cloud database.
|
||||
|
||||
**bool_trans.yaml**: Boolean value translation mappings.
|
||||
|
||||
After editing spec files, you MUST update conversion rules via Integration CONFIGURE page in Home Assistant.
|
||||
|
||||
### Platform Files (custom_components/xiaomi_home/)
|
||||
|
||||
Standard Home Assistant platform files (sensor.py, switch.py, climate.py, etc.) implement entity registration and state management. Each platform imports from miot_device.py and creates entity subclasses.
|
||||
|
||||
**config_flow.py**: Configuration flow for OAuth login and device selection.
|
||||
|
||||
**__init__.py**: Integration setup, entry management, and data structure initialization.
|
||||
|
||||
## MIoT-Spec-V2 Concepts
|
||||
|
||||
**URN Format**: `urn:<namespace>:<type>:<name>:<value>[:<vendor-product>:<version>]`
|
||||
- namespace: miot-spec-v2 (Xiaomi), bluetooth-spec (SIG), or vendor-specific
|
||||
- type: device, service, property, event, action
|
||||
- name: human-readable identifier (used for mapping)
|
||||
|
||||
**IIDs (Instance IDs)**: Decimal identifiers
|
||||
- siid: Service Instance ID
|
||||
- piid: Property Instance ID
|
||||
- eiid: Event Instance ID
|
||||
- aiid: Action Instance ID
|
||||
|
||||
**Instance Code Format**:
|
||||
```
|
||||
service:<siid> # service
|
||||
service:<siid>:property:<piid> # property
|
||||
service:<siid>:property:<piid>:valuelist:<index> # value list item
|
||||
service:<siid>:event:<eiid> # event
|
||||
service:<siid>:action:<aiid> # action
|
||||
```
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
From CONTRIBUTING.md:
|
||||
|
||||
- **Xiaomi**: Always "Xiaomi" in text. Variables: "xiaomi" or "mi"
|
||||
- **Xiaomi Home**: Always "Xiaomi Home" in text. Variables: "mihome" or "MiHome"
|
||||
- **Xiaomi IoT**: Always "MIoT" in text. Variables: "miot" or "MIoT"
|
||||
- **Home Assistant**: Always "Home Assistant" in text. Variables: "hass" or "hass_xxx"
|
||||
|
||||
Mixed Chinese/English: Add space between Chinese and English or use Chinese quotation marks.
|
||||
|
||||
## Commit Message Format
|
||||
|
||||
```
|
||||
<type>: <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
Types: feat, fix, docs, style, refactor, perf, test, chore, revert
|
||||
|
||||
Subject: Imperative, present tense. Not capitalized. No period.
|
||||
|
||||
Body: Detailed description (mandatory except for docs type).
|
||||
|
||||
## Code Style
|
||||
|
||||
Follow [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html). Use the provided `.pylintrc` for linting.
|
||||
|
||||
## Debugging
|
||||
|
||||
Enable debug logging in Home Assistant configuration.yaml:
|
||||
```yaml
|
||||
logger:
|
||||
default: critical
|
||||
logs:
|
||||
custom_components.xiaomi_home: debug
|
||||
```
|
||||
|
||||
## Control Modes
|
||||
|
||||
- **Cloud Control**: MQTT message subscription + HTTP command API
|
||||
- **Local Control**: Via Xiaomi Central Hub Gateway (firmware 3.3.0_0023+) or LAN control (IP devices only, may be unstable)
|
||||
|
||||
Central gateway local control takes priority over LAN control when both are available.
|
||||
|
||||
## Multi-Region Support
|
||||
|
||||
Regions: China (cn), Europe (eu), India (in), Russia (ru), Singapore (sg), USA (us)
|
||||
|
||||
User data is isolated per region. Integration supports multiple regions in same Home Assistant instance.
|
||||
|
||||
## Important Files Location
|
||||
|
||||
- Integration source: `custom_components/xiaomi_home/`
|
||||
- Spec mappings: `custom_components/xiaomi_home/miot/specs/specv2entity.py`
|
||||
- Spec filters: `custom_components/xiaomi_home/miot/specs/spec_filter.yaml`
|
||||
- Translations: `custom_components/xiaomi_home/translations/` and `custom_components/xiaomi_home/miot/i18n/`
|
||||
- Tests: `test/`
|
||||
70
README.md
70
README.md
@@ -33,9 +33,11 @@ git checkout v1.0.0
|
||||
|
||||
### Method 2: [HACS](https://hacs.xyz/)
|
||||
|
||||
HACS > Overflow Menu > Custom repositories > Repository: https://github.com/XiaoMi/ha_xiaomi_home.git & Category or Type: Integration > ADD > Xiaomi Home in New or Available for download section of HACS > DOWNLOAD
|
||||
One-click installation from HACS:
|
||||
|
||||
> Xiaomi Home has not been added to the HACS store as a default yet. It's coming soon.
|
||||
[](https://my.home-assistant.io/redirect/hacs_repository/?owner=XiaoMi&repository=ha_xiaomi_home&category=integration)
|
||||
|
||||
Or, HACS > In the search box, type **Xiaomi Home** > Click **Xiaomi Home**, getting into the detail page > DOWNLOAD
|
||||
|
||||
### Method 3: Manually installation via [Samba](https://github.com/home-assistant/addons/tree/master/samba) / [FTPS](https://github.com/hassio-addons/addon-ftp)
|
||||
|
||||
@@ -47,7 +49,7 @@ Download and copy `custom_components/xiaomi_home` folder to `config/custom_compo
|
||||
|
||||
[Settings > Devices & services > ADD INTEGRATION](https://my.home-assistant.io/redirect/brand/?brand=xiaomi_home) > Search `Xiaomi Home` > NEXT > Click here to login > Sign in with Xiaomi account
|
||||
|
||||
[](https://my.home-assistant.io/redirect/config_flow_start/?domain=xiaomi_home)
|
||||
[](https://my.home-assistant.io/redirect/config_flow_start/?domain=xiaomi_home)
|
||||
|
||||
### Add MIoT Devices
|
||||
|
||||
@@ -59,7 +61,7 @@ After a Xiaomi account login and its user configuration are completed, you can c
|
||||
|
||||
Method: [Settings > Devices & services > Configured > Xiaomi Home](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home) > ADD HUB > NEXT > Click here to login > Sign in with Xiaomi account
|
||||
|
||||
[](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home)
|
||||
[](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home)
|
||||
|
||||
### Update Configurations
|
||||
|
||||
@@ -81,9 +83,9 @@ Xiaomi Home Integration and the affiliated cloud interface is provided by Xiaomi
|
||||
|
||||
## FAQ
|
||||
|
||||
- Does Xiaomi Home Integration support all Xiaomi Home devices?
|
||||
- Does Xiaomi Home Integration support all Xiaomi smart devices?
|
||||
|
||||
Xiaomi Home Integration currently supports most categories of Home device. Only a few categories are not supported. They are Bluetooth device, infrared device and virtual device.
|
||||
Xiaomi Home Integration currently supports most categories of the smart device. Only a few categories are not supported. They are Bluetooth device, infrared device and virtual device.
|
||||
|
||||
- Does Xiaomi Home Integration support multiple Xiaomi accounts?
|
||||
|
||||
@@ -91,7 +93,7 @@ Xiaomi Home Integration and the affiliated cloud interface is provided by Xiaomi
|
||||
|
||||
- Does Xiaomi Home Integration support local control?
|
||||
|
||||
Local control is implemented by [Xiaomi Central Hub Gateway](https://www.mi.com/shop/buy/detail?product_id=15755&cfrom=search) (firmware version 3.4.0_0000 above) or Xiaomi home devices with built-in central hub gateway (software version 0.8.0 above) inside. If you do not have a Xiaomi central hub gateway or other devices having central hub gateway function, all control commands are sent through Xiaomi Cloud. The firmware for Xiaomi central hub gateway including the built-in central hub gateway supporting Home Assistant local control feature has not been released yet. Please refer to MIoT team's notification for upgrade plans.
|
||||
Local control is implemented by [Xiaomi Central Hub Gateway](https://www.mi.com/shop/buy/detail?product_id=15755&cfrom=search) (firmware version 3.3.0_0023 and above) or Xiaomi smart devices with built-in central hub gateway (software version 0.8.9 and above) inside. If you do not have a Xiaomi central hub gateway or other devices having central hub gateway function, all control commands are sent through Xiaomi Cloud. The firmware for Xiaomi central hub gateway including the built-in central hub gateway supporting Home Assistant local control feature has not been released yet. Please refer to MIoT team's notification for upgrade plans.
|
||||
|
||||
Xiaomi central hub gateway is only available in mainland China. In other regions, it is not available.
|
||||
|
||||
@@ -153,6 +155,8 @@ In MIoT-Spec-V2 protocol, a product is defined as a device. A device contains se
|
||||
|
||||
MIoT-Spec-V2 event is transformed to Event entity in Home Assistant. The event's parameters are also passed to entity's `_trigger_event`.
|
||||
|
||||
MIoT-Spec-V2 event's arguments field is the list of parameters of the event. The list elements represent the piid of the property in the same service. For example, the [MIoT-Spec-V2](http://poc.miot-spec.srv/miot-spec-v2/instance?type=urn:miot-spec-v2:device:remote-control:0000A021:xiaomi-mcn002:1:0000D057) of the Xiaomi Wireless Double-key Switch contains the siid=2 Switch Sensor service. The eiid=1014 Long Press event of the service is triggered when a button is long pressed. The debug level log will print `Press and hold, attributes: {'Button Type': 1}`. This is an example log that the button type is 1, which means the right button is long pressed.
|
||||
|
||||
- Action
|
||||
|
||||
| in | Entity in Home Assistant |
|
||||
@@ -287,46 +291,44 @@ The value of the event instance name indicates `_attr_device_class` of the Home
|
||||
|
||||
### MIoT-Spec-V2 Filter
|
||||
|
||||
`spec_filter.json` is used to filter out the MIoT-Spec-V2 instance that will not be converted to Home Assistant entity.
|
||||
`spec_filter.yaml` is used to filter out the MIoT-Spec-V2 instance that will not be converted to Home Assistant entity.
|
||||
|
||||
The format of `spec_filter.json` is as follows.
|
||||
The format of `spec_filter.yaml` is as follows.
|
||||
|
||||
```
|
||||
{
|
||||
"<MIoT-Spec-V2 device instance>":{
|
||||
"services": list<service_iid: str>,
|
||||
"properties": list<service_iid.property_iid: str>,
|
||||
"events": list<service_iid.event_iid: str>,
|
||||
"actions": list<service_iid.action_iid: str>,
|
||||
}
|
||||
}
|
||||
```yaml
|
||||
<MIoT-Spec-V2 device instance urn without the version field>:
|
||||
services: list<service_iid: str>
|
||||
properties: list<service_iid.property_iid: str>
|
||||
events: list<service_iid.event_iid: str>
|
||||
actions: list<service_iid.action_iid: str>
|
||||
```
|
||||
|
||||
The key of `spec_filter.json` dictionary is the urn excluding the "version" field of the MIoT-Spec-V2 device instance. The firmware of different versions of the same product may be associated with the MIoT-Spec-V2 device instances of different versions. It is required that the MIoT-Spec-V2 instance of a higher version must contain all MIoT-Spec-V2 instances of the lower versions when a vendor defines the MIoT-Spec-V2 of its product on MIoT platform. Thus, the key of `spec_filter.json` does not need to specify the version number of MIoT-Spec-V2 device instance.
|
||||
The key of `spec_filter.yaml` dictionary is the urn excluding the "version" field of the MIoT-Spec-V2 device instance. The firmware of different versions of the same product may be associated with the MIoT-Spec-V2 device instances of different versions. It is required that the MIoT-Spec-V2 instance of a higher version must contain all MIoT-Spec-V2 instances of the lower versions when a vendor defines the MIoT-Spec-V2 of its product on MIoT platform. Thus, the key of `spec_filter.yaml` does not need to specify the version number of MIoT-Spec-V2 device instance.
|
||||
|
||||
The value of "services", "properties", "events" or "actions" fields under "device instance" is the instance id (iid) of the service, property, event or action that will be ignored in the conversion process. Wildcard matching is supported.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
{
|
||||
"urn:miot-spec-v2:device:television:0000A010:xiaomi-rmi1":{
|
||||
"services": ["*"] # Filter out all services. It is equivalent to completely ignoring the device with such MIoT-Spec-V2 device instance.
|
||||
},
|
||||
"urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1": {
|
||||
"services": ["3"], # Filter out the service whose iid=3.
|
||||
"properties": ["4.*"] # Filter out all properties in the service whose iid=4.
|
||||
"events": ["4.1"], # Filter out the iid=1 event in the iid=4 service.
|
||||
"actions": ["4.1"] # Filter out the iid=1 action in the iid=4 service.
|
||||
}
|
||||
}
|
||||
```yaml
|
||||
urn:miot-spec-v2:device:television:0000A010:xiaomi-rmi1:
|
||||
services:
|
||||
- '*' # Filter out all services. It is equivalent to completely ignoring the device with such MIoT-Spec-V2.
|
||||
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:
|
||||
services:
|
||||
- '3' # Filter out the siid=3 service.
|
||||
properties:
|
||||
- '4.*' # Filter out all properties in the siid=4 service.
|
||||
events:
|
||||
- '4.1' # Filter out the eiid=1 event in the siid=4 service.
|
||||
actions:
|
||||
- '4.1' # Filter out the aiid=1 action in the siid=4 service.
|
||||
```
|
||||
|
||||
Device information service (urn:miot-spec-v2:service:device-information:00007801) of all devices will never be converted to Home Assistant entity.
|
||||
|
||||
## Multiple Language Support
|
||||
|
||||
There are 8 languages available for selection in the config flow language option of Xiaomi Home, including Simplified Chinese, Traditional Chinese, English, Spanish, Russian, French, German, and Japanese. The config flow page in Simplified Chinese and English has been manually reviewed by the developer. Other languages are translated by machine translation. If you want to modify the words and sentences in the config flow page, you need to modify the json file of the certain language in `custom_components/xiaomi_home/translations/` and `custom_components/xiaomi_home/miot/i18n/` directory.
|
||||
There are 13 languages available for selection in the config flow language option of Xiaomi Home, including Simplified Chinese, Traditional Chinese, English, Spanish, Russian, French, German, Japanese, Italian, Dutch, Portuguese, Brazilian Portuguese, and Turkish. The config flow page in Simplified Chinese and English has been manually reviewed by the developer. Other languages are translated by machine translation or community contributions. If you want to modify the words and sentences in the config flow page, you need to modify the json file of the certain language in `custom_components/xiaomi_home/translations/` and `custom_components/xiaomi_home/miot/i18n/` directory.
|
||||
|
||||
When displaying Home Assistant entity name, Xiaomi Home downloads the multiple language file configured by the device vendor from MIoT Cloud, which contains translations for MIoT-Spec-V2 instances of the device. `multi_lang.json` is a locally maintained multiple language dictionary, which has a higher priority than the multiple language file obtained from the cloud and can be used to supplement or modify the multiple language translation of devices.
|
||||
|
||||
@@ -344,7 +346,7 @@ The format of `multi_lang.json` is as follows.
|
||||
|
||||
The key of `multi_lang.json` dictionary is the urn excluding the "version" field of the MIoT-Spec-V2 device instance.
|
||||
|
||||
The language code is zh-Hans, zh-Hant, en, es, ru, fr, de, or ja, corresponding to the 8 selectable languages mentioned above.
|
||||
The language code is zh-Hans, zh-Hant, en, es, ru, fr, de, ja, it, nl, pt, pt-BR, or tr, corresponding to the 13 selectable languages mentioned above.
|
||||
|
||||
The instance code is the code of the MIoT-Spec-V2 instance, which is in the format of:
|
||||
|
||||
@@ -374,7 +376,7 @@ Example:
|
||||
}
|
||||
```
|
||||
|
||||
> If you edit `specv2entity.py`, `spec_filter.json` or `multi_lang.json` in the `custom_components/xiaomi_home/miot/specs` directory in your Home Assistant, you need to update the entity conversion rule in the integration's CONFIGURE page to take effect. Method: [Settings > Devices & services > Configured > Xiaomi Home](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home) > CONFIGURE > Update Entity Conversion Rule
|
||||
> If you edit any files in the `custom_components/xiaomi_home/miot/specs` directory (`spec_filter.yaml`, `spec_modify.yaml`, `multi_lang.json`, etc.) in your Home Assistant, you need to update the entity conversion rule in the integration's CONFIGURE page to take effect. Method: [Settings > Devices & services > Configured > Xiaomi Home](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home) > CONFIGURE > Update entity conversion rules
|
||||
|
||||
## Documents
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ async def async_setup_entry(
|
||||
for miot_device in device_list:
|
||||
if miot_device.miot_client.display_binary_bool:
|
||||
for prop in miot_device.prop_list.get('binary_sensor', []):
|
||||
new_entities.append(BinarySensor(
|
||||
miot_device=miot_device, spec=prop))
|
||||
new_entities.append(
|
||||
BinarySensor(miot_device=miot_device, spec=prop))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
@@ -90,7 +90,7 @@ class BinarySensor(MIoTPropertyEntity, BinarySensorEntity):
|
||||
def is_on(self) -> bool:
|
||||
"""On/Off state. True if the binary sensor is on, False otherwise."""
|
||||
if self.spec.name == 'contact-state':
|
||||
return self._value is False
|
||||
return bool(self._value) is False
|
||||
elif self.spec.name == 'occupancy-status':
|
||||
return bool(self._value)
|
||||
return self._value is True
|
||||
|
||||
@@ -320,9 +320,15 @@ class FeatureSwingMode(MIoTServiceEntity, ClimateEntity):
|
||||
await self.set_property_async(prop=self._prop_vertical_swing,
|
||||
value=True)
|
||||
elif swing_mode == SWING_HORIZONTAL:
|
||||
if self._prop_vertical_swing:
|
||||
await self.set_property_async(prop=self._prop_vertical_swing,
|
||||
value=False)
|
||||
await self.set_property_async(prop=self._prop_horizontal_swing,
|
||||
value=True)
|
||||
elif swing_mode == SWING_VERTICAL:
|
||||
if self._prop_horizontal_swing:
|
||||
await self.set_property_async(prop=self._prop_horizontal_swing,
|
||||
value=False)
|
||||
await self.set_property_async(prop=self._prop_vertical_swing,
|
||||
value=True)
|
||||
elif swing_mode == SWING_OFF:
|
||||
@@ -523,6 +529,8 @@ class AirConditioner(FeatureOnOff, FeatureTargetTemperature,
|
||||
self._hvac_mode_map[item.value] = HVACMode.DRY
|
||||
elif item.name in {'fan'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.FAN_ONLY
|
||||
elif item.name in {'heat_cool'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.HEAT_COOL
|
||||
self._attr_hvac_modes = list(self._hvac_mode_map.values())
|
||||
self._prop_mode = prop
|
||||
elif prop.name == 'ac-state':
|
||||
@@ -546,7 +554,7 @@ class AirConditioner(FeatureOnOff, FeatureTargetTemperature,
|
||||
f'{self.entity_id}')
|
||||
return
|
||||
# set the device on
|
||||
if self.get_prop_value(prop=self._prop_on) is False:
|
||||
if self.get_prop_value(prop=self._prop_on) is not True:
|
||||
await self.set_property_async(prop=self._prop_on,
|
||||
value=True,
|
||||
write_ha_state=False)
|
||||
|
||||
@@ -75,6 +75,9 @@ from .miot.const import (
|
||||
DEFAULT_CLOUD_SERVER,
|
||||
DEFAULT_CTRL_MODE,
|
||||
DEFAULT_INTEGRATION_LANGUAGE,
|
||||
DEFAULT_COVER_DEAD_ZONE_WIDTH,
|
||||
MIN_COVER_DEAD_ZONE_WIDTH,
|
||||
MAX_COVER_DEAD_ZONE_WIDTH,
|
||||
DEFAULT_NICK_NAME,
|
||||
DEFAULT_OAUTH2_API_HOST,
|
||||
DOMAIN,
|
||||
@@ -129,6 +132,7 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
_cloud_server: str
|
||||
_integration_language: str
|
||||
_cover_dz_width: int
|
||||
_auth_info: dict
|
||||
_nick_name: str
|
||||
_home_selected: dict
|
||||
@@ -151,6 +155,7 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._main_loop = asyncio.get_running_loop()
|
||||
self._cloud_server = DEFAULT_CLOUD_SERVER
|
||||
self._integration_language = DEFAULT_INTEGRATION_LANGUAGE
|
||||
self._cover_dz_width = DEFAULT_COVER_DEAD_ZONE_WIDTH
|
||||
self._storage_path = ''
|
||||
self._virtual_did = ''
|
||||
self._uid = ''
|
||||
@@ -951,6 +956,7 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
'action_debug': self._action_debug,
|
||||
'hide_non_standard_entities':
|
||||
self._hide_non_standard_entities,
|
||||
'cover_dead_zone_width': self._cover_dz_width,
|
||||
'display_binary_mode': self._display_binary_mode,
|
||||
'display_devices_changed_notify':
|
||||
self._display_devices_changed_notify
|
||||
@@ -995,6 +1001,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
_hide_non_standard_entities: bool
|
||||
_display_binary_mode: list[str]
|
||||
_display_devs_notify: list[str]
|
||||
_cover_dz_width: int
|
||||
|
||||
_oauth_redirect_url_full: str
|
||||
_auth_info: dict
|
||||
@@ -1015,6 +1022,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
_opt_lan_ctrl_cfg: bool
|
||||
_opt_network_detect_cfg: bool
|
||||
_opt_check_network_deps: bool
|
||||
_cover_width_new: int
|
||||
|
||||
_trans_rules_count: int
|
||||
_trans_rules_count_success: int
|
||||
@@ -1043,6 +1051,8 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
self._ctrl_mode = self._entry_data.get('ctrl_mode', DEFAULT_CTRL_MODE)
|
||||
self._integration_language = self._entry_data.get(
|
||||
'integration_language', DEFAULT_INTEGRATION_LANGUAGE)
|
||||
self._cover_dz_width = self._entry_data.get(
|
||||
'cover_dead_zone_width', DEFAULT_COVER_DEAD_ZONE_WIDTH)
|
||||
self._nick_name = self._entry_data.get('nick_name', DEFAULT_NICK_NAME)
|
||||
self._action_debug = self._entry_data.get('action_debug', False)
|
||||
self._hide_non_standard_entities = self._entry_data.get(
|
||||
@@ -1068,6 +1078,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
self._action_debug_new = False
|
||||
self._hide_non_standard_entities_new = False
|
||||
self._display_binary_mode_new = []
|
||||
self._cover_width_new = self._cover_dz_width
|
||||
self._update_user_info = False
|
||||
self._update_devices = False
|
||||
self._update_trans_rules = False
|
||||
@@ -1340,6 +1351,12 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
): cv.multi_select(
|
||||
self._miot_i18n.translate(
|
||||
'config.binary_mode')), # type: ignore
|
||||
vol.Optional(
|
||||
'cover_dead_zone_width',
|
||||
default=self._cover_dz_width # type: ignore
|
||||
): vol.All(vol.Coerce(int), vol.Range(
|
||||
min=MIN_COVER_DEAD_ZONE_WIDTH,
|
||||
max=MAX_COVER_DEAD_ZONE_WIDTH)),
|
||||
vol.Required(
|
||||
'update_trans_rules',
|
||||
default=self._update_trans_rules # type: ignore
|
||||
@@ -1378,6 +1395,8 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
'update_lan_ctrl_config', self._opt_lan_ctrl_cfg)
|
||||
self._opt_network_detect_cfg = user_input.get(
|
||||
'network_detect_config', self._opt_network_detect_cfg)
|
||||
self._cover_width_new = user_input.get(
|
||||
'cover_dead_zone_width', self._cover_dz_width)
|
||||
|
||||
return await self.async_step_update_user_info()
|
||||
|
||||
@@ -1926,6 +1945,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
'nick_name': self._nick_name,
|
||||
'lang_new': INTEGRATION_LANGUAGES[self._lang_new],
|
||||
'nick_name_new': self._nick_name_new,
|
||||
'cover_width_new': self._cover_width_new,
|
||||
'devices_add': len(self._devices_add),
|
||||
'devices_remove': len(self._devices_remove),
|
||||
'trans_rules_count': self._trans_rules_count,
|
||||
@@ -1952,6 +1972,9 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
if self._lang_new != self._integration_language:
|
||||
self._entry_data['integration_language'] = self._lang_new
|
||||
self._need_reload = True
|
||||
if self._cover_width_new != self._cover_dz_width:
|
||||
self._entry_data['cover_dead_zone_width'] = self._cover_width_new
|
||||
self._need_reload = True
|
||||
if self._update_user_info:
|
||||
self._entry_data['nick_name'] = self._nick_name_new
|
||||
if self._update_devices:
|
||||
|
||||
@@ -46,8 +46,9 @@ off Xiaomi or its affiliates' products.
|
||||
Cover entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
import re
|
||||
import logging
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -90,6 +91,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry,
|
||||
class Cover(MIoTServiceEntity, CoverEntity):
|
||||
"""Cover entities for Xiaomi Home."""
|
||||
# pylint: disable=unused-argument
|
||||
_cover_dead_zone_width: int
|
||||
_prop_motor_control: Optional[MIoTSpecProperty]
|
||||
_prop_motor_value_open: Optional[int]
|
||||
_prop_motor_value_close: Optional[int]
|
||||
@@ -97,7 +99,6 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
_prop_status: Optional[MIoTSpecProperty]
|
||||
_prop_status_opening: Optional[list[int]]
|
||||
_prop_status_closing: Optional[list[int]]
|
||||
_prop_status_stop: Optional[list[int]]
|
||||
_prop_status_closed: Optional[list[int]]
|
||||
_prop_current_position: Optional[MIoTSpecProperty]
|
||||
_prop_target_position: Optional[MIoTSpecProperty]
|
||||
@@ -115,6 +116,9 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
self._attr_supported_color_modes = set()
|
||||
self._attr_supported_features = CoverEntityFeature(0)
|
||||
|
||||
self._cover_dead_zone_width = (
|
||||
miot_device.miot_client.cover_dead_zone_width)
|
||||
|
||||
self._prop_motor_control = None
|
||||
self._prop_motor_value_open = None
|
||||
self._prop_motor_value_close = None
|
||||
@@ -122,7 +126,6 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
self._prop_status = None
|
||||
self._prop_status_opening = []
|
||||
self._prop_status_closing = []
|
||||
self._prop_status_stop = []
|
||||
self._prop_status_closed = []
|
||||
self._prop_current_position = None
|
||||
self._prop_target_position = None
|
||||
@@ -159,13 +162,22 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
self.entity_id)
|
||||
continue
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'opening', 'open', 'up'}:
|
||||
item_str: str = item.name
|
||||
item_name: str = re.sub(r'[^a-z]', '', item_str)
|
||||
if item_name in {
|
||||
'opening', 'open', 'up', 'uping', 'rise', 'rising'
|
||||
}:
|
||||
self._prop_status_opening.append(item.value)
|
||||
elif item.name in {'closing', 'close', 'down'}:
|
||||
elif item_name in {
|
||||
'closing', 'close', 'down', 'dowm', 'falling',
|
||||
'fallin', 'dropping', 'downing', 'lower'
|
||||
}:
|
||||
self._prop_status_closing.append(item.value)
|
||||
elif item.name in {'stop', 'stopped', 'pause'}:
|
||||
self._prop_status_stop.append(item.value)
|
||||
elif item.name in {'closed'}:
|
||||
elif item_name in {
|
||||
'closed', 'closeover', 'stopatlowest',
|
||||
'stoplowerlimit', 'lowerlimitstop', 'floor',
|
||||
'lowerlimit'
|
||||
}:
|
||||
self._prop_status_closed.append(item.value)
|
||||
self._prop_status = prop
|
||||
elif prop.name == 'current-position':
|
||||
@@ -263,8 +275,14 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
self._prop_pos_closing = False
|
||||
return self.get_prop_value(prop=self._prop_target_position)
|
||||
pos = self.get_prop_value(prop=self._prop_current_position)
|
||||
return None if pos is None else round(pos * 100 /
|
||||
self._prop_position_value_range)
|
||||
if pos is None:
|
||||
return None
|
||||
pos = round(pos*100/self._prop_position_value_range)
|
||||
if pos <= self._cover_dead_zone_width:
|
||||
pos = 0
|
||||
elif pos >= (100 - self._cover_dead_zone_width):
|
||||
pos = 100
|
||||
return pos
|
||||
|
||||
@property
|
||||
def is_opening(self) -> Optional[bool]:
|
||||
|
||||
126
custom_components/xiaomi_home/device_tracker.py
Normal file
126
custom_components/xiaomi_home/device_tracker.py
Normal file
@@ -0,0 +1,126 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Device tracker entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.device_tracker import TrackerEntity
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('device_tracker', []):
|
||||
new_entities.append(
|
||||
DeviceTracker(miot_device=miot_device, entity_data=data))
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class DeviceTracker(MIoTServiceEntity, TrackerEntity):
|
||||
"""Tracker entities for Xiaomi Home."""
|
||||
_prop_battery_level: Optional[MIoTSpecProperty]
|
||||
_prop_latitude: Optional[MIoTSpecProperty]
|
||||
_prop_longitude: Optional[MIoTSpecProperty]
|
||||
_prop_area_id: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._prop_battery_level = None
|
||||
self._prop_latitude = None
|
||||
self._prop_longitude = None
|
||||
self._prop_area_id = None
|
||||
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'battery-level':
|
||||
self._prop_battery_level = prop
|
||||
elif prop.name == 'latitude':
|
||||
self._prop_latitude = prop
|
||||
elif prop.name == 'longitude':
|
||||
self._prop_longitude = prop
|
||||
elif prop.name == 'area-id':
|
||||
self._prop_area_id = prop
|
||||
|
||||
@property
|
||||
def battery_level(self) -> Optional[int]:
|
||||
"""The battery level of the device."""
|
||||
return None if (self._prop_battery_level
|
||||
is None) else self.get_prop_value(
|
||||
prop=self._prop_battery_level)
|
||||
|
||||
@property
|
||||
def latitude(self) -> Optional[float]:
|
||||
"""The latitude coordinate of the device."""
|
||||
return None if self._prop_latitude is None else self.get_prop_value(
|
||||
prop=self._prop_latitude)
|
||||
|
||||
@property
|
||||
def longitude(self) -> Optional[float]:
|
||||
"""The longitude coordinate of the device."""
|
||||
return None if self._prop_longitude is None else self.get_prop_value(
|
||||
prop=self._prop_longitude)
|
||||
|
||||
@property
|
||||
def location_name(self) -> Optional[str]:
|
||||
"""The location name of the device."""
|
||||
return None if self._prop_area_id is None else self.get_prop_value(
|
||||
prop=self._prop_area_id)
|
||||
@@ -221,7 +221,7 @@ class Fan(MIoTServiceEntity, FanEntity):
|
||||
# preset_mode
|
||||
if preset_mode:
|
||||
await self.set_property_async(
|
||||
self._prop_mode,
|
||||
prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=preset_mode))
|
||||
|
||||
@@ -236,6 +236,9 @@ class Fan(MIoTServiceEntity, FanEntity):
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the percentage of the fan speed."""
|
||||
if percentage > 0:
|
||||
if not self.is_on:
|
||||
# If the fan is off, turn it on.
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
if self._speed_names:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_fan_level,
|
||||
@@ -249,16 +252,13 @@ class Fan(MIoTServiceEntity, FanEntity):
|
||||
value=int(percentage_to_ranged_value(
|
||||
low_high_range=(self._speed_min, self._speed_max),
|
||||
percentage=percentage)))
|
||||
if not self.is_on:
|
||||
# If the fan is off, turn it on.
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
else:
|
||||
await self.set_property_async(prop=self._prop_on, value=False)
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode."""
|
||||
await self.set_property_async(
|
||||
self._prop_mode,
|
||||
prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=preset_mode))
|
||||
|
||||
|
||||
@@ -52,23 +52,22 @@ from typing import Any, Optional
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.humidifier import (
|
||||
HumidifierEntity,
|
||||
HumidifierDeviceClass,
|
||||
HumidifierEntityFeature
|
||||
)
|
||||
from homeassistant.components.humidifier import (HumidifierEntity,
|
||||
HumidifierDeviceClass,
|
||||
HumidifierEntityFeature,
|
||||
HumidifierAction)
|
||||
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity
|
||||
from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
@@ -82,8 +81,8 @@ async def async_setup_entry(
|
||||
Humidifier(miot_device=miot_device, entity_data=data))
|
||||
for data in miot_device.entity_list.get('dehumidifier', []):
|
||||
data.device_class = HumidifierDeviceClass.DEHUMIDIFIER
|
||||
new_entities.append(Humidifier(
|
||||
miot_device=miot_device, entity_data=data))
|
||||
new_entities.append(
|
||||
Humidifier(miot_device=miot_device, entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
@@ -99,9 +98,8 @@ class Humidifier(MIoTServiceEntity, HumidifierEntity):
|
||||
|
||||
_mode_map: dict[Any, Any]
|
||||
|
||||
def __init__(
|
||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
|
||||
) -> None:
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the Humidifier."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_device_class = entity_data.device_class
|
||||
@@ -130,12 +128,10 @@ class Humidifier(MIoTServiceEntity, HumidifierEntity):
|
||||
# mode
|
||||
elif prop.name == 'mode':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error(
|
||||
'mode value_list is None, %s', self.entity_id)
|
||||
_LOGGER.error('mode value_list is None, %s', self.entity_id)
|
||||
continue
|
||||
self._mode_map = prop.value_list.to_map()
|
||||
self._attr_available_modes = list(
|
||||
self._mode_map.values())
|
||||
self._attr_available_modes = list(self._mode_map.values())
|
||||
self._attr_supported_features |= HumidifierEntityFeature.MODES
|
||||
self._prop_mode = prop
|
||||
# relative-humidity
|
||||
@@ -152,33 +148,45 @@ class Humidifier(MIoTServiceEntity, HumidifierEntity):
|
||||
|
||||
async def async_set_humidity(self, humidity: int) -> None:
|
||||
"""Set new target humidity."""
|
||||
await self.set_property_async(
|
||||
prop=self._prop_target_humidity, value=humidity)
|
||||
if self._prop_target_humidity is None:
|
||||
return
|
||||
await self.set_property_async(prop=self._prop_target_humidity,
|
||||
value=humidity)
|
||||
|
||||
async def async_set_mode(self, mode: str) -> None:
|
||||
"""Set new target preset mode."""
|
||||
await self.set_property_async(
|
||||
prop=self._prop_mode,
|
||||
value=self.get_map_key(map_=self._mode_map, value=mode))
|
||||
await self.set_property_async(prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=mode))
|
||||
|
||||
@property
|
||||
def is_on(self) -> Optional[bool]:
|
||||
"""Return if the humidifier is on."""
|
||||
return self.get_prop_value(prop=self._prop_on)
|
||||
|
||||
@property
|
||||
def action(self) -> Optional[HumidifierAction]:
|
||||
"""Return the current status of the device."""
|
||||
if not self.is_on:
|
||||
return HumidifierAction.OFF
|
||||
if self._attr_device_class == HumidifierDeviceClass.HUMIDIFIER:
|
||||
return HumidifierAction.HUMIDIFYING
|
||||
return HumidifierAction.DRYING
|
||||
|
||||
@property
|
||||
def current_humidity(self) -> Optional[int]:
|
||||
"""Return the current humidity."""
|
||||
return self.get_prop_value(prop=self._prop_humidity)
|
||||
return (self.get_prop_value(
|
||||
prop=self._prop_humidity) if self._prop_humidity else None)
|
||||
|
||||
@property
|
||||
def target_humidity(self) -> Optional[int]:
|
||||
"""Return the target humidity."""
|
||||
return self.get_prop_value(prop=self._prop_target_humidity)
|
||||
return (self.get_prop_value(prop=self._prop_target_humidity)
|
||||
if self._prop_target_humidity else None)
|
||||
|
||||
@property
|
||||
def mode(self) -> Optional[str]:
|
||||
"""Return the current preset mode."""
|
||||
return self.get_map_value(
|
||||
map_=self._mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_mode))
|
||||
return self.get_map_value(map_=self._mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_mode))
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"cryptography",
|
||||
"psutil"
|
||||
],
|
||||
"version": "v0.3.0",
|
||||
"version": "v0.4.4",
|
||||
"zeroconf": [
|
||||
"_miot-central._tcp.local."
|
||||
]
|
||||
|
||||
470
custom_components/xiaomi_home/media_player.py
Normal file
470
custom_components/xiaomi_home/media_player.py
Normal file
@@ -0,0 +1,470 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Media player entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.media_player import (MediaPlayerEntity,
|
||||
MediaPlayerEntityFeature,
|
||||
MediaPlayerDeviceClass,
|
||||
MediaPlayerState, MediaType)
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData
|
||||
from .miot.miot_spec import MIoTSpecProperty, MIoTSpecAction
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('wifi-speaker', []):
|
||||
new_entities.append(
|
||||
WifiSpeaker(miot_device=miot_device, entity_data=data))
|
||||
for data in miot_device.entity_list.get('television', []):
|
||||
new_entities.append(
|
||||
Television(miot_device=miot_device, entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class FeatureVolumeMute(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""VOLUME_MUTE feature of the media player entity."""
|
||||
_prop_mute: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_mute = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'mute':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.VOLUME_MUTE)
|
||||
self._prop_mute = prop
|
||||
|
||||
@property
|
||||
def is_volume_muted(self) -> Optional[bool]:
|
||||
"""True if volume is currently muted."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_mute) if self._prop_mute else None
|
||||
|
||||
async def async_mute_volume(self, mute: bool) -> None:
|
||||
"""Mute the volume."""
|
||||
await self.set_property_async(prop=self._prop_mute, value=mute)
|
||||
|
||||
|
||||
class FeatureVolumeSet(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""VOLUME_SET feature of the media player entity."""
|
||||
_prop_volume: Optional[MIoTSpecProperty]
|
||||
_volume_value_min: Optional[float]
|
||||
_volume_value_max: Optional[float]
|
||||
_volume_value_range: Optional[float]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_volume = None
|
||||
self._volume_value_min = None
|
||||
self._volume_value_max = None
|
||||
self._volume_value_range = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'volume':
|
||||
if not prop.value_range:
|
||||
_LOGGER.error('invalid volume value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._volume_value_min = prop.value_range.min_
|
||||
self._volume_value_max = prop.value_range.max_
|
||||
self._volume_value_range = (prop.value_range.max_ -
|
||||
prop.value_range.min_)
|
||||
self._attr_volume_step = (prop.value_range.step /
|
||||
self._volume_value_range)
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.VOLUME_SET |
|
||||
MediaPlayerEntityFeature.VOLUME_STEP)
|
||||
self._prop_volume = prop
|
||||
|
||||
async def async_set_volume_level(self, volume: float) -> None:
|
||||
"""Set volume level."""
|
||||
value = volume * self._volume_value_range + self._volume_value_min
|
||||
if value > self._volume_value_max:
|
||||
value = self._volume_value_max
|
||||
elif value < self._volume_value_min:
|
||||
value = self._volume_value_min
|
||||
await self.set_property_async(prop=self._prop_volume, value=value)
|
||||
|
||||
@property
|
||||
def volume_level(self) -> Optional[float]:
|
||||
"""The current volume level, range [0, 1]."""
|
||||
value = self.get_prop_value(
|
||||
prop=self._prop_volume) if self._prop_volume else None
|
||||
if value is None:
|
||||
return None
|
||||
return (value - self._volume_value_min) / self._volume_value_range
|
||||
|
||||
|
||||
class FeaturePlay(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""PLAY feature of the media player entity."""
|
||||
_action_play: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_play = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'play':
|
||||
self._attr_supported_features |= (MediaPlayerEntityFeature.PLAY)
|
||||
self._action_play = act
|
||||
|
||||
async def async_media_play(self) -> None:
|
||||
"""Send play command."""
|
||||
await self.action_async(action=self._action_play)
|
||||
|
||||
|
||||
class FeaturePause(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""PAUSE feature of the media player entity."""
|
||||
_action_pause: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_pause = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'pause':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.PAUSE)
|
||||
self._action_pause = act
|
||||
|
||||
async def async_media_pause(self) -> None:
|
||||
"""Send pause command."""
|
||||
await self.action_async(action=self._action_pause)
|
||||
|
||||
|
||||
class FeatureStop(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""STOP feature of the media player entity."""
|
||||
_action_stop: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_stop = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'stop':
|
||||
self._attr_supported_features |= (MediaPlayerEntityFeature.STOP)
|
||||
self._action_stop = act
|
||||
|
||||
async def async_media_stop(self) -> None:
|
||||
"""Send stop command."""
|
||||
await self.action_async(action=self._action_stop)
|
||||
|
||||
|
||||
class FeatureNextTrack(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""NEXT_TRACK feature of the media player entity."""
|
||||
_action_next: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_next = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'next':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.NEXT_TRACK)
|
||||
self._action_next = act
|
||||
|
||||
async def async_media_next_track(self) -> None:
|
||||
"""Send next track command."""
|
||||
await self.action_async(action=self._action_next)
|
||||
|
||||
|
||||
class FeaturePreviousTrack(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""PREVIOUS_TRACK feature of the media player entity."""
|
||||
_action_previous: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_previous = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'previous':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.PREVIOUS_TRACK)
|
||||
self._action_previous = act
|
||||
|
||||
async def async_media_previous_track(self) -> None:
|
||||
"""Send previous track command."""
|
||||
await self.action_async(action=self._action_previous)
|
||||
|
||||
|
||||
class FeatureSoundMode(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""SELECT_SOUND_MODE feature of the media player entity."""
|
||||
_prop_play_loop_mode: Optional[MIoTSpecProperty]
|
||||
_sound_mode_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_play_loop_mode = None
|
||||
self._sound_mode_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'play-loop-mode':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid play-loop-mode value_list, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._sound_mode_map = prop.value_list.to_map()
|
||||
self._attr_sound_mode_list = list(self._sound_mode_map.values())
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.SELECT_SOUND_MODE)
|
||||
self._prop_play_loop_mode = prop
|
||||
|
||||
async def async_select_sound_mode(self, sound_mode: str):
|
||||
"""Switch the sound mode of the entity."""
|
||||
await self.set_property_async(prop=self._prop_play_loop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._sound_mode_map,
|
||||
value=sound_mode))
|
||||
|
||||
@property
|
||||
def sound_mode(self) -> Optional[str]:
|
||||
"""The current sound mode."""
|
||||
return (self.get_map_value(map_=self._sound_mode_map,
|
||||
key=self.get_prop_value(
|
||||
prop=self._prop_play_loop_mode))
|
||||
if self._prop_play_loop_mode else None)
|
||||
|
||||
|
||||
class FeatureTurnOn(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""TURN_ON feature of the media player entity."""
|
||||
_action_turn_on: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_turn_on = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'turn-on':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.TURN_ON)
|
||||
self._action_turn_on = act
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the media player on."""
|
||||
await self.action_async(action=self._action_turn_on)
|
||||
|
||||
|
||||
class FeatureTurnOff(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""TURN_OFF feature of the media player entity."""
|
||||
_action_turn_off: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_turn_off = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'turn-off':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.TURN_OFF)
|
||||
self._action_turn_off = act
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the media player off."""
|
||||
await self.action_async(action=self._action_turn_off)
|
||||
|
||||
|
||||
class FeatureSource(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""SELECT_SOURCE feature of the media player entity."""
|
||||
_prop_input_control: Optional[MIoTSpecProperty]
|
||||
_input_source_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_input_control = None
|
||||
self._input_source_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'input-control':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid input-control value_list, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._input_source_map = prop.value_list.to_map()
|
||||
self._attr_source_list = list(self._input_source_map.values())
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.SELECT_SOURCE)
|
||||
self._prop_input_control = prop
|
||||
|
||||
async def async_select_source(self, source: str) -> None:
|
||||
"""Select input source."""
|
||||
await self.set_property_async(prop=self._prop_input_control,
|
||||
value=self.get_map_key(
|
||||
map_=self._input_source_map,
|
||||
value=source))
|
||||
|
||||
@property
|
||||
def source(self) -> Optional[str]:
|
||||
"""The current input source."""
|
||||
return (self.get_map_value(map_=self._input_source_map,
|
||||
key=self.get_prop_value(
|
||||
prop=self._prop_input_control))
|
||||
if self._prop_input_control else None)
|
||||
|
||||
|
||||
class FeatureState(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""States feature of the media player entity."""
|
||||
_prop_playing_state: Optional[MIoTSpecProperty]
|
||||
_playing_state_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_playing_state = None
|
||||
self._playing_state_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'playing-state':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid mode value_list, %s', self.entity_id)
|
||||
continue
|
||||
self._playing_state_map = {}
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'off'}:
|
||||
self._playing_state_map[
|
||||
item.value] = MediaPlayerState.OFF
|
||||
elif item.name in {'idle', 'stop', 'stopped'}:
|
||||
self._playing_state_map[
|
||||
item.value] = MediaPlayerState.IDLE
|
||||
elif item.name in {'playing'}:
|
||||
self._playing_state_map[
|
||||
item.value] = MediaPlayerState.PLAYING
|
||||
elif item.name in {'pause', 'paused'}:
|
||||
self._playing_state_map[
|
||||
item.value] = MediaPlayerState.PAUSED
|
||||
self._prop_playing_state = prop
|
||||
|
||||
@property
|
||||
def state(self) -> Optional[MediaPlayerState]:
|
||||
"""The current state."""
|
||||
return (self.get_map_value(map_=self._playing_state_map,
|
||||
key=self.get_prop_value(
|
||||
prop=self._prop_playing_state))
|
||||
if self._prop_playing_state else MediaPlayerState.ON)
|
||||
|
||||
|
||||
class WifiSpeaker(FeatureVolumeSet, FeatureVolumeMute, FeaturePlay,
|
||||
FeaturePause, FeatureStop, FeatureNextTrack,
|
||||
FeaturePreviousTrack, FeatureSoundMode, FeatureState):
|
||||
"""WiFi speaker, aka XiaoAI sound speaker."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the device."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
self._attr_device_class = MediaPlayerDeviceClass.SPEAKER
|
||||
self._attr_media_content_type = MediaType.MUSIC
|
||||
|
||||
|
||||
class Television(FeatureVolumeSet, FeatureVolumeMute, FeaturePlay, FeaturePause,
|
||||
FeatureStop, FeatureNextTrack, FeaturePreviousTrack,
|
||||
FeatureSoundMode, FeatureState, FeatureSource, FeatureTurnOn,
|
||||
FeatureTurnOff):
|
||||
"""Television"""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the device."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
self._attr_device_class = MediaPlayerDeviceClass.TV
|
||||
self._attr_media_content_type = MediaType.VIDEO
|
||||
@@ -71,10 +71,12 @@ SUPPORTED_PLATFORMS: list = [
|
||||
'button',
|
||||
'climate',
|
||||
'cover',
|
||||
'device_tracker',
|
||||
'event',
|
||||
'fan',
|
||||
'humidifier',
|
||||
'light',
|
||||
'media_player',
|
||||
'notify',
|
||||
'number',
|
||||
'select',
|
||||
@@ -85,6 +87,12 @@ SUPPORTED_PLATFORMS: list = [
|
||||
'water_heater',
|
||||
]
|
||||
|
||||
UNSUPPORTED_MODELS: list = [
|
||||
'chuangmi.ir.v2',
|
||||
'hmpace.motion.v6nfc',
|
||||
'xiaomi.router.rd03'
|
||||
]
|
||||
|
||||
DEFAULT_CLOUD_SERVER: str = 'cn'
|
||||
CLOUD_SERVERS: dict = {
|
||||
'cn': '中国大陆',
|
||||
@@ -109,10 +117,15 @@ INTEGRATION_LANGUAGES = {
|
||||
'pt': 'Português',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
'ru': 'Русский',
|
||||
'tr': 'Türkçe',
|
||||
'zh-Hans': '简体中文',
|
||||
'zh-Hant': '繁體中文'
|
||||
}
|
||||
|
||||
DEFAULT_COVER_DEAD_ZONE_WIDTH: int = 0
|
||||
MIN_COVER_DEAD_ZONE_WIDTH: int = 0
|
||||
MAX_COVER_DEAD_ZONE_WIDTH: int = 5
|
||||
|
||||
DEFAULT_CTRL_MODE: str = 'auto'
|
||||
|
||||
# Registered in Xiaomi OAuth 2.0 Service
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} Geräte offline:** \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Verbindungsstatus des Zentral-Gateways",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** Lokale Verbindungsstrecke des Zentral-Gateways: {conn_status}",
|
||||
"central_state_connected": "verbunden",
|
||||
"central_state_disconnected": "getrennt",
|
||||
"device_exec_error": "Fehler bei der Ausführung"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} devices offline:** \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Central Hub Gateway Connection Status",
|
||||
"central_state_changed":"**{nick_name}({uid}, {cloud_server})** local connection to Xiaomi central hub gateway: {conn_status}",
|
||||
"central_state_connected": "Connected",
|
||||
"central_state_disconnected": "Disconnected",
|
||||
"device_exec_error": "Execution error"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} dispositivos sin conexión:** \n{message}",
|
||||
"network_status_online": "En línea",
|
||||
"network_status_offline": "Desconectado",
|
||||
"central_state_changed_title": "Estado de conexión de la puerta de enlace central",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** enlace de conexión local de la puerta de enlace central: {conn_status}",
|
||||
"central_state_connected": "conectado",
|
||||
"central_state_disconnected": "desconectado",
|
||||
"device_exec_error": "Error de ejecución"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} appareils hors ligne :** \n{message}",
|
||||
"network_status_online": "En ligne",
|
||||
"network_status_offline": "Hors ligne",
|
||||
"central_state_changed_title": "État de connexion de la passerelle centrale",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** liaison de connexion locale de la passerelle centrale : {conn_status}",
|
||||
"central_state_connected": "connecté",
|
||||
"central_state_disconnected": "déconnecté",
|
||||
"device_exec_error": "Erreur d'exécution"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} dispositivi offline:** \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Stato di connessione del gateway centrale",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** collegamento locale del gateway centrale: {conn_status}",
|
||||
"central_state_connected": "connesso",
|
||||
"central_state_disconnected": "disconnesso",
|
||||
"device_exec_error": "Errore di esecuzione"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} デバイスがオフライン:** \n{message}",
|
||||
"network_status_online": "オンライン",
|
||||
"network_status_offline": "オフライン",
|
||||
"central_state_changed_title": "中枢ゲートウェイ接続ステータス",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** 中枢ゲートウェイのローカル接続リンク: {conn_status}",
|
||||
"central_state_connected": "接続済み",
|
||||
"central_state_disconnected": "切断されました",
|
||||
"device_exec_error": "実行エラー"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} apparaten offline:** \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Verbindingsstatus van centrale gateway",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** Lokale verbinding van centrale gateway: {conn_status}",
|
||||
"central_state_connected": "verbonden",
|
||||
"central_state_disconnected": "verbinding verbroken",
|
||||
"device_exec_error": "Uitvoeringsfout"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} dispositivos offline**: \n{message}",
|
||||
"network_status_online": "online",
|
||||
"network_status_offline": "offline",
|
||||
"central_state_changed_title": "Status de conexão do gateway central",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** conexão local do gateway central: {conn_status}",
|
||||
"central_state_connected": "conectado",
|
||||
"central_state_disconnected": "desconectado",
|
||||
"device_exec_error": "Erro na execução"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} dispositivos offline**: \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Estado da ligação do gateway central",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** ligação local do gateway central: {conn_status}",
|
||||
"central_state_connected": "ligado",
|
||||
"central_state_disconnected": "desligado",
|
||||
"device_exec_error": "Erro de execução"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} устройств недоступно:** \n{message}",
|
||||
"network_status_online": "В сети",
|
||||
"network_status_offline": "Не в сети",
|
||||
"central_state_changed_title": "Статус подключения центрального шлюза",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** локальное подключение центрального шлюза: {conn_status}",
|
||||
"central_state_connected": "подключено",
|
||||
"central_state_disconnected": "разъединено",
|
||||
"device_exec_error": "Ошибка выполнения"
|
||||
}
|
||||
},
|
||||
|
||||
160
custom_components/xiaomi_home/miot/i18n/tr.json
Normal file
160
custom_components/xiaomi_home/miot/i18n/tr.json
Normal file
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "Cihazlar",
|
||||
"found_central_gateway": ", Yerel Merkezi Hub Ağ Geçidi Bulundu",
|
||||
"without_room": "Oda atanmamış",
|
||||
"no_display": "Gösterme"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "Otomatik",
|
||||
"cloud": "Bulut"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "VEYA mantığı",
|
||||
"and": "VE mantığı"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "Hariç tut",
|
||||
"include": "Dahil et"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyi cihazı",
|
||||
"2": "Bulut cihazı",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "Sanal cihaz",
|
||||
"6": "BLE",
|
||||
"7": "Yerel AP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "Diğer",
|
||||
"10": "İşlev eklentisi",
|
||||
"11": "Hücresel ağ",
|
||||
"12": "Kablo",
|
||||
"13": "NB-IoT",
|
||||
"14": "Üçüncü taraf bulut erişimi",
|
||||
"15": "Kızılötesi uzaktan kumanda cihazı",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "Sanal cihaz grubu",
|
||||
"18": "Ağ geçidi alt cihazı",
|
||||
"19": "Güvenlik seviyesi ağ geçidi alt cihazı",
|
||||
"22": "PLC",
|
||||
"23": "Yalnızca kablo",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+Hücresel ağ"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "Senkronize etme",
|
||||
"home_room": "Ev Adı ve Oda Adı (Xiaomi Home Yatak Odası)",
|
||||
"room": "Oda Adı (Yatak Odası)",
|
||||
"home": "Ev Adı (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "Etkinleştir",
|
||||
"disable": "Devre Dışı Bırak"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "Metin Sensör Varlığı",
|
||||
"bool": "İkili Sensör Varlığı"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "Ekle",
|
||||
"del": "Kullanılamıyor",
|
||||
"offline": "Çevrimdışı"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Bildirim]** Aynı ağa bağlı olabilecek birden fazla ağ kartı algılandı. Lütfen seçime dikkat edin.",
|
||||
"net_unavailable": "Arayüz kullanılamıyor"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Kimlik Doğrulama Başarılı",
|
||||
"content": "Lütfen bu sayfayı kapatın ve 'İleri'ye tıklamak için hesap kimlik doğrulama sayfasına geri dönün.",
|
||||
"button": "Kapat"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Kimlik Doğrulama Başarısız",
|
||||
"content": "{error_msg}, lütfen bu sayfayı kapatın ve kimlik doğrulama bağlantısına tekrar tıklamak için hesap kimlik doğrulama sayfasına geri dönün.",
|
||||
"button": "Kapat"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Geçersiz yanıt parametreleri ('code' veya 'state' alanı boş)",
|
||||
"-10101": "Geçirilen 'state' alanı uyumsuz"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Kimlik doğrulama bilgileri geçersiz, bulut bağlantısı kullanılamayacak, lütfen Xiaomi Home entegrasyon sayfasına girin, yeniden kimlik doğrulaması yapmak için 'Seçenekler'e tıklayın",
|
||||
"invalid_device_cache": "Önbellek cihaz bilgileri anormal, lütfen Xiaomi Home entegrasyon sayfasına girin, yerel önbelleği güncellemek için 'Seçenekler->Cihaz listesini güncelle'ye tıklayın",
|
||||
"invalid_cert_info": "Geçersiz kullanıcı sertifikası, yerel merkezi bağlantı kullanılamayacak, lütfen Xiaomi Home entegrasyon sayfasına girin, yeniden kimlik doğrulaması yapmak için 'Seçenekler'e tıklayın",
|
||||
"device_cloud_error": "Buluttan cihaz bilgileri alınırken bir istisna oluştu, lütfen yerel ağ bağlantısını kontrol edin",
|
||||
"xiaomi_home_error_title": "Xiaomi Home Entegrasyon Hatası",
|
||||
"xiaomi_home_error": "**{nick_name}({uid}, {cloud_server})** hatası algılandı, lütfen yeniden yapılandırmak için seçenekler sayfasına girin.\n\n**Hata mesajı**: \n{message}",
|
||||
"device_list_changed_title": "Xiaomi Home cihaz listesi değişiklikleri",
|
||||
"device_list_changed": "**{nick_name}({uid}, {cloud_server})** cihaz bilgilerinin değiştiği algılandı, lütfen entegrasyon seçenekleri sayfasına girin, yerel cihaz bilgilerini güncellemek için `Seçenekler->Cihaz listesini güncelle`ye tıklayın.\n\nGeçerli ağ durumu: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} yeni cihaz:** \n{message}",
|
||||
"device_list_del": "\n**{count} cihaz kullanılamıyor:** \n{message}",
|
||||
"device_list_offline": "\n**{count} cihaz çevrimdışı:** \n{message}",
|
||||
"network_status_online": "Çevrimiçi",
|
||||
"network_status_offline": "Çevrimdışı",
|
||||
"central_state_changed_title": "Merkezi Hub Ağ Geçidi Bağlantı Durumu",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** Xiaomi merkezi hub ağ geçidine yerel bağlantı: {conn_status}",
|
||||
"central_state_connected": "Bağlandı",
|
||||
"central_state_disconnected": "Bağlantı kesildi",
|
||||
"device_exec_error": "Yürütme hatası"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Bilinmeyen hata",
|
||||
"-10001": "Hizmet kullanılamıyor",
|
||||
"-10002": "Geçersiz parametre",
|
||||
"-10003": "Yetersiz kaynaklar",
|
||||
"-10004": "İç hata",
|
||||
"-10005": "Yetersiz izinler",
|
||||
"-10006": "Yürütme zaman aşımı",
|
||||
"-10007": "Cihaz çevrimdışı veya mevcut değil",
|
||||
"-10020": "Yetkisiz (OAuth2)",
|
||||
"-10030": "Geçersiz token (HTTP)",
|
||||
"-10040": "Geçersiz mesaj formatı",
|
||||
"-10050": "Geçersiz sertifika",
|
||||
"-704000000": "Bilinmeyen hata",
|
||||
"-704010000": "Yetkisiz (cihaz silinmiş olabilir)",
|
||||
"-704014006": "Cihaz açıklaması bulunamadı",
|
||||
"-704030013": "Özellik okunabilir değil",
|
||||
"-704030023": "Özellik yazılabilir değil",
|
||||
"-704030033": "Özellik abone edilebilir değil",
|
||||
"-704040002": "Hizmet mevcut değil",
|
||||
"-704040003": "Özellik mevcut değil",
|
||||
"-704040004": "Olay mevcut değil",
|
||||
"-704040005": "Eylem mevcut değil",
|
||||
"-704040999": "Özellik çevrimiçi değil",
|
||||
"-704042001": "Cihaz mevcut değil",
|
||||
"-704042011": "Cihaz çevrimdışı",
|
||||
"-704053036": "Cihaz işlemi zaman aşımı",
|
||||
"-704053100": "Cihaz mevcut durumda bu işlemi gerçekleştiremiyor",
|
||||
"-704083036": "Cihaz işlemi zaman aşımı",
|
||||
"-704090001": "Cihaz mevcut değil",
|
||||
"-704220008": "Geçersiz ID",
|
||||
"-704220025": "Eylem parametre sayısı uyumsuz",
|
||||
"-704220035": "Eylem parametre hatası",
|
||||
"-704220043": "Özellik değer hatası",
|
||||
"-704222034": "Eylem dönüş değer hatası",
|
||||
"-705004000": "Bilinmeyen hata",
|
||||
"-705004501": "Bilinmeyen hata",
|
||||
"-705201013": "Özellik okunabilir değil",
|
||||
"-705201015": "Eylem yürütme hatası",
|
||||
"-705201023": "Özellik yazılabilir değil",
|
||||
"-705201033": "Özellik abone edilebilir değil",
|
||||
"-706012000": "Bilinmeyen hata",
|
||||
"-706012013": "Özellik okunabilir değil",
|
||||
"-706012015": "Eylem yürütme hatası",
|
||||
"-706012023": "Özellik yazılabilir değil",
|
||||
"-706012033": "Özellik abone edilebilir değil",
|
||||
"-706012043": "Özellik değer hatası",
|
||||
"-706014006": "Cihaz açıklaması bulunamadı"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} 个设备离线**: \n{message}",
|
||||
"network_status_online": "在线",
|
||||
"network_status_offline": "离线",
|
||||
"central_state_changed_title": "中枢网关连接状态",
|
||||
"central_state_changed":"**{nick_name}({uid}, {cloud_server})** 中枢网关本地连接链路: {conn_status}",
|
||||
"central_state_connected": "已连接",
|
||||
"central_state_disconnected": "断连",
|
||||
"device_exec_error": "执行错误"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"device_list_offline": "\n**{count} 個設備離線:** \n{message}",
|
||||
"network_status_online": "在線",
|
||||
"network_status_offline": "離線",
|
||||
"central_state_changed_title": "中枢網關連接狀態",
|
||||
"central_state_changed":"**{nick_name}({uid}, {cloud_server})** 中枢網關本地連接鏈路: {conn_status}",
|
||||
"central_state_connected": "已連接",
|
||||
"central_state_disconnected": "断連",
|
||||
"device_exec_error": "執行錯誤"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -63,7 +63,8 @@ from .common import MIoTMatcher, slugify_did
|
||||
from .const import (
|
||||
DEFAULT_CTRL_MODE, DEFAULT_INTEGRATION_LANGUAGE, DEFAULT_NICK_NAME, DOMAIN,
|
||||
MIHOME_CERT_EXPIRE_MARGIN, NETWORK_REFRESH_INTERVAL,
|
||||
OAUTH2_CLIENT_ID, SUPPORT_CENTRAL_GATEWAY_CTRL)
|
||||
OAUTH2_CLIENT_ID, SUPPORT_CENTRAL_GATEWAY_CTRL,
|
||||
DEFAULT_COVER_DEAD_ZONE_WIDTH)
|
||||
from .miot_cloud import MIoTHttpClient, MIoTOauthClient
|
||||
from .miot_error import MIoTClientError, MIoTErrorCode
|
||||
from .miot_mips import (
|
||||
@@ -252,7 +253,18 @@ class MIoTClient:
|
||||
if not self._user_config:
|
||||
# Integration need to be add again
|
||||
raise MIoTClientError('load_user_config_async error')
|
||||
_LOGGER.debug('user config, %s', json.dumps(self._user_config))
|
||||
# Hide sensitive info in printing
|
||||
p_user_config: dict = deepcopy(self._user_config)
|
||||
p_access_token: str = p_user_config['auth_info']['access_token']
|
||||
p_refresh_token: str = p_user_config['auth_info']['refresh_token']
|
||||
p_mac_key: str = p_user_config['auth_info']['mac_key']
|
||||
p_user_config['auth_info'][
|
||||
'access_token'] = f"{p_access_token[:5]}***{p_access_token[-5:]}"
|
||||
p_user_config['auth_info'][
|
||||
'refresh_token'] = f"{p_refresh_token[:5]}***{p_refresh_token[-5:]}"
|
||||
p_user_config['auth_info'][
|
||||
'mac_key'] = f"{p_mac_key[:5]}***{p_mac_key[-5:]}"
|
||||
_LOGGER.debug('user config, %s', json.dumps(p_user_config))
|
||||
# MIoT i18n client
|
||||
self._i18n = MIoTI18n(
|
||||
lang=self._entry_data.get(
|
||||
@@ -486,6 +498,11 @@ class MIoTClient:
|
||||
def display_binary_bool(self) -> bool:
|
||||
return self._display_binary_bool
|
||||
|
||||
@property
|
||||
def cover_dead_zone_width(self) -> int:
|
||||
return self._entry_data.get('cover_dead_zone_width',
|
||||
DEFAULT_COVER_DEAD_ZONE_WIDTH)
|
||||
|
||||
@display_devices_changed_notify.setter
|
||||
def display_devices_changed_notify(self, value: list[str]) -> None:
|
||||
if set(value) == set(self._display_devs_notify):
|
||||
@@ -629,11 +646,14 @@ class MIoTClient:
|
||||
mips = self._mips_local.get(device_gw['group_id'], None)
|
||||
if mips is None:
|
||||
_LOGGER.error(
|
||||
'no gw route, %s, try control throw cloud',
|
||||
'no gateway route, %s, try control through cloud',
|
||||
device_gw)
|
||||
else:
|
||||
result = await mips.set_prop_async(
|
||||
did=did, siid=siid, piid=piid, value=value)
|
||||
_LOGGER.debug(
|
||||
'gateway set prop, %s.%d.%d, %s -> %s',
|
||||
did, siid, piid, value, result)
|
||||
rc = (result or {}).get(
|
||||
'code', MIoTErrorCode.CODE_MIPS_INVALID_RESULT.value)
|
||||
if rc in [0, 1]:
|
||||
@@ -646,7 +666,8 @@ class MIoTClient:
|
||||
result = await self._miot_lan.set_prop_async(
|
||||
did=did, siid=siid, piid=piid, value=value)
|
||||
_LOGGER.debug(
|
||||
'lan set prop, %s, %s, %s -> %s', did, siid, piid, result)
|
||||
'lan set prop, %s.%d.%d, %s -> %s',
|
||||
did, siid, piid, value, result)
|
||||
rc = (result or {}).get(
|
||||
'code', MIoTErrorCode.CODE_MIPS_INVALID_RESULT.value)
|
||||
if rc in [0, 1]:
|
||||
@@ -662,7 +683,7 @@ class MIoTClient:
|
||||
{'did': did, 'siid': siid, 'piid': piid, 'value': value}
|
||||
])
|
||||
_LOGGER.debug(
|
||||
'set prop response, %s.%d.%d, %s, result, %s',
|
||||
'cloud set prop, %s.%d.%d, %s -> %s',
|
||||
did, siid, piid, value, result)
|
||||
if result and len(result) == 1:
|
||||
rc = result[0].get(
|
||||
@@ -986,7 +1007,7 @@ class MIoTClient:
|
||||
and self._device_list_cloud[did].get('online', False)
|
||||
):
|
||||
from_new = 'cloud'
|
||||
if from_new == from_old:
|
||||
if (from_new == from_old) and (from_new=='cloud' or from_new=='lan'):
|
||||
# No need to update
|
||||
return
|
||||
# Unsub old
|
||||
@@ -1105,8 +1126,10 @@ class MIoTClient:
|
||||
_LOGGER.info('local mips state changed, %s, %s', group_id, state)
|
||||
mips = self._mips_local.get(group_id, None)
|
||||
if not mips:
|
||||
_LOGGER.error(
|
||||
_LOGGER.info(
|
||||
'local mips state changed, mips not exist, %s', group_id)
|
||||
# The connection to the central hub gateway is definitely broken.
|
||||
self.__show_central_state_changed_notify(False)
|
||||
return
|
||||
if state:
|
||||
# Connected
|
||||
@@ -1140,6 +1163,7 @@ class MIoTClient:
|
||||
if sub and sub.handler:
|
||||
sub.handler(did, MIoTDeviceState.OFFLINE, sub.handler_ctx)
|
||||
self.__request_show_devices_changed_notify()
|
||||
self.__show_central_state_changed_notify(state)
|
||||
|
||||
@final
|
||||
async def __on_miot_lan_state_change(self, state: bool) -> None:
|
||||
@@ -1350,6 +1374,14 @@ class MIoTClient:
|
||||
"""Update cloud devices.
|
||||
NOTICE: This function will operate the cloud_list
|
||||
"""
|
||||
# MIoT cloud may not publish the online state updating message
|
||||
# for the BLE device. Assume that all BLE devices are online.
|
||||
# MIoT cloud does not publish the online state updating message for the
|
||||
# child device under the proxy gateway (eg, VRF air conditioner
|
||||
# controller). Assume that all proxy gateway child devices are online.
|
||||
for did, info in cloud_list.items():
|
||||
if did.startswith('blt.') or did.startswith('proxy.'):
|
||||
info['online'] = True
|
||||
for did, info in self._device_list_cache.items():
|
||||
if filter_dids and did not in filter_dids:
|
||||
continue
|
||||
@@ -1477,8 +1509,6 @@ class MIoTClient:
|
||||
if did not in filter_dids:
|
||||
continue
|
||||
device_old = self._device_list_gateway.get(did, None)
|
||||
gw_state_old = device_old.get(
|
||||
'online', False) if device_old else False
|
||||
gw_state_new: bool = False
|
||||
device_new = gw_list.pop(did, None)
|
||||
if device_new:
|
||||
@@ -1492,7 +1522,7 @@ class MIoTClient:
|
||||
device_old['online'] = False
|
||||
# Update cache group_id
|
||||
info['group_id'] = group_id
|
||||
if gw_state_old == gw_state_new:
|
||||
if not gw_state_new:
|
||||
continue
|
||||
self.__update_device_msg_sub(did=did)
|
||||
state_old: Optional[bool] = info.get('online', None)
|
||||
@@ -1902,6 +1932,23 @@ class MIoTClient:
|
||||
self._show_devices_changed_notify_timer = self._main_loop.call_later(
|
||||
delay_sec, self.__show_devices_changed_notify)
|
||||
|
||||
@final
|
||||
def __show_central_state_changed_notify(self, connected: bool) -> None:
|
||||
conn_status: str = (
|
||||
self._i18n.translate('miot.client.central_state_connected')
|
||||
if connected else
|
||||
self._i18n.translate('miot.client.central_state_disconnected'))
|
||||
self._persistence_notify(
|
||||
self.__gen_notify_key('central_state_changed'),
|
||||
self._i18n.translate('miot.client.central_state_changed_title'),
|
||||
self._i18n.translate(key='miot.client.central_state_changed',
|
||||
replace={
|
||||
'nick_name': self._entry_data.get(
|
||||
'nick_name', DEFAULT_NICK_NAME),
|
||||
'uid': self._uid,
|
||||
'cloud_server': self._cloud_server,
|
||||
'conn_status': conn_status
|
||||
}))
|
||||
|
||||
@staticmethod
|
||||
async def get_miot_instance_async(
|
||||
|
||||
@@ -59,6 +59,7 @@ import aiohttp
|
||||
# pylint: disable=relative-beyond-top-level
|
||||
from .common import calc_group_id
|
||||
from .const import (
|
||||
UNSUPPORTED_MODELS,
|
||||
DEFAULT_OAUTH2_API_HOST,
|
||||
MIHOME_HTTP_API_TIMEOUT,
|
||||
OAUTH2_AUTH_URL)
|
||||
@@ -542,6 +543,7 @@ class MIoTHttpClient:
|
||||
req_data: dict = {
|
||||
'limit': 200,
|
||||
'get_split_device': True,
|
||||
'get_third_device': True,
|
||||
'dids': dids
|
||||
}
|
||||
if start_did:
|
||||
@@ -573,6 +575,10 @@ class MIoTHttpClient:
|
||||
# were implemented.
|
||||
_LOGGER.info('ignore miwifi.* device, cloud, %s', did)
|
||||
continue
|
||||
if model in UNSUPPORTED_MODELS:
|
||||
_LOGGER.info('ignore unsupported model %s, cloud, %s',
|
||||
model, did)
|
||||
continue
|
||||
device_infos[did] = {
|
||||
'did': did,
|
||||
'uid': device.get('uid', None),
|
||||
|
||||
@@ -747,6 +747,7 @@ class MIoTDevice:
|
||||
'watt': UnitOfPower.WATT,
|
||||
'w': UnitOfPower.WATT,
|
||||
'W': UnitOfPower.WATT,
|
||||
'kW': UnitOfPower.KILO_WATT,
|
||||
'kWh': UnitOfEnergy.KILO_WATT_HOUR,
|
||||
'A': UnitOfElectricCurrent.AMPERE,
|
||||
'mA': UnitOfElectricCurrent.MILLIAMPERE,
|
||||
@@ -779,8 +780,10 @@ class MIoTDevice:
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from homeassistant.const import UnitOfConductivity # type: ignore
|
||||
unit_map['μS/cm'] = UnitOfConductivity.MICROSIEMENS_PER_CM
|
||||
unit_map['mWh'] = UnitOfEnergy.MILLIWATT_HOUR
|
||||
except Exception: # pylint: disable=broad-except
|
||||
unit_map['μS/cm'] = 'μS/cm'
|
||||
unit_map['mWh'] = 'mWh'
|
||||
|
||||
return unit_map.get(spec_unit, None)
|
||||
|
||||
@@ -1106,6 +1109,8 @@ class MIoTServiceEntity(Entity):
|
||||
):
|
||||
continue
|
||||
value: Any = prop.value_format(params['value'])
|
||||
value = prop.eval_expr(value)
|
||||
value = prop.value_format(value)
|
||||
self._prop_value_map[prop] = value
|
||||
if prop in self._prop_changed_subs:
|
||||
self._prop_changed_subs[prop](prop, value)
|
||||
@@ -1205,10 +1210,9 @@ class MIoTPropertyEntity(Entity):
|
||||
self._attr_available = miot_device.online
|
||||
|
||||
_LOGGER.info(
|
||||
'new miot property entity, %s, %s, %s, %s, %s, %s, %s',
|
||||
'new miot property entity, %s, %s, %s, %s, %s',
|
||||
self.miot_device.name, self._attr_name, spec.platform,
|
||||
spec.device_class, self.entity_id, self._value_range,
|
||||
self._value_list)
|
||||
spec.device_class, self.entity_id)
|
||||
|
||||
@property
|
||||
def device_info(self) -> Optional[DeviceInfo]:
|
||||
@@ -1278,8 +1282,9 @@ class MIoTPropertyEntity(Entity):
|
||||
|
||||
def __on_value_changed(self, params: dict, ctx: Any) -> None:
|
||||
_LOGGER.debug('property changed, %s', params)
|
||||
self._value = self.spec.value_format(params['value'])
|
||||
self._value = self.spec.eval_expr(self._value)
|
||||
value: Any = self.spec.value_format(params['value'])
|
||||
value = self.spec.eval_expr(value)
|
||||
self._value = self.spec.value_format(value)
|
||||
if not self._pending_write_ha_state_timer:
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ class _MIoTLanDevice:
|
||||
def gen_packet(
|
||||
self, out_buffer: bytearray, clear_data: dict, did: str, offset: int
|
||||
) -> int:
|
||||
clear_bytes = json.dumps(clear_data).encode('utf-8')
|
||||
clear_bytes = json.dumps(clear_data, ensure_ascii=False).encode('utf-8')
|
||||
padder = padding.PKCS7(algorithms.AES128.block_size).padder()
|
||||
padded_data = padder.update(clear_bytes) + padder.finalize()
|
||||
if len(padded_data) + self.OT_HEADER_LEN > len(out_buffer):
|
||||
|
||||
@@ -110,7 +110,6 @@ class MipsServiceData:
|
||||
version=IPVersion.V4Only)
|
||||
if not self.addresses:
|
||||
raise MipsServiceError('invalid addresses')
|
||||
self.addresses.sort()
|
||||
if not service_info.port:
|
||||
raise MipsServiceError('invalid port')
|
||||
self.port = service_info.port
|
||||
@@ -226,7 +225,7 @@ class MipsService:
|
||||
state_change: ServiceStateChange
|
||||
) -> None:
|
||||
_LOGGER.debug(
|
||||
'mips service state changed, %s, %s, %s',
|
||||
'mdns discovery changed, %s, %s, %s',
|
||||
state_change, name, service_type)
|
||||
|
||||
if state_change is ServiceStateChange.Removed:
|
||||
|
||||
@@ -60,6 +60,7 @@ from typing import Any, Callable, Optional, final, Coroutine
|
||||
|
||||
from paho.mqtt.client import (
|
||||
MQTT_ERR_SUCCESS,
|
||||
MQTT_ERR_NO_CONN,
|
||||
MQTT_ERR_UNKNOWN,
|
||||
Client,
|
||||
MQTTv5,
|
||||
@@ -67,7 +68,7 @@ from paho.mqtt.client import (
|
||||
|
||||
# pylint: disable=relative-beyond-top-level
|
||||
from .common import MIoTMatcher
|
||||
from .const import MIHOME_MQTT_KEEPALIVE
|
||||
from .const import UNSUPPORTED_MODELS, MIHOME_MQTT_KEEPALIVE
|
||||
from .miot_error import MIoTErrorCode, MIoTMipsError
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -215,7 +216,7 @@ class _MipsClient(ABC):
|
||||
MQTT_INTERVAL_S = 1
|
||||
MIPS_QOS: int = 2
|
||||
UINT32_MAX: int = 0xFFFFFFFF
|
||||
MIPS_RECONNECT_INTERVAL_MIN: float = 30
|
||||
MIPS_RECONNECT_INTERVAL_MIN: float = 10
|
||||
MIPS_RECONNECT_INTERVAL_MAX: float = 600
|
||||
MIPS_SUB_PATCH: int = 300
|
||||
MIPS_SUB_INTERVAL: float = 1
|
||||
@@ -512,6 +513,7 @@ class _MipsClient(ABC):
|
||||
"""
|
||||
self.__thread_check()
|
||||
if not self._mqtt or not self._mqtt.is_connected():
|
||||
self.log_error(f'mips sub when not connected, {topic}')
|
||||
return
|
||||
try:
|
||||
if topic not in self._mips_sub_pending_map:
|
||||
@@ -530,10 +532,11 @@ class _MipsClient(ABC):
|
||||
"""
|
||||
self.__thread_check()
|
||||
if not self._mqtt or not self._mqtt.is_connected():
|
||||
self.log_debug(f'mips unsub when not connected, {topic}')
|
||||
return
|
||||
try:
|
||||
result, mid = self._mqtt.unsubscribe(topic=topic)
|
||||
if result == MQTT_ERR_SUCCESS:
|
||||
if (result == MQTT_ERR_SUCCESS) or (result == MQTT_ERR_NO_CONN):
|
||||
self.log_debug(
|
||||
f'mips unsub internal success, {result}, {mid}, {topic}')
|
||||
return
|
||||
@@ -586,6 +589,13 @@ class _MipsClient(ABC):
|
||||
|
||||
def __mqtt_loop_handler(self) -> None:
|
||||
try:
|
||||
# If the main loop is closed, stop the internal loop immediately
|
||||
if self.main_loop.is_closed():
|
||||
self.log_debug(
|
||||
'The main loop is closed, stop the internal loop.')
|
||||
if not self._internal_loop.is_closed():
|
||||
self._internal_loop.stop()
|
||||
return
|
||||
if self._mqtt:
|
||||
self._mqtt.loop_read()
|
||||
if self._mqtt:
|
||||
@@ -638,8 +648,10 @@ class _MipsClient(ABC):
|
||||
_LOGGER.error('__on_connect, but mqtt is None')
|
||||
return
|
||||
if not self._mqtt.is_connected():
|
||||
_LOGGER.error('__on_connect, but mqtt is disconnected')
|
||||
return
|
||||
self.log_info(f'mips connect, {flags}, {rc}, {props}')
|
||||
self.__reset_reconnect_time()
|
||||
self._mqtt_state = True
|
||||
self._internal_loop.call_soon(
|
||||
self._on_mips_connect, rc, props)
|
||||
@@ -821,7 +833,7 @@ class _MipsClient(ABC):
|
||||
self._internal_loop.stop()
|
||||
|
||||
def __get_next_reconnect_time(self) -> float:
|
||||
if self._mips_reconnect_interval == 0:
|
||||
if self._mips_reconnect_interval < self.MIPS_RECONNECT_INTERVAL_MIN:
|
||||
self._mips_reconnect_interval = self.MIPS_RECONNECT_INTERVAL_MIN
|
||||
else:
|
||||
self._mips_reconnect_interval = min(
|
||||
@@ -829,6 +841,9 @@ class _MipsClient(ABC):
|
||||
self.MIPS_RECONNECT_INTERVAL_MAX)
|
||||
return self._mips_reconnect_interval
|
||||
|
||||
def __reset_reconnect_time(self) -> None:
|
||||
self._mips_reconnect_interval = 0
|
||||
|
||||
|
||||
class MipsCloudClient(_MipsClient):
|
||||
"""MIoT Pub/Sub Cloud Client."""
|
||||
@@ -989,6 +1004,13 @@ class MipsCloudClient(_MipsClient):
|
||||
handler(
|
||||
did, MIoTDeviceState.ONLINE if msg['event'] == 'online'
|
||||
else MIoTDeviceState.OFFLINE, ctx)
|
||||
|
||||
if did.startswith('blt.') or did.startswith('proxy.'):
|
||||
# MIoT cloud may not publish BLE device or proxy gateway child device
|
||||
# online/offline state message.
|
||||
# Do not subscribe BLE device or proxy gateway child device
|
||||
# online/offline state.
|
||||
return True
|
||||
return self.__reg_broadcast_external(
|
||||
topic=topic, handler=on_state_msg, handler_ctx=handler_ctx)
|
||||
|
||||
@@ -1173,7 +1195,7 @@ class MipsLocalClient(_MipsClient):
|
||||
or 'piid' not in msg
|
||||
or 'value' not in msg
|
||||
):
|
||||
# self.log_error(f'on_prop_msg, recv unknown msg, {payload}')
|
||||
self.log_info('unknown prop msg, %s', payload)
|
||||
return
|
||||
if handler:
|
||||
self.log_debug('local, on properties_changed, %s', payload)
|
||||
@@ -1360,6 +1382,9 @@ class MipsLocalClient(_MipsClient):
|
||||
if name is None or urn is None or model is None:
|
||||
self.log_error(f'invalid device info, {did}, {info}')
|
||||
continue
|
||||
if model in UNSUPPORTED_MODELS:
|
||||
self.log_info(f'unsupported model, {model}, {did}')
|
||||
continue
|
||||
device_list[did] = {
|
||||
'did': did,
|
||||
'name': name,
|
||||
|
||||
@@ -66,7 +66,7 @@ class MIoTSpecValueRange:
|
||||
"""MIoT SPEC value range class."""
|
||||
min_: int
|
||||
max_: int
|
||||
step: int
|
||||
step: int | float
|
||||
|
||||
def __init__(self, value_range: Union[dict, list]) -> None:
|
||||
if isinstance(value_range, dict):
|
||||
@@ -567,9 +567,8 @@ class MIoTSpecProperty(_MIoTSpecBase):
|
||||
return
|
||||
self._value_range = MIoTSpecValueRange(value_range=value)
|
||||
if isinstance(value, list):
|
||||
self.precision = len(str(
|
||||
value[2]).split('.')[1].rstrip('0')) if '.' in str(
|
||||
value[2]) else 0
|
||||
step_: str = format(value[2], '.10f').rstrip('0').rstrip('.')
|
||||
self.precision = len(step_.split('.')[1]) if '.' in step_ else 0
|
||||
|
||||
@property
|
||||
def value_list(self) -> Optional[MIoTSpecValueList]:
|
||||
@@ -601,7 +600,10 @@ class MIoTSpecProperty(_MIoTSpecBase):
|
||||
if value is None:
|
||||
return None
|
||||
if self.format_ == int:
|
||||
return int(value)
|
||||
if self.value_range is None:
|
||||
return int(round(value))
|
||||
return int(
|
||||
round(value / self.value_range.step) * self.value_range.step)
|
||||
if self.format_ == float:
|
||||
return round(value, self.precision)
|
||||
if self.format_ == bool:
|
||||
@@ -1195,6 +1197,9 @@ class _SpecModify:
|
||||
def get_prop_unit(self, siid: int, piid: int) -> Optional[str]:
|
||||
return self.__get_prop_item(siid=siid, piid=piid, key='unit')
|
||||
|
||||
def get_prop_format(self, siid: int, piid: int) -> Optional[str]:
|
||||
return self.__get_prop_item(siid=siid, piid=piid, key='format')
|
||||
|
||||
def get_prop_expr(self, siid: int, piid: int) -> Optional[str]:
|
||||
return self.__get_prop_item(siid=siid, piid=piid, key='expr')
|
||||
|
||||
@@ -1518,6 +1523,10 @@ class MIoTSpecParser:
|
||||
siid=service['iid'], piid=property_['iid'])
|
||||
if custom_access:
|
||||
spec_prop.access = custom_access
|
||||
custom_format = self._spec_modify.get_prop_format(
|
||||
siid=service['iid'], piid=property_['iid'])
|
||||
if custom_format:
|
||||
spec_prop.format_ = custom_format
|
||||
custom_range = self._spec_modify.get_prop_value_range(
|
||||
siid=service['iid'], piid=property_['iid'])
|
||||
if custom_range:
|
||||
|
||||
@@ -90,6 +90,9 @@ translate:
|
||||
ru:
|
||||
'false': Ложь
|
||||
'true': Истина
|
||||
tr:
|
||||
'false': Yanlış
|
||||
'true': Doğru
|
||||
zh-Hans:
|
||||
'false': 假
|
||||
'true': 真
|
||||
@@ -127,6 +130,9 @@ translate:
|
||||
ru:
|
||||
'false': Нет контакта
|
||||
'true': Контакт
|
||||
tr:
|
||||
'false': Temas Yok
|
||||
'true': Temas
|
||||
zh-Hans:
|
||||
'false': 分离
|
||||
'true': 接触
|
||||
@@ -164,6 +170,9 @@ translate:
|
||||
ru:
|
||||
'false': Движение не обнаружено
|
||||
'true': Обнаружено движение
|
||||
tr:
|
||||
'false': Hareket Algılanmadı
|
||||
'true': Hareket Algılandı
|
||||
zh-Hans:
|
||||
'false': 无人
|
||||
'true': 有人
|
||||
@@ -201,6 +210,9 @@ translate:
|
||||
ru:
|
||||
'false': Закрыть
|
||||
'true': Открыть
|
||||
tr:
|
||||
'false': Kapalı
|
||||
'true': Açık
|
||||
zh-Hans:
|
||||
'false': 关闭
|
||||
'true': 开启
|
||||
@@ -238,6 +250,9 @@ translate:
|
||||
ru:
|
||||
'false': Нет
|
||||
'true': Да
|
||||
tr:
|
||||
'false': Hayır
|
||||
'true': Evet
|
||||
zh-Hans:
|
||||
'false': 否
|
||||
'true': 是
|
||||
|
||||
@@ -1,187 +1,302 @@
|
||||
{
|
||||
"urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1": {
|
||||
"de": {
|
||||
"service:001": "Geräteinformationen",
|
||||
"service:001:property:003": "Geräte-ID",
|
||||
"service:001:property:005": "Seriennummer (SN)",
|
||||
"service:002": "Gateway",
|
||||
"service:002:event:001": "Netzwerk geändert",
|
||||
"service:002:event:002": "Netzwerk geändert",
|
||||
"service:002:property:001": "Zugriffsmethode",
|
||||
"service:002:property:001:valuelist:000": "Kabelgebunden",
|
||||
"service:002:property:001:valuelist:001": "5G Drahtlos",
|
||||
"service:002:property:001:valuelist:002": "2.4G Drahtlos",
|
||||
"service:002:property:002": "IP-Adresse",
|
||||
"service:002:property:003": "WiFi-Netzwerkname",
|
||||
"service:002:property:004": "Aktuelle Zeit",
|
||||
"service:002:property:005": "DHCP-Server-MAC-Adresse",
|
||||
"service:003": "Anzeigelampe",
|
||||
"service:003:property:001": "Schalter",
|
||||
"service:004": "Virtueller Dienst",
|
||||
"service:004:action:001": "Virtuelles Ereignis erzeugen",
|
||||
"service:004:event:001": "Virtuelles Ereignis aufgetreten",
|
||||
"service:004:property:001": "Ereignisname"
|
||||
},
|
||||
"en": {
|
||||
"service:001": "Device Information",
|
||||
"service:001:property:003": "Device ID",
|
||||
"service:001:property:005": "Serial Number (SN)",
|
||||
"service:002": "Gateway",
|
||||
"service:002:event:001": "Network Changed",
|
||||
"service:002:event:002": "Network Changed",
|
||||
"service:002:property:001": "Access Method",
|
||||
"service:002:property:001:valuelist:000": "Wired",
|
||||
"service:002:property:001:valuelist:001": "5G Wireless",
|
||||
"service:002:property:001:valuelist:002": "2.4G Wireless",
|
||||
"service:002:property:002": "IP Address",
|
||||
"service:002:property:003": "WiFi Network Name",
|
||||
"service:002:property:004": "Current Time",
|
||||
"service:002:property:005": "DHCP Server MAC Address",
|
||||
"service:003": "Indicator Light",
|
||||
"service:003:property:001": "Switch",
|
||||
"service:004": "Virtual Service",
|
||||
"service:004:action:001": "Generate Virtual Event",
|
||||
"service:004:event:001": "Virtual Event Occurred",
|
||||
"service:004:property:001": "Event Name"
|
||||
},
|
||||
"es": {
|
||||
"service:001": "Información del dispositivo",
|
||||
"service:001:property:003": "ID del dispositivo",
|
||||
"service:001:property:005": "Número de serie (SN)",
|
||||
"service:002": "Puerta de enlace",
|
||||
"service:002:event:001": "Cambio de red",
|
||||
"service:002:event:002": "Cambio de red",
|
||||
"service:002:property:001": "Método de acceso",
|
||||
"service:002:property:001:valuelist:000": "Cableado",
|
||||
"service:002:property:001:valuelist:001": "5G inalámbrico",
|
||||
"service:002:property:001:valuelist:002": "2.4G inalámbrico",
|
||||
"service:002:property:002": "Dirección IP",
|
||||
"service:002:property:003": "Nombre de red WiFi",
|
||||
"service:002:property:004": "Hora actual",
|
||||
"service:002:property:005": "Dirección MAC del servidor DHCP",
|
||||
"service:003": "Luz indicadora",
|
||||
"service:003:property:001": "Interruptor",
|
||||
"service:004": "Servicio virtual",
|
||||
"service:004:action:001": "Generar evento virtual",
|
||||
"service:004:event:001": "Ocurrió un evento virtual",
|
||||
"service:004:property:001": "Nombre del evento"
|
||||
},
|
||||
"fr": {
|
||||
"service:001": "Informations sur l'appareil",
|
||||
"service:001:property:003": "ID de l'appareil",
|
||||
"service:001:property:005": "Numéro de série (SN)",
|
||||
"service:002": "Passerelle",
|
||||
"service:002:event:001": "Changement de réseau",
|
||||
"service:002:event:002": "Changement de réseau",
|
||||
"service:002:property:001": "Méthode d'accès",
|
||||
"service:002:property:001:valuelist:000": "Câblé",
|
||||
"service:002:property:001:valuelist:001": "Sans fil 5G",
|
||||
"service:002:property:001:valuelist:002": "Sans fil 2.4G",
|
||||
"service:002:property:002": "Adresse IP",
|
||||
"service:002:property:003": "Nom du réseau WiFi",
|
||||
"service:002:property:004": "Heure actuelle",
|
||||
"service:002:property:005": "Adresse MAC du serveur DHCP",
|
||||
"service:003": "Voyant lumineux",
|
||||
"service:003:property:001": "Interrupteur",
|
||||
"service:004": "Service virtuel",
|
||||
"service:004:action:001": "Générer un événement virtuel",
|
||||
"service:004:event:001": "Événement virtuel survenu",
|
||||
"service:004:property:001": "Nom de l'événement"
|
||||
},
|
||||
"ja": {
|
||||
"service:001": "デバイス情報",
|
||||
"service:001:property:003": "デバイスID",
|
||||
"service:001:property:005": "シリアル番号 (SN)",
|
||||
"service:002": "ゲートウェイ",
|
||||
"service:002:event:001": "ネットワークが変更されました",
|
||||
"service:002:event:002": "ネットワークが変更されました",
|
||||
"service:002:property:001": "アクセス方法",
|
||||
"service:002:property:001:valuelist:000": "有線",
|
||||
"service:002:property:001:valuelist:001": "5G ワイヤレス",
|
||||
"service:002:property:001:valuelist:002": "2.4G ワイヤレス",
|
||||
"service:002:property:002": "IPアドレス",
|
||||
"service:002:property:003": "WiFiネットワーク名",
|
||||
"service:002:property:004": "現在の時間",
|
||||
"service:002:property:005": "DHCPサーバーMACアドレス",
|
||||
"service:003": "インジケータライト",
|
||||
"service:003:property:001": "スイッチ",
|
||||
"service:004": "バーチャルサービス",
|
||||
"service:004:action:001": "バーチャルイベントを生成",
|
||||
"service:004:event:001": "バーチャルイベントが発生しました",
|
||||
"service:004:property:001": "イベント名"
|
||||
},
|
||||
"ru": {
|
||||
"service:001": "Информация об устройстве",
|
||||
"service:001:property:003": "ID устройства",
|
||||
"service:001:property:005": "Серийный номер (SN)",
|
||||
"service:002": "Шлюз",
|
||||
"service:002:event:001": "Сеть изменена",
|
||||
"service:002:event:002": "Сеть изменена",
|
||||
"service:002:property:001": "Метод доступа",
|
||||
"service:002:property:001:valuelist:000": "Проводной",
|
||||
"service:002:property:001:valuelist:001": "5G Беспроводной",
|
||||
"service:002:property:001:valuelist:002": "2.4G Беспроводной",
|
||||
"service:002:property:002": "IP Адрес",
|
||||
"service:002:property:003": "Название WiFi сети",
|
||||
"service:002:property:004": "Текущее время",
|
||||
"service:002:property:005": "MAC адрес DHCP сервера",
|
||||
"service:003": "Световой индикатор",
|
||||
"service:003:property:001": "Переключатель",
|
||||
"service:004": "Виртуальная служба",
|
||||
"service:004:action:001": "Создать виртуальное событие",
|
||||
"service:004:event:001": "Произошло виртуальное событие",
|
||||
"service:004:property:001": "Название события"
|
||||
},
|
||||
"zh-Hant": {
|
||||
"service:001": "設備信息",
|
||||
"service:001:property:003": "設備ID",
|
||||
"service:001:property:005": "序號 (SN)",
|
||||
"service:002": "網關",
|
||||
"service:002:event:001": "網路發生變化",
|
||||
"service:002:event:002": "網路發生變化",
|
||||
"service:002:property:001": "接入方式",
|
||||
"service:002:property:001:valuelist:000": "有線",
|
||||
"service:002:property:001:valuelist:001": "5G 無線",
|
||||
"service:002:property:001:valuelist:002": "2.4G 無線",
|
||||
"service:002:property:002": "IP地址",
|
||||
"service:002:property:003": "WiFi網路名稱",
|
||||
"service:002:property:004": "當前時間",
|
||||
"service:002:property:005": "DHCP伺服器MAC地址",
|
||||
"service:003": "指示燈",
|
||||
"service:003:property:001": "開關",
|
||||
"service:004": "虛擬服務",
|
||||
"service:004:action:001": "產生虛擬事件",
|
||||
"service:004:event:001": "虛擬事件發生",
|
||||
"service:004:property:001": "事件名稱"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:switch:0000A003:lumi-acn040": {
|
||||
"en": {
|
||||
"service:011": "Right Button On and Off",
|
||||
"service:011:property:001": "Right Button On and Off",
|
||||
"service:015:action:001": "Left Button Identify",
|
||||
"service:016:action:001": "Middle Button Identify",
|
||||
"service:017:action:001": "Right Button Identify"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:015:action:001": "左键确认",
|
||||
"service:016:action:001": "中键确认",
|
||||
"service:017:action:001": "右键确认"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:bath-heater:0000A028:yeelink-v10": {
|
||||
"en": {
|
||||
"service:003:property:001:valuelist:000": "Idle",
|
||||
"service:003:property:001:valuelist:001": "Dry"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:plant-monitor:0000A030:hhcc-v1": {
|
||||
"en": {
|
||||
"service:002:property:001": "Soil Moisture"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:002:property:001": "土壤湿度",
|
||||
"service:002:property:003": "光照强度"
|
||||
}
|
||||
"urn:miot-spec-v2:device:bath-heater:0000A028:yeelink-v10": {
|
||||
"en": {
|
||||
"service:003:property:001:valuelist:000": "Idle",
|
||||
"service:003:property:001:valuelist:001": "Dry"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:electronic-valve:0000A0A7:ykcn-cbcs": {
|
||||
"zh-Hans": {
|
||||
"service:004:property:001": "功率过高-阈值设置",
|
||||
"service:004:property:009": "欠压告警-阈值设置"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:fan:0000A005:zhimi-za1": {
|
||||
"zh-Hans": {
|
||||
"service:002:property:005:valuelist:000": "自然风",
|
||||
"service:002:property:005:valuelist:001": "直吹风"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1": {
|
||||
"de": {
|
||||
"service:001": "Geräteinformationen",
|
||||
"service:001:property:003": "Geräte-ID",
|
||||
"service:001:property:005": "Seriennummer (SN)",
|
||||
"service:002": "Gateway",
|
||||
"service:002:event:001": "Netzwerk geändert",
|
||||
"service:002:event:002": "Netzwerk geändert",
|
||||
"service:002:property:001": "Zugriffsmethode",
|
||||
"service:002:property:001:valuelist:000": "Kabelgebunden",
|
||||
"service:002:property:001:valuelist:001": "5G Drahtlos",
|
||||
"service:002:property:001:valuelist:002": "2.4G Drahtlos",
|
||||
"service:002:property:002": "IP-Adresse",
|
||||
"service:002:property:003": "WiFi-Netzwerkname",
|
||||
"service:002:property:004": "Aktuelle Zeit",
|
||||
"service:002:property:005": "DHCP-Server-MAC-Adresse",
|
||||
"service:003": "Anzeigelampe",
|
||||
"service:003:property:001": "Schalter",
|
||||
"service:004": "Virtueller Dienst",
|
||||
"service:004:action:001": "Virtuelles Ereignis erzeugen",
|
||||
"service:004:event:001": "Virtuelles Ereignis aufgetreten",
|
||||
"service:004:property:001": "Ereignisname"
|
||||
},
|
||||
"en": {
|
||||
"service:001": "Device Information",
|
||||
"service:001:property:003": "Device ID",
|
||||
"service:001:property:005": "Serial Number (SN)",
|
||||
"service:002": "Gateway",
|
||||
"service:002:event:001": "Network Changed",
|
||||
"service:002:event:002": "Network Changed",
|
||||
"service:002:property:001": "Access Method",
|
||||
"service:002:property:001:valuelist:000": "Wired",
|
||||
"service:002:property:001:valuelist:001": "5G Wireless",
|
||||
"service:002:property:001:valuelist:002": "2.4G Wireless",
|
||||
"service:002:property:002": "IP Address",
|
||||
"service:002:property:003": "WiFi Network Name",
|
||||
"service:002:property:004": "Current Time",
|
||||
"service:002:property:005": "DHCP Server MAC Address",
|
||||
"service:003": "Indicator Light",
|
||||
"service:003:property:001": "Switch",
|
||||
"service:004": "Virtual Service",
|
||||
"service:004:action:001": "Generate Virtual Event",
|
||||
"service:004:event:001": "Virtual Event Occurred",
|
||||
"service:004:property:001": "Event Name"
|
||||
},
|
||||
"es": {
|
||||
"service:001": "Información del dispositivo",
|
||||
"service:001:property:003": "ID del dispositivo",
|
||||
"service:001:property:005": "Número de serie (SN)",
|
||||
"service:002": "Puerta de enlace",
|
||||
"service:002:event:001": "Cambio de red",
|
||||
"service:002:event:002": "Cambio de red",
|
||||
"service:002:property:001": "Método de acceso",
|
||||
"service:002:property:001:valuelist:000": "Cableado",
|
||||
"service:002:property:001:valuelist:001": "5G inalámbrico",
|
||||
"service:002:property:001:valuelist:002": "2.4G inalámbrico",
|
||||
"service:002:property:002": "Dirección IP",
|
||||
"service:002:property:003": "Nombre de red WiFi",
|
||||
"service:002:property:004": "Hora actual",
|
||||
"service:002:property:005": "Dirección MAC del servidor DHCP",
|
||||
"service:003": "Luz indicadora",
|
||||
"service:003:property:001": "Interruptor",
|
||||
"service:004": "Servicio virtual",
|
||||
"service:004:action:001": "Generar evento virtual",
|
||||
"service:004:event:001": "Ocurrió un evento virtual",
|
||||
"service:004:property:001": "Nombre del evento"
|
||||
},
|
||||
"fr": {
|
||||
"service:001": "Informations sur l'appareil",
|
||||
"service:001:property:003": "ID de l'appareil",
|
||||
"service:001:property:005": "Numéro de série (SN)",
|
||||
"service:002": "Passerelle",
|
||||
"service:002:event:001": "Changement de réseau",
|
||||
"service:002:event:002": "Changement de réseau",
|
||||
"service:002:property:001": "Méthode d'accès",
|
||||
"service:002:property:001:valuelist:000": "Câblé",
|
||||
"service:002:property:001:valuelist:001": "Sans fil 5G",
|
||||
"service:002:property:001:valuelist:002": "Sans fil 2.4G",
|
||||
"service:002:property:002": "Adresse IP",
|
||||
"service:002:property:003": "Nom du réseau WiFi",
|
||||
"service:002:property:004": "Heure actuelle",
|
||||
"service:002:property:005": "Adresse MAC du serveur DHCP",
|
||||
"service:003": "Voyant lumineux",
|
||||
"service:003:property:001": "Interrupteur",
|
||||
"service:004": "Service virtuel",
|
||||
"service:004:action:001": "Générer un événement virtuel",
|
||||
"service:004:event:001": "Événement virtuel survenu",
|
||||
"service:004:property:001": "Nom de l'événement"
|
||||
},
|
||||
"ja": {
|
||||
"service:001": "デバイス情報",
|
||||
"service:001:property:003": "デバイスID",
|
||||
"service:001:property:005": "シリアル番号 (SN)",
|
||||
"service:002": "ゲートウェイ",
|
||||
"service:002:event:001": "ネットワークが変更されました",
|
||||
"service:002:event:002": "ネットワークが変更されました",
|
||||
"service:002:property:001": "アクセス方法",
|
||||
"service:002:property:001:valuelist:000": "有線",
|
||||
"service:002:property:001:valuelist:001": "5G ワイヤレス",
|
||||
"service:002:property:001:valuelist:002": "2.4G ワイヤレス",
|
||||
"service:002:property:002": "IPアドレス",
|
||||
"service:002:property:003": "WiFiネットワーク名",
|
||||
"service:002:property:004": "現在の時間",
|
||||
"service:002:property:005": "DHCPサーバーMACアドレス",
|
||||
"service:003": "インジケータライト",
|
||||
"service:003:property:001": "スイッチ",
|
||||
"service:004": "バーチャルサービス",
|
||||
"service:004:action:001": "バーチャルイベントを生成",
|
||||
"service:004:event:001": "バーチャルイベントが発生しました",
|
||||
"service:004:property:001": "イベント名"
|
||||
},
|
||||
"ru": {
|
||||
"service:001": "Информация об устройстве",
|
||||
"service:001:property:003": "ID устройства",
|
||||
"service:001:property:005": "Серийный номер (SN)",
|
||||
"service:002": "Шлюз",
|
||||
"service:002:event:001": "Сеть изменена",
|
||||
"service:002:event:002": "Сеть изменена",
|
||||
"service:002:property:001": "Метод доступа",
|
||||
"service:002:property:001:valuelist:000": "Проводной",
|
||||
"service:002:property:001:valuelist:001": "5G Беспроводной",
|
||||
"service:002:property:001:valuelist:002": "2.4G Беспроводной",
|
||||
"service:002:property:002": "IP Адрес",
|
||||
"service:002:property:003": "Название WiFi сети",
|
||||
"service:002:property:004": "Текущее время",
|
||||
"service:002:property:005": "MAC адрес DHCP сервера",
|
||||
"service:003": "Световой индикатор",
|
||||
"service:003:property:001": "Переключатель",
|
||||
"service:004": "Виртуальная служба",
|
||||
"service:004:action:001": "Создать виртуальное событие",
|
||||
"service:004:event:001": "Произошло виртуальное событие",
|
||||
"service:004:property:001": "Название события"
|
||||
},
|
||||
"zh-Hant": {
|
||||
"service:001": "設備信息",
|
||||
"service:001:property:003": "設備ID",
|
||||
"service:001:property:005": "序號 (SN)",
|
||||
"service:002": "網關",
|
||||
"service:002:event:001": "網路發生變化",
|
||||
"service:002:event:002": "網路發生變化",
|
||||
"service:002:property:001": "接入方式",
|
||||
"service:002:property:001:valuelist:000": "有線",
|
||||
"service:002:property:001:valuelist:001": "5G 無線",
|
||||
"service:002:property:001:valuelist:002": "2.4G 無線",
|
||||
"service:002:property:002": "IP地址",
|
||||
"service:002:property:003": "WiFi網路名稱",
|
||||
"service:002:property:004": "當前時間",
|
||||
"service:002:property:005": "DHCP伺服器MAC地址",
|
||||
"service:003": "指示燈",
|
||||
"service:003:property:001": "開關",
|
||||
"service:004": "虛擬服務",
|
||||
"service:004:action:001": "產生虛擬事件",
|
||||
"service:004:event:001": "虛擬事件發生",
|
||||
"service:004:property:001": "事件名稱"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:lock:0000A038:loock-t2pv1": {
|
||||
"zh-Hans": {
|
||||
"service:003:property:1021:valuelist:000": "已上锁",
|
||||
"service:003:property:1021:valuelist:001": "已上锁(童锁)",
|
||||
"service:003:property:1021:valuelist:002": "已上锁(反锁)",
|
||||
"service:003:property:1021:valuelist:003": "已上锁(反锁+童锁)",
|
||||
"service:003:property:1021:valuelist:004": "已开锁",
|
||||
"service:003:property:1021:valuelist:008": "门未关(门超时未关)",
|
||||
"service:003:property:1021:valuelist:012": "门虚掩"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:plant-monitor:0000A030:hhcc-v1": {
|
||||
"en": {
|
||||
"service:002:property:001": "Soil Moisture"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:002:property:001": "土壤湿度",
|
||||
"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": {
|
||||
"en": {
|
||||
"service:011": "Right Button On and Off",
|
||||
"service:011:property:001": "Right Button On and Off",
|
||||
"service:015:action:001": "Left Button Identify",
|
||||
"service:016:action:001": "Middle Button Identify",
|
||||
"service:017:action:001": "Right Button Identify"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:015:action:001": "左键确认",
|
||||
"service:016:action:001": "中键确认",
|
||||
"service:017:action:001": "右键确认"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:thermostat:0000A031:cubee-th123e": {
|
||||
"ru": {
|
||||
"service:002": "термостат",
|
||||
"service:002:property:001": "выключатель",
|
||||
"service:002:property:002": "режим нагрузки",
|
||||
"service:002:property:002:valuelist:000": "без подогрева",
|
||||
"service:002:property:002:valuelist:001": "нагрев",
|
||||
"service:002:property:003": "неисправность",
|
||||
"service:002:property:003:valuelist:000": "ошибка датчика",
|
||||
"service:002:property:003:valuelist:001": "без ошибок",
|
||||
"service:002:property:003:valuelist:002": "защита от высоких температур",
|
||||
"service:002:property:003:valuelist:003": "криогенная защита",
|
||||
"service:002:property:004": "режим",
|
||||
"service:002:property:004:valuelist:000": "ручной режим",
|
||||
"service:002:property:004:valuelist:001": "домашний режим",
|
||||
"service:002:property:004:valuelist:002": "режим выхода из дома",
|
||||
"service:002:property:004:valuelist:003": "автоматический режим",
|
||||
"service:002:property:004:valuelist:004": "Режим сна",
|
||||
"service:002:property:005": "температура цели",
|
||||
"service:002:property:007": "текущая температура",
|
||||
"service:004": "Пользовательские услуги",
|
||||
"service:004:property:001": "детский замок",
|
||||
"service:004:property:002": "тип датчика",
|
||||
"service:004:property:002:valuelist:000": "внутренний датчик",
|
||||
"service:004:property:002:valuelist:001": "выносной датчик",
|
||||
"service:004:property:002:valuelist:002": "встроенный и внешний датчик",
|
||||
"service:004:property:003": "пусковая разность температур",
|
||||
"service:004:property:004": "компенсационная температура",
|
||||
"service:004:property:005": "температура выносного датчика",
|
||||
"service:004:property:006": "максимальная температура цели",
|
||||
"service:004:property:007": "минимальная температура цели "
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:thermostat:0000A031:cubee-th123w": {
|
||||
"ru": {
|
||||
"service:002": "термостат",
|
||||
"service:002:property:001": "выключатель",
|
||||
"service:002:property:002": "режим нагрузки",
|
||||
"service:002:property:002:valuelist:000": "нагрев",
|
||||
"service:002:property:002:valuelist:001": "без подогрева",
|
||||
"service:002:property:003": "неисправность",
|
||||
"service:002:property:003:valuelist:000": "без ошибок",
|
||||
"service:002:property:003:valuelist:001": "ошибка датчика",
|
||||
"service:002:property:003:valuelist:002": "защита от высоких температур",
|
||||
"service:002:property:003:valuelist:003": "криогенная защита",
|
||||
"service:002:property:004": "режим",
|
||||
"service:002:property:004:valuelist:000": "ручной режим",
|
||||
"service:002:property:004:valuelist:001": "домашний режим",
|
||||
"service:002:property:004:valuelist:002": "режим выхода из дома",
|
||||
"service:002:property:004:valuelist:003": "автоматический режим",
|
||||
"service:002:property:004:valuelist:004": "Режим сна",
|
||||
"service:002:property:005": "температура цели",
|
||||
"service:002:property:007": "текущая температура",
|
||||
"service:004": "Пользовательские услуги",
|
||||
"service:004:property:001": "детский замок",
|
||||
"service:004:property:002": "тип датчика",
|
||||
"service:004:property:002:valuelist:000": "внутренний датчик",
|
||||
"service:004:property:002:valuelist:001": "выносной датчик",
|
||||
"service:004:property:002:valuelist:002": "встроенный и внешний датчик",
|
||||
"service:004:property:003": "пусковая разность температур",
|
||||
"service:004:property:004": "компенсационная температура",
|
||||
"service:004:property:005": "температура выносного датчика",
|
||||
"service:004:property:006": "максимальная температура цели",
|
||||
"service:004:property:007": "минимальная температура цели "
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:thermostat:0000A031:tofan-wk01": {
|
||||
"en": {
|
||||
"service:002": "Thermostat",
|
||||
"service:002:property:002": "Air Conditioner Mode",
|
||||
"service:004": "Air Conditioner"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:002": "地暖",
|
||||
"service:004": "空调"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:vacuum:0000A006:ijai-v1": {
|
||||
"zh-Hans": {
|
||||
"service:007:property:005:valuelist:000": "安静",
|
||||
"service:007:property:005:valuelist:001": "标准",
|
||||
"service:007:property:005:valuelist:002": "中档",
|
||||
"service:007:property:005:valuelist:003": "强力"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,9 @@
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:090615-ktf:
|
||||
services:
|
||||
- '4'
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:759413-iez:
|
||||
properties:
|
||||
- '2.3'
|
||||
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ma4:
|
||||
properties:
|
||||
- 9.*
|
||||
@@ -41,6 +47,23 @@ urn:miot-spec-v2:device:motion-sensor:0000A014:xiaomi-pir1:
|
||||
services:
|
||||
- '1'
|
||||
- '5'
|
||||
urn:miot-spec-v2:device:router:0000A036:xiaomi-rd03:
|
||||
urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l15a:
|
||||
properties:
|
||||
- '3.3'
|
||||
- '6.1'
|
||||
- '6.2'
|
||||
- '6.3'
|
||||
- '6.4'
|
||||
urn:miot-spec-v2:device:thermostat:0000A031:tofan-wk01:
|
||||
services:
|
||||
- '2'
|
||||
- '4'
|
||||
urn:miot-spec-v2:device:vacuum:0000A006:narwa-001:
|
||||
services:
|
||||
- '*'
|
||||
urn:miot-spec-v2:device:vacuum:0000A006:narwa-ax11:
|
||||
services:
|
||||
- '*'
|
||||
urn:miot-spec-v2:device:vacuum:0000A006:roidmi-v60:
|
||||
actions:
|
||||
- '2.3'
|
||||
|
||||
@@ -1,3 +1,52 @@
|
||||
urn:miot-spec-v2:device:air-condition-outlet:0000A045:lumi-mcn04:1:
|
||||
prop.3.4:
|
||||
format: uint8
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:qdhkl-a42:1:
|
||||
prop.2.2:
|
||||
value-list:
|
||||
- value: 1
|
||||
description: Cool
|
||||
- value: 2
|
||||
description: Dry
|
||||
- value: 4
|
||||
description: Fan
|
||||
- value: 8
|
||||
description: Heat
|
||||
- value: 9
|
||||
description: Auto
|
||||
- value: 10
|
||||
description: Heat_cool
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c17:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c17:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c17:1
|
||||
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.8.6:
|
||||
unit: kWh
|
||||
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-h40h00:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-h43h00:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-h43h00:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-h43h00:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:3: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:4: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16: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: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
|
||||
@@ -6,9 +55,43 @@ 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:
|
||||
prop.10.6:
|
||||
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-conditioner:0000A004:xiaomi-rr0r00:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
prop.3.12:
|
||||
name: vertical-swing-left-up
|
||||
prop.3.13:
|
||||
name: vertical-swing-left-down
|
||||
prop.3.14:
|
||||
name: vertical-swing-right-up
|
||||
prop.3.15:
|
||||
name: vertical-swing-right-down
|
||||
prop.3.20:
|
||||
name: horizontal-swing-left
|
||||
prop.3.22:
|
||||
name: horizontal-swing-right
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:3: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:4: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:1
|
||||
urn:miot-spec-v2:device:air-monitor:0000A008:cgllc-cgd1st:1:
|
||||
prop.3.7:
|
||||
value-range:
|
||||
- -30
|
||||
- 100
|
||||
- 0.1
|
||||
urn:miot-spec-v2:device:air-monitor:0000A008:cgllc-s1:1:
|
||||
prop.2.5:
|
||||
name: voc-density
|
||||
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:1: urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:3
|
||||
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:2: urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:3
|
||||
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:3:
|
||||
prop.3.5:
|
||||
expr: (src_value*6)
|
||||
urn:miot-spec-v2:device:airer:0000A00D:hyd-lyjpro:1:
|
||||
prop.2.3:
|
||||
name: current-position-a
|
||||
@@ -16,6 +99,8 @@ urn:miot-spec-v2:device:airer:0000A00D:hyd-lyjpro:1:
|
||||
name: target-position-a
|
||||
prop.2.9:
|
||||
name: target-position-b
|
||||
prop.2.11:
|
||||
expr: (100-src_value)
|
||||
urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:1:
|
||||
prop.2.3:
|
||||
value-range:
|
||||
@@ -23,6 +108,9 @@ urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:1:
|
||||
- 1
|
||||
- 1
|
||||
urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:2: urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:1
|
||||
urn:miot-spec-v2:device:airer:0000A00D:mrbond-m1t:1:
|
||||
prop.2.3:
|
||||
name: current-position-a
|
||||
urn:miot-spec-v2:device:airer:0000A00D:mrbond-m33a:1:
|
||||
prop.2.3:
|
||||
name: current-position-a
|
||||
@@ -47,11 +135,88 @@ urn:miot-spec-v2:device:bath-heater:0000A028:opple-acmoto:1:
|
||||
urn:miot-spec-v2:device:bath-heater:0000A028:xiaomi-s1:1:
|
||||
prop.4.4:
|
||||
name: fan-level-ventilation
|
||||
urn:miot-spec-v2:device:curtain:0000A00C:bjkcz-kczble:1:0000D031:
|
||||
prop.2.2:
|
||||
name: status-a
|
||||
urn:miot-spec-v2:device:electronic-valve:0000A0A7:sanmei-s1:1:
|
||||
prop.3.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 99999999
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
prop.3.2:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 16777216
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
prop.3.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
urn:miot-spec-v2:device:electronic-valve:0000A0A7:ykcn-cbcs:1:0000C833:
|
||||
prop.3.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 99999999
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
prop.3.2:
|
||||
unit: mA
|
||||
prop.3.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
prop.4.1:
|
||||
unit: kW
|
||||
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:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p43:1:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p45:1:0000D062:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p51:1:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p69:1:0000D062:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p70:1:0000D062:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p76:1:0000D062:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:zhimi-sa1:3:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:zhimi-v3:3:
|
||||
prop.2.6:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:zhimi-za4:3:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:gateway:0000A019:lumi-mcn001:1:
|
||||
prop.2.1:
|
||||
@@ -84,19 +249,67 @@ urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:1:
|
||||
- notify
|
||||
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:2: urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:1
|
||||
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:3: urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:1
|
||||
urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:1: urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:3
|
||||
urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:2: urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:3
|
||||
urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:3:
|
||||
prop.3.1:
|
||||
name: on-ventilation
|
||||
urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:4: urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:3
|
||||
urn:miot-spec-v2:device:humidifier:0000A00E:zhimi-ca4:2:
|
||||
prop.2.7:
|
||||
unit: percentage
|
||||
expr: round(src_value*0.83)
|
||||
urn:miot-spec-v2:device:kettle:0000A009:yunmi-r3:1:
|
||||
prop.3.1:
|
||||
unit: ppm
|
||||
urn:miot-spec-v2:device:light:0000A001:shhf-sfla10:1:
|
||||
prop.8.9:
|
||||
name: wind-reverse
|
||||
urn:miot-spec-v2:device:light:0000A001:shhf-sfla12:1:
|
||||
prop.8.11:
|
||||
name: on-a
|
||||
urn:miot-spec-v2:device:magnet-sensor:0000A016:linp-m1:1: # linp.magnet.m1
|
||||
urn:miot-spec-v2:device:light:0000A001:shhf-sflt11:1:0000C802:
|
||||
prop.11.14:
|
||||
name: on-power
|
||||
urn:miot-spec-v2:device:magnet-sensor:0000A016:linp-m1:1:
|
||||
prop.2.1004:
|
||||
name: contact-state
|
||||
expr: src_value!=1
|
||||
value-list:
|
||||
- value: 0
|
||||
description: open
|
||||
- value: 1
|
||||
description: closed
|
||||
expr: (src_value!=1)
|
||||
urn:miot-spec-v2:device:motion-sensor:0000A014:lumi-acn001:1:
|
||||
prop.3.2:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
unit: mV
|
||||
urn:miot-spec-v2:device:motion-sensor:0000A014:lumi-bmgl01:1:
|
||||
prop.2.2:
|
||||
value-list:
|
||||
- value: 0
|
||||
description: 0 Seconds
|
||||
- value: 2
|
||||
description: 2 Minutes
|
||||
- value: 5
|
||||
description: 5 Minutes
|
||||
urn:miot-spec-v2:device:motor-controller:0000A01D:adp-adswb4:1:0000C837:
|
||||
prop.2.1:
|
||||
name: motor-switch
|
||||
urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:ainice-3b:1: urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:ainice-3b:2
|
||||
urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:ainice-3b:2:
|
||||
prop.2.5:
|
||||
name: people-number
|
||||
prop.2.8:
|
||||
name: people-number
|
||||
prop.2.11:
|
||||
name: people-number
|
||||
prop.2.14:
|
||||
name: people-number
|
||||
prop.2.17:
|
||||
name: people-number
|
||||
urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:izq-24:2:0000C824:
|
||||
prop.2.6:
|
||||
unit: cm
|
||||
@@ -107,32 +320,83 @@ urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:1: urn:miot-spec-v2:devi
|
||||
urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:2: urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:3
|
||||
urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:3:
|
||||
prop.5.1:
|
||||
expr: round(src_value*6/1000000, 3)
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.01
|
||||
expr: round(src_value*6/1000000, 2)
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp1md:1:
|
||||
prop.2.2:
|
||||
name: power-consumption
|
||||
expr: round(src_value/1000, 3)
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.01
|
||||
expr: round(src_value/1000, 2)
|
||||
prop.2.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 3000
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
prop.2.4:
|
||||
unit: mA
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp2:1: urn:miot-spec-v2:device:outlet:0000A002:cuco-cp2:2
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp2:2:
|
||||
prop.2.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 3000
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
prop.2.4:
|
||||
unit: mA
|
||||
prop.3.2:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp2d:1:
|
||||
prop.3.2:
|
||||
unit: mA
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-v3:1:
|
||||
prop.11.1:
|
||||
name: power-consumption
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-v3:2: urn:miot-spec-v2:device:outlet:0000A002:cuco-v3:1
|
||||
urn:miot-spec-v2:device:outlet:0000A002:giot-v8icm:1:0000C816:
|
||||
prop.4.1:
|
||||
unit: mWh
|
||||
urn:miot-spec-v2:device:outlet:0000A002:qmi-psv3:1:0000C816:
|
||||
prop.3.3:
|
||||
unit: mV
|
||||
prop.3.4:
|
||||
unit: mA
|
||||
urn:miot-spec-v2:device:outlet:0000A002:yutai-fsov8m:1:0000C816:
|
||||
prop.4.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 429497
|
||||
- 0.01
|
||||
expr: round(src_value/10000, 2)
|
||||
urn:miot-spec-v2:device:outlet:0000A002:zimi-zncz01:1:0000C816: urn:miot-spec-v2:device:outlet:0000A002:zimi-zncz01:2:0000C816
|
||||
urn:miot-spec-v2:device:outlet:0000A002:zimi-zncz01:2:0000C816:
|
||||
prop.3.1:
|
||||
name: electric-power
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 350000
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
urn:miot-spec-v2:device:plant-monitor:0000A030:hhcc-v1:1:
|
||||
prop.2.1:
|
||||
@@ -154,10 +418,32 @@ urn:miot-spec-v2:device:router:0000A036:xiaomi-rd08:1:
|
||||
name: upload-speed
|
||||
icon: mdi:upload
|
||||
unit: B/s
|
||||
urn:miot-spec-v2:device:safe-box:0000A042:loock-v1:1: # loock.safe.v1
|
||||
urn:miot-spec-v2:device:safe-box:0000A042:loock-v1:1:
|
||||
prop.5.1:
|
||||
name: contact-state
|
||||
expr: src_value!=1
|
||||
expr: (src_value!=1)
|
||||
urn:miot-spec-v2:device:switch:0000A003:090615-x1tpm:1:0000D042:
|
||||
prop.27.3:
|
||||
name: light-on
|
||||
prop.27.4:
|
||||
name: light-fan-on
|
||||
urn:miot-spec-v2:device:switch:0000A003:lxzn-cbcsmj:1:0000D00D:
|
||||
prop.3.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 99999999
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
prop.3.2:
|
||||
unit: mA
|
||||
prop.3.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
urn:miot-spec-v2:device:thermostat:0000A031:suittc-wk168:1:
|
||||
prop.2.3:
|
||||
value-list:
|
||||
|
||||
@@ -50,18 +50,11 @@ from homeassistant.components.sensor import SensorStateClass
|
||||
from homeassistant.components.event import EventDeviceClass
|
||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
EntityCategory,
|
||||
LIGHT_LUX,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfTemperature,
|
||||
UnitOfPressure,
|
||||
PERCENTAGE
|
||||
)
|
||||
from homeassistant.const import (CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
EntityCategory, LIGHT_LUX, UnitOfEnergy,
|
||||
UnitOfPower, UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential, UnitOfTemperature,
|
||||
UnitOfPressure, PERCENTAGE)
|
||||
|
||||
# pylint: disable=pointless-string-statement
|
||||
"""SPEC_DEVICE_TRANS_MAP
|
||||
@@ -107,7 +100,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'humidifier': {
|
||||
'required': {
|
||||
'humidifier': {
|
||||
'required': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
@@ -119,7 +112,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'optional': {
|
||||
'environment': {
|
||||
'required': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'relative-humidity': {'read'}
|
||||
}
|
||||
@@ -131,7 +124,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'dehumidifier': {
|
||||
'required': {
|
||||
'dehumidifier': {
|
||||
'required': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
@@ -143,7 +136,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'optional': {
|
||||
'environment': {
|
||||
'required': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'relative-humidity': {'read'}
|
||||
}
|
||||
@@ -155,15 +148,13 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'vacuum': {
|
||||
'required': {
|
||||
'vacuum': {
|
||||
'required': {
|
||||
'required': {
|
||||
'actions': {'start-sweep', 'stop-sweeping'},
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'status', 'fan-level'},
|
||||
'actions': {
|
||||
'pause-sweeping',
|
||||
'continue-sweep',
|
||||
'stop-and-gocharge'
|
||||
'pause-sweeping', 'continue-sweep', 'stop-and-gocharge'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,13 +162,13 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'optional': {
|
||||
'identify': {
|
||||
'required': {
|
||||
'actions': {'identify'}
|
||||
'actions': {'identify'}
|
||||
}
|
||||
},
|
||||
'battery': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'battery-level': {'read'}
|
||||
'actions': {
|
||||
'start-charge'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,10 +195,9 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'on',
|
||||
'fan-level',
|
||||
'horizontal-swing',
|
||||
'vertical-swing'}}
|
||||
'on', 'fan-level', 'horizontal-swing', 'vertical-swing'
|
||||
}
|
||||
}
|
||||
},
|
||||
'environment': {
|
||||
'required': {},
|
||||
@@ -235,8 +225,8 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'target-temperature', 'mode', 'fan-level',
|
||||
'temperature'}
|
||||
'target-temperature', 'mode', 'fan-level', 'temperature'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -278,7 +268,7 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'ptc-bath-heater': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'mode':{'read', 'write'}
|
||||
'mode': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
@@ -321,6 +311,89 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'optional': {},
|
||||
'entity': 'electric-blanket'
|
||||
},
|
||||
'speaker': {
|
||||
'required': {
|
||||
'speaker': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'volume': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mute'}
|
||||
}
|
||||
},
|
||||
'play-control': {
|
||||
'required': {
|
||||
'actions': {'play'}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'playing-state'},
|
||||
'actions': {'pause', 'stop', 'next', 'previous'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {},
|
||||
'entity': 'wifi-speaker'
|
||||
},
|
||||
'television': {
|
||||
'required': {
|
||||
'speaker': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'volume': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mute'}
|
||||
}
|
||||
},
|
||||
'television': {
|
||||
'required': {
|
||||
'actions': {'turn-off'}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'input-control'},
|
||||
'actions': {'turn-on'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'play-control': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {'playing-state'},
|
||||
'actions': {'play', 'pause', 'stop', 'next', 'previous'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'television'
|
||||
},
|
||||
'watch': {
|
||||
'required': {
|
||||
'watch': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'longitude': {'read'},
|
||||
'latitude': {'read'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'area-id'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'battery': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'battery-level': {'read'}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'device_tracker'
|
||||
}
|
||||
}
|
||||
|
||||
"""SPEC_SERVICE_TRANS_MAP
|
||||
@@ -351,9 +424,7 @@ SPEC_SERVICE_TRANS_MAP: dict = {
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'mode', 'brightness', 'color', 'color-temperature'
|
||||
}
|
||||
'properties': {'mode', 'brightness', 'color', 'color-temperature'}
|
||||
},
|
||||
'entity': 'light'
|
||||
},
|
||||
@@ -368,7 +439,8 @@ SPEC_SERVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'mode', 'brightness',
|
||||
'mode',
|
||||
'brightness',
|
||||
}
|
||||
},
|
||||
'entity': 'light',
|
||||
@@ -389,6 +461,7 @@ SPEC_SERVICE_TRANS_MAP: dict = {
|
||||
'fan-control': 'fan',
|
||||
'ceiling-fan': 'fan',
|
||||
'air-fresh': 'fan',
|
||||
'air-purifier': 'fan',
|
||||
'water-heater': {
|
||||
'required': {
|
||||
'properties': {
|
||||
@@ -396,20 +469,18 @@ SPEC_SERVICE_TRANS_MAP: dict = {
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'on', 'temperature', 'target-temperature', 'mode'}
|
||||
'properties': {'temperature', 'target-temperature', 'mode'}
|
||||
},
|
||||
'entity': 'water_heater'
|
||||
},
|
||||
'curtain': {
|
||||
'curtain': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'motor-control': {'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'status', 'current-position', 'target-position'
|
||||
}
|
||||
'properties': {'status', 'current-position', 'target-position'}
|
||||
},
|
||||
'entity': 'cover'
|
||||
},
|
||||
@@ -599,6 +670,4 @@ SPEC_EVENT_TRANS_MAP: dict[str, str] = {
|
||||
'doorbell-ring': EventDeviceClass.DOORBELL
|
||||
}
|
||||
|
||||
SPEC_ACTION_TRANS_MAP = {
|
||||
|
||||
}
|
||||
SPEC_ACTION_TRANS_MAP = {}
|
||||
|
||||
@@ -49,7 +49,7 @@ MIoT redirect web pages.
|
||||
import os
|
||||
import asyncio
|
||||
|
||||
_template = ''
|
||||
web_template = ''
|
||||
|
||||
|
||||
def _load_page_template():
|
||||
@@ -57,18 +57,18 @@ def _load_page_template():
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
'resource/oauth_redirect_page.html')
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
global _template
|
||||
_template = f.read()
|
||||
global web_template
|
||||
web_template = f.read()
|
||||
|
||||
|
||||
async def oauth_redirect_page(
|
||||
title: str, content: str, button: str, success: bool
|
||||
) -> str:
|
||||
"""Return oauth redirect page."""
|
||||
if _template == '':
|
||||
if web_template == '':
|
||||
await asyncio.get_running_loop().run_in_executor(
|
||||
None, _load_page_template)
|
||||
web_page = _template.replace('TITLE_PLACEHOLDER', title)
|
||||
web_page = web_template.replace('TITLE_PLACEHOLDER', title)
|
||||
web_page = web_page.replace('CONTENT_PLACEHOLDER', content)
|
||||
web_page = web_page.replace('BUTTON_PLACEHOLDER', button)
|
||||
web_page = web_page.replace(
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Risikohinweis",
|
||||
"description": "1. Ihre **Xiaomi-Benutzerinformationen und Geräteinformationen** werden in Ihrem Home Assistant-System gespeichert. **Xiaomi kann die Sicherheit des Home Assistant-Speichermechanismus nicht garantieren**. Sie sind dafür verantwortlich, Ihre Informationen vor Diebstahl zu schützen.\r\n2. Diese Integration wird von der Open-Source-Community unterstützt und gewartet. Es können jedoch Stabilitätsprobleme oder andere Probleme auftreten. Wenn Sie auf ein Problem stoßen, das mit dieser Integration zusammenhängt, sollten Sie **die Open-Source-Community um Hilfe bitten, anstatt sich an den Xiaomi Home Kundendienst zu wenden**.\r\n3. Sie benötigen bestimmte technische Fähigkeiten, um Ihre lokale Laufzeitumgebung zu warten. Diese Integration ist für Anfänger nicht geeignet. \r\n4. Bevor Sie diese Integration verwenden, lesen Sie bitte die **README-Datei sorgfältig durch**.\r\n5. Um eine stabile Nutzung der Integration zu gewährleisten und Missbrauch der Schnittstelle zu verhindern, **darf diese Integration nur in Home Assistant verwendet werden. Weitere Informationen finden Sie in der LICENSE**.",
|
||||
"description": "1. Ihre **Xiaomi-Benutzerinformationen und Geräteinformationen** werden in Ihrem Home Assistant-System gespeichert. **Xiaomi kann die Sicherheit des Home Assistant-Speichermechanismus nicht garantieren**. Sie sind dafür verantwortlich, Ihre Informationen vor Diebstahl zu schützen.\r\n2. Diese Integration wird von der Open-Source-Community unterstützt und gewartet. Es können jedoch Stabilitätsprobleme oder andere Probleme auftreten. Wenn Sie auf ein Problem stoßen, das mit dieser Integration zusammenhängt, sollten Sie **die Open-Source-Community um Hilfe bitten, anstatt sich an den Xiaomi Home Kundendienst zu wenden**.\r\n3. Sie benötigen bestimmte technische Fähigkeiten, um Ihre lokale Laufzeitumgebung zu warten. Diese Integration ist für Anfänger nicht geeignet.\r\n4. Bevor Sie diese Integration verwenden, lesen Sie bitte die **README-Datei sorgfältig durch**.\r\n5. Um eine stabile Nutzung der Integration zu gewährleisten und Missbrauch der Schnittstelle zu verhindern, **darf diese Integration nur in Home Assistant verwendet werden. Weitere Informationen finden Sie in der LICENSE**.",
|
||||
"data": {
|
||||
"eula": "Ich habe das oben genannte Risiko zur Kenntnis genommen und übernehme freiwillig die damit verbundenen Risiken durch die Verwendung der Integration."
|
||||
}
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Gerätestatusänderungen anzeigen",
|
||||
"update_trans_rules": "Entitätskonvertierungsregeln aktualisieren",
|
||||
"update_lan_ctrl_config": "LAN-Steuerungskonfiguration aktualisieren",
|
||||
"network_detect_config": "Integrierte Netzwerkkonfiguration"
|
||||
"network_detect_config": "Integrierte Netzwerkkonfiguration",
|
||||
"cover_dead_zone_width": "Die Breite des toten Winkels des Vorhangs"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Bestätigen Sie die Konfiguration",
|
||||
"description": "**{nick_name}**, bitte bestätigen Sie die neuesten Konfigurationsinformationen und klicken Sie dann auf \"Senden\". Die Integration wird mit den aktualisierten Konfigurationen erneut geladen.\r\n\r\nIntegrationsprache:\t{lang_new}\r\nBenutzername:\t{nick_name_new}\r\nAction-Debug-Modus:\t{action_debug}\r\nVerstecke Nicht-Standard-Entitäten:\t{hide_non_standard_entities}\r\nGerätestatusänderungen anzeigen:\t{display_devices_changed_notify}\r\nGeräteänderungen:\t{devices_add} neue Geräte hinzufügen, {devices_remove} Geräte entfernen\r\nKonvertierungsregeländerungen:\tInsgesamt {trans_rules_count} Regeln, aktualisiert {trans_rules_count_success} Regeln",
|
||||
"description": "**{nick_name}**, bitte bestätigen Sie die neuesten Konfigurationsinformationen und klicken Sie dann auf \"Senden\". Die Integration wird mit den aktualisierten Konfigurationen erneut geladen.\r\n\r\nIntegrationsprache:\t{lang_new}\r\nBenutzername:\t{nick_name_new}\r\nAction-Debug-Modus:\t{action_debug}\r\nVerstecke Nicht-Standard-Entitäten:\t{hide_non_standard_entities}\r\nDie Breite des toten Winkels des Vorhangs:\t{cover_width_new}\r\nGerätestatusänderungen anzeigen:\t{display_devices_changed_notify}\r\nGeräteänderungen:\t{devices_add} neue Geräte hinzufügen, {devices_remove} Geräte entfernen\r\nKonvertierungsregeländerungen:\tInsgesamt {trans_rules_count} Regeln, aktualisiert {trans_rules_count_success} Regeln",
|
||||
"data": {
|
||||
"confirm": "Änderungen bestätigen"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Display device status change notifications",
|
||||
"update_trans_rules": "Update entity conversion rules",
|
||||
"update_lan_ctrl_config": "Update LAN control configuration",
|
||||
"network_detect_config": "Integrated Network Configuration"
|
||||
"network_detect_config": "Integrated network configuration",
|
||||
"cover_dead_zone_width": "Cover dead zone width"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirm Configuration",
|
||||
"description": "Hello **{nick_name}**, please confirm the latest configuration information and then Click SUBMIT.\r\nThe integration will reload using the updated configuration.\r\n\r\nIntegration Language: \t{lang_new}\r\nNickname: \t{nick_name_new}\r\nDebug mode for action: \t{action_debug}\r\nHide non-standard created entities: \t{hide_non_standard_entities}\r\nDisplay device status change notifications:\t{display_devices_changed_notify}\r\nDevice Changes: \tAdd **{devices_add}** devices, Remove **{devices_remove}** devices\r\nTransformation rules change: \tThere are a total of **{trans_rules_count}** rules, and updated **{trans_rules_count_success}** rules",
|
||||
"description": "Hello **{nick_name}**, please confirm the latest configuration information and then Click SUBMIT.\r\nThe integration will reload using the updated configuration.\r\n\r\nIntegration Language:\t{lang_new}\r\nNickname:\t{nick_name_new}\r\nDebug mode for action:\t{action_debug}\r\nHide non-standard created entities:\t{hide_non_standard_entities}\r\nCover dead zone width:\t{cover_width_new}\r\nDisplay device status change notifications:\t{display_devices_changed_notify}\r\nDevice Changes:\tAdd **{devices_add}** devices, Remove **{devices_remove}** devices\r\nTransformation rules change:\tThere are a total of **{trans_rules_count}** rules, and updated **{trans_rules_count_success}** rules",
|
||||
"data": {
|
||||
"confirm": "Confirm the change"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Aviso de riesgo",
|
||||
"description": "1. Su **información de usuario de Xiaomi e información del dispositivo** se almacenará en su sistema Home Assistant. **Xiaomi no puede garantizar la seguridad del mecanismo de almacenamiento de Home Assistant**. Usted es responsable de evitar que su información sea robada.\r\n2. Esta integración es mantenida por la comunidad de código abierto y puede haber problemas de estabilidad u otros problemas. Cuando tenga problemas relacionados con el uso de esta integración, **busque ayuda en la comunidad de código abierto en lugar de contactar al servicio al cliente de Xiaomi**.\r\n3. Es necesario tener ciertas habilidades técnicas para mantener su entorno de ejecución local, esta integración no es amigable para los usuarios novatos.\r\n4. Antes de utilizar esta integración, por favor **lea detenidamente el archivo README**. \r\n5. Para garantizar el uso estable de la integración y prevenir el abuso de la interfaz, **esta integración solo está permitida en Home Assistant. Para más detalles, consulte la LICENSE**.",
|
||||
"description": "1. Su **información de usuario de Xiaomi e información del dispositivo** se almacenará en su sistema Home Assistant. **Xiaomi no puede garantizar la seguridad del mecanismo de almacenamiento de Home Assistant**. Usted es responsable de evitar que su información sea robada.\r\n2. Esta integración es mantenida por la comunidad de código abierto y puede haber problemas de estabilidad u otros problemas. Cuando tenga problemas relacionados con el uso de esta integración, **busque ayuda en la comunidad de código abierto en lugar de contactar al servicio al cliente de Xiaomi**.\r\n3. Es necesario tener ciertas habilidades técnicas para mantener su entorno de ejecución local, esta integración no es amigable para los usuarios novatos.\r\n4. Antes de utilizar esta integración, por favor **lea detenidamente el archivo README**.\r\n5. Para garantizar el uso estable de la integración y prevenir el abuso de la interfaz, **esta integración solo está permitida en Home Assistant. Para más detalles, consulte la LICENSE**.",
|
||||
"data": {
|
||||
"eula": "He leído y entiendo los riesgos anteriores, y estoy dispuesto a asumir cualquier riesgo relacionado con el uso de esta integración."
|
||||
}
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Mostrar notificaciones de cambio de estado del dispositivo",
|
||||
"update_trans_rules": "Actualizar reglas de conversión de entidad",
|
||||
"update_lan_ctrl_config": "Actualizar configuración de control LAN",
|
||||
"network_detect_config": "Configuración de Red Integrada"
|
||||
"network_detect_config": "Configuración de Red Integrada",
|
||||
"cover_dead_zone_width": "Anchura del punto ciego de la cortina"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirmar configuración",
|
||||
"description": "¡Hola, **{nick_name}**! Por favor, confirme la última información de configuración y haga clic en \"Enviar\" para finalizar la configuración.\r\nLa integración se volverá a cargar con la nueva configuración.\r\n\r\nIdioma de la integración:\t{lang_new}\r\nApodo de usuario:\t{nick_name_new}\r\nModo de depuración de Action:\t{action_debug}\r\nOcultar entidades generadas no estándar:\t{hide_non_standard_entities}\r\nMostrar notificaciones de cambio de estado del dispositivo:\t{display_devices_changed_notify}\r\nCambios de dispositivos:\t{devices_add} dispositivos agregados, {devices_remove} dispositivos eliminados\r\nCambios en las reglas de conversión:\t{trans_rules_count} reglas en total, {trans_rules_count_success} reglas actualizadas",
|
||||
"description": "¡Hola, **{nick_name}**! Por favor, confirme la última información de configuración y haga clic en \"Enviar\" para finalizar la configuración.\r\nLa integración se volverá a cargar con la nueva configuración.\r\n\r\nIdioma de la integración:\t{lang_new}\r\nApodo de usuario:\t{nick_name_new}\r\nModo de depuración de Action:\t{action_debug}\r\nOcultar entidades generadas no estándar:\t{hide_non_standard_entities}\r\nAnchura del punto ciego de la cortina:\t{cover_width_new}\r\nMostrar notificaciones de cambio de estado del dispositivo:\t{display_devices_changed_notify}\r\nCambios de dispositivos:\t{devices_add} dispositivos agregados, {devices_remove} dispositivos eliminados\r\nCambios en las reglas de conversión:\t{trans_rules_count} reglas en total, {trans_rules_count_success} reglas actualizadas",
|
||||
"data": {
|
||||
"confirm": "Confirmar modificación"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Afficher les notifications de changement d'état de l'appareil",
|
||||
"update_trans_rules": "Mettre à jour les règles de conversion d'entités",
|
||||
"update_lan_ctrl_config": "Mettre à jour la configuration de contrôle LAN",
|
||||
"network_detect_config": "Configuration Réseau Intégrée"
|
||||
"network_detect_config": "Configuration Réseau Intégrée",
|
||||
"cover_dead_zone_width": "Largeur de la zone aveugle du rideau"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirmer la configuration",
|
||||
"description": "**{nick_name}** Bonjour ! Veuillez confirmer les dernières informations de configuration et cliquer sur \"Soumettre\".\r\nL'intégration rechargera avec la nouvelle configuration.\r\n\r\nLangue d'intégration : {lang_new}\r\nPseudo utilisateur : {nick_name_new}\r\nMode de débogage d'action : {action_debug}\r\nMasquer les entités générées non standard : {hide_non_standard_entities}\r\nAfficher les notifications de changement d'état de l'appareil:\t{display_devices_changed_notify}\r\nModifications des appareils : Ajouter **{devices_add}** appareils, supprimer **{devices_remove}** appareils\r\nModifications des règles de conversion : **{trans_rules_count}** règles au total, mise à jour de **{trans_rules_count_success}** règles",
|
||||
"description": "**{nick_name}** Bonjour ! Veuillez confirmer les dernières informations de configuration et cliquer sur \"Soumettre\".\r\nL'intégration rechargera avec la nouvelle configuration.\r\n\r\nLangue d'intégration : {lang_new}\r\nPseudo utilisateur : {nick_name_new}\r\nMode de débogage d'action : {action_debug}\r\nMasquer les entités générées non standard : {hide_non_standard_entities}\r\nLargeur de la zone aveugle du rideau:\t{cover_width_new}\r\nAfficher les notifications de changement d'état de l'appareil:\t{display_devices_changed_notify}\r\nModifications des appareils : Ajouter **{devices_add}** appareils, supprimer **{devices_remove}** appareils\r\nModifications des règles de conversion : **{trans_rules_count}** règles au total, mise à jour de **{trans_rules_count_success}** règles",
|
||||
"data": {
|
||||
"confirm": "Confirmer la modification"
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Opzioni di Configurazione",
|
||||
"description": "### Ciao, {nick_name}\r\n\r\nID Xiaomi: {uid}\r\nRegione di Login Corrente: {cloud_server}\r\n\r\nSeleziona le opzioni che desideri configurare, poi clicca AVANTI.",
|
||||
"description": "### Ciao, {nick_name}\r\n\r\nID Xiaomi: {uid}\r\nRegione di Login Corrente: {cloud_server}\r\nID istanza di integrazione: {instance_id}\r\n\r\nSeleziona le opzioni che desideri configurare, poi clicca AVANTI.",
|
||||
"data": {
|
||||
"integration_language": "Lingua dell'Integrazione",
|
||||
"update_user_info": "Aggiorna le informazioni dell'utente",
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Mostra notifiche di cambio stato del dispositivo",
|
||||
"update_trans_rules": "Aggiorna le regole di conversione delle entità",
|
||||
"update_lan_ctrl_config": "Aggiorna configurazione del controllo LAN",
|
||||
"network_detect_config": "Configurazione di Rete Integrata"
|
||||
"network_detect_config": "Configurazione di Rete Integrata",
|
||||
"cover_dead_zone_width": "Larghezza dell’angolo cieco della tenda"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Conferma Configurazione",
|
||||
"description": "Ciao **{nick_name}**, si prega di confermare le informazioni di configurazione più recenti e poi fare clic su INVIA.\r\nL'integrazione verrà ricaricata utilizzando la configurazione aggiornata.\r\n\r\nLingua dell'Integrazione: \t{lang_new}\r\nSoprannome: \t{nick_name_new}\r\nModalità di debug per azione: \t{action_debug}\r\nNascondi entità create non standard: \t{hide_non_standard_entities}\r\nMostra notifiche di cambio stato del dispositivo:\t{display_devices_changed_notify}\r\nCambiamenti del Dispositivo: \tAggiungi **{devices_add}** dispositivi, Rimuovi **{devices_remove}** dispositivi\r\nCambiamenti delle regole di trasformazione: \tCi sono un totale di **{trans_rules_count}** regole, e aggiornate **{trans_rules_count_success}** regole",
|
||||
"description": "Ciao **{nick_name}**, si prega di confermare le informazioni di configurazione più recenti e poi fare clic su INVIA.\r\nL'integrazione verrà ricaricata utilizzando la configurazione aggiornata.\r\n\r\nLingua dell'Integrazione:\t{lang_new}\r\nSoprannome:\t{nick_name_new}\r\nModalità di debug per azione:\t{action_debug}\r\nNascondi entità create non standard:\t{hide_non_standard_entities}\r\nLarghezza dell’angolo cieco della tenda:\t{cover_width_new}\r\nMostra notifiche di cambio stato del dispositivo:\t{display_devices_changed_notify}\r\nCambiamenti del Dispositivo:\tAggiungi **{devices_add}** dispositivi, Rimuovi **{devices_remove}** dispositivi\r\nCambiamenti delle regole di trasformazione:\tCi sono un totale di **{trans_rules_count}** regole, e aggiornate **{trans_rules_count_success}** regole",
|
||||
"data": {
|
||||
"confirm": "Conferma la modifica"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "デバイスの状態変化通知を表示",
|
||||
"update_trans_rules": "エンティティ変換ルールを更新する",
|
||||
"update_lan_ctrl_config": "LAN制御構成を更新する",
|
||||
"network_detect_config": "統合ネットワーク構成"
|
||||
"network_detect_config": "統合ネットワーク構成",
|
||||
"cover_dead_zone_width": "カーテンの死角幅"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "構成を確認する",
|
||||
"description": "**{nick_name}** さん、こんにちは! 最新の構成情報を確認してください。[送信] をクリックして、更新された構成を使用して再度読み込みます。\r\n\r\n統合言語:\t{lang_new}\r\nユーザー名:\t{nick_name_new}\r\nAction デバッグモード:\t{action_debug}\r\n非標準生成エンティティを非表示にする:\t{hide_non_standard_entities}\r\nデバイスの状態変化通知を表示:\t{display_devices_changed_notify}\r\nデバイス変更:\t追加 **{devices_add}** 個のデバイス、削除 **{devices_remove}** 個のデバイス\r\n変換ルール変更:\t合計 **{trans_rules_count}** 個の規則、更新 **{trans_rules_count_success}** 個の規則",
|
||||
"description": "**{nick_name}** さん、こんにちは! 最新の構成情報を確認してください。[送信] をクリックして、更新された構成を使用して再度読み込みます。\r\n\r\n統合言語:\t{lang_new}\r\nユーザー名:\t{nick_name_new}\r\nAction デバッグモード:\t{action_debug}\r\n非標準生成エンティティを非表示にする:\t{hide_non_standard_entities}\r\nカーテンの死角幅:\t{cover_width_new}\r\nデバイスの状態変化通知を表示:\t{display_devices_changed_notify}\r\nデバイス変更:\t追加 **{devices_add}** 個のデバイス、削除 **{devices_remove}** 個のデバイス\r\n変換ルール変更:\t合計 **{trans_rules_count}** 個の規則、更新 **{trans_rules_count_success}** 個の規則",
|
||||
"data": {
|
||||
"confirm": "変更を確認する"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Apparaatstatuswijzigingen weergeven",
|
||||
"update_trans_rules": "Werk entiteitsconversieregels bij",
|
||||
"update_lan_ctrl_config": "Werk LAN controleconfiguratie bij",
|
||||
"network_detect_config": "Geïntegreerde Netwerkconfiguratie"
|
||||
"network_detect_config": "Geïntegreerde Netwerkconfiguratie",
|
||||
"cover_dead_zone_width": "Breedte van de dode hoek van het gordijn"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Bevestig Configuratie",
|
||||
"description": "Hallo **{nick_name}**, bevestig alstublieft de nieuwste configuratie-informatie en klik vervolgens op INDENKEN.\r\nDe integratie zal opnieuw laden met de bijgewerkte configuratie.\r\n\r\nIntegratietaal: \t{lang_new}\r\nBijnaam: \t{nick_name_new}\r\nDebugmodus voor actie: \t{action_debug}\r\nVerberg niet-standaard gemaakte entiteiten: \t{hide_non_standard_entities}\r\nApparaatstatuswijzigingen weergeven:\t{display_devices_changed_notify}\r\nWijzigingen in apparaten: \tVoeg **{devices_add}** apparaten toe, Verwijder **{devices_remove}** apparaten\r\nWijzigingen in transformateregels: \tEr zijn in totaal **{trans_rules_count}** regels, en **{trans_rules_count_success}** regels zijn bijgewerkt",
|
||||
"description": "Hallo **{nick_name}**, bevestig alstublieft de nieuwste configuratie-informatie en klik vervolgens op INDENKEN.\r\nDe integratie zal opnieuw laden met de bijgewerkte configuratie.\r\n\r\nIntegratietaal:\t{lang_new}\r\nBijnaam:\t{nick_name_new}\r\nDebugmodus voor actie:\t{action_debug}\r\nVerberg niet-standaard gemaakte entiteiten:\t{hide_non_standard_entities}\r\nBreedte van de dode hoek van het gordijn:\t{cover_width_new}\r\nApparaatstatuswijzigingen weergeven:\t{display_devices_changed_notify}\r\nWijzigingen in apparaten:\tVoeg **{devices_add}** apparaten toe, Verwijder **{devices_remove}** apparaten\r\nWijzigingen in transformateregels:\tEr zijn in totaal **{trans_rules_count}** regels, en **{trans_rules_count_success}** regels zijn bijgewerkt",
|
||||
"data": {
|
||||
"confirm": "Bevestig de wijziging"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Exibir notificações de mudança de status do dispositivo",
|
||||
"update_trans_rules": "Atualizar regras de conversão de entidades",
|
||||
"update_lan_ctrl_config": "Atualizar configuração de controle LAN",
|
||||
"network_detect_config": "Configuração de Rede Integrada"
|
||||
"network_detect_config": "Configuração de Rede Integrada",
|
||||
"cover_dead_zone_width": "Largura da área cega da cortina"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirmar Configuração",
|
||||
"description": "Olá **{nick_name}**, confirme as informações da configuração mais recente e depois clique em ENVIAR.\r\nA integração será recarregada com a configuração atualizada.\r\n\r\nIdioma da Integração:\t{lang_new}\r\nApelido:\t{nick_name_new}\r\nModo de depuração para ação:\t{action_debug}\r\nOcultar entidades não padrão criadas:\t{hide_non_standard_entities}\r\nExibir notificações de mudança de status do dispositivo:\t{display_devices_changed_notify}\r\nAlterações de Dispositivos:\tAdicionar **{devices_add}** dispositivos, Remover **{devices_remove}** dispositivos\r\nAlteração nas Regras de Transformação:\tUm total de **{trans_rules_count}** regras, e **{trans_rules_count_success}** regras atualizadas",
|
||||
"description": "Olá **{nick_name}**, confirme as informações da configuração mais recente e depois clique em ENVIAR.\r\nA integração será recarregada com a configuração atualizada.\r\n\r\nIdioma da Integração:\t{lang_new}\r\nApelido:\t{nick_name_new}\r\nModo de depuração para ação:\t{action_debug}\r\nOcultar entidades não padrão criadas:\t{hide_non_standard_entities}\r\nLargura da área cega da cortina:\t{cover_width_new}\r\nExibir notificações de mudança de status do dispositivo:\t{display_devices_changed_notify}\r\nAlterações de Dispositivos:\tAdicionar **{devices_add}** dispositivos, Remover **{devices_remove}** dispositivos\r\nAlteração nas Regras de Transformação:\tUm total de **{trans_rules_count}** regras, e **{trans_rules_count_success}** regras atualizadas",
|
||||
"data": {
|
||||
"confirm": "Confirmar a mudança"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Exibir notificações de mudança de status do dispositivo",
|
||||
"update_trans_rules": "Atualizar regras de conversão de entidades",
|
||||
"update_lan_ctrl_config": "Atualizar configuração de controlo LAN",
|
||||
"network_detect_config": "Configuração de Rede Integrada"
|
||||
"network_detect_config": "Configuração de Rede Integrada",
|
||||
"cover_dead_zone_width": "Largura da zona cega da cortina"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirmar Configuração",
|
||||
"description": "Olá **{nick_name}**, confirme a informação da configuração mais recente e depois clique em SUBMETER.\r\nA integração será recarregada com a configuração atualizada.\r\n\r\nIdioma da Integração:\t{lang_new}\r\nAlcunha:\t{nick_name_new}\r\nModo de depuração de ação:\t{action_debug}\r\nOcultar entidades não padrão:\t{hide_non_standard_entities}\r\nExibir notificações de mudança de status do dispositivo:\t{display_devices_changed_notify}\r\nAlterações aos Dispositivos:\tAdicionar **{devices_add}** dispositivos, Remover **{devices_remove}** dispositivos\r\nAlteração das Regras de Transformação:\tExistem **{trans_rules_count}** regras no total, com **{trans_rules_count_success}** regras atualizadas",
|
||||
"description": "Olá **{nick_name}**, confirme a informação da configuração mais recente e depois clique em SUBMETER.\r\nA integração será recarregada com a configuração atualizada.\r\n\r\nIdioma da Integração:\t{lang_new}\r\nAlcunha:\t{nick_name_new}\r\nModo de depuração de ação:\t{action_debug}\r\nOcultar entidades não padrão:\t{hide_non_standard_entities}\r\nLargura da zona cega da cortina:\t{cover_width_new}\r\nExibir notificações de mudança de status do dispositivo:\t{display_devices_changed_notify}\r\nAlterações aos Dispositivos:\tAdicionar **{devices_add}** dispositivos, Remover **{devices_remove}** dispositivos\r\nAlteração das Regras de Transformação:\tExistem **{trans_rules_count}** regras no total, com **{trans_rules_count_success}** regras atualizadas",
|
||||
"data": {
|
||||
"confirm": "Confirmar a alteração"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "Отображать уведомления о изменении состояния устройства",
|
||||
"update_trans_rules": "Обновить правила преобразования сущностей",
|
||||
"update_lan_ctrl_config": "Обновить конфигурацию управления LAN",
|
||||
"network_detect_config": "Интегрированная Сетевая Конфигурация"
|
||||
"network_detect_config": "Интегрированная Сетевая Конфигурация",
|
||||
"cover_dead_zone_width": "Ширина «мертвой зоны» шторы"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Подтверждение настройки",
|
||||
"description": "**{nick_name}** Здравствуйте! Подтвердите последнюю информацию о настройке и нажмите «Отправить». Интеграция будет перезагружена с использованием обновленных настроек.\r\n\r\nЯзык интеграции:\t{lang_new}\r\nИмя пользователя:\t{nick_name_new}\r\nРежим отладки Action:\t{action_debug}\r\nСкрыть непроизводственные сущности:\t{hide_non_standard_entities}\r\nОтображать уведомления о изменении состояния устройства:\t{display_devices_changed_notify}\r\nИзменение устройства:\tДобавлено **{devices_add}** устройство, удалено **{devices_remove}** устройства\r\nИзменение правил преобразования:\tВсего **{trans_rules_count}** правил, обновлено **{trans_rules_count_success}** правил",
|
||||
"description": "**{nick_name}** Здравствуйте! Подтвердите последнюю информацию о настройке и нажмите «Отправить». Интеграция будет перезагружена с использованием обновленных настроек.\r\n\r\nЯзык интеграции:\t{lang_new}\r\nИмя пользователя:\t{nick_name_new}\r\nРежим отладки Action:\t{action_debug}\r\nСкрыть непроизводственные сущности:\t{hide_non_standard_entities}\r\nШирина «мертвой зоны» шторы:\t{cover_width_new}\r\nОтображать уведомления о изменении состояния устройства:\t{display_devices_changed_notify}\r\nИзменение устройства:\tДобавлено **{devices_add}** устройство, удалено **{devices_remove}** устройства\r\nИзменение правил преобразования:\tВсего **{trans_rules_count}** правил, обновлено **{trans_rules_count_success}** правил",
|
||||
"data": {
|
||||
"confirm": "Подтвердить изменения"
|
||||
}
|
||||
|
||||
225
custom_components/xiaomi_home/translations/tr.json
Normal file
225
custom_components/xiaomi_home/translations/tr.json
Normal file
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Xiaomi Home Entegrasyonu",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Risk Bildirimi",
|
||||
"description": "1. Xiaomi kullanıcı bilgileriniz ve cihaz bilgileriniz Home Assistant sisteminde saklanacaktır. **Xiaomi, Home Assistant depolama mekanizmasının güvenliğini garanti edemez**. Bilgilerinizin çalınmasını önlemekten siz sorumlusunuz.\r\n2. Bu entegrasyon açık kaynak topluluğu tarafından sürdürülmektedir. Kararlılık sorunları veya diğer sorunlar olabilir. Bu entegrasyonla ilgili sorunlar veya hatalarla karşılaştığınızda, **Xiaomi müşteri hizmetleriyle iletişime geçmek yerine açık kaynak topluluğundan yardım istemelisiniz**.\r\n3. Yerel işletim ortamınızı sürdürmek için teknik beceriye ihtiyacınız vardır. Entegrasyon yeni başlayanlar için kullanıcı dostu değildir.\r\n4. Lütfen başlamadan önce README dosyasını okuyun.\n\n5. Entegrasyonun kararlı kullanımını sağlamak ve arayüz kötüye kullanımını önlemek için, **bu entegrasyonun yalnızca Home Assistant'ta kullanılmasına izin verilir. Ayrıntılar için lütfen LICENSE'a bakın**.",
|
||||
"data": {
|
||||
"eula": "Yukarıdaki risklerin farkındayım ve entegrasyonun kullanımıyla ilişkili tüm riskleri gönüllü olarak üstlenmeye razıyım."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Temel yapılandırma",
|
||||
"description": "### Giriş Bölgesi\r\nXiaomi hesabınızın bölgesini seçin. Bunu Xiaomi Home UYGULAMASI > Profil (alttaki menüde bulunur) > Ek ayarlar > Xiaomi Home Hakkında bölümünde bulabilirsiniz.\r\n### Dil\r\nCihaz ve varlık adlarının dilini seçin. Çevirisi olmayan bazı cümleler İngilizce olarak görüntülenecektir.\r\n### OAuth2 Yönlendirme URL'si\r\nOAuth2 kimlik doğrulama yönlendirme adresi **[http://homeassistant.local:8123](http://homeassistant.local:8123)** şeklindedir. Home Assistant'ın mevcut işletim terminali (örn. kişisel bilgisayar) ile aynı yerel ağda olması ve işletim terminalinin bu adres üzerinden Home Assistant ana sayfasına erişebilmesi gerekir. Aksi takdirde giriş kimlik doğrulaması başarısız olabilir.\r\n### Entegre Ağ Yapılandırması\r\nYerel ağın düzgün çalışıp çalışmadığını ve ilgili ağ kaynaklarının erişilebilir olup olmadığını kontrol edin. **İlk kez eklerken bunu seçmeniz önerilir.**\r\n### Not\r\n- Yüzlerce veya daha fazla Mi Home cihazına sahip kullanıcılar için, entegrasyonun ilk eklenmesi biraz zaman alacaktır. Lütfen sabırlı olun.\r\n- Home Assistant bir Docker ortamında çalışıyorsa, lütfen Docker ağ modunun host olarak ayarlandığından emin olun, aksi takdirde yerel kontrol işlevi düzgün çalışmayabilir.\r\n- Entegrasyonun yerel kontrol işlevinin bazı bağımlılıkları vardır. Lütfen README'yi dikkatlice okuyun.",
|
||||
"data": {
|
||||
"cloud_server": "Giriş Bölgesi",
|
||||
"integration_language": "Dil",
|
||||
"oauth_redirect_url": "OAuth2 Yönlendirme URL'si",
|
||||
"network_detect_config": "Entegre Ağ Yapılandırması"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Entegre Ağ Yapılandırması",
|
||||
"description": "## Kullanım Tanıtımı\r\n### Ağ Algılama Adresi\r\nAğın düzgün çalışıp çalışmadığını kontrol etmek için kullanılır. Ayarlanmazsa, sistem varsayılan adresi kullanılacaktır. Varsayılan adres kontrolü başarısız olursa, özel bir adres girmeyi deneyebilirsiniz.\r\n- Virgülle ayrılmış birden fazla algılama adresi girebilirsiniz, örneğin `8.8.8.8,https://www.bing.com`\r\n- Bir IP adresi ise, algılama ping üzerinden yapılacaktır. Bir HTTP(s) adresi ise, algılama HTTP GET isteği üzerinden yapılacaktır.\r\n- Sistem varsayılan algılama adresini geri yüklemek istiyorsanız, lütfen bir virgül `,` girin ve 'İleri'ye tıklayın.\r\n- **Bu yapılandırma geneldir ve değişiklikler diğer entegrasyon örneklerini etkileyecektir. Lütfen dikkatli değiştirin.**\r\n### Ağ Bağımlılıklarını Kontrol Et\r\nAşağıdaki ağ bağımlılıklarının erişilebilir olup olmadığını tek tek kontrol edin. İlgili adresler erişilebilir değilse, entegrasyon sorunlarına neden olacaktır.\r\n- OAuth2 Kimlik Doğrulama Adresi: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API Adresi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API Adresi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker Adresi: `mqtts://{cloud_server}-ha.mqtt.io.mi.com:8883`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Ağ Algılama Adresi",
|
||||
"check_network_deps": "Ağ Bağımlılıklarını Kontrol Et"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Giriş Hatası",
|
||||
"description": "Tekrar denemek için İLERİ'ye tıklayın."
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Ev ve Cihaz Seçimi",
|
||||
"description": "## Tanıtım\r\n### Cihazın Evini İçe Aktar\r\nEntegrasyon, seçilen evden cihazları ekleyecektir.\r\n### Oda Adı Senkronizasyon Modu\r\nMi Home UYGULAMASINDAN Home Assistant'a cihazlar senkronize edilirken, Home Assistant'taki alanın adlandırılması aşağıdaki kurallara uyacaktır. Senkronizasyon işleminin Mi Home UYGULAMASINDAKI ev ve oda ayarlarını değiştirmeyeceğini unutmayın.\r\n- Senkronize etme: Cihaz herhangi bir alana eklenmeyecektir.\r\n- Diğer seçenekler: Cihazın eklendiği alan, Mi Home UYGULAMASINDAKI ev veya oda adına göre adlandırılacaktır.\r\n### Gelişmiş Ayarlar\r\nEntegrasyonun profesyonel yapılandırma seçeneklerini değiştirmek için gelişmiş ayarları gösterin.\r\n\r\n \r\n### {nick_name} Merhaba! Lütfen cihaz eklemek istediğiniz evi seçin.",
|
||||
"data": {
|
||||
"home_infos": "Cihazın Evini İçe Aktar",
|
||||
"area_name_rule": "Oda Adı Senkronizasyon Modu",
|
||||
"advanced_options": "Gelişmiş Ayarlar"
|
||||
}
|
||||
},
|
||||
"advanced_options": {
|
||||
"title": "Gelişmiş Ayarlar",
|
||||
"description": "## Tanıtım\r\n### Aşağıdaki seçeneklerin anlamını çok net bir şekilde bilmiyorsanız, lütfen varsayılan ayarları koruyun.\r\n### Cihazları Filtrele\r\nCihazları oda adı ve cihaz türüne göre filtrelemeyi destekler, ayrıca cihaz boyutu filtrelemesini de destekler.\r\n### Kontrol Modu\r\n- Otomatik: Yerel ağda kullanılabilir bir Xiaomi merkezi hub ağ geçidi olduğunda, Home Assistant cihaz kontrol komutlarını öncelikle merkezi hub ağ geçidi üzerinden göndererek yerel kontrolü sağlar. Yerel ağda merkezi hub ağ geçidi yoksa, Xiaomi OT protokolü üzerinden kontrol komutları göndermeye çalışır. Yalnızca yukarıdaki yerel kontrol koşulları karşılanmadığında, cihaz kontrol komutları bulut üzerinden gönderilir.\r\n- Bulut: Tüm kontrol komutları bulut üzerinden gönderilir.\r\n### Eylem Hata Ayıklama Modu\r\nCihaz MIoT-Spec-V2 tarafından tanımlanan yöntemler için, bildirim varlıkları oluşturmaya ek olarak, bir metin girişi kutusu varlığı da oluşturulacaktır. Hata ayıklama sırasında cihaza kontrol komutları göndermek için bunu kullanabilirsiniz.\r\n### Standart Olmayan Oluşturulan Varlıkları Gizle\r\nAdı \"*\" ile başlayan standart olmayan MIoT-Spec-V2 örnekleri tarafından oluşturulan varlıkları gizle.\r\n### İkili Sensör Görüntüleme Modu\r\nXiaomi Home'daki ikili sensörleri metin sensör varlığı veya ikili sensör varlığı olarak görüntüleyin.\r\n### Cihaz Durum Değişikliği Bildirimlerini Göster\r\nDetaylı cihaz durum değişikliği bildirimlerini görüntüleyin, yalnızca seçilen bildirimleri gösterin.",
|
||||
"data": {
|
||||
"devices_filter": "Cihazları Filtrele",
|
||||
"ctrl_mode": "Kontrol Modu",
|
||||
"action_debug": "Eylem Hata Ayıklama Modu",
|
||||
"hide_non_standard_entities": "Standart Olmayan Oluşturulan Varlıkları Gizle",
|
||||
"display_binary_mode": "İkili Sensör Görüntüleme Modu",
|
||||
"display_devices_changed_notify": "Cihaz Durum Değişikliği Bildirimlerini Göster"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Cihazları Filtrele",
|
||||
"description": "## Kullanım Talimatları\r\nCihazları ev oda adı, cihaz erişim türü ve cihaz modeline göre filtrelemeyi destekler, ayrıca cihaz boyutu filtrelemesini de destekler. Filtreleme mantığı aşağıdaki gibidir:\r\n- İlk olarak, istatistik mantığına göre, dahil edilen tüm öğelerin birleşimini veya kesişimini alın, ardından hariç tutulan öğelerin kesişimini veya birleşimini alın ve son olarak [hariç tutulan özet sonucu]ndan [dahil edilen özet sonucu]nu çıkararak [filtre sonucu]nu elde edin.\r\n- Dahil edilen öğe seçilmemişse, tümünün dahil edildiği anlamına gelir.\r\n### Filtre Modu\r\n- Hariç tut: İstenmeyen öğeleri kaldırın.\r\n- Dahil et: İstenen öğeleri dahil edin.\r\n### İstatistik Mantığı\r\n- VE mantığı: Aynı moddaki tüm öğelerin kesişimini alın.\r\n- VEYA mantığı: Aynı moddaki tüm öğelerin birleşimini alın.\r\n\r\nAyrıca entegrasyon öğesinin [Yapılandırma > Cihaz Listesini Güncelle] sayfasına gidip, yeniden filtrelemek için [Cihazları Filtrele]'yi işaretleyebilirsiniz.",
|
||||
"data": {
|
||||
"room_filter_mode": "Ev Odalarını Filtrele",
|
||||
"room_list": "Ev Odaları",
|
||||
"type_filter_mode": "Cihaz Bağlantı Türünü Filtrele",
|
||||
"type_list": "Cihaz Bağlantı Türü",
|
||||
"model_filter_mode": "Cihaz Modelini Filtrele",
|
||||
"model_list": "Cihaz Modeli",
|
||||
"devices_filter_mode": "Cihazları Filtrele",
|
||||
"device_list": "Cihaz Listesi",
|
||||
"statistics_logic": "İstatistik Mantığı"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Giriş yapmak için buraya tıklayın{link_right}\r\n(Başarılı girişten sonra otomatik olarak bir sonraki sayfaya yönlendirileceksiniz)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Lütfen risk bildirimini okuyun.",
|
||||
"get_token_error": "Giriş yetkilendirme bilgileri (OAuth token) alınamadı.",
|
||||
"get_homeinfo_error": "Ev bilgileri alınamadı.",
|
||||
"mdns_discovery_error": "Yerel cihaz keşif hizmeti istisnası.",
|
||||
"get_cert_error": "Merkezi hub ağ geçidi sertifikası alınamadı.",
|
||||
"no_family_selected": "Ev seçilmedi.",
|
||||
"no_devices": "Seçilen evde cihaz yok. Lütfen cihazı olan bir ev seçin ve devam edin.",
|
||||
"no_filter_devices": "Filtrelenmiş cihazlar boş. Lütfen geçerli filtre kriterleri seçin ve devam edin.",
|
||||
"no_central_device": "[Merkezi Hub Ağ Geçidi Modu], Home Assistant'ın bulunduğu yerel ağda kullanılabilir bir Xiaomi merkezi hub ağ geçidi gerektirir. Lütfen seçilen evin gereksinimi karşılayıp karşılamadığını kontrol edin.",
|
||||
"invalid_network_addr": "Geçersiz IP adresi veya HTTP adresi algılandı, lütfen geçerli bir adres girin.",
|
||||
"invalid_ip_addr": "Ulaşılamayan IP adresi algılandı, lütfen geçerli bir IP adresi girin.",
|
||||
"invalid_http_addr": "Ulaşılamayan HTTP adresi algılandı, lütfen geçerli bir HTTP adresi girin.",
|
||||
"invalid_default_addr": "Varsayılan ağ algılama adresi ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin veya özel bir ağ algılama adresi kullanın.",
|
||||
"unreachable_oauth2_host": "OAuth2 kimlik doğrulama adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_http_host": "Xiaomi HTTP API adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_spec_host": "Xiaomi SPEC API adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_mqtt_broker": "Xiaomi MQTT Broker adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Home Assistant UUID alınamadı.",
|
||||
"network_connect_error": "Yapılandırma başarısız oldu. Ağ bağlantısı anormal. Lütfen ekipman ağ yapılandırmasını kontrol edin.",
|
||||
"already_configured": "Bu kullanıcı için yapılandırma zaten tamamlandı. Lütfen entegrasyon sayfasına gidin ve değişiklikler için YAPILANDIRMA düğmesine tıklayın.",
|
||||
"invalid_auth_info": "Kimlik doğrulama bilgileri süresi doldu. Lütfen entegrasyon sayfasına gidin ve yeniden kimlik doğrulaması yapmak için YAPILANDIRMA düğmesine tıklayın.",
|
||||
"config_flow_error": "Entegrasyon yapılandırma hatası: {error}."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Kimlik Doğrulama Yapılandırması",
|
||||
"description": "Yerel kimlik doğrulama bilgileri süresi doldu. Lütfen kimlik doğrulama işlemini yeniden başlatın.\r\n### Geçerli Giriş Bölgesi: {cloud_server}\r\n### OAuth2 Yönlendirme URL'si\r\nOAuth2 kimlik doğrulama yönlendirme adresi **[http://homeassistant.local:8123](http://homeassistant.local:8123)** şeklindedir. Home Assistant'ın mevcut işletim terminali (örn. kişisel bilgisayar) ile aynı yerel ağda olması ve işletim terminalinin bu adres üzerinden Home Assistant ana sayfasına erişebilmesi gerekir. Aksi takdirde giriş kimlik doğrulaması başarısız olabilir.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "OAuth2 Yönlendirme URL'si"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Giriş sırasında bir hata oluştu.",
|
||||
"description": "Tekrar denemek için İLERİ'ye tıklayın."
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Yapılandırma Seçenekleri",
|
||||
"description": "### Merhaba, {nick_name}\r\n\r\nXiaomi ID: {uid}\r\nGeçerli Giriş Bölgesi: {cloud_server}\r\nEntegrasyon Örnek Kimliği: {instance_id}\r\n\r\nLütfen yapılandırmak istediğiniz seçenekleri seçin, ardından İLERİ'ye tıklayın.",
|
||||
"data": {
|
||||
"integration_language": "Entegrasyon Dili",
|
||||
"update_user_info": "Kullanıcı bilgilerini güncelle",
|
||||
"update_devices": "Cihaz listesini güncelle",
|
||||
"action_debug": "Eylem için hata ayıklama modu",
|
||||
"hide_non_standard_entities": "Standart olmayan oluşturulan varlıkları gizle",
|
||||
"display_binary_mode": "İkili Sensör Görüntüleme Modu",
|
||||
"display_devices_changed_notify": "Cihaz durum değişikliği bildirimlerini göster",
|
||||
"update_trans_rules": "Varlık dönüştürme kurallarını güncelle",
|
||||
"update_lan_ctrl_config": "LAN kontrol yapılandırmasını güncelle",
|
||||
"network_detect_config": "Entegre ağ yapılandırması",
|
||||
"cover_dead_zone_width": "Perde ölü bölge genişliği"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Kullanıcı Takma Adını Güncelle",
|
||||
"description": "Merhaba {nick_name}, aşağıda özel takma adınızı değiştirebilirsiniz.",
|
||||
"data": {
|
||||
"nick_name": "Takma Ad"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Evi ve Cihazları Yeniden Seç",
|
||||
"description": "## Kullanım Talimatları\r\n### Evden cihazları içe aktar\r\nEntegrasyon, seçilen evlerden cihazları ekleyecektir.\r\n### Cihazları Filtrele\r\nCihazları ev oda adı, cihaz erişim türü ve cihaz modeline göre filtrelemeyi destekler, ayrıca cihaz boyutu filtrelemesini de destekler. **{local_count}** cihaz filtrelendi.\r\n### Kontrol modu\r\n- Otomatik: Yerel ağda kullanılabilir bir Xiaomi merkezi hub ağ geçidi olduğunda, Home Assistant cihaz kontrol komutlarını öncelikle merkezi hub ağ geçidi üzerinden göndererek yerel kontrolü sağlar. Yerel ağda merkezi hub ağ geçidi yoksa, Xiaomi LAN kontrol işlevi aracılığıyla kontrol komutları göndermeye çalışır. Yalnızca yukarıdaki yerel kontrol koşulları karşılanmadığında, cihaz kontrol komutları bulut üzerinden gönderilir.\r\n- Bulut: Tüm kontrol komutları bulut üzerinden gönderilir.",
|
||||
"data": {
|
||||
"home_infos": "Evden cihazları içe aktar",
|
||||
"devices_filter": "Cihazları filtrele",
|
||||
"ctrl_mode": "Kontrol modu"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Cihazları Filtrele",
|
||||
"description": "## Kullanım Talimatları\r\nCihazları ev oda adı, cihaz erişim türü ve cihaz modeline göre filtrelemeyi destekler, ayrıca cihaz boyutu filtrelemesini de destekler. Filtreleme mantığı aşağıdaki gibidir:\r\n- İlk olarak, istatistik mantığına göre, dahil edilen tüm öğelerin birleşimini veya kesişimini alın, ardından hariç tutulan öğelerin kesişimini veya birleşimini alın ve son olarak [hariç tutulan özet sonucu]ndan [dahil edilen özet sonucu]nu çıkararak [filtre sonucu]nu elde edin.\r\n- Dahil edilen öğe seçilmemişse, tümünün dahil edildiği anlamına gelir.\r\n### Filtre Modu\r\n- Hariç tut: İstenmeyen öğeleri kaldırın.\r\n- Dahil et: İstenen öğeleri dahil edin.\r\n### İstatistik Mantığı\r\n- VE mantığı: Aynı moddaki tüm öğelerin kesişimini alın.\r\n- VEYA mantığı: Aynı moddaki tüm öğelerin birleşimini alın.\r\n\r\nAyrıca entegrasyon öğesinin [Yapılandırma > Cihaz Listesini Güncelle] sayfasına gidip, yeniden filtrelemek için [Cihazları Filtrele]'yi işaretleyebilirsiniz.",
|
||||
"data": {
|
||||
"room_filter_mode": "Ev Odalarını Filtrele",
|
||||
"room_list": "Ev Odaları",
|
||||
"type_filter_mode": "Cihaz Bağlantı Türünü Filtrele",
|
||||
"type_list": "Cihaz Bağlantı Türü",
|
||||
"model_filter_mode": "Cihaz Modelini Filtrele",
|
||||
"model_list": "Cihaz Modeli",
|
||||
"devices_filter_mode": "Cihazları Filtrele",
|
||||
"device_list": "Cihaz Listesi",
|
||||
"statistics_logic": "İstatistik Mantığı"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Varlık Dönüştürme Kurallarını Güncelle",
|
||||
"description": "## Kullanım Talimatları\r\n- Mevcut entegrasyon örneğindeki cihazların varlık bilgilerini güncelleyin, MIoT-Spec-V2 çok dilli yapılandırma, boolean çeviri ve model filtreleme dahil.\r\n- **Uyarı**: Bu genel bir yapılandırmadır ve yerel önbelleği güncelleyecektir. Tüm entegrasyon örneklerini etkileyecektir.\r\n- Bu işlem biraz zaman alacaktır, lütfen sabırlı olun. \"Güncellemeyi Onayla\"yı işaretleyin ve **{urn_count}** kuralı güncellemeye başlamak için \"İleri\"ye tıklayın, aksi takdirde güncellemeyi atlayın.",
|
||||
"data": {
|
||||
"confirm": "Güncellemeyi onayla"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "LAN kontrol yapılandırmasını güncelle",
|
||||
"description": "## Kullanım Talimatları\r\nXiaomi LAN kontrol işlevi için yapılandırmaları güncelleyin. Bulut ve merkezi hub ağ geçidi cihazları kontrol edemediğinde, entegrasyon LAN üzerinden cihazları kontrol etmeye çalışacaktır. Hiçbir ağ kartı seçilmezse, LAN kontrol işlevi etkin olmayacaktır.\r\n- Yalnızca LAN'daki MIoT-Spec-V2 uyumlu IP cihazları desteklenir. 2020'den önce üretilen bazı cihazlar LAN kontrolünü veya LAN aboneliğini desteklemeyebilir.\r\n- Lütfen kontrol edilecek cihazlarla aynı ağdaki ağ kartlarını seçin. Birden fazla ağ kartı seçilebilir. Home Assistant'ın birden fazla ağ kartı seçimi nedeniyle yerel ağa iki veya daha fazla bağlantısı varsa, en iyi ağ bağlantısına sahip olanı seçmeniz önerilir, aksi takdirde cihazlar üzerinde kötü etkisi olabilir.\r\n- LAN'da yerel kontrolü destekleyen terminal cihazlar (ekranlı Xiaomi hoparlör, cep telefonu, vb.) varsa, LAN aboneliğini etkinleştirmek yerel otomasyon ve cihaz anormalliklerine neden olabilir.\r\n- **Uyarı**: Bu genel bir yapılandırmadır. Tüm entegrasyon örneklerini etkileyecektir. Lütfen dikkatli kullanın.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Lütfen kullanılacak ağ kartını seçin",
|
||||
"enable_subscribe": "LAN aboneliğini etkinleştir"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Entegre Ağ Yapılandırması",
|
||||
"description": "## Kullanım Tanıtımı\r\n### Ağ Algılama Adresi\r\nAğın düzgün çalışıp çalışmadığını kontrol etmek için kullanılır. Ayarlanmazsa, sistem varsayılan adresi kullanılacaktır. Varsayılan adres kontrolü başarısız olursa, özel bir adres girmeyi deneyebilirsiniz.\r\n- Virgülle ayrılmış birden fazla algılama adresi girebilirsiniz, örneğin `8.8.8.8,https://www.bing.com`\r\n- Bir IP adresi ise, algılama ping üzerinden yapılacaktır. Bir HTTP(s) adresi ise, algılama HTTP GET isteği üzerinden yapılacaktır.\r\n- Sistem varsayılan algılama adresini geri yüklemek istiyorsanız, lütfen bir virgül `,` girin ve 'İleri'ye tıklayın.\r\n- **Bu yapılandırma geneldir ve değişiklikler diğer entegrasyon örneklerini etkileyecektir. Lütfen dikkatli değiştirin.**\r\n### Ağ Bağımlılıklarını Kontrol Et\r\nAşağıdaki ağ bağımlılıklarının erişilebilir olup olmadığını tek tek kontrol edin. İlgili adresler erişilebilir değilse, entegrasyon sorunlarına neden olacaktır.\r\n- OAuth2 Kimlik Doğrulama Adresi: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API Adresi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API Adresi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker Adresi: `mqtts://{cloud_server}-ha.mqtt.io.mi.com:8883`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Ağ Algılama Adresi",
|
||||
"check_network_deps": "Ağ Bağımlılıklarını Kontrol Et"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Yapılandırmayı Onayla",
|
||||
"description": "Merhaba **{nick_name}**, lütfen en son yapılandırma bilgilerini onaylayın ve ardından GÖNDER'e tıklayın.\r\nEntegrasyon güncellenmiş yapılandırmayla yeniden yüklenecektir.\r\n\r\nEntegrasyon Dili:\t{lang_new}\r\nTakma Ad:\t{nick_name_new}\r\nEylem için hata ayıklama modu:\t{action_debug}\r\nStandart olmayan oluşturulan varlıkları gizle:\t{hide_non_standard_entities}\r\nPerde ölü bölge genişliği:\t{cover_width_new}\r\nCihaz durum değişikliği bildirimlerini göster:\t{display_devices_changed_notify}\r\nCihaz Değişiklikleri:\t**{devices_add}** cihaz ekle, **{devices_remove}** cihaz kaldır\r\nDönüştürme kuralları değişikliği:\tToplam **{trans_rules_count}** kural var ve **{trans_rules_count_success}** kural güncellendi",
|
||||
"data": {
|
||||
"confirm": "Değişikliği onayla"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Yeniden giriş yapmak için lütfen buraya tıklayın{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Kimlik doğrulanmadı. Lütfen kullanıcı kimliğini doğrulamak için kimlik doğrulama bağlantısına tıklayın.",
|
||||
"get_token_error": "Giriş yetkilendirme bilgileri (OAuth token) alınamadı.",
|
||||
"get_homeinfo_error": "Ev bilgileri alınamadı.",
|
||||
"get_cert_error": "Merkezi hub ağ geçidi sertifikası alınamadı.",
|
||||
"no_devices": "Seçilen evde cihaz yok. Lütfen cihazı olan bir ev seçin ve devam edin.",
|
||||
"no_filter_devices": "Filtrelenmiş cihazlar boş. Lütfen geçerli filtre kriterleri seçin ve devam edin.",
|
||||
"no_family_selected": "Ev seçilmedi.",
|
||||
"no_central_device": "[Merkezi Hub Ağ Geçidi Modu], Home Assistant'ın bulunduğu yerel ağda kullanılabilir bir Xiaomi merkezi hub ağ geçidi gerektirir. Lütfen seçilen evin gereksinimi karşılayıp karşılamadığını kontrol edin.",
|
||||
"mdns_discovery_error": "Yerel cihaz keşif hizmeti istisnası.",
|
||||
"update_config_error": "Yapılandırma bilgileri güncellenemedi.",
|
||||
"not_confirm": "Değişiklikler onaylanmadı. Lütfen göndermeden önce değişikliği onaylayın.",
|
||||
"invalid_network_addr": "Geçersiz IP adresi veya HTTP adresi algılandı, lütfen geçerli bir adres girin.",
|
||||
"invalid_ip_addr": "Ulaşılamayan IP adresi algılandı, lütfen geçerli bir IP adresi girin.",
|
||||
"invalid_http_addr": "Ulaşılamayan HTTP adresi algılandı, lütfen geçerli bir HTTP adresi girin.",
|
||||
"invalid_default_addr": "Varsayılan ağ algılama adresi ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin veya özel bir ağ algılama adresi kullanın.",
|
||||
"unreachable_oauth2_host": "OAuth2 kimlik doğrulama adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_http_host": "Xiaomi HTTP API adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_spec_host": "Xiaomi SPEC API adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_mqtt_broker": "Xiaomi MQTT Broker adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "Yapılandırma başarısız oldu. Ağ bağlantısı anormal. Lütfen ekipman ağ yapılandırmasını kontrol edin.",
|
||||
"options_flow_error": "Entegrasyon yeniden yapılandırma hatası: {error}",
|
||||
"re_add": "Lütfen entegrasyonu yeniden ekleyin. Hata mesajı: {error}",
|
||||
"storage_error": "Entegrasyon depolama modülü istisnası. Lütfen tekrar deneyin veya entegrasyonu yeniden ekleyin: {error}",
|
||||
"inconsistent_account": "Hesap bilgileri tutarsız. Lütfen doğru hesapla giriş yapın."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "显示设备状态变化通知",
|
||||
"update_trans_rules": "更新实体转换规则",
|
||||
"update_lan_ctrl_config": "更新局域网控制配置",
|
||||
"network_detect_config": "集成网络配置"
|
||||
"network_detect_config": "集成网络配置",
|
||||
"cover_dead_zone_width": "窗帘盲区宽度"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "确认配置",
|
||||
"description": "**{nick_name}** 您好!请确认最新的配置信息,然后点击“提交”。\r\n集成将会使用更新后的配置重新载入。\r\n\r\n集成语言:\t{lang_new}\r\n用户昵称:\t{nick_name_new}\r\nAction 调试模式:\t{action_debug}\r\n隐藏非标准生成实体:\t{hide_non_standard_entities}\r\n显示设备状态变化通知:\t{display_devices_changed_notify}\r\n设备变化:\t新增 **{devices_add}** 个设备,移除 **{devices_remove}** 个设备\r\n转换规则变化:\t共条 **{trans_rules_count}** 规则,更新 **{trans_rules_count_success}** 条规则",
|
||||
"description": "**{nick_name}** 您好!请确认最新的配置信息,然后点击“提交”。\r\n集成将会使用更新后的配置重新载入。\r\n\r\n集成语言:\t{lang_new}\r\n用户昵称:\t{nick_name_new}\r\nAction 调试模式:\t{action_debug}\r\n隐藏非标准生成实体:\t{hide_non_standard_entities}\r\n窗帘盲区宽度:\t{cover_width_new}\r\n显示设备状态变化通知:\t{display_devices_changed_notify}\r\n设备变化:\t新增 **{devices_add}** 个设备,移除 **{devices_remove}** 个设备\r\n转换规则变化:\t共条 **{trans_rules_count}** 规则,更新 **{trans_rules_count_success}** 条规则",
|
||||
"data": {
|
||||
"confirm": "确认修改"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"display_devices_changed_notify": "顯示設備狀態變化通知",
|
||||
"update_trans_rules": "更新實體轉換規則",
|
||||
"update_lan_ctrl_config": "更新局域網控制配置",
|
||||
"network_detect_config": "集成網絡配置"
|
||||
"network_detect_config": "集成網絡配置",
|
||||
"cover_dead_zone_width": "窗簾盲區寬度"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
@@ -183,7 +184,7 @@
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "確認配置",
|
||||
"description": "**{nick_name}** 您好!請確認最新的配置信息,然後點擊“提交”。\r\n集成將會使用更新後的配置重新載入。\r\n\r\n集成語言:\t{lang_new}\r\n用戶暱稱:\t{nick_name_new}\r\nAction 調試模式:\t{action_debug}\r\n隱藏非標準生成實體:\t{hide_non_standard_entities}\r\n顯示設備狀態變化通知:\t{display_devices_changed_notify}\r\n設備變化:\t新增 **{devices_add}** 個設備,移除 **{devices_remove}** 個設備\r\n轉換規則變化:\t共條 **{trans_rules_count}** 規則,更新 **{trans_rules_count_success}** 條規則",
|
||||
"description": "**{nick_name}** 您好!請確認最新的配置信息,然後點擊“提交”。\r\n集成將會使用更新後的配置重新載入。\r\n\r\n集成語言:\t{lang_new}\r\n用戶暱稱:\t{nick_name_new}\r\nAction 調試模式:\t{action_debug}\r\n隱藏非標準生成實體:\t{hide_non_standard_entities}\r\n窗簾盲區寬度:\t{cover_width_new}\r\n顯示設備狀態變化通知:\t{display_devices_changed_notify}\r\n設備變化:\t新增 **{devices_add}** 個設備,移除 **{devices_remove}** 個設備\r\n轉換規則變化:\t共條 **{trans_rules_count}** 規則,更新 **{trans_rules_count_success}** 條規則",
|
||||
"data": {
|
||||
"confirm": "確認修改"
|
||||
}
|
||||
|
||||
@@ -47,29 +47,32 @@ Vacuum entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Any, Optional
|
||||
import re
|
||||
import logging
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.vacuum import (
|
||||
StateVacuumEntity,
|
||||
VacuumEntityFeature
|
||||
)
|
||||
from homeassistant.components.vacuum import (StateVacuumEntity,
|
||||
VacuumEntityFeature)
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData
|
||||
from .miot.miot_spec import (
|
||||
MIoTSpecAction,
|
||||
MIoTSpecProperty)
|
||||
from .miot.miot_spec import (MIoTSpecAction, MIoTSpecProperty)
|
||||
|
||||
try: # VacuumActivity is introduced in HA core 2025.1.0
|
||||
from homeassistant.components.vacuum import VacuumActivity
|
||||
HA_CORE_HAS_ACTIVITY = True
|
||||
except ImportError:
|
||||
HA_CORE_HAS_ACTIVITY = False
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
@@ -87,7 +90,11 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
||||
# pylint: disable=unused-argument
|
||||
_prop_status: Optional[MIoTSpecProperty]
|
||||
_prop_fan_level: Optional[MIoTSpecProperty]
|
||||
_prop_battery_level: Optional[MIoTSpecProperty]
|
||||
_prop_status_cleaning: Optional[list[int]]
|
||||
_prop_status_docked: Optional[list[int]]
|
||||
_prop_status_paused: Optional[list[int]]
|
||||
_prop_status_returning: Optional[list[int]]
|
||||
_prop_status_error: Optional[list[int]]
|
||||
|
||||
_action_start_sweep: Optional[MIoTSpecAction]
|
||||
_action_stop_sweeping: Optional[MIoTSpecAction]
|
||||
@@ -99,15 +106,21 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
||||
_status_map: Optional[dict[int, str]]
|
||||
_fan_level_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(
|
||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
|
||||
) -> None:
|
||||
_device_name: str
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._device_name = miot_device.name
|
||||
self._attr_supported_features = VacuumEntityFeature(0)
|
||||
|
||||
self._prop_status = None
|
||||
self._prop_fan_level = None
|
||||
self._prop_battery_level = None
|
||||
self._prop_status_cleaning = []
|
||||
self._prop_status_docked = []
|
||||
self._prop_status_paused = []
|
||||
self._prop_status_returning = []
|
||||
self._prop_status_error = []
|
||||
self._action_start_sweep = None
|
||||
self._action_stop_sweeping = None
|
||||
self._action_pause_sweeping = None
|
||||
@@ -121,24 +134,50 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'status':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error(
|
||||
'invalid status value_list, %s', self.entity_id)
|
||||
_LOGGER.error('invalid status value_list, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._status_map = prop.value_list.to_map()
|
||||
self._attr_supported_features |= VacuumEntityFeature.STATE
|
||||
self._prop_status = prop
|
||||
for item in prop.value_list.items:
|
||||
item_str: str = item.name
|
||||
item_name: str = re.sub(r'[^a-z]', '', item_str)
|
||||
if item_name in {
|
||||
'charging', 'charged', 'chargingcompleted',
|
||||
'fullcharge', 'fullpower', 'findchargerpause',
|
||||
'drying', 'washing', 'wash', 'inthewash',
|
||||
'inthedry', 'stationworking', 'dustcollecting',
|
||||
'upgrade', 'upgrading', 'updating'
|
||||
}:
|
||||
self._prop_status_docked.append(item.value)
|
||||
elif item_name in {'paused', 'pause'}:
|
||||
self._prop_status_paused.append(item.value)
|
||||
elif item_name in {
|
||||
'gocharging', 'cleancompletegocharging',
|
||||
'findchargewash', 'backtowashmop', 'gowash',
|
||||
'gowashing', 'summon'
|
||||
}:
|
||||
self._prop_status_returning.append(item.value)
|
||||
elif item_name in {
|
||||
'error', 'breakcharging', 'gochargebreak'
|
||||
}:
|
||||
self._prop_status_error.append(item.value)
|
||||
elif (item_name.find('sweeping') != -1) or (
|
||||
item_name.find('mopping') != -1) or (item_name in {
|
||||
'cleaning', 'remoteclean', 'continuesweep',
|
||||
'busy', 'building', 'buildingmap', 'mapping'
|
||||
}):
|
||||
self._prop_status_cleaning.append(item.value)
|
||||
elif prop.name == 'fan-level':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error(
|
||||
'invalid fan-level value_list, %s', self.entity_id)
|
||||
_LOGGER.error('invalid fan-level value_list, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._fan_level_map = prop.value_list.to_map()
|
||||
self._attr_fan_speed_list = list(self._fan_level_map.values())
|
||||
self._attr_supported_features |= VacuumEntityFeature.FAN_SPEED
|
||||
self._prop_fan_level = prop
|
||||
|
||||
elif prop.name == 'battery-level':
|
||||
self._attr_supported_features |= VacuumEntityFeature.BATTERY
|
||||
self._prop_battery_level = prop
|
||||
# action
|
||||
for action in entity_data.actions:
|
||||
if action.name == 'start-sweep':
|
||||
@@ -155,16 +194,28 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
||||
elif action.name == 'stop-and-gocharge':
|
||||
self._attr_supported_features |= VacuumEntityFeature.RETURN_HOME
|
||||
self._action_stop_and_gocharge = action
|
||||
|
||||
elif action.name == 'identify':
|
||||
self._attr_supported_features |= VacuumEntityFeature.LOCATE
|
||||
self._action_identify = action
|
||||
|
||||
# Use start-charge from battery service as fallback
|
||||
# if stop-and-gocharge is not available
|
||||
if self._action_stop_and_gocharge is None:
|
||||
for action in entity_data.actions:
|
||||
if action.name == 'start-charge':
|
||||
self._attr_supported_features |= (
|
||||
VacuumEntityFeature.RETURN_HOME)
|
||||
self._action_stop_and_gocharge = action
|
||||
break
|
||||
|
||||
async def async_start(self) -> None:
|
||||
"""Start or resume the cleaning task."""
|
||||
if self.state.lower() in ['paused', '暂停中']:
|
||||
await self.action_async(action=self._action_continue_sweep)
|
||||
return
|
||||
if self._prop_status is not None:
|
||||
status = self.get_prop_value(prop=self._prop_status)
|
||||
if (status in self._prop_status_paused
|
||||
) and self._action_continue_sweep:
|
||||
await self.action_async(action=self._action_continue_sweep)
|
||||
return
|
||||
await self.action_async(action=self._action_start_sweep)
|
||||
|
||||
async def async_stop(self, **kwargs: Any) -> None:
|
||||
@@ -179,31 +230,69 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity):
|
||||
"""Set the vacuum cleaner to return to the dock."""
|
||||
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:
|
||||
"""Locate the vacuum cleaner."""
|
||||
await self.action_async(action=self._action_identify)
|
||||
|
||||
async def async_set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
|
||||
"""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 state(self) -> Optional[str]:
|
||||
"""Return the current state of the vacuum cleaner."""
|
||||
return self.get_map_value(
|
||||
map_=self._status_map,
|
||||
key=self.get_prop_value(prop=self._prop_status))
|
||||
|
||||
@property
|
||||
def battery_level(self) -> Optional[int]:
|
||||
"""Return the current battery level of the vacuum cleaner."""
|
||||
return self.get_prop_value(prop=self._prop_battery_level)
|
||||
def name(self) -> Optional[str]:
|
||||
"""Name of the vacuum entity."""
|
||||
return self._device_name
|
||||
|
||||
@property
|
||||
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(
|
||||
map_=self._fan_level_map,
|
||||
key=self.get_prop_value(prop=self._prop_fan_level))
|
||||
|
||||
if HA_CORE_HAS_ACTIVITY:
|
||||
|
||||
@property
|
||||
def activity(self) -> Optional[str]:
|
||||
"""The current vacuum activity.
|
||||
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.
|
||||
"""
|
||||
status = self.get_prop_value(prop=self._prop_status)
|
||||
if status is None:
|
||||
return None
|
||||
if status in self._prop_status_cleaning:
|
||||
return VacuumActivity.CLEANING
|
||||
if status in self._prop_status_docked:
|
||||
return VacuumActivity.DOCKED
|
||||
if status in self._prop_status_paused:
|
||||
return VacuumActivity.PAUSED
|
||||
if status in self._prop_status_returning:
|
||||
return VacuumActivity.RETURNING
|
||||
if status in self._prop_status_error:
|
||||
return VacuumActivity.ERROR
|
||||
return VacuumActivity.IDLE
|
||||
|
||||
else:
|
||||
|
||||
@property
|
||||
def state(self) -> Optional[str]:
|
||||
"""The current state of the vacuum."""
|
||||
status = self.get_prop_value(prop=self._prop_status)
|
||||
return None if (status is None) else self.get_map_value(
|
||||
map_=self._status_map, key=status)
|
||||
|
||||
@@ -52,25 +52,22 @@ from typing import Any, Optional
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.water_heater import (
|
||||
STATE_ON,
|
||||
STATE_OFF,
|
||||
ATTR_TEMPERATURE,
|
||||
WaterHeaterEntity,
|
||||
WaterHeaterEntityFeature
|
||||
)
|
||||
from homeassistant.components.water_heater import (STATE_ON, STATE_OFF,
|
||||
ATTR_TEMPERATURE,
|
||||
WaterHeaterEntity,
|
||||
WaterHeaterEntityFeature)
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity
|
||||
from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
@@ -79,8 +76,8 @@ async def async_setup_entry(
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('water_heater', []):
|
||||
new_entities.append(WaterHeater(
|
||||
miot_device=miot_device, entity_data=data))
|
||||
new_entities.append(
|
||||
WaterHeater(miot_device=miot_device, entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
@@ -95,12 +92,11 @@ class WaterHeater(MIoTServiceEntity, WaterHeaterEntity):
|
||||
|
||||
_mode_map: Optional[dict[Any, Any]]
|
||||
|
||||
def __init__(
|
||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
|
||||
) -> None:
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the Water heater."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_temperature_unit = None # type: ignore
|
||||
self._attr_temperature_unit = None
|
||||
self._attr_supported_features = WaterHeaterEntityFeature(0)
|
||||
self._prop_on = None
|
||||
self._prop_temp = None
|
||||
@@ -117,14 +113,11 @@ class WaterHeater(MIoTServiceEntity, WaterHeaterEntity):
|
||||
# temperature
|
||||
if prop.name == 'temperature':
|
||||
if not prop.value_range:
|
||||
_LOGGER.error(
|
||||
'invalid temperature value_range format, %s',
|
||||
self.entity_id)
|
||||
_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':
|
||||
@@ -133,9 +126,9 @@ class WaterHeater(MIoTServiceEntity, WaterHeaterEntity):
|
||||
'invalid target-temperature value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
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
|
||||
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
|
||||
if self._attr_temperature_unit is None and prop.external_unit:
|
||||
self._attr_temperature_unit = prop.external_unit
|
||||
self._attr_supported_features |= (
|
||||
@@ -144,17 +137,15 @@ class WaterHeater(MIoTServiceEntity, WaterHeaterEntity):
|
||||
# mode
|
||||
if prop.name == 'mode':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error(
|
||||
'mode value_list is None, %s', self.entity_id)
|
||||
_LOGGER.error('mode value_list is None, %s', self.entity_id)
|
||||
continue
|
||||
self._mode_map = prop.value_list.to_map()
|
||||
self._attr_operation_list = list(self._mode_map.values())
|
||||
self._attr_supported_features |= (
|
||||
WaterHeaterEntityFeature.OPERATION_MODE)
|
||||
self._prop_mode = prop
|
||||
if not self._attr_operation_list:
|
||||
self._attr_operation_list = [STATE_ON]
|
||||
self._attr_operation_list.append(STATE_OFF)
|
||||
self._attr_supported_features |= WaterHeaterEntityFeature.OPERATION_MODE
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the water heater on."""
|
||||
@@ -165,49 +156,45 @@ class WaterHeater(MIoTServiceEntity, WaterHeaterEntity):
|
||||
await self.set_property_async(prop=self._prop_on, value=False)
|
||||
|
||||
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])
|
||||
"""Set the target temperature."""
|
||||
await self.set_property_async(prop=self._prop_target_temp,
|
||||
value=kwargs[ATTR_TEMPERATURE])
|
||||
|
||||
async def async_set_operation_mode(self, operation_mode: str) -> None:
|
||||
"""Set the operation mode of the water heater.
|
||||
Must be in the operation_list.
|
||||
"""
|
||||
"""Set the operation mode of the water heater."""
|
||||
if operation_mode == STATE_OFF:
|
||||
await self.set_property_async(prop=self._prop_on, value=False)
|
||||
return
|
||||
if operation_mode == STATE_ON:
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
return
|
||||
if self.get_prop_value(prop=self._prop_on) is False:
|
||||
await self.set_property_async(
|
||||
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))
|
||||
if self.get_prop_value(prop=self._prop_on) is not True:
|
||||
await self.set_property_async(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))
|
||||
|
||||
@property
|
||||
def current_temperature(self) -> Optional[float]:
|
||||
"""Return the current temperature."""
|
||||
return self.get_prop_value(prop=self._prop_temp)
|
||||
"""The current temperature."""
|
||||
return (None if self._prop_temp is None else self.get_prop_value(
|
||||
prop=self._prop_temp))
|
||||
|
||||
@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)
|
||||
"""The target temperature."""
|
||||
return (None if self._prop_target_temp is None else self.get_prop_value(
|
||||
prop=self._prop_target_temp))
|
||||
|
||||
@property
|
||||
def current_operation(self) -> Optional[str]:
|
||||
"""Return the current mode."""
|
||||
"""The current mode."""
|
||||
if self.get_prop_value(prop=self._prop_on) is False:
|
||||
return STATE_OFF
|
||||
if not self._prop_mode and self.get_prop_value(prop=self._prop_on):
|
||||
return STATE_ON
|
||||
return self.get_map_value(
|
||||
map_=self._mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_mode))
|
||||
return (None if self._prop_mode is None else self.get_map_value(
|
||||
map_=self._mode_map, key=self.get_prop_value(prop=self._prop_mode)))
|
||||
|
||||
@@ -33,9 +33,11 @@ git checkout v1.0.0
|
||||
|
||||
### 方法 2: [HACS](https://hacs.xyz/)
|
||||
|
||||
HACS > 右上角三个点 > Custom repositories > Repository: https://github.com/XiaoMi/ha_xiaomi_home.git & Category or Type: Integration > ADD > 点击 HACS 的 New 或 Available for download 分类下的 Xiaomi Home ,进入集成详情页 > DOWNLOAD
|
||||
一键从 HACS 安装米家集成:
|
||||
|
||||
> 米家集成暂未添加到 HACS 商店,敬请期待。
|
||||
[](https://my.home-assistant.io/redirect/hacs_repository/?owner=XiaoMi&repository=ha_xiaomi_home&category=integration)
|
||||
|
||||
或者,HACS > 在搜索框中输入 **Xiaomi Home** > 点击 **Xiaomi Home** ,进入集成详情页 > DOWNLOAD
|
||||
|
||||
### 方法 3:通过 [Samba](https://github.com/home-assistant/addons/tree/master/samba) 或 [FTPS](https://github.com/hassio-addons/addon-ftp) 手动安装
|
||||
|
||||
@@ -47,7 +49,7 @@ HACS > 右上角三个点 > Custom repositories > Repository: https://github.com
|
||||
|
||||
[设置 > 设备与服务 > 添加集成](https://my.home-assistant.io/redirect/brand/?brand=xiaomi_home) > 搜索“`Xiaomi Home`” > 下一步 > 请点击此处进行登录 > 使用小米账号登录
|
||||
|
||||
[](https://my.home-assistant.io/redirect/config_flow_start/?domain=xiaomi_home)
|
||||
[](https://my.home-assistant.io/redirect/config_flow_start/?domain=xiaomi_home)
|
||||
|
||||
### 添加 MIoT 设备
|
||||
|
||||
@@ -59,7 +61,7 @@ HACS > 右上角三个点 > Custom repositories > Repository: https://github.com
|
||||
|
||||
方法:[设置 > 设备与服务 > 已配置 > Xiaomi Home](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home) > 添加中枢 > 下一步 > 请点击此处进行登录 > 使用小米账号登录
|
||||
|
||||
[](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home)
|
||||
[](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home)
|
||||
|
||||
### 修改配置项
|
||||
|
||||
@@ -91,7 +93,7 @@ HACS > 右上角三个点 > Custom repositories > Repository: https://github.com
|
||||
|
||||
- 米家集成是否支持本地化控制?
|
||||
|
||||
米家集成支持通过[小米中枢网关](https://www.mi.com/shop/buy/detail?product_id=15755&cfrom=search)(固件版本 3.4.0_000 以上)或内置中枢网关(软件版本 0.8.0 以上)的米家设备实现本地化控制。如果没有小米中枢网关或其他带中枢网关功能的设备,那么所有控制指令都会通过小米云发送。支持 Home Assistant 本地化控制的小米中枢网关(含内置中枢网关)的固件尚未发布,固件升级计划请参阅 MIoT 团队的通知。
|
||||
米家集成支持通过[小米中枢网关](https://www.mi.com/shop/buy/detail?product_id=15755&cfrom=search)(固件版本 3.3.0_0023 及以上)或内置中枢网关(软件版本 0.8.9 及以上)的米家设备实现本地化控制。如果没有小米中枢网关或其他带中枢网关功能的设备,那么所有控制指令都会通过小米云发送。支持 Home Assistant 本地化控制的小米中枢网关(含内置中枢网关)的固件尚未发布,固件升级计划请参阅 MIoT 团队的通知。
|
||||
|
||||
小米中枢网关仅在中国大陆可用,在其他地区不可用。
|
||||
|
||||
@@ -155,6 +157,8 @@ HACS > 右上角三个点 > Custom repositories > Repository: https://github.com
|
||||
|
||||
转换后的实体为 Event,事件参数同时传递给实体的 `_trigger_event` 。
|
||||
|
||||
MIoT-Spec-V2 事件的 arguments 字段是事件的参数列表,列表元素代表同服务下属性的 piid 。例如,小米智能无线开关(双开)的 [MIoT-Spec-V2](http://poc.miot-spec.srv/miot-spec-v2/instance?type=urn:miot-spec-v2:device:remote-control:0000A021:xiaomi-mcn002:1:0000D057)的 siid=2 无线开关服务下包含 eiid=1014 长按事件,该事件触发时会携带一个 piid=2 的按键类型属性作为事件参数, debug 等级日志会打印 `长按, attributes: {'按键类型': 1}` (日志示例,按键类型为 1 表示右键触发了长按事件)。
|
||||
|
||||
- 方法(Action)
|
||||
|
||||
| in(输入参数列表) | 转换后的实体 |
|
||||
@@ -289,46 +293,44 @@ event instance name 下的值表示转换后实体所用的 `_attr_device_class`
|
||||
|
||||
### MIoT-Spec-V2 过滤规则
|
||||
|
||||
`spec_filter.json` 用于过滤掉不需要的 MIoT-Spec-V2 实例,过滤掉的实例不会转换成 Home Assistant 实体。
|
||||
`spec_filter.yaml` 用于过滤掉不需要的 MIoT-Spec-V2 实例,过滤掉的实例不会转换成 Home Assistant 实体。
|
||||
|
||||
`spec_filter.json`的格式如下:
|
||||
`spec_filter.yaml`的格式如下:
|
||||
|
||||
```
|
||||
{
|
||||
"<MIoT-Spec-V2 device instance>":{
|
||||
"services": list<service_iid: str>,
|
||||
"properties": list<service_iid.property_iid: str>,
|
||||
"events": list<service_iid.event_iid: str>,
|
||||
"actions": list<service_iid.action_iid: str>,
|
||||
}
|
||||
}
|
||||
```yaml
|
||||
<MIoT-Spec-V2 device instance urn without the version field>:
|
||||
services: list<service_iid: str>
|
||||
properties: list<service_iid.property_iid: str>
|
||||
events: list<service_iid.event_iid: str>
|
||||
actions: list<service_iid.action_iid: str>
|
||||
```
|
||||
|
||||
`spec_filter.json` 的键值为 MIoT-Spec-V2 设备实例的 urn (不含版本号“version”字段)。一个产品的不同版本的固件可能会关联不同版本的 MIoT-Spec-V2 设备实例。 MIoT 平台要求厂商定义产品的 MIoT-Spec-V2 时,高版本的 MIoT-Spec-V2 实例必须包含全部低版本的 MIoT-Spec-V2 实例。因此, `spec_filter.json` 的键值不需要指定设备实例的版本号。
|
||||
`spec_filter.yaml` 的键值为 MIoT-Spec-V2 设备实例的 urn (不含版本号“version”字段)。一个产品的不同版本的固件可能会关联不同版本的 MIoT-Spec-V2 设备实例。 MIoT 平台要求厂商定义产品的 MIoT-Spec-V2 时,高版本的 MIoT-Spec-V2 实例必须包含全部低版本的 MIoT-Spec-V2 实例。因此, `spec_filter.yaml` 的键值不需要指定设备实例的版本号。
|
||||
|
||||
设备实例下的 services 、 properties 、 events 、 actions 域的值表示需要过滤掉的服务、属性、事件、方法的实例号( iid ,即 instance id )。支持通配符匹配。
|
||||
|
||||
示例:
|
||||
|
||||
```
|
||||
{
|
||||
"urn:miot-spec-v2:device:television:0000A010:xiaomi-rmi1":{
|
||||
"services": ["*"] # Filter out all services. It is equivalent to completely ignoring the device with such MIoT-Spec-V2 device instance.
|
||||
},
|
||||
"urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1": {
|
||||
"services": ["3"], # Filter out the service whose iid=3.
|
||||
"properties": ["4.*"] # Filter out all properties in the service whose iid=4.
|
||||
"events": ["4.1"], # Filter out the iid=1 event in the iid=4 service.
|
||||
"actions": ["4.1"] # Filter out the iid=1 action in the iid=4 service.
|
||||
}
|
||||
}
|
||||
```yaml
|
||||
urn:miot-spec-v2:device:television:0000A010:xiaomi-rmi1:
|
||||
services:
|
||||
- '*' # 排除所有服务,相当于排除拥有该 MIoT-Spec-V2 的设备。
|
||||
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:
|
||||
services:
|
||||
- '3' # 排除 siid=3 的服务。
|
||||
properties:
|
||||
- '4.*' # 排除 siid=4 服务的所有属性。
|
||||
events:
|
||||
- '4.1' # 排除 siid=4 服务的 eiid=1 的事件。
|
||||
actions:
|
||||
- '4.1' # 排除 siid=4 服务的 aiid=1 的方法。
|
||||
```
|
||||
|
||||
所有设备的设备信息服务( urn:miot-spec-v2:service:device-information:00007801 )均不会生成 Home Assistant 实体。
|
||||
|
||||
## 多语言支持
|
||||
|
||||
米家集成配置选项中可选择的集成使用的语言有简体中文、繁体中文、英文、西班牙语、俄语、法语、德语、日语这八种语言。目前,米家集成配置页面的简体中文和英文已经过人工校审,其他语言由机器翻译。如果您希望修改配置页面的词句,则需要修改 `custom_components/xiaomi_home/translations/` 以及 `custom_components/xiaomi_home/miot/i18n/` 目录下相应语言的 json 文件。
|
||||
米家集成配置选项中可选择的集成使用的语言有简体中文、繁体中文、英文、西班牙语、俄语、法语、德语、日语、意大利语、荷兰语、葡萄牙语、巴西葡萄牙语、土耳其语这十三种语言。目前,米家集成配置页面的简体中文和英文已经过人工校审,其他语言由机器翻译或社区贡献。如果您希望修改配置页面的词句,则需要修改 `custom_components/xiaomi_home/translations/` 以及 `custom_components/xiaomi_home/miot/i18n/` 目录下相应语言的 json 文件。
|
||||
|
||||
在显示 Home Assistant 实体名称时,米家集成会从小米云下载设备厂商为设备配置的多语言文件,该文件包含设备 MIoT-Spec-V2 实例的多语言翻译。 `multi_lang.json` 是本地维护的多语言配置字典,其优先级高于从云端获取的多语言文件,可用于补充或修改设备的多语言翻译。
|
||||
|
||||
@@ -346,14 +348,14 @@ event instance name 下的值表示转换后实体所用的 `_attr_device_class`
|
||||
|
||||
`multi_lang.json` 的键值为 MIoT-Spec-V2 设备实例的 urn (不含版本号“version”字段)。
|
||||
|
||||
language code 为语言代码,取值为 zh-Hans、zh-Hant、en、es、ru、fr、de、ja (对应上述米家集成可选的八种语言)。
|
||||
language code 为语言代码,取值为 zh-Hans、zh-Hant、en、es、ru、fr、de、ja、it、nl、pt、pt-BR、tr(对应上述米家集成可选的十三种语言)。
|
||||
|
||||
instance code 为 MIoT-Spec-V2 实例代码,格式如下:
|
||||
|
||||
```
|
||||
service:<siid> # 服务
|
||||
service:<siid>:property:<piid> # 属性
|
||||
service:<siid>:property:<piid>:valuelist:<value> # 属性取值列表的值
|
||||
service:<siid>:property:<piid>:valuelist:<value> # 属性取值列表的索引值
|
||||
service:<siid>:event:<eiid> # 事件
|
||||
service:<siid>:action:<aiid> # 方法
|
||||
```
|
||||
@@ -376,7 +378,7 @@ siid、piid、eiid、aiid、value 均为十进制三位整数。
|
||||
}
|
||||
```
|
||||
|
||||
> 在 Home Assistant 中修改了 `custom_components/xiaomi_home/miot/specs` 路径下的 `specv2entity.py`、`spec_filter.json`、`multi_lang.json` 文件的内容,需要在集成配置中更新实体转换规则才能生效。方法:[设置 > 设备与服务 > 已配置 > Xiaomi Home](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home) > 配置 > 更新实体转换规则
|
||||
> 在 Home Assistant 中修改了 `custom_components/xiaomi_home/miot/specs` 路径下的任何文件(`spec_filter.yaml`、`spec_modify.yaml`、`multi_lang.json`等),需要在集成配置中更新实体转换规则才能生效。方法:[设置 > 设备与服务 > 已配置 > Xiaomi Home](https://my.home-assistant.io/redirect/integration/?domain=xiaomi_home) > 配置 > 更新实体转换规则
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ SPEC_BOOL_TRANS_FILE = path.join(
|
||||
ROOT_PATH, '../custom_components/xiaomi_home/miot/specs/bool_trans.yaml')
|
||||
SPEC_FILTER_FILE = path.join(
|
||||
ROOT_PATH, '../custom_components/xiaomi_home/miot/specs/spec_filter.yaml')
|
||||
SPEC_MULTI_LANG_FILE = path.join(
|
||||
ROOT_PATH, '../custom_components/xiaomi_home/miot/specs/multi_lang.json')
|
||||
SPEC_ADD_FILE = path.join(
|
||||
ROOT_PATH, '../custom_components/xiaomi_home/miot/specs/spec_add.json')
|
||||
SPEC_MODIFY_FILE = path.join(
|
||||
@@ -38,7 +40,7 @@ def load_json_file(file_path: str) -> Optional[dict]:
|
||||
|
||||
def save_json_file(file_path: str, data: dict) -> None:
|
||||
with open(file_path, 'w', encoding='utf-8') as file:
|
||||
json.dump(data, file, ensure_ascii=False, indent=4)
|
||||
json.dump(data, file, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
def load_yaml_file(file_path: str) -> Optional[dict]:
|
||||
@@ -140,6 +142,14 @@ def bool_trans(d: dict) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def multi_lang(data: dict) -> bool:
|
||||
"""dict[str, dict[str, dict[str, str]]]"""
|
||||
for key in data.keys():
|
||||
if key.count(':') != 5:
|
||||
return False
|
||||
return nested_3_dict_str_str(data)
|
||||
|
||||
|
||||
def spec_add(data: dict) -> bool:
|
||||
"""dict[str, list[dict[str, int| str | list]]]"""
|
||||
if not isinstance(data, dict):
|
||||
@@ -304,6 +314,10 @@ def sort_spec_add(file_path: str):
|
||||
return dict(sorted(filter_data.items()))
|
||||
|
||||
|
||||
def sort_multi_lang(file_path: str):
|
||||
return sort_spec_add(file_path)
|
||||
|
||||
|
||||
def sort_spec_modify(file_path: str):
|
||||
filter_data = load_yaml_file(file_path=file_path)
|
||||
assert isinstance(filter_data, dict), f'{file_path} format error'
|
||||
@@ -326,6 +340,14 @@ def test_spec_filter():
|
||||
assert spec_filter(data), f'{SPEC_FILTER_FILE} format error'
|
||||
|
||||
|
||||
@pytest.mark.github
|
||||
def test_multi_lang():
|
||||
data = load_json_file(SPEC_MULTI_LANG_FILE)
|
||||
assert isinstance(data, dict)
|
||||
assert data, f'load {SPEC_MULTI_LANG_FILE} failed'
|
||||
assert multi_lang(data), f'{SPEC_MULTI_LANG_FILE} format error'
|
||||
|
||||
|
||||
@pytest.mark.github
|
||||
def test_spec_add():
|
||||
data = load_json_file(SPEC_ADD_FILE)
|
||||
@@ -418,6 +440,12 @@ def test_miot_data_sort():
|
||||
f'{SPEC_FILTER_FILE} not sorted, goto project root path'
|
||||
' and run the following command sorting, ',
|
||||
'pytest -s -v -m update ./test/check_rule_format.py')
|
||||
assert json.dumps(
|
||||
load_json_file(file_path=SPEC_MULTI_LANG_FILE)) == json.dumps(
|
||||
sort_multi_lang(file_path=SPEC_MULTI_LANG_FILE)), (
|
||||
f'{SPEC_MULTI_LANG_FILE} not sorted, goto project root path'
|
||||
' and run the following command sorting, ',
|
||||
'pytest -s -v -m update ./test/check_rule_format.py')
|
||||
assert json.dumps(load_json_file(file_path=SPEC_ADD_FILE)) == json.dumps(
|
||||
sort_spec_add(file_path=SPEC_ADD_FILE)), (
|
||||
f'{SPEC_ADD_FILE} not sorted, goto project root path'
|
||||
@@ -438,6 +466,8 @@ def test_sort_spec_data():
|
||||
sort_data = sort_spec_filter(file_path=SPEC_FILTER_FILE)
|
||||
save_yaml_file(file_path=SPEC_FILTER_FILE, data=sort_data)
|
||||
_LOGGER.info('%s formatted.', SPEC_FILTER_FILE)
|
||||
sort_data = sort_multi_lang(file_path=SPEC_MULTI_LANG_FILE)
|
||||
save_json_file(file_path=SPEC_MULTI_LANG_FILE, data=sort_data)
|
||||
sort_data = sort_spec_add(file_path=SPEC_ADD_FILE)
|
||||
save_json_file(file_path=SPEC_ADD_FILE, data=sort_data)
|
||||
_LOGGER.info('%s formatted.', SPEC_ADD_FILE)
|
||||
|
||||
Reference in New Issue
Block a user