Initial commit: EMS — Energie Management System
Complete self-consumption optimisation system for 7 kWp PV installation: - Prometheus collector (grid power, SOC, PV, per-phase, compressor) - Pure decision engine with SOC gates, hysteresis, priority ordering - Shelly Gen1/Gen2 actuator (SHA-256 Digest auth, PM power readback) - Viessmann OAuth2 client for DHW temperature control - PV forecast integration (forecast.solar) - Wallbox mutual exclusion (VX3 4.6 kW AC output constraint) - Car-not-charging detection via Shelly PM - Compressor idle → early SG-Ready release - Per-phase grid power for single-phase wallbox decisions - Manual override detection and web UI with override buttons - Full unit test coverage for decision engine - systemd service, Makefile, complete documentation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
76
CLAUDE.md
Normal file
76
CLAUDE.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# EMS — Energie Management System
|
||||
|
||||
## Project overview
|
||||
Eigenverbrauchsoptimiertes Energie Management System für eine Heim-PV-Anlage.
|
||||
Liest Zustandsdaten aus einem bestehenden Prometheus, trifft Schaltentscheidungen
|
||||
basierend auf SOC-Schwellen und Hysterese, und steuert Shelly-Aktoren per HTTP.
|
||||
|
||||
## Architecture
|
||||
```
|
||||
Prometheus (192.168.0.23:9090) → Collector (PromQL) → Decision Engine → Actuator → Shelly HTTP
|
||||
↓
|
||||
Prometheus Exporter (:9099)
|
||||
```
|
||||
|
||||
### Layers
|
||||
- **Collector** (`internal/collector/`): Reads system state via PromQL instant queries from existing Prometheus
|
||||
- **Engine** (`internal/engine/`): Pure decision logic — SOC gates, hysteresis, priority ordering. No side effects, fully testable.
|
||||
- **Actuator** (`internal/actuator/`): Executes switching via Shelly Gen1/Gen2 HTTP APIs
|
||||
- **Metrics** (`internal/metrics/`): Exports EMS decisions as Prometheus metrics on :9099
|
||||
|
||||
### Key design decisions
|
||||
- Data reads come from Prometheus (already scraped every 2min by custom Viessmann exporter)
|
||||
- Data writes (Shelly switching, Viessmann API for WW) are done directly by the EMS
|
||||
- `pcc_transfer_power_exchange_value`: positive = grid import, negative = grid export
|
||||
- Decision engine is pure: `func Decide(state, now) → []Action` — easy to unit test
|
||||
- All thresholds configurable via YAML (`configs/ems-config.yaml`)
|
||||
|
||||
## Hardware setup
|
||||
| Component | Details |
|
||||
|---|---|
|
||||
| PV | 7 kWp, Trina VX3 4.6 hybrid inverter |
|
||||
| Battery | 8 kWh, managed autonomously by VX3 |
|
||||
| Heat pump | Viessmann Vitocal 200-S AWB-E-AC |
|
||||
| SG-Ready | Shelly 1 Gen1 @ 192.168.42.90 → heating buffer +5°C |
|
||||
| Wallbox A | 2kW, Shelly Plus 1 PM Gen2 @ 192.168.42.107 |
|
||||
| Wallbox B | 4kW, Shelly Plus 1 Gen2 @ 192.168.42.51 |
|
||||
| WW control | Viessmann API (OAuth2, refresh token) — NOT YET IMPLEMENTED |
|
||||
|
||||
## Prometheus metrics (read from existing instance)
|
||||
- `pcc_transfer_power_exchange_value` — grid power (pos=import, neg=export)
|
||||
- `ess_stateOfCharge_value` — battery SOC (0-100%)
|
||||
- `photovoltaic_production_current_value` — current PV production (W)
|
||||
- `ess_power_value` — battery charge/discharge (W)
|
||||
- `heating_compressors_0_power_value` — heat pump compressor power (W)
|
||||
- `heating_sensors_temperature_outside_value` — outdoor temp (°C)
|
||||
|
||||
## Decision logic summary
|
||||
1. SOC gates: <50% all blocked, 50-70% SG-Ready only, 70-90% +WB_A, >90% all
|
||||
2. Export threshold + hysteresis (4min on, 6min off)
|
||||
3. Priority: SG-Ready (heating only) → WB_A (2kW) → WB_B (4kW)
|
||||
4. Shutdown: reverse order, respecting min runtimes (15min WB, 30min SG-Ready)
|
||||
5. Emergency brake: SOC drops below threshold → immediate shutdown
|
||||
|
||||
## TODO / open items
|
||||
- [ ] Viessmann API OAuth2 write integration (WW-Solltemperatur)
|
||||
- [ ] PV Forecast integration (Solcast/forecast.solar) for strategic layer
|
||||
- [ ] Modbus TCP/RS485 for faster PCC data (Phase 3)
|
||||
- [ ] Grafana dashboard for EMS metrics
|
||||
- [ ] go.sum generation (`go mod tidy`)
|
||||
- [ ] Integration tests with mock Prometheus / mock Shelly endpoints
|
||||
|
||||
## Commands
|
||||
```bash
|
||||
make build # Build binary
|
||||
make test # Run unit tests
|
||||
make dry-run # Run without switching (log only)
|
||||
make run # Run with live switching
|
||||
make install # Install as systemd service
|
||||
```
|
||||
|
||||
## Code style
|
||||
- Go 1.23+, structured logging via `log/slog`
|
||||
- Idiomatic Go: no frameworks, standard library where possible
|
||||
- Engine is pure (no I/O) — all side effects in Collector and Actuator
|
||||
- Config via YAML, parsed with gopkg.in/yaml.v3
|
||||
- Prometheus metrics via prometheus/client_golang
|
||||
Reference in New Issue
Block a user