Skip to content

修复多网关下相同分机编号的实体冲突#3

Merged
caibinqing merged 8 commits into
caibinqing:devfrom
jackjinke:dev
Jun 1, 2026
Merged

修复多网关下相同分机编号的实体冲突#3
caibinqing merged 8 commits into
caibinqing:devfrom
jackjinke:dev

Conversation

@jackjinke

Copy link
Copy Markdown

背景

当前 DS-AIR 实体的 unique_id 主要依赖 room_id / unit_id。多个网关同时接入时,不同网关下
可能存在相同的分机编号,Home Assistant 会把它们识别为同一设备或实体,导致第二个网关的部
分空调/传感器无法正常创建。

改动

  • 使用 config entry 的 entry_id 作为 gateway_id,并加入设备 / 实体 unique_id,避免多网
    关下 room_id / unit_id 重复冲突
  • 为网关创建 hub device,空调和传感器通过 via_device 关联到对应网关
  • 传感器绑定从按空调名称匹配改为按 climate unique_id 匹配,避免同名或同编号设备歧义
  • 移除 sensor 手动设置 entity_id 的逻辑,避免 Home Assistant 对 invalid entity_id 的警
  • 保持空调默认可见名称逻辑不变,传感器默认名称增加“传感器”后缀

注意

  • 这次没有加入旧 unique_id 到新 unique_id 的 registry migration。升级后,已有实体可能会被
    Home Assistant 视为新实体;但新接入和多网关场景下可以正确区分不同网关的设备。
  • 当前传感器数据有bug,实体显示为不可用(已有issue https://github.com/mypal/ha-dsair/issues/93),这个改动不涉及相关问题。
  • Coding过程中有使用Codex + GPT-5.5 xhigh。

测试

在我自己的HA实例上测试没有发现问题。HA版本2026.5.4。
截屏2026-05-30 03 07 11

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the ds_air integration to support multiple gateways by incorporating the gateway ID into device unique IDs and registering the gateway itself in the device registry. The review feedback highlights critical backward compatibility issues where existing sensor bindings using climate aliases will fail to load or pre-populate in the options flow. Additionally, the reviewer suggests adding defensive null checks for device aliases to prevent potential runtime errors, and improving the usability of multi-gateway setups by dynamically naming gateway devices and appending host IPs to integration titles.

Comment on lines +86 to +87
climate_id = i.get("climate")
if climate := climate_by_unique_id.get(climate_id):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

对于已经配置了传感器绑定的现有用户,其绑定关系中存储的是空调的 alias(名称)而不是新的 unique_id。升级到此版本后,由于 climate_by_unique_id.get(climate_id) 会返回 None,这些已有的绑定关系将会静默失效。建议在此处增加一个基于 alias 匹配的兼容逻辑,以确保向后兼容性。

Suggested change
climate_id = i.get("climate")
if climate := climate_by_unique_id.get(climate_id):
climate_id = i.get("climate")
climate = climate_by_unique_id.get(climate_id)
if not climate:
climate = next((c for c in climates if c._device_info.alias == climate_id), None)
if climate:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前为了避免代码过度复杂化,没有加向后兼容的逻辑。如果后续讨论认为有这个必要,可以再加入完整的向后兼容代码。

Comment on lines 223 to 225
cur_link = next(
(link for link in cur_links if link["climate"] == cur_climate), None
(link for link in cur_links if link.get("climate") == cur_climate), None
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

与气候实体绑定类似,在编辑选项(OptionsFlow)时,cur_links 中已有的绑定关系可能仍使用空调的 alias。如果不做兼容处理,选项表单将无法正确回显(pre-populate)已有的传感器绑定。建议在此处增加对 alias 的兼容匹配。

        service = self.hass.data[DOMAIN][self._config_entry.entry_id]
        aircon = next((ac for ac in service.get_aircons() if ac.unique_id == cur_climate), None)
        cur_link = next(
            (
                link for link in cur_links
                if link.get("climate") == cur_climate
                or (aircon and link.get("climate") == aircon.alias)
            ),
            None
        )

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前为了避免代码过度复杂化,没有加向后兼容的逻辑。如果后续讨论认为有这个必要,可以再加入完整的向后兼容代码。

Comment thread custom_components/ds_air/ds_air_service/dao.py
Comment thread custom_components/ds_air/__init__.py Outdated
Comment on lines +53 to +56
return self.async_create_entry(
title=get_default_gateway_name(),
data=self.user_input,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在配置多个网关时,默认的集成标题都是 "金制空气"。建议在默认标题中附带主机 IP 地址(如 金制空气 (192.168.1.x)),这样用户在集成页面中可以非常直观地识别和管理不同的网关。

                host = self.user_input.get(CONF_HOST)
                title = f"{get_default_gateway_name()} ({host})" if host else get_default_gateway_name()
                return self.async_create_entry(
                    title=title,
                    data=self.user_input,
                )

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

使用IP地址作为实体名称有些奇怪,实际上最好的方案是用金制空气APP中的名称或者MAC地址,不过相关方法目前没有实现。我也想过改成“智能网关”作为默认名,不过还涉及到一些本地化的修改,就暂时没动。

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@caibinqing

Copy link
Copy Markdown
Owner

我觉得兼容还是有必要的,我实测了一下直接切到这个版本,原有实体就失效了,清理一遍很麻烦的,希望能无感升级。建议加上迁移逻辑

@caibinqing
caibinqing merged commit 625e87f into caibinqing:dev Jun 1, 2026
1 check passed
@caibinqing

Copy link
Copy Markdown
Owner

上游今天把这些PR合并了,但是没有包含你最后一个提交(dbd6ea1),建议单开一个PR给上游。这个迁移流程我测试过了,没有问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants