ha(H5): исправления по ревью — GitHub/HACS, рабочий ESPHome-канал, restore, manylinux

- critical: README честно описывает HACS (только публичный GitHub-зеркало)
  + ручная установка копированием; RELEASE_HA — шаг зеркала и codeowners
- critical: ESPHome-канал приёмки реализован реально (aioesphomeapi:
  connect/list_entities/climate_command для режима и уставки; fan/swing —
  только HA); unit-тест на фейковом модуле
- major: quick/long восстанавливают исходное состояние в finally даже при
  сбое; quick ждёт восстановления; ошибки шага пишутся в результат (rc 1),
  а не фаталят (rc 2)
- major: RELEASE_HA — manylinux через auditwheel repair (PyPI отклоняет
  linux_x86_64), build/twine, aarch64, корректные проверки .so, тег/версия
- major: полный ключ для ESPHome теперь реально виден в options flow
  («Настройка» на карточке интеграции, поле LAN IP key, можно заменить) —
  README/diagnostics синхронизированы
- minor: non-JSON ответ → rc 2; CSV quick+long и инкрементальная запись;
  допуск _matches в long; --settle-timeout; hacs.json homeassistant=2025.1;
  brand/{icon,logo}.png заглушки; план §6/§7 уточнён
- тесты: acceptance self-test 11 (restore-after-failure, long fail, non-JSON,
  esphome channel), options flow (2), всего 28+11+49
This commit is contained in:
2026-09-29 14:54:50 +03:00
parent 8013781e09
commit a03458f9bc
15 changed files with 609 additions and 178 deletions
@@ -479,3 +479,44 @@ async def test_reconfigure_wrong_device(hass: HomeAssistant):
)
assert result["type"] == "abort"
assert result["reason"] == "unique_id_mismatch"
async def test_options_flow_shows_and_updates_key(
hass: HomeAssistant, mock_ac, socket_enabled
):
from test_entities import _setup_entry
proc = mock_ac(["--set", "operation_mode=6"])
entry = await _setup_entry(hass, proc.port)
result = await hass.config_entries.options.async_init(entry.entry_id)
assert result["type"] == "form"
assert result["step_id"] == "init"
assert _suggested(result["data_schema"], "lanip_key") == LANIP_KEY
assert result["description_placeholders"]["dsn"] == DSN
result = await hass.config_entries.options.async_configure(
result["flow_id"], {"lanip_key": LANIP_KEY}
)
assert result["type"] == "create_entry"
await hass.async_block_till_done()
assert entry.data["lanip_key"] == LANIP_KEY
assert await hass.config_entries.async_unload(entry.entry_id)
async def test_options_flow_new_key_reloads(
hass: HomeAssistant, mock_ac, socket_enabled
):
from test_entities import _setup_entry
proc = mock_ac(["--set", "operation_mode=6"])
entry = await _setup_entry(hass, proc.port)
result = await hass.config_entries.options.async_init(entry.entry_id)
result = await hass.config_entries.options.async_configure(
result["flow_id"], {"lanip_key": "bmV3LWtleQ=="}
)
assert result["type"] == "create_entry"
await hass.async_block_till_done()
assert entry.data["lanip_key"] == "bmV3LWtleQ=="
assert entry.state.name in ("LOADED", "SETUP_RETRY")
if entry.state.name == "LOADED":
assert await hass.config_entries.async_unload(entry.entry_id)