Architecture Decisions – Zero-UI Home Automation (2025)
Purpose of This File
This document records deliberate architectural decisions made for the Zero-UI Home Automation project.
It exists to:
- Prevent regression into cloud-heavy or UI-driven designs
- Give future humans and AI systems context for why things are the way they are
- Establish non-negotiable constraints for all future code and configuration
This file answers “why,” not “how.”
Decision 001 — Local-First Is Mandatory
Decision:
All real-time automation logic must run on-prem.
Rationale:
Cloud latency, outages, API changes, and vendor lock-in break family trust faster than any bug.
Implications:
- Cloud APIs may be used only for non-critical state
- Internet loss must not prevent lighting, security, or basic automation
- Local polling is preferred over push APIs when available
Rejected Alternatives:
- Cloud-first automation platforms
- Vendor-hosted rule engines
Decision 002 — Home Assistant Is the Single Brain
Decision:
Home Assistant is the authoritative logic engine.
Rationale:
HA provides:
- Local execution
- Mature integrations
- Deterministic automation
- Strong ecosystem without mandatory cloud dependence
Implications:
- No parallel automation logic in SmartThings, Apple Home, or vendor apps
- All logic flows through HA, even if exposed elsewhere
Rejected Alternatives:
- SmartThings as primary brain
- Apple Home automations beyond trivial UI bindings
Decision 003 — Apple Home Is the Only Family UI
Decision:
Apple Home is the exclusive interface for non-technical users.
Rationale:
- Familiar
- Stable
- No training required
- Works across iPhone, iPad, Apple TV, HomePod
Implications:
- HA dashboards are operator-only
- Any feature that requires HA UI interaction is not “family-ready”
- Devices exposed to Apple Home must be calm, minimal, and curated
Rejected Alternatives:
- Wall tablets as primary UI
- Custom dashboards for family members
Decision 004 — Physical Controls Always Win
Decision:
Physical switches and sensors override automation logic.
Rationale:
Humans trust tactile feedback.
Nothing destroys confidence faster than a system that “fights back.”
Implications:
- Automations must yield to manual interaction
- No automation may disable or intercept physical controls
- Lighting logic must tolerate manual overrides gracefully
Rejected Alternatives:
- Scene-only lighting
- Software-exclusive control
Decision 005 — Hardwired Sensors Are First-Class Citizens
Decision:
Existing hardwired motion and door sensors are retained and modernized.
Rationale:
They are:
- Faster
- More reliable
- Battery-free
- Immune to RF congestion
Implications:
- Konnected + ESPHome becomes a core platform component
- Wired sensors drive occupancy and presence logic
- Wireless sensors are supplemental, not foundational
Rejected Alternatives:
- Full replacement with battery-powered sensors
Decision 006 — MQTT as the Internal Event Bus
Decision:
MQTT is used as the central message transport.
Rationale:
- Loose coupling between systems
- Scales cleanly
- Human-readable debugging
- Excellent fit for sensors, vehicles, and energy assets
Implications:
- No hidden point-to-point logic
- State changes should be publish/subscribe where possible
- AI systems may observe without interfering
Rejected Alternatives:
- REST-only integrations
- Vendor-specific messaging
Decision 007 — Cameras Are Sensors, Not Entertainment
Decision:
Cameras exist to provide situational awareness, not constant viewing.
Rationale:
- Continuous video feeds increase cognitive load
- False notifications destroy trust
- AI should filter reality before humans see it
Implications:
- PoE cameras preferred
- Local NVR required
- AI detection must suppress noise
- Silence is better than uncertainty
Rejected Alternatives:
- Cloud-only camera ecosystems
- Motion-only alerts without classification
Decision 008 — AI Reduces Noise, Not Adds Features
Decision:
AI is used strictly for filtering and classification.
Rationale:
The goal is fewer notifications, not more “smart” behavior.
Implications:
- Person > package > vehicle detection only
- No “experimental” AI-driven automations
- AI failure must default to silence
Rejected Alternatives:
- AI-generated automations
- Predictive behavior without explicit rules
Decision 009 — Energy Systems Inform, They Do Not Nag
Decision:
Energy data is contextual intelligence, not a notification source.
Rationale:
Energy systems change slowly; humans should not be interrupted.
Implications:
- Energy dashboards are operator-only
- Automations may adapt silently (load shifting)
- Alerts only for true anomalies (outages, failures)
Rejected Alternatives:
- Frequent energy alerts
- User-driven energy micromanagement
Decision 010 — Containers Over Bare Metal Services
Decision:
All core services run in Docker containers.
Rationale:
- Reproducibility
- Isolation
- Simplified recovery
- Clear dependency boundaries
Implications:
- No “snowflake” host configs
- All state persisted via volumes
- Services restart safely without human intervention
Rejected Alternatives:
- Manual systemd services
- VM sprawl
Decision 011 — Stability Over Novelty
Decision:
Stable, boring technology is preferred over cutting-edge features.
Rationale:
This is a house, not a demo lab.
Implications:
- No beta firmware in production
- Upgrades planned, not impulsive
- If it works, it stays
Rejected Alternatives:
- Feature-chasing
- Experimental integrations in core systems
Decision 012 — Failure Must Be Predictable
Decision:
Every automation must have an understood failure mode.
Rationale:
Unpredictable systems erode trust.
Implications:
- Automations fail “dark and quiet”
- No cascading dependencies
- No automation required for safety-critical behavior
Rejected Alternatives:
- Hard dependencies between unrelated systems
Decision 013 — Reverse Proxy & Subdomain Ingress
Decision:
All external access terminates at Nginx Proxy Manager (NPM) with name-based routing on the Docker network. Private services do not expose host ports.
Rationale:
Centralized TLS, clean domain model, least-privilege exposure, and simpler recovery. Avoids port collisions and accidental public exposure.
Implications:
- Router forwards 80/443 → NPM only (no 3000/port pinholes)
- Services attach to
nginx-proxy_default; NPM forwards by container name - Subdomains map to services:
teamlewis.co(portal),docs.teamlewis.co(docs),ai.teamlewis.co(Open WebUI),ha.teamlewis.co(Home Assistant),cam.teamlewis.co(NVR) - Remove host port mappings for private services (e.g., Open WebUI 8080 only)
- Let’s Encrypt issued per host; Force SSL, HTTP/2, HSTS enabled
Rejected Alternatives:
- Mixed host-port and reverse-proxy ingress
- Wild west per-service random ports
Summary Principle
The system exists to disappear.
If users think about it, something has already gone wrong.
This document is authoritative.
Any future implementation that conflicts with these decisions must be revised or rejected.