8 Commits

Author SHA1 Message Date
0c245b0af5 Per-packet diagrams: every PacketType now has a wire-format visual
src/assets/diagrams/packet-control-empty.svg
  Covers the five empty-payload control types: NoMessage (0x00),
  ClientRequestNewSession (0x01), ClientSessionTerminated (0x05),
  ControllerSessionTerminated (0x06), ControllerCannotStartNewSession
  (0x07). Single 4-byte header diagram with the type byte highlighted,
  '(no payload)' shown as a dashed empty box, and all five type values
  enumerated below.

src/assets/diagrams/packet-controller-ack-new-session.svg
  Type 0x02. 11 bytes total — 4-byte header + 2-byte protocol version
  (0x00 0x01) + 5-byte SessionID nonce. SessionID cells in accent
  colour because they're what feed quirk #1's session key XOR mix.
  Bottom annotation explains the proto-version is hard-coded.

src/assets/diagrams/packet-secure-session.svg
  Types 0x03 and 0x04 share the same shape both directions. Two-row
  layout: top shows the plaintext (5-byte SessionID echo + 11 zero-pad
  cells with 'zero pad to 16 bytes'); bottom shows the wire form
  (header + 16-byte AES ciphertext block). Highlights the symmetric
  client-up/controller-down design.

src/assets/diagrams/packet-omnilink-message.svg
  Covers all four conversation packet types in one diagram: 0x10
  (v1 encrypted), 0x11 (v1 plaintext), 0x20 (v2 encrypted), 0x21 (v2
  plaintext). Top row shows the encrypted variant with N x 16-byte
  ciphertext blocks; brace down to bottom row showing the inner
  Message format (start byte + length + opcode + data + CRC u16 LE).
  Same diagram serves all 4 since the layout is identical except
  for the type byte and whether AES is applied.

src/content/docs/reference/protocol.mdx
  Added five new sections so every PacketType is now documented:
  - NoMessage (0x00) folded into the ClientRequestNewSession heading
    (same empty-payload layout)
  - ClientSessionTerminated (0x05) / ControllerSessionTerminated (0x06)
    / ControllerCannotStartNewSession (0x07) get a combined section
    with a one-paragraph explanation of when each fires
  - OmniLinkMessage (0x10), OmniLinkUnencryptedMessage (0x11),
    OmniLink2Message (0x20), OmniLink2UnencryptedMessage (0x21)
    consolidated into one section with the diagram + a note about
    which TCP/PC-Access actually uses

  ClientRequestSecureSession + ControllerAckSecureSession merged into
  one section since they share the diagram; original prose preserved
  as #### subsections beneath.

Build: 23 pages clean. Protocol page now 118 KB (was 92 KB) — six
inline SVG titles confirmed via grep on the rendered HTML. Every
packet type defined in omni_pca.opcodes.PacketType (12 values) is
now visualized in the docs.
2026-05-10 17:44:27 -06:00
d5d2ea3d32 Diagrams: five hand-crafted SVGs explaining the protocol + architecture
The auto-extracted manual SVGs were unusable PDF text-glyph soup. These
are fresh, theme-aware (currentColor everywhere, accent via the
--sl-color-accent CSS var), and built to teach.

src/assets/diagrams/handshake-sequence.svg
  Sequence diagram with CLIENT and CONTROLLER swim lanes, five steps:
  ClientRequestNewSession -> ControllerAckNewSession (carries SessionID)
  -> derive SessionKey (inline note) -> ClientRequestSecureSession
  (encrypted, accent-coloured) -> ControllerAckSecureSession (encrypted)
  -> first OmniLink2Message. Plaintext arrows in currentColor, encrypted
  arrows in accent.

src/assets/diagrams/packet-structure.svg
  Bytes-on-the-wire box diagram: outer Packet header (seq u16 + type +
  reserved + encrypted payload) decomposed below into the inner Message
  (start byte 0x21, length, opcode, data, CRC u16 LE). Plain vs encrypted
  fields colour-coded with a legend.

src/assets/diagrams/session-key-derivation.svg
  Quirk #1 visual. Three rows of byte cells: ControllerKey (16 bytes,
  with bytes 0..10 in plain colour and 11..15 highlighted), SessionID
  (5 bytes), and the resulting SessionKey with the XOR boundary
  visible. XOR operator in the accent colour to draw the eye.

src/assets/diagrams/per-block-whitening.svg
  Quirk #2 visual. seq pill at the top, three blocks below (block 1,
  block 2, block N) each showing 16 byte cells with the first two
  highlighted in accent and labelled with the seq XOR mask. Drives home
  that it's the SAME mask on EVERY block.

src/assets/diagrams/architecture.svg
  Three groups (LIBRARY, HA INTEGRATION, TEST SURFACE) with boxes
  inside. Library shows the four protocol-layer modules + connection +
  client + models + events. HA shows coordinator + 8 platforms. Test
  surface shows MockPanel (accent-coloured), HA test harness, e2e tests,
  unit tests. One accent-coloured arrow runs from OmniConnection across
  to MockPanel labelled 'TCP/4369 (encrypted)'.

