Homelab.
The hardware that runs everything else on this site.
Two parts that act like one. A segmented network (OPNsense + UniFi, six VLANs) and a self-learning climate + energy system (Homey Pro v18, 152 devices, BigQuery behind it). The other technical projects on this site run on top of this. Documentation lives in two private repos — this page is the public version.
Six VLANs, segmented on purpose.
The network exists so the rest of the system can. Every service that runs locally — climate, audio, surveillance, automations — sits on a VLAN that matches its trust level. A misbehaving device gets blast-radiused by its segment, not by the firewall's patience.
| VLAN | Purpose |
|---|---|
| Management | Network infrastructure itself — firewall, switches, controllers. |
| Secure | High-trust devices, including the surveillance recorder. Tight egress. |
| Trusted | Personal laptops, phones, workstations. |
| IoT | Smart-home devices that should never talk to anything they don't have a reason to talk to. |
| Guest | Anyone visiting. No lateral access. |
| Management LAN (legacy) | Bootstrap-only path that exists so a misconfiguration on a VLAN never locks the network out of itself. |
The hardware behind it
| Layer | Detail |
|---|---|
| Firewall | OPNsense with ISC DHCPv4. KPN delivers WAN as PPPoE over VLAN 6 — that single config is the load-bearing piece between the house and the internet. |
| Switching | UniFi Aggregation (10Gb uplink from KPN) → PoE Pro switch (10Gb to Aggregation) → USW24 for distribution (1Gb fiber). |
| Wireless | Seven UniFi access points. Two SSIDs broadcast — one bound to the Trusted VLAN, one to the IoT VLAN — so a smart bulb never lands on the same broadcast domain as a laptop. |
| Cameras | Seven UniFi Protect cameras + one UNVR. Recording stays on the Secure VLAN; egress is firewalled at the network boundary. |
| Inter-VLAN services | mDNS reflection, UDP broadcast relay, and IGMP Proxy configured per-VLAN. Required to make AirPlay and multi-brand multiroom discovery work across segments. |
One Homey Pro, one v18 controller, 152 devices.
The climate side is a self-learning thermostat with real feedback loops, not a thermostat with an app. Lighting and presence run on the same hub through the same scripting layer.
| Layer | Detail |
|---|---|
| Controller | Custom Homey Pro v18 — seasonal ranges, cold-feet prevention, comfort-signal model. The previous controllers (v14 → v17) are kept as references so behaviour drift is debuggable. |
| Heating | Five active floor-heating zones (1e verdieping) via Fibaro Smart Implant. Three pending zones on the ground floor. Heat pump is driven by a Fibaro Q2 wall relay rather than the heat pump's own thermostat. |
| Air conditioning | Six Daikin units. The Daikin cloud API is rate-limited to 200 calls/day per account, which the controller respects — polling cadence is the budget. |
| Sensors | 25+ temperature sensors feeding a thermal model. Per-room thermal lag measured (35–55 min total) and used by the controller's lookahead. |
| Heating-rate ceiling | Max measured 1.58°C/hour (Bijkeuken). The controller respects per-room ceilings — anything faster is a sensor reporting wrong, not a comfort win. |
| Lighting | 30 flows + 24 HomeyScript scripts. Presence-aware, scene-aware, motion-aware per room. 'Adaptive' in the sense that the rules adapt to the time of day and the mode of the house, not in the sense that an LLM picks the temperature. |
The house front-runs the grid.
Dynamic Dutch energy prices change every hour and tomorrow's curve lands after 13:00. The controller plans heating, EV charging, and battery dispatch against the next 24 hours — not the current price.
| System | Role |
|---|---|
| Tibber | Dynamic energy prices (tomorrow's prices land after 13:00). The controller plans heating + EV charging against the price curve, not against the clock. |
| Enphase | Solar production + house battery. JWT-token refresh handled by the integration; the battery dispatches against the same price curve the heating reads. |
| Zaptec | EV wall-charging, driven by Tibber pricing. Charge during low-price windows by default; override by hand when needed. |
| Load shedding | energie_loadshed.js — the moment grid draw approaches the contract cap, the controller sheds the lowest-priority loads (deferred-acceptable ones first) instead of tripping the main. |
| EVs | Vehicle state-of-charge reports into the same data plane; charging syncs against the same price + load curve. |
Multi-brand audio — on one fabric.
Multi-brand audio on a segmented network is mostly a multicast problem. mDNS reflection, IGMP Querier and STP priority are the unglamorous primitives that make multiroom "just work" across VLANs.
| Brand | Detail |
|---|---|
| Primary multiroom stack | A paired set that needs PTP sync — EEE disabled at the switch port to keep the clock stable — plus a vendor API exposed on a fixed port. Does multiroom and Apple AirPlay across rooms. |
| Second multiroom brand | Configured with STP priority + IGMP Querier so multicast discovery survives the VLAN-segmented network. |
| WiFi-only pair | Deliberately kept on the same VLAN as the controller, on 5GHz, so the vendor's auto-pairing works at all. |
Homey Pro → Cloud Run → BigQuery.
The same data plane behind every interesting decision in the house. 152 devices × 5-minute cadence = a real time-series, validated on ingest and persisted long-term for analysis.
| Layer | Detail |
|---|---|
| Capture | Homey Pro polls 152 devices every 5 minutes — sensors, switches, climate units, EV chargers, the lot. |
| Validate + ingest | Cloud Run worker validates the payload, drops malformed rows, and inserts into BigQuery (home_data.measurements). |
| Analyse | BigQuery is the long-term store. Thermal-model fitting, energy-arbitrage backtests, lighting-pattern analysis — all SQL against the same table. |
| Loop back | Lessons from the offline analysis become controller-version bumps (v17 → v18). The production loop stays simple; the analysis loop stays curious. |
The lessons the network learned the hard way.
- Segment before you optimise
- Six VLANs. The IoT VLAN exists so a smart appliance with questionable firmware physically cannot pivot to a workstation. Every other 'smart home' problem is easier once that's true.
- Keep a bootstrap path
- The management LAN on the untagged native subnet stays around. Not for production — for the day a VLAN change is wrong and the firewall has to be reached without the VLAN config that's broken.
- OPNsense, single owner
- ISC DHCPv4 is on; Kea and Dnsmasq are off. One DHCP service, one source of truth. Configurations that 'mostly' work because multiple services are mostly-coordinating are how networks rot in private.
- Inter-VLAN services are explicit, not implicit
- mDNS reflection, UDP broadcast relay, IGMP Proxy. Each one written down per-VLAN, because every audio brand needs a slightly different one and forgetting one breaks the multiroom in a subtle way.
- Climate is a controller, not a chatbot
- The v18 thermostat is a deterministic model with seasonal ranges and cold-feet prevention. No LLM picks the setpoint. AI lives in the offline analytics layer that explains why a zone behaved oddly — not in the production loop.
- Energy arbitrage uses tomorrow's prices
- Tibber publishes the next day's price curve after 13:00. Heating windows + EV charging schedule against the next 24h, not the current hour. The house front-runs the grid.
- Daikin's rate limit is the polling budget
- 200 calls/day per Daikin account. The controller treats that as a hard budget, not a guideline — adapts polling cadence per unit so the cap is never hit and the API stays responsive.
- Logs are the ground truth
- Every measurement, every controller decision, every device state lands in BigQuery via the sensor_uploader pipeline. Every weird behaviour can be back-traced. The data plane is the debugger.
Half of it is craft for craft's sake — running a real network at home is a privilege and a hobby. The other half is operational: if Luminary needs a fresh checkout to deploy from, or Shop Life needs a private WhatsApp webhook to land, or Bedtime Stories needs a place to render that isn't metered — the homelab is the floor everything else stands on. Worth writing down for that reason alone.