Files
EMS/configs/ems-config.yaml
Lutz Finsterle ca0f9ed1c3 house/son: placeholder config for son's installation
All house-specific values (IPs, coordinates, Viessmann credentials, kWp)
replaced with <...> placeholders. Ready to fill in once hardware is known.
Notable differences from house/lutz template:
- installation_id left empty (disables WW boost until credentials obtained)
- base_load_w set to 400W (adjust after measuring)
- forecast lat/lon/declination/azimuth/kwp all require local values

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:19:30 +02:00

116 lines
5.3 KiB
YAML

# EMS Configuration — house/son
# Fill in all values marked with <...> before deploying.
# All thresholds and timing parameters are configurable here.
prometheus:
url: "http://<prometheus-ip>:9090"
# Metric names from the custom Viessmann exporter (same as house/lutz)
metrics:
grid_power_exchange: "pcc_transfer_power_exchange_value" # positive = import, negative = export
battery_soc: "ess_stateOfCharge_value" # 0-100%
pv_production: "photovoltaic_production_current_value" # watts
battery_power: "ess_power_value" # watts
compressor_power: "heating_compressors_0_power_value" # watts
ambient_temp: "heating_sensors_temperature_outside_value" # °C
phase_l1_power: "pcc_ac_active_power_phaseOne" # per-phase grid power L1 (W)
phase_l2_power: "pcc_ac_active_power_phaseTwo" # per-phase grid power L2 (W)
phase_l3_power: "pcc_ac_active_power_phaseThree" # per-phase grid power L3 (W)
# Shelly actuators
shelly:
sg_ready:
ip: "<shelly-sg-ready-ip>"
gen: 1 # Gen1: /relay/0?turn=on|off
wallbox_a:
ip: "<shelly-wallbox-a-ip>"
gen: 2 # Gen2: /rpc/Switch.Set
power_w: 2000 # rated power of the wallbox (W)
password: "" # set Shelly admin password if auth is enabled
wallbox_b:
ip: "<shelly-wallbox-b-ip>"
gen: 2 # Gen2: /rpc/Switch.Set
power_w: 4000 # rated power of the wallbox (W)
password: "" # set Shelly admin password if auth is enabled
# Viessmann API (write access for WW temperature)
# Leave installation_id empty to disable WW boost (EMS runs without it)
viessmann:
token_file: "/etc/ems/viessmann-token.json" # OAuth2 refresh token
client_id: "<viessmann-oauth2-client-id>"
installation_id: "" # leave empty to disable WW boost
gateway_serial: "<gateway-serial>"
device_id: "0"
# SOC thresholds — which consumers are allowed at which battery level
soc_thresholds:
block_all: 50 # below 50%: no consumers
sg_ready_only: 70 # 50-70%: only SG-Ready (heating period)
plus_wallbox_a: 90 # 70-90%: + Wallbox A
all_consumers: 90 # above 90%: all consumers
# Hysteresis settings
hysteresis:
export_on_duration: "4m" # export must persist for 4 min before switching on
import_off_duration: "6m" # import must persist for 6 min before switching off
min_runtime_wallbox: "15m"
min_runtime_sg_ready: "30m"
# Power thresholds (grid_power_exchange is positive=import, so we check for negative values)
# These are the NEGATIVE thresholds (export) that trigger consumers
thresholds:
sg_ready_export_w: -500 # export > 500W → SG-Ready
ww_export_w: -500 # export > 500W → WW boost
wallbox_a_export_w: -1800 # export > 1800W → Wallbox A (total, fallback if no phase data)
wallbox_a_phase_export_w: -1500 # per-phase export needed for single-phase Wallbox A
wallbox_b_export_w: -3800 # export > 3800W → Wallbox B
import_off_w: 200 # import > 200W → start shutdown timer
# Strategic layer (PV forecast based, daily)
strategic:
forecast_high_kwh: 25
forecast_mid_kwh: 15
ww_base_c: 48 # normal WW setpoint (°C) — adjust to your heat pump
ww_boost_high_c: 5 # +5°C on high-forecast days (>25 kWh)
ww_boost_mid_c: 3 # +3°C on medium-forecast days (>15 kWh)
ww_window_start: "12:30" # WW boost only allowed from 12:30
ww_window_end: "18:00" # ... until 18:00
schedule_on: "08:00"
schedule_off: "20:00"
# Consumer behavior — idle detection thresholds
consumers:
compressor_idle_w: 50 # heat pump compressor below this = idle (W)
wallbox_min_charge_w: 50 # wallbox below this = car not charging (W)
idle_cycles: 3 # consecutive idle cycles before early release (~6 min at 2-min poll)
# Season detection
season:
heating_start_month: 10 # October
heating_end_month: 4 # April
heating_min_ambient_c: 15 # above 15°C outdoor temp: no SG-Ready even within heating months
# PV forecast — forecast.solar (free, no API key required)
forecast:
enabled: true
lat: <latitude> # decimal degrees, e.g. 48.7839
lon: <longitude> # decimal degrees, e.g. 9.3889
declination: <tilt> # panel tilt in degrees from horizontal (0=flat, 90=vertical)
azimuth: <azimuth> # degrees from south (south=0, west=90, east=-90)
kwp: <kwp> # installed peak power in kWp, e.g. 8.5
fetch_interval: "4h" # re-fetch during the day (free tier: 12 req/day → 3 fetches)
fetch_window_start: "07:00"
fetch_window_end: "19:00"
base_load_w: 400 # steady-state house consumption (W) — measure and adjust
min_surplus_w: 1800 # min export surplus to trigger wallbox charging (W)
# EMS operational settings
ems:
poll_interval: "2m"
listen_addr: ":9099" # Prometheus metrics endpoint
log_level: "info"
state_file: "/run/ems/heartbeat" # written each cycle for state recovery
recovery_timeout: "1h" # ignore Shelly state if EMS was down longer
override_timeout: "1h" # default lockout when EMS detects external Shelly change
override_max_import_w: 800 # cancel override immediately if importing more than this (0 = disabled)