#!/usr/bin/env bash # Odstraní predikované PV intervaly (a navázaný tracking přesnosti) pro jeden kalendářní den v Europe/Prague. # # VAROVÁNÍ (provozní / datová kontinuita) # ──────────────────────────────────────── # - Řád v repozitáři je držet historické běhy FVE forecastu pro analýzu a učení delty (@see docs/04-modules/forecast.md). # - Používej jen když vědomě potřebuješ „načisto“ vygenerovat nový forecast (forecast service). # - Fyzický breaker řeší měnič/Deye — skript jen čistí databázi od uloženého PV forecastu. # # Nenahrazuje mazání/load baseline spotřeby (`consumption_baseline_stats` / její výpočet). # # Použití: # export DATABASE_URL='postgres://…/ems' # ./scripts/wipe_pv_forecast_prague_day.sh # dnešní den (Europe/Prague), všechny lokality # ./scripts/wipe_pv_forecast_prague_day.sh 2026-05-02 # konkrétní datum YYYY-MM-DD # ./scripts/wipe_pv_forecast_prague_day.sh 2026-05-02 2 # jen site.id = 2 (např. home-01) # # Šedý režim (jen počty, žádné mazání): # DRY_RUN=1 ./scripts/wipe_pv_forecast_prague_day.sh 2026-05-02 2 set -euo pipefail DAY="${1:-$(TZ=Europe/Prague date +%Y-%m-%d)}" SITE_ID="${2:-}" if ! [[ "$DAY" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then echo "Datum musí být YYYY-MM-DD, dostal jsem: $DAY" >&2 exit 1 fi if [[ -z "${DATABASE_URL:-}" ]] && [[ -z "${PGHOST:-}" ]]; then echo "Nastav DATABASE_URL nebo standardní PG proměnné (PGHOST, PGUSER, PGDATABASE, …)." >&2 exit 1 fi PSQL=(psql -v ON_ERROR_STOP=1) if [[ -n "${DATABASE_URL:-}" ]]; then PSQL+=("$DATABASE_URL") else PSQL+=("${PGDATABASE:-ems}") fi SITE_CLAUSE="" if [[ -n "$SITE_ID" ]]; then if ! [[ "$SITE_ID" =~ ^[0-9]+$ ]]; then echo "Druhý argument musí být číslo site_id." >&2 exit 1 fi SITE_CLAUSE="AND r.site_id = ${SITE_ID}::int" fi DRY="${DRY_RUN:-0}" if [[ "$DRY" == "1" ]] || [[ "$DRY" == "true" ]]; then echo "DRY_RUN: den $DAY (Europe/Prague)${SITE_ID:+ site_id=$SITE_ID}" "${PSQL[@]}" -c " with bounds as ( select ('${DAY}'::date::text || ' 00:00:00')::timestamp at time zone 'Europe/Prague' as ts_start, (('${DAY}'::date + 1)::text || ' 00:00:00')::timestamp at time zone 'Europe/Prague' as ts_end ), targets as ( select fi.run_id, fi.pv_array_id, fi.interval_start from ems.forecast_pv_interval fi inner join ems.forecast_pv_run r on r.id = fi.run_id cross join bounds b where fi.interval_start >= b.ts_start and fi.interval_start < b.ts_end ${SITE_CLAUSE} ) select count(*) as interval_rows_to_delete, count(distinct run_id) as distinct_run_ids from targets; " exit 0 fi echo "Mažu PV forecast intervaly pro den $DAY (Europe/Prague)${SITE_ID:+ site_id=$SITE_ID} …" "${PSQL[@]}" -c " begin; create temporary table _ems_wipe_pv_forecast_targets ( run_id int not null, pv_array_id int not null, interval_start timestamptz not null ) on commit drop; with bounds as ( select ('${DAY}'::date::text || ' 00:00:00')::timestamp at time zone 'Europe/Prague' as ts_start, (('${DAY}'::date + 1)::text || ' 00:00:00')::timestamp at time zone 'Europe/Prague' as ts_end ) insert into _ems_wipe_pv_forecast_targets (run_id, pv_array_id, interval_start) select fi.run_id, fi.pv_array_id, fi.interval_start from ems.forecast_pv_interval fi inner join ems.forecast_pv_run r on r.id = fi.run_id cross join bounds b where fi.interval_start >= b.ts_start and fi.interval_start < b.ts_end ${SITE_CLAUSE}; delete from ems.forecast_accuracy fa using (select distinct run_id, interval_start from _ems_wipe_pv_forecast_targets) t where fa.run_id = t.run_id and fa.interval_start = t.interval_start; delete from ems.forecast_pv_interval fi using _ems_wipe_pv_forecast_targets t where fi.run_id = t.run_id and fi.pv_array_id = t.pv_array_id and fi.interval_start = t.interval_start; delete from ems.forecast_pv_run fr where fr.id in (select distinct run_id from _ems_wipe_pv_forecast_targets) and not exists ( select 1 from ems.forecast_pv_interval x where x.run_id = fr.id ); select (select count(*) from _ems_wipe_pv_forecast_targets) as targets_interval_rows, (select count(distinct run_id) from _ems_wipe_pv_forecast_targets) as distinct_run_ids_touched; commit; " echo "Hotovo. Spusť forecast job / službu v backendu (Open-Meteo běh), aby se řádky ${DAY} doplnily znovu."