From 9e7141b758c6467cca285acf8ab75227285cc3fc Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Wed, 11 Jun 2025 08:40:14 +0200 Subject: [PATCH 01/10] custom vehicle and charge point colors --- .../control/chargepoint/chargepoint_data.py | 1 + packages/control/ev/ev.py | 1 + .../measurement_logging/write_log.py | 155 ++++++++++-------- 3 files changed, 93 insertions(+), 64 deletions(-) diff --git a/packages/control/chargepoint/chargepoint_data.py b/packages/control/chargepoint/chargepoint_data.py index ad5e296c4d..29e1b0c8a0 100644 --- a/packages/control/chargepoint/chargepoint_data.py +++ b/packages/control/chargepoint/chargepoint_data.py @@ -176,6 +176,7 @@ class Config: configuration: Dict = field(default_factory=empty_dict_factory) ev: int = 0 name: str = "neuer Ladepunkt" + color: str = "#0000ff" type: Optional[str] = None template: int = 0 connected_phases: int = 3 diff --git a/packages/control/ev/ev.py b/packages/control/ev/ev.py index b1c1c54767..1136db62c1 100644 --- a/packages/control/ev/ev.py +++ b/packages/control/ev/ev.py @@ -77,6 +77,7 @@ class EvData: charge_template: int = field(default=0, metadata={"topic": "charge_template"}) ev_template: int = field(default=0, metadata={"topic": "ev_template"}) name: str = field(default="neues Fahrzeug", metadata={"topic": "name"}) + color: str = field(default="#17a2b8", metadata={"topic": "color"}) tag_id: List[str] = field(default_factory=empty_list_factory, metadata={ "topic": "tag_id"}) get: Get = field(default_factory=get_factory) diff --git a/packages/helpermodules/measurement_logging/write_log.py b/packages/helpermodules/measurement_logging/write_log.py index 36ccc2fc44..a0422a811d 100644 --- a/packages/helpermodules/measurement_logging/write_log.py +++ b/packages/helpermodules/measurement_logging/write_log.py @@ -20,77 +20,80 @@ # erstellt für jeden Tag eine Datei, die die Daten für den Langzeitgraph enthält. # Dazu werden alle 5 Min folgende Daten als json-Liste gespeichert: -# {"entries": [ -# { -# "timestamp": int, -# "date": str, -# "prices": { -# "grid": Preis für Netzbezug, -# "pv": Preis für PV-Strom, -# "bat": Preis für Speicherstrom -# } -# "cp": { -# "cp1": { -# "imported": Zählerstand in Wh, -# "exported": Zählerstand in Wh -# } -# ... (dynamisch, je nach konfigurierter Anzahl) -# "all": { -# "imported": Zählerstand in Wh, -# "exported": Zählerstand in Wh -# } -# } -# "ev": { -# "ev1": { -# "soc": int in % +# { +# "entries": [ +# { +# "timestamp": int, +# "date": str, +# "prices": { +# "grid": Preis für Netzbezug, +# "pv": Preis für PV-Strom, +# "bat": Preis für Speicherstrom # } -# ... (dynamisch, je nach konfigurierter Anzahl) -# } -# "counter": { -# "counter0": { -# "grid": bool, -# "imported": Wh, -# "exported": Wh +# "cp": { +# "cp1": { +# "imported": Zählerstand in Wh, +# "exported": Zählerstand in Wh +# } +# ... (dynamisch, je nach konfigurierter Anzahl) +# "all": { +# "imported": Zählerstand in Wh, +# "exported": Zählerstand in Wh +# } # } -# ... (dynamisch, je nach konfigurierter Anzahl) -# } -# "pv": { -# "all": { -# "exported": Wh +# "ev": { +# "ev1": { +# "soc": int in % +# } +# ... (dynamisch, je nach konfigurierter Anzahl) # } -# "pv0": { -# "exported": Wh +# "counter": { +# "counter0": { +# "grid": bool, +# "imported": Wh, +# "exported": Wh +# } +# ... (dynamisch, je nach konfigurierter Anzahl) # } -# ... (dynamisch, je nach konfigurierter Anzahl) -# } -# "bat": { -# "all": { -# "imported": Wh, -# "exported": Wh, -# "soc": int in % +# "pv": { +# "all": { +# "exported": Wh +# } +# "pv0": { +# "exported": Wh +# } +# ... (dynamisch, je nach konfigurierter Anzahl) # } -# "bat0": { -# "imported": Wh, -# "exported": Wh, -# "soc": int in % +# "bat": { +# "all": { +# "imported": Wh, +# "exported": Wh, +# "soc": int in % +# } +# "bat0": { +# "imported": Wh, +# "exported": Wh, +# "soc": int in % +# } +# ... (dynamisch, je nach konfigurierter Anzahl) # } -# ... (dynamisch, je nach konfigurierter Anzahl) -# } -# "sh": { -# "sh1": { -# "exported": Wh, -# "imported": Wh, -# wenn konfiguriert: -# "temp1": int in °C, -# "temp2": int in °C, -# "temp3": int in °C +# "sh": { +# "sh1": { +# "exported": Wh, +# "imported": Wh, +# wenn konfiguriert: +# "temp1": int in °C, +# "temp2": int in °C, +# "temp3": int in °C +# }, +# ... (dynamisch, je nach Anzahl konfigurierter Geräte) # }, -# ... (dynamisch, je nach Anzahl konfigurierter Geräte) -# }, -# "hc": {"all": {"imported": Wh # Hausverbrauch}} -# }], -# "names": "names": {"sh1": "", "cp1": "", "counter2": "", "pv3": ""} -# } +# "hc": {"all": {"imported": Wh # Hausverbrauch}} +# } +# ], +# "names": {"cp1": "", "counter2": "", "pv3": ""}, +# "colors": {"cp1": "", "counter2": "", "pv3": ""}, +# } class LogType(Enum): @@ -357,3 +360,27 @@ def get_names(elements: Dict, sh_names: Dict, valid_names: Optional[Dict] = None except (ValueError, KeyError, AttributeError): names.update({entry: entry}) return names + + +def get_colors(elements: Dict) -> Dict: + """ Ermittelt die Farben der Fahrzeuge und Ladepunkte, welche + in elements vorhanden sind und gibt diese als Dictionary zurück. + Parameter + --------- + elements: dict + Dictionary, das die Messwerte enthält. + """ + colors = {} + for group in elements.items(): + if group[0] not in ("ev", "cp"): + continue + for entry in group[1]: + if "all" != entry: + try: + if "ev" in entry: + colors.update({entry: data.data.ev_data[entry].data.color}) + elif "cp" in entry: + colors.update({entry: data.data.cp_data[entry].data.config.color}) + except (ValueError, KeyError, AttributeError): + colors.update({entry: "#000000"}) + return colors From 4c883b684d08a0fe7b5850a6519f84331d43e33f Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Wed, 11 Jun 2025 08:46:11 +0200 Subject: [PATCH 02/10] custom component colors --- .../helpermodules/measurement_logging/write_log.py | 10 +++++++--- packages/modules/common/component_setup.py | 3 ++- packages/modules/common/utils/component_parser.py | 10 ++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/helpermodules/measurement_logging/write_log.py b/packages/helpermodules/measurement_logging/write_log.py index a0422a811d..7083698b1d 100644 --- a/packages/helpermodules/measurement_logging/write_log.py +++ b/packages/helpermodules/measurement_logging/write_log.py @@ -14,7 +14,7 @@ from helpermodules import timecheck from helpermodules.utils.json_file_handler import write_and_check from helpermodules.utils.topic_parser import decode_payload, get_index -from modules.common.utils.component_parser import get_component_name_by_id +from modules.common.utils.component_parser import get_component_name_by_id, get_component_color_by_id log = logging.getLogger(__name__) @@ -168,6 +168,7 @@ def save_log(log_type: LogType): entries = content["entries"] entries.append(new_entry) content["names"] = get_names(content["entries"][-1], sh_log_data.sh_names) + content["colors"] = get_colors(content["entries"][-1]) write_and_check(filepath, content) return content["entries"] except Exception: @@ -363,7 +364,7 @@ def get_names(elements: Dict, sh_names: Dict, valid_names: Optional[Dict] = None def get_colors(elements: Dict) -> Dict: - """ Ermittelt die Farben der Fahrzeuge und Ladepunkte, welche + """ Ermittelt die Farben der Fahrzeuge, Ladepunkte und Komponenten, welche in elements vorhanden sind und gibt diese als Dictionary zurück. Parameter --------- @@ -372,7 +373,7 @@ def get_colors(elements: Dict) -> Dict: """ colors = {} for group in elements.items(): - if group[0] not in ("ev", "cp"): + if group[0] not in ("ev", "cp", "counter", "pv", "bat"): continue for entry in group[1]: if "all" != entry: @@ -381,6 +382,9 @@ def get_colors(elements: Dict) -> Dict: colors.update({entry: data.data.ev_data[entry].data.color}) elif "cp" in entry: colors.update({entry: data.data.cp_data[entry].data.config.color}) + else: + id = entry.strip(string.ascii_letters) + colors.update({entry: get_component_color_by_id(int(id))}) except (ValueError, KeyError, AttributeError): colors.update({entry: "#000000"}) return colors diff --git a/packages/modules/common/component_setup.py b/packages/modules/common/component_setup.py index c4eaffe1a1..2ddf79a014 100644 --- a/packages/modules/common/component_setup.py +++ b/packages/modules/common/component_setup.py @@ -4,8 +4,9 @@ class ComponentSetup(Generic[T]): - def __init__(self, name: str, type: str, id: int, configuration: T) -> None: + def __init__(self, name: str, color: str, type: str, id: int, configuration: T) -> None: self.name = name + self.color = color self.info = {"manufacturer": None, "model": None} self.type = type self.id = id diff --git a/packages/modules/common/utils/component_parser.py b/packages/modules/common/utils/component_parser.py index 5dcbb226ac..4b3a27be95 100644 --- a/packages/modules/common/utils/component_parser.py +++ b/packages/modules/common/utils/component_parser.py @@ -18,6 +18,16 @@ def get_component_name_by_id(id: int): raise ValueError(f"Element {id} konnte keinem Gerät zugeordnet werden.") +def get_component_color_by_id(id: int): + for item in data.data.system_data.values(): + if isinstance(item, AbstractDevice): + for comp in item.components.values(): + if comp.component_config.id == id: + return comp.component_config.color + else: + raise ValueError(f"Element {id} konnte keinem Gerät zugeordnet werden.") + + def get_io_name_by_id(id: int): for item in data.data.system_data.values(): if isinstance(item, AbstractIoDevice): From 968816b645fc10f0222012183e824503dd58a29e Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Wed, 11 Jun 2025 08:47:59 +0200 Subject: [PATCH 03/10] update config step 1 --- packages/helpermodules/update_config.py | 35 ++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 749cfa51ed..d4f777c080 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -57,7 +57,7 @@ class UpdateConfig: - DATASTORE_VERSION = 101 + DATASTORE_VERSION = 102 valid_topic = [ "^openWB/bat/config/bat_control_permitted$", @@ -360,6 +360,7 @@ class UpdateConfig: "^openWB/vehicle/[0-9]+/charge_template$", "^openWB/vehicle/[0-9]+/ev_template$", "^openWB/vehicle/[0-9]+/name$", + "^openWB/vehicle/[0-9]+/color$", "^openWB/vehicle/[0-9]+/info$", "^openWB/vehicle/[0-9]+/soc_module/calculated_soc_state$", "^openWB/vehicle/[0-9]+/soc_module/config$", @@ -523,6 +524,7 @@ class UpdateConfig: ("openWB/counter/config/consider_less_charging", counter_all.Config().consider_less_charging), ("openWB/counter/config/home_consumption_source_id", counter_all.Config().home_consumption_source_id), ("openWB/vehicle/0/name", "Standard-Fahrzeug"), + ("openWB/vehicle/0/color", "#17a2b8"), ("openWB/vehicle/0/info", {"manufacturer": None, "model": None}), ("openWB/vehicle/0/charge_template", ev.Ev(0).charge_template.data.id), ("openWB/vehicle/0/soc_module/config", NO_MODULE), @@ -2625,3 +2627,34 @@ def upgrade(topic: str, payload) -> None: Pub().pub(topic, payload) self._loop_all_received_topics(upgrade) self._append_datastore_version(101) + + def upgrade_datastore_102(self) -> None: + def upgrade(topic: str, payload) -> Optional[dict]: + # add vehicle color to vehicle topics + if re.search("^openWB/vehicle/[0-9]+/name$", topic) is not None: + vehicle_color_topic = topic.replace("/name", "/color") + if vehicle_color_topic not in self.all_received_topics: + return {vehicle_color_topic: "#17a2b8"} + # add property "color" to charge points + if re.search("^openWB/chargepoint/[0-9]+/config$", topic) is not None: + config = decode_payload(payload) + if "color" not in config: + config.update({"color": "#17a2b8"}) + return {topic: config} + # add property "color" to components + if re.search("^openWB/system/device/[0-9]+/component/[0-9]+/config$", topic) is not None: + config = decode_payload(payload) + if "color" not in config: + if config.get("type").contains("counter"): + config.update({"color": "#dc3545"}) + elif config.get("type").contains("bat"): + config.update({"color": "#ffc107"}) + elif config.get("type").contains("inverter"): + config.update({"color": "#28a745"}) + else: + log.warning(f"Unknown component type {config.get('type')} for topic {topic}.") + config.update({"color": "#000000"}) + return {topic: config} + self._loop_all_received_topics(upgrade) + # ToDo: update already present log files with color information + self.__update_topic("openWB/system/datastore_version", 103) From ad7e0e18de783b6ada8aab365e5afebfad54cd43 Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Thu, 12 Jun 2025 09:22:02 +0200 Subject: [PATCH 04/10] fix upgrade config --- packages/helpermodules/update_config.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index d4f777c080..476cb9b6c8 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -2632,28 +2632,35 @@ def upgrade_datastore_102(self) -> None: def upgrade(topic: str, payload) -> Optional[dict]: # add vehicle color to vehicle topics if re.search("^openWB/vehicle/[0-9]+/name$", topic) is not None: + log.debug(f"Received vehicle name topic {topic}") vehicle_color_topic = topic.replace("/name", "/color") + log.debug(f"Checking for vehicle color topic {vehicle_color_topic}") if vehicle_color_topic not in self.all_received_topics: + log.debug(f"Adding vehicle color topic {vehicle_color_topic} with value '#17a2b8'") return {vehicle_color_topic: "#17a2b8"} # add property "color" to charge points if re.search("^openWB/chargepoint/[0-9]+/config$", topic) is not None: config = decode_payload(payload) + log.debug(f"Received charge point config topic {topic} with payload {payload}") if "color" not in config: - config.update({"color": "#17a2b8"}) + config.update({"color": "#0000ff"}) + log.debug(f"Added color to charge point config {config}") return {topic: config} # add property "color" to components if re.search("^openWB/system/device/[0-9]+/component/[0-9]+/config$", topic) is not None: config = decode_payload(payload) + log.debug(f"Received component config topic {topic} with payload {payload}") if "color" not in config: - if config.get("type").contains("counter"): + if "counter" in config.get("type").lower(): config.update({"color": "#dc3545"}) - elif config.get("type").contains("bat"): + elif "bat" in config.get("type").lower(): config.update({"color": "#ffc107"}) - elif config.get("type").contains("inverter"): + elif "inverter" in config.get("type").lower(): config.update({"color": "#28a745"}) else: log.warning(f"Unknown component type {config.get('type')} for topic {topic}.") config.update({"color": "#000000"}) + log.debug(f"Updated component config with color {config}") return {topic: config} self._loop_all_received_topics(upgrade) # ToDo: update already present log files with color information From dfdcabd7545d53d49f968660b3f049a1440749cc Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Thu, 12 Jun 2025 13:22:21 +0200 Subject: [PATCH 05/10] fix component setup --- packages/modules/common/component_setup.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/modules/common/component_setup.py b/packages/modules/common/component_setup.py index 2ddf79a014..022ac6571c 100644 --- a/packages/modules/common/component_setup.py +++ b/packages/modules/common/component_setup.py @@ -4,10 +4,18 @@ class ComponentSetup(Generic[T]): - def __init__(self, name: str, color: str, type: str, id: int, configuration: T) -> None: + def __init__(self, name: str, type: str, id: int, configuration: T) -> None: self.name = name - self.color = color self.info = {"manufacturer": None, "model": None} self.type = type self.id = id self.configuration = configuration + if "counter" in type.lower(): + self.color = "#dc3545" + elif "bat" in type.lower(): + self.color = "#ffc107" + elif "inverter" in type.lower(): + self.color = "#28a745" + else: + # Default color for other types + self.color = "#000000" From c7e3c584370ecdc8bb56e53e8e096c59faa8ef41 Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Thu, 12 Jun 2025 13:22:44 +0200 Subject: [PATCH 06/10] extend setdata for new vehicle topic --- packages/helpermodules/setdata.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/helpermodules/setdata.py b/packages/helpermodules/setdata.py index 2c3fdd573e..1e3e6aa3ad 100644 --- a/packages/helpermodules/setdata.py +++ b/packages/helpermodules/setdata.py @@ -365,6 +365,8 @@ def process_vehicle_topic(self, msg: mqtt.MQTTMessage): try: if "/name" in msg.topic: self._validate_value(msg, str) + elif "/color" in msg.topic: + self._validate_value(msg, str) elif "/info" in msg.topic: self._validate_value(msg, "json") elif "openWB/set/vehicle/set/vehicle_update_completed" in msg.topic: From 9092d9a4eb2aac0ca0abf833468cb454578aaa50 Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Mon, 14 Jul 2025 10:30:47 +0200 Subject: [PATCH 07/10] use bootstrap primary color for charge points --- packages/control/chargepoint/chargepoint_data.py | 2 +- packages/helpermodules/update_config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/control/chargepoint/chargepoint_data.py b/packages/control/chargepoint/chargepoint_data.py index 29e1b0c8a0..a27d7cdbcd 100644 --- a/packages/control/chargepoint/chargepoint_data.py +++ b/packages/control/chargepoint/chargepoint_data.py @@ -176,7 +176,7 @@ class Config: configuration: Dict = field(default_factory=empty_dict_factory) ev: int = 0 name: str = "neuer Ladepunkt" - color: str = "#0000ff" + color: str = "#007bff" type: Optional[str] = None template: int = 0 connected_phases: int = 3 diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 476cb9b6c8..ba58ef6873 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -2643,7 +2643,7 @@ def upgrade(topic: str, payload) -> Optional[dict]: config = decode_payload(payload) log.debug(f"Received charge point config topic {topic} with payload {payload}") if "color" not in config: - config.update({"color": "#0000ff"}) + config.update({"color": "#007bff"}) log.debug(f"Added color to charge point config {config}") return {topic: config} # add property "color" to components From 04bacbdac622e6448552daf387b11efbc19abb97 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Thu, 31 Jul 2025 09:20:23 +0200 Subject: [PATCH 08/10] update logfiles --- packages/helpermodules/update_config.py | 54 +++++++++++++++++++++---- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index ba58ef6873..63d96e47a2 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -1,3 +1,4 @@ +from concurrent.futures import ProcessPoolExecutor import copy from dataclasses import asdict import datetime @@ -2421,6 +2422,13 @@ def upgrade(topic: str, payload) -> None: self._loop_all_received_topics(upgrade) self._append_datastore_version(90) + BLACK = "#000000" + BLUE = "#007bff" + CYAN = "#17a2b8" + GREEN = "#28a745" + RED = "#dc3545" + YELLOW = "#ffc107" + def upgrade_datastore_91(self) -> None: def upgrade(topic: str, payload) -> Optional[dict]: if re.search("openWB/vehicle/template/ev_template/[0-9]+$", topic) is not None: @@ -2629,6 +2637,13 @@ def upgrade(topic: str, payload) -> None: self._append_datastore_version(101) def upgrade_datastore_102(self) -> None: + def add_colors_to_logs(): + files = glob.glob(str(self.base_path / "data" / "daily_log") + "/*") + files.extend(glob.glob(str(self.base_path / "data" / "monthly_log") + "/*")) + files.sort() + with ProcessPoolExecutor() as executor: + executor.map(self.process_file, files) + def upgrade(topic: str, payload) -> Optional[dict]: # add vehicle color to vehicle topics if re.search("^openWB/vehicle/[0-9]+/name$", topic) is not None: @@ -2637,13 +2652,13 @@ def upgrade(topic: str, payload) -> Optional[dict]: log.debug(f"Checking for vehicle color topic {vehicle_color_topic}") if vehicle_color_topic not in self.all_received_topics: log.debug(f"Adding vehicle color topic {vehicle_color_topic} with value '#17a2b8'") - return {vehicle_color_topic: "#17a2b8"} + return {vehicle_color_topic: self.CYAN} # add property "color" to charge points if re.search("^openWB/chargepoint/[0-9]+/config$", topic) is not None: config = decode_payload(payload) log.debug(f"Received charge point config topic {topic} with payload {payload}") if "color" not in config: - config.update({"color": "#007bff"}) + config.update({"color": self.BLUE}) log.debug(f"Added color to charge point config {config}") return {topic: config} # add property "color" to components @@ -2652,16 +2667,41 @@ def upgrade(topic: str, payload) -> Optional[dict]: log.debug(f"Received component config topic {topic} with payload {payload}") if "color" not in config: if "counter" in config.get("type").lower(): - config.update({"color": "#dc3545"}) + config.update({"color": self.RED}) elif "bat" in config.get("type").lower(): - config.update({"color": "#ffc107"}) + config.update({"color": self.YELLOW}) elif "inverter" in config.get("type").lower(): - config.update({"color": "#28a745"}) + config.update({"color": self.GREEN}) else: log.warning(f"Unknown component type {config.get('type')} for topic {topic}.") - config.update({"color": "#000000"}) + config.update({"color": self.BLACK}) log.debug(f"Updated component config with color {config}") return {topic: config} self._loop_all_received_topics(upgrade) - # ToDo: update already present log files with color information + add_colors_to_logs() self.__update_topic("openWB/system/datastore_version", 103) + + def process_file(self, file): + colors = {} + with open(file, "r+") as jsonFile: + content_raw = jsonFile.read() + content = json.loads(content_raw) + if "colors" in content: + return + for key in content["names"].keys(): + if "bat" in key: + colors[key] = self.YELLOW + elif "counter" in key: + colors[key] = self.RED + elif "cp" in key: + colors[key] = self.BLUE + elif "ev" in key: + colors[key] = self.CYAN + elif "inverter" in key: + colors[key] = self.GREEN + else: + colors[key] = self.BLACK + content["colors"] = colors + jsonFile.seek(0) + jsonFile.write(json.dumps(content)) + jsonFile.truncate() From 95404ce1578c2a646a3322c179b0f884d410f524 Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Mon, 4 Aug 2025 12:58:01 +0200 Subject: [PATCH 09/10] rename color constants --- packages/helpermodules/update_config.py | 41 +++++++++++++------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 63d96e47a2..a4f294bfba 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -55,6 +55,14 @@ NO_MODULE = {"type": None, "configuration": {}} +# Default colors +COLOR_CHARGEPOINT = "#007bff" # Default color for charge points: blue +COLOR_VEHICLE = "#17a2b8" # Default color for vehicles: teal +COLOR_INVERTER = "#28a745" # Default color for inverters: green +COLOR_COUNTER = "#dc3545" # Default color for counters: red +COLOR_BATTERY = "#ffc107" # Default color for batteries: yellow +COLOR_UNKNOWN = "#000000" # Default color for unknown components: black + class UpdateConfig: @@ -2422,13 +2430,6 @@ def upgrade(topic: str, payload) -> None: self._loop_all_received_topics(upgrade) self._append_datastore_version(90) - BLACK = "#000000" - BLUE = "#007bff" - CYAN = "#17a2b8" - GREEN = "#28a745" - RED = "#dc3545" - YELLOW = "#ffc107" - def upgrade_datastore_91(self) -> None: def upgrade(topic: str, payload) -> Optional[dict]: if re.search("openWB/vehicle/template/ev_template/[0-9]+$", topic) is not None: @@ -2651,14 +2652,14 @@ def upgrade(topic: str, payload) -> Optional[dict]: vehicle_color_topic = topic.replace("/name", "/color") log.debug(f"Checking for vehicle color topic {vehicle_color_topic}") if vehicle_color_topic not in self.all_received_topics: - log.debug(f"Adding vehicle color topic {vehicle_color_topic} with value '#17a2b8'") - return {vehicle_color_topic: self.CYAN} + log.debug(f"Adding vehicle color topic {vehicle_color_topic} with value '{COLOR_VEHICLE}'") + return {vehicle_color_topic: COLOR_VEHICLE} # add property "color" to charge points if re.search("^openWB/chargepoint/[0-9]+/config$", topic) is not None: config = decode_payload(payload) log.debug(f"Received charge point config topic {topic} with payload {payload}") if "color" not in config: - config.update({"color": self.BLUE}) + config.update({"color": COLOR_CHARGEPOINT}) log.debug(f"Added color to charge point config {config}") return {topic: config} # add property "color" to components @@ -2667,14 +2668,14 @@ def upgrade(topic: str, payload) -> Optional[dict]: log.debug(f"Received component config topic {topic} with payload {payload}") if "color" not in config: if "counter" in config.get("type").lower(): - config.update({"color": self.RED}) + config.update({"color": COLOR_COUNTER}) elif "bat" in config.get("type").lower(): - config.update({"color": self.YELLOW}) + config.update({"color": COLOR_BATTERY}) elif "inverter" in config.get("type").lower(): - config.update({"color": self.GREEN}) + config.update({"color": COLOR_INVERTER}) else: log.warning(f"Unknown component type {config.get('type')} for topic {topic}.") - config.update({"color": self.BLACK}) + config.update({"color": COLOR_UNKNOWN}) log.debug(f"Updated component config with color {config}") return {topic: config} self._loop_all_received_topics(upgrade) @@ -2690,17 +2691,17 @@ def process_file(self, file): return for key in content["names"].keys(): if "bat" in key: - colors[key] = self.YELLOW + colors[key] = COLOR_BATTERY elif "counter" in key: - colors[key] = self.RED + colors[key] = COLOR_COUNTER elif "cp" in key: - colors[key] = self.BLUE + colors[key] = COLOR_CHARGEPOINT elif "ev" in key: - colors[key] = self.CYAN + colors[key] = COLOR_VEHICLE elif "inverter" in key: - colors[key] = self.GREEN + colors[key] = COLOR_INVERTER else: - colors[key] = self.BLACK + colors[key] = COLOR_UNKNOWN content["colors"] = colors jsonFile.seek(0) jsonFile.write(json.dumps(content)) From f824b4ea576414007f1da38122076d65035edeff Mon Sep 17 00:00:00 2001 From: Lutz Bender Date: Mon, 20 Oct 2025 13:16:27 +0200 Subject: [PATCH 10/10] upgrade method --- packages/helpermodules/update_config.py | 100 ++++++++++++------------ 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index a4f294bfba..6775b1c2a2 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -55,14 +55,6 @@ NO_MODULE = {"type": None, "configuration": {}} -# Default colors -COLOR_CHARGEPOINT = "#007bff" # Default color for charge points: blue -COLOR_VEHICLE = "#17a2b8" # Default color for vehicles: teal -COLOR_INVERTER = "#28a745" # Default color for inverters: green -COLOR_COUNTER = "#dc3545" # Default color for counters: red -COLOR_BATTERY = "#ffc107" # Default color for batteries: yellow -COLOR_UNKNOWN = "#000000" # Default color for unknown components: black - class UpdateConfig: @@ -2638,71 +2630,81 @@ def upgrade(topic: str, payload) -> None: self._append_datastore_version(101) def upgrade_datastore_102(self) -> None: + DEFAULT_COLORS = { + "CHARGEPOINT": "#007bff", + "VEHICLE": "#17a2b8", + "INVERTER": "#28a745", + "COUNTER": "#dc3545", + "BATTERY": "#ffc107", + "UNKNOWN": "#000000" + } + + def _add_colors_to_log(file): + colors = {} + with open(file, "r+") as jsonFile: + content_raw = jsonFile.read() + content = json.loads(content_raw) + if "colors" in content: + return + for key in content["names"].keys(): + if "bat" in key: + colors[key] = DEFAULT_COLORS["BATTERY"] + elif "counter" in key: + colors[key] = DEFAULT_COLORS["COUNTER"] + elif "cp" in key: + colors[key] = DEFAULT_COLORS["CHARGEPOINT"] + elif "ev" in key: + colors[key] = DEFAULT_COLORS["VEHICLE"] + elif "inverter" in key: + colors[key] = DEFAULT_COLORS["INVERTER"] + else: + colors[key] = DEFAULT_COLORS["UNKNOWN"] + content["colors"] = colors + jsonFile.seek(0) + jsonFile.write(json.dumps(content)) + jsonFile.truncate() + def add_colors_to_logs(): files = glob.glob(str(self.base_path / "data" / "daily_log") + "/*") files.extend(glob.glob(str(self.base_path / "data" / "monthly_log") + "/*")) files.sort() with ProcessPoolExecutor() as executor: - executor.map(self.process_file, files) + executor.map(_add_colors_to_log, files) def upgrade(topic: str, payload) -> Optional[dict]: # add vehicle color to vehicle topics if re.search("^openWB/vehicle/[0-9]+/name$", topic) is not None: - log.debug(f"Received vehicle name topic {topic}") + log.debug(f"Received vehicle name topic '{topic}'") vehicle_color_topic = topic.replace("/name", "/color") - log.debug(f"Checking for vehicle color topic {vehicle_color_topic}") + log.debug(f"Checking for vehicle color topic '{vehicle_color_topic}'") if vehicle_color_topic not in self.all_received_topics: - log.debug(f"Adding vehicle color topic {vehicle_color_topic} with value '{COLOR_VEHICLE}'") - return {vehicle_color_topic: COLOR_VEHICLE} + log.debug(f"Adding vehicle color topic '{vehicle_color_topic}'" + f" with value: '{DEFAULT_COLORS['VEHICLE']}'") + return {vehicle_color_topic: DEFAULT_COLORS['VEHICLE']} # add property "color" to charge points if re.search("^openWB/chargepoint/[0-9]+/config$", topic) is not None: config = decode_payload(payload) - log.debug(f"Received charge point config topic {topic} with payload {payload}") + log.debug(f"Received charge point config topic '{topic}' with payload: {payload}") if "color" not in config: - config.update({"color": COLOR_CHARGEPOINT}) - log.debug(f"Added color to charge point config {config}") + config.update({"color": DEFAULT_COLORS['CHARGEPOINT']}) + log.debug(f"Added color to charge point config: {config}") return {topic: config} # add property "color" to components if re.search("^openWB/system/device/[0-9]+/component/[0-9]+/config$", topic) is not None: config = decode_payload(payload) - log.debug(f"Received component config topic {topic} with payload {payload}") + log.debug(f"Received component config topic '{topic}' with payload: {payload}") if "color" not in config: if "counter" in config.get("type").lower(): - config.update({"color": COLOR_COUNTER}) + config.update({"color": DEFAULT_COLORS['COUNTER']}) elif "bat" in config.get("type").lower(): - config.update({"color": COLOR_BATTERY}) + config.update({"color": DEFAULT_COLORS['BATTERY']}) elif "inverter" in config.get("type").lower(): - config.update({"color": COLOR_INVERTER}) + config.update({"color": DEFAULT_COLORS['INVERTER']}) else: - log.warning(f"Unknown component type {config.get('type')} for topic {topic}.") - config.update({"color": COLOR_UNKNOWN}) - log.debug(f"Updated component config with color {config}") + log.warning(f"Unknown component type '{config.get('type')}' for topic '{topic}'.") + config.update({"color": DEFAULT_COLORS['UNKNOWN']}) + log.debug(f"Updated component config with color: {config}") return {topic: config} self._loop_all_received_topics(upgrade) add_colors_to_logs() - self.__update_topic("openWB/system/datastore_version", 103) - - def process_file(self, file): - colors = {} - with open(file, "r+") as jsonFile: - content_raw = jsonFile.read() - content = json.loads(content_raw) - if "colors" in content: - return - for key in content["names"].keys(): - if "bat" in key: - colors[key] = COLOR_BATTERY - elif "counter" in key: - colors[key] = COLOR_COUNTER - elif "cp" in key: - colors[key] = COLOR_CHARGEPOINT - elif "ev" in key: - colors[key] = COLOR_VEHICLE - elif "inverter" in key: - colors[key] = COLOR_INVERTER - else: - colors[key] = COLOR_UNKNOWN - content["colors"] = colors - jsonFile.seek(0) - jsonFile.write(json.dumps(content)) - jsonFile.truncate() + self._append_datastore_version(102)