diff --git a/packages/doorman.yaml b/packages/doorman.yaml index 2f5c5ff..b50a9f3 100644 --- a/packages/doorman.yaml +++ b/packages/doorman.yaml @@ -8,10 +8,11 @@ # mechanics, NO submodule (git_pull add-on lacks submodule support), # NO local copy: access-roster remains the single source of truth. # -# UNLOCK IS DELIBERATELY NOT WIRED. Known badges are logged and -# notified; nothing actuates. The HA->Pi relay control path is an open -# design decision (#345 sketch, GLPI #741). Fail-safe: this automation -# can never open the door. +# UNLOCK PATH (founder-approved 2026-09-03): valid badge + the +# doorman_unlock_enabled input_boolean ON -> rest_command fires the +# doorctl endpoint on pfvsvrpi (Tailscale-bound, token+source +# allowlisted, self-securing relay — KNEL/doorman README). Disarm = the +# boolean OFF; unknown/disabled badges never reach this path. # # Change control (founder ruling 2026-09-02/03): this file deploys via # the pfv-bms master pipeline (webhook fast path + sha-watch safety @@ -72,6 +73,23 @@ input_datetime: has_date: true has_time: true +input_boolean: + # Arming switch (founder-level): ON = a valid badge DISPATCHES the + # unlock to the pfvsvrpi relay. OFF = valid badges log + notify but + # the door stays shut. + doorman_unlock_enabled: + name: Doorman unlock armed + icon: mdi:lock-open-variant + +rest_command: + # Fires the doorctl endpoint on pfvsvrpi (systemd socket-activated, + # Tailscale-bound, token+source allowlisted; self-securing relay). + # URL contains the token -> secret. KNEL/doorman README documents it. + doorman_unlock: + url: !secret doorman_unlock_url + method: get + timeout: 20 + automation: - id: doorman_badge_scan alias: Doorman - badge scan ingest + decision @@ -137,8 +155,8 @@ automation: checked: roster sensors are not populated. Logged only; whitelist NOT evaluated. Check gitea connectivity / KNEL/access-roster. - # Known + enabled badge: log + quiet notification. Unlock not - # wired by design (see header). + # Known + enabled badge: log, then dispatch unlock IF armed + # (founder-level input_boolean). Disarmed = log + notice only. - conditions: "{{ is_known and is_enabled }}" sequence: - action: logbook.log @@ -146,11 +164,27 @@ automation: name: Doorman message: >- Badge {{ badge_id }} ({{ holder }}) accepted at - {{ reader }} — logged, unlock not wired (#741). - - action: notify.persistent_notification - data: - title: Doorman — badge accepted - message: "{{ holder }} scanned at {{ reader }} ({{ scanned }}). Logged. Unlock not wired (#741)." + {{ reader }}. + - if: + - condition: state + entity_id: input_boolean.doorman_unlock_enabled + state: 'on' + then: + - action: rest_command.doorman_unlock + continue_on_error: true + - action: logbook.log + data: + name: Doorman + message: "UNLOCK dispatched to the {{ reader }} relay (armed)." + - action: notify.persistent_notification + data: + title: Doorman — badge accepted, UNLOCK dispatched + message: "{{ holder }} scanned at {{ reader }} ({{ scanned }}). Door released for the hold window." + else: + - action: persistent_notification.create + data: + title: Doorman — badge accepted, unlock NOT armed + message: "{{ holder }} scanned at {{ reader }} ({{ scanned }}). Unlock is disarmed — door stayed shut." # In roster but disabled: flag it loudly (stolen/suspended # badge use is exactly what we want to know about). - conditions: "{{ is_known and not is_enabled }}"