fix enf load
This commit is contained in:
@@ -5,6 +5,14 @@ Ekonomický screening velikosti baterie (15min, jednobusová energie).
|
||||
Typicky BA81: fixní nákup + prodej spot, limity výkonu z baterie min(0,5C, střídač),
|
||||
export/import podle připojení. Načte OTE z Postgres (stejná DB jako EMS) nebo z CSV.
|
||||
|
||||
Připojení k DB (deploy / Docker):
|
||||
- Postgres v compose poslouchá na ``EMS_DB_BIND:5432`` (výchozí 127.0.0.1). ``connection refused``
|
||||
= služba ``db`` neběží, nebo je port vázaný jen na jinou IP (WireGuard) → nastav stejný host.
|
||||
- Skript načte první nalezené ``.env`` z ``…/ems-deploy/.env`` nebo ``…/app/.env`` (není-li
|
||||
``--no-auto-env``) a doplní ``PGUSER``/``PGPASSWORD`` z ``DB_USER``/``DB_PASSWORD``.
|
||||
- Nebo ``DATABASE_URL`` / ``postgresql://USER:PASS@HOST:5432/ems`` (na hostu HOST=127.0.0.1
|
||||
nebo EMS_DB_BIND, ne ``db`` — to je jen uvnitř Docker sítě).
|
||||
|
||||
Příklad:
|
||||
python3 scripts/analysis/battery_sizing_screen.py \\
|
||||
--db \\
|
||||
@@ -31,6 +39,7 @@ import os
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, datetime, timedelta
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Sequence
|
||||
|
||||
try:
|
||||
@@ -93,6 +102,41 @@ def effective_sell_kc_kwh(raw_ote: float, margin_fixed: float, margin_pct: float
|
||||
return raw_ote + margin_fixed + (raw_ote * margin_pct / 100.0)
|
||||
|
||||
|
||||
def load_env_file(path: Path) -> None:
|
||||
if not path.is_file():
|
||||
return
|
||||
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
k, _, v = line.partition("=")
|
||||
k, v = k.strip(), v.strip().strip('"').strip("'")
|
||||
if not k:
|
||||
continue
|
||||
if k not in os.environ or os.environ.get(k, "") == "":
|
||||
os.environ[k] = v
|
||||
|
||||
|
||||
def apply_auto_env_files() -> None:
|
||||
"""Na produkci: /opt/ems-deploy/.env (když tam je docker-compose), pak app/.env nebo kořen repa."""
|
||||
script = Path(__file__).resolve()
|
||||
if len(script.parents) >= 3:
|
||||
deploy_root = script.parents[2]
|
||||
if (deploy_root / "docker-compose.yml").is_file():
|
||||
load_env_file(deploy_root / ".env")
|
||||
if len(script.parents) >= 2:
|
||||
load_env_file(script.parents[1] / ".env")
|
||||
|
||||
|
||||
def sync_pg_env_from_db_vars() -> None:
|
||||
if not os.environ.get("PGUSER") and os.environ.get("DB_USER"):
|
||||
os.environ["PGUSER"] = os.environ["DB_USER"]
|
||||
if not os.environ.get("PGPASSWORD") and os.environ.get("DB_PASSWORD"):
|
||||
os.environ["PGPASSWORD"] = os.environ["DB_PASSWORD"]
|
||||
if not os.environ.get("PGDATABASE"):
|
||||
os.environ["PGDATABASE"] = "ems"
|
||||
|
||||
|
||||
def load_prices_csv(path: str) -> list[tuple[datetime, float]]:
|
||||
out: list[tuple[datetime, float]] = []
|
||||
with open(path, newline="", encoding="utf-8") as f:
|
||||
@@ -118,6 +162,16 @@ def load_prices_db(date_from: date, date_to: date) -> list[tuple[datetime, float
|
||||
t0 = datetime.combine(date_from, datetime.min.time(), tzinfo=prg).astimezone(timezone.utc)
|
||||
t1 = datetime.combine(date_to, datetime.min.time(), tzinfo=prg).astimezone(timezone.utc)
|
||||
|
||||
dsn = (
|
||||
os.environ.get("DATABASE_URL")
|
||||
or os.environ.get("EMS_DATABASE_URL")
|
||||
or os.environ.get("POSTGRES_URL")
|
||||
)
|
||||
if dsn:
|
||||
if dsn.startswith("postgres://"):
|
||||
dsn = "postgresql://" + dsn[len("postgres://") :]
|
||||
conn = psycopg2.connect(dsn)
|
||||
else:
|
||||
conn = psycopg2.connect(
|
||||
host=os.environ.get("PGHOST", "127.0.0.1"),
|
||||
port=int(os.environ.get("PGPORT", "5432")),
|
||||
@@ -270,7 +324,19 @@ def simulate_year(
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("--db", action="store_true", help="Načti OTE z Postgres (env PG* / DB_*)")
|
||||
ap.add_argument("--db", action="store_true", help="Načti OTE z Postgres (env PG* / DB_* / DATABASE_URL)")
|
||||
ap.add_argument(
|
||||
"--no-auto-env",
|
||||
action="store_true",
|
||||
help="Nenačítej automaticky .env z ems-deploy/ ani app/",
|
||||
)
|
||||
ap.add_argument("--env-file", type=str, default="", help="Dodatečný soubor .env (po auto-env)")
|
||||
ap.add_argument(
|
||||
"--pg-host",
|
||||
type=str,
|
||||
default="",
|
||||
help="Přepíše PGHOST (např. stejná IP jako EMS_DB_BIND ve compose)",
|
||||
)
|
||||
ap.add_argument("--price-csv", type=str, default="", help="CSV: interval_start, sell_raw_price_czk_kwh")
|
||||
ap.add_argument("--date-from", type=str, required=True)
|
||||
ap.add_argument("--date-to", type=str, required=True)
|
||||
@@ -291,6 +357,13 @@ def main() -> None:
|
||||
d0 = date.fromisoformat(args.date_from)
|
||||
d1 = date.fromisoformat(args.date_to)
|
||||
if args.db:
|
||||
if not args.no_auto_env:
|
||||
apply_auto_env_files()
|
||||
if args.env_file:
|
||||
load_env_file(Path(args.env_file))
|
||||
sync_pg_env_from_db_vars()
|
||||
if args.pg_host:
|
||||
os.environ["PGHOST"] = args.pg_host
|
||||
series = load_prices_db(d0, d1)
|
||||
elif args.price_csv:
|
||||
series = load_prices_csv(args.price_csv)
|
||||
|
||||
Reference in New Issue
Block a user