diff --git a/packages/modules/devices/kostal/kostal_plenticore/bat.py b/packages/modules/devices/kostal/kostal_plenticore/bat.py index 2357adae06..2ea9003784 100644 --- a/packages/modules/devices/kostal/kostal_plenticore/bat.py +++ b/packages/modules/devices/kostal/kostal_plenticore/bat.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 import logging -from typing import Any, Callable, TypedDict +from typing import TypedDict, Any + from modules.common.abstract_device import AbstractBat from modules.common.component_state import BatState from modules.common.component_type import ComponentDescriptor -from modules.common.modbus import ModbusDataType 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_bat_value_store from modules.devices.kostal.kostal_plenticore.config import KostalPlenticoreBatSetup @@ -15,6 +16,8 @@ class KwargsDict(TypedDict): device_id: int + modbus_id: int + client: ModbusTcpClient_ class KostalPlenticoreBat(AbstractBat): @@ -24,29 +27,27 @@ def __init__(self, component_config: KostalPlenticoreBatSetup, **kwargs: Any) -> def initialize(self) -> None: self.__device_id: int = self.kwargs['device_id'] + self.modbus_id: int = self.kwargs['modbus_id'] + self.client: ModbusTcpClient_ = self.kwargs['client'] self.store = get_bat_value_store(self.component_config.id) - self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="speicher") self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) + self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="speicher") - def read_state(self, reader: Callable[[int, ModbusDataType], Any]) -> BatState: - power = reader(582, ModbusDataType.INT_16) * -1 - soc = reader(514, ModbusDataType.INT_16) + def update(self) -> None: + power = self.client.read_holding_registers(582, ModbusDataType.INT_16, unit=self.modbus_id) * -1 + soc = self.client.read_holding_registers(514, ModbusDataType.INT_16, unit=self.modbus_id) + if power < 0: + power = self.client.read_holding_registers(106, ModbusDataType.FLOAT_32, unit=self.modbus_id) * -1 imported, exported = self.sim_counter.sim_count(power) log.debug("raw bat power "+str(power)) - # Speicherladung muss durch Wandlungsverluste und internen Verbrauch korrigiert werden, sonst - # wird ein falscher Hausverbrauch berechnet. Die Verluste fallen hier unter den Tisch. - if power < 0: - power = reader(106, ModbusDataType.FLOAT_32) * -1 - return BatState( + bat_state = BatState( power=power, soc=soc, imported=imported, - exported=exported, + exported=exported ) - - def update(self, state): - self.store.set(state) + self.store.set(bat_state) component_descriptor = ComponentDescriptor(configuration_factory=KostalPlenticoreBatSetup) diff --git a/packages/modules/devices/kostal/kostal_plenticore/counter.py b/packages/modules/devices/kostal/kostal_plenticore/counter.py index ed91eb0120..ea1836e29d 100644 --- a/packages/modules/devices/kostal/kostal_plenticore/counter.py +++ b/packages/modules/devices/kostal/kostal_plenticore/counter.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 -from typing import Any, Callable, TypedDict +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 +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.kostal.kostal_plenticore.config import KostalPlenticoreCounterSetup @@ -12,6 +13,8 @@ class KwargsDict(TypedDict): device_id: int + modbus_id: int + client: ModbusTcpClient_ class KostalPlenticoreCounter(AbstractCounter): @@ -21,33 +24,35 @@ def __init__(self, component_config: KostalPlenticoreCounterSetup, **kwargs: Any def initialize(self) -> None: self.__device_id: int = self.kwargs['device_id'] + self.modbus_id: int = self.kwargs['modbus_id'] + self.client: ModbusTcpClient_ = self.kwargs['client'] self.store = get_counter_value_store(self.component_config.id) - self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="bezug") self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) + self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="bezug") - def get_values(self, reader: Callable[[int, ModbusDataType], Any]) -> CounterState: - power_factor = reader(150, ModbusDataType.FLOAT_32) - currents = [reader(register, ModbusDataType.FLOAT_32) for register in [222, 232, 242]] - voltages = [reader(register, ModbusDataType.FLOAT_32) for register in [230, 240, 250]] - powers = [reader(register, ModbusDataType.FLOAT_32) for register in [224, 234, 244]] - power = reader(252, ModbusDataType.FLOAT_32) - frequency = reader(220, ModbusDataType.FLOAT_32) - - return CounterState( + def update(self) -> None: + power = self.client.read_holding_registers(252, ModbusDataType.FLOAT_32, unit=self.modbus_id) + imported, exported = self.sim_counter.sim_count(power) + power_factor = self.client.read_holding_registers(150, ModbusDataType.FLOAT_32, unit=self.modbus_id) + currents = [self.client.read_holding_registers( + reg, ModbusDataType.FLOAT_32, unit=self.modbus_id) for reg in [222, 232, 242]] + voltages = [self.client.read_holding_registers( + reg, ModbusDataType.FLOAT_32, unit=self.modbus_id) for reg in [230, 240, 250]] + powers = [self.client.read_holding_registers( + reg, ModbusDataType.FLOAT_32, unit=self.modbus_id) for reg in [224, 234, 244]] + frequency = self.client.read_holding_registers(220, ModbusDataType.FLOAT_32, unit=self.modbus_id) + + counter_state = CounterState( powers=powers, currents=currents, voltages=voltages, power=power, power_factors=[power_factor]*3, - frequency=frequency + frequency=frequency, + imported=imported, + exported=exported ) - - def update_imported_exported(self, state: CounterState) -> CounterState: - state.imported, state.exported = self.sim_counter.sim_count(state.power) - return state - - def update(self, reader: Callable[[int, ModbusDataType], Any]): - self.store.set(self.update_imported_exported(self.get_values(reader))) + self.store.set(counter_state) component_descriptor = ComponentDescriptor(configuration_factory=KostalPlenticoreCounterSetup) diff --git a/packages/modules/devices/kostal/kostal_plenticore/device.py b/packages/modules/devices/kostal/kostal_plenticore/device.py index 87a729beca..87dc441f4c 100644 --- a/packages/modules/devices/kostal/kostal_plenticore/device.py +++ b/packages/modules/devices/kostal/kostal_plenticore/device.py @@ -1,88 +1,64 @@ -# !/usr/bin/env python3 -from enum import IntEnum -from typing import Any, Callable, Iterable, Union -from pymodbus.constants import Endian -import functools +#!/usr/bin/env python3 import logging +from typing import Iterable, Union -from modules.common import modbus 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.kostal.kostal_plenticore.bat import KostalPlenticoreBat -from modules.devices.kostal.kostal_plenticore.inverter import KostalPlenticoreInverter -from modules.devices.kostal.kostal_plenticore.config import (KostalPlenticore, KostalPlenticoreBatSetup, - KostalPlenticoreCounterSetup, - KostalPlenticoreInverterSetup) from modules.devices.kostal.kostal_plenticore.counter import KostalPlenticoreCounter - +from modules.devices.kostal.kostal_plenticore.inverter import KostalPlenticoreInverter +from modules.devices.kostal.kostal_plenticore.config import KostalPlenticore, KostalPlenticoreBatSetup +from modules.devices.kostal.kostal_plenticore.config import KostalPlenticoreCounterSetup, KostalPlenticoreInverterSetup log = logging.getLogger(__name__) -class LegacyCounterPosition(IntEnum): - HOME_CONSUMPTION = 0 - GRID = 1 - - -def update( - components: Iterable[Union[KostalPlenticoreBat, KostalPlenticoreCounter, KostalPlenticoreInverter]], - reader: Callable[[int, modbus.ModbusDataType], Any], - set_inverter_state: bool = True): - battery = next((component for component in components if isinstance(component, KostalPlenticoreBat)), None) - bat_state = battery.read_state(reader) if battery else None - for component in components: - if isinstance(component, KostalPlenticoreInverter): - # Fürs erste nur die WR-Werte nutzen ohne Verlustberechnung. - # power: R575(inverter generation power (actual)) - # exported: R320 (Total yield) - inverter_state = component.read_state(reader) - pv_state = inverter_state - if set_inverter_state: - component.update(pv_state) - elif isinstance(component, KostalPlenticoreCounter): - component.update(reader) - if bat_state: - battery.update(bat_state) - if set_inverter_state is False: - return pv_state - - def create_device(device_config: KostalPlenticore): client = None - reader = None def create_bat_component(component_config: KostalPlenticoreBatSetup): - return KostalPlenticoreBat(component_config, device_id=device_config.id) + nonlocal client + return KostalPlenticoreBat(component_config, + device_id=device_config.id, + modbus_id=device_config.configuration.modbus_id, + client=client) def create_counter_component(component_config: KostalPlenticoreCounterSetup): - return KostalPlenticoreCounter(component_config, device_id=device_config.id) + nonlocal client + return KostalPlenticoreCounter(component_config, + device_id=device_config.id, + modbus_id=device_config.configuration.modbus_id, + client=client) def create_inverter_component(component_config: KostalPlenticoreInverterSetup): - return KostalPlenticoreInverter(component_config) + nonlocal client + return KostalPlenticoreInverter(component_config, + device_id=device_config.id, + modbus_id=device_config.configuration.modbus_id, + client=client) def update_components( - components: Iterable[Union[KostalPlenticoreBat, KostalPlenticoreCounter, KostalPlenticoreInverter]] - ): - nonlocal client, reader + components: Iterable[Union[KostalPlenticoreBat, KostalPlenticoreCounter, KostalPlenticoreInverter]]): + nonlocal client with client: - update(components, reader) + for component in components: + component.update() def initializer(): - nonlocal client, reader - client = modbus.ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port) - reader = _create_reader(client, device_config.configuration.modbus_id) + nonlocal client + client = ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port) return ConfigurableDevice( device_config=device_config, initializer=initializer, component_factory=ComponentFactoryByType( - bat=create_bat_component, counter=create_counter_component, inverter=create_inverter_component), - component_updater=MultiComponentUpdater(update_components), + bat=create_bat_component, + counter=create_counter_component, + inverter=create_inverter_component, + ), + component_updater=MultiComponentUpdater(update_components) ) -def _create_reader(tcp_client: modbus.ModbusTcpClient_, modbus_id: int) -> Callable[[int, modbus.ModbusDataType], Any]: - return functools.partial(tcp_client.read_holding_registers, unit=modbus_id, wordorder=Endian.Little) - - device_descriptor = DeviceDescriptor(configuration_factory=KostalPlenticore) diff --git a/packages/modules/devices/kostal/kostal_plenticore/inverter.py b/packages/modules/devices/kostal/kostal_plenticore/inverter.py index ba6a7db640..966f16b3df 100644 --- a/packages/modules/devices/kostal/kostal_plenticore/inverter.py +++ b/packages/modules/devices/kostal/kostal_plenticore/inverter.py @@ -1,37 +1,44 @@ #!/usr/bin/env python3 -from typing import Any, Callable +from typing import TypedDict, Any + 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.modbus import ModbusDataType, ModbusTcpClient_ +from modules.common.simcount import SimCounter from modules.common.store import get_inverter_value_store from modules.devices.kostal.kostal_plenticore.config import KostalPlenticoreInverterSetup +class KwargsDict(TypedDict): + device_id: int + modbus_id: int + client: ModbusTcpClient_ + + class KostalPlenticoreInverter(AbstractInverter): - def __init__(self, component_config: KostalPlenticoreInverterSetup) -> None: + def __init__(self, component_config: KostalPlenticoreInverterSetup, **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.modbus_id: int = self.kwargs['modbus_id'] + self.client: ModbusTcpClient_ = self.kwargs['client'] self.store = get_inverter_value_store(self.component_config.id) self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) + self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="pv") - def read_state(self, reader: Callable[[int, ModbusDataType], Any]) -> InverterState: - # PV-Anlage kann nichts verbrauchen, also ggf. Register-/Rundungsfehler korrigieren. - power = reader(575, ModbusDataType.INT_16) * -1 - exported = reader(320, ModbusDataType.FLOAT_32) + def update(self) -> None: + power = self.client.read_holding_registers(575, ModbusDataType.INT_16, unit=self.modbus_id) * -1 + exported = self.client.read_holding_registers(320, ModbusDataType.FLOAT_32, unit=self.modbus_id) - return InverterState( + inverter_state = InverterState( power=power, exported=exported ) - - def dc_in_string_1_2(self, reader: Callable[[int, ModbusDataType], Any]): - return reader(260, ModbusDataType.FLOAT_32) + reader(270, ModbusDataType.FLOAT_32) - - def update(self, state): - self.store.set(state) + self.store.set(inverter_state) component_descriptor = ComponentDescriptor(configuration_factory=KostalPlenticoreInverterSetup)