Skip to content

修复docker环境下设备重启导致无法搜索到设备的问题 - #36

Open
WaterBucket0819 wants to merge 1 commit into
fooling:mainfrom
WaterBucket0819:main
Open

修复docker环境下设备重启导致无法搜索到设备的问题#36
WaterBucket0819 wants to merge 1 commit into
fooling:mainfrom
WaterBucket0819:main

Conversation

@WaterBucket0819

Copy link
Copy Markdown

No description provided.

@fooling

fooling commented Aug 4, 2026

Copy link
Copy Markdown
Owner

首先感谢代码贡献。

看了下代码。先提一句根因:read_all_sensors() 结尾会断开,但 coordinator 紧接着调的 read_buzzer_state()(以及 set_buzzer_state())重新建链后在任何路径上都没有断开,所以链路在每个 60 秒周期里大约有 55 秒是开着的 —— 任何一次重启(包括正常重启)都会留下残留链路。这才是「重启后搜不到设备」的根因,我已经另开 PR 修这部分了。顺带说明我一直没复现的原因:我本地用的是 ESPHome 蓝牙网关,连接由代理持有、不经过宿主机 BlueZ。

这个 PR 需要改的只有一处:设备名不能随启动变化。 分两步,都要做,漏一步都不生效。

第 1 步:去掉按广播名取设备名的逻辑

custom_components/em1003/__init__.py:

  • 删掉新增的整个 async_advertised_name() 函数;
  • async_setup_entry() 里这一段:
    device_name = async_advertised_name(hass, mac_address)

    if device_name:
        _LOGGER.info("Using advertised device name: %s", device_name)
    else:
        _LOGGER.debug("No advertised name for %s, using %s", mac_address, entry.title)
        device_name = entry.title

    em1003_device.device_name = device_name

改成:

    device_name = entry.title
    em1003_device.device_name = device_name

第 2 步:三处 name= 改成 default_name=

只做第 1 步还不够 —— 每次启动仍然会把 device_name 传进设备注册表,而 async_get_or_create()已存在的设备照样会覆盖 namedefault_name 只在设备还没有名字时才生效(HA helpers/device_registry.py:if default_name is not UNDEFINED and device.name is None),正是这里需要的语义。

文件 位置 改法
__init__.py async_setup_entry() 里的 device_registry.async_get_or_create(...) name=device_namedefault_name=device_name
sensor.py EM1003Sensor.device_infoDeviceInfo(...) name=self._device_namedefault_name=self._device_name
switch.py EM1003BuzzerSwitch.device_infoDeviceInfo(...) name=self._device_namedefault_name=self._device_name

三处都要改 —— 只要漏掉一个 DeviceInfo,实体添加时 entity_platform 还是会拿它去覆盖设备名。

为什么必须这么改

  • 会取到 MAC 当名字:Linux/BlueZ 上 BLEDevice.name 取的不是广播 local name,而是 BlueZ 的 Alias 属性;Alias 在没有名字时 fallback 成短横线格式的 MAC(bluez src/device.c)。而守卫 if not name or name == mac_address 比的是冒号格式(config_flow.py 里做过 .replace("-", ":") 规范化),两者永不相等,守卫失效 → 设备名会变成 AA-BB-CC-DD-EE-FF
  • 蓝牙代理场景直接改名:走 ESPHome 蓝牙网关时拿到的是广播 local_name(EM1003… / 720…),而不是设备 GATT 0x2A00 报的名字(协议文档里是 3GCG300ZY4 这种)。我自己就是这种部署,这个改动合进来我这边设备名会直接变。
  • 影响面:实体都是 _attr_has_entity_name = True,friendly_name = 设备名 + 实体名,所以设备名一变,8 个传感器加蜂鸣器开关的显示名全部跟着变;BlueZ 缓存里有没有名字还会导致每次启动来回翻转。
  • 不受影响的部分(明确一下范围,免得误会):unique_id 是 MAC 派生的,entity_id、自动化、历史和长期统计都不受影响;在 UI 里手动重命名过设备的用户走 name_by_user,也完全不受影响。受影响的只有没改过名的老用户的显示名。

二、根因修复的分支已推送

分支 fix/release-ble-link-after-buzzer-query(commit 1e782c2)已推到 origin,等这个PR合并后我再改下那里

改动只有 device.py 10 增 4 删:给 read_buzzer_state()set_buzzer_state() 各加一个 finally: await self.disconnect(),和 read_all_sensors() 现有做法一致;同时删掉了两个 except 分支里那句只把 self._client = None、并不真正拆链路的赋值(disconnect() 自己会清 client)。

@fooling

fooling commented Aug 12, 2026

Copy link
Copy Markdown
Owner

ok, 我改天基于你这个改一版合了

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