Build1 distinct publisher3 min readUpdated
A homelab operator wired UniFi WAN failover and UPS battery state into Kubernetes as declarative state keys, so optional workloads scale themselves to zero while the condition holds.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Robbe Verhelst has published UniFi Reactor, a Kubernetes operator that polls the UniFi Network API, normalizes what it sees into state keys, and reconciles Automation custom resources against those keys [1]. The gear already held the facts that matter during an outage; what was missing was a representation the scheduler could act on [2].
The failure mode he describes is specific enough to repeat. His UniFi equipment knew when the WAN failed over and when the UPS switched to battery, and Kubernetes did not [2], so a primary WAN failure at 3 AM left qBittorrent seeding over a metered backup link [3], and a power cut left the UPS counting down its remaining runtime while the cluster carried on with background ML jobs and backups [4].
The keys are deliberately coarse: wan primary or backup; internet ok, degraded or down; ups online or on-battery; ups.battery normal, low or critical; devices all-online or degraded; and per-device online or offline [5]. Six families, total [6]. An Automation matches on a provider plus a state map, applies its actions while the match holds, and applies onExit actions when it stops holding [7]. The first rule he actually deployed scales the immich-machine-learning Deployment to zero when ups reads on-battery and back to one replica when mains power returns [8]. He calls it boring in the right way, on the grounds that nobody minds if photo indexing pauses during a power cut [9].
The design choice that carries the weight is state over events: polling is the source of truth, and webhooks may become a fast path later but should not be the mechanism of record [10]. His reasoning is that one-shot events are easy to miss, because controllers restart, networks flap and webhooks fail, and an edge-triggered system can end up stranded in the wrong mode [11]. That is the transferable part. An alert says a condition occurred; a state key says a condition currently holds, and "currently holds" is the only thing a reconciler can act on. Verhelst is explicit that monitoring tells you about state while Reactor changes cluster behaviour while that state holds [12], and that for notification-only cases Prometheus is probably still the better tool [13]. He already runs Prometheus, Grafana and Gatus [14].
The honest limits are in the post. The flagship case, pausing downloads while on backup WAN, exists as a YAML example that stops qBittorrent and restores it when the primary link returns [15], but he frames it as what he wants once failover is verified end to end [16]. The follow-ons he lists, suspending offsite backup CronJobs on metered WAN, scaling down Jellyfin remote streaming, disabling guest WiFi during failover, and notifying when the primary link is up but the internet is still down, are not all implemented [17]. The API group is v1alpha1 [18]. And the restore path carries a literal replicas: 1 rather than the pre-outage count [19], which is fine for a single-replica Deployment and wrong the moment an autoscaler owns that field.
Worth watching: whether onExit learns to capture prior state instead of asserting a constant; whether the low and critical battery tiers get distinct policies rather than one binary shed [5]; and what the poll interval and any flap hold-off are, since the post does not state them [20].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
UniFi Reactor is a Kubernetes operator, built by Robbe Verhelst, that polls the UniFi Network API, normalizes what it sees into state keys, and reconciles Kubernetes Automation resources against those keys. Docs at reactor.robbeverhelst.com.
The author's UniFi gear knew when the WAN failed over and when the UPS switched to battery; Kubernetes did not. He writes that the network already had the state and the cluster just needed to react to it.
If the main WAN failed at 3 AM, qBittorrent could keep seeding over a metered backup link.
If power dropped, the UPS could be counting down its remaining runtime while the cluster continued background ML jobs, backups and other work that did not need to happen during an outage. The author added a UPS and backup internet to the homelab a few weeks before writing.
Example state keys: wan (primary or backup); internet (ok, degraded, down); ups (online or on-battery); ups.battery (normal, low, critical); devices (all-online or degraded); device.<name> (online or offline).
An Automation resource specifies a when block containing a provider (unifi) and a state map, a list of actions applied while conditions hold, and an onExit list applied when they no longer hold.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Self-reported build log with readable artifacts, no independent verification
Everything rests on one first-person post by the project's author. The descriptive core is well evidenced because it is self-demonstrating: the state-key vocabulary, the v1alpha1 Automation schema and two complete manifests are printed in the text. But there is no third-party replication, no benchmark, no telemetry, no repository or issue-tracker corroboration, and no operational data on how the operator behaves during a real outage. Notably absent details (poll interval, debounce) further cap what can be verified.
One automation live in the author's own homelab
Adoption is a single cluster operated by the author, with exactly one automation reported as deployed. The headline metered-WAN use case is aspirational pending end-to-end failover verification, and several further automations are stated as unimplemented. No other users, installs, stars, downloads, or deployments are disclosed anywhere in the supplied material.
Mildly overstated readiness, substantially self-hedged
The framing ('flagship use case', a clean architecture diagram, a general-purpose operator narrative) runs slightly ahead of a v1alpha1 project with one live automation and undisclosed flap handling, which is the source of the positive gap. It stays small because the author supplies his own corrections: he cedes notification-only cases to Prometheus, says the WAN automation awaits verified failover, and states plainly that some roadmap items are unimplemented.
Author promoting his own project and docs, no commercial stake disclosed
The post is written by the creator of the software it describes and links his own documentation domain, which is a clear promotional incentive around a personal project. It is moderated by the absence of any disclosed commercial model, pricing, sponsorship, or vendor relationship, and by the author volunteering limitations rather than concealing them.
High confidence on design description, low on efficacy and generality
Confidence is split. What the software declares - keys, schema, example manifests, stated design rationale - can be read straight off the page and is unlikely to be wrong. What the story implies - that this pattern works reliably under real failover and generalizes past one homelab - has one uncorroborated data point behind it, with timing and safety mechanics undocumented, so the aggregate lands just below the midpoint.
build
One alert, two causes, four green dashboards: the day the stack agreed and was wrong1 distinct publisher
build
Deleting kube-proxy moves your service traffic where your SIEM cannot follow it1 distinct publisher
build
Five pods green, GPU at 99 percent, queue up 70x: the Kubernetes dashboard is the wrong instrument1 distinct publisher
build
A Prometheus that had written nothing for hours passed every health check1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 16, 2026