@@ -44,7 +44,7 @@ def flexible_tariff_module(self, value: TypingOptional[ConfigurableFlexibleTarif
4444 (self ._flexible_tariff_module and value and
4545 self ._flexible_tariff_module .config .name != value .config .name )):
4646 self .data .electricity_pricing .flexible_tariff .get = PricingGet ()
47- self ._reset_state (self .data .electricity_pricing .flexible_tariff , "flexible_tariff" )
47+ self ._reset_state (self .data .electricity_pricing .flexible_tariff )
4848 self ._flexible_tariff_module = value
4949 self ._set_ep_configured ()
5050
@@ -55,9 +55,10 @@ def grid_fee_module(self) -> TypingOptional[ConfigurableGridFee]:
5555 @grid_fee_module .setter
5656 def grid_fee_module (self , value : TypingOptional [ConfigurableGridFee ]):
5757 if (value is None or
58- (self ._grid_fee_module and value and self ._grid_fee_module .config .name != value .config .name )):
58+ (self ._grid_fee_module and value and
59+ self ._grid_fee_module .config .name != value .config .name )):
5960 self .data .electricity_pricing .grid_fee .get = PricingGet ()
60- self ._reset_state (self .data .electricity_pricing .grid_fee , "grid_fee" )
61+ self ._reset_state (self .data .electricity_pricing .grid_fee )
6162 self ._grid_fee_module = value
6263 self ._set_ep_configured ()
6364
@@ -69,15 +70,15 @@ def _set_ep_configured(self):
6970 self .data .electricity_pricing .configured = False
7071 Pub ().pub ("openWB/set/optional/ep/configured" , False )
7172
72- def _reset_state (self , module : Union [FlexibleTariff , GridFee ], module_name : str ):
73+ def _reset_state (self , module : Union [FlexibleTariff , GridFee ]):
7374 if (module .get .fault_state != 0 or module .get .fault_str != NO_ERROR ):
7475 module .get .fault_state = 0
7576 module .get .fault_str = NO_ERROR
76- Pub ().pub (f"openWB/set/optional/ep/{ module_name } /get/fault_state" , 0 )
77- Pub ().pub (f"openWB/set/optional/ep/{ module_name } /get/fault_str" , NO_ERROR )
78- Pub ().pub (f"openWB/set/optional/ep/{ module_name } /get/prices" , {})
77+ Pub ().pub (f"openWB/set/optional/ep/{ module .name } /get/fault_state" , 0 )
78+ Pub ().pub (f"openWB/set/optional/ep/{ module .name } /get/fault_str" , NO_ERROR )
79+ Pub ().pub (f"openWB/set/optional/ep/{ module .name } /get/prices" , {})
80+ Pub ().pub (f"openWB/set/optional/ep/{ module .name } /get/next_query_time" , None )
7981 Pub ().pub ("openWB/set/optional/ep/get/prices" , {})
80- Pub ().pub ("openWB/set/optional/ep/get/next_query_time" , None )
8182
8283 def monitoring_start (self ):
8384 if self .monitoring_module is not None :
@@ -104,7 +105,7 @@ def ep_is_charging_allowed_hours_list(self, selected_hours: list[int]) -> bool:
104105 if self .data .electricity_pricing .configured :
105106 return self .__get_current_timeslot_start () in selected_hours
106107 else :
107- log .info ("Prüfe strompreisbasiertes Laden: Nicht konfiguriert" )
108+ log .debug ("Prüfe strompreisbasiertes Laden: Nicht konfiguriert" )
108109 return False
109110 except Exception as e :
110111 log .exception (f"Fehler im Optional-Modul: { e } " )
@@ -144,14 +145,13 @@ def __get_first_entry(self) -> tuple[str, float]:
144145 return timestamp , first
145146
146147 def remove_outdated_prices (self ):
147- def remove (price_data : Dict ) -> Dict :
148- price_timeslot_seconds = self .__calculate_price_timeslot_length (price_data )
148+ def remove (price_data : Dict , last_active_timestamp : int = 0 ) -> Dict :
149149 now = timecheck .create_timestamp ()
150- return {
151- price [ 0 ]: price [ 1 ]
152- for price in price_data .items ()
153- if float ( price [ 0 ]) > now - ( price_timeslot_seconds - 1 )
154- }
150+ first_timestamp = ( max ([ timestamp for timestamp in price_data . keys ()
151+ if float ( timestamp ) <= now ], default = 0 ))
152+ return { int ( timestamp ): price for timestamp , price in price_data .items ()
153+ if ( timestamp ) >= first_timestamp and
154+ ( int ( timestamp ) <= last_active_timestamp if last_active_timestamp > 0 else True ) }
155155
156156 try :
157157 if self .data .electricity_pricing .configured :
@@ -162,7 +162,10 @@ def remove(price_data: Dict) -> Dict:
162162 if self ._flexible_tariff_module :
163163 Pub ().pub (f"{ MQTT_PREFIX } /flexible_tariff/get/prices" , remove (ep .flexible_tariff .get .prices ))
164164 if self ._grid_fee_module :
165- Pub ().pub (f"{ MQTT_PREFIX } /grid_fee/get/prices" , remove (ep .grid_fee .get .prices ))
165+ Pub ().pub (f"{ MQTT_PREFIX } /grid_fee/get/prices" ,
166+ remove (ep .grid_fee .get .prices ,
167+ last_active_timestamp = int (max (ep .get .prices .keys ()))
168+ if ep .get .prices else 0 ))
166169 except Exception as e :
167170 log .exception ("Fehler beim Entfernen veralteter Preise: %s" , e )
168171
@@ -178,7 +181,7 @@ def ep_get_current_price(self) -> float:
178181 raise Exception ("Kein Anbieter für strompreisbasiertes Laden konfiguriert." )
179182
180183 def __calculate_price_timeslot_length (self , prices : dict ) -> int :
181- first_timestamps = list (prices .keys ())[:2 ]
184+ first_timestamps = sorted ( list (prices .keys () ))[:2 ]
182185 return float (first_timestamps [1 ]) - float (first_timestamps [0 ])
183186
184187 def ep_get_loading_hours (self , duration : float , remaining_time : float ) -> List [int ]:
@@ -197,7 +200,12 @@ def ep_get_loading_hours(self, duration: float, remaining_time: float) -> List[i
197200 raise Exception ("Kein Anbieter für strompreisbasiertes Laden konfiguriert." )
198201 try :
199202 prices = self .data .electricity_pricing .get .prices
203+ log .debug ("Berechne günstige Zeit-Slots für strompreisbasiertes Laden, "
204+ "benötigte Ladezeit: %.2f Sekunden, Restzeit bis Termin: %.2f Sekunden" ,
205+ duration , remaining_time )
206+ log .debug ("Verfügbare Preise: %s" , prices )
200207 price_timeslot_seconds = self .__calculate_price_timeslot_length (prices )
208+ log .debug ("Preis-Zeitslot-Länge: %.2f Sekunden" , price_timeslot_seconds )
201209 now = timecheck .create_timestamp ()
202210 price_candidates = {
203211 timestamp : price
@@ -214,43 +222,47 @@ def ep_get_loading_hours(self, duration: float, remaining_time: float) -> List[i
214222 duration ,
215223 datetime .fromtimestamp (now ),
216224 datetime .fromtimestamp (now + remaining_time ),
217- datetime .fromtimestamp (float (min (price_candidates ))),
218- datetime .fromtimestamp (float (max (price_candidates ))+ price_timeslot_seconds ))
225+ datetime .fromtimestamp (float (min (price_candidates , default = 0 ))),
226+ datetime .fromtimestamp (float (max (price_candidates , default = 0 ))+ price_timeslot_seconds ))
219227 ordered_by_date_reverse = reversed (sorted (price_candidates .items (), key = lambda x : x [0 ]))
220228 ordered_by_price = sorted (ordered_by_date_reverse , key = lambda x : x [1 ])
221229 selected_time_slots = {float (i [0 ]): float (i [1 ])
222230 for i in ordered_by_price [:1 + ceil (duration / price_timeslot_seconds )]}
223231 selected_lenght = (
224232 price_timeslot_seconds * (len (selected_time_slots )- 1 ) -
225- (float (now ) - min (selected_time_slots ))
233+ (float (now ) - min (selected_time_slots , default = now ))
226234 )
227235 return sorted (selected_time_slots .keys ()
228- if not (min (selected_time_slots ) > now or duration <= selected_lenght )
236+ if not (min (selected_time_slots , default = 0 ) > now or duration <= selected_lenght )
229237 else [timestamp [0 ] for timestamp in iter (selected_time_slots .items ())][:- 1 ]
230238 )
231239 # if sum() sorted([int(i[0]) for i in ordered_by_price][:ceil(duration/price_timeslot_seconds)])
232240 except Exception as e :
233241 log .exception ("Fehler im Optional-Modul: %s" , e )
234242 return []
235243
244+ def _is_et_price_update_required_for_module (self , module : Union [FlexibleTariff , GridFee ]) -> bool :
245+ if module is None :
246+ return False
247+ if module .get .next_query_time is None :
248+ return True
249+ now = timecheck .create_timestamp ()
250+ next_query_formatted = datetime .fromtimestamp (module .get .next_query_time ).strftime ("%Y%m%d-%H:%M:%S" )
251+ if now > module .get .next_query_time :
252+ log .debug (f'Wartezeit { next_query_formatted } für { module .name } abgelaufen, Strompreise werden abgefragt' )
253+ return True
254+ else :
255+ log .debug (f'Nächster Abruf der { module .name } Strompreise { next_query_formatted } .' )
256+ return False
257+
236258 def et_price_update_required (self ) -> bool :
237259 self ._set_ep_configured ()
238260 if self .data .electricity_pricing .configured is False :
239261 return False
240262 if len (self .data .electricity_pricing .get .prices ) == 0 :
241263 return True
242- if self .data .electricity_pricing .get .next_query_time is None :
243- return True
244- if timecheck .create_timestamp () > self .data .electricity_pricing .get .next_query_time :
245- next_query_formatted = datetime .fromtimestamp (
246- self .data .electricity_pricing .get .next_query_time ).strftime ("%Y%m%d-%H:%M:%S" )
247- log .info (f'Wartezeit { next_query_formatted } abgelaufen, Strompreise werden abgefragt' )
248- return True
249- else :
250- next_query_formatted = datetime .fromtimestamp (
251- self .data .electricity_pricing .get .next_query_time ).strftime ("%Y%m%d-%H:%M:%S" )
252- log .info (f'Nächster Abruf der Strompreise { next_query_formatted } .' )
253- return False
264+ return (self ._is_et_price_update_required_for_module (self .data .electricity_pricing .flexible_tariff ) or
265+ self ._is_et_price_update_required_for_module (self .data .electricity_pricing .grid_fee ))
254266
255267 def ocpp_transfer_meter_values (self ):
256268 try :
0 commit comments