SkarHome
A self-hosted smart-home and farm-automation platform: one server that runs a house, a water pump, a solar inverter and a chicken farm — with nothing routed through a vendor's cloud.
The problem
A property that combines a house and a working farm has devices commercial smart-home apps simply don't cover: a water pump that destroys itself if it runs dry, a solar inverter that blacks out the whole house if you overload it, incubators and coop fans that need to react to temperature at 3 a.m. The off-the-shelf answer is a different vendor app per device, each one round-tripping through somebody else's cloud.
I wanted a single private app for everything, running on my own server, where a dropped internet connection is a non-event and a family member abroad can be given access to exactly four devices and nothing else.
By the numbers
What I built
- Backend — Fastify + TypeScript exposing 59 HTTP endpoints across 12 route modules, plus a WebSocket channel that streams live device state to every open browser.
- Time-series storage — PostgreSQL 16 with TimescaleDB, so years of sensor readings compress automatically and charts stay fast.
- A rules engine as a shared package — 6 trigger types (metric, state, availability, schedule, sun, manual), 5 condition types and 4 action types. The same package is imported unchanged by the server, by the Raspberry Pi hub, and by the browser.
- React PWA — 17 screens: a drag-to-arrange dashboard with 11 widget kinds, a full visual rule builder, device management, a live device map, and an ops screen showing every board's IP, MAC, Wi-Fi signal and firmware version.
- Permissions that actually mean something — Firebase handles identity only; authorization lives in my own database with users, groups, per-device view/control/manage levels, guest accounts that expire, and an audit log of every command.
- Notifications end to end — a dispatcher that resolves who can see a device, their per-event preferences and quiet hours, then delivers via self-hosted Web Push (my own VAPID keys, no Google dependency) with FCM wired for future mobile apps.
- Over-the-air firmware updates — upload a compiled .bin in the browser, and the board pulls it down over a one-time key and reflashes itself. Board-family mismatches are refused, because flashing an ESP32 image to an ESP8266 bricks it.
- Integrations both directions — outbound webhooks signed with HMAC-SHA256 and a circuit breaker for dead endpoints; inbound trigger URLs so IFTTT, Siri Shortcuts or a curl can run a scene.
- Nine ESP32/ESP8266 firmware projects sharing one C++ MQTT library that handles Wi-Fi, reconnection, last-will availability, JSON telemetry, command acknowledgement and OTA — so every node type inherits all of it for free.
The engineering decision I'm most pleased with
Rather than compete with ESPHome's enormous library of ready-made sensor components, I taught my server to speak ESPHome. A 251-line bridge subscribes to the Home Assistant-style discovery topics that stock ESPHome nodes publish and folds them into my own device model — so a board flashed with ten lines of ESPHome YAML shows up in my app's discovery list and works with every screen, rule and dashboard widget with no code on either side.
The subtle part: my app contract expects a command to be acknowledged within five seconds, and ESPHome has no acknowledgement concept at all. Instead of special-casing ESPHome throughout the codebase, the bridge synthesizes the acknowledgement by watching for the device's state echo. One small translation layer, and thousands of existing ESPHome components work against an app that knows nothing about them.
The same instinct shows up elsewhere: the OTA flash handler lives inside the shared firmware library so all nine node types inherit it; the rules engine is one npm package the server, the offline hub and the browser all import; and safety-critical logic deliberately does not live on the server at all — see the farm automation case study for why.
Offline by design
ESP nodes connect to a local Raspberry Pi broker, not to the internet. Rules tagged local run on the Pi, which keeps its own copy of the rule bundle and buffers telemetry to SQLite while the WAN is down, back-filling when it returns. The server is where you look at history and change configuration — it is not in the path of the automation that has to work at 3 a.m. during an outage.
Stack
Status, honestly
The platform is deployed and running at home.skarrnd.top, with push-to-deploy CI from GitHub Actions. The full software path is proven end to end — I validated it with a bench ESP32 and a protocol-accurate simulator: telemetry lands in TimescaleDB, offline detection fires real notifications, and commands are acknowledged.
The hardware rollout is the part still in progress. The firmware for all nine node types is written and compiles, but most boards are not yet installed in the field — so the pump, inverter and coop devices exist in code and on the bench, not yet on the wall. That work is ongoing, and the farm automation write-up covers what is being installed next.