Skip to content
This repository was archived by the owner on Aug 14, 2026. It is now read-only.

Commit 3209941

Browse files
committed
remove confusing fallback solar calculation
1 parent 4ffd77e commit 3209941

4 files changed

Lines changed: 25 additions & 37 deletions

File tree

‎app.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def get_weather_forecast():
221221
else:
222222
capacity_kw = 0
223223
logger.info(f"Solar capacity for forecast: {capacity_kw} kW (panel={panel_kw}, inverter_config={inverter_kw}, inverter_api={api_inverter_kw})")
224-
# Analyse forecast with solar predictions (uses forecast.solar if available, falls back to weather-based)
224+
# Analyse forecast with solar predictions (uses forecast.solar if available)
225225
forecast = weather_analyser.analyse_forecast(
226226
forecast,
227227
panel_capacity_kw=capacity_kw if capacity_kw > 0 else None,
@@ -952,8 +952,8 @@ def get_weather():
952952
"icon": day.get("icon"),
953953
"temp_max": day.get("temp_max"),
954954
"temp_min": day.get("temp_min"),
955-
"cloud_cover": day.get("cloud_cover"),
956-
"precipitation_probability": day.get("precipitation_probability"),
955+
"cloud_cover": day.get("clouds"), # Map from internal "clouds" key
956+
"precipitation_probability": day.get("pop"), # Map from internal "pop" key
957957
"is_bad_weather": day.get("is_bad_weather", False),
958958
"estimated_solar_kwh": day.get("estimated_solar_kwh"),
959959
"solar_source": day.get("solar_source")

‎templates/index.html‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,15 +1503,17 @@ <h2>Schedule Settings</h2>
15031503
const tempMax = day.temp_max !== null ? Math.round(day.temp_max) : '--';
15041504

15051505
const solarEstimate = day.estimated_solar_kwh ? `<div class="solar-estimate">☀️ ~${day.estimated_solar_kwh} kWh</div>` : '';
1506+
const cloudCover = day.cloud_cover !== null && day.cloud_cover !== undefined ? `${day.cloud_cover}%` : '--';
1507+
const precip = day.precipitation_probability;
15061508
forecastHtml += `
15071509
<div class="${classes.join(' ')}">
15081510
<div class="day-name">${dayName}</div>
15091511
<div class="day-date">${formatDate(day.date)}</div>
15101512
<div class="weather-icon">${icon}</div>
15111513
<div class="condition">${day.condition}</div>
15121514
<div class="temp">${tempMin}° / ${tempMax}°</div>
1513-
<div class="clouds">☁️ ${day.clouds}%</div>
1514-
${day.pop > 0 ? `<div class="pop">💧 ${day.pop}%</div>` : ''}
1515+
<div class="clouds">☁️ ${cloudCover}</div>
1516+
${precip !== null && precip > 0 ? `<div class="pop">💧 ${precip}%</div>` : ''}
15151517
${solarEstimate}
15161518
</div>
15171519
`;

‎tests/test_weather_client.py‎

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -623,27 +623,24 @@ def test_analyse_forecast_uses_solar_client(self):
623623
assert result["daily"][0]["solar_source"] == "forecast.solar"
624624
assert result["daily"][1]["estimated_solar_kwh"] == 8.0
625625

626-
def test_analyse_forecast_falls_back_to_weather_estimate(self):
627-
"""Test that analyse_forecast falls back to weather estimate when solar client unavailable"""
626+
def test_analyse_forecast_no_solar_client(self):
627+
"""Test that analyse_forecast sets None for solar when solar client unavailable"""
628628
forecast = {
629629
"success": True,
630630
"daily": [
631631
{"date": "2023-12-22", "condition": "Clear", "clouds": 10, "pop": 5}
632632
]
633633
}
634634

635-
# Create a mock weather client with hourly data
636-
mock_weather_client = Mock()
637-
mock_weather_client.estimate_solar_output_hourly.return_value = 20.0
638-
639635
result = self.analyser.analyse_forecast(
640636
forecast,
641-
panel_capacity_kw=5.0,
642-
weather_client=mock_weather_client
637+
panel_capacity_kw=5.0
643638
)
644639

645-
assert result["daily"][0]["estimated_solar_kwh"] == 20.0
646-
assert result["daily"][0]["solar_source"] == "weather_estimate"
640+
# Without solar_client, no solar prediction is available
641+
assert result["daily"][0]["estimated_solar_kwh"] is None
642+
assert result["daily"][0]["has_solar_prediction"] is False
643+
assert result["daily"][0]["solar_source"] is None
647644

648645

649646
class TestWeatherClientAdditionalCoverage:

‎weather_client.py‎

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -631,8 +631,8 @@ def analyse_forecast(
631631
632632
Args:
633633
forecast: Forecast data from weather client
634-
panel_capacity_kw: Panel capacity for weather-based solar estimation
635-
weather_client: WeatherClient instance for hourly solar calculations
634+
panel_capacity_kw: Panel capacity (unused, kept for compatibility)
635+
weather_client: WeatherClient instance (unused, kept for compatibility)
636636
solar_client: SolarForecastClient for accurate solar predictions
637637
min_solar_threshold: Minimum solar kWh to consider a "good" day
638638
"""
@@ -642,17 +642,19 @@ def analyse_forecast(
642642
daily = forecast["daily"]
643643
bad_weather_days = []
644644

645-
# Try to get solar forecast from forecast.solar first
645+
# Try to get solar forecast from forecast.solar
646646
solar_forecast = None
647647
if solar_client:
648648
solar_forecast = solar_client.get_forecast()
649649
if solar_forecast.get("success"):
650650
logger.info("Using forecast.solar for solar predictions")
651+
elif solar_forecast.get("is_temporary"):
652+
logger.warning("forecast.solar temporarily unavailable (rate limited or timeout)")
651653

652654
for day in daily:
653655
date_str = day.get("date", "")
654656

655-
# Priority 1: Use forecast.solar if available
657+
# Use forecast.solar if available
656658
if solar_forecast and solar_forecast.get("success"):
657659
for solar_day in solar_forecast.get("daily", []):
658660
if solar_day["date"] == date_str:
@@ -663,27 +665,14 @@ def analyse_forecast(
663665
else:
664666
day["estimated_solar_kwh"] = None
665667
day["has_solar_prediction"] = False
666-
667-
# Priority 2: Fall back to weather-based estimation
668-
if not day.get("has_solar_prediction") and panel_capacity_kw and panel_capacity_kw > 0 and weather_client:
669-
hourly_estimate = weather_client.estimate_solar_output_hourly(
670-
panel_capacity_kw,
671-
date_str
672-
)
673-
674-
if hourly_estimate is not None:
675-
day["estimated_solar_kwh"] = hourly_estimate
676-
day["has_solar_prediction"] = True
677-
day["solar_source"] = "weather_estimate"
678-
else:
679-
day["estimated_solar_kwh"] = None
680-
day["has_solar_prediction"] = False
681-
682-
if not day.get("has_solar_prediction"):
668+
day["solar_source"] = None
669+
else:
670+
# No API prediction available - don't fall back to weather estimate
683671
day["estimated_solar_kwh"] = None
684672
day["has_solar_prediction"] = False
673+
day["solar_source"] = None
685674

686-
# Determine if bad weather based on solar prediction
675+
# Determine if bad weather based on solar prediction or weather conditions
687676
if day.get("has_solar_prediction") and min_solar_threshold:
688677
is_bad = day["estimated_solar_kwh"] < min_solar_threshold
689678
else:

0 commit comments

Comments
 (0)