From ce78b78ed1b42d301853c11c7714526d59ee57ea Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Thu, 24 Jul 2025 12:44:52 +0200 Subject: [PATCH 1/2] add Algodue inverter and battery --- .../modules/devices/algodue/algodue/bat.py | 53 +++++++++++++++++++ .../modules/devices/algodue/algodue/config.py | 35 ++++++++++++ .../modules/devices/algodue/algodue/device.py | 19 +++++-- .../devices/algodue/algodue/inverter.py | 52 ++++++++++++++++++ 4 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 packages/modules/devices/algodue/algodue/bat.py create mode 100644 packages/modules/devices/algodue/algodue/inverter.py diff --git a/packages/modules/devices/algodue/algodue/bat.py b/packages/modules/devices/algodue/algodue/bat.py new file mode 100644 index 0000000000..9b265c5d5c --- /dev/null +++ b/packages/modules/devices/algodue/algodue/bat.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +from typing import Any, TypedDict + +from modules.devices.algodue.algodue.config import AlgodueBatSetup +from modules.common import modbus +from modules.common.abstract_device import AbstractBat +from modules.common.component_state import BatState +from modules.common.component_type import ComponentDescriptor +from modules.common.fault_state import ComponentInfo, FaultState +from modules.common.modbus import ModbusDataType +from modules.common.simcount import SimCounter +from modules.common.store import get_bat_value_store + + +class KwargsDict(TypedDict): + device_id: int + tcp_client: modbus.ModbusTcpClient_ + modbus_id: int + + +class AlgodueBat(AbstractBat): + def __init__(self, component_config: AlgodueBatSetup, **kwargs: Any) -> None: + self.component_config = component_config + self.kwargs: KwargsDict = kwargs + + def initialize(self) -> None: + self.__device_id: int = self.kwargs['device_id'] + self.__tcp_client: modbus.ModbusTcpClient_ = self.kwargs['tcp_client'] + self.__modbus_id: int = self.kwargs['modbus_id'] + self.sim_counter = SimCounter(self.__device_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)) + + def update(self): + with self.__tcp_client: + + currents = self.__tcp_client.read_input_registers( + 0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + powers = self.__tcp_client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + power = sum(powers) + + imported, exported = self.sim_counter.sim_count(power) + + bat_state = BatState( + power=power, + currents=currents, + imported=imported, + exported=exported + ) + self.store.set(bat_state) + + +component_descriptor = ComponentDescriptor(configuration_factory=AlgodueBatSetup) diff --git a/packages/modules/devices/algodue/algodue/config.py b/packages/modules/devices/algodue/algodue/config.py index 46844970cc..d4717dcce0 100644 --- a/packages/modules/devices/algodue/algodue/config.py +++ b/packages/modules/devices/algodue/algodue/config.py @@ -2,6 +2,7 @@ from modules.common.component_setup import ComponentSetup from ..vendor import vendor_descriptor +from helpermodules.auto_str import auto_str class AlgodueConfiguration: @@ -24,11 +25,13 @@ def __init__(self, self.configuration = configuration or AlgodueConfiguration() +@auto_str class AlgodueCounterConfiguration: def __init__(self): pass +@auto_str class AlgodueCounterSetup(ComponentSetup[AlgodueCounterConfiguration]): def __init__(self, name: str = "Algodue Zähler", @@ -36,3 +39,35 @@ def __init__(self, id: int = 0, configuration: AlgodueCounterConfiguration = None) -> None: super().__init__(name, type, id, configuration or AlgodueCounterConfiguration()) + + +@auto_str +class AlgodueInverterConfiguration: + def __init__(self): + pass + + +@auto_str +class AlgodueInverterSetup(ComponentSetup[AlgodueInverterConfiguration]): + def __init__(self, + name: str = "Algodue Wechselrichterzähler", + type: str = "inverter", + id: int = 0, + configuration: AlgodueInverterConfiguration = None) -> None: + super().__init__(name, type, id, configuration or AlgodueInverterConfiguration()) + + +@auto_str +class AlgodueBatConfiguration: + def __init__(self): + pass + + +@auto_str +class AlgodueBatSetup(ComponentSetup[AlgodueBatConfiguration]): + def __init__(self, + name: str = "Algodue Speicherzähler", + type: str = "bat", + id: int = 0, + configuration: AlgodueBatConfiguration = None) -> None: + super().__init__(name, type, id, configuration or AlgodueBatConfiguration()) diff --git a/packages/modules/devices/algodue/algodue/device.py b/packages/modules/devices/algodue/algodue/device.py index 8b3ff704b6..08821584c3 100644 --- a/packages/modules/devices/algodue/algodue/device.py +++ b/packages/modules/devices/algodue/algodue/device.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 import logging -from typing import Iterable +from typing import Iterable, Union from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, MultiComponentUpdater -from modules.devices.algodue.algodue import counter -from modules.devices.algodue.algodue.config import Algodue, AlgodueCounterSetup +from modules.devices.algodue.algodue import counter, inverter, bat +from modules.devices.algodue.algodue.config import Algodue, AlgodueCounterSetup, AlgodueInverterSetup, AlgodueBatSetup from modules.common import modbus from modules.common.abstract_device import DeviceDescriptor from modules.common.component_context import SingleComponentUpdateContext @@ -20,7 +20,18 @@ def create_counter_component(component_config: AlgodueCounterSetup): return counter.AlgodueCounter(component_config=component_config, device_id=device_config.id, tcp_client=client, modbus_id=device_config.configuration.modbus_id) - def update_components(components: Iterable[counter.AlgodueCounter]): + def create_inverter_component(component_config: AlgodueInverterSetup): + nonlocal client + return inverter.AlgodueInverter(component_config=component_config, device_id=device_config.id, + tcp_client=client, modbus_id=device_config.configuration.modbus_id) + + def create_bat_component(component_config: AlgodueBatSetup): + nonlocal client + return bat.AlgodueBat(component_config=component_config, device_id=device_config.id, + tcp_client=client, modbus_id=device_config.configuration.modbus_id) + + def update_components( + components: Iterable[Union[counter.AlgodueCounter, inverter.AlgodueInverter, bat.AlgodueBat]]): with client: for component in components: with SingleComponentUpdateContext(component.fault_state): diff --git a/packages/modules/devices/algodue/algodue/inverter.py b/packages/modules/devices/algodue/algodue/inverter.py new file mode 100644 index 0000000000..8e901a58bc --- /dev/null +++ b/packages/modules/devices/algodue/algodue/inverter.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +from typing import Any, TypedDict + +from modules.devices.algodue.algodue.config import AlgodueInverterSetup +from modules.common import modbus +from modules.common.abstract_device import AbstractInverter +from modules.common.component_state import InverterState +from modules.common.component_type import ComponentDescriptor +from modules.common.fault_state import ComponentInfo, FaultState +from modules.common.modbus import ModbusDataType +from modules.common.simcount import SimCounter +from modules.common.store import get_inverter_value_store + + +class KwargsDict(TypedDict): + device_id: int + tcp_client: modbus.ModbusTcpClient_ + modbus_id: int + + +class AlgodueInverter(AbstractInverter): + def __init__(self, component_config: AlgodueInverterSetup, **kwargs: Any) -> None: + self.component_config = component_config + self.kwargs: KwargsDict = kwargs + + def initialize(self) -> None: + self.__device_id: int = self.kwargs['device_id'] + self.__tcp_client: modbus.ModbusTcpClient_ = self.kwargs['tcp_client'] + self.__modbus_id: int = self.kwargs['modbus_id'] + self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="pv") + self.store = get_inverter_value_store(self.component_config.id) + self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) + + def update(self): + with self.__tcp_client: + + currents = self.__tcp_client.read_input_registers( + 0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + powers = self.__tcp_client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + power = sum(powers) + + _, exported = self.sim_counter.sim_count(power) + + inverter_state = InverterState( + power=power, + currents=currents, + exported=exported + ) + self.store.set(inverter_state) + + +component_descriptor = ComponentDescriptor(configuration_factory=AlgodueInverterSetup) From 662f2acaae38113df61bb892c723add2f9150e87 Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Fri, 1 Aug 2025 14:48:29 +0200 Subject: [PATCH 2/2] remove duplicate context handler --- .../modules/devices/algodue/algodue/bat.py | 10 ++++------ .../devices/algodue/algodue/counter.py | 20 +++++++++---------- .../devices/algodue/algodue/inverter.py | 10 ++++------ 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/packages/modules/devices/algodue/algodue/bat.py b/packages/modules/devices/algodue/algodue/bat.py index 9b265c5d5c..48fecab95f 100644 --- a/packages/modules/devices/algodue/algodue/bat.py +++ b/packages/modules/devices/algodue/algodue/bat.py @@ -32,12 +32,10 @@ def initialize(self) -> None: self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) def update(self): - with self.__tcp_client: - - currents = self.__tcp_client.read_input_registers( - 0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) - powers = self.__tcp_client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) - power = sum(powers) + currents = self.__tcp_client.read_input_registers( + 0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + powers = self.__tcp_client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + power = sum(powers) imported, exported = self.sim_counter.sim_count(power) diff --git a/packages/modules/devices/algodue/algodue/counter.py b/packages/modules/devices/algodue/algodue/counter.py index 3f432a816a..162176b8fc 100644 --- a/packages/modules/devices/algodue/algodue/counter.py +++ b/packages/modules/devices/algodue/algodue/counter.py @@ -32,17 +32,15 @@ def initialize(self) -> None: self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) def update(self): - with self.__tcp_client: - - frequency = self.__tcp_client.read_input_registers(0x1038, ModbusDataType.FLOAT_32, unit=self.__modbus_id) - currents = self.__tcp_client.read_input_registers( - 0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) - powers = self.__tcp_client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) - power = sum(powers) - voltages = self.__tcp_client.read_input_registers( - 0x1000, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) - power_factors = self.__tcp_client.read_input_registers( - 0x1018, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + frequency = self.__tcp_client.read_input_registers(0x1038, ModbusDataType.FLOAT_32, unit=self.__modbus_id) + currents = self.__tcp_client.read_input_registers( + 0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + powers = self.__tcp_client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + power = sum(powers) + voltages = self.__tcp_client.read_input_registers( + 0x1000, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + power_factors = self.__tcp_client.read_input_registers( + 0x1018, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) imported, exported = self.sim_counter.sim_count(power) diff --git a/packages/modules/devices/algodue/algodue/inverter.py b/packages/modules/devices/algodue/algodue/inverter.py index 8e901a58bc..63ad9adca2 100644 --- a/packages/modules/devices/algodue/algodue/inverter.py +++ b/packages/modules/devices/algodue/algodue/inverter.py @@ -32,12 +32,10 @@ def initialize(self) -> None: self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) def update(self): - with self.__tcp_client: - - currents = self.__tcp_client.read_input_registers( - 0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) - powers = self.__tcp_client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) - power = sum(powers) + currents = self.__tcp_client.read_input_registers( + 0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + powers = self.__tcp_client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.__modbus_id) + power = sum(powers) _, exported = self.sim_counter.sim_count(power)