safraeli commited on
Commit
b3e1b1d
·
verified ·
1 Parent(s): c8ee080

Fix daily planner: pass forecast + budget to plan_day()

Browse files
Files changed (1) hide show
  1. backend/workers/daily_planner.py +55 -2
backend/workers/daily_planner.py CHANGED
@@ -33,16 +33,69 @@ logging.basicConfig(
33
  log = logging.getLogger("daily_planner")
34
 
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  def main():
37
  from src.day_ahead_planner import DayAheadPlanner
38
  from src.data.redis_cache import get_redis
39
- from config.settings import DAILY_PLAN_PATH
40
 
41
  target = date.today()
42
  log.info("Computing day-ahead plan for %s", target)
43
 
 
 
 
 
 
 
44
  planner = DayAheadPlanner()
45
- plan = planner.plan(target_date=target)
 
 
 
 
 
46
 
47
  plan_dict = plan.to_dict() if hasattr(plan, "to_dict") else {"raw": str(plan)}
48
  plan_dict["_computed_at"] = datetime.now(timezone.utc).isoformat()
 
33
  log = logging.getLogger("daily_planner")
34
 
35
 
36
+ def _get_forecast(target: date):
37
+ """Build 96-slot (15-min) forecast arrays from IMS cache or defaults."""
38
+ try:
39
+ from src.data.ims_client import IMSClient
40
+ import pandas as pd
41
+
42
+ client = IMSClient()
43
+ df = client.load_cached()
44
+ if df.empty:
45
+ raise ValueError("No IMS cache available")
46
+
47
+ # Get the most recent day's pattern as a proxy for tomorrow
48
+ df["hour"] = pd.to_datetime(df["timestamp_utc"]).dt.hour
49
+ # Build 96 slots of temp and GHI
50
+ temps = []
51
+ ghis = []
52
+ for slot in range(96):
53
+ h = slot // 4
54
+ # Use mean values per hour from recent data
55
+ hour_data = df[df["hour"] == h]
56
+ t = hour_data["air_temperature_c"].mean() if "air_temperature_c" in df.columns and not hour_data.empty else 25.0
57
+ g = hour_data["ghi_w_m2"].mean() if "ghi_w_m2" in df.columns and not hour_data.empty else 0.0
58
+ temps.append(float(t) if not pd.isna(t) else 25.0)
59
+ ghis.append(float(g) if not pd.isna(g) else 0.0)
60
+ return temps, ghis
61
+ except Exception as exc:
62
+ log.warning("Could not build forecast from IMS: %s — using defaults", exc)
63
+ # Default: sinusoidal temperature and GHI profile for Sde Boker
64
+ import math
65
+ temps = []
66
+ ghis = []
67
+ for slot in range(96):
68
+ h = slot / 4 # fractional hour
69
+ # Temp: 18°C at night, peaks ~35°C at 14:00
70
+ t = 26.5 + 8.5 * math.sin(math.pi * (h - 6) / 12) if 6 <= h <= 18 else 20.0
71
+ # GHI: 0 at night, peaks ~900 W/m² at noon
72
+ g = max(0, 900 * math.sin(math.pi * (h - 6) / 12)) if 6 <= h <= 18 else 0.0
73
+ temps.append(round(t, 1))
74
+ ghis.append(round(g, 1))
75
+ return temps, ghis
76
+
77
+
78
  def main():
79
  from src.day_ahead_planner import DayAheadPlanner
80
  from src.data.redis_cache import get_redis
81
+ from config.settings import DAILY_PLAN_PATH, MAX_ENERGY_REDUCTION_PCT
82
 
83
  target = date.today()
84
  log.info("Computing day-ahead plan for %s", target)
85
 
86
+ # Build forecast inputs
87
+ forecast_temps, forecast_ghi = _get_forecast(target)
88
+
89
+ # Compute a reasonable daily budget (5% of ~25 kWh potential = ~1.25 kWh)
90
+ daily_budget_kwh = 25.0 * MAX_ENERGY_REDUCTION_PCT / 100.0
91
+
92
  planner = DayAheadPlanner()
93
+ plan = planner.plan_day(
94
+ target_date=target,
95
+ forecast_temps=forecast_temps,
96
+ forecast_ghi=forecast_ghi,
97
+ daily_budget_kwh=daily_budget_kwh,
98
+ )
99
 
100
  plan_dict = plan.to_dict() if hasattr(plan, "to_dict") else {"raw": str(plan)}
101
  plan_dict["_computed_at"] = datetime.now(timezone.utc).isoformat()