ha(H3): превью шаблона с конверсиями; climate и сущности

- config flow: шаг preview (шаблон A/B/F, диапазон/шаг уставки, линейные
  коэффициенты num/den/offset, текст-превью по данным trial: hvac/fan/
  swing/capabilities/текущая температура)
- coordinator: push-driven DataUpdateCoordinator (снимок кэша, доступность
  online/recovering, первичный GET-батч, один batch_commit на действие)
- overrides.py: ConversionSet (ручные линейные конверсии и диапазон поверх
  таблиц ядра, применяются в HA)
- entity.py: DeviceInfo/unique_id/доступность, capabilities-фильтры
- climate: hvac/fan/swing/vertical+horizontal swing/preset ECO-BOOST,
  уставка 16-30 °C (шаг по шаблону), current_temperature
- sensor: room_temperature, error_code, connection_state (диагностика)
- binary_sensor: connectivity + флаги op_status (PROTOCOL §8.4)
- switch: 8 флагов-свойств; select: положения заслонок 0..N-1
- тесты: превью/конверсии/ошибки диапазона, сущности против mock_ac
  (снимок, команды, capabilities-фильтр, ручная конверсия), ConversionSet
- mock_ac: --set NAME=VALUE (0b/0x) для сценариев
- план: demand_control отложен (семантика не зафиксирована)
This commit is contained in:
2026-09-29 12:44:34 +03:00
parent 29f62b639c
commit 3e0b6b3653
21 changed files with 1974 additions and 87 deletions
+101 -1
View File
@@ -51,6 +51,24 @@
"data_description": {
"config_json": "Paste a JSON object produced by fglair-discover or fglctl"
}
},
"preview": {
"title": "Template preview",
"description": "Computed mapping (compare with the FGLair app):\n\n{preview}\n\nSetpoint range and conversion can be adjusted below.",
"data": {
"template": "Template",
"temp_min": "Minimum setpoint (°C)",
"temp_max": "Maximum setpoint (°C)",
"temp_step": "Setpoint step (°C)",
"temp_num": "Conversion numerator",
"temp_den": "Conversion denominator",
"temp_offset": "Conversion offset (0.1 °C)"
},
"data_description": {
"temp_num": "display = raw × num / den + offset (raw in API units, 0.1 °C)",
"temp_den": "display = raw × num / den + offset (raw in API units, 0.1 °C)",
"temp_offset": "display = raw × num / den + offset (raw in API units, 0.1 °C)"
}
}
},
"error": {
@@ -62,7 +80,8 @@
"invalid_import": "Invalid config JSON",
"no_devices": "No devices found in the account",
"unknown": "Unexpected error",
"properties_missing": "The device connected but did not report its base properties"
"properties_missing": "The device connected but did not report its base properties",
"invalid_range": "Minimum must be less than maximum, step must be positive"
},
"abort": {
"already_configured": "This device is already configured",
@@ -73,5 +92,86 @@
"timeout": "Timed out waiting for the device",
"properties_missing": "The device connected but did not report its base properties"
}
},
"entity": {
"climate": {
"name": "Air conditioner"
},
"sensor": {
"room_temperature": {
"name": "Room temperature"
},
"error_code": {
"name": "Error code"
},
"connection_state": {
"name": "Connection state",
"state": {
"idle": "Idle",
"registering": "Registering",
"online": "Online",
"recovering": "Recovering",
"offline": "Offline",
"key_error": "Key error"
}
}
},
"binary_sensor": {
"connectivity": {
"name": "Connectivity"
},
"defrost": {
"name": "Defrost"
},
"maintenance": {
"name": "Maintenance"
},
"oil_recovery": {
"name": "Oil recovery"
},
"pump_down": {
"name": "Pump down"
},
"check_operation": {
"name": "Check operation"
},
"simultaneous": {
"name": "Simultaneous operation"
}
},
"switch": {
"economy_mode": {
"name": "Economy"
},
"powerful_mode": {
"name": "Powerful"
},
"coil_dry_mode": {
"name": "Coil dry"
},
"min_heat": {
"name": "Minimum heat"
},
"outdoor_low_noise": {
"name": "Outdoor low noise"
},
"human_det_auto_save": {
"name": "Human detection auto save"
},
"wifi_led_enable": {
"name": "Wi-Fi LED"
},
"indoor_fan_control": {
"name": "Indoor fan control"
}
},
"select": {
"af_vertical_direction": {
"name": "Vertical airflow direction"
},
"af_horizontal_direction": {
"name": "Horizontal airflow direction"
}
}
}
}
+101 -1
View File
@@ -51,6 +51,24 @@
"data_description": {
"config_json": "Вставьте объект JSON, созданный fglair-discover или fglctl"
}
},
"preview": {
"title": "Превью шаблона",
"description": "Рассчитанные значения (сверьте с приложением FGLair):\n\n{preview}\n\nДиапазон уставки и конверсию можно поправить ниже.",
"data": {
"template": "Шаблон",
"temp_min": "Минимум уставки (°C)",
"temp_max": "Максимум уставки (°C)",
"temp_step": "Шаг уставки (°C)",
"temp_num": "Числитель конверсии",
"temp_den": "Знаменатель конверсии",
"temp_offset": "Смещение конверсии (0,1 °C)"
},
"data_description": {
"temp_num": "display = raw × num / den + offset (raw в единицах API, 0,1 °C)",
"temp_den": "display = raw × num / den + offset (raw в единицах API, 0,1 °C)",
"temp_offset": "display = raw × num / den + offset (raw в единицах API, 0,1 °C)"
}
}
},
"error": {
@@ -62,7 +80,8 @@
"invalid_import": "Некорректный config JSON",
"no_devices": "В аккаунте не найдено устройств",
"unknown": "Неожиданная ошибка",
"properties_missing": "Устройство подключилось, но не отдало базовые свойства"
"properties_missing": "Устройство подключилось, но не отдало базовые свойства",
"invalid_range": "Минимум должен быть меньше максимума, шаг — положительным"
},
"abort": {
"already_configured": "Устройство уже настроено",
@@ -73,5 +92,86 @@
"timeout": "Устройство не вышло на связь за отведённое время",
"properties_missing": "Устройство подключилось, но не отдало базовые свойства"
}
},
"entity": {
"climate": {
"name": "Кондиционер"
},
"sensor": {
"room_temperature": {
"name": "Температура в помещении"
},
"error_code": {
"name": "Код ошибки"
},
"connection_state": {
"name": "Состояние связи",
"state": {
"idle": "Покой",
"registering": "Регистрация",
"online": "На связи",
"recovering": "Восстановление",
"offline": "Не в сети",
"key_error": "Ошибка ключа"
}
}
},
"binary_sensor": {
"connectivity": {
"name": "Связь"
},
"defrost": {
"name": "Разморозка"
},
"maintenance": {
"name": "Обслуживание"
},
"oil_recovery": {
"name": "Возврат масла"
},
"pump_down": {
"name": "Pump down"
},
"check_operation": {
"name": "Проверка работы"
},
"simultaneous": {
"name": "Одновременные операции"
}
},
"switch": {
"economy_mode": {
"name": "Экономичный режим"
},
"powerful_mode": {
"name": "Мощный режим"
},
"coil_dry_mode": {
"name": "Сушка испарителя"
},
"min_heat": {
"name": "Минимальный обогрев"
},
"outdoor_low_noise": {
"name": "Тихий наружный блок"
},
"human_det_auto_save": {
"name": "Автосохранение при отсутствии людей"
},
"wifi_led_enable": {
"name": "Wi-Fi индикатор"
},
"indoor_fan_control": {
"name": "Управление вентилятором"
}
},
"select": {
"af_vertical_direction": {
"name": "Положение заслонки (верт.)"
},
"af_horizontal_direction": {
"name": "Положение заслонки (гориз.)"
}
}
}
}