diff --git a/packages/modules/http/bat.py b/packages/modules/http/bat.py index 50f36a8158..3573ea05bd 100644 --- a/packages/modules/http/bat.py +++ b/packages/modules/http/bat.py @@ -12,20 +12,20 @@ def get_default_config() -> dict: "id": 0, "type": "bat", "configuration": { - "power_path": "", - "imported_path": "none", - "exported_path": "none", - "soc_path": "" + "power_path": None, + "imported_path": None, + "exported_path": None, + "soc_path": None } } class HttpBat: - def __init__(self, device_id: int, component_config: dict, domain: str) -> None: - self.__get_power = create_request_function(domain, component_config["configuration"]["power_path"]) - self.__get_imported = create_request_function(domain, component_config["configuration"]["imported_path"]) - self.__get_exported = create_request_function(domain, component_config["configuration"]["exported_path"]) - self.__get_soc = create_request_function(domain, component_config["configuration"]["soc_path"]) + def __init__(self, device_id: int, component_config: dict, url: str) -> None: + self.__get_power = create_request_function(url, component_config["configuration"]["power_path"]) + self.__get_imported = create_request_function(url, component_config["configuration"]["imported_path"]) + self.__get_exported = create_request_function(url, component_config["configuration"]["exported_path"]) + self.__get_soc = create_request_function(url, component_config["configuration"]["soc_path"]) self.__device_id = device_id self.component_config = component_config diff --git a/packages/modules/http/counter.py b/packages/modules/http/counter.py index 16fca0a1b3..fbb7392303 100644 --- a/packages/modules/http/counter.py +++ b/packages/modules/http/counter.py @@ -12,23 +12,23 @@ def get_default_config() -> dict: "id": 0, "type": "counter", "configuration": { - "power_path": "", - "imported_path": "none", - "exported_path": "none", - "current_l1_path": "none", - "current_l2_path": "none", - "current_l3_path": "none", + "power_path": None, + "imported_path": None, + "exported_path": None, + "current_l1_path": None, + "current_l2_path": None, + "current_l3_path": None, } } class HttpCounter: - def __init__(self, device_id: int, component_config: dict, domain: str) -> None: - self.__get_power = create_request_function(domain, component_config["configuration"]["power_path"]) - self.__get_imported = create_request_function(domain, component_config["configuration"]["imported_path"]) - self.__get_exported = create_request_function(domain, component_config["configuration"]["exported_path"]) + def __init__(self, device_id: int, component_config: dict, url: str) -> None: + self.__get_power = create_request_function(url, component_config["configuration"]["power_path"]) + self.__get_imported = create_request_function(url, component_config["configuration"]["imported_path"]) + self.__get_exported = create_request_function(url, component_config["configuration"]["exported_path"]) self.__get_currents = [ - create_request_function(domain, + create_request_function(url, component_config["configuration"]["current_l" + str(i) + "_path"]) for i in range(1, 4) ] diff --git a/packages/modules/http/device.py b/packages/modules/http/device.py index b846f9f8e9..3af141443d 100644 --- a/packages/modules/http/device.py +++ b/packages/modules/http/device.py @@ -3,8 +3,6 @@ import re from typing import Dict, Union, List -from urllib3.util import parse_url - from helpermodules.cli import run_using_positional_cli_args from modules.common.abstract_device import AbstractDevice from modules.common.component_context import SingleComponentUpdateContext @@ -21,13 +19,52 @@ def get_default_config() -> dict: "type": "http", "id": 0, "configuration": { - "protocol": "http", - "domain": None, - "port": 80 + "url": None } } +class HttpConfiguration: + def __init__(self, url: str): + self.url = url + + @staticmethod + def from_dict(device_config: dict): + keys = ["url"] + try: + values = [device_config[key] for key in keys] + except KeyError as e: + raise Exception( + "Illegal configuration <{}>: Expected object with properties: {}".format(device_config, keys) + ) from e + return HttpConfiguration(*values) + + +class Http: + def __init__(self, name: str, type: str, id: int, configuration: HttpConfiguration) -> None: + self.name = name + self.type = type + self.id = id + self.configuration = configuration + + @staticmethod + def from_dict(device_config: dict): + keys = ["name", "type", "id", "configuration"] + try: + values = [device_config[key] for key in keys] + values = [] + for key in keys: + if isinstance(device_config[key], Dict): + values.append(HttpConfiguration.from_dict(device_config[key])) + else: + values.append(device_config[key]) + except KeyError as e: + raise Exception( + "Illegal configuration <{}>: Expected object with properties: {}".format(device_config, keys) + ) from e + return Http(*values) + + http_component_classes = Union[bat.HttpBat, counter.HttpCounter, inverter.HttpInverter] @@ -41,12 +78,9 @@ class Device(AbstractDevice): def __init__(self, device_config: dict) -> None: self.components = {} # type: Dict[str, http_component_classes] try: - self.device_config = device_config - port = self.device_config["configuration"]["port"] - self.domain = self.device_config["configuration"]["protocol"] + \ - "://" + self.device_config["configuration"]["domain"] - if port is not None: - self.domain = self.domain + ":" + str(port) + self.device_config = device_config \ + if isinstance(device_config, Http) \ + else Http.from_dict(device_config) except Exception: log.exception("Fehler im Modul "+device_config["name"]) @@ -54,7 +88,7 @@ def add_component(self, component_config: dict) -> None: component_type = component_config["type"] if component_type in self.COMPONENT_TYPE_TO_CLASS: self.components["component"+str(component_config["id"])] = self.COMPONENT_TYPE_TO_CLASS[component_type]( - self.device_config["id"], component_config, self.domain) + self.device_config.id, component_config, self.device_config.configuration.url) else: raise Exception( "illegal component type " + component_type + ". Allowed values: " + @@ -70,7 +104,7 @@ def update(self) -> None: self.components[component].update() else: log.warning( - self.device_config["name"] + + self.device_config.name + ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden." ) @@ -104,14 +138,13 @@ def run_device_legacy(device_config: dict, component_config: dict): def create_legacy_device_config(url: str): - parsed_url = parse_url(url) + regex = re.compile("^(https?://[^/]+)(.*)") + match = regex.search(url) + if match is None: + raise Exception("Invalid URL <" + url + ">: Absolute HTTP or HTTPS URL required") + host_scheme = match.group(1) device_config = get_default_config() - device_config["configuration"]["protocol"] = parsed_url.scheme - device_config["configuration"]["domain"] = parsed_url.hostname - if parsed_url.port is not None: - device_config["configuration"]["port"] = int(parsed_url.port) - else: - device_config["configuration"]["port"] = None + device_config["configuration"]["url"] = host_scheme return device_config diff --git a/packages/modules/http/inverter.py b/packages/modules/http/inverter.py index f782b5ac41..d94b6b09ab 100644 --- a/packages/modules/http/inverter.py +++ b/packages/modules/http/inverter.py @@ -14,16 +14,16 @@ def get_default_config() -> dict: "id": 0, "type": "inverter", "configuration": { - "power_path": "", - "counter_path": "none", + "power_path": None, + "counter_path": None } } class HttpInverter: - def __init__(self, device_id: int, component_config: dict, domain: str) -> None: - self.__get_power = create_request_function(domain, component_config["configuration"]["power_path"]) - self.__get_counter = create_request_function(domain, component_config["configuration"]["counter_path"]) + def __init__(self, device_id: int, component_config: dict, url: str) -> None: + self.__get_power = create_request_function(url, component_config["configuration"]["power_path"]) + self.__get_counter = create_request_function(url, component_config["configuration"]["counter_path"]) self.__device_id = device_id self.component_config = component_config diff --git a/packages/modules/json/device.py b/packages/modules/json/device.py index 8f916ce4ba..5451347713 100644 --- a/packages/modules/json/device.py +++ b/packages/modules/json/device.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import logging from typing import Dict, List, Union, Optional -from urllib3.util import parse_url from helpermodules.cli import run_using_positional_cli_args from modules.common import req @@ -20,13 +19,52 @@ def get_default_config() -> dict: "type": "json", "id": 0, "configuration": { - "protocol": "http", - "domain": None, - "port": 80 + "url": None } } +class JsonConfiguration: + def __init__(self, url: str): + self.url = url + + @staticmethod + def from_dict(device_config: dict): + keys = ["url"] + try: + values = [device_config[key] for key in keys] + except KeyError as e: + raise Exception( + "Illegal configuration <{}>: Expected object with properties: {}".format(device_config, keys) + ) from e + return JsonConfiguration(*values) + + +class Json: + def __init__(self, name: str, type: str, id: int, configuration: JsonConfiguration) -> None: + self.name = name + self.type = type + self.id = id + self.configuration = configuration + + @staticmethod + def from_dict(device_config: dict): + keys = ["name", "type", "id", "configuration"] + try: + values = [device_config[key] for key in keys] + values = [] + for key in keys: + if isinstance(device_config[key], Dict): + values.append(JsonConfiguration.from_dict(device_config[key])) + else: + values.append(device_config[key]) + except KeyError as e: + raise Exception( + "Illegal configuration <{}>: Expected object with properties: {}".format(device_config, keys) + ) from e + return Json(*values) + + json_component_classes = Union[bat.JsonBat, counter.JsonCounter, inverter.JsonInverter] @@ -40,11 +78,9 @@ class Device(AbstractDevice): def __init__(self, device_config: dict) -> None: self.components = {} # type: Dict[str, json_component_classes] try: - self.device_config = device_config - port = self.device_config["configuration"]["port"] - self.domain = self.device_config["configuration"]["protocol"] + \ - "://" + self.device_config["configuration"]["domain"] + \ - ":" + str(port) if port else "" + self.device_config = device_config \ + if isinstance(device_config, Json) \ + else Json.from_dict(device_config) except Exception: log.exception("Fehler im Modul "+device_config["name"]) @@ -52,7 +88,7 @@ def add_component(self, component_config: dict) -> None: component_type = component_config["type"] if component_type in self.COMPONENT_TYPE_TO_CLASS: self.components["component"+str(component_config["id"])] = self.COMPONENT_TYPE_TO_CLASS[component_type]( - self.device_config["id"], component_config) + self.device_config.id, component_config) else: raise Exception( "illegal component type " + component_type + ". Allowed values: " + @@ -63,26 +99,22 @@ def update(self) -> None: log.debug("Start device reading " + str(self.components)) if self.components: with MultiComponentUpdateContext(self.components): - response = req.get_http_session().get(self.domain, timeout=5) + response = req.get_http_session().get(self.device_config.configuration.url, timeout=5) for component in self.components: self.components[component].update(response.json()) else: log.warning( - self.device_config["name"] + + self.device_config.name + ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden." ) -def read_legacy(ip_address: str, component_config: dict, num: Optional[int] = None, **kwargs) -> None: +def read_legacy(url: str, component_config: dict, num: Optional[int] = None, **kwargs) -> None: component_config["configuration"].update(kwargs) component_config["id"] = num - parsed_url = parse_url(ip_address) device_config = get_default_config() - device_config["configuration"]["protocol"] = parsed_url.scheme - device_config["configuration"]["domain"] = parsed_url.hostname - device_config["configuration"]["port"] = int(parsed_url.port) - + device_config["configuration"]["url"] = url dev = Device(device_config) dev.add_component(component_config) dev.update()