As-built auto-arming home alarm on telep-mainframe: arms when no trusted phone is on the network, escalates person/car detections to Telegram, and plays a siren on the TV. Single-process intruder-alarm.service, python3 stdlib-only. Supersedes the spec in 2026-07-17-intruder-alarm-design.
For Agents
Service:
intruder-alarm.serviceon telep-mainframe. Script:/home/levander/intruder-alarm.py(stdlib only, no pip deps). State dir:/home/levander/alarm/. Self-test:python3 /home/levander/intruder-alarm.py --selftest(31 assertions). Bot: same “Dezsi az őr” bot as frigate-notify; token read at runtime from~/nvr/frigate-notify/config.yml(never hard-coded). This service is the solegetUpdatesconsumer for the bot (frigate-notify only sends). Router access: SSH to the router via key/home/levander/.ssh/router_alarm→ LAN-only dropbear (see Prerequisite router access).
Presence detection
A device is “present” if seen by either of two independent sources (union), polled together:
- Router WiFi association table — SSH to telep-router,
iwinfo <ap> assocliston thetelep1APsphy0-ap0(5 GHz) andphy1-ap0(2.4 GHz). arp-scanon the mainframe’s LAN NICenp5s0.
Why arp-scan alone false-arms — sleeping iOS phones
A sleeping iPhone stays WiFi-associated but stops answering ARP. arp-scan alone would see everyone “leave” and arm the house overnight. The router association table still sees the sleeping phone, so the union keeps it present. This is the whole reason the router path exists.
A failed poll is skipped, never "everyone left"
If a presence scan fails (SSH down, arp-scan error), that cycle is discarded rather than interpreted as an empty network. Transient blips cannot false-arm.
Excluded infrastructure MACs
Infra devices are excluded so they never appear as enrollable phones or count as “trusted present”: mainframe, printer, router, camera (18:69:45:a9:01:25).
Camera-VLAN gotcha — telep-cc leaked an enrollable device
The camera SSID
telep-ccis APphy1-ap1. An early version queried it too, so the Tapo camera (18:69:45:a9:01:25) showed up as a new device begging to be enrolled. Fix: only query thetelep1APs (phy0-ap0,phy1-ap0) and hard-exclude the camera MAC. See Camera VLAN (telep-cc).
Prerequisite: router access
The mainframe could not reach the router at all: the router only ran Tailscale-SSH (ACL-blocked from the mainframe) with no port-22 daemon. Fix:
- Enabled a LAN-only, key-only dropbear on the router:
ucidropbear withInterface=lanandPasswordAuth off. - Added a dedicated key on the mainframe:
/home/levander/.ssh/router_alarm(public half in the router’sauthorized_keys).
Enabling dropbear changed the router's SSH host key
Standing up the new dropbear rotated the router’s SSH host key, so existing
known_hostsentries for telep-router now mismatch. Refresh known_hosts when SSHing to the router from any other client. (This new instance is also keys-only, partially closing the “dropbear password auth” security gap.)
Device naming & enrollment
New present MAC (not trusted, not ignored, not infra) → Telegram message with inline buttons Trust / Ignore; enrolled only on Trust, suppressed on Ignore. Confirm-each.
Names resolve through a fallback chain, hardened so a dig/network error can never leak into a device name:
- mDNS —
avahi-resolve(gives distinctive names likeMark-iPhone-ja). - dnsmasq reverse DNS —
dig -x <ip> @192.168.1.1. - Fallback —
eszköz-<last4-of-mac>.
State machine
- Dormant until ≥1 trusted device exists (empty trusted list = never arm, no intruder watch).
- Any trusted device present → disarmed.
- All trusted devices absent for 10 min → armed.
- Any trusted device returning → disarmed instantly.
- Arm/disarm Telegram messages name the device that triggered the transition.
- Manual override commands:
/arm,/disarm,/auto(return to automatic mode).
Intruder escalation (only while armed)
- Frigate person or car →
🚨 BETŐRŐ!Telegram message + snapshot. - Repeated 1×/day, 2×/night (night = 20:00–08:00), ~45s apart, cooldown 60s.
- All pending repeats cancel on disarm.
TV siren (always — armed or not)
- Every person/car detection plays a 2-beep siren on the LG TV, independent of armed state.
aplay -D plughw:1,3 /home/levander/alarm/siren.wav— the NVIDIA HDMI audio out is ALSA card 1, device 3.- 60s cooldown.
Commands
| Command | Effect |
|---|---|
/status | Lists devices (MAC + present marker) and armed state |
/rename <mac|name> <newname> | Rename a trusted device |
/untrust <mac|name> | Remove a trusted device |
/arm / /disarm | Manual override |
/auto | Return to automatic arming |
Persistence (/home/levander/alarm/)
| File | Contents |
|---|---|
trusted.json | enrolled devices {mac: {name, ...}} |
ignored.json | MACs to never re-prompt |
state.json | armed state / timers / telegram offset (survives restart) |
siren.wav | 2-beep siren played on the TV |
Related
- telep-mainframe — the host; Frigate NVR this alarm watches, and the same “Dezsi az őr” bot
- telep-router — WiFi association source; new LAN-only dropbear +
router_alarmkey - 2026-07-17-intruder-alarm-design — the reviewed spec this implements
- SESSION-HANDOVER
- homelab
- LOG
- TOPICS