src/assets/diagrams/pca-file-format.svg
  Key chain: hardcoded keyPC01 -> decrypts PCA01.CFG (boxes for the
  CFG fields including the highlighted pca_key) -> arrow showing the
  extracted pca_key -> decrypts the .pca file (boxes for PCA03 magic,
  account info, model byte, body, and the highlighted ControllerKey)
  -> caption 'feeds session-key derivation (quirk #1)'.

Wired in via inline-SVG-via-?raw-import + set:html (so currentColor
adapts to the theme). Required converting four pages to .mdx:
  reference/protocol.mdx        + handshake + packet diagrams
  reference/file-format.mdx     + pca-file-format diagram
  explanation/quirks.mdx        + session-key + whitening diagrams
  explanation/architecture.mdx  + architecture diagram

Two MDX paper cuts during conversion: bare '<100ms' and '<50ms' in
architecture.mdx confused the JSX parser; backticked them as .

Build: 23 pages clean. Verified inline SVG ships in the rendered HTML
(grep for SVG title IDs returns 2/2 hits per relevant page). Container
rebuilt + redeployed. Protocol page is now 92750 bytes (was ~63000),
quirks page 84156 (was ~63000).
2026-05-10 17:32:49 -06:00
d7ee0a3e98 How-to: install-in-home-assistant — full setup + reauth + troubleshooting
src/content/docs/how-to/install-in-home-assistant.md (~900 w)
  Sidebar order 0 so it appears first in the How-to section. Covers:
  - Prereqs: HA 2026.1+, panel reachable, ControllerKey
  - Backup-first nudge before adding any custom component
  - HACS install path (custom repo until upstream publish)
  - Manual git+cp path that works on every HA install type
  - The 'untested custom integration' WARNING is expected
  - Add-via-UI walkthrough with screenshots of integration page +
    device page
  - Customise: entity rename, areas, dashboards, logbook
  - Common errors table (4 toast messages and their fixes)
  - 'Loads but no entities' deep-dive (3 ordered causes)
  - Reauth flow when ControllerKey rotates
  - Cross-links to the other how-tos and entity/service references
  - Known gaps: HACS not published yet, omni-pca not on PyPI yet,
    live panel validation pending

23 pages now (was 22). Sidebar autogenerates so it appears at the top
of How-to without further config.
2026-05-10 17:25:46 -06:00
4812b56622 Tutorials + how-tos: nine new pages populating the empty Diataxis lanes
src/content/docs/tutorials/  (3 pages, learning-oriented)
  decrypt-your-pca.md (~600 w)
    Walks the user through installing the CLI and running decode-pca
    against a real .pca file, ending with --include-pii to confirm the
    decryption landed on real plaintext (their own customer name).
    Cites the file format reference for what's actually happening.

  dev-stack.md (~700 w)
    Boots the docker dev stack, onboards HA in 60 seconds, adds the
    integration with the documented host/port/key, then five concrete
    things to try (toggle a light, arm an area with right and wrong
    code, trigger a button, watch developer states). Includes the
    panel-device screenshot.

  first-script.md (~750 w)
    Twenty-line Python script: connect, get system info, walk zones,
    then evolves through three more steps to add an event-stream
    consumer and a command dispatch. Shows ASCII output so the user
    knows what to expect on success. Cross-links the two protocol
    quirks pages.

src/content/docs/how-to/  (6 pages, task-oriented recipes)
  find-controller-key.md (~400 w)
    Four ways: from .pca file, PC Access UI, panel keypad, generate
    a new one. Plus a smoke-test command to verify the key works.

  automate-on-alarm.md (~600 w)
    HA event automation pattern keyed off the omni_pca event entity's
    event_type / event_data attributes. Includes an alarm-type-specific
    filter table and a fire-alarm worked example.

  bypass-zone.md (~400 w)
    Three flavours: HA service call, HA per-zone switch entity, raw
    Python. Includes verification snippets and caveats around
    installer-disabled bypass and code requirements.

  send-panel-message.md (~350 w)
    show_message / clear_message services with a 'laundry done'
    automation example. Notes that Omni messages are pre-programmed in
    PC Access, not free-form.

  decode-a-packet.md (~750 w)
    Step-by-step: take a hex dump, decode the outer Packet, derive the
    session key from the ack, decrypt with per-block whitening,
    decode the inner Message, dispatch on opcode. Includes tcpdump
    capture commands at the end.

  migrate-from-jomnilinkii.md (~700 w)
    What changes when swapping from jomnilinkII / pyomnilink to
    omni-pca. Method-name translation table, async-vs-sync surface,
    pattern-matching event handler example, what's gained (quirks,
    types, mock) and what's lost (years of production hardening).

