Skip to content

Commit

Permalink
Merge pull request #1431 from LKuemmel/fix
Browse files Browse the repository at this point in the history
Bugfixes
  • Loading branch information
LKuemmel authored Feb 21, 2024
2 parents 5347e2a + 97240fa commit c887be5
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 25 deletions.
2 changes: 1 addition & 1 deletion packages/control/algorithm/filter_chargepoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def _get_preferenced_chargepoint(valid_chargepoints: List[Chargepoint]) -> List:
for cp in chargepoints.keys())
elif condition_types[condition] == "soc":
chargepoints.update(
(cp, cp.data.set.charging_ev_data.data.get.soc) for cp in chargepoints.keys())
(cp, cp.data.set.charging_ev_data.data.get.soc or 0) for cp in chargepoints.keys())
elif condition_types[condition] == "plug_in":
chargepoints.update((cp, cp.data.set.plug_time)
for cp in chargepoints.keys())
Expand Down
41 changes: 25 additions & 16 deletions packages/control/ev.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ def set_factory() -> Set:

@dataclass
class Get:
soc: int = 0
soc_timestamp: float = 0
soc: Optional[int] = None
soc_timestamp: Optional[float] = None
force_soc_update: bool = False
range: float = 0
range: Optional[float] = None
fault_state: int = 0
fault_str: str = ""

Expand Down Expand Up @@ -568,7 +568,7 @@ def __init__(self, index):
TIME_CHARGING_AMOUNT_REACHED = "Kein Zeitladen, da die Energiemenge bereits geladen wurde."

