A self-hosted dashboard for solar, battery, and grid energy
metrd is mine end to end - the idea, the architecture, the code, the pipeline it ships through, and the plan for where it goes next. It's a live display that shows a household exactly where its power is coming from and where it's going, reading straight from solar inverters and forecasting services without ever sending a command back to them.
More people are generating their own clean energy every year. metrd exists so that generation doesn't go to waste just because it's invisible - so a full battery or a sunny afternoon actually gets used, instead of being quietly wasted while the grid takes over unnoticed.
The Idea
Most home energy monitoring is built around locking you in, not showing you your own data.
Buy a solar inverter or a battery and you usually inherit whichever app the manufacturer bundled with it - cluttered, chasing a subscription, or simply unusable the moment you mix hardware from two different brands. Very little of it asks what the person watching the dashboard actually wants: a clear, honest, live picture of the clean energy they're already generating.
metrd is built directly against that gap - self-hosted, hardware-agnostic, and focused on one job. You keep the data, you keep control of it, and it runs on hardware you already own rather than a subscription you have to keep paying for.
Designing the Display
The centrepiece of metrd is a display: a live diagram of energy flowing between solar, battery, grid, and house, built from up to four sections arranged so power visually flows between them. Only the sections a given install actually has hardware for appear - if there's no battery configured, the diagram simply doesn't show one, rather than a greyed-out placeholder pretending it exists.
A connecting line only lights up when there's real flow to show, and it runs in whichever direction power is actually moving - the same line between grid and house reverses when you go from importing to exporting. I spent real time on the failure case too: if a reading stalls or a connection drops, that section's value simply stops updating rather than dropping to zero, so a paused feed never gets misread as an actual power outage.

View Media
Talking to Real Hardware
metrd reads from SolaX inverters - locally over the network or via SolaX Cloud - covering thirteen inverter families across several hardware and firmware revisions, handled automatically so nobody has to know their exact revision to connect one. Solcast supplies solar forecasts for the hours and days ahead, rate-limited on a daily allowance that metrd tracks itself, pausing forecast polling automatically once it's used up rather than surfacing an error, and resuming again the next day without anyone touching it.
Every integration is built behind the same adapter pattern, so bringing in another inverter or battery brand is a new adapter, not new architecture - and every credential an install stores for one is encrypted at rest.
Built to Scale With Less
metrd is meant to run comfortably on something like a Raspberry Pi, not a spare server, so keeping it frugal is a design decision, not an afterthought. Reference data that rarely changes is served from an in-process cache instead of hitting the database on every request, and reading history is bucketed down over time - full resolution while it's recent, progressively compressed the further back it goes - so it stays useful without growing forever. The layered architecture keeps every database round trip confined to a repository, which makes it straightforward to see, and control, exactly where a query happens.
That target isn't just a claim - every published image is built for both amd64 and arm64, so the same release that runs on a server runs on a Pi.
A Design System, Not Just Screens
The app's UI is built on a shared component package rather than one-off screens - buttons, tables, dialogs, and a confirm-delete pattern used everywhere something destructive happens, plus page templates that cover the empty state and the filtered-list state the same way every time instead of reinventing them per page. The dashboard's management screens - displays, tariffs, reading-bucket defaults - are all built from that same small set of templates, so a new management page is mostly configuration, not new UI work.
Design tokens are generated from a single source and checked in CI, so the code and the design can't silently drift apart - if someone changes a token without regenerating it, the build catches it rather than a reviewer having to notice by eye.
Accessibility is built in rather than bolted on: landmark roles and ARIA attributes throughout, a labelled primary navigation with aria-current on the active page, and accessible labelling on interactive elements like dialogs, by default rather than as an afterthought once something already shipped.
Architecture
Three deployable pieces and a shared package, built and released independently: an ASP.NET Core API layered Service → Business → Data with a dependency-free Integration layer for third-party clients, a Next.js app that talks to it live over SignalR, and a documentation and marketing site that ships on its own. The App's API client is generated straight from the API's own controllers and SignalR hubs, so there's no separate schema to keep in sync by hand.

View Media
Shipping It Like Production Software
Every change goes through the same gate a team would enforce: the API builds in Release, checks for an Entity Framework migration that was written but never committed, then runs the full test suite with coverage. The App installs, lints, and builds. Docker builds both images and brings the whole stack up with Compose, then smoke-tests it for real - hitting the actual health and version endpoints through the app's proxy rather than just trusting the containers started.
Releases are multi-architecture: each platform builds in parallel, and the resulting digests are merged into a single manifest and pushed to GitHub Container Registry tagged by version and latest. Self-hosting it is one file - a single docker-compose.yml brings up Postgres, the API, and the App together, migrations apply automatically on first run, and every service exposes its own health check.
Documented Like It's Not Just Me
metrd has a public docs site covering both using it and building it - because when there's no second reviewer, the documentation and the tooling have to catch what a teammate normally would. A set of custom Roslyn analysers enforce naming, file structure, and member ordering at compile time, several with automatic fixes available in-editor, alongside strict TypeScript, ESLint, and Prettier on the frontend. Writing it this way from day one means it's already in the shape it would need to be to hand off or open up.
What's Next
The roadmap is a direction of travel, not a promise, but it's a deliberate one: GivEnergy support next, since the adapter pattern behind SolaX was built to generalise rather than be a one-off. Octopus Energy tariff data so cost and value show up alongside the watts, not just a separate bill to do the maths against yourself. An EV charger as another node on the display. Alerts when a device goes quiet or a battery gets stuck. A proper historical trends view, separate from the live display, for spotting patterns rather than watching the current moment. And multi-user accounts, so a display can be shared without sharing the whole account.
Where It Stands
metrd is in active alpha. The docs and product live publicly at metrd.io; the source is currently private while it's this early, but the architecture, the docs, and the pipeline are already built as if someone else is going to read them - because eventually, someone will.