multisite update dokumentace
This commit is contained in:
@@ -17,7 +17,7 @@ Multi-site Energy Management System: optimalizuje FVE, baterii a flexibilní zá
|
|||||||
| DB | PostgreSQL 16 + TimescaleDB |
|
| DB | PostgreSQL 16 + TimescaleDB |
|
||||||
| Migrace | Flyway (`db/migration`, `db/routines`, `db/views`) |
|
| Migrace | Flyway (`db/migration`, `db/routines`, `db/views`) |
|
||||||
| API | PostgREST (REST ze schématu `ems`) + FastAPI (logika, joby – plán v docs) |
|
| API | PostgREST (REST ze schématu `ems`) + FastAPI (logika, joby – plán v docs) |
|
||||||
| Frontend | React + TypeScript + Vite (očekáváno u kořene / Docker) |
|
| Frontend | React + TypeScript + Vite (očekáváno u kořene / Docker); výběr lokality comboboxem (`SiteSelectionContext`, `GET /api/v1/me/sites`, persist `localStorage` `ems.selected_site_id`) |
|
||||||
| Pole / zařízení | Modbus TCP (`pymodbus`), HTTP (Loxone, případně API vozidel) |
|
| Pole / zařízení | Modbus TCP (`pymodbus`), HTTP (Loxone, případně API vozidel) |
|
||||||
| Solver | PuLP + HiGHS (`HiGHS_CMD`) |
|
| Solver | PuLP + HiGHS (`HiGHS_CMD`) |
|
||||||
| Runtime | Docker Compose |
|
| Runtime | Docker Compose |
|
||||||
@@ -140,7 +140,7 @@ Specifikace z `docs/02-architecture.md`, modulových docs a komentářů v `plan
|
|||||||
| Úloha | Frekvence | Poznámka |
|
| Úloha | Frekvence | Poznámka |
|
||||||
|-------|-----------|----------|
|
|-------|-----------|----------|
|
||||||
| `telemetry_collector` | každých **60 s** | Smyčka polling Modbus (Deye, EV×2, TČ) – viz `docs/04-modules/telemetry.md` |
|
| `telemetry_collector` | každých **60 s** | Smyčka polling Modbus (Deye, EV×2, TČ) – viz `docs/04-modules/telemetry.md` |
|
||||||
| `price_importer` | **14:00** denně + **00:05** kontrola | `docs/04-modules/market-prices.md` (časy CET v dokumentaci) |
|
| `price_importer` (scheduler) | **13:30 / 14:00 / 00:05** | Jeden globální zápis do `market_interval_price` za tick (ne cyklus per site); po importu obnova predikce záporných cen pro každou aktivní site. Viz `docs/04-modules/market-prices.md` |
|
||||||
| `forecast_service` | **14:30** + **06:00** denně | `docs/04-modules/forecast.md` |
|
| `forecast_service` | **14:30** + **06:00** denně | `docs/04-modules/forecast.md` |
|
||||||
| `run_daily_plan` | **15:00** denně | `backend/services/planning_engine.py` (horizont **96 h**, váhy slotů 1,0 / 0,7 / 0,4) |
|
| `run_daily_plan` | **15:00** denně | `backend/services/planning_engine.py` (horizont **96 h**, váhy slotů 1,0 / 0,7 / 0,4) |
|
||||||
| `run_rolling_replan` | **každých 15 min** (`*/15`) | `planning_engine.py` – přepočet od aktuálního slotu |
|
| `run_rolling_replan` | **každých 15 min** (`*/15`) | `planning_engine.py` – přepočet od aktuálního slotu |
|
||||||
@@ -160,7 +160,8 @@ Specifikace z `docs/02-architecture.md`, modulových docs a komentářů v `plan
|
|||||||
|-------|-----|
|
|-------|-----|
|
||||||
| Pochopit systém end-to-end | `docs/01-overview.md`, `docs/02-architecture.md` |
|
| Pochopit systém end-to-end | `docs/01-overview.md`, `docs/02-architecture.md` |
|
||||||
| Tabulky, vazby, jednotky | `docs/03-data-model.md` |
|
| Tabulky, vazby, jednotky | `docs/03-data-model.md` |
|
||||||
| OTE ceny, marže, efektivní cena | `docs/04-modules/market-prices.md`, `db/views/R__vw_site_effective_price.sql` |
|
| OTE ceny, marže, efektivní cena | `docs/04-modules/market-prices.md`, `db/views/R__vw_site_effective_price.sql`, `backend/services/price_importer.py` |
|
||||||
|
| Multi-site UI (combobox), seznam aktivních lokalit | `GET /api/v1/me/sites` v `backend/app/main.py`, `frontend/src/context/SiteSelectionContext.tsx`, `useSiteStatus` (filtr `vw_site_status`) |
|
||||||
| FVE forecast, počasí | `docs/04-modules/forecast.md` |
|
| FVE forecast, počasí | `docs/04-modules/forecast.md` |
|
||||||
| Bazální spotřeba | `docs/04-modules/consumption.md` |
|
| Bazální spotřeba | `docs/04-modules/consumption.md` |
|
||||||
| TČ, COP, TUV | `docs/04-modules/heat-pump.md`, `db/routines/R__fn_cop_estimate.sql` |
|
| TČ, COP, TUV | `docs/04-modules/heat-pump.md`, `db/routines/R__fn_cop_estimate.sql` |
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Systém přebírá rozhodovací logiku od Loxone a stává se „mozkem" – pl
|
|||||||
- Plánování provozu baterie, EV nabíjení, TUV na základě cen a predikce
|
- Plánování provozu baterie, EV nabíjení, TUV na základě cen a predikce
|
||||||
- Export setpointů do Loxone přes HTTP Virtual Inputs
|
- Export setpointů do Loxone přes HTTP Virtual Inputs
|
||||||
- Audit skutečnosti vs plánu
|
- Audit skutečnosti vs plánu
|
||||||
- Multi-site: jeden systém, více lokalit
|
- Multi-site: jeden systém, více lokalit (sdílené raw ceny OTE; forecast a plán per `site_id`; ve webu výběr aktivní lokality comboboxem)
|
||||||
|
|
||||||
## Co systém není
|
## Co systém není
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────┐
|
||||||
│ React Frontend (Vite + TypeScript) │
|
│ React Frontend (Vite + TypeScript) │
|
||||||
│ Dashboard, plány, telemetrie, overrides │
|
│ Dashboard, plány, telemetrie; výběr site │
|
||||||
|
│ (combobox → /api/v1/me/sites + PostgREST) │
|
||||||
└─────────────┬───────────────────────────────┘
|
└─────────────┬───────────────────────────────┘
|
||||||
│ HTTP/REST
|
│ HTTP/REST
|
||||||
┌─────────────▼───────────────────────────────┐
|
┌─────────────▼───────────────────────────────┐
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
│ FastAPI (Python) │
|
│ FastAPI (Python) │
|
||||||
│ – Scheduled tasks (APScheduler) │
|
│ – Scheduled tasks (APScheduler) │
|
||||||
│ – telemetry_collector (každých 60s) │
|
│ – telemetry_collector (každých 60s) │
|
||||||
│ – price_importer (13:30, 14:00, 00:05)│
|
│ – price_importer (13:30, 14:00, 00:05) │
|
||||||
│ – forecast_service (každé 2h, minute 05)│
|
│ – forecast_service (každé 2h, minute 05)│
|
||||||
│ – planning_engine (denně 15:00) │
|
│ – planning_engine (denně 15:00) │
|
||||||
│ – control_exporter (každých 15min) │
|
│ – control_exporter (každých 15min) │
|
||||||
@@ -118,7 +119,9 @@ ems-platform/
|
|||||||
App.tsx
|
App.tsx
|
||||||
api/
|
api/
|
||||||
postgrest.ts ← PostgREST client
|
postgrest.ts ← PostgREST client
|
||||||
backend.ts ← FastAPI client
|
backend.ts ← FastAPI client (/me/sites, …)
|
||||||
|
context/
|
||||||
|
SiteSelectionContext.tsx ← výběr lokality, localStorage
|
||||||
pages/
|
pages/
|
||||||
Dashboard.tsx
|
Dashboard.tsx
|
||||||
Planning.tsx
|
Planning.tsx
|
||||||
@@ -162,7 +165,8 @@ PostgreSQL (ceny + forecast) → fn_create_planning_run() → planning_interval
|
|||||||
### Operátorské manuální akce (UI)
|
### Operátorské manuální akce (UI)
|
||||||
```
|
```
|
||||||
Browser → FastAPI:
|
Browser → FastAPI:
|
||||||
POST /api/v1/sites/{site_id}/prices/import?date=YYYY-MM-DD
|
GET /api/v1/me/sites ← seznam aktivních lokalit (UI combobox; bez auth zatím = všechny aktivní)
|
||||||
|
POST /api/v1/sites/{site_id}/prices/import?date=YYYY-MM-DD ← zapisuje globální market_interval_price; site_id jen validace URL
|
||||||
POST /api/v1/sites/{site_id}/forecast/run
|
POST /api/v1/sites/{site_id}/forecast/run
|
||||||
POST /api/v1/sites/{site_id}/plan/run?type=daily|rolling
|
POST /api/v1/sites/{site_id}/plan/run?type=daily|rolling
|
||||||
```
|
```
|
||||||
@@ -176,8 +180,8 @@ PostgreSQL (planning_interval + overrides) → control_exporter
|
|||||||
|
|
||||||
### Frontend
|
### Frontend
|
||||||
```
|
```
|
||||||
Browser → PostgREST (čtení views/tabulek)
|
Browser → PostgREST (čtení views/tabulek, filtr site_id dle výběru v UI)
|
||||||
Browser → FastAPI (triggery: replanning, override, manual export)
|
Browser → FastAPI (seznam lokalit /me/sites, triggery: replanning, import cen, …)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ CREATE TABLE asset_flexible_device (
|
|||||||
|
|
||||||
### `market_interval_price`
|
### `market_interval_price`
|
||||||
Raw spotové ceny OTE CZ. Bez vazby na lokalitu – sdílené.
|
Raw spotové ceny OTE CZ. Bez vazby na lokalitu – sdílené.
|
||||||
|
Backend stahuje OTE **jednou** za naplánovaný import (data platí pro všechny site); efektivní ceny per site jen přes `site_market_config` a view.
|
||||||
TimescaleDB hypertable.
|
TimescaleDB hypertable.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ OTE CZ publikuje denní ceny zpravidla **den předem (D-1)** okolo 13:00–14:00
|
|||||||
- Body: `data.dataLine[0].point[]` s `x` = 1…96 (15min slot), `y` = cena.
|
- Body: `data.dataLine[0].point[]` s `x` = 1…96 (15min slot), `y` = cena.
|
||||||
- Jednotka ceny se bere z `axis.y.legend` (typicky **EUR/MWh**); kód podporuje i CZK/MWh a CZK/kWh.
|
- Jednotka ceny se bere z `axis.y.legend` (typicky **EUR/MWh**); kód podporuje i CZK/MWh a CZK/kWh.
|
||||||
- Přepočet do `buy_raw_price_czk_kwh`: EUR/MWh → `× EUR_CZK / 1000`; CZK/MWh → `/ 1000`; CZK/kWh beze změny.
|
- Přepočet do `buy_raw_price_czk_kwh`: EUR/MWh → `× EUR_CZK / 1000`; CZK/MWh → `/ 1000`; CZK/kWh beze změny.
|
||||||
- Časové razítko slotu: půlnoc v **timezone lokality** (`site.timezone`) + (x−1)×15 min → UTC.
|
- Časové razítko slotu při importu: závisí na volbě dne; scheduler a globální import používají **Europe/Prague**. Volitelný parametr `site_id` v `import_ote_prices` umožní pro manuální volání bez explicitního data použít `site.timezone` místo Prahy.
|
||||||
|
|
||||||
### Legacy / alternativa
|
### Legacy / alternativa
|
||||||
|
|
||||||
@@ -38,6 +38,14 @@ OTE CZ publikuje denní ceny zpravidla **den předem (D-1)** okolo 13:00–14:00
|
|||||||
|
|
||||||
Samostatný modul (ne součást FastAPI, ale může být volán z ní jako task).
|
Samostatný modul (ne součást FastAPI, ale může být volán z ní jako task).
|
||||||
|
|
||||||
|
### Multi-site: jeden import na tick
|
||||||
|
|
||||||
|
Tabulka `ems.market_interval_price` je **globální** (jeden zdroj `OTE_CZ` pro celou instalaci). Plánovaný job v `backend/app/main.py` proto pro dnešek a zítřek v `Europe/Prague` doplňuje chybějící dny **nejednou v cyklu po každé lokalitě**, ale jedním HTTP dotazem na OTE a jedním zápisem do DB. Po úspěšném importu se pro **každou aktivní** `ems.site` znovu naplní cache predikce záporných cen (`fn_predict_negative_price_windows`).
|
||||||
|
|
||||||
|
Funkce `import_ote_prices(db, site_id=None, target_date=…)` akceptuje volitelný `site_id` jen pro odvození „dnes/zítra“, pokud není zadán `target_date`; při `site_id is None` se použije `Europe/Prague` (shodně se schedulerem).
|
||||||
|
|
||||||
|
**Manuální** `POST /api/v1/sites/{site_id}/prices/import` ponechává `site_id` v cestě kvůli kompatibilitě s UI (ověření, že lokalita existuje), ale zapisuje stejná sdílená data jako scheduler.
|
||||||
|
|
||||||
### Implementované provozní změny (2026-03)
|
### Implementované provozní změny (2026-03)
|
||||||
|
|
||||||
- Robustní HTTP fetch přes `httpx`:
|
- Robustní HTTP fetch přes `httpx`:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ Tento soubor slouží jako živý seznam věcí které je potřeba rozhodnout p
|
|||||||
|
|
||||||
## Fáze 2 (zatím neřešíme)
|
## Fáze 2 (zatím neřešíme)
|
||||||
|
|
||||||
- [ ] Více lokalit – multi-site UI a správa
|
- [ ] Více lokalit – **správa** (admin CRUD site v UI, šablony migrací pro novou lokalitu) — základ UI je: combobox aktivních lokalit (`GET /api/v1/me/sites`), PostgREST dotazy filtrované podle výběru; autorizace per user/site a RLS u PostgREST stále otevřené, viz níže.
|
||||||
- [ ] Solcast jako alternativa k Open-Meteo
|
- [ ] Solcast jako alternativa k Open-Meteo
|
||||||
- [ ] Intraday OTE ceny
|
- [ ] Intraday OTE ceny
|
||||||
- [ ] Sezónní korekce predikce spotřeby
|
- [ ] Sezónní korekce predikce spotřeby
|
||||||
@@ -44,3 +44,5 @@ Tento soubor slouží jako živý seznam věcí které je potřeba rozhodnout p
|
|||||||
## Vyřešeno
|
## Vyřešeno
|
||||||
|
|
||||||
- **PostgREST anon role:** `ems_anon`, read-only na vybrané views a tabulky (migrace `V009__postgrest_roles.sql` + repeatable `R__z_postgrest_ems_anon_grants.sql` kvůli pořadí Flyway); zápisy přes FastAPI. Compose / `.env`: `POSTGREST_ANON_ROLE=ems_anon`, PostgREST `PGRST_DB_ANON_ROLE`.
|
- **PostgREST anon role:** `ems_anon`, read-only na vybrané views a tabulky (migrace `V009__postgrest_roles.sql` + repeatable `R__z_postgrest_ems_anon_grants.sql` kvůli pořadí Flyway); zápisy přes FastAPI. Compose / `.env`: `POSTGREST_ANON_ROLE=ems_anon`, PostgREST `PGRST_DB_ANON_ROLE`.
|
||||||
|
|
||||||
|
- **Multi-site (částečně):** OTE import jednou pro celý systém do `market_interval_price`; frontend výběr lokality (`SiteSelectionContext`, persist `ems.selected_site_id`), API `GET /api/v1/me/sites` (zatím všechny aktivní site). Chybí: mapování uživatel → site, JWT/RLS u PostgREST (viz otevřená otázka výše).
|
||||||
|
|||||||
Reference in New Issue
Block a user