diff --git a/packages/modules/common/b23.py b/packages/modules/common/b23.py index 3bb55f012e..6f2caeee05 100644 --- a/packages/modules/common/b23.py +++ b/packages/modules/common/b23.py @@ -25,6 +25,10 @@ def get_imported(self) -> float: time.sleep(0.1) return self.client.read_holding_registers(0x5000, ModbusDataType.UINT_64, unit=self.id) * 10 + def get_exported(self) -> float: + time.sleep(0.1) + return self.client.read_holding_registers(0x5004, ModbusDataType.UINT_64, unit=self.id) * 10 + def get_power(self) -> Tuple[List[float], float]: time.sleep(0.1) power = self.client.read_holding_registers(0x5B14, ModbusDataType.INT_32, unit=self.id) / 100 diff --git a/packages/modules/devices/openwb_flex/config.py b/packages/modules/devices/openwb_flex/config.py index cbcf24d5fd..0294b1854e 100644 --- a/packages/modules/devices/openwb_flex/config.py +++ b/packages/modules/devices/openwb_flex/config.py @@ -54,6 +54,21 @@ def __init__(self, super().__init__(name, type, id, configuration or EvuKitFlexConfiguration()) +class ConsumptionCounterFlexConfiguration: + def __init__(self, id: int = 115, type: str = "sdm630"): + self.id = id + self.type = type + + +class ConsumptionCounterFlexSetup(ComponentSetup[ConsumptionCounterFlexConfiguration]): + def __init__(self, + name: str = "openWB Verbrauchszähler flex", + type: str = "consumption_counter", + id: int = 0, + configuration: ConsumptionCounterFlexConfiguration = None) -> None: + super().__init__(name, type, id, configuration or ConsumptionCounterFlexConfiguration()) + + class PvKitFlexConfiguration: def __init__(self, id: int = 116, version: int = 2): self.id = id diff --git a/packages/modules/devices/openwb_flex/consumption_counter.py b/packages/modules/devices/openwb_flex/consumption_counter.py new file mode 100644 index 0000000000..e2f6966746 --- /dev/null +++ b/packages/modules/devices/openwb_flex/consumption_counter.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +from typing import Dict, Union + +from dataclass_utils import dataclass_from_dict +from modules.common import modbus +from modules.common.component_state import CounterState +from modules.common.component_type import ComponentDescriptor +from modules.common.fault_state import ComponentInfo, FaultState +from modules.common.simcount import SimCounter +from modules.common.store import get_counter_value_store +from modules.devices.openwb_flex.config import ConsumptionCounterFlexSetup +from modules.devices.openwb_flex.versions import consumption_counter_factory + + +class ConsumptionCounterFlex: + def __init__(self, + device_id: int, + component_config: Union[Dict, ConsumptionCounterFlexSetup], + tcp_client: modbus.ModbusTcpClient_) -> None: + self.__device_id = device_id + self.component_config = dataclass_from_dict(ConsumptionCounterFlexSetup, component_config) + factory = consumption_counter_factory( + self.component_config.configuration.type) + self.__client = factory(self.component_config.configuration.id, tcp_client) + self.__tcp_client = tcp_client + self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="bezug") + self.store = get_counter_value_store(self.component_config.id) + self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) + + def update(self): + with self.__tcp_client: + voltages = self.__client.get_voltages() + powers, power = self.__client.get_power() + frequency = self.__client.get_frequency() + power_factors = self.__client.get_power_factors() + imported = self.__client.get_imported() + currents = self.__client.get_currents() + if self.component_config.configuration.type == "b23": + exported = self.__client.get_exported() + else: + exported = 0 + + counter_state = CounterState( + voltages=voltages, + currents=currents, + powers=powers, + power_factors=power_factors, + imported=imported, + exported=exported, + power=power, + frequency=frequency + ) + self.store.set(counter_state) + + +component_descriptor = ComponentDescriptor(configuration_factory=ConsumptionCounterFlexSetup) diff --git a/packages/modules/devices/openwb_flex/device.py b/packages/modules/devices/openwb_flex/device.py index b6b63f7f77..2ded4a8d99 100644 --- a/packages/modules/devices/openwb_flex/device.py +++ b/packages/modules/devices/openwb_flex/device.py @@ -1,99 +1,53 @@ +#!/usr/bin/env python3 import logging -from typing import Dict, Union, Optional, List +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.devices.openwb_flex import bat -from modules.devices.openwb_flex import counter -from modules.devices.openwb_flex import inverter -from modules.devices.openwb_flex.config import Flex, BatKitFlexSetup, EvuKitFlexSetup, FlexConfiguration, PvKitFlexSetup +from modules.common.configurable_device import ConfigurableDevice, ComponentFactoryByType, MultiComponentUpdater +from modules.common.modbus import ModbusTcpClient_ +from modules.devices.openwb_flex.bat import BatKitFlex +from modules.devices.openwb_flex.config import (BatKitFlexSetup, ConsumptionCounterFlexSetup, EvuKitFlexSetup, Flex, + PvKitFlexSetup) +from modules.devices.openwb_flex.consumption_counter import ConsumptionCounterFlex +from modules.devices.openwb_flex.counter import EvuKitFlex +from modules.devices.openwb_flex.inverter import PvKitFlex log = logging.getLogger(__name__) -class Device(AbstractDevice): - COMPONENT_TYPE_TO_CLASS = { - "bat": bat.BatKitFlex, - "counter": counter.EvuKitFlex, - "inverter": inverter.PvKitFlex - } - - def __init__(self, device_config: Union[Dict, Flex]) -> None: - self.components = {} # type: Dict[str, Union[counter.EvuKitFlex, inverter.PvKitFlex]] - try: - self.device_config = dataclass_from_dict(Flex, device_config) - ip_address = self.device_config.configuration.ip_address - port = self.device_config.configuration.port - self.client = modbus.ModbusTcpClient_(ip_address, port) - except Exception: - log.exception("Fehler im Modul " + self.device_config.name) - - def add_component(self, component_config: Union[Dict, BatKitFlexSetup, EvuKitFlexSetup, PvKitFlexSetup]) -> 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, version: int, ip_address: str, port: int, id: int, num: Optional[int] = None): - """ Ausführung des Moduls als Python-Skript - """ - log.debug('Start reading flex') - dev = Device(Flex(configuration=FlexConfiguration(ip_address=ip_address, port=port))) - 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.version = version - component_config.configuration.id = id - dev.add_component(component_config) - - log.debug('openWB flex Version: ' + str(version)) - log.debug('openWB flex-Kit IP-Adresse: ' + ip_address) - log.debug('openWB flex-Kit Port: ' + str(port)) - log.debug('openWB flex-Kit ID: ' + str(id)) - - dev.update() - - -def main(argv: List[str]): - run_using_positional_cli_args(read_legacy, argv) +def create_device(device_config: Flex): + def create_bat_component(component_config: BatKitFlexSetup): + return BatKitFlex(device_config.id, component_config, client) + + def create_counter_component(component_config: EvuKitFlexSetup): + return EvuKitFlex(device_config.id, component_config, client) + + def create_consumption_counter_component(component_config: ConsumptionCounterFlexSetup): + return ConsumptionCounterFlex(device_config.id, component_config, client) + + def create_inverter_component(component_config: PvKitFlexSetup): + return PvKitFlex(device_config.id, component_config, client) + + def update_components(components: Iterable[Union[BatKitFlex, ConsumptionCounterFlex, EvuKitFlex, PvKitFlex]]): + for component in components: + with SingleComponentUpdateContext(component.fault_state): + component.update() + + try: + client = 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, + consumption_counter=create_consumption_counter_component, + counter=create_counter_component, + inverter=create_inverter_component, + ), + component_updater=MultiComponentUpdater(update_components) + ) device_descriptor = DeviceDescriptor(configuration_factory=Flex) diff --git a/packages/modules/devices/openwb_flex/versions.py b/packages/modules/devices/openwb_flex/versions.py index 653aa14178..f5a62ce8b0 100644 --- a/packages/modules/devices/openwb_flex/versions.py +++ b/packages/modules/devices/openwb_flex/versions.py @@ -1,6 +1,6 @@ from typing import Type, Union -from modules.common import lovato +from modules.common import b23, lovato from modules.common import mpm3pm from modules.common import sdm @@ -40,3 +40,14 @@ def kit_bat_version_factory(version: int) -> Type[Union[mpm3pm.Mpm3pm, sdm.Sdm63 return sdm.Sdm630 else: raise ValueError("Version "+str(version) + " unbekannt.") + + +def consumption_counter_factory(type: str) -> Type[Union[sdm.Sdm120, sdm.Sdm630, b23.B23]]: + if type == "sdm120": + return sdm.Sdm120 + elif type == "sdm630": + return sdm.Sdm630 + elif type == "b23": + return b23.B23 + else: + raise ValueError(f"Version {type} unbekannt.")