---
title: "One WebSocket and a tile registry behind my home app"
description: "The home app runs on one Home Assistant WebSocket, a small backend that holds every token, and a tile registry I rearrange from the phone."
url: "https://michael.zazon.us/notes/one-websocket-and-a-tile-registry-behind-my-home-app"
published: "2026-10-24T12:00:00-04:00"
kind: "build-log"
subject: "home-automation"
tags: ["home-assistant","home-app"]
series: "Maison"
part: 2
---
Halfway through the design of the app from [A home super app for the house and the homelab](https://michael.zazon.us/notes/a-home-super-app-for-the-house-and-the-homelab), I came up with a new requirement. I wanted to be able to rearrange and reconfigure the tiles on my phone without having to change any code or start a coding session just to move a tile. I already had the "everything possible, whittle later" rule for scope, but I kept coming back to the question of how I'd get the 40th tile in there without anyone touching any code. The shape had to make it cheap to add a tile.

I compared a thin proxy and a server pre-rendered page against a third shape.. server adapters feeding a tile registry, the layout living as a document on the server. I went with the registry because it was the only one where adding a tile and rearranging the grid both stayed cheap. The backend holds all the tokens, so the phone never holds a credential. I didn't want the page to call Home Assistant directly because then the token would sit in the browser. The non-Home Assistant tiles needed a server anyway. It's a small [Fastify](https://fastify.dev/) backend serving a [Preact](https://preactjs.com/) app.

The backend keeps a single [Home Assistant WebSocket](https://developers.home-assistant.io/docs/api/websocket/) open and subscribes only to the entities the current layout needs (out of 1,555 in the house at the time). The homelab sources are polled with the same adapter contract. The phone only sends the tile id and action, and live tile updates come back over [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). House rules are baked into the code: locks can be locked from the app, but never unlocked. The water main is display-only (it already [closes itself on a leak](https://michael.zazon.us/notes/leak-to-closed-valve-in-68-ms)), and the smoke/CO alarms and boiler are untouchable.

[Diagram: Phone sends tile actions to a backend with registry and rules, connected to Home Assistant](https://michael.zazon.us/notes/one-websocket-and-a-tile-registry-behind-my-home-app)

Edit mode on the phone does what I wanted: a long press lets me drag or resize a tile, and I can pull new ones from a catalog. The registry-backed build grew from a handful of live tiles to dozens within a day. Every new kind of tile is just one extra entry in the catalog. The Infra tiles read from [VictoriaMetrics as the first metrics database on my home server](https://michael.zazon.us/notes/victoriametrics-as-the-first-metrics-database-on-my-home-server), the Sites tiles from [Ten years of site analytics in Loki](https://michael.zazon.us/notes/ten-years-of-site-analytics-in-loki), and they use the same tile contract as the Home Assistant-sourced tiles.

[Image: Infra tab with two firing alerts, server health tiles and internet throughput](https://michael.zazon.us/notes/one-websocket-and-a-tile-registry-behind-my-home-app)

[Image: Sites tab with visit count, page speed and hourly edge request chart](https://michael.zazon.us/notes/one-websocket-and-a-tile-registry-behind-my-home-app)

Part 3 is about the design side of the app.. the coded mockups I decided to keep, and a full day of releases that came from using the finished app on the phone.