Ryan Malloy d4c4e530f6
Some checks are pending
Validate / HACS validation (push) Waiting to run
Validate / Hassfest (push) Waiting to run
program_engine: real AND/OR condition evaluator
StateEvaluator decodes AND/OR records against MockState. ProgramEngine
.use_state_evaluator() installs one bound to the engine's panel + clock
+ location. Replaces the stub that always-passes-AND-always-fails-OR.

Traditional (OP=0) decode follows clsConditionLine.Cond synthesis
(clsConditionLine.cs:17-33): disk byte 1 (= and_family) carries the
compact GetConditionalText family byte, disk bytes 3-4 (and_instance
from cond2>>8) carry the object index. Family decoding mirrors
clsText.GetConditionalText (clsText.cs:2224-2274):

  family & 0xFC == 0x00 → OTHER  (low 4 bits = MiscConditional)
  family & 0xFC == 0x04 → ZONE   (bit 0x02 = NOT_READY, else SECURE)
  family & 0xFC == 0x08 → CTRL   (bit 0x02 = ON,         else OFF)
  family & 0xFC == 0x0C → TIME   (no MockState model → False)
  family >= 0x10        → SEC    (high nibble = mode, low = area)

Structured (OP > 0) decode uses Arg1 OP Arg2 with both sides resolved
via _resolve_arg(argtype, ix, field). MockState-backed resolution:

  ZONE        → loop / current_state / arming_state / latched_state
  UNIT        → on/off byte / time_remaining / dim level
  THERMOSTAT  → temp / setpoints / modes / humidity
  AREA        → mode
  TIME_DATE   → (clock-derived) year / month / day / DoW / hour /
                minute / time-of-day-in-minutes

CondOP supported: EQ / NE / LT / GT / ODD / EVEN / MULTIPLE / IN /
NOT_IN. Unknown argtypes or fields raise _UnsupportedCondition
internally — the evaluator swallows it and returns False, keeping the
chain *guarded* rather than firing too eagerly.

LIGHT/DARK MiscConditional uses astral via the engine's PanelLocation
when set. When location is missing, returns False either way (don't
fire if we can't determine).

15 new tests covering each evaluator branch (Traditional ZONE secure/
not-ready/undefined, CTRL on/off/dimmed, SEC mode-match, OTHER NEVER/
DARK; Structured Zone.CurrentState EQ/NE, Thermostat.Temp GT/LT,
TimeDate.Hour/DOW EQ, TimeDate-without-clock) plus end-to-end engine
integration showing use_state_evaluator() gates a real WHEN+AND chain
and the OR-alternative path works against real state.

Full suite: 581 passed, 1 skipped (up from 563, 82 engine tests total).
2026-05-14 02:39:41 -06:00
..