Files
ems/docs/04-modules/operating-modes.md
Dusan Vojacek 8b4af663d8 Initial commit
Made-with: Cursor
2026-03-20 13:27:44 +01:00

133 lines
4.8 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.
# Modul: Operating Modes (Provozní režimy)
## Koncept
EMS a Loxone komunikují přes **provozní režimy** pojmenované stavy které mají smysl pro obě strany.
EMS rozhoduje a přepíná režimy. Loxone dostane kód režimu jako číslo přes Virtual Input a ví jak se v daném režimu chovat **autonomně a nezávisle na EMS**.
```
EMS backend (každou minutu)
→ HTTP GET /dev/sps/io/EMS_Heartbeat/1 ← pulz do Loxone
EMS backend (při přepnutí režimu)
→ ems.fn_set_mode(site_id, 'SELF_SUSTAIN') ← zapsat do DB
→ HTTP GET /dev/sps/io/EMS_Mode/2 ← informovat Loxone
Loxone (zcela nezávisle na EMS)
→ sleduje přítomnost EMS_Heartbeat pulzů
→ pokud 5min žádný pulz → sám přepne na SELF_SUSTAIN
→ řídí střídač dle aktivního režimu bez čekání na setpointy
```
**Klíčový princip:** Loxone watchdog nečte DB. Sleduje pouze HTTP pulzy přímo.
Pokud padne celý server (RPi, Docker, síť) Loxone to pozná sám a přepne bezpečný režim.
Viz `docs/loxone-integration.md` pro kompletní popis Loxone implementace.
---
## Přehled režimů
| Kód | Loxone int | EV | TČ | Baterie | Síť | Loxone autonomní |
|---|---|---|---|---|---|---|
| `AUTO` | 1 | dle plánu | dle plánu | dle plánu | dle plánu | **ne** čeká na setpointy |
| `SELF_SUSTAIN` | 2 | ❌ stop | ❌ stop | vybíjí do domu | bez exportu | **ano** |
| `CHARGE_CHEAP` | 3 | ❌ stop | ❌ stop | max nabíjení | import ok | **ne** EMS posílá výkon |
| `PRESERVE` | 4 | ❌ stop | ❌ stop | drží SoC | import ok | **ano** |
| `MANUAL` | 0 | ❌ stop | ❌ stop | žádné akce | žádné akce | **ano** |
### `AUTO`
Normální provoz. EMS posílá přesné setpointy W každých 15 minut.
Loxone je čistý exekutor přijme číslo a zapíše do střídače.
Pokud setpoint nepřijde (výpadek EMS) → Loxone watchdog přepne na `SELF_SUSTAIN`.
### `SELF_SUSTAIN` ← výchozí stav + fallback
Aktivuje se:
- automaticky watchdogem při výpadku EMS (5min bez pulzu)
- manuálně uživatelem z UI (dovolená, odchod z domu)
- při prvním startu systému (seed data)
Loxone sám bez EMS:
- FVE pokrývá spotřebu
- baterie vybíjí do domu (ne do sítě)
- blokuje export do sítě
- zastavuje EV nabíjení a TČ
### `CHARGE_CHEAP`
Manuální přepis. EMS posílá max charge setpoint.
Použít při levné ceně nebo přetoku FVE ze sousedství (pokud víš o levné ceně dopředu).
### `PRESERVE`
Dovolená / servis. Loxone drží baterii na aktuálním SoC, žádné optimalizace.
Autonomní Loxone nevyžaduje setpointy od EMS.
### `MANUAL`
Technické práce. Žádná logika neřídí střídač. Pouze pro servis.
---
## Přepínání z UI (React)
```
POST /api/sites/{site_id}/mode
{
"mode": "SELF_SUSTAIN",
"valid_until": null, // nebo "2025-03-15T06:00:00+01:00" pro dočasný přepis
"notes": "Odjezd na dovolenou"
}
```
Backend při přepnutí:
1. Zavolá `ems.fn_set_mode(site_id, mode, 'user:'+username)` → zápis do DB + log
2. Okamžitě odešle HTTP do Loxone: `/dev/sps/io/EMS_Mode/{loxone_mode_value}`
3. Pokud `CHARGE_CHEAP` nebo návrat na `AUTO` → spustí replanning
**Dočasný přepis s automatickým návratem:**
`fn_expire_modes()` běží každou minutu a přepíná zpět lokality s prosahlým `valid_until`.
---
## EMS restart / reconnect
Při startu backendu:
1. Přečíst z Loxone aktuální `EMS_Mode_Active` (Virtual Output) přes HTTP GET
2. Porovnat s `ems.site_operating_mode` v DB
3. Pokud Loxone přepnul na `SELF_SUSTAIN` během výpadku → logovat, informovat, spustit nový plán
4. Přepnout na `AUTO` a začít posílat setpointy + heartbeat pulzy
---
## Heartbeat v DB pouze informační
Tabulka `ems.site_heartbeat` zaznamenává kdy EMS naposledy úspěšně odeslal pulz do Loxone.
Slouží pro EMS dashboard (`vw_site_status.ems_heartbeat_status`) a případný alerting.
**Neplní funkci watchdogu** to je čistě na Loxone straně.
```python
# backend/services/control_exporter.py každou minutu
async def send_heartbeat(site_id: int, loxone_endpoint, db):
try:
await loxone_http.get(f"/dev/sps/io/EMS_Heartbeat/1")
await db.execute(
"SELECT ems.fn_update_heartbeat($1, 'ok', $2)",
site_id, EMS_VERSION
)
except Exception as e:
logger.error(f"Heartbeat failed for site {site_id}: {e}")
await db.execute(
"SELECT ems.fn_update_heartbeat($1, 'error', $2)",
site_id, EMS_VERSION
)
# EMS nemůže nic dělat Loxone watchdog to vyřeší sám
```
---
## Otevřené body
- [ ] Ověřit Deye Modbus registry pro přepnutí Self-Consumption / Grid-First modu (pro SELF_SUSTAIN)
- [ ] Implementace Loxone watchdog viz `docs/loxone-integration.md`
- [ ] Alert notifikace (email / push) pokud `ems_heartbeat_status = 'stale'` déle než 10 minut