From 701cc7dec9936b59b02f1ef827c004414dad26e8 Mon Sep 17 00:00:00 2001 From: cr0i Date: Sat, 19 Apr 2025 20:04:27 +0200 Subject: [PATCH 1/9] thermia-counter --- packages/modules/devices/thermia/__init__ .py | 0 .../devices/thermia/thermia/__init__.py | 0 .../modules/devices/thermia/thermia/config.py | 39 +++++++++++++++ .../devices/thermia/thermia/counter.py | 47 +++++++++++++++++++ .../modules/devices/thermia/thermia/device.py | 40 ++++++++++++++++ packages/modules/devices/thermia/vendor.py | 14 ++++++ 6 files changed, 140 insertions(+) create mode 100644 packages/modules/devices/thermia/__init__ .py create mode 100644 packages/modules/devices/thermia/thermia/__init__.py create mode 100644 packages/modules/devices/thermia/thermia/config.py create mode 100644 packages/modules/devices/thermia/thermia/counter.py create mode 100644 packages/modules/devices/thermia/thermia/device.py create mode 100644 packages/modules/devices/thermia/vendor.py diff --git a/packages/modules/devices/thermia/__init__ .py b/packages/modules/devices/thermia/__init__ .py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/modules/devices/thermia/thermia/__init__.py b/packages/modules/devices/thermia/thermia/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/modules/devices/thermia/thermia/config.py b/packages/modules/devices/thermia/thermia/config.py new file mode 100644 index 0000000000..1e872d1115 --- /dev/null +++ b/packages/modules/devices/thermia/thermia/config.py @@ -0,0 +1,39 @@ +from typing import Optional +from helpermodules.auto_str import auto_str +from modules.common.component_setup import ComponentSetup + + +@auto_str +class ThermiaConfiguration: + def __init__(self, ip_address: Optional[str] = None, port: int = 502): + self.ip_address = ip_address + self.port = port + + +@auto_str +class Thermia: + def __init__(self, + name: str = "Thermia", + type: str = "thermia", + id: int = 0, + configuration: ThermiaConfiguration = None) -> None: + self.name = name + self.type = type + self.id = id + self.configuration = configuration or ThermiaConfiguration() + + +@auto_str +class ThermiaCounterConfiguration: + def __init__(self, modbus_id: int = 1): + self.modbus_id = modbus_id + + +@auto_str +class ThermiaCounterSetup(ComponentSetup[ThermiaCounterConfiguration]): + def __init__(self, + name: str = "Thermia Zähler", + type: str = "counter", + id: int = 0, + configuration: ThermiaCounterConfiguration = None) -> None: + super().__init__(name, type, id, configuration or ThermiaCounterConfiguration()) diff --git a/packages/modules/devices/thermia/thermia/counter.py b/packages/modules/devices/thermia/thermia/counter.py new file mode 100644 index 0000000000..2c51783655 --- /dev/null +++ b/packages/modules/devices/thermia/thermia/counter.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +from typing import TypedDict, Any +from modules.common.abstract_device import AbstractCounter +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.modbus import ModbusDataType, ModbusTcpClient_ +from modules.common.simcount import SimCounter +from modules.common.store import get_counter_value_store +from modules.devices.thermia.thermia.config import ThermiaCounterSetup + + +class KwargsDict(TypedDict): + device_id: int + client: ModbusTcpClient_ + + +class ThermiaCounter(AbstractCounter): + def __init__(self, component_config: ThermiaCounterSetup, **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.client: ModbusTcpClient_ = self.kwargs['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): + power = self.client.read_holding_registers(reg, ModbusDataType.INT_32, unit=unit) + imported, exported = self.sim_counter.sim_count(power) + + counter_state = CounterState( + currents=currents, + imported=imported, + exported=exported, + power=power, + frequency=frequency, + power_factors=power_factors, + powers=powers, + voltages=voltages + ) + self.store.set(counter_state) + + +component_descriptor = ComponentDescriptor(configuration_factory=ThermiaCounterSetup) diff --git a/packages/modules/devices/thermia/thermia/device.py b/packages/modules/devices/thermia/thermia/device.py new file mode 100644 index 0000000000..59c8ba19c1 --- /dev/null +++ b/packages/modules/devices/thermia/thermia/device.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +import logging +from typing import Iterable, Union + +from modules.common.abstract_device import DeviceDescriptor +from modules.common.configurable_device import ConfigurableDevice, ComponentFactoryByType, MultiComponentUpdater +from modules.common.modbus import ModbusTcpClient_ +from modules.devices.thermia.thermia.config import Thermia, ThermiaCounterSetup +from modules.devices.thermia.thermia.counter import ThermiaCounter + +log = logging.getLogger(__name__) + + +def create_device(device_config: Thermia): + client = None + + def create_counter_component(component_config: ThermiaCounterSetup): + nonlocal client + return ThermiaCounter(component_config, device_id=device_config.id, client=client) + + def update_components(components: Iterable[Union[ThermiaCounter]]): + with client: + for component in components: + component.update() + + def initializer(): + nonlocal client + client = ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port) + + return ConfigurableDevice( + device_config=device_config, + initializer=initializer, + component_factory=ComponentFactoryByType( + counter=create_counter_component, + ), + component_updater=MultiComponentUpdater(update_components) + ) + + +device_descriptor = DeviceDescriptor(configuration_factory=Thermia) diff --git a/packages/modules/devices/thermia/vendor.py b/packages/modules/devices/thermia/vendor.py new file mode 100644 index 0000000000..911c58a237 --- /dev/null +++ b/packages/modules/devices/thermia/vendor.py @@ -0,0 +1,14 @@ +from pathlib import Path + +from modules.common.abstract_device import DeviceDescriptor +from modules.devices.vendors import VendorGroup + + +class Vendor: + def __init__(self): + self.type = Path(__file__).parent.name + self.vendor = "Thermia" + self.group = VendorGroup.VENDORS.value + + +vendor_descriptor = DeviceDescriptor(configuration_factory=Vendor) From 5b276cc73398e434147f9284387d2b36d29dda4b Mon Sep 17 00:00:00 2001 From: cr0i Date: Sat, 19 Apr 2025 20:58:47 +0200 Subject: [PATCH 2/9] Update counter.py --- .../modules/devices/thermia/thermia/counter.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/modules/devices/thermia/thermia/counter.py b/packages/modules/devices/thermia/thermia/counter.py index 2c51783655..1c1093112d 100644 --- a/packages/modules/devices/thermia/thermia/counter.py +++ b/packages/modules/devices/thermia/thermia/counter.py @@ -28,16 +28,26 @@ def initialize(self) -> None: self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) def update(self): - power = self.client.read_holding_registers(reg, ModbusDataType.INT_32, unit=unit) - imported, exported = self.sim_counter.sim_count(power) + #power = self.client.read_holding_registers(reg, ModbusDataType.INT_32, unit=unit) + #imported, exported = self.sim_counter.sim_count(power) + + with self.__tcp_client: + voltages = [val / 100 for val in self.__tcp_client.read_input_registers( + 72, [ModbusDataType.INT_16] * 3, unit=self.__modbus_id)] + powers = [val / 1 for val in self.__tcp_client.read_input_registers( + 78, [ModbusDataType.INT_16] * 3, unit=self.__modbus_id)] + power = sum(powers) + currents = [(val / 100) for val in self.__tcp_client.read_input_registers( + 69, [ModbusDataType.INT_16] * 3, unit=self.__modbus_id)] + imported = [val / 10 for val in self.__tcp_client.read_input_registers( + 83, [ModbusDataType.INT_32], wordorder=Endian.Little, unit=self.__modbus_id)] + exported = 0 counter_state = CounterState( currents=currents, imported=imported, exported=exported, power=power, - frequency=frequency, - power_factors=power_factors, powers=powers, voltages=voltages ) From 59f90af25fb77dc56252ef459c51495401311f33 Mon Sep 17 00:00:00 2001 From: cr0i Date: Sat, 19 Apr 2025 21:11:52 +0200 Subject: [PATCH 3/9] Update counter.py --- packages/modules/devices/thermia/thermia/counter.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/modules/devices/thermia/thermia/counter.py b/packages/modules/devices/thermia/thermia/counter.py index 1c1093112d..bd51f1e998 100644 --- a/packages/modules/devices/thermia/thermia/counter.py +++ b/packages/modules/devices/thermia/thermia/counter.py @@ -1,5 +1,8 @@ #!/usr/bin/env python3 from typing import TypedDict, Any + +from pymodbus.constants import Endian + from modules.common.abstract_device import AbstractCounter from modules.common.component_state import CounterState from modules.common.component_type import ComponentDescriptor @@ -9,7 +12,6 @@ from modules.common.store import get_counter_value_store from modules.devices.thermia.thermia.config import ThermiaCounterSetup - class KwargsDict(TypedDict): device_id: int client: ModbusTcpClient_ From fdb9e6ab5f2fe1fa79bfab22c5ed2da6c9c4139e Mon Sep 17 00:00:00 2001 From: cr0i Date: Sun, 20 Apr 2025 03:21:55 +0200 Subject: [PATCH 4/9] thermia-counter --- .../modules/devices/thermia/thermia/config.py | 4 ++++ .../devices/thermia/thermia/counter.py | 22 +++++++++---------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/modules/devices/thermia/thermia/config.py b/packages/modules/devices/thermia/thermia/config.py index 1e872d1115..ea5230d93e 100644 --- a/packages/modules/devices/thermia/thermia/config.py +++ b/packages/modules/devices/thermia/thermia/config.py @@ -2,6 +2,7 @@ from helpermodules.auto_str import auto_str from modules.common.component_setup import ComponentSetup +from ..vendor import vendor_descriptor @auto_str class ThermiaConfiguration: @@ -19,6 +20,9 @@ def __init__(self, configuration: ThermiaConfiguration = None) -> None: self.name = name self.type = type + + self.vendor = vendor_descriptor.configuration_factory().type + self.id = id self.configuration = configuration or ThermiaConfiguration() diff --git a/packages/modules/devices/thermia/thermia/counter.py b/packages/modules/devices/thermia/thermia/counter.py index bd51f1e998..888bee4b3e 100644 --- a/packages/modules/devices/thermia/thermia/counter.py +++ b/packages/modules/devices/thermia/thermia/counter.py @@ -30,19 +30,17 @@ def initialize(self) -> None: self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) def update(self): - #power = self.client.read_holding_registers(reg, ModbusDataType.INT_32, unit=unit) - #imported, exported = self.sim_counter.sim_count(power) - - with self.__tcp_client: - voltages = [val / 100 for val in self.__tcp_client.read_input_registers( - 72, [ModbusDataType.INT_16] * 3, unit=self.__modbus_id)] - powers = [val / 1 for val in self.__tcp_client.read_input_registers( - 78, [ModbusDataType.INT_16] * 3, unit=self.__modbus_id)] + with self.client: + voltages = [val / 100 for val in self.client.read_input_registers( + 72, [ModbusDataType.INT_16] * 3, unit=self.component_config.configuration.modbus_id)] + powers = [val / 1 for val in self.client.read_input_registers( + 78, [ModbusDataType.INT_16] * 3, unit=self.component_config.configuration.modbus_id)] power = sum(powers) - currents = [(val / 100) for val in self.__tcp_client.read_input_registers( - 69, [ModbusDataType.INT_16] * 3, unit=self.__modbus_id)] - imported = [val / 10 for val in self.__tcp_client.read_input_registers( - 83, [ModbusDataType.INT_32], wordorder=Endian.Little, unit=self.__modbus_id)] + currents = [(val / 100) for val in self.client.read_input_registers( + 69, [ModbusDataType.INT_16] * 3, unit=self.component_config.configuration.modbus_id)] + imported = self.client.read_input_registers( + 83, ModbusDataType.INT_32, wordorder=Endian.Little, + unit=self.component_config.configuration.modbus_id) * 100 exported = 0 counter_state = CounterState( From a3d350cd9031e3c84b931f4f0efae9932344fd97 Mon Sep 17 00:00:00 2001 From: cr0i Date: Sun, 20 Apr 2025 08:17:03 +0200 Subject: [PATCH 5/9] Update --- packages/modules/devices/thermia/thermia/config.py | 3 --- packages/modules/devices/thermia/thermia/counter.py | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/modules/devices/thermia/thermia/config.py b/packages/modules/devices/thermia/thermia/config.py index ea5230d93e..de9bed45ad 100644 --- a/packages/modules/devices/thermia/thermia/config.py +++ b/packages/modules/devices/thermia/thermia/config.py @@ -1,7 +1,6 @@ from typing import Optional from helpermodules.auto_str import auto_str from modules.common.component_setup import ComponentSetup - from ..vendor import vendor_descriptor @auto_str @@ -20,9 +19,7 @@ def __init__(self, configuration: ThermiaConfiguration = None) -> None: self.name = name self.type = type - self.vendor = vendor_descriptor.configuration_factory().type - self.id = id self.configuration = configuration or ThermiaConfiguration() diff --git a/packages/modules/devices/thermia/thermia/counter.py b/packages/modules/devices/thermia/thermia/counter.py index 888bee4b3e..c458f1290e 100644 --- a/packages/modules/devices/thermia/thermia/counter.py +++ b/packages/modules/devices/thermia/thermia/counter.py @@ -1,8 +1,5 @@ #!/usr/bin/env python3 from typing import TypedDict, Any - -from pymodbus.constants import Endian - from modules.common.abstract_device import AbstractCounter from modules.common.component_state import CounterState from modules.common.component_type import ComponentDescriptor @@ -11,6 +8,8 @@ from modules.common.simcount import SimCounter from modules.common.store import get_counter_value_store from modules.devices.thermia.thermia.config import ThermiaCounterSetup +from pymodbus.constants import Endian + class KwargsDict(TypedDict): device_id: int From 252276439ddd5c565db10b5cbe7f4bbfa1f495f1 Mon Sep 17 00:00:00 2001 From: cr0i Date: Sun, 20 Apr 2025 08:24:14 +0200 Subject: [PATCH 6/9] Update --- packages/modules/devices/thermia/thermia/config.py | 1 + packages/modules/devices/thermia/thermia/counter.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/modules/devices/thermia/thermia/config.py b/packages/modules/devices/thermia/thermia/config.py index de9bed45ad..f4ad9ac3d6 100644 --- a/packages/modules/devices/thermia/thermia/config.py +++ b/packages/modules/devices/thermia/thermia/config.py @@ -3,6 +3,7 @@ from modules.common.component_setup import ComponentSetup from ..vendor import vendor_descriptor + @auto_str class ThermiaConfiguration: def __init__(self, ip_address: Optional[str] = None, port: int = 502): diff --git a/packages/modules/devices/thermia/thermia/counter.py b/packages/modules/devices/thermia/thermia/counter.py index c458f1290e..9f52675db7 100644 --- a/packages/modules/devices/thermia/thermia/counter.py +++ b/packages/modules/devices/thermia/thermia/counter.py @@ -38,7 +38,7 @@ def update(self): currents = [(val / 100) for val in self.client.read_input_registers( 69, [ModbusDataType.INT_16] * 3, unit=self.component_config.configuration.modbus_id)] imported = self.client.read_input_registers( - 83, ModbusDataType.INT_32, wordorder=Endian.Little, + 83, ModbusDataType.INT_32, wordorder=Endian.Little, unit=self.component_config.configuration.modbus_id) * 100 exported = 0 From f869bb00efe0443fab6e36cffdc245be7b5796ad Mon Sep 17 00:00:00 2001 From: cr0i Date: Mon, 5 May 2025 19:53:51 +0200 Subject: [PATCH 7/9] Move Modbus-ID to Device --- packages/modules/devices/thermia/thermia/config.py | 7 ++++--- packages/modules/devices/thermia/thermia/counter.py | 10 ++++++---- packages/modules/devices/thermia/thermia/device.py | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/modules/devices/thermia/thermia/config.py b/packages/modules/devices/thermia/thermia/config.py index f4ad9ac3d6..e597e10826 100644 --- a/packages/modules/devices/thermia/thermia/config.py +++ b/packages/modules/devices/thermia/thermia/config.py @@ -6,9 +6,10 @@ @auto_str class ThermiaConfiguration: - def __init__(self, ip_address: Optional[str] = None, port: int = 502): + def __init__(self, ip_address: Optional[str] = None, port: int = 502, modbus_id: int = 1): self.ip_address = ip_address self.port = port + self.modbus_id = modbus_id @auto_str @@ -27,8 +28,8 @@ def __init__(self, @auto_str class ThermiaCounterConfiguration: - def __init__(self, modbus_id: int = 1): - self.modbus_id = modbus_id + def __init__(self): + pass @auto_str diff --git a/packages/modules/devices/thermia/thermia/counter.py b/packages/modules/devices/thermia/thermia/counter.py index 9f52675db7..20d39d773e 100644 --- a/packages/modules/devices/thermia/thermia/counter.py +++ b/packages/modules/devices/thermia/thermia/counter.py @@ -14,6 +14,7 @@ class KwargsDict(TypedDict): device_id: int client: ModbusTcpClient_ + modbus_id: int class ThermiaCounter(AbstractCounter): @@ -24,6 +25,7 @@ def __init__(self, component_config: ThermiaCounterSetup, **kwargs: Any) -> None def initialize(self) -> None: self.__device_id: int = self.kwargs['device_id'] self.client: ModbusTcpClient_ = self.kwargs['client'] + self.modbus_id: int = self.kwargs['modbus_id'] 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)) @@ -31,15 +33,15 @@ def initialize(self) -> None: def update(self): with self.client: voltages = [val / 100 for val in self.client.read_input_registers( - 72, [ModbusDataType.INT_16] * 3, unit=self.component_config.configuration.modbus_id)] + 72, [ModbusDataType.INT_16] * 3, unit=self.modbus_id)] powers = [val / 1 for val in self.client.read_input_registers( - 78, [ModbusDataType.INT_16] * 3, unit=self.component_config.configuration.modbus_id)] + 78, [ModbusDataType.INT_16] * 3, unit=self.modbus_id)] power = sum(powers) currents = [(val / 100) for val in self.client.read_input_registers( - 69, [ModbusDataType.INT_16] * 3, unit=self.component_config.configuration.modbus_id)] + 69, [ModbusDataType.INT_16] * 3, unit=self.modbus_id)] imported = self.client.read_input_registers( 83, ModbusDataType.INT_32, wordorder=Endian.Little, - unit=self.component_config.configuration.modbus_id) * 100 + unit=self.modbus_id) * 100 exported = 0 counter_state = CounterState( diff --git a/packages/modules/devices/thermia/thermia/device.py b/packages/modules/devices/thermia/thermia/device.py index 59c8ba19c1..4f92f28252 100644 --- a/packages/modules/devices/thermia/thermia/device.py +++ b/packages/modules/devices/thermia/thermia/device.py @@ -16,7 +16,7 @@ def create_device(device_config: Thermia): def create_counter_component(component_config: ThermiaCounterSetup): nonlocal client - return ThermiaCounter(component_config, device_id=device_config.id, client=client) + return ThermiaCounter(component_config, device_id=device_config.id, client=client, modbus_id=device_config.configuration.modbus_id) def update_components(components: Iterable[Union[ThermiaCounter]]): with client: From 2a944e1b6a0c5188c77b682e8a32230dc0413059 Mon Sep 17 00:00:00 2001 From: cr0i Date: Mon, 5 May 2025 19:57:20 +0200 Subject: [PATCH 8/9] Update device.py --- packages/modules/devices/thermia/thermia/device.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/modules/devices/thermia/thermia/device.py b/packages/modules/devices/thermia/thermia/device.py index 4f92f28252..ed68a89650 100644 --- a/packages/modules/devices/thermia/thermia/device.py +++ b/packages/modules/devices/thermia/thermia/device.py @@ -16,7 +16,8 @@ def create_device(device_config: Thermia): def create_counter_component(component_config: ThermiaCounterSetup): nonlocal client - return ThermiaCounter(component_config, device_id=device_config.id, client=client, modbus_id=device_config.configuration.modbus_id) + return ThermiaCounter(component_config, device_id=device_config.id, + client=client, modbus_id=device_config.configuration.modbus_id) def update_components(components: Iterable[Union[ThermiaCounter]]): with client: From ace17854e437477a6b6750922f5144b39f18bc27 Mon Sep 17 00:00:00 2001 From: cr0i Date: Mon, 5 May 2025 19:59:02 +0200 Subject: [PATCH 9/9] Update device.py --- packages/modules/devices/thermia/thermia/device.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modules/devices/thermia/thermia/device.py b/packages/modules/devices/thermia/thermia/device.py index ed68a89650..0f85723c84 100644 --- a/packages/modules/devices/thermia/thermia/device.py +++ b/packages/modules/devices/thermia/thermia/device.py @@ -16,7 +16,7 @@ def create_device(device_config: Thermia): def create_counter_component(component_config: ThermiaCounterSetup): nonlocal client - return ThermiaCounter(component_config, device_id=device_config.id, + return ThermiaCounter(component_config, device_id=device_config.id, client=client, modbus_id=device_config.configuration.modbus_id) def update_components(components: Iterable[Union[ThermiaCounter]]):