@@ -171,13 +171,17 @@ def calculate_energy(self, power: PowerReadings) -> EnergyTotals:
171171 energy .monthly_battery_discharge = self ._get_monthly ("battery_discharge" , month_key )
172172 energy .yearly_battery_discharge = self ._get_yearly ("battery_discharge" , year_key )
173173
174- # Self-consumption savings (incremental, rate-weighted for dynamic tariff accuracy)
174+ # Solar self-consumption savings (incremental, rate-weighted for dynamic tariff accuracy)
175+ # Only tracks savings from solar — battery discharge savings are in cost_batt_savings.
176+ # Subtracting discharge_incr prevents double-counting: battery discharge is not solar.
175177 home_incr = (power .home_consumption_power * interval_hours ) / 1000 if power .home_consumption_power >= MIN_POWER_THRESHOLD else 0.0
176178 ev_incr = (power .ev_power * interval_hours ) / 1000 if power .ev_power >= MIN_POWER_THRESHOLD else 0.0
177179 import_incr = (power .grid_import_power * interval_hours ) / 1000 if power .grid_import_power >= MIN_POWER_THRESHOLD else 0.0
178- savings_incr = max (0.0 , (home_incr + ev_incr ) - import_incr )
179- if savings_incr > 0.0 :
180- self ._accumulate_cost ("cost_savings" , today , month_key , year_key , savings_incr * self ._import_rate )
180+ discharge_incr = (power .battery_discharge_power * interval_hours ) / 1000 if power .battery_discharge_power >= MIN_POWER_THRESHOLD else 0.0
181+ # Solar self-consumed = total consumption minus what came from grid or battery discharge
182+ solar_self_consumed = max (0.0 , (home_incr + ev_incr ) - import_incr - discharge_incr )
183+ if solar_self_consumed > 0.0 :
184+ self ._accumulate_cost ("cost_savings" , today , month_key , year_key , solar_self_consumed * self ._import_rate )
181185
182186 # Sanity checks — warn and cap if values exceed physical limits
183187 battery_capacity = self .config .get ("battery_capacity_kwh" , 15 )
@@ -603,6 +607,7 @@ def calculate_costs(self, energy: EnergyTotals) -> CostData:
603607 costs .monthly_export_revenue = self ._get_monthly_cost ("cost_export" , month_key )
604608 costs .monthly_net_cost = round (costs .monthly_costs - costs .monthly_export_revenue , 2 )
605609 costs .monthly_savings = max (0 , self ._get_monthly_cost ("cost_savings" , month_key ))
610+ costs .monthly_battery_savings = self ._get_monthly_cost ("cost_batt_savings" , month_key )
606611
607612 # Yearly calculations
608613 costs .yearly_costs = self ._get_yearly_cost ("cost_import" , year_key )
@@ -817,11 +822,13 @@ def _snapshot_daily_costs(self, today: date) -> None:
817822 self ._accumulated_self_consumed_kwh += daily_self_consumed
818823 self ._accumulated_export_kwh += daily_grid_export
819824
820- # Store today's rate for averaging
825+ # Store today's rate for averaging; also record whether snapshot had meaningful data
826+ # (used by _check_rollover to detect trivial snapshots that should be retried)
821827 self ._rate_history .append ({
822828 "date" : today_str ,
823829 "import_rate" : self ._import_rate ,
824830 "export_rate" : self ._export_rate ,
831+ "energy_kwh" : round (daily_solar + daily_grid_import , 4 ),
825832 })
826833
827834 def _check_rollover (self , today : date , month_key : str , year_key : str = None ) -> None :
@@ -838,9 +845,13 @@ def _check_rollover(self, today: date, month_key: str, year_key: str = None) ->
838845 k .endswith (yesterday_str ) and not k .startswith ("ev_daily_sun" )
839846 for k in self ._daily_accumulators
840847 )
841- already_snapshotted = any (
842- r .get ("date" ) == yesterday_str for r in self ._rate_history
848+ # A prior snapshot is only considered valid if it captured non-zero energy.
849+ # If the system restarted around midnight and snapshotted before real data
850+ # accumulated, allow a re-snapshot when meaningful data is now present. (#225)
851+ prior_snapshot = next (
852+ (r for r in self ._rate_history if r .get ("date" ) == yesterday_str ), None
843853 )
854+ already_snapshotted = prior_snapshot is not None and prior_snapshot .get ("energy_kwh" , 1.0 ) > 0
844855 if has_yesterday_data and not already_snapshotted :
845856 self ._snapshot_daily_costs (yesterday )
846857
0 commit comments