← All work

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.

Live 2026 Solo — design, backend, frontend, firmware, infra Open the app ↗ (login required)

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

11,147
lines of TypeScript
59
API endpoints
9
firmware projects
17
app screens
22
database tables
26
device types

What I built

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

TypeScript Fastify PostgreSQL + TimescaleDB Mosquitto / MQTT React 18 + Vite TanStack Query Zustand Tailwind CSS Recharts Firebase Auth Web Push (VAPID) C++ / PlatformIO ESPHome Docker Compose Caddy GitHub Actions

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.