Build: 22 pages clean (was 13), sitemap regenerated, Pagefind index
covers everything. Container rebuilt + recreated; verified
/how-to/automate-on-alarm/ returns HTTP 200 with the right title.
Sidebar autogenerates from the directories so all nine pages appear
without further config.
2026-05-10 17:23:02 -06:00
4ec43b269f Images: wordmark hero + four HA screenshots scattered through pages
src/assets/manual/omnipro-ii-wordmark.png
  Lifted from the Owner's Manual cover (Owner_s_Manual_page_1_img_1).
  1280x592, 13KB, 8-bit grayscale. Used as the eager-loaded hero on
  index.mdx via Astro's Image component, with CSS filter:invert(1) so
  the black-on-white wordmark renders crisp on the dark theme.

src/assets/screenshots/  (six PNGs, copied from omni-pca/dev/artifacts):
  01-overview.png            HA Lovelace
  02-integrations-list.png   HAI/Leviton tile in the integrations list
  03-omni-pca-config.png     '1 device, 38 entities' integration page
  04-panel-device.png        Omni Pro II device page with all controls
  05-entities-omni.png       config-entry filtered entity table
  06-developer-states.png    alarm_control_panel.omni_pro_ii_main raw
                             attributes from Developer Tools

Wired into pages:

  index.mdx                       wordmark hero (eager load)
  start/quickstart.md             04-panel-device.png at the bottom of
                                  step 3 so the reader sees the payoff
  reference/ha-entities.md        new 'What it looks like in HA' section
                                  with four screenshots (integrations
                                  list, integration detail, device page,
                                  developer states)

Astro Image processed all screenshots into webp at request size:
  06-developer-states 188 KB -> 91 KB after VP8 encoding.

Build: 13 pages clean in 1.66s, sitemap and Pagefind index regenerated.
Container rebuilt + recreated; verified HTTP 200 with 33315-byte index
page and the /reference/ha-entities/ page references four /_astro/*.webp
URLs that all return 200 from the running container.
2026-05-10 17:15:07 -06:00
0e6f75d2f7 Domain: hai-omni-pro-ii.l.warehack.ing (local subdomain pattern)
The .l.warehack.ing subdomain is the convention for the user's local
services. DNS for hai-omni-pro-ii.l.warehack.ing already resolves to
the host; caddy-docker-proxy picks up the new caddy label and routes
appropriately.

Patched .env, .env.example, docker-compose.yml, README.md,
astro.config.mjs.

Container rebuilt and restarted; verified caddy-docker-proxy is
serving 200 OK with 33051 bytes of rendered HTML on the internal
network, and the host-level Caddy issues a 308 redirect to https://
on the new hostname.
2026-05-10 17:06:35 -06:00
9dbe563aed Content + docker pin: 13-page Starlight site live behind Caddy
src/content/docs/ — twelve pages totalling ~18,800 words, ported from
the omni-pca repo's docs and reference material:

  index.mdx (377 w)               landing page with three CardGrid links
  start/quickstart.md (572 w)     three flows: decode .pca / talk to
                                  panel / install in HA

  reference/protocol.md (2525 w)  byte-level Omni-Link II spec, full
                                  packet+message layouts, the two
                                  non-public quirks, opcode tables
  reference/file-format.md (1593 w)  XOR-LCG cipher, key derivation,
                                  PCA01.CFG schema, .pca PCA03 header
  reference/library-api.md (1170 w)  module-by-module Python API summary
  reference/ha-entities.md (1070 w)  per-platform entity catalogue
  reference/ha-services.md (567 w)   seven services + automation YAML

  explanation/quirks.md (1448 w)  the headline RE essay — session-key
                                  XOR mix + per-block whitening, why
                                  no public client documents them
  explanation/architecture.md (1123 w)  library + HA + mock + tests
  explanation/pc-access-bug.md (1131 w)  LargeVocabulary off-by-N

  journey.md (6194 w)             chronological retrospective ported
                                  from omni-pca/docs/JOURNEY.md
  changelog.md (1213 w)           full 2026.5.10 release notes

Dockerfile — pinned node:lts-alpine and caddy:latest (registry-1
.docker.io was returning 'tls: internal error' on node:25-alpine and
caddy:2-alpine pulls; the pinned tags are cached locally and work).
TODO comment notes to bump back to node:25 once registry stabilises.

.gitignore — added .env / .env.local just in case.

Build: 13 pages built clean in 1.83s, sitemap + Pagefind search index
emitted. Container runs at hai-omni-docs-docs (caddy network), accepts
requests with Host: hai-omni-pro-ii.warehack.ing, returns rendered
Starlight HTML with title/description meta intact. Once DNS for
hai-omni-pro-ii.warehack.ing points at the host, the site is live.
2026-05-10 17:05:25 -06:00
c5e72c679b Initial scaffold
Astro 6 + Starlight 0.39 documentation site for omni-pca, organised
around the Diatáxis framework (Tutorials / How-to / Reference /
Explanation), plus a chronological Journey page and Changelog.

Theme: muted slate-blue with amber accents. astro-icon + lucide
preinstalled. Astro telemetry and Starlight devToolbar both off.

Deployment: multi-stage Dockerfile (node:25-alpine builder ->
caddy:2-alpine runtime), inner Caddy serves static dist on :80,
outer caddy-docker-proxy on the host terminates TLS for
hai-omni-pro-ii.warehack.ing.
2026-05-10 16:42:12 -06:00