Files
MeterVault/README.md
T
schmidt.florian 18dd4f720d
ci / build-test (push) Successful in 1m18s
Deploy: Proxmox VE community-scripts LXC installer (Gitea, build-from-source)
Adds deploy/ct/metervault.sh (host) + deploy/install/metervault-install.sh (in-LXC), modeled on MQTTower's community-scripts installer but adapted for MeterVault: it lives on public Gitea (not GitHub) and is a single Blazor app + TimescaleDB (not multi-mode). The host script sources the community-scripts framework, creates a Debian 12 LXC and runs the install script via pct exec. The install script sets up PostgreSQL 16 + TimescaleDB, installs the .NET SDK, builds the app from the public Gitea repo (no prebuilt tarball exists — releases ship as a container image), writes /etc/metervault/environment + a systemd unit on port 8760, and installs an 'update' command (git pull + rebuild). scripts/run-metervault-ct-install.sh is the maintainer helper. All three pass shellcheck (warning-level clean) and bash -n. README documents the one-liner.

Claude-Session: https://claude.ai/code/session_01Kib2MniVFbD95fkgLgBBnB
2026-07-17 11:18:27 +02:00

113 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MeterVault
A self-hosted, local-first **energy & utility metering platform**. MeterVault pulls meter data
from Home Assistant, Tasmota and raw MQTT on a schedule, stores every reading timestamped and
immutable, normalizes it into consumption, and turns it into cost dashboards. Energy types
(electricity, water, heating oil, gas, district heat, …) and meters are **user-defined — nothing
is hardcoded**.
Successor to a hand-maintained *Energiebilanz* spreadsheet. See [`docs/SDD.md`](docs/SDD.md) for the
full design.
## Features
- **Automatic ingestion** from MQTT/Tasmota (persistent subscriptions) and Home Assistant (REST
poll or push), plus manual entry, a REST push API, and CSV import.
- **Immutable raw readings** on a TimescaleDB hypertable; a normalized, append-only **consumption**
layer on top — reproducible, auditable.
- **Seven measurement modes** (cumulative/generation registers, burner runtime, tank/consumable,
direct delta, instant rate, virtual). Handles meter swaps, counter resets, tank dip-sticks with
calibration, and **virtual meters** defined by an expression (PV self-consumption, savings, net).
- **Tariff engine** with time-ranged price history (unit/base/feed-in), scoped global / per type /
per meter; **cost categories** decoupled from energy types; meterless manual costs.
- **Continuous aggregates** (daily/monthly/yearly, local timezone) so dashboards never scan raw.
- **Dashboard**: cost KPIs with period-over-period deltas, "what costs most", a "what cost more/
less" difference view, trends, a **PV/Solar panel** (generation, self-consumption, autarky %,
savings), an **oil/consumable panel** (tank gauge, deliveries, burner runtime, effective L/h,
forecast-to-empty) and a **per-meter detail view** (raw readings, consumption, sources, tariff
timeline, events), one-click reference-data load, CSV dry-run.
- **Per-energy-type flow pages** (Electricity, Water, …): a **Sankey diagram** of the meter chain —
a downstream meter is a *subsection* of an upstream one (main → car, pool, garden, …), arrow
thickness ∝ amount, with an auto-computed "Other/unmetered" remainder. Meters can have several
upstreams (a merge, e.g. grid + solar → house).
- **Admin UI**: full create/edit/delete for energy types, meters (with consumption recompute on
mode/baseline change, and cycle-safe upstream-meter wiring), ingest sources, tariffs, cost
categories, and MQTT/Home-Assistant connectors; a "Test connection" for Home Assistant;
effective-settings view.
- **REST API + OpenAPI/Swagger**, API-key auth, reverse-proxy trust (Authelia/Traefik).
- **JSON config export/import** for portability; Docker Compose + multi-arch image.
## Quick start (Docker)
```bash
docker compose -f deploy/docker-compose.yml up -d
# open http://localhost:8760 → Import → "Load reference data" for a populated demo
# ...or start pre-populated: METERVAULT_SEED=true docker compose -f deploy/docker-compose.yml up -d
# API docs at http://localhost:8760/swagger
```
## Quick start (Proxmox VE LXC)
A community-scriptsstyle installer builds a self-contained LXC (Debian + PostgreSQL/TimescaleDB +
the app as a systemd service). Run **on the Proxmox host**:
```bash
bash -c "$(curl -fsSL https://git.finalfactory.de/FinalFactory/MeterVault/raw/branch/master/deploy/ct/metervault.sh)"
```
It asks the standard container questions, optionally loads the demo dataset, and prints the URL
(`http://<ct-ip>:8760`) plus the generated DB password. Re-run `update` inside the container to pull
the latest source and rebuild. It builds from this public Gitea repo (there is no prebuilt tarball —
releases ship as a container image). See [`deploy/ct/metervault.sh`](deploy/ct/metervault.sh) and
[`deploy/install/metervault-install.sh`](deploy/install/metervault-install.sh).
Configuration is via environment variables (`Section__Key` double-underscore mapping), e.g.:
| Variable | Purpose |
|----------|---------|
| `ConnectionStrings__Default` | PostgreSQL/Timescale connection string |
| `MeterVault__TimeZone` | Local timezone for buckets/display (default `Europe/Berlin`) |
| `MeterVault__ApiKeys__0` | An API key accepted on the `X-Api-Key` header |
| `MeterVault__AllowAnonymousApi` | `true` to open the REST API without a key (trusted LAN only) |
| `MeterVault__ReverseProxyTrust` | `true` to honour `X-Forwarded-User` behind an auth proxy |
| `MeterVault__EnableLiveIngestion` | `false` to disable the MQTT/HA workers |
| `MeterVault__SeedReferenceData` | `true` to load the bundled demo dataset on first start (idempotent) |
The REST API is **closed by default**: with no `ApiKeys` configured and `AllowAnonymousApi` off, it
returns 401. Set at least one API key (or open it explicitly for a trusted network).
Secrets (broker/HA tokens) are **never** stored in the database — endpoint configs hold the *name*
of an environment variable, resolved at runtime.
## Pushing readings (Home Assistant)
```bash
curl -X POST http://localhost:8760/api/v1/readings \
-H "X-Api-Key: $METERVAULT_API_KEY" -H "Content-Type: application/json" \
-d '[{"meterId": 1, "time": "2026-01-01T12:00:00Z", "value": 47200}]'
```
See [`docs/wiring.md`](docs/wiring.md) for wiring up Tasmota, MQTT and Home Assistant.
## Development
```bash
dotnet build
dotnet test # integration tests spin a TimescaleDB via Testcontainers (needs Docker)
dotnet test tests/Core.Tests # fast unit tests, no Docker
dotnet run --project src/App
```
Architecture, project layout and conventions live in [`CLAUDE.md`](CLAUDE.md).
## Releasing
Edit the [`VERSION`](VERSION) file on `master`; Gitea Actions tags `vX.Y.Z` and builds/pushes a
multi-arch image to the Gitea container registry (`.gitea/workflows/`). Locally:
`pwsh deploy/build-and-push.ps1 -Registry git.finalfactory.de -Image finalfactory/metervault -Push`.
Requires a Docker-capable `act_runner`; the image build itself is self-contained.
## License
Not yet chosen (see SDD §14). Add a `LICENSE` before the first public tag.