From afd9ecf7c79694e18f4e02c122aea18f334421c8 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 17 Aug 2026 13:53:57 +0200 Subject: [PATCH 1/5] Vampair --- .../modules/consumers/solarfocus/__init__.py | 0 .../consumers/solarfocus/vampair/__init__.py | 0 .../consumers/solarfocus/vampair/config.py | 29 +++++++++++ .../consumers/solarfocus/vampair/consumer.py | 50 +++++++++++++++++++ .../modules/consumers/solarfocus/vendor.py | 14 ++++++ 5 files changed, 93 insertions(+) create mode 100644 packages/modules/consumers/solarfocus/__init__.py create mode 100644 packages/modules/consumers/solarfocus/vampair/__init__.py create mode 100644 packages/modules/consumers/solarfocus/vampair/config.py create mode 100644 packages/modules/consumers/solarfocus/vampair/consumer.py create mode 100644 packages/modules/consumers/solarfocus/vendor.py diff --git a/packages/modules/consumers/solarfocus/__init__.py b/packages/modules/consumers/solarfocus/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/modules/consumers/solarfocus/vampair/__init__.py b/packages/modules/consumers/solarfocus/vampair/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/modules/consumers/solarfocus/vampair/config.py b/packages/modules/consumers/solarfocus/vampair/config.py new file mode 100644 index 0000000000..612e3b9095 --- /dev/null +++ b/packages/modules/consumers/solarfocus/vampair/config.py @@ -0,0 +1,29 @@ +from typing import Optional, Tuple + +from control.consumer.consumer_data import ConsumerUsage +from helpermodules.auto_str import auto_str +from modules.common.consumer_setup import ConsumerSetup +from ..vendor import vendor_descriptor + + +@auto_str +class VampairConfiguration: + def __init__(self, ip_address: Optional[str] = None, port: Optional[int] = 502, modbus_id: Optional[int] = 1): + self.ip_address = ip_address + self.port = port + self.modbus_id = modbus_id + + +@auto_str +class VampairHeatPump(ConsumerSetup[VampairConfiguration]): + def __init__(self, + name: str = "Vampair Wärmepumpe", + type: str = "vampair", + id: int = 0, + configuration: VampairConfiguration = None, + usage: Tuple[ConsumerUsage, ...] = (ConsumerUsage.SELF_CONTROLLED, + ConsumerUsage.SUSPENDABLE_TUNABLE, + ConsumerUsage.METER_ONLY), + **kwargs) -> None: + super().__init__(name, type, id, vendor=vendor_descriptor.configuration_factory( + ).type, configuration=configuration or VampairConfiguration(), usage=usage, **kwargs) diff --git a/packages/modules/consumers/solarfocus/vampair/consumer.py b/packages/modules/consumers/solarfocus/vampair/consumer.py new file mode 100644 index 0000000000..c76b3fda88 --- /dev/null +++ b/packages/modules/consumers/solarfocus/vampair/consumer.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +from modules.common.abstract_consumer import CurrentValues +from modules.common.abstract_device import DeviceDescriptor +from modules.common.component_state import ConsumerState +from modules.common.component_type import ComponentType +from modules.common.configurable_consumer import ConfigurableConsumer +from modules.common.modbus import ModbusDataType, ModbusTcpClient_ +from modules.common.simcount._simcounter import SimCounterConsumer +from modules.consumers.vampair.vampair.config import VampairHeatPump + + +def create_consumer(config: VampairHeatPump): + client = None + sim_counter = None + + def initializer(): + nonlocal client, sim_counter + client = ModbusTcpClient_(config.configuration.ip_address, config.configuration.port) + sim_counter = SimCounterConsumer(config.id, ComponentType.CONSUMER) + + def error_handler() -> None: + initializer() + + def update() -> ConsumerState: + power = client.read_holding_registers(2322, ModbusDataType.INT_16, unit=config.configuration.modbus_id) + imported, exported = sim_counter.sim_count(power) + return ConsumerState( + power=power, + imported=imported, + exported=exported + ) + + def set_limit(power_limit: float) -> None: + # Elektrische Sollleistung HEMS (PV) + client.write_register(33415, power_limit, unit=config.configuration.modbus_id) + client.write_register(33409, power_limit * -1, unit=config.configuration.modbus_id) + + def send_values(values: CurrentValues) -> None: + client.write_register(33408, values.pv_power * -1, unit=config.configuration.modbus_id) + client.write_register(33409, values.evu_power * -1, unit=config.configuration.modbus_id) + + return ConfigurableConsumer(consumer_config=config, + initializer=initializer, + error_handler=error_handler, + update=update, + set_limit=set_limit, + send_values=send_values) + + +device_descriptor = DeviceDescriptor(configuration_factory=VampairHeatPump) diff --git a/packages/modules/consumers/solarfocus/vendor.py b/packages/modules/consumers/solarfocus/vendor.py new file mode 100644 index 0000000000..fa7842045c --- /dev/null +++ b/packages/modules/consumers/solarfocus/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 = "Solarfocus" + self.group = VendorGroup.VENDORS.value + + +vendor_descriptor = DeviceDescriptor(configuration_factory=Vendor) From 9caca795d8178b2df2fd4bcb9441659d97c3e327 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 17 Aug 2026 14:14:11 +0200 Subject: [PATCH 2/5] typo --- packages/modules/consumers/solarfocus/vampair/consumer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modules/consumers/solarfocus/vampair/consumer.py b/packages/modules/consumers/solarfocus/vampair/consumer.py index c76b3fda88..13016c0da9 100644 --- a/packages/modules/consumers/solarfocus/vampair/consumer.py +++ b/packages/modules/consumers/solarfocus/vampair/consumer.py @@ -6,7 +6,7 @@ from modules.common.configurable_consumer import ConfigurableConsumer from modules.common.modbus import ModbusDataType, ModbusTcpClient_ from modules.common.simcount._simcounter import SimCounterConsumer -from modules.consumers.vampair.vampair.config import VampairHeatPump +from modules.consumers.solarfocus.vampair.config import VampairHeatPump def create_consumer(config: VampairHeatPump): From df6452e80716daf86d6e3067ce9490bf934da443 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 17 Aug 2026 14:44:38 +0200 Subject: [PATCH 3/5] review --- .../modules/consumers/solarfocus/vampair/config.py | 2 +- .../modules/consumers/solarfocus/vampair/consumer.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/modules/consumers/solarfocus/vampair/config.py b/packages/modules/consumers/solarfocus/vampair/config.py index 612e3b9095..0de42b9fba 100644 --- a/packages/modules/consumers/solarfocus/vampair/config.py +++ b/packages/modules/consumers/solarfocus/vampair/config.py @@ -15,7 +15,7 @@ def __init__(self, ip_address: Optional[str] = None, port: Optional[int] = 502, @auto_str -class VampairHeatPump(ConsumerSetup[VampairConfiguration]): +class Vampair(ConsumerSetup[VampairConfiguration]): def __init__(self, name: str = "Vampair Wärmepumpe", type: str = "vampair", diff --git a/packages/modules/consumers/solarfocus/vampair/consumer.py b/packages/modules/consumers/solarfocus/vampair/consumer.py index 13016c0da9..20b0440799 100644 --- a/packages/modules/consumers/solarfocus/vampair/consumer.py +++ b/packages/modules/consumers/solarfocus/vampair/consumer.py @@ -6,10 +6,10 @@ from modules.common.configurable_consumer import ConfigurableConsumer from modules.common.modbus import ModbusDataType, ModbusTcpClient_ from modules.common.simcount._simcounter import SimCounterConsumer -from modules.consumers.solarfocus.vampair.config import VampairHeatPump +from modules.consumers.solarfocus.vampair.config import Vampair -def create_consumer(config: VampairHeatPump): +def create_consumer(config: Vampair): client = None sim_counter = None @@ -30,7 +30,7 @@ def update() -> ConsumerState: exported=exported ) - def set_limit(power_limit: float) -> None: + def set_power_limit(power_limit: float) -> None: # Elektrische Sollleistung HEMS (PV) client.write_register(33415, power_limit, unit=config.configuration.modbus_id) client.write_register(33409, power_limit * -1, unit=config.configuration.modbus_id) @@ -43,8 +43,8 @@ def send_values(values: CurrentValues) -> None: initializer=initializer, error_handler=error_handler, update=update, - set_limit=set_limit, + set_power_limit=set_power_limit, send_values=send_values) -device_descriptor = DeviceDescriptor(configuration_factory=VampairHeatPump) +device_descriptor = DeviceDescriptor(configuration_factory=Vampair) From 9410e72b7dae60329e4a706a8324e60d4e58a5f4 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Tue, 18 Aug 2026 14:56:43 +0200 Subject: [PATCH 4/5] review --- docs/samples/sample_consumer/sample_consumer/consumer.py | 3 ++- packages/modules/consumers/generic/json/config.py | 4 +--- packages/modules/consumers/generic/json/consumer.py | 6 +++--- packages/modules/consumers/my_pv/elwa_e/consumer.py | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/samples/sample_consumer/sample_consumer/consumer.py b/docs/samples/sample_consumer/sample_consumer/consumer.py index af25c43365..fb94155b6a 100644 --- a/docs/samples/sample_consumer/sample_consumer/consumer.py +++ b/docs/samples/sample_consumer/sample_consumer/consumer.py @@ -4,10 +4,11 @@ from modules.common.abstract_consumer import CurrentValues from modules.common.abstract_device import DeviceDescriptor from modules.common.component_state import ConsumerState +from modules.common.component_type import ComponentType from modules.common.configurable_consumer import ConfigurableConsumer from modules.common.modbus import ModbusDataType, ModbusTcpClient_ from modules.common.simcount._simcounter import SimCounterConsumer -from modules.consumers.askoma.askoheat.config import SampleConsumer +from modules.consumers.sample.sample.config import SampleConsumer log = logging.getLogger(__name__) diff --git a/packages/modules/consumers/generic/json/config.py b/packages/modules/consumers/generic/json/config.py index fda50af220..8d92c20b4c 100644 --- a/packages/modules/consumers/generic/json/config.py +++ b/packages/modules/consumers/generic/json/config.py @@ -21,9 +21,7 @@ def __init__(self, jq_switch_off: str = None, jq_set_power_limit: str = None): self.url = url - self.jq_current_l1 = jq_current_l1 - self.jq_current_l2 = jq_current_l2 - self.jq_current_l3 = jq_current_l3 + self.jq_currents = (jq_current_l1, jq_current_l2, jq_current_l3) self.jq_power = jq_power self.jq_temperatures = jq_temperatures self.jq_imported = jq_imported diff --git a/packages/modules/consumers/generic/json/consumer.py b/packages/modules/consumers/generic/json/consumer.py index 07f0e070d3..84791334ae 100644 --- a/packages/modules/consumers/generic/json/consumer.py +++ b/packages/modules/consumers/generic/json/consumer.py @@ -78,15 +78,15 @@ def update() -> None: def switch_on(): # Authorization? - jq_switch_on(session, params={"state": True}) + jq_switch_on(params={"state": True}) def switch_off(): # Authorization? - jq_switch_off(session, params={"state": False}) + jq_switch_off(params={"state": False}) def set_power_limit(power_limit: int): # Authorization? - jq_set_power_limit(session, params={"power_limit": power_limit}) + jq_set_power_limit(params={"power_limit": power_limit}) return ConfigurableConsumer(consumer_config=config, initializer=initializer, diff --git a/packages/modules/consumers/my_pv/elwa_e/consumer.py b/packages/modules/consumers/my_pv/elwa_e/consumer.py index 779fb41c6b..2fc0312bfb 100644 --- a/packages/modules/consumers/my_pv/elwa_e/consumer.py +++ b/packages/modules/consumers/my_pv/elwa_e/consumer.py @@ -55,7 +55,7 @@ def error_handler() -> None: initializer() def update() -> ConsumerState: - nonlocal status + nonlocal power, status resp = client.read_holding_registers_bulk( Register.POWER, 4, mapping=REG_MAPPING, unit=config.configuration.modbus_id) power = resp[Register.POWER] @@ -77,7 +77,7 @@ def set_limit(power_limit: float) -> None: if power_limit < power: power_limit = power + (power - power_limit) * fuse power_limit = min(power_limit, 4000) - power_limit = min(power_limit, 0) + power_limit = max(power_limit, 0) client.write_registers(1000, power_limit, unit=config.configuration.modbus_id) return ConfigurableConsumer(consumer_config=config, From b845c7eb677d622c70dd38ba2dd0fc975bd09361 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Tue, 18 Aug 2026 15:03:53 +0200 Subject: [PATCH 5/5] review --- packages/modules/consumers/generic/json/consumer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/modules/consumers/generic/json/consumer.py b/packages/modules/consumers/generic/json/consumer.py index 84791334ae..71b737bac2 100644 --- a/packages/modules/consumers/generic/json/consumer.py +++ b/packages/modules/consumers/generic/json/consumer.py @@ -78,15 +78,15 @@ def update() -> None: def switch_on(): # Authorization? - jq_switch_on(params={"state": True}) + jq_switch_on({"state": True}) def switch_off(): # Authorization? - jq_switch_off(params={"state": False}) + jq_switch_off({"state": False}) def set_power_limit(power_limit: int): # Authorization? - jq_set_power_limit(params={"power_limit": power_limit}) + jq_set_power_limit({"power_limit": power_limit}) return ConfigurableConsumer(consumer_config=config, initializer=initializer,