Files
mrcharles 09f3276b31 feat(deploy): branch model — box tracks release, dev is WIP-integration [#779 #344]
webhook ref-guard + sha-watch sensor pinned to ?sha=release;
sensor renamed pfv_deploy_gitea_release_head; master frozen.
https://projects.knownelement.com/issues/779
2026-09-04 06:32:56 -05:00

183 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🏠 pfv-bms — the house brain
> **Datacenter-grade monitoring and access control for a private residence + server room** —
> 372 entities, ~260 sensors, and a badge-actuated door, all deployed by `git push`.
![license](https://img.shields.io/badge/license-AGPLv3-blue)
![HA](https://img.shields.io/badge/Home%20Assistant-2026.8.3-41bdf5?logo=homeassistant&logoColor=white)
![HAOS](https://img.shields.io/badge/HAOS-18.2-orange)
![deploy](https://img.shields.io/badge/deploy-git%20push%20%E2%86%92%20live-4EAA25)
![entities](https://img.shields.io/badge/entities-372-9c27b0)
Production Home Assistant configuration for the Turnsys PFV —
environmental monitoring (temperatures, power, UPS) across a seven-node
Proxmox fleet plus single-board computers, server-room badge access
control, and tiered alerting to mobile devices.
Work tracking: [Redmine](https://projects.knownelement.com)
([#344](https://projects.knownelement.com/issues/344) umbrella) ·
Docs: [VP TechOps on Discourse](https://community.turnsys.com/c/vp-techops)
---
## 🗺️ System architecture
```mermaid
flowchart LR
subgraph FIELD[📡 The field]
TS[🖥️ 7× Proxmox hosts<br/>lm-sensors + iDRAC extends]
BOARDS[🥧 SBCs<br/>pfvsvrpi · jetson · 3× subopi]
UPS[🔋 UPS on tsys1<br/>NUT server :3493]
PDU[🔌 Garage PDU<br/>SNMPv1 relay]
METER[⚡ Utility meter<br/>Smart Meter Texas]
READER[🪪 Badge readers<br/>pfvsvrpi · ultix-field]
end
subgraph HA[🏠 pfv-bms — this repo]
INGEST[📦 packages/plant_snmp.yaml<br/>SNMP pollers → raw sensors]
TEMPLATE[🧮 template sensors<br/>raw → °F/units + thresholds]
DOOR[🚪 packages/doorman.yaml<br/>scan ingest + decision engine]
ROSTER[🔒 roster sensors<br/>REST poll of private access-roster]
ENERGY[📊 utility_meter +<br/>Riemann-sum energy]
AUTO[🚨 automations.yaml<br/>tiered thermal + UPS alerts]
end
subgraph OUT[📲 Outcomes]
ALERT[📱 push alerts<br/>companion apps]
LOG[📓 logbook + history<br/>every scan, every degree]
DASH[🖥️ dashboards<br/>server-room + plant]
RELAY[⚡ doorctl → usbrelay<br/>→ door strike]
end
READER -->|webhook| DOOR
DOOR -->|whitelist| ROSTER
DOOR -->|armed + valid| RELAY
TS & BOARDS -->|SNMP| INGEST
UPS -->|NUT| INGEST
PDU -->|SNMP relay| INGEST
METER -->|REST| INGEST
INGEST --> TEMPLATE --> AUTO
INGEST --> ENERGY
AUTO --> ALERT
TEMPLATE & DOOR --> LOG & DASH
```
### 🛡️ Badge access lane (server-room door)
| Component | Role | Lives |
|-----------|------|-------|
| USB HID readers | 13.56 MHz badge readers (keyboard-emulating) | door + dev bench |
| [`KNEL/doorman`](https://git.knownelement.com/KNEL/doorman) | pure-bash listener, decode, webhook, doorctl | `pfvsvrpi` (prod), `ultix-field` (dev) |
| `packages/doorman.yaml` | scan ingest, whitelist decision, alerts, unlock dispatch | **this repo** |
| [`KNEL/access-roster`](https://git.knownelement.com/KNEL/access-roster) 🔒 | badge IDs + holders — **private**, two-human PR gate | gitea (private) |
| `doorctl` + usbrelay | socket-activated, token + source-IP ACL, EXIT-trap secured | `pfvsvrpi` |
Fail-closed end to end: HA unreachable → the door does not open.
Break-glass badges fire the relay locally (works with HA down) and
report `local_unlock` so HA never double-fires. Arm switch
(`input_boolean.doorman_unlock_enabled`) is founder-level control.
Verified end-to-end 2026-09-03: real armed scan → dispatch → relay.
---
## 🌡️ Environmental monitoring
Raw SNMP pollers (`packages/plant_snmp.yaml`) → unit-normalized
template sensors → tiered automations. Every host contributes
lm-sensors extends; iDRAC hosts add inlet/exhaust/CPU; NUT feeds UPS
electricals.
| Family | Coverage |
|--------|----------|
| 🖥️ Host silicon | CPU/drive/NVMe/PCH temps on 7 Proxmox hosts |
| 🌡️ Thermal zones | rack ambient, DIMM banks, GPU, tsys7 iDRAC inlet→exhaust ΔT |
| 🥧 Boards | pfvsvrpi, jetson, 3× subopi |
| 🔋 UPS | tsys1 battery charge/voltage, on-battery + runtime alerts |
| ⚡ Power | whole-house kWh (utility), tsys6/7 node watts + kWh integrals, garage PDU amps |
| 🏠 Rooms | temp/humidity/battery sensors (Govee, cloud-fed) |
### 🚨 Alert tiers (automations.yaml)
| Trigger | Threshold |
|---------|-----------|
| Drive / DIMM temps | > 140 °F |
| NVMe | > 150 °F |
| PCH | > 160 °F |
| GPU | > 185 °F |
| Ambient | > 104 °F |
| UPS | on-battery transitions + runtime |
| Watchdog | plant sensor freshness sweep every 30 min |
### 📊 Snapshot (2026-09-03)
372 entities · ~260 sensors · 45 temperature sensors · 21
electrical/energy sensors · 8 todo lists · 2-way alerting to companion
apps.
---
## 🔐 Security model (read this before forking)
- **No secrets in git, ever.** Everything sensitive is `!secret`
indirection into an on-box `secrets.yaml` (gitignored). Verified by
full-history scans.
- **Badge IDs are NOT in this repo.** The roster lives in the *private*
[`KNEL/access-roster`](https://git.knownelement.com/KNEL/access-roster)
repo (two-human PR gate) and is fetched live at runtime.
- **Fail-closed access control** — see the badge lane above.
- Battery room sensors and locks are cloud-fed; credentials also live
in `secrets.yaml`.
- **HomeKit is controller-only (founder ruling 2026-09-04).** HA pulls
*from* HomeKit accessories when one enters the fleet; HA entities are
NEVER exposed *to* Apple Home — no `homekit` bridge integration, no
outward QR pairing.
## 🚀 Deployment pipeline
**Branch model (2026-09-04):** `dev` = WIP integration — the pipeline
IGNORES it. `release` = what the box runs — pushing release IS the deploy.
`master` is frozen (pre-branch-model history). A PR process with AI +
human reviewers will gate dev → release (founder, upcoming).
```mermaid
flowchart LR
PUSH[📝 push to dev] --> NOOP[🚫 pipeline ignores dev]
REL[🚀 merge dev → release<br/>and push] --> HOOK[gitea webhook<br/>fast path]
REL --> SHA[sha-watch<br/>release sha · 300 s poll]
HOOK & SHA --> CHECK{changed files?}
CHECK -->|configuration.yaml,<br/>packages/**| RESTART[♻️ core restart<br/>webhook triggers need it]
CHECK -->|other YAML| RELOAD[⚡ reload only<br/>~5 min to live]
```
Gate before pushing `release` (and after any `packages/**` change on
`dev`): `ha core check` must pass on-box.
Measured end-to-end: 4 m 52 s commit → live.
## 🗺️ Repo map
| Path | What |
|------|------|
| `configuration.yaml` | entrypoint + package includes |
| `packages/doorman.yaml` | 🚪 badge scan ingest + decisions |
| `packages/plant_snmp.yaml` | 🌡️ SNMP pollers + templates |
| `automations.yaml` | 🚨 tiered alerts + watchdogs |
| `dashboards/` | Lovelace dashboards |
| `tools/` | operator tooling (websocket CLI) |
| `docs/reference-packs/` | historical YAML references — NOT loaded |
## 🔗 Related
- Badge listener + relay code: [`KNEL/doorman`](https://git.knownelement.com/KNEL/doorman)
- Wider fleet (Proxmox, DNS, monitoring): [`KNEL/PFVCluster`](https://git.knownelement.com/KNEL/PFVCluster)
- Badge roster (private): `KNEL/access-roster` 🔒
## License
Copyright © 2026 Known Element Enterprises / Charles Wyble.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version. See [LICENSE](LICENSE)
for the full text.