3838DELAY_EVALUATION_BY_SECONDS = 15 # Delay evaluation for x seconds at every trigger
3939# Interval between evaluations in seconds
4040TIME_BETWEEN_EVALUATIONS = EVALUATIONS_EVERY_MINUTES * 60
41+
42+
43+ def _to_float (value ) -> float :
44+ """ Convert a config or API value to float, handling European comma decimal notation.
45+ Args:
46+ value: The value to convert. Can be a float, int, or string
47+ (including European notation like '0,9').
48+ Returns:
49+ float: The converted value.
50+ Raises:
51+ ValueError: If the value cannot be converted to float.
52+ """
53+ if isinstance (value , str ):
54+ return float (value .replace (',' , '.' ))
55+ return float (value )
56+
57+
4158TIME_BETWEEN_UTILITY_API_CALLS = 900 # 15 Minutes
4259MIN_FORECAST_HOURS = 1 # Minimum required forecast hours
4360FORECAST_TOLERANCE = 3 # Acceptable tolerance for forecast hours
@@ -60,7 +77,8 @@ def __init__(self, configdict: dict):
6077 # -1 = charge from grid , 0 = avoid discharge , 8 = limit battery charge, 10 = discharge allowed
6178 self .last_mode = None
6279 self .last_charge_rate = 0
63- self ._limit_battery_charge_rate = - 1 # Dynamic battery charge rate limit (-1 = no limit)
80+ # Dynamic battery charge rate limit (-1 = no limit)
81+ self ._limit_battery_charge_rate = - 1
6482 self .last_prices = None
6583 self .last_consumption = None
6684 self .last_production = None
@@ -155,7 +173,8 @@ def __init__(self, configdict: dict):
155173 'max_pv_charge_rate' ,
156174 getattr (self .inverter , 'max_pv_charge_rate' , 0 ),
157175 )
158- self .min_pv_charge_rate = config ['inverter' ].get ('min_pv_charge_rate' , 0 )
176+ self .min_pv_charge_rate = config ['inverter' ].get (
177+ 'min_pv_charge_rate' , 0 )
159178
160179 # Validate min/max PV charge rate configuration at startup
161180 if (
@@ -214,8 +233,8 @@ def __init__(self, configdict: dict):
214233 self .general_logic = CommonLogic .get_instance (
215234 charge_rate_multiplier = self .batconfig .get (
216235 'charge_rate_multiplier' , 1.1 ),
217- always_allow_discharge_limit = self .batconfig .get (
218- 'always_allow_discharge_limit' , 0.9 ),
236+ always_allow_discharge_limit = _to_float ( self .batconfig .get (
237+ 'always_allow_discharge_limit' , 0.9 )) ,
219238 max_capacity = self .inverter .get_max_capacity (),
220239 min_charge_energy = self .batconfig .get ('min_recharge_amount' , 100.0 )
221240 )
@@ -363,7 +382,8 @@ def handle_forecast_error(self):
363382
364383 def run (self ):
365384 """ Main calculation & control loop """
366- logger .debug ('Timeslots are in %d-minute intervals' , self .time_resolution )
385+ logger .debug ('Timeslots are in %d-minute intervals' ,
386+ self .time_resolution )
367387
368388 # Reset some values
369389 self .__reset_run_data ()
@@ -542,7 +562,8 @@ def run(self):
542562
543563 if inverter_settings .allow_discharge :
544564 if inverter_settings .limit_battery_charge_rate >= 0 :
545- self .limit_battery_charge_rate (inverter_settings .limit_battery_charge_rate )
565+ self .limit_battery_charge_rate (
566+ inverter_settings .limit_battery_charge_rate )
546567 else :
547568 self .allow_discharging ()
548569 elif inverter_settings .charge_from_grid :
@@ -611,7 +632,8 @@ def limit_battery_charge_rate(self, limit_charge_rate: int = 0):
611632 if self .min_pv_charge_rate > 0 and effective_limit > 0 :
612633 effective_limit = max (effective_limit , self .min_pv_charge_rate )
613634
614- logger .info ('Mode: Limit Battery Charge Rate to %d W, discharge allowed' , effective_limit )
635+ logger .info (
636+ 'Mode: Limit Battery Charge Rate to %d W, discharge allowed' , effective_limit )
615637 self .inverter .set_mode_limit_battery_charge (effective_limit )
616638 self .__set_mode (MODE_LIMIT_BATTERY_CHARGE_RATE )
617639
@@ -723,11 +745,10 @@ def set_discharge_limit(self, discharge_limit) -> None:
723745 def set_always_allow_discharge_limit (
724746 self , always_allow_discharge_limit : float ) -> None :
725747 """ Set the always allow discharge limit for battery control """
726- self . general_logic . set_always_allow_discharge_limit (
727- always_allow_discharge_limit )
748+ limit = _to_float ( always_allow_discharge_limit )
749+ self . general_logic . set_always_allow_discharge_limit ( limit )
728750 if self .mqtt_api is not None :
729- self .mqtt_api .publish_always_allow_discharge_limit (
730- always_allow_discharge_limit )
751+ self .mqtt_api .publish_always_allow_discharge_limit (limit )
731752
732753 def get_always_allow_discharge_limit (self ) -> float :
733754 """ Get the always allow discharge limit for battery control """
@@ -848,7 +869,8 @@ def api_set_limit_battery_charge_rate(self, limit: int):
848869 limit: Maximum battery charge rate in W (0 = no charging, -1 = no limit)
849870 """
850871 if limit < - 1 :
851- logger .warning ('API: Invalid limit_battery_charge_rate %d W' , limit )
872+ logger .warning (
873+ 'API: Invalid limit_battery_charge_rate %d W' , limit )
852874 return
853875
854876 logger .info ('API: Setting limit_battery_charge_rate to %d W' , limit )
0 commit comments