- 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 отложен (семантика не зафиксирована)
67 lines
2.4 KiB
Python
67 lines
2.4 KiB
Python
"""Ручные конверсии/диапазоны (ConversionSet) без HA-рантайма."""
|
|
from __future__ import annotations
|
|
|
|
from custom_components.fglair.overrides import ConversionSet, LinearOverride
|
|
from pyfglair import Prop, Template
|
|
|
|
|
|
def test_identity_keeps_api_units():
|
|
conversions = ConversionSet(Template.A, {}, 5)
|
|
assert conversions.to_display(Prop.DISPLAY_TEMPERATURE, 200) == 200
|
|
assert conversions.to_display(Prop.ADJUST_TEMPERATURE, 220) == 220
|
|
assert conversions.from_display(Prop.ADJUST_TEMPERATURE, 220) == 220
|
|
assert conversions.temperature_range() == (160, 300)
|
|
|
|
|
|
def test_linear_override_roundtrip_and_clamp():
|
|
override = LinearOverride(
|
|
num=1, den=1, offset=5, min_value=170, max_value=280
|
|
)
|
|
conversions = ConversionSet(
|
|
Template.A, {Prop.ADJUST_TEMPERATURE: override}, 5
|
|
)
|
|
assert conversions.to_display(Prop.ADJUST_TEMPERATURE, 220) == 225
|
|
assert conversions.from_display(Prop.ADJUST_TEMPERATURE, 225) == 220
|
|
assert conversions.clamp(Prop.ADJUST_TEMPERATURE, 100) == 170
|
|
assert conversions.clamp(Prop.ADJUST_TEMPERATURE, 999) == 280
|
|
assert conversions.temperature_range() == (170, 280)
|
|
|
|
|
|
def test_linear_override_scaled():
|
|
override = LinearOverride(num=2, den=4, offset=0)
|
|
conversions = ConversionSet(
|
|
Template.A, {Prop.ADJUST_TEMPERATURE: override}, 5
|
|
)
|
|
assert conversions.to_display(Prop.ADJUST_TEMPERATURE, 200) == 100
|
|
assert conversions.from_display(Prop.ADJUST_TEMPERATURE, 100) == 200
|
|
|
|
|
|
def test_from_entry_parses_spec():
|
|
conversions = ConversionSet.from_entry(
|
|
{
|
|
"template": "B",
|
|
"temp_step": 10,
|
|
"overrides": {
|
|
"adjust_temperature": {
|
|
"num": 2,
|
|
"den": 4,
|
|
"offset": 5,
|
|
"min": 170,
|
|
"max": 280,
|
|
}
|
|
},
|
|
}
|
|
)
|
|
assert conversions.template == Template.B
|
|
assert conversions.step_tenths == 10
|
|
assert conversions.temperature_range() == (170, 280)
|
|
override = conversions.override(Prop.ADJUST_TEMPERATURE)
|
|
assert (override.num, override.den, override.offset) == (2, 4, 5)
|
|
assert conversions.override(Prop.FAN_SPEED).identity
|
|
|
|
|
|
def test_from_entry_defaults():
|
|
conversions = ConversionSet.from_entry({"template": "F"})
|
|
assert conversions.step_tenths == 5
|
|
assert conversions.temperature_range() == (160, 300)
|