diff --git a/docs/samples/sample_modbus/device.py b/docs/samples/sample_modbus/device.py index 70b4372277..22b1957857 100644 --- a/docs/samples/sample_modbus/device.py +++ b/docs/samples/sample_modbus/device.py @@ -33,7 +33,7 @@ def update_components(components: Iterable[Union[SampleBat, SampleCounter, Sampl component.update(c) try: - client = ModbusTcpClient_(device_config.configuration.ip_address, port) + client = ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port) except Exception: log.exception("Fehler in create_device") return ConfigurableDevice( diff --git a/packages/modules/devices/byd/bat.py b/packages/modules/devices/byd/bat.py index 330bc83316..c5c9cbfd03 100644 --- a/packages/modules/devices/byd/bat.py +++ b/packages/modules/devices/byd/bat.py @@ -3,7 +3,6 @@ from html.parser import HTMLParser from typing import Dict, List, Union, Tuple -from dataclass_utils import dataclass_from_dict from modules.devices.byd.config import BYDBatSetup from modules.common import req from modules.common.component_state import BatState @@ -20,7 +19,7 @@ def __init__(self, component_config: Union[Dict, BYDBatSetup], device_config) -> None: self.__device_config = device_config - self.component_config = dataclass_from_dict(BYDBatSetup, component_config) + self.component_config = component_config self.sim_counter = SimCounter(self.__device_config.id, self.component_config.id, prefix="speicher") self.store = get_bat_value_store(self.component_config.id) self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) diff --git a/packages/modules/devices/byd/device.py b/packages/modules/devices/byd/device.py index 503bc6d26d..116c7244e2 100644 --- a/packages/modules/devices/byd/device.py +++ b/packages/modules/devices/byd/device.py @@ -1,90 +1,25 @@ #!/usr/bin/env python3 import logging -from typing import Dict, Optional, List, Union -from dataclass_utils import dataclass_from_dict -from helpermodules.cli import run_using_positional_cli_args -from modules.devices.byd.config import BYD, BYDBatSetup, BYDConfiguration +from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, IndependentComponentUpdater +from modules.devices.byd.config import BYD, BYDBatSetup from modules.devices.byd import bat -from modules.common.abstract_device import AbstractDevice, DeviceDescriptor -from modules.common.component_context import SingleComponentUpdateContext +from modules.common.abstract_device import DeviceDescriptor log = logging.getLogger(__name__) -class Device(AbstractDevice): - COMPONENT_TYPE_TO_CLASS = { - "bat": bat.BYDBat - } +def create_device(device_config: BYD): + def create_bat_component(component_config: BYDBatSetup): + return bat.BYDBat(component_config, device_config) - def __init__(self, device_config: Union[Dict, BYD]) -> None: - self.components = {} # type: Dict[str, bat.BYDBat] - try: - self.device_config = dataclass_from_dict(BYD, device_config) - except Exception: - log.exception("Fehler im Modul "+self.device_config.name) - - def add_component(self, component_config: Union[Dict, BYDBatSetup]) -> None: - if isinstance(component_config, Dict): - component_type = component_config["type"] - else: - component_type = component_config.type - component_config = dataclass_from_dict(COMPONENT_TYPE_TO_MODULE[ - component_type].component_descriptor.configuration_factory, component_config) - if component_type in self.COMPONENT_TYPE_TO_CLASS: - self.components["component"+str(component_config.id)] = (self.COMPONENT_TYPE_TO_CLASS[component_type]( - component_config, - self.device_config)) - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(self.COMPONENT_TYPE_TO_CLASS.keys()) - ) - - def update(self) -> None: - log.debug("Start device reading " + str(self.components)) - if self.components: - for component in self.components: - # Auch wenn bei einer Komponente ein Fehler auftritt, sollen alle anderen noch ausgelesen werden. - with SingleComponentUpdateContext(self.components[component].fault_state): - self.components[component].update() - else: - log.warning( - self.device_config.name + - ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden." - ) - - -COMPONENT_TYPE_TO_MODULE = { - "bat": bat -} - - -def read_legacy(component_type: str, - ip_address: str, - username: str, - password: str, - num: Optional[int] = None) -> None: - dev = Device(BYD(configuration=BYDConfiguration(user=username, password=password, ip_address=ip_address))) - if component_type in COMPONENT_TYPE_TO_MODULE: - component_config = COMPONENT_TYPE_TO_MODULE[component_type].component_descriptor.configuration_factory() - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(COMPONENT_TYPE_TO_MODULE.keys()) - ) - component_config.id = num - dev.add_component(component_config) - - log.debug('byd IP-Adresse: ' + ip_address) - log.debug('byd Benutzer: ' + username) - log.debug('byd Passwort: ' + password) - - dev.update() - - -def main(argv: List[str]): - run_using_positional_cli_args(read_legacy, argv) + return ConfigurableDevice( + device_config=device_config, + component_factory=ComponentFactoryByType( + bat=create_bat_component + ), + component_updater=IndependentComponentUpdater(lambda component: component.update()) + ) device_descriptor = DeviceDescriptor(configuration_factory=BYD) diff --git a/packages/modules/devices/carlo_gavazzi/counter.py b/packages/modules/devices/carlo_gavazzi/counter.py index dc25dabe37..efa07162e4 100644 --- a/packages/modules/devices/carlo_gavazzi/counter.py +++ b/packages/modules/devices/carlo_gavazzi/counter.py @@ -3,7 +3,6 @@ from pymodbus.constants import Endian -from dataclass_utils import dataclass_from_dict from modules.devices.carlo_gavazzi.config import CarloGavazziCounterSetup from modules.common import modbus from modules.common.component_state import CounterState @@ -21,7 +20,7 @@ def __init__(self, tcp_client: modbus.ModbusTcpClient_, modbus_id: int) -> None: self.__device_id = device_id - self.component_config = dataclass_from_dict(CarloGavazziCounterSetup, component_config) + self.component_config = component_config self.__tcp_client = tcp_client self.__modbus_id = modbus_id self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="bezug") diff --git a/packages/modules/devices/carlo_gavazzi/device.py b/packages/modules/devices/carlo_gavazzi/device.py index 18623efe52..e29dfe17bc 100644 --- a/packages/modules/devices/carlo_gavazzi/device.py +++ b/packages/modules/devices/carlo_gavazzi/device.py @@ -1,89 +1,39 @@ #!/usr/bin/env python3 import logging -from typing import Dict, Optional, List, Union +from typing import Iterable -from dataclass_utils import dataclass_from_dict -from helpermodules.cli import run_using_positional_cli_args +from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, MultiComponentUpdater from modules.devices.carlo_gavazzi import counter from modules.devices.carlo_gavazzi.config import CarloGavazzi, CarloGavazziCounterSetup from modules.common import modbus -from modules.common.abstract_device import AbstractDevice, DeviceDescriptor +from modules.common.abstract_device import DeviceDescriptor from modules.common.component_context import SingleComponentUpdateContext log = logging.getLogger(__name__) -class Device(AbstractDevice): - COMPONENT_TYPE_TO_CLASS = { - "counter": counter.CarloGavazziCounter, - } - - def __init__(self, device_config: Union[Dict, CarloGavazzi]) -> None: - self.components = {} # type: Dict[str, counter.CarloGavazziCounter] - try: - self.device_config = dataclass_from_dict(CarloGavazzi, device_config) - self.client = modbus.ModbusTcpClient_( - self.device_config.configuration.ip_address, self.device_config.configuration.port) - except Exception: - log.exception("Fehler im Modul "+self.device_config.name) - - def add_component(self, component_config: Union[Dict, CarloGavazziCounterSetup]) -> None: - if isinstance(component_config, Dict): - component_type = component_config["type"] - else: - component_type = component_config.type - component_config = dataclass_from_dict(COMPONENT_TYPE_TO_MODULE[ - component_type].component_descriptor.configuration_factory, component_config) - 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.client, - self.device_config.configuration.modbus_id) - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(self.COMPONENT_TYPE_TO_CLASS.keys()) - ) - - def update(self) -> None: - log.debug("Start device reading " + str(self.components)) - if self.components: - for component in self.components: - # Auch wenn bei einer Komponente ein Fehler auftritt, sollen alle anderen noch ausgelesen werden. - with SingleComponentUpdateContext(self.components[component].fault_state): - self.components[component].update() - else: - log.warning( - self.device_config.name + - ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden." - ) - - -COMPONENT_TYPE_TO_MODULE = { - "counter": counter -} - - -def read_legacy(component_type: str, ip_address: str, num: Optional[int] = None) -> None: - device_config = CarloGavazzi() - device_config.configuration.ip_address = ip_address - dev = Device(device_config) - if component_type in COMPONENT_TYPE_TO_MODULE: - component_config = COMPONENT_TYPE_TO_MODULE[component_type].component_descriptor.configuration_factory() - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(COMPONENT_TYPE_TO_MODULE.keys()) - ) - component_config.id = num - dev.add_component(component_config) - - log.debug('carlo gavazzi IP-Adresse: ' + str(ip_address)) - - dev.update() - - -def main(argv: List[str]): - run_using_positional_cli_args(read_legacy, argv) +def create_device(device_config: CarloGavazzi): + def create_counter_component(component_config: CarloGavazziCounterSetup): + return counter.CarloGavazziCounter(device_config.id, component_config, client, + device_config.configuration.modbus_id) + + def update_components(components: Iterable[counter.CarloGavazziCounter]): + with client: + for component in components: + with SingleComponentUpdateContext(component.fault_state): + component.update() + + try: + client = modbus.ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port) + except Exception: + log.exception("Fehler in create_device") + return ConfigurableDevice( + device_config=device_config, + component_factory=ComponentFactoryByType( + counter=create_counter_component + ), + component_updater=MultiComponentUpdater(update_components) + ) device_descriptor = DeviceDescriptor(configuration_factory=CarloGavazzi) diff --git a/packages/modules/devices/good_we/counter.py b/packages/modules/devices/good_we/counter.py index ebc49bf258..a4b14bb2f3 100644 --- a/packages/modules/devices/good_we/counter.py +++ b/packages/modules/devices/good_we/counter.py @@ -25,7 +25,6 @@ def __init__(self, self.__modbus_id = modbus_id self.version = version self.firmware = firmware - self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="bezug") self.component_config = dataclass_from_dict(GoodWeCounterSetup, component_config) self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="bezug") self.__tcp_client = tcp_client diff --git a/packages/modules/devices/good_we/device.py b/packages/modules/devices/good_we/device.py index 2504aa2ca9..bddb34fa06 100644 --- a/packages/modules/devices/good_we/device.py +++ b/packages/modules/devices/good_we/device.py @@ -1,102 +1,56 @@ #!/usr/bin/env python3 import logging -from typing import Dict, List, Union, Optional +from typing import Iterable, Union -from dataclass_utils import dataclass_from_dict -from helpermodules.cli import run_using_positional_cli_args from modules.common import modbus -from modules.common.abstract_device import AbstractDevice, DeviceDescriptor +from modules.common.abstract_device import DeviceDescriptor from modules.common.component_context import SingleComponentUpdateContext +from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, MultiComponentUpdater from modules.devices.good_we import bat from modules.devices.good_we import counter from modules.devices.good_we import inverter -from modules.devices.good_we.config import (GoodWe, GoodWeBatSetup, GoodWeConfiguration, GoodWeCounterSetup, - GoodWeInverterSetup) +from modules.devices.good_we.config import GoodWe, GoodWeBatSetup, GoodWeCounterSetup, GoodWeInverterSetup log = logging.getLogger(__name__) good_we_component_classes = Union[bat.GoodWeBat, counter.GoodWeCounter, inverter.GoodWeInverter] -class Device(AbstractDevice): - COMPONENT_TYPE_TO_CLASS = { - "bat": bat.GoodWeBat, - "counter": counter.GoodWeCounter, - "inverter": inverter.GoodWeInverter - } - - def __init__(self, device_config: Union[Dict, GoodWe]) -> None: - self.components = {} # type: Dict[str, good_we_component_classes] - try: - self.device_config = dataclass_from_dict(GoodWe, device_config) - self.client = modbus.ModbusTcpClient_( - self.device_config.configuration.ip_address, self.device_config.configuration.port) - except Exception: - log.exception("Fehler im Modul " + self.device_config.name) - - def add_component(self, - component_config: Union[Dict, GoodWeBatSetup, GoodWeCounterSetup, GoodWeInverterSetup]) -> None: - if isinstance(component_config, Dict): - component_type = component_config["type"] - else: - component_type = component_config.type - component_config = dataclass_from_dict(COMPONENT_TYPE_TO_MODULE[ - component_type].component_descriptor.configuration_factory, - component_config) - 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, self.device_config.configuration.modbus_id, - self.device_config.configuration.version, self.device_config.configuration.firmware, - component_config, self.client)) - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(self.COMPONENT_TYPE_TO_CLASS.keys()) - ) - - def update(self) -> None: - log.debug("Start device reading " + str(self.components)) - if self.components: - for component in self.components: - # Auch wenn bei einer Komponente ein Fehler auftritt, sollen alle anderen noch ausgelesen werden. - with SingleComponentUpdateContext(self.components[component].fault_state): - self.components[component].update() - else: - log.warning( - self.device_config.name + - ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden." - ) - - -COMPONENT_TYPE_TO_MODULE = { - "bat": bat, - "counter": counter, - "inverter": inverter -} - - -def read_legacy(component_type: str, ip_address: str, id: int, num: Optional[int]) -> None: - device_config = GoodWe(configuration=GoodWeConfiguration(ip_address=ip_address, modbus_id=id)) - dev = Device(device_config) - if component_type in COMPONENT_TYPE_TO_MODULE: - component_config = COMPONENT_TYPE_TO_MODULE[component_type].component_descriptor.configuration_factory() - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(COMPONENT_TYPE_TO_MODULE.keys()) - ) - component_config.id = num - dev.add_component(component_config) - - log.debug('GoodWe IP-Adresse: ' + ip_address) - log.debug('GoodWe ID: ' + str(id)) - - dev.update() - dev.client.close() - - -def main(argv: List[str]): - run_using_positional_cli_args(read_legacy, argv) +def create_device(device_config: GoodWe): + def create_bat_component(component_config: GoodWeBatSetup): + return bat.GoodWeBat(device_config.id, device_config.configuration.modbus_id, + device_config.configuration.version, device_config.configuration.firmware, + component_config, client) + + def create_counter_component(component_config: GoodWeCounterSetup): + return counter.GoodWeCounter(device_config.id, device_config.configuration.modbus_id, + device_config.configuration.version, device_config.configuration.firmware, + component_config, client) + + def create_inverter_component(component_config: GoodWeInverterSetup): + return inverter.GoodWeInverter(device_config.id, device_config.configuration.modbus_id, + device_config.configuration.version, device_config.configuration.firmware, + component_config, client) + + def update_components(components: Iterable[good_we_component_classes]): + with client: + for component in components: + with SingleComponentUpdateContext(component.fault_state): + component.update() + + try: + client = modbus.ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port) + except Exception: + log.exception("Fehler in create_device") + return ConfigurableDevice( + device_config=device_config, + component_factory=ComponentFactoryByType( + bat=create_bat_component, + counter=create_counter_component, + inverter=create_inverter_component, + ), + component_updater=MultiComponentUpdater(update_components) + ) device_descriptor = DeviceDescriptor(configuration_factory=GoodWe) diff --git a/packages/modules/devices/huawei_smartlogger/device.py b/packages/modules/devices/huawei_smartlogger/device.py index 9eb3b157d6..34f8aa058e 100644 --- a/packages/modules/devices/huawei_smartlogger/device.py +++ b/packages/modules/devices/huawei_smartlogger/device.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 import logging -from typing import Optional, Union, List, Dict -from dataclass_utils import dataclass_from_dict -from helpermodules.cli import run_using_positional_cli_args -from modules.common.abstract_device import AbstractDevice, DeviceDescriptor +from typing import Iterable, Union + +from modules.common.abstract_device import DeviceDescriptor from modules.common.component_context import SingleComponentUpdateContext from modules.common import modbus +from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, MultiComponentUpdater from modules.devices.huawei_smartlogger import counter from modules.devices.huawei_smartlogger import inverter from modules.devices.huawei_smartlogger import bat @@ -21,91 +21,35 @@ inverter.Huawei_SmartloggerInverter] -class Device(AbstractDevice): - COMPONENT_TYPE_TO_CLASS = { - "bat": bat.Huawei_SmartloggerBat, - "counter": counter.Huawei_SmartloggerCounter, - "inverter": inverter.Huawei_SmartloggerInverter - } - - def __init__(self, device_config: Union[Dict, Huawei_Smartlogger]) -> None: - self.components = {} # type: Dict[str, huawei_smartlogger_component_classes] - try: - self.device_config = dataclass_from_dict(Huawei_Smartlogger, device_config) - ip_address = self.device_config.configuration.ip_address - self.port = self.device_config.configuration.port - self.client = modbus.ModbusTcpClient_(ip_address, self.device_config.configuration.port) - self.client.connect() - except Exception: - log.exception("Fehler im Modul "+self.device_config.name) - - def add_component(self, component_config: Union[Dict, - Huawei_SmartloggerBatSetup, - Huawei_SmartloggerCounterSetup, - Huawei_SmartloggerInverterSetup]) -> None: - if isinstance(component_config, Dict): - component_type = component_config["type"] - else: - component_type = component_config.type - component_config = dataclass_from_dict(COMPONENT_TYPE_TO_MODULE[ - component_type].component_descriptor.configuration_factory, component_config) - 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.client)) - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(self.COMPONENT_TYPE_TO_CLASS.keys()) - ) - - def update(self) -> None: - log.debug("Start device reading " + str(self.components)) - if self.components: - for component in self.components: - # Auch wenn bei einer Komponente ein Fehler auftritt, sollen alle anderen noch ausgelesen werden. - with SingleComponentUpdateContext(self.components[component].fault_state): - self.components[component].update() - else: - log.warning( - self.device_config.name + - ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden." - ) - - -COMPONENT_TYPE_TO_MODULE = { - "bat": bat, - "counter": counter, - "inverter": inverter -} - - -def read_legacy(component_type: str, - ip_address: str, - modbus_id: Optional[int] = 1, - num: Optional[int] = None) -> None: - - device_config = Huawei_Smartlogger() - device_config.configuration.ip_address = ip_address - dev = Device(device_config) - - if component_type in COMPONENT_TYPE_TO_MODULE: - component_config = COMPONENT_TYPE_TO_MODULE[component_type].component_descriptor.configuration_factory() - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(COMPONENT_TYPE_TO_MODULE.keys()) - ) - component_config.id = num - component_config.configuration.modbus_id = modbus_id - dev.add_component(component_config) - - log.debug('Huawei Smartlogger IP-Adresse: ' + ip_address) - log.debug('Huawei Device Modbus-ID: ' + str(modbus_id)) - dev.update() - - -def main(argv: List[str]): - run_using_positional_cli_args(read_legacy, argv) +def create_device(device_config: Huawei_Smartlogger): + def create_bat_component(component_config: Huawei_SmartloggerBatSetup): + return bat.Huawei_SmartloggerBat(device_config.id, component_config, client) + + def create_counter_component(component_config: Huawei_SmartloggerCounterSetup): + return counter.Huawei_SmartloggerCounter(device_config.id, component_config, client) + + def create_inverter_component(component_config: Huawei_SmartloggerInverterSetup): + return inverter.Huawei_SmartloggerInverter(device_config.id, component_config, client) + + def update_components(components: Iterable[huawei_smartlogger_component_classes]): + with client: + for component in components: + with SingleComponentUpdateContext(component.fault_state): + component.update() + + try: + client = modbus.ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port) + except Exception: + log.exception("Fehler in create_device") + return ConfigurableDevice( + device_config=device_config, + component_factory=ComponentFactoryByType( + bat=create_bat_component, + counter=create_counter_component, + inverter=create_inverter_component, + ), + component_updater=MultiComponentUpdater(update_components) + ) device_descriptor = DeviceDescriptor(configuration_factory=Huawei_Smartlogger) diff --git a/packages/modules/devices/janitza/device.py b/packages/modules/devices/janitza/device.py index 59e0e69fc2..e3aef00be8 100644 --- a/packages/modules/devices/janitza/device.py +++ b/packages/modules/devices/janitza/device.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 import logging -from typing import Dict, Optional, List, Union +from typing import Iterable -from dataclass_utils import dataclass_from_dict -from helpermodules.cli import run_using_positional_cli_args +from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, MultiComponentUpdater from modules.common import modbus -from modules.common.abstract_device import AbstractDevice, DeviceDescriptor +from modules.common.abstract_device import DeviceDescriptor from modules.common.component_context import SingleComponentUpdateContext from modules.devices.janitza import counter from modules.devices.janitza.config import Janitza, JanitzaCounterSetup @@ -13,77 +12,28 @@ log = logging.getLogger(__name__) -class Device(AbstractDevice): - COMPONENT_TYPE_TO_CLASS = { - "counter": counter.JanitzaCounter - } - - def __init__(self, device_config: Union[Dict, Janitza]) -> None: - self.components = {} # type: Dict[str, counter.JanitzaCounter] - try: - self.device_config = dataclass_from_dict(Janitza, device_config) - self.client = modbus.ModbusTcpClient_( - self.device_config.configuration.ip_address, self.device_config.configuration.port) - except Exception: - log.exception("Fehler im Modul "+self.device_config.name) - - def add_component(self, component_config: Union[Dict, JanitzaCounterSetup]) -> None: - if isinstance(component_config, Dict): - component_type = component_config["type"] - else: - component_type = component_config.type - component_config = dataclass_from_dict(COMPONENT_TYPE_TO_MODULE[ - component_type].component_descriptor.configuration_factory, component_config) - 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.client, - self.device_config.configuration.modbus_id)) - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(self.COMPONENT_TYPE_TO_CLASS.keys()) - ) - - def update(self) -> None: - log.debug("Start device reading " + str(self.components)) - if self.components: - for component in self.components: - # Auch wenn bei einer Komponente ein Fehler auftritt, sollen alle anderen noch ausgelesen werden. - with SingleComponentUpdateContext(self.components[component].fault_state): - self.components[component].update() - else: - log.warning( - self.device_config.name + - ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden." - ) - - -COMPONENT_TYPE_TO_MODULE = { - "counter": counter -} - - -def read_legacy(component_type: str, ip_address: str, num: Optional[int] = None) -> None: - device_config = Janitza() - device_config.configuration.ip_address = ip_address - dev = Device(device_config) - if component_type in COMPONENT_TYPE_TO_MODULE: - component_config = COMPONENT_TYPE_TO_MODULE[component_type].component_descriptor.configuration_factory() - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(COMPONENT_TYPE_TO_MODULE.keys()) - ) - component_config.id = num - dev.add_component(component_config) - - log.debug('Janitza IP-Adresse: ' + ip_address) - - dev.update() - - -def main(argv: List[str]): - run_using_positional_cli_args(read_legacy, argv) +def create_device(device_config: Janitza): + def create_counter_component(component_config: JanitzaCounterSetup): + return counter.JanitzaCounter(device_config.id, component_config, client, + device_config.configuration.modbus_id) + + def update_components(components: Iterable[counter.JanitzaCounter]): + with client: + for component in components: + with SingleComponentUpdateContext(component.fault_state): + component.update() + + try: + client = modbus.ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port) + except Exception: + log.exception("Fehler in create_device") + return ConfigurableDevice( + device_config=device_config, + component_factory=ComponentFactoryByType( + counter=create_counter_component, + ), + component_updater=MultiComponentUpdater(update_components) + ) device_descriptor = DeviceDescriptor(configuration_factory=Janitza) diff --git a/packages/modules/devices/kostal_piko/device.py b/packages/modules/devices/kostal_piko/device.py index 20f18f1d10..567d6f26cd 100644 --- a/packages/modules/devices/kostal_piko/device.py +++ b/packages/modules/devices/kostal_piko/device.py @@ -1,136 +1,30 @@ #!/usr/bin/env python3 import logging -from typing import Dict, Union, Optional, List -from dataclass_utils import dataclass_from_dict -from helpermodules.cli import run_using_positional_cli_args -from modules.devices.byd.config import BYD, BYDBatSetup, BYDConfiguration -from modules.devices.byd.device import Device as BYDDevice -from modules.common.abstract_device import AbstractDevice, DeviceDescriptor -from modules.common.component_context import SingleComponentUpdateContext -from modules.common.component_state import CounterState -from modules.common.simcount import sim_count -from modules.common.store import get_counter_value_store +from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, IndependentComponentUpdater +from modules.common.abstract_device import DeviceDescriptor from modules.devices.kostal_piko import counter from modules.devices.kostal_piko import inverter -from modules.devices.kostal_piko.config import (KostalPiko, - KostalPikoConfiguration, - KostalPikoCounterSetup, KostalPikoInverterConfiguration, - KostalPikoInverterSetup) +from modules.devices.kostal_piko.config import KostalPiko, KostalPikoCounterSetup, KostalPikoInverterSetup log = logging.getLogger(__name__) -kostal_piko_component_classes = Union[counter.KostalPikoCounter, inverter.KostalPikoInverter] +def create_device(device_config: KostalPiko): + def create_counter_component(component_config: KostalPikoCounterSetup): + return counter.KostalPikoCounter(device_config.id, component_config, device_config.configuration.ip_address) + def create_inverter_component(component_config: KostalPikoInverterSetup): + return inverter.KostalPikoInverter(device_config.id, component_config, device_config.configuration.ip_address) -class Device(AbstractDevice): - COMPONENT_TYPE_TO_CLASS = { - "counter": counter.KostalPikoCounter, - "inverter": inverter.KostalPikoInverter - } - - def __init__(self, device_config: Union[Dict, KostalPiko]) -> None: - self.components = {} # type: Dict[str, kostal_piko_component_classes] - try: - self.device_config = dataclass_from_dict(KostalPiko, device_config) - except Exception: - log.exception("Fehler im Modul "+self.device_config.name) - - def add_component(self, component_config: Union[Dict, KostalPikoCounterSetup, KostalPikoInverterSetup]) -> None: - if isinstance(component_config, Dict): - component_type = component_config["type"] - else: - component_type = component_config.type - component_config = dataclass_from_dict(COMPONENT_TYPE_TO_MODULE[ - component_type].component_descriptor.configuration_factory, component_config) - 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.configuration.ip_address)) - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(self.COMPONENT_TYPE_TO_CLASS.keys()) - ) - - def update(self) -> None: - log.debug("Start device reading " + str(self.components)) - if self.components: - for component in self.components: - # Auch wenn bei einer Komponente ein Fehler auftritt, sollen alle anderen noch ausgelesen werden. - with SingleComponentUpdateContext(self.components[component].fault_state): - self.components[component].update() - else: - log.warning( - self.device_config.name + - ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden." - ) - - -COMPONENT_TYPE_TO_MODULE = { - "counter": counter, - "inverter": inverter -} - - -def read_legacy(component_type: str, - address: str, - bat_module: str, - bat_ip: str, - bat_username: str, - bat_password: str, - num: Optional[int] = None) -> None: - dev = Device(KostalPiko(configuration=KostalPikoConfiguration(ip_address=address))) - if component_type in COMPONENT_TYPE_TO_MODULE: - component_config = COMPONENT_TYPE_TO_MODULE[component_type].component_descriptor.configuration_factory() - else: - raise Exception( - "illegal component type " + component_type + ". Allowed values: " + - ','.join(COMPONENT_TYPE_TO_MODULE.keys()) - ) - component_config.id = num - if isinstance(component_config, KostalPikoInverterSetup) and bat_module != "none": - component_config.configuration.bat_configured = True - dev.add_component(component_config) - - log.debug('KostalPiko IP-Adresse: ' + address) - log.debug('KostalPiko Speicher: ' + bat_module) - - if isinstance(component_config, KostalPikoInverterSetup): - dev.update() - elif isinstance(component_config, KostalPikoCounterSetup): - with SingleComponentUpdateContext(dev.components["componentNone"].component_info): - home_consumption, powers = dev.components["componentNone"].get_values() - if bat_module == "speicher_bydhv": - bat_power = _get_byd_bat_power(bat_ip, bat_username, bat_password, 1) - home_consumption += bat_power - - dev.add_component(KostalPikoInverterSetup( - id=1, configuration=KostalPikoInverterConfiguration(bat_configured=True))) - inverter_power, _ = dev.components["component"+str(1)].update() - - power = home_consumption + inverter_power - imported, exported = sim_count(power, prefix="bezug") - counter_state = CounterState( - imported=imported, - exported=exported, - power=power, - powers=powers - ) - get_counter_value_store(None).set(counter_state) - - -def _get_byd_bat_power(bat_ip: str, bat_username: str, bat_password: str, num: int) -> float: - bat_dev = BYDDevice(BYD(configuration=BYDConfiguration(user=bat_username, - password=bat_password, - ip_address=bat_ip))) - bat_dev.add_component(BYDBatSetup(id=num)) - bat_power, _ = bat_dev.components["component"+str(num)].get_values() - return bat_power - - -def main(argv: List[str]): - run_using_positional_cli_args(read_legacy, argv) + return ConfigurableDevice( + device_config=device_config, + component_factory=ComponentFactoryByType( + counter=create_counter_component, + inverter=create_inverter_component, + ), + component_updater=IndependentComponentUpdater(lambda component: component.update()) + ) device_descriptor = DeviceDescriptor(configuration_factory=KostalPiko)