- TypeScript 77.6%
- CSS 17%
- Dockerfile 3.2%
- JavaScript 1.8%
- HTML 0.4%
Enables the Redis-backed cache (added in
|
||
|---|---|---|
| .forgejo/workflows | ||
| .github | ||
| .husky | ||
| backend | ||
| frontend | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc | ||
| docker-compose.yml | ||
| Dockerfile | ||
| lint-staged.config.mjs | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
PV Monitor
A self-hosted photovoltaic (solar) monitoring dashboard that reads live and historical data from Home Assistant and displays it in a React web UI.
Features
- Live power chart – PV generation, grid import/export, and battery charge/discharge over the last 24 hours
- Yield cards – today, this month, this year, and all-time totals
- Daily & monthly bar charts – production history with optional autarky overlay
- Battery status – state of charge, current power, and charge/discharge totals for today
- EV card – state of charge, charging power, odometer, energy charged, and solar share percentage
- Earnings – estimated revenue from feed-in and savings from self-consumption
- Auto-refresh every 30 seconds with a manual refresh button
All sections are optional — if the corresponding environment variables are not set, that section is silently disabled.
Architecture
Browser ←→ React + Vite SPA (port 3000 in prod)
↕
Express API server ←→ Home Assistant REST / WebSocket API
The Express server proxies requests to Home Assistant so that the HA token is never exposed to the browser. In development, Vite's dev server proxies /api/* to the Express server.
Quick Start (Docker)
- Copy
.env.exampleto.envand fill in your values (see Configuration below). - Run:
docker compose up -d - Open
http://localhost:3000.
Development
This is a pnpm workspace containing the backend and frontend packages, with a single lockfile at the repo root.
pnpm install
# terminal 1 - backend (API on :3000)
pnpm --filter backend dev
# terminal 2 - frontend (dev server on :5173, proxies /api to :3000)
pnpm --filter frontend dev
The Vite dev server runs on http://localhost:5173 and proxies /api/* to http://localhost:3000.
Git hooks
pnpm install sets up a pre-commit hook (via husky + lint-staged) that lints and formats staged backend/frontend files automatically.
Other scripts
Run with pnpm --filter backend <script> / pnpm --filter frontend <script>, or cd into the package first:
| Script | Description |
|---|---|
build |
Build for production |
typecheck |
Run tsc --noEmit |
lint |
Run ESLint |
format |
Format with Prettier |
backend's production build compiles to backend/dist/index.js (pnpm --filter backend start runs it); frontend's production build outputs to frontend/dist/, served as static files by the backend.
API
| Method | Path | Description |
|---|---|---|
GET |
/api/health |
Health check ({"status":"ok"}) |
GET |
/api/version |
Git commit hash baked in at build time ({"version":"<hash>"}, "unknown" outside Docker) |
GET |
/api/dashboard |
Current dashboard snapshot |
GET |
/api/charts/daily |
Daily production history |
GET |
/api/charts/monthly |
Monthly production history |
GET |
/api/charts/power |
Live power chart data |
Configuration
Set environment variables (e.g. in a .env file for docker compose, or in .env.local for pnpm --filter backend dev).
Required
| Variable | Description |
|---|---|
HA_URL |
Base URL of your Home Assistant instance, e.g. http://homeassistant.local:8123 |
HA_TOKEN |
Long-lived access token from your HA user profile |
Optional — Pricing
| Variable | Description |
|---|---|
FEED_IN_TARIFF |
Feed-in tariff in €/kWh (used to calculate feed-in earnings) |
GRID_PRICE |
Grid electricity price in €/kWh (used to calculate self-consumption savings) |
Optional — Sign Inversion
Some inverters/meters report power with the opposite sign convention. Set these to true to invert.
| Variable | Default | Description |
|---|---|---|
INVERT_GRID |
false |
Invert grid power sign |
INVERT_BATT |
false |
Invert battery power sign |
Optional — Entity IDs
All entity IDs support a comma-separated list of IDs whose values are summed (useful for multi-inverter setups).
| Variable | Description |
|---|---|
ENTITY_PV_POWER |
Real-time PV generation power (W) |
ENTITY_PV_TODAY |
Energy generated today (kWh) |
ENTITY_PV_MONTH |
Energy generated this month (kWh) |
ENTITY_PV_YEAR |
Energy generated this year (kWh) |
ENTITY_PV_ALLTIME |
Total energy generated all time (kWh) |
ENTITY_GRID |
Grid power — positive = export/feed-in, negative = import (W) |
ENTITY_BATT_SOC |
Battery state of charge (%) |
ENTITY_BATT_POWER |
Battery power — positive = charging, negative = discharging (W) |
ENTITY_BATT_CHARGE_TODAY |
Energy charged to battery today (kWh) |
ENTITY_BATT_DISCHARGE_TODAY |
Energy discharged from battery today (kWh) |
ENTITY_FEED_IN_TODAY |
Energy fed into the grid today (kWh) |
ENTITY_FEED_IN_TOTAL |
Total energy fed into the grid (kWh) |
ENTITY_GRID_IMPORT_TODAY |
Energy imported from grid today (kWh) |
ENTITY_EV_SOC |
EV state of charge (%) |
ENTITY_EV_POWER |
EV charging power (W) |
ENTITY_EV_ODOMETER |
EV odometer |
ENTITY_EV_CHARGED |
Total energy charged to EV (kWh) |
ENTITY_EV_CHARGING |
Binary sensor — EV currently charging |
ENTITY_EV_CONNECTED |
Binary sensor — EV connected to charger |
Tech Stack
- Frontend (
frontend/): React 18, TypeScript, Vite, Recharts - Backend (
backend/): Node.js, Express, TypeScript - Deployment: Docker (multi-stage build), Docker Compose
Project Structure
frontend/ React + Vite SPA (src/, index.html, vite.config.ts)
backend/ Express API server (index.ts, haApi.ts — Home Assistant client)
Dockerfile Multi-stage build: git hash, frontend build, backend build, runtime