def time_charging(self,
soc: float,
soc: Optional[float],
used_amount_time_charging: float) -> Tuple[int, str, Optional[str], Optional[str]]:
""" prüft, ob ein Zeitfenster aktiv ist und setzt entsprechend den Ladestrom
"""
Expand All @@ -583,10 +583,13 @@ def time_charging(self,
if plan.limit.selected == "none": # kein Limit konfiguriert, mit konfigurierter Stromstärke laden
return plan.current, "time_charging", message, plan.name
elif plan.limit.selected == "soc": # SoC Limit konfiguriert
if soc < plan.limit.soc:
return plan.current, "time_charging", message, plan.name # Limit nicht erreicht
if soc:
if soc < plan.limit.soc:
return plan.current, "time_charging", message, plan.name # Limit nicht erreicht
else:
return 0, "stop", self.TIME_CHARGING_SOC_REACHED, plan.name # Limit erreicht
else:
return 0, "stop", self.TIME_CHARGING_SOC_REACHED, plan.name # Limit erreicht
return plan.current, "time_charging", message, plan.name
elif plan.limit.selected == "amount": # Energiemengenlimit konfiguriert
if used_amount_time_charging < plan.limit.amount:
return plan.current, "time_charging", message, plan.name # Limit nicht erreicht
Expand All @@ -608,7 +611,7 @@ def time_charging(self,
INSTANT_CHARGING_AMOUNT_REACHED = "Kein Sofortladen, da die Energiemenge bereits geladen wurde."

def instant_charging(self,
soc: float,
soc: Optional[float],
imported_instant_charging: float) -> Tuple[int, str, Optional[str]]:
""" prüft, ob die Lademengenbegrenzung erreicht wurde und setzt entsprechend den Ladestrom.
"""
Expand All @@ -621,10 +624,13 @@ def instant_charging(self,
if instant_charging.limit.selected == "none":
return instant_charging.current, "instant_charging", message
elif instant_charging.limit.selected == "soc":
if soc < instant_charging.limit.soc:
return instant_charging.current, "instant_charging", message
if soc:
if soc < instant_charging.limit.soc:
return instant_charging.current, "instant_charging", message
else:
return 0, "stop", self.INSTANT_CHARGING_SOC_REACHED
else:
return 0, "stop", self.INSTANT_CHARGING_SOC_REACHED
return instant_charging.current, "instant_charging", message
elif instant_charging.limit.selected == "amount":
if imported_instant_charging < self.data.chargemode.instant_charging.limit.amount:
return instant_charging.current, "instant_charging", message
Expand All @@ -638,14 +644,14 @@ def instant_charging(self,

PV_CHARGING_SOC_REACHED = "Keine Ladung, da der maximale Soc bereits erreicht wurde."

def pv_charging(self, soc: float, min_current: int) -> Tuple[int, str, Optional[str]]:
def pv_charging(self, soc: Optional[float], min_current: int) -> Tuple[int, str, Optional[str]]:
""" prüft, ob Min-oder Max-Soc erreicht wurden und setzt entsprechend den Ladestrom.
"""
message = None
try:
pv_charging = self.data.chargemode.pv_charging
if soc < pv_charging.max_soc:
if pv_charging.min_soc != 0:
if soc is None or soc < pv_charging.max_soc:
if pv_charging.min_soc != 0 and soc is not None:
if soc < pv_charging.min_soc:
return pv_charging.min_soc_current, "instant_charging", message
if pv_charging.min_current == 0:
Expand Down Expand Up @@ -739,12 +745,15 @@ def search_plan(self,

def calculate_duration(self,
plan: ScheduledChargingPlan,
soc: float,
soc: Optional[float],
battery_capacity: float,
used_amount: float,
phases: int) -> Tuple[float, float]:
if plan.limit.selected == "soc":
missing_amount = ((plan.limit.soc_scheduled - soc) / 100) * battery_capacity
if soc:
missing_amount = ((plan.limit.soc_scheduled - soc) / 100) * battery_capacity
else:
raise ValueError("Um Zielladen mit SoC-Ziel nutzen zu können, bitte ein SoC-Modul konfigurieren.")
else:
missing_amount = plan.limit.amount - used_amount
duration = missing_amount/(plan.current * phases*230) * 3600
Expand Down
40 changes: 32 additions & 8 deletions packages/control/ev_charge_template_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from control.ev import ChargeTemplate, EvTemplate, EvTemplateData, SelectedPlan
from control.general import General
from helpermodules import timecheck
from helpermodules.abstract_plans import ScheduledChargingPlan, TimeChargingPlan
from helpermodules.abstract_plans import Limit, ScheduledChargingPlan, TimeChargingPlan


@pytest.fixture(autouse=True)
Expand All @@ -21,13 +21,35 @@ def data_module() -> None:

@pytest.mark.parametrize(
"plans, soc, used_amount_time_charging, plan_found, expected",
[pytest.param({}, 0, 0, None, (0, "stop", ChargeTemplate.TIME_CHARGING_NO_PLAN_CONFIGURED, None),
id="no plan defined"),
pytest.param({"0": TimeChargingPlan()}, 0, 0, None,
(0, "stop", ChargeTemplate.TIME_CHARGING_NO_PLAN_ACTIVE, None), id="no plan active"),
pytest.param({"0": TimeChargingPlan()}, 0, 0, TimeChargingPlan(),
(16, "time_charging", None, "Zeitladen-Standard"), id="plan active")
])
[
pytest.param({}, 0, 0, None, (0, "stop", ChargeTemplate.TIME_CHARGING_NO_PLAN_CONFIGURED, None),
id="no plan defined"),
pytest.param({"0": TimeChargingPlan()}, 0, 0, None,
(0, "stop", ChargeTemplate.TIME_CHARGING_NO_PLAN_ACTIVE, None), id="no plan active"),
pytest.param({"0": TimeChargingPlan()}, 0, 0, TimeChargingPlan(),
(16, "time_charging", None, "Zeitladen-Standard"), id="plan active"),
pytest.param({"0": TimeChargingPlan(limit=Limit(selected="soc"))}, 100, 0,
TimeChargingPlan(limit=Limit(selected="soc")),
(0, "stop", ChargeTemplate.TIME_CHARGING_SOC_REACHED, "Zeitladen-Standard"),
id="plan active, soc is reached"),
pytest.param({"0": TimeChargingPlan(limit=Limit(selected="soc"))}, 40, 0,
TimeChargingPlan(limit=Limit(selected="soc")),
(16, "time_charging", None, "Zeitladen-Standard"), id="plan active, soc is not reached"),
pytest.param({"0": TimeChargingPlan(limit=Limit(selected="soc"))}, None, 0,
TimeChargingPlan(limit=Limit(selected="soc")),
(16, "time_charging", None, "Zeitladen-Standard"), id="plan active, soc is not defined"),
pytest.param({"0": TimeChargingPlan(limit=Limit(selected="amount"))}, 0, 1500,
TimeChargingPlan(limit=Limit(selected="amount")),
(0, "stop", ChargeTemplate.TIME_CHARGING_AMOUNT_REACHED, "Zeitladen-Standard"),
id="plan active, used_amount_time_charging is reached"),
pytest.param({"0": TimeChargingPlan(limit=Limit(selected="amount"))}, 0, 500,
TimeChargingPlan(limit=Limit(selected="amount")),
(16, "time_charging", None, "Zeitladen-Standard"),
id="plan active, used_amount_time_charging is not reached"),
pytest.param({"0": TimeChargingPlan()}, 0, 0, None,
(0, "stop", ChargeTemplate.TIME_CHARGING_NO_PLAN_ACTIVE, None), id="plan defined but not found"),
]
)
def test_time_charging(plans: Dict[int, TimeChargingPlan], soc: float, used_amount_time_charging: float,
plan_found: TimeChargingPlan,
expected: Tuple[int, str, Optional[str], Optional[str]],
Expand All @@ -49,6 +71,7 @@ def test_time_charging(plans: Dict[int, TimeChargingPlan], soc: float, used_amou
"selected, current_soc, used_amount, expected",
[
pytest.param("none", 0, 0, (10, "instant_charging", None), id="without limit"),
pytest.param("soc", None, 0, (10, "instant_charging", None), id="limit soc: soc not defined"),
pytest.param("soc", 49, 0, (10, "instant_charging", None), id="limit soc: soc not reached"),
pytest.param("soc", 50, 0, (0, "stop", ChargeTemplate.INSTANT_CHARGING_SOC_REACHED),
id="limit soc: soc reached"),
Expand Down Expand Up @@ -77,6 +100,7 @@ def test_instant_charging(selected: str, current_soc: float, used_amount: float,
ChargeTemplate.PV_CHARGING_SOC_REACHED), id="max soc reached"),
pytest.param(15, 0, 14, SwitchOnBatState.CHARGE_FROM_BAT,
(10, "instant_charging", None), id="min soc not reached"),
pytest.param(15, 0, None, SwitchOnBatState.CHARGE_FROM_BAT, (6, "pv_charging", None), id="soc not defined"),
pytest.param(15, 8, 15, SwitchOnBatState.CHARGE_FROM_BAT,
(8, "instant_charging", None), id="min current configured"),
pytest.param(15, 8, 15, SwitchOnBatState.SWITCH_OFF_SOC_REACHED, (0, "stop",
Expand Down
2 changes: 2 additions & 0 deletions packages/helpermodules/scale_metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@


def scale_metric(value: Union[float, int], metric: Optional[str], base_metric: str):
if value is None:
return value

# If no unit or too short unit or the base unit is not matching, return the unmodified value
# This is crucial for fallback cases where no unit is given at all
Expand Down
3 changes: 3 additions & 0 deletions packages/modules/update_soc.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ def _get_threads(self) -> Tuple[List[Thread], List[Thread]]:
if ev.data.get.fault_state != 0 or ev.data.get.fault_str != NO_ERROR:
Pub().pub(f"openWB/set/vehicle/{ev.num}/get/fault_state", 0)
Pub().pub(f"openWB/set/vehicle/{ev.num}/get/fault_str", NO_ERROR)
Pub().pub(f"openWB/set/vehicle/{ev.num}/get/soc", None)
Pub().pub(f"openWB/set/vehicle/{ev.num}/get/soc_timestamp", None)
Pub().pub(f"openWB/set/vehicle/{ev.num}/get/range", None)
except Exception:
log.exception("Fehler im update_soc-Modul")
return threads_update, threads_store
Expand Down

0 comments on commit c887be5

Please sign in to comment.