From e3fbfdcbe11eaedaf517868835c9d1e29ecf4256 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 27 Jan 2025 16:10:09 +0100 Subject: [PATCH 01/17] ids in charge and ev template config --- .../algorithm/additional_current_test.py | 2 +- .../algorithm/surplus_controlled_test.py | 2 +- packages/control/chargepoint/chargepoint.py | 6 +++--- packages/control/counter_test.py | 2 +- packages/control/ev/charge_template.py | 8 +++---- packages/control/ev/charge_template_test.py | 21 ++++++++++--------- packages/control/ev/ev.py | 2 +- packages/control/ev/ev_template.py | 2 +- packages/helpermodules/subdata.py | 6 +++--- packages/helpermodules/update_config.py | 19 +++++++++++++---- 10 files changed, 41 insertions(+), 29 deletions(-) diff --git a/packages/control/algorithm/additional_current_test.py b/packages/control/algorithm/additional_current_test.py index 89c552aeff..4a8904a082 100644 --- a/packages/control/algorithm/additional_current_test.py +++ b/packages/control/algorithm/additional_current_test.py @@ -30,7 +30,7 @@ def test_set_loadmangement_message(set_current, limit, expected_msg, monkeypatch): # setup ev = Ev(0) - ev.charge_template = ChargeTemplate(0) + ev.charge_template = ChargeTemplate() cp1 = Chargepoint(1, None) cp1.data = ChargepointData(set=Set(current=set_current), control_parameter=ControlParameter(required_currents=[8]*3)) diff --git a/packages/control/algorithm/surplus_controlled_test.py b/packages/control/algorithm/surplus_controlled_test.py index 6e50210534..c36f671959 100644 --- a/packages/control/algorithm/surplus_controlled_test.py +++ b/packages/control/algorithm/surplus_controlled_test.py @@ -41,7 +41,7 @@ def test_filter_by_feed_in_limit(feed_in_limit_1: bool, # setup def setup_cp(cp: Chargepoint, feed_in_limit: bool) -> Chargepoint: ev = Ev(0) - ev.charge_template = ChargeTemplate(0) + ev.charge_template = ChargeTemplate() ev.charge_template.data.chargemode.pv_charging.feed_in_limit = feed_in_limit cp.data = ChargepointData(set=Set(charging_ev_data=ev)) return cp diff --git a/packages/control/chargepoint/chargepoint.py b/packages/control/chargepoint/chargepoint.py index 6a20efeb2a..b3c6af8a98 100644 --- a/packages/control/chargepoint/chargepoint.py +++ b/packages/control/chargepoint/chargepoint.py @@ -786,8 +786,8 @@ def _pub_connected_vehicle(self, vehicle: Ev): else: current_plan = None config_obj = ConnectedConfig( - charge_template=vehicle.charge_template.ct_num, - ev_template=vehicle.ev_template.et_num, + charge_template=vehicle.charge_template.data.id, + ev_template=vehicle.ev_template.data.id, chargemode=vehicle.charge_template.data.chargemode.selected, priority=vehicle.charge_template.data.prio, current_plan=current_plan, @@ -795,7 +795,7 @@ def _pub_connected_vehicle(self, vehicle: Ev): time_charging_in_use=True if (self.data.control_parameter.submode == "time_charging") else False) if soc_obj != self.data.get.connected_vehicle.soc: - Pub().pub("openWB/chargepoint/"+str(self.num) + + Pub().pub("openWB/chargepoint/"+str(self.data.id) + "/get/connected_vehicle/soc", dataclasses.asdict(soc_obj)) if info_obj != self.data.get.connected_vehicle.info: Pub().pub("openWB/chargepoint/"+str(self.num) + diff --git a/packages/control/counter_test.py b/packages/control/counter_test.py index 4b10d1335f..4b3e59466a 100644 --- a/packages/control/counter_test.py +++ b/packages/control/counter_test.py @@ -140,7 +140,7 @@ def test_switch_on_threshold_reached(params: Params, caplog, general_data_fixtur cp.data.control_parameter.phases = 1 cp.data.control_parameter.state = params.state cp.data.control_parameter.timestamp_switch_on_off = params.timestamp_switch_on_off - ev.data.charge_template = ChargeTemplate(0) + ev.data.charge_template = ChargeTemplate() ev.data.charge_template.data.chargemode.pv_charging.feed_in_limit = params.feed_in_limit cp.data.set.charging_ev_data = ev mock_calc_switch_on_power = Mock(return_value=[params.surplus, params.threshold]) diff --git a/packages/control/ev/charge_template.py b/packages/control/ev/charge_template.py index 988637ce73..f22ebd5048 100644 --- a/packages/control/ev/charge_template.py +++ b/packages/control/ev/charge_template.py @@ -105,6 +105,7 @@ def chargemode_factory() -> Chargemode: @dataclass class ChargeTemplateData: + id: int = 0 name: str = "Lade-Profil" prio: bool = False load_default: bool = False @@ -129,7 +130,6 @@ class SelectedPlan: class ChargeTemplate: """ Klasse der Lade-Profile """ - ct_num: int data: ChargeTemplateData = field(default_factory=charge_template_data_factory, metadata={ "topic": ""}) @@ -180,7 +180,7 @@ def time_charging(self, sub_mode = "stop" return current, sub_mode, message, id, phases except Exception: - log.exception("Fehler im ev-Modul "+str(self.ct_num)) + log.exception("Fehler im ev-Modul "+str(self.data.id)) return (0, "stop", "Keine Ladung, da da ein interner Fehler aufgetreten ist: "+traceback.format_exc(), None, 0) @@ -214,7 +214,7 @@ def instant_charging(self, message = self.AMOUNT_REACHED return current, sub_mode, message, phases except Exception: - log.exception("Fehler im ev-Modul "+str(self.ct_num)) + log.exception("Fehler im ev-Modul "+str(self.data.id)) return 0, "stop", "Keine Ladung, da da ein interner Fehler aufgetreten ist: "+traceback.format_exc(), 0 PV_CHARGING_SOC_CHARGING = ("Ladung evtl. auch ohne PV-Überschuss, da der Mindest-SoC des Fahrzeugs noch nicht " @@ -300,7 +300,7 @@ def eco_charging(self, current = min_current return current, sub_mode, message, phases except Exception: - log.exception("Fehler im ev-Modul "+str(self.ct_num)) + log.exception("Fehler im ev-Modul "+str(self.data.id)) return 0, "stop", "Keine Ladung, da ein interner Fehler aufgetreten ist: "+traceback.format_exc(), 0 def scheduled_charging_recent_plan(self, diff --git a/packages/control/ev/charge_template_test.py b/packages/control/ev/charge_template_test.py index 6592d9413d..0d37b83154 100644 --- a/packages/control/ev/charge_template_test.py +++ b/packages/control/ev/charge_template_test.py @@ -8,7 +8,7 @@ from control.chargepoint.control_parameter import ControlParameter from control.ev.charge_template import SelectedPlan from control.chargepoint.charging_type import ChargingType -from control.ev.ev import ChargeTemplate +from control.ev.charge_template import ChargeTemplate from control.ev.ev_template import EvTemplate, EvTemplateData from control.general import General from helpermodules import timecheck @@ -59,7 +59,7 @@ def test_time_charging(plans: Dict[int, TimeChargingPlan], soc: float, used_amou expected: Tuple[int, str, Optional[str], Optional[str]], monkeypatch): # setup - ct = ChargeTemplate(0) + ct = ChargeTemplate() ct.data.time_charging.plans = plans check_plans_timeframe_mock = Mock(return_value=plan_found) monkeypatch.setattr(timecheck, "check_plans_timeframe", check_plans_timeframe_mock) @@ -86,7 +86,8 @@ def test_time_charging(plans: Dict[int, TimeChargingPlan], soc: float, used_amou def test_instant_charging(selected: str, current_soc: float, used_amount: float, expected: Tuple[int, str, Optional[str]]): # setup - ct = ChargeTemplate(0) + data.data.optional_data.data.et.active = False + ct = ChargeTemplate() ct.data.chargemode.instant_charging.limit.selected = selected # execution @@ -111,7 +112,7 @@ def test_instant_charging(selected: str, current_soc: float, used_amount: float, def test_pv_charging(min_soc: int, min_current: int, limit_selected: str, current_soc: float, used_amount: float, expected: Tuple[int, str, Optional[str], int]): # setup - ct = ChargeTemplate(0) + ct = ChargeTemplate() ct.data.chargemode.pv_charging.min_soc = min_soc ct.data.chargemode.pv_charging.min_current = min_current ct.data.chargemode.pv_charging.phases_to_use = 0 @@ -143,7 +144,7 @@ def test_calc_remaining_time(phases_to_use, phase_switch_supported, expected, monkeypatch): # setup - ct = ChargeTemplate(0) + ct = ChargeTemplate() plan = ScheduledChargingPlan(phases_to_use=phases_to_use) calculate_duration_mock = Mock(side_effect=calc_duration) monkeypatch.setattr(ChargeTemplate, "_calculate_duration", calculate_duration_mock) @@ -166,7 +167,7 @@ def test_calc_remaining_time(phases_to_use, ]) def test_calculate_duration(selected: str, phases: int, expected_duration: float, expected_missing_amount: float): # setup - ct = ChargeTemplate(0) + ct = ChargeTemplate() plan = ScheduledChargingPlan() plan.limit.selected = selected # execution @@ -193,7 +194,7 @@ def test_sscheduled_charging_recent_plan(end_time_mock, monkeypatch.setattr(ChargeTemplate, "_calc_remaining_time", calculate_duration_mock) check_end_time_mock = Mock(side_effect=end_time_mock) monkeypatch.setattr(timecheck, "check_end_time", check_end_time_mock) - ct = ChargeTemplate(0) + ct = ChargeTemplate() plan_mock_0 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=0, limit=Limit(selected="amount")) plan_mock_1 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=1, limit=Limit(selected="amount")) plan_mock_2 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=2, limit=Limit(selected="amount")) @@ -246,7 +247,7 @@ def test_scheduled_charging_calc_current(plan_data: SelectedPlan, selected: str, expected: Tuple[float, str, str, int]): # setup - ct = ChargeTemplate(0) + ct = ChargeTemplate() plan = ScheduledChargingPlan(active=True, id=0) plan.limit.selected = selected # json verwandelt Keys in strings @@ -263,7 +264,7 @@ def test_scheduled_charging_calc_current(plan_data: SelectedPlan, def test_scheduled_charging_calc_current_no_plans(): # setup - ct = ChargeTemplate(0) + ct = ChargeTemplate() # execution ret = ct.scheduled_charging_calc_current(None, 63, 5, 3, 6, 0, ChargingType.AC.value, EvTemplate()) @@ -280,7 +281,7 @@ def test_scheduled_charging_calc_current_no_plans(): ]) def test_scheduled_charging_calc_current_electricity_tariff(loading_hour, expected, monkeypatch): # setup - ct = ChargeTemplate(0) + ct = ChargeTemplate() plan = ScheduledChargingPlan(active=True) plan.limit.selected = "soc" ct.data.chargemode.scheduled_charging.plans = {"0": plan} diff --git a/packages/control/ev/ev.py b/packages/control/ev/ev.py index 947185ed29..728cdb6203 100644 --- a/packages/control/ev/ev.py +++ b/packages/control/ev/ev.py @@ -86,7 +86,7 @@ class Ev: def __init__(self, index: int): try: self.ev_template: EvTemplate = EvTemplate() - self.charge_template: ChargeTemplate = ChargeTemplate(0) + self.charge_template: ChargeTemplate = ChargeTemplate() self.soc_module: ConfigurableVehicle = None self.chargemode_changed = False self.submode_changed = False diff --git a/packages/control/ev/ev_template.py b/packages/control/ev/ev_template.py index 8da234a1ff..a8e8fbe02d 100644 --- a/packages/control/ev/ev_template.py +++ b/packages/control/ev/ev_template.py @@ -5,6 +5,7 @@ class EvTemplateData: dc_min_current: int = 0 dc_max_current: int = 0 + id: int = 0 name: str = "Fahrzeug-Profil" max_current_multi_phases: int = 16 max_phases: int = 3 @@ -33,4 +34,3 @@ class EvTemplate: data: EvTemplateData = field(default_factory=ev_template_data_factory, metadata={ "topic": "config"}) - et_num: int = 0 diff --git a/packages/helpermodules/subdata.py b/packages/helpermodules/subdata.py index e864c75bae..f978b4f9e6 100644 --- a/packages/helpermodules/subdata.py +++ b/packages/helpermodules/subdata.py @@ -304,7 +304,7 @@ def process_vehicle_topic(self, client: mqtt.Client, var: Dict[str, ev.Ev], msg: except Exception: log.exception("Fehler im subdata-Modul") - def process_vehicle_charge_template_topic(self, var: Dict[str, ev.ChargeTemplate], msg: mqtt.MQTTMessage): + def process_vehicle_charge_template_topic(self, var: Dict[str, ChargeTemplate], msg: mqtt.MQTTMessage): """ Handler für die EV-Topics Parameter @@ -322,7 +322,7 @@ def process_vehicle_charge_template_topic(self, var: Dict[str, ev.ChargeTemplate var.pop("ct"+index) else: if "ct"+index not in var: - var["ct"+index] = ev.ChargeTemplate(int(index)) + var["ct"+index] = ChargeTemplate() if re.search("/vehicle/template/charge_template/[0-9]+/chargemode/scheduled_charging/plans/[0-9]+$", msg.topic) is not None: index_second = get_second_index(msg.topic) @@ -378,7 +378,7 @@ def process_vehicle_ev_template_topic(self, var: Dict[str, EvTemplate], msg: mqt var.pop("et"+index) else: if "et"+index not in var: - var["et"+index] = EvTemplate(et_num=int(index)) + var["et"+index] = EvTemplate() var["et" + index].data = dataclass_from_dict(EvTemplateData, decode_payload(msg.payload)) self.event_ev_template.set() except Exception: diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 9a64bc9652..6c756cc83a 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -53,7 +53,7 @@ class UpdateConfig: - DATASTORE_VERSION = 76 + DATASTORE_VERSION = 77 valid_topic = [ "^openWB/bat/config/configured$", "^openWB/bat/config/power_limit_mode$", @@ -447,10 +447,10 @@ class UpdateConfig: ("openWB/counter/config/home_consumption_source_id", counter_all.Config().home_consumption_source_id), ("openWB/vehicle/0/name", "Standard-Fahrzeug"), ("openWB/vehicle/0/info", {"manufacturer": None, "model": None}), - ("openWB/vehicle/0/charge_template", ev.Ev(0).charge_template.ct_num), + ("openWB/vehicle/0/charge_template", ev.Ev(0).charge_template.data.id), ("openWB/vehicle/0/soc_module/config", NO_MODULE), ("openWB/vehicle/0/soc_module/general_config", dataclass_utils.asdict(GeneralVehicleConfig())), - ("openWB/vehicle/0/ev_template", ev.Ev(0).ev_template.et_num), + ("openWB/vehicle/0/ev_template", ev.Ev(0).ev_template.data.id), ("openWB/vehicle/0/tag_id", ev.Ev(0).data.tag_id), ("openWB/vehicle/0/get/soc", ev.Ev(0).data.get.soc), ("openWB/vehicle/template/ev_template/0", asdict(EvTemplateData(name="Standard-Fahrzeug-Profil", @@ -843,7 +843,7 @@ def upgrade(topic: str, payload) -> Optional[dict]: if re.search("openWB/vehicle/template/ev_template/[0-9]+$", topic) is not None: payload = decode_payload(payload) if "keep_charge_active_duration" not in payload: - payload["keep_charge_active_duration"] = ev.EvTemplateData().keep_charge_active_duration + payload["keep_charge_active_duration"] = EvTemplateData().keep_charge_active_duration return {topic: payload} self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 8) @@ -2026,3 +2026,14 @@ def get_new_phases_to_use(topic) -> int: return topics self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 76) + + def upgrade_datastore_76(self) -> None: + def upgrade(topic: str, payload) -> None: + if (re.search("openWB/vehicle/template/charge_template/[0-9]+", topic) is not None or + re.search("openWB/vehicle/template/ev_template/[0-9]+", topic) is not None): + payload = decode_payload(payload) + index = get_index(topic) + payload.update({"id", index}) + Pub().pub(topic, payload) + self._loop_all_received_topics(upgrade) + self.__update_topic("openWB/system/datastore_version", 77) From 85ad3a8856e00246d4fc918a43b34928d8c77e36 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 23 Oct 2024 08:32:50 +0200 Subject: [PATCH 02/17] dashboard temporary settings --- .../control/algorithm/surplus_controlled.py | 6 +- .../algorithm/surplus_controlled_test.py | 6 +- packages/control/chargepoint/chargepoint.py | 191 ++++++++++-------- .../control/chargepoint/chargepoint_data.py | 5 + packages/control/counter.py | 8 +- packages/control/ev/ev.py | 19 +- packages/helpermodules/update_config.py | 1 - 7 files changed, 123 insertions(+), 113 deletions(-) diff --git a/packages/control/algorithm/surplus_controlled.py b/packages/control/algorithm/surplus_controlled.py index 51e0aaa1c7..0f3eca4a83 100644 --- a/packages/control/algorithm/surplus_controlled.py +++ b/packages/control/algorithm/surplus_controlled.py @@ -96,9 +96,9 @@ def _set_loadmangement_message(self, # tested def filter_by_feed_in_limit(self, chargepoints: List[Chargepoint]) -> Tuple[List[Chargepoint], List[Chargepoint]]: - cp_with_feed_in = list(filter(lambda cp: cp.data.set.charging_ev_data.charge_template.data.chargemode. + cp_with_feed_in = list(filter(lambda cp: cp.data.set.charge_template.data.chargemode. pv_charging.feed_in_limit is True, chargepoints)) - cp_without_feed_in = list(filter(lambda cp: cp.data.set.charging_ev_data.charge_template.data.chargemode. + cp_without_feed_in = list(filter(lambda cp: cp.data.set.charge_template.data.chargemode. pv_charging.feed_in_limit is False, chargepoints)) return cp_with_feed_in, cp_without_feed_in @@ -153,7 +153,7 @@ def check_submode_pv_charging(self) -> None: def phase_switch_necessary() -> bool: return cp.cp_ev_chargemode_support_phase_switch() and cp.data.get.phases_in_use != 1 control_parameter = cp.data.control_parameter - if cp.data.set.charging_ev_data.chargemode_changed or cp.data.set.charging_ev_data.submode_changed: + if cp.chargemode_changed or cp.submode_changed: if control_parameter.state == ChargepointState.CHARGING_ALLOWED: if (cp.data.set.charging_ev_data.ev_template.data.prevent_charge_stop is False and phase_switch_necessary() is False): diff --git a/packages/control/algorithm/surplus_controlled_test.py b/packages/control/algorithm/surplus_controlled_test.py index c36f671959..235a327a71 100644 --- a/packages/control/algorithm/surplus_controlled_test.py +++ b/packages/control/algorithm/surplus_controlled_test.py @@ -40,10 +40,8 @@ def test_filter_by_feed_in_limit(feed_in_limit_1: bool, expected_sorted: int): # setup def setup_cp(cp: Chargepoint, feed_in_limit: bool) -> Chargepoint: - ev = Ev(0) - ev.charge_template = ChargeTemplate() - ev.charge_template.data.chargemode.pv_charging.feed_in_limit = feed_in_limit - cp.data = ChargepointData(set=Set(charging_ev_data=ev)) + cp.data = ChargepointData() + cp.data.set.charge_template.data.chargemode.pv_charging.feed_in_limit = feed_in_limit return cp cp1 = setup_cp(mock_cp1, feed_in_limit_1) diff --git a/packages/control/chargepoint/chargepoint.py b/packages/control/chargepoint/chargepoint.py index b3c6af8a98..891aeb4e6b 100644 --- a/packages/control/chargepoint/chargepoint.py +++ b/packages/control/chargepoint/chargepoint.py @@ -14,6 +14,7 @@ Tag-Liste: Tags, mit denen der Ladepunkt freigeschaltet werden kann. Ist diese leer, kann mit jedem Tag der Ladepunkt freigeschaltet werden. """ +import copy from dataclasses import asdict import dataclasses import logging @@ -70,6 +71,9 @@ def __init__(self, index: int, event: Optional[threading.Event]): self.template: CpTemplate = None self.chargepoint_module: AbstractChargepoint = None self.num = index + + self.chargemode_changed = False + self.submode_changed = False # bestehende Daten auf dem Broker nicht zurücksetzen, daher nicht veröffentlichen self.data: ChargepointData = ChargepointData() self.data.set_event(event) @@ -226,7 +230,7 @@ def _process_charge_stop(self) -> None: if not self.data.get.plug_state: self.data.control_parameter = control_parameter_factory() # Standardprofil nach Abstecken laden - if data.data.ev_data["ev"+str(self.data.set.charging_ev_prev)].charge_template.data.load_default: + if self.data.set.charge_template.data.load_default: self.data.config.ev = 0 Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/config/ev", 0) # Ladepunkt nach Abstecken sperren @@ -235,6 +239,8 @@ def _process_charge_stop(self) -> None: Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/manual_lock", True) log.debug("/set/manual_lock True") # Ev wurde noch nicht aktualisiert. + # Ladeprofil aus den Einstellungen laden. + self.data.set.charge_template = copy.deepcopy(self.data.set.charging_ev_data.charge_template) chargelog.save_and_reset_data(self, data.data.ev_data["ev"+str(self.data.set.charging_ev_prev)]) self.data.set.charging_ev_prev = -1 Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/charging_ev_prev", @@ -280,8 +286,8 @@ def set_control_parameter(self, submode: str, required_current: float): self.data.control_parameter.chargemode = Chargemode.TIME_CHARGING else: self.data.control_parameter.chargemode = Chargemode( - self.data.set.charging_ev_data.charge_template.data.chargemode.selected) - self.data.control_parameter.prio = self.data.set.charging_ev_data.charge_template.data.prio + self.data.set.charge_template.data.chargemode.selected) + self.data.control_parameter.prio = self.data.set.charge_template.data.prio self.data.control_parameter.required_current = required_current if self.template.data.charging_type == ChargingType.AC.value: self.data.control_parameter.min_current = self.data.set.charging_ev_data.ev_template.data.min_current @@ -502,44 +508,58 @@ def initiate_phase_switch(self): def get_phases_by_selected_chargemode(self, phases_chargemode: int) -> int: charging_ev = self.data.set.charging_ev_data + + +<< << << < HEAD if ((self.data.config.auto_phase_switch_hw is False and self.data.get.charge_state) or +== == === # Zeitladen kann nicht als Lademodus ausgewählt werden. Ob Zeitladen aktiv ist, lässt sich aus dem Submode + # erkennen. + if self.data.control_parameter.submode == "time_charging": + mode="time_charging" + else: + mode=self.data.set.charge_template.data.chargemode.selected + chargemode=data.data.general_data.get_phases_chargemode(mode, self.data.control_parameter.submode) + + if (chargemode is None or + (self.data.config.auto_phase_switch_hw is False and self.data.get.charge_state) or +>>>>>> > a77a9e2ed(dashboard temporary settings) self.data.control_parameter.failed_phase_switches > self.MAX_FAILED_PHASE_SWITCHES): # Wenn keine Umschaltung verbaut ist, die Phasenzahl nehmen, mit der geladen wird. Damit werden zB auch # einphasige EV an dreiphasigen openWBs korrekt berücksichtigt. - phases = self.data.get.phases_in_use or self.data.set.phases_to_use + phases=self.data.get.phases_in_use or self.data.set.phases_to_use elif self.data.control_parameter.state == ChargepointState.PERFORMING_PHASE_SWITCH: - phases = self.data.set.phases_to_use + phases=self.data.set.phases_to_use log.debug(f"Umschaltung wird durchgeführt, Phasenzahl nicht ändern {phases}") elif phases_chargemode == 0: # Wenn die Lademodus-Phasen 0 sind, wird die bisher genutzte Phasenzahl weiter genutzt, # bis der Algorithmus eine Umschaltung vorgibt, zB weil der gewählte Lademodus eine # andere Phasenzahl benötigt oder bei PV-Laden die automatische Umschaltung aktiv ist. if self.data.get.charge_state: - phases = self.data.set.phases_to_use + phases=self.data.set.phases_to_use else: if ((not charging_ev.ev_template.data.prevent_phase_switch or self.data.set.log.imported_since_plugged == 0) and self.data.config.auto_phase_switch_hw): - phases = 1 + phases=1 else: if self.data.set.phases_to_use != 0: - phases = self.data.set.phases_to_use + phases=self.data.set.phases_to_use else: # phases_target - phases = self.data.config.connected_phases + phases=self.data.config.connected_phases log.debug(f"Phasenzahl Lademodus: {phases}") else: if phases_chargemode == 0: - phases = self.data.control_parameter.phases + phases=self.data.control_parameter.phases else: - phases = phases_chargemode + phases=phases_chargemode return phases def get_max_phase_hw(self) -> int: - charging_ev = self.data.set.charging_ev_data - config = self.data.config + charging_ev=self.data.set.charging_ev_data + config=self.data.config - phases = min(charging_ev.ev_template.data.max_phases, config.connected_phases) + phases=min(charging_ev.ev_template.data.max_phases, config.connected_phases) if charging_ev.ev_template.data.max_phases <= config.connected_phases: log.debug(f"EV-Phasenzahl beschränkt die nutzbaren Phasen auf {phases}") else: @@ -547,7 +567,7 @@ def get_max_phase_hw(self) -> int: return phases def set_phases(self, phases: int) -> int: - charging_ev = self.data.set.charging_ev_data + charging_ev=self.data.set.charging_ev_data if phases != self.data.get.phases_in_use: # Wenn noch kein Eintrag im Protokoll erstellt wurde, wurde noch nicht geladen und die Phase kann noch @@ -557,20 +577,20 @@ def set_phases(self, phases: int) -> int: log.info(f"Phasenumschaltung an Ladepunkt {self.num} nicht möglich, da bei EV" f"{charging_ev.num} nach Ladestart nicht mehr umgeschaltet werden darf.") if self.data.get.phases_in_use != 0: - phases = self.data.get.phases_in_use + phases=self.data.get.phases_in_use else: - phases = self.data.control_parameter.phases + phases=self.data.control_parameter.phases elif self.cp_ev_support_phase_switch() is False: # sonst passt die Phasenzahl nicht bei Autos, die eine Phase weg schalten. log.info(f"Phasenumschaltung an Ladepunkt {self.num} wird durch die Hardware nicht unterstützt.") - phases = phases + phases=phases if phases != self.data.control_parameter.phases: - self.data.control_parameter.phases = phases + self.data.control_parameter.phases=phases return phases - def check_min_max_current(self, required_current: float, phases: int, pv: bool = False) -> float: - required_current_prev = required_current - required_current, msg = self.data.set.charging_ev_data.check_min_max_current( + def check_min_max_current(self, required_current: float, phases: int, pv: bool=False) -> float: + required_current_prev=required_current + required_current, msg=self.data.set.charging_ev_data.check_min_max_current( self.data.control_parameter, required_current, phases, @@ -578,59 +598,59 @@ def check_min_max_current(self, required_current: float, phases: int, pv: bool = pv) if self.template.data.charging_type == ChargingType.AC.value: if phases == 1: - required_current = min(required_current, self.template.data.max_current_single_phase) + required_current=min(required_current, self.template.data.max_current_single_phase) else: - required_current = min(required_current, self.template.data.max_current_multi_phases) + required_current=min(required_current, self.template.data.max_current_multi_phases) else: - required_current = min(required_current, self.template.data.dc_max_current) + required_current=min(required_current, self.template.data.dc_max_current) if required_current != required_current_prev and msg is None: - msg = ("Die Einstellungen in dem Ladepunkt-Profil beschränken den Strom auf " + msg=("Die Einstellungen in dem Ladepunkt-Profil beschränken den Strom auf " f"maximal {required_current} A.") self.set_state_and_log(msg) return required_current def set_required_currents(self, required_current: float) -> None: - control_parameter = self.data.control_parameter + control_parameter=self.data.control_parameter try: for i in range(0, control_parameter.phases): - evu_phase = convert_single_evu_phase_to_cp_phase(self.data.config.phase_1, i) - control_parameter.required_currents[evu_phase] = required_current + evu_phase=convert_single_evu_phase_to_cp_phase(self.data.config.phase_1, i) + control_parameter.required_currents[evu_phase]=required_current except KeyError: - control_parameter.required_currents = [required_current]*3 + control_parameter.required_currents=[required_current]*3 self.set_state_and_log("Bitte in den Ladepunkt-Einstellungen die Einstellung 'Phase 1 des Ladekabels'" + " angeben. Andernfalls wird der benötigte Strom auf allen 3 Phasen vorgehalten, " + "was ggf eine unnötige Reduktion der Ladeleistung zur Folge hat.") - self.data.set.required_power = sum(control_parameter.required_currents) * 230 + self.data.set.required_power=sum(control_parameter.required_currents) * 230 def set_timestamp_charge_start(self): # Beim Ladestart Timer laufen lassen, manche Fahrzeuge brauchen sehr lange. # Nach dem Algorithmus setzen, sonst steht set current noch nicht fest. if self.data.control_parameter.timestamp_charge_start is None: if self.data.set.current_prev == 0 and self.data.set.current != 0: - self.data.control_parameter.timestamp_charge_start = create_timestamp() + self.data.control_parameter.timestamp_charge_start=create_timestamp() elif self.data.set.current == 0: - self.data.control_parameter.timestamp_charge_start = None + self.data.control_parameter.timestamp_charge_start=None def update_ev(self, ev_list: Dict[str, Ev]) -> None: self._validate_rfid() - charging_possible = self.is_charging_possible()[0] + charging_possible=self.is_charging_possible()[0] if charging_possible: - vehicle = self.template.get_ev(self.data.get.rfid or self.data.set.rfid, + vehicle=self.template.get_ev(self.data.get.rfid or self.data.set.rfid, self.data.get.vehicle_id, self.data.config.ev)[0] - charging_ev = self._get_charging_ev(vehicle, ev_list) + charging_ev=self._get_charging_ev(vehicle, ev_list) self._pub_connected_vehicle(charging_ev) else: - vehicle = -1 + vehicle=-1 self._pub_configured_ev(ev_list) def update(self, ev_list: Dict[str, Ev]) -> None: try: self._validate_rfid() - charging_possible, message = self.is_charging_possible() + charging_possible, message=self.is_charging_possible() if self.data.get.rfid is not None and self.data.get.plug_state: self._link_rfid_to_cp() - vehicle, message_ev = self.template.get_ev(self.data.set.rfid or self.data.get.rfid, + vehicle, message_ev=self.template.get_ev(self.data.set.rfid or self.data.get.rfid, self.data.get.vehicle_id, self.data.config.ev) if message_ev: @@ -638,25 +658,25 @@ def update(self, ev_list: Dict[str, Ev]) -> None: if charging_possible: try: - charging_ev = self._get_charging_ev(vehicle, ev_list) - max_phase_hw = self.get_max_phase_hw() - state, message_ev, submode, required_current, phases = charging_ev.get_required_current( + charging_ev=self._get_charging_ev(vehicle, ev_list) + max_phase_hw=self.get_max_phase_hw() + state, message_ev, submode, required_current, phases=charging_ev.get_required_current( self.data.control_parameter, max_phase_hw, self.cp_ev_support_phase_switch(), self.template.data.charging_type, self.data.set.log.timestamp_start_charging, self.data.set.log.imported_since_plugged) - phases = self.get_phases_by_selected_chargemode(phases) - phases = self.set_phases(phases) + phases=self.get_phases_by_selected_chargemode(phases) + phases=self.set_phases(phases) self._pub_connected_vehicle(charging_ev) - required_current = self.chargepoint_module.add_conversion_loss_to_current(required_current) + required_current=self.chargepoint_module.add_conversion_loss_to_current(required_current) # Einhaltung des Minimal- und Maximalstroms prüfen - required_current = self.check_min_max_current( + required_current=self.check_min_max_current( required_current, self.data.control_parameter.phases) - required_current = self.chargepoint_module.add_conversion_loss_to_current(required_current) - charging_ev.set_chargemode_changed(self.data.control_parameter, submode) - charging_ev.set_submode_changed(self.data.control_parameter, submode) + required_current=self.chargepoint_module.add_conversion_loss_to_current(required_current) + self.set_chargemode_changed(self.data.control_parameter, submode) + self.set_submode_changed(self.data.control_parameter, submode) self.set_control_parameter(submode, required_current) self.set_required_currents(required_current) self.check_phase_switch_completed() @@ -665,10 +685,10 @@ def update(self, ev_list: Dict[str, Ev]) -> None: data.data.counter_all_data.get_evu_counter().reset_switch_on_off( self, charging_ev) charging_ev.reset_phase_switch(self.data.control_parameter) - message = message_ev if message_ev else message + message=message_ev if message_ev else message # Ein Eintrag muss nur erstellt werden, wenn vorher schon geladen wurde und auch danach noch # geladen werden soll. - if charging_ev.chargemode_changed and self.data.set.log.imported_since_mode_switch != 0 and state: + if self.chargemode_changed and self.data.set.log.imported_since_mode_switch != 0 and state: chargelog.save_interim_data(self, charging_ev) # Wenn die Nachrichten gesendet wurden, EV wieder löschen, wenn das EV im Algorithmus nicht @@ -676,15 +696,15 @@ def update(self, ev_list: Dict[str, Ev]) -> None: if not state: if self.data.set.charging_ev != -1: # Altes EV merken - self.data.set.charging_ev_prev = self.data.set.charging_ev + self.data.set.charging_ev_prev=self.data.set.charging_ev Pub().pub("openWB/set/chargepoint/"+str(self.num) + "/set/charging_ev_prev", self.data.set.charging_ev_prev) - self.data.set.charging_ev = -1 + self.data.set.charging_ev=-1 Pub().pub("openWB/set/chargepoint/" + str(self.num)+"/set/charging_ev", -1) log.debug(f'LP {self.num}, EV: {self.data.set.charging_ev_data.data.name}' f' (EV-Nr.{vehicle}): Lademodus ' - f'{charging_ev.charge_template.data.chargemode.selected}, Submodus: ' + f'{self.data.set.charge_template.data.chargemode.selected}, Submodus: ' f'{self.data.control_parameter.submode}') else: if (self.data.control_parameter.state == ChargepointState.SWITCH_ON_DELAY and @@ -694,14 +714,14 @@ def update(self, ev_list: Dict[str, Ev]) -> None: log.info( f"LP {self.num}, EV: {self.data.set.charging_ev_data.data.name} (EV-Nr.{vehicle}): " f"Theoretisch benötigter Strom {required_current}A, Lademodus " - f"{charging_ev.charge_template.data.chargemode.selected}, Submodus: " + f"{self.data.set.charge_template.data.chargemode.selected}, Submodus: " f"{self.data.control_parameter.submode}, Phasen: " f"{self.data.control_parameter.phases}" - f", Priorität: {charging_ev.charge_template.data.prio}" + f", Priorität: {self.data.control_parameter.prio}" f", max. Ist-Strom: {max(self.data.get.currents)}") except Exception: log.exception("Fehler im Prepare-Modul für Ladepunkt "+str(self.num)) - self.data.control_parameter.submode = "stop" + self.data.control_parameter.submode="stop" else: self._process_charge_stop() if vehicle != -1: @@ -711,7 +731,7 @@ def update(self, ev_list: Dict[str, Ev]) -> None: # OCPP Start Transaction nach Anstecken if ((self.data.get.plug_state and self.data.set.plug_state_prev is False) or (self.data.set.ocpp_transaction_id is None and self.data.get.charge_state)): - self.data.set.ocpp_transaction_id = data.data.optional_data.start_transaction( + self.data.set.ocpp_transaction_id=data.data.optional_data.start_transaction( self.data.config.ocpp_chargebox_id, self.chargepoint_module.fault_state, self.num, @@ -741,19 +761,20 @@ def _pub_configured_ev(self, ev_list: Dict[str, Ev]) -> None: def _get_charging_ev(self, vehicle: int, ev_list: Dict[str, Ev]) -> Ev: try: - charging_ev = ev_list[f"ev{vehicle}"] + charging_ev=ev_list[f"ev{vehicle}"] except KeyError: log.error(f"EV {vehicle} konnte nicht gefunden werden, daher wird das Standardfahrzeug" + " verwendet.") - charging_ev = ev_list["ev0"] - vehicle = 0 + charging_ev=ev_list["ev0"] + vehicle=0 if self.data.set.charging_ev != vehicle and self.data.set.charging_ev_prev != vehicle: Pub().pub(f"openWB/set/vehicle/{charging_ev.num}/get/force_soc_update", True) log.debug("SoC nach EV-Wechsel") - self.data.set.charging_ev_data = charging_ev - self.data.set.charging_ev = vehicle + self.data.set.charge_template=copy.deepcopy(charging_ev.charge_template) + self.data.set.charging_ev_data=charging_ev + self.data.set.charging_ev=vehicle Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/charging_ev", vehicle) - self.data.set.charging_ev_prev = vehicle + self.data.set.charging_ev_prev=vehicle Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/charging_ev_prev", vehicle) return charging_ev @@ -768,28 +789,28 @@ def _pub_connected_vehicle(self, vehicle: Ev): LP-Nummer """ try: - soc_obj = ConnectedSoc( + soc_obj=ConnectedSoc( range_charged=self.data.set.log.range_charged, range_unit=data.data.general_data.data.range_unit, ) if vehicle.soc_module is not None: - soc_obj.timestamp = vehicle.data.get.soc_timestamp - soc_obj.soc = vehicle.data.get.soc - soc_obj.fault_state = vehicle.data.get.fault_state - soc_obj.fault_str = vehicle.data.get.fault_str - soc_obj.range = vehicle.data.get.range - info_obj = ConnectedInfo(id=vehicle.num, + soc_obj.timestamp=vehicle.data.get.soc_timestamp + soc_obj.soc=vehicle.data.get.soc + soc_obj.fault_state=vehicle.data.get.fault_state + soc_obj.fault_str=vehicle.data.get.fault_str + soc_obj.range=vehicle.data.get.range + info_obj=ConnectedInfo(id=vehicle.num, name=vehicle.data.name) - if (vehicle.charge_template.data.chargemode.selected == "time_charging" or - vehicle.charge_template.data.chargemode.selected == "scheduled_charging"): - current_plan = self.data.control_parameter.current_plan + if (self.data.set.charge_template.data.chargemode.selected == "time_charging" or + self.data.set.charge_template.data.chargemode.selected == "scheduled_charging"): + current_plan=self.data.control_parameter.current_plan else: - current_plan = None - config_obj = ConnectedConfig( - charge_template=vehicle.charge_template.data.id, - ev_template=vehicle.ev_template.data.id, - chargemode=vehicle.charge_template.data.chargemode.selected, - priority=vehicle.charge_template.data.prio, + current_plan=None + config_obj=ConnectedConfig( + charge_template=self.data.set.charge_template.data.id, + ev_template=vehicle.ev_template.et_num, + chargemode=self.data.set.charge_template.data.chargemode.selected, + priority=self.data.set.charge_template.data.prio, current_plan=current_plan, average_consumption=vehicle.ev_template.data.average_consump, time_charging_in_use=True if (self.data.control_parameter.submode == @@ -807,10 +828,10 @@ def _pub_connected_vehicle(self, vehicle: Ev): log.exception("Fehler im Prepare-Modul") def cp_ev_chargemode_support_phase_switch(self) -> bool: - control_parameter = self.data.control_parameter - pv_auto_switch = (control_parameter.chargemode == Chargemode.PV_CHARGING and + control_parameter=self.data.control_parameter + pv_auto_switch=(control_parameter.chargemode == Chargemode.PV_CHARGING and self.data.set.charging_ev_data.charge_template.data.chargemode.pv_charging.phases_to_use == 0) - scheduled_auto_switch = ( + scheduled_auto_switch=( control_parameter.chargemode == Chargemode.SCHEDULED_CHARGING and control_parameter.submode == Chargemode.PV_CHARGING and self.data.set.charging_ev_data.charge_template.data.chargemode.scheduled_charging.plans[ @@ -819,9 +840,9 @@ def cp_ev_chargemode_support_phase_switch(self) -> bool: self.data.control_parameter.failed_phase_switches > self.MAX_FAILED_PHASE_SWITCHES) or (data.data.general_data.data.chargemode_config.retry_failed_phase_switches is False and self.data.control_parameter.failed_phase_switches == 1)): - failed_phase_switches_reached = True + failed_phase_switches_reached=True else: - failed_phase_switches_reached = False + failed_phase_switches_reached=False return (self.cp_ev_support_phase_switch() and self.data.get.charge_state and (pv_auto_switch or scheduled_auto_switch) and diff --git a/packages/control/chargepoint/chargepoint_data.py b/packages/control/chargepoint/chargepoint_data.py index 9d2f9bb02c..b624d056d4 100644 --- a/packages/control/chargepoint/chargepoint_data.py +++ b/packages/control/chargepoint/chargepoint_data.py @@ -117,6 +117,10 @@ class Get: voltages: List[float] = field(default_factory=voltages_list_factory) +def charge_template_factory() -> ChargeTemplate: + return ChargeTemplate(None) + + def ev_factory() -> Ev: return Ev(0) @@ -144,6 +148,7 @@ class Set: current_prev: float = 0.0 target_current: float = 0 # Soll-Strom aus fest vorgegebener Stromstärke charging_ev_data: Ev = field(default_factory=ev_factory) + charge_template: ChargeTemplate = field(default_factory=charge_template_factory) ocpp_transaction_id: Optional[int] = None diff --git a/packages/control/counter.py b/packages/control/counter.py index c61cfdd2d7..42580305fb 100644 --- a/packages/control/counter.py +++ b/packages/control/counter.py @@ -264,7 +264,7 @@ def calc_switch_on_power(self, chargepoint: Chargepoint) -> Tuple[float, float]: control_parameter = chargepoint.data.control_parameter pv_config = data.data.general_data.data.chargemode_config.pv_charging - if chargepoint.data.set.charging_ev_data.charge_template.data.chargemode.pv_charging.feed_in_limit: + if chargepoint.data.set.charge_template.data.chargemode.pv_charging.feed_in_limit: threshold = pv_config.feed_in_yield else: threshold = pv_config.switch_on_threshold*control_parameter.phases @@ -274,7 +274,7 @@ def switch_on_threshold_reached(self, chargepoint: Chargepoint) -> None: try: message = None control_parameter = chargepoint.data.control_parameter - feed_in_limit = chargepoint.data.set.charging_ev_data.charge_template.data.chargemode.pv_charging.\ + feed_in_limit = chargepoint.data.set.charge_template.data.chargemode.pv_charging.\ feed_in_limit pv_config = data.data.general_data.data.chargemode_config.pv_charging timestamp_switch_on_off = control_parameter.timestamp_switch_on_off @@ -337,7 +337,7 @@ def switch_on_timer_expired(self, chargepoint: Chargepoint) -> None: msg = self.SWITCH_ON_EXPIRED.format(pv_config.switch_on_threshold) control_parameter.state = ChargepointState.CHARGING_ALLOWED - if charging_ev_data.charge_template.data.chargemode.pv_charging.feed_in_limit: + if chargepoint.data.set.charge_template.data.chargemode.pv_charging.feed_in_limit: feed_in_yield = pv_config.feed_in_yield else: feed_in_yield = 0 @@ -385,7 +385,7 @@ def switch_off_check_timer(self, chargepoint: Chargepoint) -> None: def calc_switch_off_threshold(self, chargepoint: Chargepoint) -> Tuple[float, float]: pv_config = data.data.general_data.data.chargemode_config.pv_charging control_parameter = chargepoint.data.control_parameter - if chargepoint.data.set.charging_ev_data.charge_template.data.chargemode.pv_charging.feed_in_limit: + if chargepoint.data.set.charge_template.data.chargemode.pv_charging.feed_in_limit: # Der EVU-Überschuss muss ggf um die Einspeisegrenze bereinigt werden. # Wnn die Leistung nicht Einspeisegrenze + Einschaltschwelle erreicht, darf die Ladung nicht pulsieren. # Abschaltschwelle um Einschaltschwelle reduzieren. diff --git a/packages/control/ev/ev.py b/packages/control/ev/ev.py index 728cdb6203..c64b5082cd 100644 --- a/packages/control/ev/ev.py +++ b/packages/control/ev/ev.py @@ -11,10 +11,10 @@ from typing import List, Optional, Tuple from control import data +from control.ev.charge_template import ChargeTemplate from control.chargepoint.chargepoint_state import ChargepointState, PHASE_SWITCH_STATES from control.chargepoint.charging_type import ChargingType from control.chargepoint.control_parameter import ControlParameter -from control.ev.charge_template import ChargeTemplate from control.ev.ev_template import EvTemplate from control.limiting_value import LimitingValue from dataclass_utils.factories import empty_list_factory @@ -88,8 +88,6 @@ def __init__(self, index: int): self.ev_template: EvTemplate = EvTemplate() self.charge_template: ChargeTemplate = ChargeTemplate() self.soc_module: ConfigurableVehicle = None - self.chargemode_changed = False - self.submode_changed = False self.num = index self.data = EvData() except Exception: @@ -114,6 +112,7 @@ def soc_interval_expired(self, vehicle_update_data: VehicleUpdateData) -> bool: return request_soc def get_required_current(self, + charge_template: ChargeTemplate, control_parameter: ControlParameter, max_phases_hw: int, phase_switch_supported: bool, @@ -165,7 +164,7 @@ def get_required_current(self, control_parameter.current_plan = plan_data.plan.id else: control_parameter.current_plan = None - required_current, submode, message, phases = self.charge_template.scheduled_charging_calc_current( + required_current, submode, message, phases = charge_template.scheduled_charging_calc_current( plan_data, self.data.get.soc, imported_since_plugged, @@ -216,18 +215,6 @@ def get_required_current(self, return (False, f"Kein Ladevorgang, da ein Fehler aufgetreten ist: {' '.join(e.args)}", "stop", 0, control_parameter.phases) - def set_chargemode_changed(self, control_parameter: ControlParameter, submode: str) -> None: - if ((submode == "time_charging" and control_parameter.chargemode != "time_charging") or - (submode != "time_charging" and - control_parameter.chargemode != self.charge_template.data.chargemode.selected)): - self.chargemode_changed = True - log.debug("Änderung des Lademodus") - else: - self.chargemode_changed = False - - def set_submode_changed(self, control_parameter: ControlParameter, submode: str) -> None: - self.submode_changed = (submode != control_parameter.submode) - def check_min_max_current(self, control_parameter: ControlParameter, required_current: float, diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 6c756cc83a..0ac99f627c 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -9,7 +9,6 @@ import time from typing import List, Optional from paho.mqtt.client import Client as MqttClient, MQTTMessage - import dataclass_utils from control.chargepoint.chargepoint_template import get_chargepoint_template_default From 874719f7699ae225f5da66e8891fed19e030bd4c Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 28 Oct 2024 16:01:27 +0100 Subject: [PATCH 03/17] topics --- .../control/chargepoint/chargepoint_data.py | 1 + packages/helpermodules/setdata.py | 23 +++++-- packages/helpermodules/subdata.py | 69 ++++++++++--------- .../web_themes/standard_legacy/web/index.html | 24 +++---- .../standard_legacy/web/setupMqttServices.js | 7 +- 5 files changed, 73 insertions(+), 51 deletions(-) diff --git a/packages/control/chargepoint/chargepoint_data.py b/packages/control/chargepoint/chargepoint_data.py index b624d056d4..b665f122aa 100644 --- a/packages/control/chargepoint/chargepoint_data.py +++ b/packages/control/chargepoint/chargepoint_data.py @@ -4,6 +4,7 @@ from control.chargepoint.chargepoint_template import CpTemplate from control.chargepoint.control_parameter import ControlParameter, control_parameter_factory +from control.ev.charge_template import ChargeTemplate from control.ev.ev import Ev from dataclass_utils.factories import currents_list_factory, empty_dict_factory, voltages_list_factory from helpermodules.constants import NO_ERROR diff --git a/packages/helpermodules/setdata.py b/packages/helpermodules/setdata.py index be3b1a1c7c..8a3d5ff10f 100644 --- a/packages/helpermodules/setdata.py +++ b/packages/helpermodules/setdata.py @@ -73,11 +73,17 @@ def on_message(self, client: mqtt.Client, userdata, msg: mqtt.MQTTMessage): if "openWB/set/vehicle/" in msg.topic: if "openWB/set/vehicle/template/ev_template/" in msg.topic: self.event_ev_template.wait(5) + self.process_vehicle_ev_template_topic(msg) elif "openWB/set/vehicle/template/charge_template/" in msg.topic: self.event_charge_template.wait(5) - self.process_vehicle_topic(msg) + self.process_vehicle_charge_template_topic(msg) + else: + self.process_vehicle_topic(msg) elif "openWB/set/chargepoint/" in msg.topic: - self.process_chargepoint_topic(msg) + if "openWB/set/chargepoint/set/charge_template" in msg.topic: + self.process_vehicle_charge_template_topic(msg) + else: + self.process_vehicle_topic(msg) elif "openWB/set/pv/" in msg.topic: self.process_pv_topic(msg) elif "openWB/set/bat/" in msg.topic: @@ -402,8 +408,6 @@ def process_vehicle_topic(self, msg: mqtt.MQTTMessage): self._validate_value(msg, str) elif "/info" in msg.topic: self._validate_value(msg, "json") - elif "openWB/set/vehicle/template" in msg.topic: - self._subprocess_vehicle_chargemode_topic(msg) elif "openWB/set/vehicle/set/vehicle_update_completed" in msg.topic: self._validate_value(msg, bool) elif "/set/soc_error_counter" in msg.topic: @@ -437,7 +441,7 @@ def process_vehicle_topic(self, msg: mqtt.MQTTMessage): except Exception: log.exception(f"Fehler im setdata-Modul: Topic {msg.topic}, Value: {msg.payload}") - def _subprocess_vehicle_chargemode_topic(self, msg: mqtt.MQTTMessage): + def process_vehicle_charge_template_topic(self, msg: mqtt.MQTTMessage): """ Handler für die Lade-Profil-Topics Parameters ---------- @@ -514,6 +518,15 @@ def _subprocess_vehicle_chargemode_topic(self, msg: mqtt.MQTTMessage): except Exception: log.exception(f"Fehler im setdata-Modul: Topic {msg.topic}, Value: {msg.payload}") + def process_vehicle_ev_template_topic(self, msg: mqtt.MQTTMessage): + try: + if "ev_template" in msg.topic: + self._validate_value(msg, "json") + else: + self.__unknown_topic(msg) + except Exception: + log.exception(f"Fehler im setdata-Modul: Topic {msg.topic}, Value: {msg.payload}") + def process_chargepoint_topic(self, msg: mqtt.MQTTMessage): """ Handler für die Ladepunkt-Topics diff --git a/packages/helpermodules/subdata.py b/packages/helpermodules/subdata.py index f978b4f9e6..55bd59b0c5 100644 --- a/packages/helpermodules/subdata.py +++ b/packages/helpermodules/subdata.py @@ -322,44 +322,51 @@ def process_vehicle_charge_template_topic(self, var: Dict[str, ChargeTemplate], var.pop("ct"+index) else: if "ct"+index not in var: - var["ct"+index] = ChargeTemplate() - if re.search("/vehicle/template/charge_template/[0-9]+/chargemode/scheduled_charging/plans/[0-9]+$", - msg.topic) is not None: - index_second = get_second_index(msg.topic) - if decode_payload(msg.payload) == "": - try: - var["ct"+index].data.chargemode.scheduled_charging.plans.pop(index_second) - except KeyError: - log.error("Es konnte kein Zielladen-Plan mit der ID " + - str(index_second)+" in dem Lade-Profil "+str(index)+" gefunden werden.") - else: - var["ct"+index].data.chargemode.scheduled_charging.plans[ - index_second] = dataclass_from_dict(ScheduledChargingPlan, decode_payload(msg.payload)) + var["ct"+index] = ev.ChargeTemplate() + self.process_charge_template_topic(var["ct"+index]) + if re.search("/chargemode/scheduled_charging/plans/[0-9]+$", msg.topic) is not None: self.event_scheduled_charging_plan.set() - elif re.search("/vehicle/template/charge_template/[0-9]+/time_charging/plans/[0-9]+$", - msg.topic) is not None: - index_second = get_second_index(msg.topic) - if decode_payload(msg.payload) == "": - try: - var["ct"+index].data.time_charging.plans.pop(index_second) - except KeyError: - log.error("Es konnte kein Zeitladen-Plan mit der ID " + - str(index_second)+" in dem Lade-Profil "+str(index)+" gefunden werden.") - else: - var["ct"+index].data.time_charging.plans[ - index_second] = dataclass_from_dict(TimeChargingPlan, decode_payload(msg.payload)) + elif re.search("/time_charging/plans/[0-9]+$", msg.topic) is not None: self.event_time_charging_plan.set() else: - # Pläne unverändert übernehmen - scheduled_charging_plans = var["ct" + index].data.chargemode.scheduled_charging.plans - time_charging_plans = var["ct" + index].data.time_charging.plans - var["ct" + index].data = dataclass_from_dict(ChargeTemplateData, decode_payload(msg.payload)) - var["ct"+index].data.time_charging.plans = time_charging_plans - var["ct"+index].data.chargemode.scheduled_charging.plans = scheduled_charging_plans self.event_charge_template.set() except Exception: log.exception("Fehler im subdata-Modul") + def process_charge_template_topic(self, var: ChargeTemplate, msg: mqtt.MQTTMessage): + try: + if re.search("/chargemode/scheduled_charging/plans/[0-9]+$", msg.topic) is not None: + index_second = get_second_index(msg.topic) + if decode_payload(msg.payload) == "": + try: + var.data.chargemode.scheduled_charging.plans.pop(index_second) + except KeyError: + log.error(f"Es konnte kein Zielladen-Plan mit der ID {index_second} " + "in dem Lade-Profil gefunden werden.") + else: + var.data.chargemode.scheduled_charging.plans[ + index_second] = dataclass_from_dict(ScheduledChargingPlan, decode_payload(msg.payload)) + elif re.search("/time_charging/plans/[0-9]+$", msg.topic) is not None: + index_second = get_second_index(msg.topic) + if decode_payload(msg.payload) == "": + try: + var.data.time_charging.plans.pop(index_second) + except KeyError: + log.error("Es konnte kein Zeitladen-Plan mit der ID " + + str(index_second)+" in dem Lade-Profil gefunden werden.") + else: + var.data.time_charging.plans[ + index_second] = dataclass_from_dict(TimeChargingPlan, decode_payload(msg.payload)) + else: + # Pläne unverändert übernehmen + scheduled_charging_plans = var.data.chargemode.scheduled_charging.plans + time_charging_plans = var.data.time_charging.plans + var.data = dataclass_from_dict(ChargeTemplateData, decode_payload(msg.payload)) + var.data.time_charging.plans = time_charging_plans + var.data.chargemode.scheduled_charging.plans = scheduled_charging_plans + except Exception: + log.exception("Fehler im subdata-Modul") + def process_vehicle_ev_template_topic(self, var: Dict[str, EvTemplate], msg: mqtt.MQTTMessage): """ Handler für die EV-Topics diff --git a/packages/modules/web_themes/standard_legacy/web/index.html b/packages/modules/web_themes/standard_legacy/web/index.html index 60d01051d3..b4a687d93f 100644 --- a/packages/modules/web_themes/standard_legacy/web/index.html +++ b/packages/modules/web_themes/standard_legacy/web/index.html @@ -500,7 +500,7 @@
+ data-topic="openWB/set/chargepoint//set/charge_template/chargemode/selected"> @@ -526,7 +526,7 @@
@@ -601,7 +601,7 @@

Einstellungen für "Sofort"