Coverage for src/ramses_tx/typed_dicts.py: 100%
309 statements
« prev ^ index » next coverage.py v7.11.3, created at 2026-01-05 21:44 +0100
« prev ^ index » next coverage.py v7.11.3, created at 2026-01-05 21:44 +0100
1# We use typed dicts rather than data classes because we migrated from dicts
3from enum import EnumCheck, StrEnum, verify
4from typing import Literal, NotRequired, TypeAlias, TypedDict
6from ramses_tx.const import FaultDeviceClass, FaultState, FaultType
7from ramses_tx.schemas import DeviceIdT
9_HexToTempT: TypeAlias = float | None
12__all__ = ["PayDictT"]
15# fmt: off
16LogIdxT = Literal[
17 '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0A', '0B', '0C', '0D', '0E', '0F',
18 '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1A', '1B', '1C', '1D', '1E', '1F',
19 '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2A', '2B', '2C', '2D', '2E', '2F',
20 '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3A', '3B', '3C', '3D', '3E', '3F',
21]
22# fmt: on
25class _FlowRate(TypedDict):
26 dhw_flow_rate: _HexToTempT
29class _Pressure(TypedDict):
30 pressure: _HexToTempT
33class _Setpoint(TypedDict):
34 setpoint: _HexToTempT
37class _Temperature(TypedDict):
38 temperature: _HexToTempT
41class FaultLogEntryNull(TypedDict): # NOTE: not identical to _0418
42 _log_idx: LogIdxT # "00" to ?"3F"
45class FaultLogEntry(TypedDict): # NOTE: not identical to _0418
46 _log_idx: LogIdxT # "00" to ?"3F"
48 timestamp: str
49 fault_state: FaultState
50 fault_type: FaultType
51 domain_idx: str
52 device_class: FaultDeviceClass
53 device_id: DeviceIdT | None
55 _unknown_3: str
56 _unknown_7: str
57 _unknown_15: str
60# These are from 31DA...
61class AirQuality(TypedDict):
62 air_quality: float | None
63 air_quality_basis: NotRequired[str]
66class Co2Level(TypedDict):
67 co2_level: float | None
70class RelativeHumidity(TypedDict):
71 relative_humidity: _HexToTempT
72 temperature: NotRequired[float | None]
73 dewpoint_temp: NotRequired[float | None]
76class IndoorHumidity(TypedDict):
77 indoor_humidity: _HexToTempT
78 temperature: NotRequired[float | None]
79 dewpoint_temp: NotRequired[float | None]
82class OutdoorHumidity(TypedDict):
83 outdoor_humidity: _HexToTempT
84 temperature: NotRequired[float | None]
85 dewpoint_temp: NotRequired[float | None]
88class ExhaustTemp(TypedDict):
89 exhaust_temp: _HexToTempT
92class SupplyTemp(TypedDict):
93 supply_temp: _HexToTempT
96class IndoorTemp(TypedDict):
97 indoor_temp: _HexToTempT
100class OutdoorTemp(TypedDict):
101 outdoor_temp: _HexToTempT
104class Capabilities(TypedDict):
105 speed_capabilities: list[str] | None
108class BypassPosition(TypedDict):
109 bypass_position: float | None
112class FanInfo(TypedDict):
113 fan_info: str
114 _unknown_fan_info_flags: list[int]
117class ExhaustFanSpeed(TypedDict):
118 exhaust_fan: float | None
121class SupplyFanSpeed(TypedDict):
122 supply_fan: float | None
125class RemainingMins(TypedDict):
126 remaining_mins: int | None
129class PostHeater(TypedDict):
130 post_heater: float | None
133class PreHeater(TypedDict):
134 pre_heater: float | None
137class SupplyFlow(TypedDict):
138 supply_flow: float | None
141class ExhaustFlow(TypedDict):
142 exhaust_flow: float | None
145class _VentilationState(
146 ExhaustFanSpeed,
147 FanInfo,
148 AirQuality,
149 Co2Level,
150 ExhaustTemp,
151 SupplyTemp,
152 IndoorTemp,
153 OutdoorTemp,
154 Capabilities,
155 BypassPosition,
156 SupplyFanSpeed,
157 RemainingMins,
158 PostHeater,
159 PreHeater,
160 SupplyFlow,
161 ExhaustFlow,
162):
163 indoor_humidity: _HexToTempT
164 outdoor_humidity: _HexToTempT
165 extra: NotRequired[str | None]
168# These are payload-specific...
169class _empty(TypedDict):
170 pass
173class _0004(TypedDict):
174 name: NotRequired[str | None]
177class _0006(TypedDict):
178 change_counter: NotRequired[int | None]
181class _0008(TypedDict):
182 relay_demand: float | None
185class _000a(TypedDict):
186 zone_idx: NotRequired[str]
187 min_temp: float | None
188 max_temp: float | None
189 local_override: bool
190 openwindow_function: bool
191 multiroom_mode: bool
192 _unknown_bitmap: str
195class _0100(TypedDict):
196 language: str
197 _unknown_0: str
200class _0404(TypedDict):
201 frag_number: int
202 total_frags: int | None
203 frag_length: NotRequired[int | None]
204 fragment: NotRequired[str]
207class _0418_NULL(TypedDict): # only I_/RP with null payload
208 log_idx: NotRequired[LogIdxT] # only when I_|0418|00 with null payload
209 log_entry: None
212class _0418(TypedDict):
213 log_idx: LogIdxT
214 log_entry: tuple[str, ...] # TODO: = namedtuple("Fault", "timestamp fault_state...
217class _1060(TypedDict):
218 battery_low: bool
219 battery_level: float | None
222class _1030(TypedDict):
223 max_flow_setpoint: float
224 min_flow_setpoint: float
225 valve_run_time: int
226 pump_run_time: int
227 boolean_cc: bool
230class _1090(TypedDict):
231 temperature_0: float | None
232 temperature_1: float | None
235class _10a0(TypedDict):
236 setpoint: _HexToTempT | None
237 overrun: NotRequired[int]
238 differential: NotRequired[_HexToTempT]
241class _10d0(TypedDict):
242 days_remaining: int | None
243 days_lifetime: NotRequired[int | None]
244 percent_remaining: NotRequired[float | None]
247class _10e1(TypedDict):
248 device_id: DeviceIdT
251class _1100(TypedDict):
252 domain_id: NotRequired[str]
253 cycle_rate: int
254 min_on_time: float
255 min_off_time: float
256 _unknown_0: str
257 proportional_band_width: NotRequired[float | None]
258 _unknown_1: NotRequired[str | None]
261class _1100_IDX(TypedDict):
262 domain_id: str
265class _12a0(TypedDict):
266 hvac_idx: str
267 indoor_humidity: NotRequired[_HexToTempT | None]
268 outdoor_humidity: NotRequired[_HexToTempT | None]
269 relative_humidity: NotRequired[_HexToTempT | None]
270 temperature: NotRequired[float | None]
271 dewpoint_temp: NotRequired[float | None]
274class _12b0(TypedDict):
275 window_open: bool | None
278class _12c0(TypedDict):
279 temperature: float | None
280 units: Literal["Fahrenheit", "Celsius"]
281 _unknown_6: NotRequired[str]
284class _1f09(TypedDict):
285 remaining_seconds: float
286 _next_sync: str
289class _1f41(TypedDict):
290 mode: str
291 active: NotRequired[bool | None]
292 until: NotRequired[str | None]
295class _1fd4(TypedDict):
296 ticker: int
299@verify(EnumCheck.UNIQUE)
300class _BindPhase(StrEnum):
301 OFFER = "offer"
302 ACCEPT = "accept"
303 CONFIRM = "confirm"
306class _1fc9(TypedDict):
307 phase: str | None
308 bindings: list[list[str]]
311class _22b0(TypedDict):
312 enabled: bool
315class _22f4(TypedDict): # WIP
316 fan_mode: str | None
317 fan_rate: str | None
320class _2309(TypedDict):
321 zone_idx: NotRequired[str]
322 setpoint: float | None
325@verify(EnumCheck.UNIQUE)
326class _ZoneMode(StrEnum):
327 FOLLOW = "follow_schedule"
328 ADVANCED = "advanced_override" # until the next scheduled setpoint
329 PERMANENT = "permanent_override" # indefinitely, until auto_reset
330 COUNTDOWN = "countdown_override" # for x mins (duration, max 1,215?)
331 TEMPORARY = "temporary_override" # until a given date/time (until)
334class _2349(TypedDict):
335 mode: _ZoneMode
336 setpoint: float | None
337 duration: NotRequired[int | None]
338 until: NotRequired[str | None]
341class _2d49(TypedDict):
342 state: bool | None
345class _2e04(TypedDict):
346 system_mode: str
347 until: NotRequired[str | None]
350class _3110(TypedDict):
351 mode: str
352 demand: NotRequired[float | None]
355class _313f(TypedDict):
356 datetime: str | None
357 is_dst: bool | None
358 _unknown_0: str
361class _3220(TypedDict):
362 msg_id: int # OtDataId
363 msg_type: str # OtMsgType
364 msg_name: str
365 description: str
368class _3222(TypedDict):
369 start: int | None
370 length: int
371 data: NotRequired[str]
374class _3b00(TypedDict):
375 domain_id: NotRequired[Literal["FC"]]
376 actuator_sync: bool | None
379class _3ef0_3(TypedDict): # payload of 3 bytes
380 modulation_level: float | None
381 _flags_2: str
384class _3ef0_6(_3ef0_3): # payload of 6 bytes
385 _flags_3: list[int]
386 ch_active: bool
387 dhw_active: bool
388 cool_active: bool
389 flame_on: bool
390 _unknown_4: str
391 _unknown_5: str
394class _3ef0_9(_3ef0_6): # payload of 9 bytes
395 _flags_6: list[int]
396 ch_enabled: bool
397 ch_setpoint: int
398 max_rel_modulation: float
401class _3ef1(TypedDict):
402 modulation_level: float | None
403 actuator_countdown: int | None
404 cycle_countdown: int | None
405 _unknown_0: str
408class _JASPER(TypedDict):
409 ordinal: str
410 blob: str
413class PayDictT:
414 """Payload dict types."""
416 EMPTY: TypeAlias = _empty
418 # command codes
419 _0004: TypeAlias = _0004
420 _0006: TypeAlias = _0006
421 _0008: TypeAlias = _0008
422 _000A: TypeAlias = _000a
423 _0100: TypeAlias = _0100
424 _0404: TypeAlias = _0404
425 _0418: TypeAlias = _0418
426 _0418_NULL: TypeAlias = _0418_NULL
427 _1030: TypeAlias = _1030
428 _1060: TypeAlias = _1060
429 _1081: TypeAlias = _Setpoint
430 _1090: TypeAlias = _1090
431 _10A0: TypeAlias = _10a0
432 _10D0: TypeAlias = _10d0
433 _10E1: TypeAlias = _10e1
434 _1100: TypeAlias = _1100
435 _1100_IDX: TypeAlias = _1100_IDX
436 _1260: TypeAlias = _Temperature
437 _1280: TypeAlias = OutdoorHumidity
438 _1290: TypeAlias = OutdoorTemp
439 _1298: TypeAlias = Co2Level
440 _12A0: TypeAlias = _12a0
441 _12B0: TypeAlias = _12b0
442 _12C0: TypeAlias = _12c0
443 _12C8: TypeAlias = AirQuality
444 _12F0: TypeAlias = _FlowRate
445 _1300: TypeAlias = _Pressure
446 _1F09: TypeAlias = _1f09
447 _1F41: TypeAlias = _1f41
448 _1FC9: TypeAlias = _1fc9
449 _1FD4: TypeAlias = _1fd4
450 _22B0: TypeAlias = _22b0
451 _22F4: TypeAlias = _22f4
452 _2309: TypeAlias = _2309
453 _2349: TypeAlias = _2349
454 _22D9: TypeAlias = _Setpoint
455 _2D49: TypeAlias = _2d49
456 _2E04: TypeAlias = _2e04
457 _3110: TypeAlias = _3110
458 _313F: TypeAlias = _313f
459 _31DA: TypeAlias = _VentilationState
460 _3200: TypeAlias = _Temperature
461 _3210: TypeAlias = _Temperature
462 _3B00: TypeAlias = _3b00
463 _3EF0: TypeAlias = _3ef0_3 | _3ef0_6 | _3ef0_9
464 _3EF1: TypeAlias = _3ef1
466 _JASPER: TypeAlias = _JASPER
468 FAULT_LOG_ENTRY: TypeAlias = FaultLogEntry
469 FAULT_LOG_ENTRY_NULL: TypeAlias = FaultLogEntryNull
470 TEMPERATURE: TypeAlias = _Temperature
472 # 12A0 primitive
473 RELATIVE_HUMIDITY: TypeAlias = RelativeHumidity
475 # 31DA primitives
476 AIR_QUALITY: TypeAlias = AirQuality
477 CO2_LEVEL: TypeAlias = Co2Level
478 EXHAUST_TEMP: TypeAlias = ExhaustTemp
479 SUPPLY_TEMP: TypeAlias = SupplyTemp
480 INDOOR_HUMIDITY: TypeAlias = IndoorHumidity
481 OUTDOOR_HUMIDITY: TypeAlias = OutdoorHumidity
482 INDOOR_TEMP: TypeAlias = IndoorTemp
483 OUTDOOR_TEMP: TypeAlias = OutdoorTemp
484 CAPABILITIES: TypeAlias = Capabilities
485 BYPASS_POSITION: TypeAlias = BypassPosition
486 FAN_INFO: TypeAlias = FanInfo
487 EXHAUST_FAN_SPEED: TypeAlias = ExhaustFanSpeed
488 SUPPLY_FAN_SPEED: TypeAlias = SupplyFanSpeed
489 REMAINING_MINUTES: TypeAlias = RemainingMins
490 POST_HEATER: TypeAlias = PostHeater
491 PRE_HEATER: TypeAlias = PreHeater
492 SUPPLY_FLOW: TypeAlias = SupplyFlow
493 EXHAUST_FLOW: TypeAlias = ExhaustFlow