From 1f575df92503734416ea7cba228911ec11cfc319 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 1 Sep 2025 11:18:41 +0200 Subject: [PATCH 1/4] fix scheduled charging plan id --- packages/helpermodules/update_config.py | 59 ++++++++++++------- packages/helpermodules/update_config_test.py | 25 ++++++++ .../helpermodules/upgrade_datastore_94.json | 3 + 3 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 packages/helpermodules/upgrade_datastore_94.json diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index f5ce2c377b..2ea026f5e2 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -647,7 +647,7 @@ def __update_topic(self, topic: str, payload): if payload == "": del self.all_received_topics[topic] else: - self.all_received_topics[topic] = payload + self.all_received_topics[topic] = copy.deepcopy(payload) def __remove_outdated_topics(self): """ remove outdated topics from all_received_topics and broker @@ -1967,7 +1967,7 @@ def upgrade(topic: str, payload) -> None: # replace smarteq soc module by no_module if payload.get("type") == "smarteq": payload = NO_MODULE - Pub().pub(topic, payload) + return {topic: payload} self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 71) @@ -1983,7 +1983,7 @@ def upgrade(topic: str, payload) -> None: payload["configuration"]["firmware"] = "v1" elif payload["configuration"].get("firmware") == "v112": payload["configuration"]["firmware"] = "v2" - Pub().pub(topic, payload) + return {topic: payload} self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 72) @@ -1994,7 +1994,7 @@ def upgrade(topic: str, payload) -> None: # replace bmw soc module by no_module if payload.get("type") == "bmw": payload = NO_MODULE - Pub().pub(topic, payload) + return {topic: payload} self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 73) @@ -2017,7 +2017,7 @@ def upgrade(topic: str, payload) -> None: if payload.get("type") == "solax": if "version" not in payload["configuration"]: payload["configuration"].update({"version": "g3"}) - Pub().pub(topic, payload) + return {topic: payload} self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 75) @@ -2129,8 +2129,8 @@ def upgrade(topic: str, payload) -> Optional[dict]: component_topic): component_config = decode_payload(component_payload) if "counter" == component_config["type"]: - Pub().pub((f"openWB/system/device/{device_config['id']}/component/" - f"{component_config['id']}/simulation"), "") + return {(f"openWB/system/device/{device_config['id']}/component/" + f"{component_config['id']}/simulation"): ""} self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 80) @@ -2338,7 +2338,7 @@ def upgrade(topic: str, payload) -> None: payload = decode_payload(payload) index = int(get_index(topic)) payload.update({"id": index}) - Pub().pub(topic, payload) + return {topic: payload} self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 88) @@ -2430,6 +2430,7 @@ def upgrade_datastore_93(self) -> None: # Pläne die keinen plans Key haben, id=None max_id = -1 none_id = False + modified_topics = {} for topic, payload in self.all_received_topics.items(): if re.search("openWB/vehicle/template/charge_template/[0-9]+$", topic) is not None: payload = decode_payload(payload) @@ -2444,8 +2445,7 @@ def upgrade_datastore_93(self) -> None: raise TypeError(f"Plan {plan} hat keinen Key 'id' und ist kein NoneType.") except KeyError: payload["chargemode"]["scheduled_charging"].update({"plans": []}) - self.all_received_topics[topic] = json.dumps(payload, ensure_ascii=False).encode("utf-8") - Pub().pub(f"openWB/set/vehicle/template/charge_template/{get_index(topic)}", payload) + modified_topics[f"openWB/set/vehicle/template/charge_template/{get_index(topic)}"] = payload if none_id: for topic, payload in self.all_received_topics.items(): if re.search("openWB/vehicle/template/charge_template/[0-9]+$", topic) is not None: @@ -2454,8 +2454,7 @@ def upgrade_datastore_93(self) -> None: if plan["id"] is None: plan["id"] = max_id + 1 max_id += 1 - self.all_received_topics[topic] = json.dumps(payload, ensure_ascii=False).encode("utf-8") - Pub().pub(f"openWB/set/vehicle/template/charge_template/{get_index(topic)}", payload) + modified_topics[f"openWB/vehicle/template/charge_template/{get_index(topic)}"] = payload max_id = -1 none_id = False @@ -2473,8 +2472,7 @@ def upgrade_datastore_93(self) -> None: raise TypeError(f"Plan {plan} hat keinen Key 'id' und ist kein NoneType.") except KeyError: payload["time_charging"].update({"plans": []}) - self.all_received_topics[topic] = json.dumps(payload, ensure_ascii=False).encode("utf-8") - Pub().pub(f"openWB/set/vehicle/template/charge_template/{get_index(topic)}", payload) + modified_topics[f"openWB/vehicle/template/charge_template/{get_index(topic)}"] = payload if none_id: for topic, payload in self.all_received_topics.items(): if re.search("openWB/vehicle/template/charge_template/[0-9]+$", topic) is not None: @@ -2483,8 +2481,7 @@ def upgrade_datastore_93(self) -> None: if plan["id"] is None: plan["id"] = max_id + 1 max_id += 1 - self.all_received_topics[topic] = json.dumps(payload, ensure_ascii=False).encode("utf-8") - Pub().pub(f"openWB/set/vehicle/template/charge_template/{get_index(topic)}", payload) + modified_topics[f"openWB/vehicle/template/charge_template/{get_index(topic)}"] = payload max_id = -1 none_id = False @@ -2502,8 +2499,7 @@ def upgrade_datastore_93(self) -> None: raise TypeError(f"Plan {plan} hat keinen Key 'id' und ist kein NoneType.") except KeyError: payload["autolock"].update({"plans": []}) - self.all_received_topics[topic] = json.dumps(payload, ensure_ascii=False).encode("utf-8") - Pub().pub(f"openWB/set/chargepoint/template/{get_index(topic)}", payload) + modified_topics[f"openWB/chargepoint/template/{get_index(topic)}"] = payload if none_id: for topic, payload in self.all_received_topics.items(): if re.search("openWB/chargepoint/template/[0-9]+$", topic) is not None: @@ -2512,6 +2508,29 @@ def upgrade_datastore_93(self) -> None: if plan["id"] is None: plan["id"] = max_id + 1 max_id += 1 - self.all_received_topics[topic] = json.dumps(payload, ensure_ascii=False).encode("utf-8") - Pub().pub(f"openWB/set/chargepoint/template/{get_index(topic)}", payload) + modified_topics[f"openWB/chargepoint/template/{get_index(topic)}"] = payload + for topic, payload in modified_topics.items(): + self.__update_topic(topic, payload) self.__update_topic("openWB/system/datastore_version", 94) + + def upgrade_datastore_94(self): + def upgrade(topic, payload): + ids = [] + if re.search("openWB/vehicle/template/charge_template/[0-9]+$", topic) is not None: + payload = decode_payload(payload) + for plan in payload["chargemode"]["scheduled_charging"]["plans"]: + if plan["id"] is not None: + ids.append(plan["id"]) + ids.sort() + unique_ids = set(ids) + if len(ids) != len(unique_ids): + for plan in payload["chargemode"]["scheduled_charging"]["plans"]: + try: + unique_ids.remove(plan["id"]) + except KeyError: + self.all_received_topics["openWB/command/max_id/charge_template_scheduled_plan"] += 1 + plan["id"] = self.all_received_topics[ + "openWB/command/max_id/charge_template_scheduled_plan"] + return {topic: payload} + self._loop_all_received_topics(upgrade) + self.__update_topic("openWB/system/datastore_version", 95) diff --git a/packages/helpermodules/update_config_test.py b/packages/helpermodules/update_config_test.py index 79405ebd4f..3b2addd873 100644 --- a/packages/helpermodules/update_config_test.py +++ b/packages/helpermodules/update_config_test.py @@ -1,3 +1,7 @@ +import json +from pathlib import Path + +import pytest from helpermodules.update_config import UpdateConfig @@ -28,3 +32,24 @@ def test_remove_invalid_topics(mock_pub): assert len(mock_pub.method_calls) == 2 assert mock_pub.method_calls[0][1][0] == 'openWB/chargepoint/5/get/voltages' assert mock_pub.method_calls[1][1][0] == 'openWB/optional/int_display/theme' + + +@pytest.mark.parametrize("index_test_template, expected_index", [ + pytest.param(0, [2, 1], id="IDs korrekt"), + pytest.param(1, [0, 3], id="IDs gleich"), + pytest.param(2, [], id="keine Pläne"), +]) +def test_upgrade_datastore_94(index_test_template, expected_index): + update_con = UpdateConfig() + update_con.all_received_topics = {"openWB/command/max_id/charge_template_scheduled_plan": 2} + with open(Path(__file__).resolve().parents[0]/"upgrade_datastore_94.json", "r") as f: + test_data = f.read() + update_con.all_received_topics.update(json.loads(test_data)[index_test_template]) + + update_con.upgrade_datastore_94() + + plan_ids = [] + for plan in update_con.all_received_topics["openWB/vehicle/template/charge_template/0"]["chargemode"][ + "scheduled_charging"]["plans"]: + plan_ids.append(plan["id"]) + assert plan_ids == expected_index diff --git a/packages/helpermodules/upgrade_datastore_94.json b/packages/helpermodules/upgrade_datastore_94.json new file mode 100644 index 0000000000..11a3cd1c85 --- /dev/null +++ b/packages/helpermodules/upgrade_datastore_94.json @@ -0,0 +1,3 @@ +[{"openWB/vehicle/template/charge_template/0": {"name": "Standard-Lade-Profil", "prio": false, "load_default": false, "time_charging": {"active": false, "plans": []}, "chargemode": {"selected": "stop", "pv_charging": {"dc_min_current": 145, "dc_min_soc_current": 145, "min_soc_current": 10, "min_current": 0, "feed_in_limit": false, "min_soc": 0, "phases_to_use": 0, "phases_to_use_min_soc": 3, "limit": {"selected": "soc", "amount": 1000, "soc": 100}}, "scheduled_charging": {"plans": [{"active": true, "frequency": {"selected": "daily", "once": "2021-11-01", "weekly": [false, false, false, false, false, false, false]}, "current": 14, "dc_current": 145, "id": 2, "name": "neuer Zielladen-Plan", "limit": {"selected": "amount", "amount": 1000, "soc_limit": 90, "soc_scheduled": 80}, "time": "07: 00", "phases_to_use": 0, "phases_to_use_pv": 0, "et_active": false, "bidi_power": 10000, "bidi_charging_enabled": false}, {"active": true, "frequency": {"selected": "daily", "once": "2021-11-01", "weekly": [false, false, false, false, false, false, false]}, "current": 14, "dc_current": 145, "id": 1, "name": "neuer Zielladen-Plan", "limit": {"selected": "amount", "amount": 1000, "soc_limit": 90, "soc_scheduled": 80}, "time": "07:00", "phases_to_use": 0, "phases_to_use_pv": 0, "et_active": false, "bidi_power": 10000, "bidi_charging_enabled": false}]}, "instant_charging": {"current": 10, "dc_current": 145, "limit": {"selected": "none", "amount": 1000, "soc": 50}, "phases_to_use": 3}, "eco_charging": {"current": 6, "dc_current": 145, "limit": {"selected": "none", "amount": 1000, "soc": 50}, "max_price": 0.0002, "phases_to_use": 3}}, "id": 0}}, +{"openWB/vehicle/template/charge_template/0": {"name": "Standard-Lade-Profil", "prio": false, "load_default": false, "time_charging": {"active": false, "plans": []}, "chargemode": {"selected": "stop", "pv_charging": {"dc_min_current": 145, "dc_min_soc_current": 145, "min_soc_current": 10, "min_current": 0, "feed_in_limit": false, "min_soc": 0, "phases_to_use": 0, "phases_to_use_min_soc": 3, "limit": {"selected": "soc", "amount": 1000, "soc": 100}}, "scheduled_charging": {"plans": [{"active": true, "frequency": {"selected": "daily", "once": "2021-11-01", "weekly": [false, false, false, false, false, false, false]}, "current": 14, "dc_current": 145, "id": 0, "name": "neuer Zielladen-Plan", "limit": {"selected": "amount", "amount": 1000, "soc_limit": 90, "soc_scheduled": 80}, "time": "07: 00", "phases_to_use": 0, "phases_to_use_pv": 0, "et_active": false, "bidi_power": 10000, "bidi_charging_enabled": false}, {"active": true, "frequency": {"selected": "daily", "once": "2021-11-01", "weekly": [false, false, false, false, false, false, false]}, "current": 14, "dc_current": 145, "id": 0, "name": "neuer Zielladen-Plan", "limit": {"selected": "amount", "amount": 1000, "soc_limit": 90, "soc_scheduled": 80}, "time": "07:00", "phases_to_use": 0, "phases_to_use_pv": 0, "et_active": false, "bidi_power": 10000, "bidi_charging_enabled": false}]}, "instant_charging": {"current": 10, "dc_current": 145, "limit": {"selected": "none", "amount": 1000, "soc": 50}, "phases_to_use": 3}, "eco_charging": {"current": 6, "dc_current": 145, "limit": {"selected": "none", "amount": 1000, "soc": 50}, "max_price": 0.0002, "phases_to_use": 3}}, "id": 0}}, +{"openWB/vehicle/template/charge_template/0": {"name": "Standard-Lade-Profil", "prio": false, "load_default": false, "time_charging": {"active": false, "plans": []}, "chargemode": {"selected": "stop", "pv_charging": {"dc_min_current": 145, "dc_min_soc_current": 145, "min_soc_current": 10, "min_current": 0, "feed_in_limit": false, "min_soc": 0, "phases_to_use": 0, "phases_to_use_min_soc": 3, "limit": {"selected": "soc", "amount": 1000, "soc": 100}}, "scheduled_charging": {"plans": []}, "instant_charging": {"current": 10, "dc_current": 145, "limit": {"selected": "none", "amount": 1000, "soc": 50}, "phases_to_use": 3}, "eco_charging": {"current": 6, "dc_current": 145, "limit": {"selected": "none", "amount": 1000, "soc": 50}, "max_price": 0.0002, "phases_to_use": 3}}, "id": 0}}] \ No newline at end of file From 875222667d28295c13b0a3fcb41f00ede6701a21 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 1 Sep 2025 11:19:02 +0200 Subject: [PATCH 2/4] ammend --- packages/helpermodules/update_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 2ea026f5e2..979e6156d5 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -57,7 +57,7 @@ class UpdateConfig: - DATASTORE_VERSION = 94 + DATASTORE_VERSION = 95 valid_topic = [ "^openWB/bat/config/bat_control_permitted$", From 50d88e0dcaea5e579a1f173f1e411510442813a7 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 1 Sep 2025 11:26:14 +0200 Subject: [PATCH 3/4] fix --- packages/helpermodules/update_config.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 979e6156d5..bff69d716c 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -2524,13 +2524,14 @@ def upgrade(topic, payload): ids.sort() unique_ids = set(ids) if len(ids) != len(unique_ids): + max_id = decode_payload( + self.all_received_topics["openWB/command/max_id/charge_template_scheduled_plan"]) for plan in payload["chargemode"]["scheduled_charging"]["plans"]: try: unique_ids.remove(plan["id"]) except KeyError: - self.all_received_topics["openWB/command/max_id/charge_template_scheduled_plan"] += 1 - plan["id"] = self.all_received_topics[ - "openWB/command/max_id/charge_template_scheduled_plan"] - return {topic: payload} + max_id += 1 + plan["id"] = max_id + return {topic: payload, "openWB/command/max_id/charge_template_scheduled_plan": max_id} self._loop_all_received_topics(upgrade) self.__update_topic("openWB/system/datastore_version", 95) From e4bb4abc62df2ebfed8855ab503e61d8fa58e232 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 1 Sep 2025 11:40:00 +0200 Subject: [PATCH 4/4] fix --- packages/helpermodules/update_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index bff69d716c..87a7b9a06a 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -2333,8 +2333,8 @@ def upgrade_datastore_86(self) -> None: def upgrade_datastore_87(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): + 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 = int(get_index(topic)) payload.update({"id": index})