
物联网智能家居【免费下载链接】hass-xiaomi-miotAutomatic integrate all Xiaomi devices to HomeAssistant via miot-spec, support Wi-Fi, BLE, ZigBee devices. 小米米家智能家居设备接入Hass集成项目地址https://gitcode.com/gh_mirrors/ha/hass-xiaomi-miot点击查看免费下载导读cnhdm.airrtc.wkq01新风机/暖通一体设备通过单个 MIoTthermostat服务同时暴露空调、地暖与新风三种功能且电源、目标温度、风速等属性语义高度重叠。本指南基于仓库中的设计规范文档 docs/superpowers/specs/2026-07-11-multi-climate-converters-design.md完整讲解如何通过模型级converters显式替换 精确 MIoT 属性选择器 实体唯一 ID 选项将设备拆分为两个 Climate 实体与一个 Fan 实体并保留共享温度 Sensor 与物理按键锁 Switch。读完本指南你将掌握这套多实体转换器机制的配置结构、唯一 ID 判定优先级、固定 HVAC 模式power-only Climate的行为规则以及与之配套的 pytest 测试策略。一、问题背景一个 thermostat 服务承载三种功能cnhdm.airrtc.wkq01的 MIoT 规格中空调、地暖和新鲜空气功能全部挂在同一个thermostat服务SIID 2下且多个属性承担重叠的语义角色——例如存在多个电源属性、多个目标温度属性、多个风速属性。在当时的全局转换器机制下GLOBAL_CONVERTERS中的 Climate 转换器按语义名分组属性遇到重复属性时只能先到先得。PR #2878 曾提议在ClimateEntity.on_init()中加入重复属性防护第一个匹配属性胜出但评审结论认为该方案不安全它依赖转换器的处理顺序结果不确定它会静默抑制设备真实具备的功能例如新风、地暖将无法独立控制它仍然无法把地暖和新风暴露为独立实体。模型级属性排除方案也被否决。最终设计目标明确必须保留每一个可独立控制的功能同时避免不相关属性被组合进同一个 Home Assistant 实体。本文档即该目标的批准设计状态Approved for implementation planning。二、设计目标与非目标Goals目标将设备表示为三个可独立控制的实体空调 Climate、地暖 Climate、新风 Fan共享环境温度保留为独立 Sensor物理控制锁保留为 Switch通过精确的 MIoT 标识符如prop.2.3声明式地选择存在歧义的属性保持既有空调实体身份不变含用户自定义的 Entity Registry ID为新增的父转换器与实体提供稳定、唯一、可区分的身份未配置新机制的其他型号设备转换器行为保持不变。Non-Goals非目标不改变全局 Climate 实体的重复属性选择逻辑不为单个型号抽取可复用的全局转换器常量不拆分 MIoT 服务定义本身默认不改变既有型号的实体身份。三、设备属性映射精确选择器 vs 语义名3.1 属性映射总表功能MIoT 选择器含义空调prop.2.3电源空调prop.2.1模式空调prop.2.5目标温度空调prop.2.2风速新风prop.2.9电源新风prop.2.7风速地暖prop.2.10电源地暖prop.2.8目标温度共享环境prop.3.1当前温度temperature设备控制prop.5.1物理控制锁physical_controls_locked3.2 两种寻址方式的取舍设计文档明确了一条重要规则三个父转换器内部使用精确选择器prop.2.x因为这些属性虽然同属一个服务却对应不同的逻辑功能而独立的 Sensor 和 Switch 使用语义属性名temperature、physical_controls_locked因为这两个名称本身无歧义。从源码实现看core/device.py 的init_converters()对子属性converters列表的解析逻辑是当props条目中包含.时走self.spec.get_properties(p, ...)精确查找可匹配全局唯一属性否则走service.get_properties(p, ...)按服务内语义名查找——这正与设计文档中的寻址规则一一对应。四、转换器选择语义模型级converters显式替换4.1 新增配置键与核心逻辑在Device.init_converters()中新增可选的模型定制键converterscustom_converters self.custom_config(converters) base_converters ( GLOBAL_CONVERTERS if custom_converters is None else custom_converters ) appends self.custom_config_list(append_converters) or [] for cfg in [*base_converters, *appends]: ...该逻辑已在 core/device.py 中落地实现init_converters()首先加入InfoConverter并分发设备信息随后按上述规则选取基础转换器集合再拼接append_converters。4.2 三种配置形态的行为表模型配置实际处理的转换器定义converters缺失依次处理GLOBAL_CONVERTERS再处理append_convertersconverters: []跳过全局转换器仅处理append_converters非空converters用模型converters替换全局转换器再处理append_converters关键语义这是显式替换机制而非合并——模型条目不会与GLOBAL_CONVERTERS融合。由于缺失该键时保持原有全局行为所有未配置该键的既有型号不受影响。4.3 Info 实体诊断数据的净化模型级converters定义中包含 Python 转换器类与内部配置结构不适合 Home Assistant 状态序列化或 recorder 持久化。因此InfoConv.decode()在构造负载前需要从复制出的customizes中剔除这些键customizes {**device.customizes} customizes.pop(append_converters, None) customizes.pop(converters, None) customizes.pop(extend_miot_specs, None)该实现已存在于 core/converters.pyInfoConv.decode()在payload.update(...)前完成上述pop随后通过converters: [c.full_name for c in device.converters]见 core/converters.py在顶层诊断字段中保留有效的运行时转换器全名——既保留有用诊断又不暴露类对象、不重复声明式配置。五、实体身份full_name 去重与唯一 ID 优先级5.1 父转换器去重父转换器去重已基于conv.full_name实现见 core/device.py 的add_converter与find_converter。空调转换器沿用由属性派生的默认属性名地暖与新风转换器通过kwargs.attr显式指定因此父转换器全名稳定且互不相同climate.floor_heating fan.fresh_air5.2 实体键与唯一 ID 的冲突点实体创建存在另一个碰撞点convert_unique_id()原先对每个MiotServiceConv都返回服务 IID。由于空调与地暖两个 Climate 转换器同属 SIID 2 的thermostat服务若不处理两者将获得相同的实体键与 HA 唯一 ID。设计在既有 fallback 之前插入两个可选唯一 ID 选项def convert_unique_id(conv): if uid : conv.option.get(unique_id): return uid if conv.option.get(use_unique_attr): return conv.attr # Existing fallback behavior remains unchanged. service getattr(conv, service, None) if isinstance(conv, MiotServiceConv) and isinstance(service, MiotService): return service.iid ...该实现已落地于 core/hass_entity.py 的convert_unique_id()。优先级如下option.unique_id option.use_unique_attr existing fallback三条规则要点kwargs.attr只决定转换器属性及其full_name本身不改变实体身份option.unique_id提供显式、稳定的实体标识优先级最高option.use_unique_attr: true使用conv.attr作为实体标识与建议实体 ID 后缀避免在已配置稳定属性时重复指定两者都未设置时MiotServiceConv维持原有按服务 IID 生成身份的行为。空调 Climate刻意保留原有服务 IID fallback身份不变地暖与新风设置稳定逻辑属性并开启use_unique_attr。5.3 固定显示名与翻译键option.name提供实体的固定英文显示名。设置后_attr_name被替换为指定名称_attr_translation_key被清除避免 Home Assistant 将thermostat翻译覆盖配置名配置名不做本地化如需更多语言须在代码中使用翻译键。当同时设置option.use_unique_attr: true时建议实体 ID 由conv.attr生成而非底层服务/属性标识。既有空调 Climate 不设置option.name、不启用use_unique_attr因此保留服务派生的Thermostat显示名、thermostat翻译键以及由thermostat服务派生的实体 ID——这正是兼容用户已重命名实体 ID的关键。六、固定 HVAC 模式power-only Climate 的option.hvac_mode6.1 适用条件与行为表option.hvac_mode为只有电源转换器、没有真实模式转换器的 Climate 实体定义固定运行模式。配置值通过现有_hvac_modes映射解析从而保持对应HVACAction一致映射初始化见 custom_components/xiaomi_miot/climate.py选项读取与_power_hvac_mode设置见 climate.py。以option.hvac_mode: heat为例完整行为电源状态HVAC 模式HVAC 动作offHVACMode.OFFHVACAction.OFFonHVACMode.HEATHVACAction.HEATING支持的 HVAC 模式恰好只有OFF与HEAT。选择 Heat 或调用开启时只写入实体被分配的电源属性设置目标温度时只写入其被分配的目标温度属性。6.2 条件性语义仅当存在电源转换器且无真实模式转换器时生效真实模式转换器始终优先一旦存在option.hvac_mode对支持的模式、状态、动作与写入全部失效未配置该选项的 power-only Climate 保留既有OFF/AUTO行为。6.3 状态更新的电源驱动不变量负载包含电源属性时其值确定性地设置is_on、HVAC 模式与 HVAC 动作与之前取值无关重复的电源值具有幂等性会重新断言完整的对应状态负载不包含电源属性时不得改变is_on、HVAC 模式或动作目标温度与当前温度仍独立更新同时包含电源与温度的负载在一次调用中同时更新两组状态。6.4 明确不引入 RestoreEntity设计不为ClimateEntity增加RestoreEntity行为设置/重载之后由设备返回的首次电源更新确立固定 HVAC 状态该约束同样写入测试策略见后文。七、模型配置cnhdm.airrtc.wkq01完整定制以下配置为设计文档批准的完整模型定制源码中已落地于 core/device_customizes.py 的DEVICE_CUSTOMIZES[cnhdm.airrtc.wkq01]cnhdm.airrtc.wkq01: { converters: [ { class: MiotClimateConv, services: [thermostat], kwargs: { main_props: [prop.2.1], }, converters: [ {props: [prop.2.1], desc: True}, {props: [prop.2.2], desc: True}, {props: [prop.2.3]}, {props: [prop.2.5]}, {props: [prop.3.1]}, ], }, { class: MiotClimateConv, services: [thermostat], kwargs: { attr: floor_heating, main_props: [prop.2.8], option: { name: Floor Heating, use_unique_attr: True, hvac_mode: heat, }, }, converters: [ {props: [prop.2.8]}, {props: [prop.2.10]}, {props: [prop.3.1]}, ], }, { class: MiotFanConv, services: [thermostat], kwargs: { attr: fresh_air, main_props: [prop.2.9], option: { name: Fresh Air, use_unique_attr: True, }, }, converters: [ {props: [prop.2.7], desc: True}, {props: [prop.2.9]}, ], }, ], sensor_properties: temperature, switch_properties: physical_controls_locked, }从源码看init_converters()对每个cfg的处理流程为先按services查找thermostat服务并创建父转换器MiotClimateConv/MiotFanConv再遍历converters子列表逐条按精确选择器解析属性并挂接到父转换器的attrscore/device.py。此外Device在get_spec()中调用init_converters()之前会先通过extend_miot_specs扩展本地规格core/device.py确保精确选择器解析到正确的属性对象。八、实体行为细则8.1 空调 Climate身份保持既有电源prop.2.3模式prop.2.1目标温度prop.2.5风速prop.2.2当前温度prop.3.1实体身份既有服务 IID fallback其支持的 HVAC 模式继续由模式属性的值列表派生对应 climate.py 中prop.in_list([mode])分支对_hvac_modes的填充逻辑。8.2 地暖 Climate固定 power-only 行为电源prop.2.10目标温度prop.2.8当前温度prop.3.1转换器属性floor_heating实体身份floor_heating源自显式转换器属性建议实体 ID 后缀floor_heating固定显示名Floor Heating该转换器无真实模式属性因此option.hvac_mode: heat应用前述固定 power-only 行为。开启地暖或选择 Heat 仅写prop.2.10设置目标温度仅写prop.2.8。8.3 新风 Fan有序列表映射电源prop.2.9风速prop.2.7转换器属性fresh_air实体身份fresh_air源自显式转换器属性建议实体 ID 后缀fresh_air固定显示名Fresh Air风速属性是三值枚举原始值描述1Low2Medium3High既有 Fan 有序列表转换ordered_list_item_to_percentage将描述映射为 Home Assistant 百分比并将百分比反向映射为原始 MIoT 值。实体报告三档速度支持FanEntityFeature.SET_SPEED。写入行为取决于当前电源状态开启状态下调整百分比仅写prop.2.7关闭状态下设置正百分比同时写prop.2.9 True与对应prop.2.7值将百分比设为 0仅写prop.2.9 False不带百分比调用开启仅写prop.2.9 True调用关闭仅写prop.2.9 False。任何新风操作都不得写入空调的电源或风速属性prop.2.3、prop.2.2——这是保证三实体互不干扰的硬约束。8.4 独立实体sensor_properties: temperature通过既有语义查找路径创建共享当前温度 Sensor即prop.3.1switch_properties: physical_controls_locked通过既有语义查找路径创建物理控制锁 Switch即prop.5.1。共享温度同时喂给两个 Climate 实体是有意为之Climate 需要当前温度而独立 Sensor 保留了设备原有功能特征二者并不冲突。九、兼容性保障未配置converters的型号继续处理GLOBAL_CONVERTERS后再处理append_converters既有append_converters定制语义保持不变既有转换器与实体唯一 ID 不变除非转换器显式设置unique_id或启用use_unique_attr该型号的既有空调实体保留基于服务 IID 的身份升级与重载后用户自定义的 Entity Registry 实体 ID 依然生效该变更不引入全局属性顺序优先级也不会抑制其他设备的重复属性因为该型号跳过了全局转换器未来 MIoT 规格新增内容必须先显式评审该模型定制及其 checked-in fixture之后才可能暴露新实体。十、测试策略首个聚焦的 pytest 基础设施10.1 测试目录结构本变更随设计引入仓库首个聚焦的 pytest 基础设施requirements_test.txt tests/ ├── conftest.py ├── fixtures/ │ └── cnhdm.airrtc.wkq01.json ├── test_converter_options.py └── test_cnhdm_airrtc_wkq01.pyrequirements_test.txt提供 pytest 与 Home Assistant 自定义组件测试支持fixtures 依赖tests/conftest.py仅包含这些测试所需的共享 HA 与集成 fixturestests/fixtures/cnhdm.airrtc.wkq01.json是固定的本地 MIoT 规格 fixture测试不拉取在线规格保证确定性tests/test_converter_options.py覆盖框架级转换器替换、身份、命名与 Info 诊断行为tests/test_cnhdm_airrtc_wkq01.py覆盖型号专属的实体分组、运行时行为与实体注册表迁移生命周期。CI 中新增 pytest 任务.github/workflows/validate.yml仅针对当前稳定版 Home Assistant 环境运行既有 stable/dev/2023.7 配置验证矩阵保持不变新单元测试任务不扩展该兼容性矩阵。基础设施保持最小化、聚焦于本转换器设计不引入覆盖率工具、多版本 pytest 矩阵或无关集成行为的测试。10.2 关键验证点转换器选择验证无converters键时获得全局追加转换器converters: []跳过全局但处理追加非空converters替换全局但仍处理追加Info 实体的customizes状态属性中省略模型级convertersInfo 顶层converters字段仍列出有效运行时转换器全名。唯一 ID验证option.unique_id覆盖use_unique_attr与服务 IID fallbackuse_unique_attr: true在无显式 ID 时返回conv.attr并以其生成建议实体 ID未设置任何选项的MiotServiceConv仍用服务 IID显式kwargs.attr产生稳定、互异的转换器全名该型号的两个 Climate 与一个 Fan 实体键、HA 唯一 ID 均互不相同。实体注册表迁移纯身份单元测试与注册表生命周期测试分离生命周期测试必须通过 HA 的 Entity Platform 添加实体以真正触达 Entity Registry仅 mockasync_add_entities不够。以既有空调身份预置注册表platform: xiaomi_miot unique ID: device unique ID-2 entity ID: climate.living_room_ac加载新模型配置后验证空调 Climate 复用既有注册条目、保留climate.living_room_ac地暖唯一 ID 为device unique ID-floor_heating、建议后缀floor_heating新风唯一 ID 为device unique ID-fresh_air、建议后缀fresh_air注册表中恰好两个 Climate 一个 Fan不产生重复 thermostat/空调实体服务派生的Thermostat显示名与thermostat翻译键不影响既有注册条目的复用。卸载并重载配置条目后三个唯一 ID 与实体 ID 全部保持不变、实体计数不增加、不出现_2/_3碰撞后缀、用户重命名的climate.living_room_ac仍指向原注册条目。固定 HVAC 模式地暖 Climate 恰好声明OFF与HEATHEAT → OFF → HEAT序列确定性地映射为HEAT/HEATING、OFF/OFF、HEAT/HEATING重复True/重复False电源更新幂等并重断言完整模式/动作状态仅含目标温度的负载更新温度而保留当前is_on、模式与动作通电与断电两种状态均验证含电源与温度的负载在同一次调用中更新两组状态选择 Heat 与调用开启仅写prop.2.10设置地暖目标温度仅写prop.2.8存在真实模式转换器时忽略option.hvac_mode无该选项的 power-only Climate 保留OFF/AUTO行为不引入/不测试新的 RestoreEntity 行为——设置或重载后首次电源更新确立正确的固定模式与动作。新风 Fan原始值1/2/3经 Low/Medium/High 解码为有序列表百分比代表性百分比反向编码为原始值1/2/3断言不重复实现 HA 的百分比取整算法speed_count 3且支持SET_SPEED开启时改百分比仅写prop.2.7关闭时设正百分比同时写prop.2.9 True与对应prop.2.7百分比置零与关闭仅写prop.2.9 False无百分比开启仅写prop.2.9 True任何新风操作不写prop.2.2/prop.2.3。模型映射以固定 fixture 为准完整获批实体集合恰好为域实体buttonInfoclimateThermostatclimateFloor HeatingfanFresh AirsensorTemperatureswitchPhysical Controls Locked同时验证恰好两个 Climate 父转换器与一个 Fan 父转换器每个父级attrs只含其声明属性子属性转换器保持domainNone且不创建为独立实体模型converters替换GLOBAL_CONVERTERS后 Info 转换器仍存在语义temperature恰好创建一个 Sensor、physical_controls_locked恰好创建一个 Switch无残留全局 thermostat 转换器产生额外 Climate/Fanfunction服务的属性含周程数据不因副作用而暴露空调实体保留旧唯一 ID 与服务派生实体 ID空调父级使用Thermostat显示名与thermostat翻译键地暖/新风使用固定名并清除服务翻译键地暖/新风使用floor_heating/fresh_air作为建议实体 ID 后缀各实体写入仅指向其被分配的电/模式/温度/风速属性。测试不得比较新旧完整转换器列表旧 Climate 分组正是被替换的缺陷上文六实体集合才是 checked-in fixture 的权威预期结果。该测试设计已部分在仓库中实现例如 tests/test_cnhdm_airrtc_wkq01.py 已断言两个MiotClimateConv、一个MiotFanConv、父级full_nameclimate.floor_heating、fan.fresh_air、各父级attrs的精确属性集合以及子属性转换器domain is None且 Info 转换器仍然存在——与上文设计逐条对应。十一、实施范围涉及文件一览本变更的预期实现文件设计文档Implementation Scope章节文件职责custom_components/xiaomi_miot/core/device.py选择模型converters或GLOBAL_CONVERTERS再追加append_converterscustom_components/xiaomi_miot/core/converters.py从 Info 实体的customizes状态属性中剔除模型级converters定义同时保留有效转换器名custom_components/xiaomi_miot/core/hass_entity.py应用唯一 ID 选项优先级启用use_unique_attr时以conv.attr作为建议实体 ID 后缀应用option.name固定显示名并清除服务翻译键custom_components/xiaomi_miot/climate.py仅对 power-only Climate 应用option.hvac_mode由_hvac_modes映射派生支持模式、通电状态与 HVAC Action电源存在时确定性更新模式/动作、无关部分负载时予以保留保持真实模式转换器优先级与默认OFF/AUTO行为custom_components/xiaomi_miot/core/device_customizes.py添加该型号专属转换器定义与语义 Sensor/Switch 属性.github/workflows/validate.yml新增使用当前稳定版 HA 测试环境的 pytest 任务requirements_test.txt声明最小 pytest 与 HA 自定义组件测试依赖tests/conftest.py提供共享 HA 与集成 fixturestests/fixtures/cnhdm.airrtc.wkq01.json提供确定性的本地 MIoT 规格供模型测试tests/test_converter_options.py测试转换器替换、身份选项、命名与 Info 诊断tests/test_cnhdm_airrtc_wkq01.py测试型号专属转换器分组与实体行为本设计不包含全局转换器抽取或无关的 Climate 重构。结语cnhdm.airrtc.wkq01多实体转换器设计给出了一条可复用的技术路线当单个 MIoT 服务承载多种相互独立的功能、且属性语义重叠时通过在模型定制中显式替换converters、以精确属性选择器prop.siid.piid声明式划分职责、辅以use_unique_attr/unique_id消解实体身份冲突、并用option.hvac_mode为 power-only Climate 固化运行模式即可在完全不触碰全局逻辑的前提下把一个物理设备优雅地建模为多个边界清晰的 Home Assistant 实体。该设计已被仓库源码完整落地并配有一整套确定性测试基础设施固定本地 MIoT fixture 实体注册表迁移生命周期测试可作为后续同类一服务多功能设备的接入蓝本。赞分享物联网智能家居【免费下载链接】hass-xiaomi-miotAutomatic integrate all Xiaomi devices to HomeAssistant via miot-spec, support Wi-Fi, BLE, ZigBee devices. 小米米家智能家居设备接入Hass集成项目地址https://gitcode.com/gh_mirrors/ha/hass-xiaomi-miot点击查看免费下载相关推荐小米热水器智能控制hass-xiaomi-miot water_heater温度调节与模式切换小米热水器智能控制hass xiaomi miot water_heater温度调节与模式切换 想要让家中的小米热水器变得更智能吗 通过 hass xi物联网智能家居上一篇NoneBot2 消息处理实战指南Message 消息序列、MessageSegment 消息段与消息模板深度解析下一篇KMS智能激活Windows和Office批量授权的终极解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考