diff --git a/src/content/docs/reference/program-format.mdx b/src/content/docs/reference/program-format.mdx index e1e58fd..d5c13bd 100644 --- a/src/content/docs/reference/program-format.mdx +++ b/src/content/docs/reference/program-format.mdx @@ -152,6 +152,40 @@ Decoded as a file record: So: "TIMED program firing at 07:15 on weekdays, doing command 0x44 with par=3 and pr2=256, gated by the condition pair 0x8d09 / 0x9b09." +## TIMED programs: absolute time vs sunrise/sunset offset + +The `hour` byte at offset 12 is **overloaded** as a one-of-three +discriminator: + +| `hour` byte | Meaning | +|-------------|---------| +| 0 – 23 | Absolute wall-clock time. `minute` is unsigned 0-59. | +| **25** | Sunrise-relative. `minute` is read as a **signed** byte. | +| **26** | Sunset-relative. `minute` is read as a **signed** byte. | + +For the sunrise/sunset forms, the signed `minute` byte is the offset +in minutes: positive = *after*, negative = *before*, zero = *at*. + +```python +from omni_pca.programs import Program, ProgramType, TimeKind + +p = Program(prog_type=int(ProgramType.TIMED), hour=26, minute=246, days=0x40) +assert p.time_kind == TimeKind.SUNSET +assert p.time_offset_minutes == -10 # 246 as sbyte == -10 +assert p.format_time() == "10 min before sunset" +``` + +The decoder hides the sbyte trick behind a `time_kind` property and a +`time_offset_minutes` view; the original `hour` / `minute` bytes are +still on the dataclass for round-trip fidelity. `format_time()` +renders a friendly label so HA entity callers get +`"30 min after sunrise"` rather than `(25, 30)`. + +Source: `frmPopUpEditTime.cs:186-217` (decode) and `:241-263` (encode) +in the decompiled PC Access form. The Owner's Manual ("±0-120 minutes") +is a UI-level constraint; the wire encoding supports the full +sbyte range (-128..127). + ## Quirk: the `EVENT` Mon/Day swap For `EVENT`-typed programs on disk only, bytes 9 and 10 are stored in the @@ -239,11 +273,6 @@ pass. So is the multi-record clausal encoding hinted at by the records for the Omni Pro II. Other models may use the 12-byte form. Locating where the panel advertises the flag (and which non-OPII models clear it) is its own follow-up. -- **TIMED time-of-day encoding.** Some TIMED programs in the live - fixture have `hour > 23` or `minute > 59`, suggesting bytes 12/13 - also encode sunrise/sunset-relative offsets (Owner's Manual: - ±0-120 minutes). The flag distinguishing absolute time from - relative offset has not been isolated. ## Python usage