133 lines
4.8 KiB
Markdown
133 lines
4.8 KiB
Markdown
# 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
|