27 KiB
CLAUDE.md – EMS Platform (Cursor Agent)
Čti před každou implementační změnou. Stručná orientace; detail v docs/ a SQL v db/.
1. Co to je
Multi-site Energy Management System: optimalizuje FVE, baterii a flexibilní zátěž (EV, TČ) podle spotových cen OTE CZ a předpovědí; výstupy řídí zařízení (Modbus) a informuje Loxone jako exekutora. Referenční lokalita v seedu: home-01 (Deye, baterie, 2× EV Teltonika, Samsung TČ).
2. Technologický stack
| Vrstva | Technologie |
|---|---|
| DB | PostgreSQL 16 + TimescaleDB |
| Migrace | Flyway (db/migration, db/routines, db/views) |
| 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); 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) |
| Solver | PuLP + HiGHS (HiGHS_CMD) |
| Runtime | Docker Compose |
| Živá DB přes MCP (Cursor) | Server ID user-postgres-ems, nástroj query, { "sql": "…" } — viz docs/07-mcp-postgres-ems.md a pravidlo .cursor/rules/mcp-postgres-ems.mdc |
2b. MCP — živá EMS databáze (read-only)
Když uživatel napíše „použij MCP“ nebo potřebuje aktuální řádky z Postgresu (plán, telemetrie, journal):
- Zavolej MCP nástroj
queryna serveruuser-postgres-emss argumentem{"sql": "<SELECT …>"}. - Neodmlouvej bez pokusu (typ „nepřipojím se“, „MCP neexistuje“). Po chybě popiš skutečnou chybu a co zkontrolovat.
- Kanonický popis, příklady a bezpečnost:
docs/07-mcp-postgres-ems.md.
3. Adresářová struktura
| Cesta | Účel |
|---|---|
CLAUDE.md, .env.example, docker-compose.yml |
Kořen: pravidla, env šablona, compose |
docs/ |
Produktová a technická specifikace (overview, architektura, datový model, integrace) |
docs/04-modules/ |
Modulové specifikace (ceny, forecast, spotřeba, TČ, telemetrie, řízení, plánování, režimy, EV) |
docs/loxone-integration.md |
Loxone watchdog, heartbeat, role exekutora |
docs/06-open-questions.md |
Nedokončené rozhodnutí – doplňovat místo hádání |
docs/07-mcp-postgres-ems.md |
MCP read-only SQL na EMS DB (server user-postgres-ems, nástroj query) |
db/migration/ |
Flyway versioned migrace V00x__*.sql (schéma, seed, alter) |
db/routines/ |
Repeatable SQL: funkce ems.fn_* |
db/views/ |
Repeatable SQL: view ems.vw_* |
backend/services/ |
Python služby (v repozitáři zatím hlavně plánování) |
4. Pravidla – NIKDY neporušovat
-
15min logika pro plán/ceny/baseline/audit/forecast intervaly. Časové řady v těchto doménách = 15min sloty. Telemetrie zařízení je 1min (hypertables) – agregace do 15min přes SQL/job, ne ukládat „hodinové“ řádky jako primární plánovací záznam.
-
Všechny doménové záznamy vázat na
site_id(telemetrie, plány, audit, konfigurace aktiv, session, …). Výjimka:market_interval_priceje globální pro zdroj/trh; vazba na site je přes konfiguraci a view. -
Raw ceny ≠ efektivní ceny.
ems.market_interval_price= bez marží. Efektivní nákup/prodej jen přesems.vw_site_effective_price(join na platnousite_market_config). -
Loxone = exekutor + autonomní fallback, ne optimalizátor. Logika a plán v EMS. Watchdog v Loxone nesmí záviset na čtení DB (
site_heartbeatje jen pro EMS UI/diagnostiku). -
FVE pole B (
controllable = false, typicky ongrid GEN) – žádný curtailment. Curtailment jen pole A (Deye). Solver smí omezovat jenpv_a; pole B může mít zelený bonus naasset_pv_array(green_bonus_*), auditpv_b_production_wh/green_bonus_czk. -
Záporná prodejní cena →
grid_export == 0v LP (hard constraint kde zapnuté): buďdeye_gen_microinverter_cutoff_enablednadeye-main, neboems.site_grid_connection.block_export_on_negative_sell(default false). home-01 kvůli neriťitelnému PV B často bez druhého přepínače — přebytek pole B nesmí dělat PL infeasible; KV1 (bez pole B / fixní nákup) migrace V074 nastavujeblock_export_on_negative_sell = true. -
Záporná nákupní cena → omezit import na realistický horní strop (viz
solve_dispatchvplanning_engine.py– nesmí „nekonečný“ import). -
PuLP + HiGHS pro dispatch; žádný návrat k greedy
fn_plan_dayjako primárnímu řešení (SQL wrapper může zůstat pro uložení výsledků – dle docs). Ekonomika slotů: masky + guardy vsolve_dispatch— vizdocs/04-modules/planning.md. Arbitráž baterie: neúčtovatbuy[t]/sell[t]ve stejném 15min slotu jako nákup/prodej téže kWh;min(buy)horizontu ≠ cena nabití (home-01 nabíjí hodiny, ne jednu čtvrthodinu). Povinné:docs/04-modules/planning-arbitrage-accounting.md. -
Zelený bonus je na
asset_pv_array(sloupcegreen_bonus_*), nikdy vsite_market_config. Výpočet přesfn_green_bonus_revenue(). Bonus se nepočítá v solveru – pouze v audit_filler (fn_fill_audit_interval). -
Deye Modbus: čtení i zápis (setpointy). RS485→Waveshare→TCP, knihovna
pymodbus. -
Přepínání provozního režimu přes DB API /
ems.fn_set_mode– držet konzistenci soperating_mode_defa Loxoneloxone_mode_value.
SQL-first a read-model (Python jen tenká orchestrace)
Projekt je SQL-first: doménová logika, agregace, joiny mezi tabulkami a stabilní čtecí rozhraní patří do PostgreSQL (ems.fn_*, případně ems.vw_*). Python (FastAPI, joby) volá DB; neskladá vlastní dotazy nad schématem mimo výjimky níže.
Formát SQL v repu (db/migration, db/routines, db/views): odsazení 2 mezery na úroveň vnoření; rezervovaná klíčová slova PostgreSQL vždy malými písmeny (create table, select, where, references, …). Identifikátory (ems.*, sloupce) snake_case; typy v deklaracích též malými (int, text, timestamptz, jsonb). Nový / upravený SQL v tomto stylu — nesmí se objevovat verzované migrace psané „ALL CAPS keywords“.
- Preferuj: novou nebo rozšířenou
ems.fn_*(…)s jasnými parametry; potřebuješ často stejné sloupce z více tabulek →ems.vw_*(view zapouzdřuje joiny a strukturu DB; z Pythonu jeSELECT … FROM ems.vw_*v pořádku). - Nechtěné: skládání dotazů v Pythonu (vlastní JOIN / WITH / poddotazy nad
ems.*tabulkami). Místo toho funkce nebo view vdb/routines//db/views/+ jedno volání z aplikace. - Jediné SQL v
backend/services/*.pyabackend/app/routers/*.py:SELECT 1/EXISTS;select ems.fn_*(…);SELECT … FROM ems.vw_*(read přes view); žádné jiné ad-hocSELECT/INSERT/UPDATE. IO (Modbus, HTTP); PuLP; orchestrace scheduleru. - Health a Loxone po změně režimu:
fn_health_summary,fn_health_detailed_db,fn_vw_site_directory_active,fn_site_economics_yesterday_notification,fn_site_mode_loxone_bundlev repeatabledb/routines/R__073_fn_health_site_jobs_mode_bundle.sql; FastAPI je vapp/main.py+ joby vapp/lifespan.py.
Provozní režimy (operating_mode)
- Pět hodnot
mode_codevems.site_operating_mode: AUTO, SELF_SUSTAIN, CHARGE_CHEAP, PRESERVE, MANUAL. - Režim se načítá v
planning_engine._load_site_context(); dodatečné LP constraints podle režimu jsou vsolve_dispatch()(žádný export / limit importu / zákaz nabíjení nebo vybíjení baterie podle módu). - Fyzické režimy Deye (PASSIVE / SELL / CHARGE) se odvozují v
exporter_monolith.get_deye_modea zapisují vwrite_inverter_setpoints. lock_battery=TrueuControlSetpoints(PRESERVE): registry 108/109 = 0 – Deye baterii nepoužívá. Výjimka oproti obecnému pravidlu max A ve PASSIVE/SELL.
-
forecast_pv_runaforecast_pv_intervalse NESMÍ mazat – historické běhy zůstávají v DB pro tracking přesnosti (forecast_accuracy,fn_fill_forecast_accuracy). -
Endpoint
GET …/forecast/pvvracíDISTINCT ON (interval_start, pv_array_id)seřazené podle nejnovějšíhoforecast_pv_run.created_at, aby UI nemělo duplikáty slotů; plná historie běhů zůstává v tabulkách.
13a. PV delta kalibrace: GET …/forecast/pv-delta-profile vrací JSON z fn_pv_forecast_delta_profile; GET …/configuration obsahuje pv_forecast_calibration z ems.site_pv_forecast_calibration; PATCH …/configuration/pv-forecast-calibration mění cutoff / policy / přepsání parametrů delty. Referenční dny špičkové produkce zpětně: tabulka ems.site_pv_forecast_reference_day (V076) + volitelně sloupec reference_day_weight_mult v kalibraci — v fn_pv_forecast_delta_profile zvednou váhu řádků forecast_accuracy těchto kalendářních dní (datum ve site.timezone jako u slotů); doplňovat lze ems.fn_pv_forecast_sync_reference_days. Provozní mazání uložené predikce za den (hranice Europe/Prague, ne TZ site): ems.fn_delete_forecast_pv_prague_calendar_day. Telemetrie telemetry_inverter.is_export_limited / pv_derating_flags (V058) řídí vyloučení slotu z učení v fn_fill_forecast_accuracy (telemetry_derating); telemetry_collector je plní čtením Deye reg 145 a 179 při poll střídače.
-
Příchod a odjezd EV detekuje
telemetry_collectorz telemetrie nabíječky: přechodavailable→preparing/charging(resp. jakýkoli stav ≠available) znamená příjezd; přechod naavailableuzavřeev_session. Tabulkaev_arrival_statsse při příjezdu doplňuje přesfn_update_ev_arrival_statsa nemá se mazat (dlouhodobá historická statistika). -
Bazální spotřeba =
load_power_wminus řízené zátěže (součet EV ztelemetry_ev_charger, TČ ztelemetry_heat_pump). Tabulkaconsumption_baseline_statsse plní denně (APScheduler 00:30) přesfn_update_baseline_stats; bez EMA „ocasu“ přepočítáš smaž+hromadný update přesems.fn_rebuild_consumption_baseline_stats(site_id, lookback)(site_id NULL→ všechny lokality). Solver načítá průměr bazálu zconsumption_baseline_stats(DOW + hodina v Europe/Prague), ne zconsumption_baseline_interval. -
Dynamický horizont plánování (jen OTE): konec okna z
ems.fn_planning_horizon_end(site_id, horizon_start)(minposledního OTE konce astart + 36 h, NULL pokud je známé OTE kratší než 1 h od startu – rolling se přeskočí; denní plán při NULL použije 1 h fallback v Pythonu). Strop a práh měnit v SQL (defaultní argumenty funkce / repeatable migrace), ne přes env. Solver používá výhradně sloty s efektivní cenou zvw_site_effective_price(žádná predikce v LP). Účelová funkce má terminal SoC shadow price:−(průměr buy v prvních 24 h slotů × planner_terminal_soc_value_factor / 1000) × soc[T−1](Kč; SoC v Wh), kdeplanner_terminal_soc_value_factorjeems.asset_battery.planner_terminal_soc_value_factornačtené přesems.fn_planning_site_context(žádný skrytý faktor v Pythonu). Fázované SoC v okněsell < 0(v32):planner_neg_sell_prep_soc_percent,planner_neg_sell_full_soc_tail_slots,planner_neg_sell_vent_min_sell_czk_kwhnaasset_battery; curtail A → reg 340, plná baterie = solar sell off bez zápisu 340.market_price_stats/fn_get_predicted_pricezůstávají pro statistiky; detail:docs/04-modules/planning.md,docs/04-modules/planning-extended-horizon.md. -
Modbus zápis = journal. Každý zápis do zařízení přes control exporter se loguje do
ems.modbus_command. Verifikační job běží každé 2 minuty a ověřuje nedávno zápis (written→ čtení registru). Při mismatch po max. 3 pokusech o zápis → u běžných registrů přepnutí na SELF_SUSTAIN (run_fn_set_mode_with_discord→fn_set_mode,activated_by=system:mismatch) + Discord při skutečné změně režimu. Výjimka: souvislý blok Deye 62–64 (čas) → po 3 neúspěšných ověřeních bez změny režimu, kritický Discord (notify_modbus_clock_verify_exhausted). Obecně: při jakékoli změněmode_codez Pythonu (POST /api/v1/sites/{id}/mode, mismatch → SELF_SUSTAIN,fn_expire_modes) lze Discord zapnout přesDISCORD_WEBHOOK_URL. Detail:docs/04-modules/modbus-command-journal.md. -
Deye zápis registrů 60–499: pouze FC 0x10 (
write_registers), nikdy FC 0x06 pro tento rozsah;execute_modbus_commandsslučuje souvislé adresy do jednoho FC 0x10. Fyzický režim Deye (PASSIVE/CHARGE/SELL): výhradněget_deye_modevexporter_monolith.py(bez wattových prahů: SELL přibattery_w< 0 agrid_setpoint_w< 0; CHARGE při obou > 0; jinak PASSIVE). PASSIVE (ZERO, AUTO):export_mode=PV_SURPLUS→ 108=0, 109=max, 142=deye_zero_export_mode(ne selling first); jinak 108/109 dledeye_battery_charge_discharge_amps/_deye_zero_export_amps_for_passive(import bez vybíjení → 109=0); TOU SOC (reg 166+): PASSIVE =min_soc_percent, CHARGE =max_soc_percent(clamp 10–100 z DB), SELL =reserve_soc_percent(_deye_passive_tou_battery_soc_pct,_deye_tou_params). SELL: 108=0, 109=max, 178=32 (peak shaving off), 143 omezeno podle|grid_setpoint_w|; 142/145/TOU jako vwrite_inverter_setpoints. Reg 340 (max solar power, W): jen pokudems.fn_site_has_active_green_bonus_pv(site_id)aems.fn_inverter_pv_a_max_w(inverter_id) > 0(strop zdeye_reg340_max_solar_w, typ. 32k home-01 / 65k jinde, ne součet Wp; mindeye_reg340_min_solar_w, home-01 400); hodnota z plánu / curtailu (AUTO). Není vDEYE_CRITICAL_REGS_SELF_SUSTAIN— verify mismatch nečeká přepnutí do SELF_SUSTAIN. PRESERVE:lock_battery→ 108/109=0. Čas 62–64, bloky TOU 1–2 vs 3–6, verify, Discord: beze změny oproti dřívějšímu chování — plný popisdocs/04-modules/modbus-registers.mdadocs/04-modules/operating-modes.md. -
Baterie – export v LP: V
solve_dispatchbinárkaz_export[t]: pokudgrid_exportv daném slotu ≥ 1 W, platí koncovésoc[t] ≥ arb_base_wh(ekonomická rezerva z DB, ne časová řadaarb_floor_series). Bez exportu může plán jít kmin_soc_percent(provozní podlaha; u paralelních packů často 11–12 %, migrace V029 + komentář sloupce).
5. Schéma ems – tabulky (jedna věta)
| Tabulka | Popis |
|---|---|
site |
Lokalita (časová zóna, GPS, aktivita). |
site_endpoint |
Endpointy: Modbus, Loxone HTTP, atd. |
site_market_config |
Marže, režimy cenění; časová platnost (zelený bonus není zde – viz asset_pv_array). |
site_grid_connection |
Limity import/export, block_export_on_negative_sell (LP při záporném sell), no_export, rezervovaný výkon. |
site_override |
Manuální přepisy nad plánem (JSON + platnost). |
site_operating_mode |
Aktuální provozní režim na site (1 řádek/site). |
site_operating_mode_log |
Historie přepnutí režimů. |
site_heartbeat |
Poslední EMS heartbeat pro dashboard (ne pro Loxone watchdog). |
operating_mode_def |
Číselník režimů (baterie/síť/EV/TČ, hodnota pro Loxone). |
asset_inverter |
Střídač (výkony, endpoint, zda řiditelný). |
asset_battery |
Baterie vázaná na střídač (SoC limity, účinnosti, degradace). |
asset_pv_array |
FVE pole (Wp, orientace, curtailable vs ne; volitelně green_bonus_* pro dotované pole). |
asset_ev_charger |
Nabíječka EV (výkony, fáze, endpoint). |
asset_heat_pump |
TČ (výkon, COP ref, limity běhu, TUV parametry). |
asset_vehicle |
Vozidlo (kapacita, max AC výkon, default target SoC/deadline). |
market_interval_price |
Raw spot OTE (15min), bez marží. |
telemetry_inverter |
1min telemetrie střídače (Timescale); volitelně is_export_limited, pv_derating_flags pro vyloučení slotu z učení delty. |
telemetry_ev_charger |
1min telemetrie nabíječky (Timescale). |
telemetry_heat_pump |
1min telemetrie TČ (Timescale). |
forecast_pv_run |
Metadata běhu predikce FVE. |
forecast_pv_interval |
Predikovaný výkon FVE po 15min (Timescale). |
forecast_accuracy |
Řádky přesnosti predikce vs telemetrie po 15min (per run); doplňuje fn_fill_forecast_accuracy. |
site_pv_forecast_calibration |
Per site: cutoff učení delty, policy škrcení, přepsání parametrů fn_pv_forecast_delta_profile. |
forecast_weather_interval |
Počasí 15min pro site (Timescale). |
forecast_correction_log |
Log korekcí forecastu vs skutečnost při rolling replanu. |
planning_run |
Jeden běh plánovače (daily/rolling/manual, stav, parametry solveru). |
planning_interval |
Výstup solveru po 15min (baterie, síť, EV, TČ, curtailment A). |
audit_interval |
Skutečnost vs plán po 15min (náklady, odchylky, bonus pole B). |
consumption_baseline_interval |
Bazální spotřeba actual/forecast 15min (Timescale). |
consumption_baseline_stats |
Historické průměry bazálu per DOW+hodina (EMA z telemetrie); vstup solveru. |
market_price_stats |
Historické průměry raw OTE ceny per DOW+hodina; predikce cen za horizont OTE (fn_get_predicted_price). |
tuv_usage_stats |
Průměrná změna teploty TUV zásobníku per DOW+hodina (telemetrie TČ); vstup TUV look-ahead ve solveru. |
ev_session |
Nabíjecí session na WB (deadline, energie, náklady). |
ev_arrival_stats |
Agregované počty příjezdů EV podle dne v týdnu a hodiny (Europe/Prague); plní se z detekce příjezdu v telemetrii. |
modbus_command |
Journal Modbus zápisů (pending → written → verified / mismatch / failed); retry a vazba na planning_run; u Deye exportu deye_physical_mode (PASSIVE/SELL/CHARGE). |
signal_def |
Katalog odchozích signálů (kód, typ hodnoty); seed EXPORT_BAN_ACTIVE. |
signal_route |
Mapování signál → cíl (loxone_vi, http_rest) per site + endpoint_id + volitelný route_config_json / verify_config_json. |
signal_outbound_journal |
Journal HTTP odeslání signálů (queued → sent → verified / retry / abandoned). |
signal_state |
Poslední požadovaná / odeslaná / ověřená hodnota na cíli (idempotence). |
cutoff_switch_log |
Log přepnutí cut-off přepínačů (mikroinvertory); edge trigger, důvod a cena. |
View / funkce (nejsou tabulky): vw_site_effective_price, vw_site_directory, vw_modbus_last_verified, vw_asset_inverter_modbus_poll, vw_asset_ev_charger_modbus_poll, vw_asset_heat_pump_modbus_poll, vw_latest_telemetry, vw_telemetry_hourly_7d, vw_telemetry_15m_7d (15min agregát pro dashboard sloty; repeatable R__071_vw_telemetry_15m_7d.sql), vw_audit_summary, vw_operating_mode, vw_forecast_accuracy_by_lead_time, vw_forecast_accuracy_daily; fn_effective_price, fn_green_bonus_revenue, fn_cop_estimate, fn_fill_audit_interval, fn_fill_forecast_accuracy, fn_delete_forecast_pv_prague_calendar_day, fn_pv_forecast_sync_reference_days, fn_set_mode, fn_expire_modes (vrací řádky přepnutí pro Discord), fn_restore_previous_mode, fn_update_ev_arrival_stats, fn_ev_expected_arrival, fn_update_baseline_stats, fn_rebuild_consumption_baseline_stats, fn_get_baseline_forecast, fn_update_market_price_stats, fn_update_tuv_usage_stats, fn_get_predicted_price, dále read-modely: fn_site_configuration, fn_site_full_status, fn_site_notifications_context, fn_plan_current_bundle, fn_planning_run_horizon, fn_planning_future_price_days, fn_economics_daily_month, fn_economics_monthly_chart, fn_economics_lock_day, fn_economics_unlock_day, fn_energy_flows_daily_month, fn_energy_flows_intervals_day, fn_forecast_pv_split, fn_ev_sessions_active, fn_ev_session_apply_patch, fn_ev_arrival_prediction_bundle, fn_ev_session_transition, fn_negative_price_predictions, fn_latest_ote_day_stats, fn_ote_day_slot_stats_prague, fn_ote_list_missing_days, fn_site_effective_prices_day_prague, fn_modbus_journal_list, fn_modbus_written_command_ids, fn_modbus_commands_by_ids, fn_inverter_modbus_caps_patch, fn_set_mode_with_context, fn_fill_audit_for_site_window, plánování: fn_load_planning_slots_full, fn_last_effective_ote, fn_planning_horizon_end, fn_planning_site_context, fn_pv_forecast_correction_factor, fn_planning_run_commit, fn_planning_slot_boundary_prague, fn_planning_interval_at_offset, fn_telemetry_inverter_sample, fn_telemetry_ev_charger_sample, fn_telemetry_heat_pump_sample, fn_battery_cycle_audit, Deye helpery: fn_deye_pack_system_time, fn_deye_clock_drift_sec, fn_deye_time_point_regs, fn_deye_tou_inactive_signature, fn_modbus_last_verified_map, fn_inverter_pv_a_max_w, fn_site_has_active_green_bonus_pv.
6. Periodické úlohy backendu (APScheduler / smyčky)
Specifikace z docs/02-architecture.md, modulových docs a komentářů v planning_engine.py. V gitu je zatím rozpracovaný backend – joby mají být v backend/app/main.py (zatím často chybí).
| Ú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 |
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 |
run_daily_plan |
15:00 denně | backend/services/planning_engine.py + ems.fn_planning_horizon_end (dynamický OTE horizont, terminal SoC) |
run_rolling_replan |
každých 15 min (*/15) |
planning_engine.py – přepočet od aktuálního slotu |
control_exporter |
každých 15 min (slot boundary) | docs/04-modules/control.md |
verify_modbus |
každé 2 min | Ověření modbus_command ve stavu written (posledních 10 min); viz docs/04-modules/modbus-command-journal.md |
signal_outbound_send / signal_outbound_verify |
každých 15 s | services/signal_service.py — odeslání fronty signal_outbound_journal a readback verify (Loxone / HTTP REST). |
audit_filler / fn_fill_audit_interval |
každých 15 min | docs/02-architecture.md, DB fn_fill_audit_interval |
forecast_accuracy / fn_fill_forecast_accuracy |
každých 15 min (min. 2,17,32,47) | Po audit filleru; doplní actual z telemetrie do forecast_accuracy |
fn_update_baseline_stats |
00:30 denně | Aktualizace consumption_baseline_stats z telemetrie (30d lookback) |
fn_update_market_price_stats |
14:45 denně | Po importu OTE a forecastu; market_price_stats (90d lookback) |
fn_update_tuv_usage_stats |
00:45 denně | Po baseline jobu; tuv_usage_stats (30d lookback) |
7. Kde hledat co
| Chci… | Kam |
|---|---|
| Pochopit systém end-to-end | docs/01-overview.md, docs/02-architecture.md |
| Tabulky, vazby, jednotky | docs/03-data-model.md |
| OTE ceny, marže, efektivní cena | docs/04-modules/market-prices.md, db/views/R__061_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 |
| Bazální spotřeba | docs/04-modules/consumption.md |
| TČ, COP, TUV | docs/04-modules/heat-pump.md, db/routines/R__005_fn_cop_estimate.sql |
| Modbus, telemetrie, agregace | docs/04-modules/telemetry.md |
| Dashboard přehled – 15min grafy slotů, SoC vs. živá telemetrie | docs/04-modules/telemetry.md (CA telemetry_inverter_15m, view vw_telemetry_15m_7d), frontend/src/hooks/useDashboardData.ts, frontend/src/components/charts/SocTuvChart.tsx |
| Modbus journal, verifikace, Discord | docs/04-modules/modbus-command-journal.md |
| Deye registry (FC 0x10, 108/109/141/142/178/143/145/340) | docs/04-modules/modbus-registers.md |
| Export setpointů, Loxone HTTP | docs/04-modules/control.md, docs/loxone-integration.md |
| LP solver, rolling replan, korekce FVE, dynamický OTE horizont | docs/04-modules/planning.md, docs/04-modules/planning-extended-horizon.md, docs/planning-changelog.md, planning_engine.py |
| Záporný výkup, bod T, termika, bazén (home-01 strategie) | docs/04-modules/planning-neg-sell-strategy.md |
| Arbitráž baterie (mezi sloty ≠ buy/sell v jednom 15min) | docs/04-modules/planning-arbitrage-accounting.md |
| Provozní režimy AUTO / SELF_SUSTAIN / … | docs/04-modules/operating-modes.md, db/migration/V004__operating_modes.sql, db/routines/R__044_fn_set_mode.sql |
| EV, session, deadline charging | docs/04-modules/ev-charging.md, db/migration/V006__vehicles.sql |
| Curtailment A, zelený bonus B | db/migration/V005__planning_curtailment.sql |
| Rolling plán, forecast log | db/migration/V007__rolling_replanning.sql |
| Audit 15min | db/routines/R__019_fn_fill_audit_interval.sql, docs/04-modules/telemetry.md |
| Nové sloupce / tabulky | nový db/migration/V00x__*.sql + případně db/routines / db/views |
JSONB read-model (fn_*, fetch_json) |
docs/02-architecture.md sekce Read-model JSONB, app/db_json.py |
Self-hosted deploy (Gitea, Caddy, /opt/ems-deploy) |
docs/deployment-self-hosted.md, deploy/deploy.sh |
| Reset DB / restore z dumpu (Docker volume, Timescale) | docs/database-reset-and-restore.md, scripts/import_ems_db.sh |
| Nespecifikované chování | docs/06-open-questions.md (přidat otázku, neimpl. naslepo) |
| MCP read-only SQL na EMS DB | docs/07-mcp-postgres-ems.md — server ID user-postgres-ems, nástroj query, {"sql":"…"}. Pravidlo .cursor/rules/mcp-postgres-ems.mdc. |
Konvence (krátce)
- Python:
snake_case, type hints, Pydantic pro API modely. - SQL: viz také odstavec Formát SQL u sekce SQL-first výše — 2 mezery odsazení, klíčová slova malými písmeny,
snake_caseidentifikátory, explicitní FK; Flyway pořadíV###__/ repeatableR__NNN_*.sql(třímístný prefix = pořadí závislostí mezi fn/vw). - Timescale continuous aggregate (CA): komentář k objektu CA je
COMMENT ON VIEW, neCOMMENT ON MATERIALIZED VIEW(PG hlásí 42809). Viz.cursor/rules/timescale-continuous-aggregate.mdc. - Výkon W, energie Wh, ceny Kč/kWh; čas v DB
TIMESTAMPTZ(UTC). - NIKDY neupravuj existující V__ migrační soubory po jejich aplikaci na DB.
- Pokud je potřeba opravit chybu ve verzované migraci, vytvoř novou V{N+1} migraci.
- Deploy:
flyway validatepředmigrate(deploy/deploy.sh). Lokálně./scripts/flyway_validate_local.sh; CI vizdocs/deployment-self-hosted.mdascripts/ci_check_migration_immutability.sh.