Цепочка багов: crash config flow → Unknown entity → unavailable сенсоры
Устройство
- Чайник: Polaris PWK-1725CGLD (devtype 86, firmware 2.30, MAC d8:bc:38:ae:cf:ff)
Другие Syncleo-устройства в сети (не управляются этой интеграцией, но влияют на config flow)
- Polaris PCM-1540WiFi (devtype 279, MAC 48:e7:29:72:00:29) — кофемашина, управляется через polaris-mqtt
- Polaris PVCRDC-5004 (devtype 202, MAC ec:41:f9:b8:c5:07) — пылесос, управляется через polaris-mqtt
Все три устройства используют протокол Syncleo и видны в Zeroconf под _syncleo._udp. Config flow отображает их все в списке, и крэш вызывается именно тем, что кофемашина отдаёт basetype: 'Unknown'.
- Версия интеграции: v1.0.1
- Home Assistant: 2026.3.x
Описание проблемы
Интеграция не работает с устройствами, которые при Zeroconf discovery отдают пустые или запоздавшие TXT-записи. Это приводит к цепочке из четырёх последовательных багов, каждый из которых блокирует работу.
Баг 1: Config flow падает с ValueError — окно добавления крашится
Воспроизведение
- Открыть «Добавить интеграцию» → Syncleo Kettle
- В списке устройств отображаются:
202: ec41f9b8c507 (Polaris PVCR-5001), Unknown: d8bc38aecfff, Unknown: 48e729720029
- Выбрать любое устройство → нажать «Подтвердить»
- Результат: «Unknown error occurred» / «Неверный формат данных»
Причина
В config_flow.py строка 63:
if int(device['basetype']) in POLARIS_DEVICE:
Кофемашина и чайник отдают basetype: 'Unknown' (TXT-записи не успели прийти). int('Unknown') → ValueError. Из-за одного устройства с кривыми данными крашится окно для всех устройств.
Скриншот
(см. приложенный скриншот 1 — «Unknown error occurred»)
Баг 2: После фикса config flow — KeyError: 'addresses'
Воспроизведение
- После патча config_flow (замена
int() на безопасную проверку) чайник появляется в списке как 86: d8bc38aecfff (Polaris PWK-1725CGLD)
- Ввести токен → нажать «Подтвердить»
- Результат: «Не удалось подключиться к устройству»
Причина
validate_input() передаёт discovered_device_info из Zeroconf-кэша в coordinator.async_setup(). Но кэш содержит словарь из discovery.py (с ключами mac, vendor, devtype...), а coordinator ожидает объект ServiceInfo (с ключом addresses). Итог: KeyError: 'addresses'.
Скриншот
(см. приложенный скриншот 2 — «Не удалось подключиться к устройству»)
Баг 3: Чайник добавляется как «Unknown» с unavailable сенсорами
Воспроизведение
- После второго патча (передача
None вместо device_info в validate_input) чайник успешно добавляется
- Но entity отображается как «Type Unknown (Unknown)», все сенсоры — «Недоступно»
Причина
__init__.py → async_setup_entry() снова передаёт discovered_device_info из кэша в coordinator. Та же проблема: кривые данные из кэша → coordinator падает → сенсоры не инициализируются.
Баг 4: Чайник отваливается при рестарте HA
Воспроизведение
- После полного фикса (передача
None в __init__.py) чайник работает
- Перезагрузить HA несколько раз подряд
- В 2–3 случаях из 5: entity уходят в
unavailable, появляется «Этот объект больше не предоставляется интеграцией syncleo_kettle»
Причина — цепочка:
discovery.py: Метод _update_service добавляет устройство в кэш даже с пустыми properties. В mDNS информация приходит частями — сначала факт наличия устройства, потом TXT-записи (vendor, devtype). Если TXT ещё не прилетели, устройство записывается как devtype: 'Unknown'.
coordinator.py: async_setup делает одну попытку discovery с таймаутом 10 секунд. Если чайник не успел — создаётся заглушка devtype=00, model=Unknown. Entity регистрируется с этими данными. При следующем рестарте, если чайник отвечает нормально, HA видит другой device_info и решает что старая entity «больше не предоставляется».
Логи при проблемном старте
Discovered device: d8bc38aecfff - 192.168.1.120:41122 (devtype: Unknown, vendor: Unknown)
Discovered device has empty properties, continuing to wait...
Timeout waiting for device with properties
Device info from dict: vendor=Polaris, basetype=00, devtype=00, firmware=0.00, model=Unknown
Device service info not available, cannot start server
Kettle is not connected (connection check failed)
Логи при успешном старте
Discovered device: d8bc38aecfff - 192.168.1.120:41122 (devtype: 86, vendor: Polaris)
Device info: vendor=Polaris, basetype=00, devtype=86, firmware=2.30, model=PWK-1725CGLD
Connection status updated: ConnectionStatus.CONNECTED
Что исправлено
1. discovery.py — фильтр Unknown-устройств
Было: _update_service берёт всё из Zeroconf. Если TXT-записи не пришли — записывает устройство как devtype: Unknown, vendor: Unknown. Мусор попадает в кэш и отравляет всю цепочку.
Стало: Жёсткий фильтр. Если properties пустые или нет devtype/vendor — пакет игнорируется. Ждём следующего обновления от Zeroconf с реальными данными. Полностью убирает появление «призраков» в системе.
devtype = properties.get('devtype')
vendor = properties.get('vendor')
if not devtype or not vendor:
_LOGGER.debug(
"Ignoring device %s - missing critical properties, "
"TXT records may not have arrived yet", mac
)
return
2. coordinator.py — стабильность подключения
Было: async_setup делает одну попытку с таймаутом 10 секунд. Не ответил — заглушка Unknown, и всё.
Стало:
Retry-логика: 3 попытки с увеличивающимся таймаутом (10/15/20 сек). HA не сдаётся сразу, а долбится в чайник до 45 секунд.
retry_timeouts = [10, 15, 20]
for attempt, timeout in enumerate(retry_timeouts, 1):
service_info = await self._hass.async_add_executor_job(
self.kettle.discover, True, timeout, zeroconf_instance
)
if service_info:
break
if attempt < len(retry_timeouts):
await asyncio.sleep(3)
Восстановление device_info: Если девайс всё же создался как Unknown, координатор сам перепишет информацию в реестре HA, как только получит нормальные данные.
if (self.device_info and
self.device_info.get("model_id") == "00" and
self.kettle.device and self.kettle.device.si and
self.kettle.device.si.properties):
self._create_device_info(self.kettle.device.si)
self.async_update_listeners()
3. __init__.py — оптимизация и чистка
Было:
- Глобальный запуск discovery в
async_setup — работает всегда, даже если нет ни одного чайника. Источник race condition.
async_setup_entry передаёт мусорные данные из кэша в coordinator → KeyError: 'addresses' → сенсоры unavailable.
async_unload_entry падает с KeyError если setup завершился с ошибкой на полпути.
Стало:
async_setup удалён целиком. Внедрён _async_lookup_discovered_device — умный поиск в кэше с короткими итерациями. Старт не блокирует весь HA.
async_setup_entry передаёт None в coordinator — coordinator всегда проходит через полный discovery с retry, не полагаясь на потенциально мусорные данные.
- Defensive Unload: при удалении/перезагрузке интеграция не падает с
KeyError, корректно вычищает данные через .get() / .pop(..., None).
- Единообразное использование
DOMAIN из .const.
- Очистка
hass.data[DOMAIN] при выгрузке последней записи.
4. config_flow.py — валидация «на берегу»
Было:
int(device['basetype']) крашит весь config flow если basetype не число → ValueError → «Unknown error occurred» для всех устройств.
- 3-секундная задержка discovery при каждой отправке формы, а не только при первом показе.
async_step_zeroconf запускал лишний discovery, хотя Zeroconf уже нашёл устройство.
validate_input передаёт кривой кэш в coordinator → KeyError: 'addresses'.
coordinator.shutdown() не вызывался при ошибке → утечка ресурсов.
Стало:
- Безопасная проверка через
_get_model_name() — isdigit() перед int(), хелпер вынесен и используется единообразно.
- Discovery только при первом показе формы.
- Zeroconf заранее заполняет
_discovered_devices — пропускает повторное 3-секундное сканирование.
validate_input передаёт None в coordinator — свежий discovery вместо мусора из кэша.
coordinator.shutdown() обёрнут в finally.
- Вынесен
_normalize_mac() — убрана дупликация.
start_discovery обёрнут в try/except.
- Константа
DISCOVERY_WAIT_SECONDS вместо хардкода 3.0.
Окружение
- HA 2026.3.x (Python 3.14)
- Polaris PWK-1725CGLD (devtype 86, firmware 2.30)
- В сети также присутствуют PCM-1540WiFi (devtype 279) и PVCRDC-5004 (devtype 202) — оба на Syncleo, видны в config flow
- Подключение: UDP (Syncleo protocol), Zeroconf discovery
- Wi-Fi: RSSI стабильный, все устройства в одной подсети с HA
Приложенные файлы
Исправленные версии четырёх файлов + два скриншота:
discovery.py
coordinator.py
__init__.py
config_flow.py
- Скриншот 1: crash config flow («Unknown error occurred»)
- Скриншот 2: после частичного фикса («Не удалось подключиться к устройству»)
fix.zip
Цепочка багов: crash config flow → Unknown entity → unavailable сенсоры
Устройство
Другие Syncleo-устройства в сети (не управляются этой интеграцией, но влияют на config flow)
Все три устройства используют протокол Syncleo и видны в Zeroconf под
_syncleo._udp. Config flow отображает их все в списке, и крэш вызывается именно тем, что кофемашина отдаётbasetype: 'Unknown'.Описание проблемы
Интеграция не работает с устройствами, которые при Zeroconf discovery отдают пустые или запоздавшие TXT-записи. Это приводит к цепочке из четырёх последовательных багов, каждый из которых блокирует работу.
Баг 1: Config flow падает с
ValueError— окно добавления крашитсяВоспроизведение
202: ec41f9b8c507 (Polaris PVCR-5001),Unknown: d8bc38aecfff,Unknown: 48e729720029Причина
В
config_flow.pyстрока 63:Кофемашина и чайник отдают
basetype: 'Unknown'(TXT-записи не успели прийти).int('Unknown')→ValueError. Из-за одного устройства с кривыми данными крашится окно для всех устройств.Скриншот
(см. приложенный скриншот 1 — «Unknown error occurred»)
Баг 2: После фикса config flow —
KeyError: 'addresses'Воспроизведение
int()на безопасную проверку) чайник появляется в списке как86: d8bc38aecfff (Polaris PWK-1725CGLD)Причина
validate_input()передаётdiscovered_device_infoиз Zeroconf-кэша вcoordinator.async_setup(). Но кэш содержит словарь изdiscovery.py(с ключамиmac,vendor,devtype...), а coordinator ожидает объектServiceInfo(с ключомaddresses). Итог:KeyError: 'addresses'.Скриншот
(см. приложенный скриншот 2 — «Не удалось подключиться к устройству»)
Баг 3: Чайник добавляется как «Unknown» с unavailable сенсорами
Воспроизведение
Noneвместоdevice_infoвvalidate_input) чайник успешно добавляетсяПричина
__init__.py→async_setup_entry()снова передаётdiscovered_device_infoиз кэша в coordinator. Та же проблема: кривые данные из кэша → coordinator падает → сенсоры не инициализируются.Баг 4: Чайник отваливается при рестарте HA
Воспроизведение
Noneв__init__.py) чайник работаетunavailable, появляется «Этот объект больше не предоставляется интеграцией syncleo_kettle»Причина — цепочка:
discovery.py: Метод_update_serviceдобавляет устройство в кэш даже с пустыми properties. В mDNS информация приходит частями — сначала факт наличия устройства, потом TXT-записи (vendor,devtype). Если TXT ещё не прилетели, устройство записывается какdevtype: 'Unknown'.coordinator.py:async_setupделает одну попытку discovery с таймаутом 10 секунд. Если чайник не успел — создаётся заглушкаdevtype=00, model=Unknown. Entity регистрируется с этими данными. При следующем рестарте, если чайник отвечает нормально, HA видит другойdevice_infoи решает что старая entity «больше не предоставляется».Логи при проблемном старте
Логи при успешном старте
Что исправлено
1.
discovery.py— фильтр Unknown-устройствБыло:
_update_serviceберёт всё из Zeroconf. Если TXT-записи не пришли — записывает устройство какdevtype: Unknown, vendor: Unknown. Мусор попадает в кэш и отравляет всю цепочку.Стало: Жёсткий фильтр. Если
propertiesпустые или нетdevtype/vendor— пакет игнорируется. Ждём следующего обновления от Zeroconf с реальными данными. Полностью убирает появление «призраков» в системе.2.
coordinator.py— стабильность подключенияБыло:
async_setupделает одну попытку с таймаутом 10 секунд. Не ответил — заглушкаUnknown, и всё.Стало:
Retry-логика: 3 попытки с увеличивающимся таймаутом (10/15/20 сек). HA не сдаётся сразу, а долбится в чайник до 45 секунд.
Восстановление device_info: Если девайс всё же создался как Unknown, координатор сам перепишет информацию в реестре HA, как только получит нормальные данные.
3.
__init__.py— оптимизация и чисткаБыло:
async_setup— работает всегда, даже если нет ни одного чайника. Источник race condition.async_setup_entryпередаёт мусорные данные из кэша в coordinator →KeyError: 'addresses'→ сенсоры unavailable.async_unload_entryпадает сKeyErrorесли setup завершился с ошибкой на полпути.Стало:
async_setupудалён целиком. Внедрён_async_lookup_discovered_device— умный поиск в кэше с короткими итерациями. Старт не блокирует весь HA.async_setup_entryпередаётNoneв coordinator — coordinator всегда проходит через полный discovery с retry, не полагаясь на потенциально мусорные данные.KeyError, корректно вычищает данные через.get()/.pop(..., None).DOMAINиз.const.hass.data[DOMAIN]при выгрузке последней записи.4.
config_flow.py— валидация «на берегу»Было:
int(device['basetype'])крашит весь config flow если basetype не число →ValueError→ «Unknown error occurred» для всех устройств.async_step_zeroconfзапускал лишний discovery, хотя Zeroconf уже нашёл устройство.validate_inputпередаёт кривой кэш в coordinator →KeyError: 'addresses'.coordinator.shutdown()не вызывался при ошибке → утечка ресурсов.Стало:
_get_model_name()—isdigit()передint(), хелпер вынесен и используется единообразно._discovered_devices— пропускает повторное 3-секундное сканирование.validate_inputпередаётNoneв coordinator — свежий discovery вместо мусора из кэша.coordinator.shutdown()обёрнут вfinally._normalize_mac()— убрана дупликация.start_discoveryобёрнут в try/except.DISCOVERY_WAIT_SECONDSвместо хардкода3.0.Окружение
Приложенные файлы
Исправленные версии четырёх файлов + два скриншота:
discovery.pycoordinator.py__init__.pyconfig_flow.pyfix.zip