diff --git a/data/config/configuration.json b/data/config/configuration.json new file mode 100644 index 0000000000..d765199d71 --- /dev/null +++ b/data/config/configuration.json @@ -0,0 +1 @@ +{"openwb-version": 1, "ripple_control_receiver_configured": false, "max_c_socket": 32} \ No newline at end of file diff --git a/packages/control/general.py b/packages/control/general.py index 05b9564639..64d99a1cf5 100644 --- a/packages/control/general.py +++ b/packages/control/general.py @@ -6,8 +6,10 @@ from typing import List, Optional from control import data +from helpermodules import hardware_configuration from helpermodules.pub import Pub from helpermodules import timecheck +from modules import ripple_control_receiver log = logging.getLogger(__name__) @@ -179,3 +181,15 @@ def grid_protection(self): "openWB/set/general/grid_protection_random_stop", 0) except Exception: log.exception("Fehler im General-Modul") + + def check_ripple_control_receiver(self): + configured = hardware_configuration.get_hardware_configuration_setting( + "ripple_control_receiver_configured") + Pub().pub("openWB/set/general/ripple_control_receiver/configured", configured) + self.data.ripple_control_receiver.configured = configured + if configured: + r1_active, r2_active = ripple_control_receiver.read() + self.data.ripple_control_receiver.r1_active = r1_active + Pub().pub("openWB/set/general/ripple_control_receiver/r1_active", r1_active) + self.data.ripple_control_receiver.r2_active = r2_active + Pub().pub("openWB/set/general/ripple_control_receiver/r2_active", r2_active) diff --git a/packages/control/prepare.py b/packages/control/prepare.py index 2db06097a1..a5f02f185e 100644 --- a/packages/control/prepare.py +++ b/packages/control/prepare.py @@ -18,6 +18,7 @@ def setup_algorithm(self) -> None: """ bereitet die Daten für den Algorithmus vor und startet diesen. """ try: + data.data.general_data.check_ripple_control_receiver() for cp in data.data.cp_data.values(): cp.reset_values_at_start() data.data.bat_all_data.setup_bat() diff --git a/packages/helpermodules/data_migration/data_migration.py b/packages/helpermodules/data_migration/data_migration.py index ccbb59e68b..80bcfd9876 100644 --- a/packages/helpermodules/data_migration/data_migration.py +++ b/packages/helpermodules/data_migration/data_migration.py @@ -16,11 +16,12 @@ import shutil import tarfile from threading import Thread -from typing import Callable, Dict, List, Union +from typing import Callable, Dict, List, Optional, Union from control import data, ev from dataclass_utils import dataclass_from_dict from helpermodules.data_migration.id_mapping import MapId +from helpermodules.hardware_configuration import update_hardware_configuration from helpermodules.measurement_log import LegacySmartHomeLogData, get_names, get_totals, string_to_float, string_to_int from helpermodules.utils import thread_handler from helpermodules.pub import Pub @@ -65,19 +66,44 @@ def __len__(self): class MigrateData: + MAJOR_VERSION = 1 + MINOR_VERSION = 9 + PATCH_VERSION = 303 BACKUP_DATA_PATH = "./data/data_migration/var/www/html/openWB/web/logging/data" def __init__(self, id_map: Dict) -> None: self.id_map = dataclass_from_dict(MapId, id_map) def migrate(self): - self.extract_files("ladelog") - self.extract_files("daily") - self.extract_files("monthly") - thread_handler(self.convert_csv_to_json_chargelog(), None) - thread_handler(self.convert_csv_to_json_measurement_log("daily"), None) - thread_handler(self.convert_csv_to_json_measurement_log("monthly"), None) - self.move_serial_number_cloud_data() + try: + self._extract() + self._check_version() + thread_handler(self.convert_csv_to_json_chargelog(), None) + thread_handler(self.convert_csv_to_json_measurement_log("daily"), None) + thread_handler(self.convert_csv_to_json_measurement_log("monthly"), None) + self._migrate_settings_from_openwb_conf() + except Exception as e: + raise e + finally: + self._remove_migration_data() + + def _check_version(self): + with open("./data/data_migration/var/www/html/openWB/web/version") as f: + version = f.read().replace("\n", "") + sub_version = version.split(".") + if not (int(sub_version[0]) > self.MAJOR_VERSION or ( + (int(sub_version[0]) == self.MAJOR_VERSION) and ( + (int(sub_version[1]) > self.MINOR_VERSION) or + ((int(sub_version[1]) == self.MINOR_VERSION) and + (int(sub_version[2]) >= self.PATCH_VERSION)) + ) + )): + self._remove_migration_data() + raise ValueError(f"Das Backup für die Datenübernahme muss mindestens mit Version {self.MAJOR_VERSION}." + f"{self.MINOR_VERSION}.{self.PATCH_VERSION} erstellt worden sein. " + f"Backup-Version ist {version}.") + + def _remove_migration_data(self): shutil.rmtree("./data/data_migration/var") os.remove("./data/data_migration/data_migration.tar.gz") @@ -89,11 +115,19 @@ def _file_to_extract_generator(self, members, log_folder_name: str): if tarinfo.name.startswith(f"var/www/html/openWB/web/logging/data/{log_folder_name}"): yield tarinfo - def extract_files(self, log_folder_name: str): + def _extract_files(self, log_folder_name: str): with tarfile.open('./data/data_migration/data_migration.tar.gz') as tar: tar.extractall(members=self._file_to_extract_generator( tar, log_folder_name), path="./data/data_migration") + def _extract(self): + self._extract_files("ladelog") + self._extract_files("daily") + self._extract_files("monthly") + with tarfile.open('./data/data_migration/data_migration.tar.gz') as tar: + tar.extract(member="var/www/html/openWB/openwb.conf", path="./data/data_migration") + tar.extract(member="var/www/html/openWB/web/version", path="./data/data_migration") + def convert_csv_to_json_chargelog(self) -> List[Thread]: """ konvertiert die alten Lade-Log-Dateien in das neue Format für 2.x. """ @@ -487,37 +521,62 @@ def _monthly_log_entry(self, file: str): log.exception(f"Fehler beim Konvertieren des Monats-Logs vom {file}, Reihe {row}") return entries - def move_serial_number_cloud_data(self) -> None: - def strip_openwb_conf_entry(entry: str, key: str) -> str: - value = entry.replace(f"{key}=", "") - return value.rstrip("\n") - with tarfile.open('./data/data_migration/data_migration.tar.gz') as tar: - tar.extract(member="var/www/html/openWB/openwb.conf", path="./data/data_migration") - with open("./data/data_migration/var/www/html/openWB/openwb.conf", "r") as file: - serial_number = "" - openwb_conf = file.readlines() - for line in openwb_conf: - if "snnumber" in line: - serial_number = strip_openwb_conf_entry(line, "snnumber") - break - else: - log.debug("Keine Seriennummer gefunden.") - with open("/home/openwb/snnumber", "w") as file: - file.write(f"snnumber={serial_number}") + def _get_openwb_conf_value(self, key: str) -> Optional[str]: + value = None + for line in self.openwb_conf: + if key in line: + raw_value = line.replace(f"{key}=", "") + value = raw_value.rstrip("\n") + break + return value + def _migrate_settings_from_openwb_conf(self): with open("./data/data_migration/var/www/html/openWB/openwb.conf", "r") as file: - cloud_user = "" - cloud_pw = "" - openwb_conf = file.readlines() - for line in openwb_conf: - if "clouduser" in line: - cloud_user = strip_openwb_conf_entry(line, "clouduser") - elif "cloudpw" in line: - cloud_pw = strip_openwb_conf_entry(line, "cloudpw") - if cloud_user == "": - log.debug("Keine Cloud-Zugangsdaten gefunden.") - Pub().pub("openWB/set/command/data_migration/todo", - {"command": "connectCloud", "data": {"username": cloud_user, "password": cloud_pw, "partner": 0}}) + self.openwb_conf = file.readlines() + self._move_serial_number() + self._move_cloud_data() + self._move_rse() + self._move_max_c_socket() + self._move_pddate() + + def _move_serial_number(self) -> None: + serial_number = self._get_openwb_conf_value("snnumber") + if serial_number: + with open("/home/openwb/snnumber", "w") as file: + file.write(f"snnumber={serial_number}") + else: + log.debug("Keine Seriennummer gefunden.") + + def _move_cloud_data(self) -> None: + cloud_user = self._get_openwb_conf_value("clouduser") + cloud_pw = self._get_openwb_conf_value("cloudpw") + if cloud_user is not None and cloud_pw is not None: + Pub().pub("openWB/set/command/data_migration/todo", + {"command": "connectCloud", "data": {"username": cloud_user, "password": cloud_pw, "partner": 0}}) + else: + log.debug("Keine Cloud-Zugangsdaten gefunden.") + + def _move_rse(self) -> None: + rse = bool(self._get_openwb_conf_value("rseenabled")) + if rse is None: + log.debug("Keine Rundsteuerempfänger-Konfiguration gefunden. Setze auf False.") + rse = False + update_hardware_configuration({"ripple_control_receiver_configured": rse}) + + def _move_max_c_socket(self): + max_c_socket = self._get_openwb_conf_value("ppbuchse") + if max_c_socket is None: + log.debug("Keine max_c_socket-Konfiguration gefunden. Setze auf False.") + max_c_socket = 32 + update_hardware_configuration({"max_c_socket": max_c_socket}) + + def _move_pddate(self) -> None: + pddate = self._get_openwb_conf_value("pddate") + if pddate is not None: + with open("/home/openwb/pddate", "w") as file: + file.write(f"pddate={pddate}") + else: + log.debug("Kein Produktionsdatum gefunden.") NOT_CONFIGURED = " wurde in openWB software2 nicht konfiguriert." diff --git a/packages/helpermodules/hardware_configuration.py b/packages/helpermodules/hardware_configuration.py new file mode 100644 index 0000000000..e0d3cb2839 --- /dev/null +++ b/packages/helpermodules/hardware_configuration.py @@ -0,0 +1,15 @@ +import json +from typing import Dict + + +def update_hardware_configuration(new_setting: Dict) -> None: + with open("/home/openwb/configuration.json", "r") as f: + data = json.loads(f.read()) + with open("/home/openwb/configuration.json", "w") as f: + data.update(new_setting) + f.write(json.dumps(data)) + + +def get_hardware_configuration_setting(name: str): + with open("/home/openwb/configuration.json", "r") as f: + return json.loads(f.read())[name] diff --git a/packages/helpermodules/subdata.py b/packages/helpermodules/subdata.py index f08d2ccec8..28f01bb882 100644 --- a/packages/helpermodules/subdata.py +++ b/packages/helpermodules/subdata.py @@ -544,7 +544,7 @@ def process_general_topic(self, var: general.General, msg: mqtt.MQTTMessage): try: if re.search("/general/", msg.topic) is not None: if re.search("/general/ripple_control_receiver/", msg.topic) is not None: - self.set_json_payload_class(var.data.ripple_control_receiver, msg) + return elif re.search("/general/chargemode_config/", msg.topic) is not None: if re.search("/general/chargemode_config/pv_charging/", msg.topic) is not None: self.set_json_payload_class(var.data.chargemode_config.pv_charging, msg) diff --git a/packages/modules/internal_chargepoint_handler/internal_chargepoint_handler.py b/packages/modules/internal_chargepoint_handler/internal_chargepoint_handler.py index cc1377350d..a2619c1758 100644 --- a/packages/modules/internal_chargepoint_handler/internal_chargepoint_handler.py +++ b/packages/modules/internal_chargepoint_handler/internal_chargepoint_handler.py @@ -26,8 +26,6 @@ except ImportError: log.info("failed to import RPi.GPIO! maybe we are not running on a pi") -SOCKET_MAX_CURRENT: int = 16 - class UpdateValues: def __init__(self, local_charge_point_num: int, parent_ip: str, parent_cp: str) -> None: @@ -198,7 +196,7 @@ def __init__(self, self.local_charge_point_num = local_charge_point_num if local_charge_point_num == 0: if mode == InternalChargepointMode.SOCKET.value: - self.module = Socket(SOCKET_MAX_CURRENT, local_charge_point_num, client_handler, global_data.parent_ip) + self.module = Socket(local_charge_point_num, client_handler, global_data.parent_ip) else: self.module = chargepoint_module.ChargepointModule( local_charge_point_num, client_handler, global_data.parent_ip) diff --git a/packages/modules/internal_chargepoint_handler/socket.py b/packages/modules/internal_chargepoint_handler/socket.py index d4c473c4b9..3ad8df0b3c 100644 --- a/packages/modules/internal_chargepoint_handler/socket.py +++ b/packages/modules/internal_chargepoint_handler/socket.py @@ -3,6 +3,7 @@ import logging import time from typing import Callable, Tuple +from helpermodules.hardware_configuration import get_hardware_configuration_setting from modules.common.component_context import SingleComponentUpdateContext from modules.common.component_state import ChargepointState @@ -45,12 +46,11 @@ class ActorState(IntEnum): class Socket(ChargepointModule): def __init__(self, - socket_max_current: int, local_charge_point_num: int, client_handler: ClientHandler, parent_hostname: str) -> None: - log.debug("Konfiguration als Buchse.") - self.socket_max_current = socket_max_current + self.socket_max_current = get_hardware_configuration_setting("max_c_socket") + log.debug(f"Konfiguration als Buchse mit maximal {self.socket_max_current}A Ladestrom je Phase.") super().__init__(local_charge_point_num, client_handler, parent_hostname) def set_current(self, current: float) -> None: diff --git a/packages/modules/ripple_control_receiver.py b/packages/modules/ripple_control_receiver.py index 1e814cf8e9..5c722a0ed2 100644 --- a/packages/modules/ripple_control_receiver.py +++ b/packages/modules/ripple_control_receiver.py @@ -1,6 +1,5 @@ import logging -import time -from helpermodules.pub import Pub +from typing import Tuple log = logging.getLogger(__name__) has_gpio = True @@ -13,25 +12,20 @@ log.warning("RSE disabled!") -def read(): +def read() -> Tuple[bool, bool]: rse1: bool = False rse2: bool = False if has_gpio: - GPIO.setmode(GPIO.BCM) - GPIO.setup(8, GPIO.IN, pull_up_down=GPIO.PUD_UP) - GPIO.setup(9, GPIO.IN, pull_up_down=GPIO.PUD_UP) + GPIO.setmode(GPIO.BOARD) + GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP) + GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP) try: - button1_state = GPIO.input(8) - button2_state = GPIO.input(9) - - time.sleep(10.2) - - rse1 = not button1_state - rse2 = not button2_state + rse1 = GPIO.input(24) == GPIO.LOW + rse2 = GPIO.input(21) == GPIO.LOW except Exception: GPIO.cleanup() - log.exception() - Pub().pub("openWB/set/general/ripple_control_receiver/r1_active", rse1) - Pub().pub("openWB/set/general/ripple_control_receiver/r2_active", rse2) + log.exception("Fehler beim Auslesen der Rundsteuer-Kontakte.") + log.debug(f"RSE1-Status: {rse1}, RSE2-Satus: {rse2}") + return rse1, rse2 diff --git a/runs/atreboot.sh b/runs/atreboot.sh index 4040bea074..190133e2fb 100755 --- a/runs/atreboot.sh +++ b/runs/atreboot.sh @@ -290,6 +290,11 @@ chmod 666 "$LOGFILE" fi echo "mosquitto done" + # check for home configuration + if [[ ! -f "/home/openwb/configuration.json" ]]; then + sudo cp -a "${OPENWBBASEDIR}/data/config/configuration.json" "/home/openwb/configuration.json" + fi + # check for python dependencies echo "install required python packages with 'pip3'..." pip3 install -r "${OPENWBBASEDIR}/requirements.txt"