@@ -80,7 +80,6 @@ def _start(self) -> None:
80
80
next_price_minimum = self .tibber_api_handler .get_next_price_minimum (first_iteration )
81
81
first_iteration = False
82
82
else :
83
- self .write_newlines_to_log_file ()
84
83
next_price_minimum = self ._do_iteration (next_price_minimum )
85
84
86
85
if next_price_minimum .has_to_be_rechecked :
@@ -124,13 +123,19 @@ def _do_iteration(self, current_energy_rate: EnergyRate) -> EnergyRate:
124
123
- Sets the maximum charging duration of the current energy rate.
125
124
- Gets the current state of the inverter.
126
125
- Gets the average power consumption.
127
- - Calculates the estimated minimum state of charge until the next price minimum.
128
- - If the estimated minimum state of charge is lower than the target minimum state of charge, the method
129
- calculates the required state of charge to reach the target minimum state of charge and initiates charging.
126
+ - Calculates the estimated minimum and maximum state of charge until the next price minimum.
127
+ - If the next price minimum is higher than the current one
128
+ - If the estimated minimum state of charge is higher than the target minimum state of charge no charging is
129
+ initiated.
130
+ - Else the method calculates the required state of charge to reach the target minimum state of charge and
131
+ start charging.
132
+ - Else the method calculates how much power can be bought such that no energy of the sun is wasted.
133
+ "Wasted" being the energy is sold instead of used to charge the battery.
130
134
131
135
Returns:
132
136
EnergyRate: The next price minimum energy rate.
133
137
"""
138
+ self .write_newlines_to_log_file ()
134
139
self .log .info (
135
140
"Waiting is over, now is the a price minimum. Checking what has to be done to reach the next minimum..."
136
141
)
@@ -145,77 +150,89 @@ def _do_iteration(self, current_energy_rate: EnergyRate) -> EnergyRate:
145
150
f"{ current_energy_rate .maximum_charging_duration } "
146
151
)
147
152
148
- if next_price_minimum > current_energy_rate :
149
- # Information is unused at the moment
150
- self .log .info ("The price of the upcoming minimum is higher than the current energy rate" )
151
-
152
153
current_state_of_charge = self .inverter .get_state_of_charge ()
153
154
self .log .info (f"The battery is currently is at { current_state_of_charge } " )
154
155
155
156
average_power_consumption = self ._get_average_power_consumption ()
156
157
self .log .info (f"The average power consumption is { average_power_consumption } " )
157
158
158
- minimum_of_soc_until_next_price_minimum = self ._get_minimum_of_soc_until_next_price_minimum (
159
- next_price_minimum .timestamp ,
160
- average_power_consumption ,
161
- current_state_of_charge ,
162
- next_price_minimum .has_to_be_rechecked ,
163
- )
164
- self .log .info (
165
- f"The expected minimum of state of charge until the next price minimum with the current state of charge is "
166
- f"{ minimum_of_soc_until_next_price_minimum } "
167
- )
168
-
169
159
target_min_soc = StateOfCharge .from_percentage (
170
160
int (EnvironmentVariableGetter .get ("INVERTER_TARGET_MIN_STATE_OF_CHARGE" , 15 ))
171
161
)
172
162
self .log .info (f"The battery shall be at least at { target_min_soc } at all times" )
173
163
164
+ target_max_soc = StateOfCharge .from_percentage (
165
+ int (EnvironmentVariableGetter .get ("INVERTER_TARGET_MAX_STATE_OF_CHARGE" , 95 ))
166
+ )
167
+ self .log .info (f"The battery shall be at most be charged up to { target_max_soc } " )
168
+
169
+ minimum_of_soc_until_next_price_minimum , maximum_of_soc_until_next_price_minimum = (
170
+ self .sun_forecast_handler .calculate_min_and_max_of_soc_in_timeframe (
171
+ timestamp_now ,
172
+ next_price_minimum .timestamp ,
173
+ average_power_consumption ,
174
+ current_state_of_charge ,
175
+ next_price_minimum .has_to_be_rechecked ,
176
+ )
177
+ )
178
+ self .log .info (
179
+ f"The expected minimum of state of charge until the next price minimum with the current state of charge is "
180
+ f"{ minimum_of_soc_until_next_price_minimum } , "
181
+ f"the expected maximum is { maximum_of_soc_until_next_price_minimum } "
182
+ )
183
+
174
184
summary_of_energy_vales = {
175
185
"timestamp now" : str (timestamp_now ),
176
186
"next price minimum" : next_price_minimum ,
177
- "minimum_has_to_be_rechecked " : next_price_minimum .has_to_be_rechecked ,
187
+ "next price minimum has to be rechecked " : next_price_minimum .has_to_be_rechecked ,
178
188
"maximum charging duration" : current_energy_rate .format_maximum_charging_duration (),
179
189
"current state of charge" : current_state_of_charge ,
180
190
"average power consumption" : average_power_consumption .watts ,
181
- "minimum of soc until next price minimum" : minimum_of_soc_until_next_price_minimum ,
182
191
"target min soc" : target_min_soc ,
192
+ "target max soc" : target_max_soc ,
193
+ "minimum of soc until next price minimum" : minimum_of_soc_until_next_price_minimum ,
194
+ "maximum of soc until next price minimum" : maximum_of_soc_until_next_price_minimum ,
183
195
}
184
196
self .log .debug (f"Summary of energy values: { summary_of_energy_vales } " )
185
197
186
- if minimum_of_soc_until_next_price_minimum > target_min_soc :
198
+ if current_energy_rate > next_price_minimum :
187
199
self .log .info (
188
- "The expected minimum state of charge until the next price minimum without additional charging "
189
- "is higher than the target minimum state of charge --> There is no need to charge"
200
+ f"The price of the current minimum ({ next_price_minimum .rate } ct/kWh) is higher than the one of "
201
+ f"the upcoming minimum ({ current_energy_rate .rate } ct/kWh) "
202
+ "--> Will only charge the battery to reach the next price minimum"
190
203
)
191
- self .iteration_cache = {}
192
- return next_price_minimum
204
+ if minimum_of_soc_until_next_price_minimum > target_min_soc :
205
+ self .log .info (
206
+ "The expected minimum state of charge until the next price minimum without additional charging "
207
+ "is higher than the target minimum state of charge --> There is no need to charge"
208
+ )
209
+ self .iteration_cache = {}
210
+ return next_price_minimum
193
211
194
- required_state_of_charge = current_state_of_charge + (target_min_soc - minimum_of_soc_until_next_price_minimum )
195
- self .log .info (f"There is a need to charge to { required_state_of_charge } (from { current_state_of_charge } )" )
196
- maximum_possible_state_of_charge = StateOfCharge .from_percentage (100 )
197
- if required_state_of_charge > maximum_possible_state_of_charge :
212
+ charging_target_soc = current_state_of_charge + (target_min_soc - minimum_of_soc_until_next_price_minimum )
213
+ else :
198
214
self .log .info (
199
- "The target state of charge is higher than possible "
200
- f"--> Setting it to { maximum_possible_state_of_charge } "
215
+ f"The price of the upcoming minimum ({ next_price_minimum .rate } ct/kWh) is higher than the one of "
216
+ f"the current minimum ({ current_energy_rate .rate } ct/kWh)"
217
+ "--> Will charge as much as possible without wasting any energy of the sun"
218
+ )
219
+ charging_target_soc = current_state_of_charge + (
220
+ StateOfCharge .from_percentage (100 ) - maximum_of_soc_until_next_price_minimum
201
221
)
202
- required_state_of_charge = maximum_possible_state_of_charge
222
+ self . log . info ( f"The calculated target state of charge is { charging_target_soc } " )
203
223
204
- max_target_soc = StateOfCharge .from_percentage (
205
- int (EnvironmentVariableGetter .get ("INVERTER_TARGET_MAX_STATE_OF_CHARGE" , 95 ))
206
- )
207
- if required_state_of_charge > max_target_soc :
224
+ if charging_target_soc > target_max_soc :
208
225
self .log .info (
209
226
"The target state of charge is more than the maximum allowed charge set in the environment "
210
- f"--> Setting it to { max_target_soc } "
227
+ f"--> Setting it to { target_max_soc } "
211
228
)
212
- required_state_of_charge = max_target_soc
229
+ charging_target_soc = target_max_soc
213
230
214
231
energy_bought_before_charging = self .sems_portal_api_handler .get_energy_buy ()
215
232
timestamp_starting_to_charge = TimeHandler .get_time ()
216
233
self .log .debug (f"The amount of energy bought before charging is { energy_bought_before_charging } " )
217
234
218
- self ._charge_inverter (required_state_of_charge , current_energy_rate .maximum_charging_duration )
235
+ self ._charge_inverter (charging_target_soc , current_energy_rate .maximum_charging_duration )
219
236
220
237
timestamp_ending_to_charge = TimeHandler .get_time ()
221
238
@@ -408,30 +425,6 @@ def _get_average_power_consumption(self) -> Power:
408
425
self ._set_cache_key (cache_key , average_power_consumption )
409
426
return average_power_consumption
410
427
411
- def _get_minimum_of_soc_until_next_price_minimum (
412
- self ,
413
- next_price_minimum_timestamp : datetime ,
414
- average_power_consumption : Power ,
415
- current_soc : StateOfCharge ,
416
- minimum_has_to_rechecked : bool ,
417
- ) -> StateOfCharge :
418
- cache_key = "minimum_of_soc_until_next_price_minimum"
419
- minimum_of_soc_until_next_price_minimum = self ._get_value_from_cache_if_exists (cache_key )
420
- if minimum_of_soc_until_next_price_minimum :
421
- return minimum_of_soc_until_next_price_minimum
422
-
423
- minimum_of_soc_until_next_price_minimum , _ = (
424
- self .sun_forecast_handler .calculate_minimum_of_soc_and_power_generation_in_timeframe (
425
- TimeHandler .get_time (),
426
- next_price_minimum_timestamp ,
427
- average_power_consumption ,
428
- current_soc ,
429
- minimum_has_to_rechecked ,
430
- )
431
- )
432
- self ._set_cache_key (cache_key , minimum_of_soc_until_next_price_minimum )
433
- return minimum_of_soc_until_next_price_minimum
434
-
435
428
def _get_value_from_cache_if_exists (self , cache_key : str ) -> Optional [Any ]:
436
429
if cache_key not in self .iteration_cache .keys ():
437
430
return None
0 commit comments