Поддержка вкл/выкл контура через hvac_mode + ряд фиксов (протестировано на H-1) - #54
Open
Anzic23 wants to merge 9 commits into
Open
Поддержка вкл/выкл контура через hvac_mode + ряд фиксов (протестировано на H-1)#54Anzic23 wants to merge 9 commits into
Anzic23 wants to merge 9 commits into
Conversation
Replace SetHvacModeError with async_set_hvac_mode: - OFF maps to first mode with выкл/откл/off in name - HEAT restores last known mode or picks first non-off mode - Extract _async_apply_heating_mode shared by preset and hvac-mode setters - Track _last_heat_mode_id in coordinator updates
…hvac_mode Root cause of the 400 not_z3k_device error: heating-mode dispatch guessed the API family from the model name (+/pro -> V3, else -> V1). H-1 (widget_type=zth) fell into the V1 z3k branch and ZONT rejected it. - Dispatch on device_info.widget_type: z3k -> API V1, otherwise V3. - hvac_mode now reports OFF when the active heating mode is an off-mode (is_off alone does not reflect the Выключен mode). - Track last non-off mode via _update_last_heat_mode for HEAT restore. - Add TURN_ON/TURN_OFF features (HA 2026.x) so the power toggle maps to async_set_hvac_mode.
… 5-80
Per real H-1 behaviour (verified against live ZONT API):
- mode activation endpoint is device-wide; circuit_ids is effectively
ignored, but ГВС works on_request so only Отопление target changes.
- thermostat OFF -> set consumer target to HVAC_OFF_TEMP (5) + activate
«Выключен»; HEAT -> set target to HVAC_HEAT_TEMP (40) + activate «Комфорт».
- hvac_mode derived from target_temp (<=5 = OFF): mode fields
(current_mode/applied) are unreliable/desynced on H-1.
- Отопление temp limits 5-80 (MATCHES_HEATING); API min/max -30/100 is
rejected by the validator and fell back to 5-35.
API fixes in core/zont.py:
- set_heating_mode_all_circuits: send json={} (без тела -> «Не указан
Content-Type»); this also makes the heating-mode buttons work.
- set_heating_mode: body circuit_ids (array), not circuit_id (singular),
which returned «not implemented».
- _async_apply_heating_mode routes T100/T102 by device_info.id too
(H-1 reports device_info.id=T100).
Manual target-temp setting puts the circuit into manual mode (current_mode -> None) and drops it from modes.applied, so the mode never showed active in ZONT LK/app when toggled from HA. Verified on live API: activating a mode alone auto-sets the heat-carrier target (Komfort->40, Vykluchen->5) AND marks the mode applied across circuits. - async_set_hvac_mode now just activates the mode; target follows. - Makes HA and LK mode state consistent both directions (preset_mode reflects current_mode; LK shows the activated mode). - Drop unused HVAC_HEAT_TEMP. Note: GVS target is untouched by mode changes (works on_request).
ZONT pushes events (e.g. SelectHeatingMode) with additional_info={} but
AdditionalInfo.object_id was required -> pydantic ValidationError (a
ValueError) -> handler logged "Wrong webhook request" and dropped the
event, so LK/app changes never triggered an immediate HA refresh and
relied on the 60s poll instead.
Make object_id optional; webhook now parses and calls
coordinator.async_request_refresh() -> near-instant LK -> HA sync.
hvac_mode was read from target_temp while preset_mode read current_mode. On mode switch ZONT updates current_mode and target_temp non-atomically, so the thermostat could show hvac=off together with preset=Комфорт. Derive hvac_mode from the active heating mode (off-mode -> OFF, else HEAT); fall back to target_temp only when no mode is set (manual).
Root cause of "change one, another updates": heating modes on H-1 are device-wide, so current_mode is identical on ГВС and Отопление. Deriving hvac_mode/preset_mode from current_mode made toggling heating also flip the DHW tile. - hvac_mode and preset_mode now both derive from the per-circuit target_temp (<= HVAC_OFF_TEMP = OFF). Circuits are independent and the two properties never disagree. ГВС stays HEAT regardless of heating. - webhook: two-stage delayed resync (6s, +8s) to cover ZONT read-API eventual-consistency lag (~10s) after a mode change. - poll interval 60s -> 30s as a safety net for changes that emit no webhook (e.g. target-temp edits in the ZONT app).
Turning hot water off in ZONT LK removes the DHW circuit from the API response entirely, not is_off=true. The climate entity then crashed on every coordinator update: get_circuit returned None then None.id. - Track a stable self._circuit_id; on update, if the circuit is missing, mark the entity unavailable instead of crashing. GVS shows unavailable while hot water is off and recovers when it is back on. - DHW on/off cannot be driven via the widget v3 API; for the DHW thermostat hvac OFF/HEAT now sets the circuit target (5 / DHW_ON_TEMP) per-circuit instead of activating the device-wide mode.
Owner
|
Здравствуйте! Благодарю за вклад в развитие проекта! Извиняюсь за долгий ответ, не хватало времени. Предлагаю оставить только 1 и 2 категорию правок, а третью пока не добавлять. В начале сезона надо будет потестировать как будет работать на разных устройствах. |
Owner
|
Если что, то можете написать мне в телеграм mihvs, для более быстрой обратной связи |
Owner
1 категория
2 категория
3 категорияпотестирую вашу идею на разных устройствах, ближе к сезону. Просьба, подготовьте пул реквест только по 3 категории. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Привет! Спасибо за интеграцию — пользуюсь на котле ZONT H-1.
В процессе настройки «нормального» термостата я сделал ряд правок в своём форке (Anzic23/zont_ha). Ветка лежит ровно поверх вашего main, конфликтов нет. Не настаиваю на полном слиянии — разбил всё по категориям, чтобы вы могли забрать только то, что считаете безопасным.
🟢 Категория 1. Универсальные багфиксы (предлагаю забрать в любом случае)
Это, как мне кажется, баги, проявляющиеся независимо от модели:
Webhook отбрасывал события с пустым
additional_info.AdditionalInfo.object_idбыл обязательным (str | int), а ZONT шлёт часть событий сadditional_info: {}. Pydantic кидалValidationError, событие падало вexcept ValueError→ «Wrong webhook request», и HA обновлялся только по таймеру. Фикс:object_id: str | int | None = None. (core/models_zont_webhook.py)set_heating_modeслал неверное тело запроса. Отправлялось{'circuit_id': N}, а эндпоинтmodes/{id}/actions/activateожидает массив{'circuit_ids': [N]}. На H-1 без этого приходилnot implemented. (core/zont.py)set_heating_mode_all_circuitsслал запрос без тела. ZONT отвечал «Не указан Content-Type». Добавилjson={}. (core/zont.py)🟡 Категория 2. Улучшения (полезны всем, но это вопрос вкуса/нагрузки)
Двухстадийный resync после webhook-события.
target_tempв read-API обновляется с задержкой ~10с после смены режима (eventual consistency), поэтому первыйasync_request_refresh()ловит старую уставку. Добавил добор-опросы через 6 и 8 секунд. (__init__.py)Диапазон 5–80°C для отопительных контуров. Добавил
MATCHES_HEATING = ('отопл', 'теплонос')по аналогии с GVS/FLOOR — иначе у контура теплоносителя брались значения из API, неудобные для climate-сущности. Диапазон выбран эмпирически. (const.py)TIME_UPDATE60 → 30с. Это лично моя настройка (подстраховка для изменений без webhook). Для upstream — на ваше усмотрение, удваивает частоту опроса API.🔴 Категория 3. Поведенческое изменение под H-1 (нужно ваше решение)
Вкл/выкл контура через
hvac_mode(HEAT/OFF). Основная правка (climate.py, ~155 строк). Сейчас в README прямо написано, чтоset_hvac_modeне поддерживается — «такова особенность ZONT». На H-1 мне удалось это обойти:hvac_modeиpreset_modeвыводятся из per-circuittarget_temp(<= 5°= OFF), а не из device-widecurrent_mode. На H-1current_modeобщий для всех контуров, и если выводить состояние из него — смена режима одного контура «дёргала» отображение остальных.async_set_hvac_mode(HEAT/OFF)для отопления только активирует режим (Комфорт/Выключен) — активация сама ставит уставку и помечает режим активным в ЛК. Ручная установка target сбрасывалаcurrent_mode → None.circuit_id+available, чтобы не падало сAttributeError, и сущность уходила вunavailable.widget_type(z3k→ V1, иначе → V3) иdevice_info.id ∈ {T100, T102}— у меня оригинальная логика по имени модели не срабатывала для H-1.Это меняет задокументированное поведение, и я не уверен, что логика
target_temp ≤ 5 = OFFи device-wide режимы верны для всех приборов. Поэтому выношу отдельно — возможно, имеет смысл прятать за условие по модели/типу, либо обсудить.Готов разбить на отдельные PR'ы (например, отдельно категорию 1), переписать под ваши соглашения или просто оставить как референс. Как вам удобнее?