Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 35 additions & 3 deletions packages/modules/devices/solarmax/solarmax/bat.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env python3
from typing import TypedDict, Any
import logging
from typing import TypedDict, Any, Optional

from pymodbus.constants import Endian
from modules.common.abstract_device import AbstractBat
from modules.common.component_state import BatState
from modules.common.component_type import ComponentDescriptor
Expand All @@ -10,6 +12,8 @@
from modules.common.store import get_bat_value_store
from modules.devices.solarmax.solarmax.config import SolarmaxBatSetup

log = logging.getLogger(__name__)


class KwargsDict(TypedDict):
device_id: int
Expand All @@ -30,8 +34,8 @@ def initialize(self) -> None:

def update(self) -> None:
unit = self.component_config.configuration.modbus_id
power = self.client.read_holding_registers(114, ModbusDataType.INT_32, unit=unit)
soc = self.client.read_holding_registers(122, ModbusDataType.INT_16, unit=unit)
power = self.client.read_input_registers(114, ModbusDataType.INT_32, unit=unit, wordorder=Endian.Little)
soc = self.client.read_input_registers(122, ModbusDataType.INT_16, unit=unit)
imported, exported = self.sim_counter.sim_count(power)

bat_state = BatState(
Expand All @@ -42,5 +46,33 @@ def update(self) -> None:
)
self.store.set(bat_state)

def set_power_limit(self, power_limit: Optional[int]) -> None:
unit = self.component_config.configuration.modbus_id
log.debug(f'last_mode: {self.last_mode}')
# reg 142 is automatically reset every 60s so needs to be written continuously
if power_limit is None:
log.debug("Keine Batteriesteuerung, Selbstregelung durch Wechselrichter")
if self.last_mode is not None:
self.__tcp_client.write_registers(142, [0], data_type=ModbusDataType.INT_16, unit=unit)
self.last_mode = None
elif power_limit == 0:
log.debug("Aktive Batteriesteuerung. Batterie wird auf Stop gesetzt und nicht entladen")
self.__tcp_client.write_registers(140, [0], data_type=ModbusDataType.INT_16, unit=unit)
self.__tcp_client.write_registers(141, [0], data_type=ModbusDataType.INT_16, unit=unit)
self.__tcp_client.write_registers(142, [1], data_type=ModbusDataType.INT_16, unit=unit)
self.last_mode = 'stop'
elif power_limit < 0:
log.debug(f"Aktive Batteriesteuerung. Batterie wird mit {power_limit} W entladen für den Hausverbrauch")
self.__tcp_client.write_registers(142, [1], data_type=ModbusDataType.INT_16, unit=unit)
self.last_mode = 'discharge'
# Die maximale Entladeleistung begrenzen auf 5000W, maximaler Wertebereich Modbusregister.
power_value = int(min(abs(power_limit), 7000))
log.debug(f"Aktive Batteriesteuerung. Batterie wird mit {power_value} W entladen für den Hausverbrauch")
self.__tcp_client.write_registers(140, [power_value], data_type=ModbusDataType.INT_16, unit=unit)
self.__tcp_client.write_registers(141, [power_value], data_type=ModbusDataType.INT_16, unit=unit)

def power_limit_controllable(self) -> bool:
return self.component_config.configuration.power_limit_controllable


component_descriptor = ComponentDescriptor(configuration_factory=SolarmaxBatSetup)
31 changes: 30 additions & 1 deletion packages/modules/devices/solarmax/solarmax/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,26 @@ def __init__(self,
self.configuration = configuration or SolarmaxConfiguration()


class SolarmaxBatConfiguration:
class SolarmaxMsCounterConfiguration:
def __init__(self, modbus_id: int = 1):
self.modbus_id = modbus_id


class SolarmaxMsCounterSetup(ComponentSetup[SolarmaxMsCounterConfiguration]):
def __init__(self,
name: str = "Solarmax MAX.STORAGE / MAX.STORAGE Ultimate Zähler",
type: str = "counter_maxstorage",
id: Optional[int] = 0,
configuration: SolarmaxMsCounterConfiguration = None) -> None:
super().__init__(name, type, id, configuration or SolarmaxMsCounterConfiguration())


class SolarmaxBatConfiguration:
def __init__(self, modbus_id: int = 1, power_limit_controllable: bool = False):
self.modbus_id = modbus_id
self.power_limit_controllable = power_limit_controllable


class SolarmaxBatSetup(ComponentSetup[SolarmaxBatConfiguration]):
def __init__(self,
name: str = "Solarmax MAX.STORAGE / MAX.STORAGE Ultimate Speicher",
Expand All @@ -37,6 +52,20 @@ def __init__(self,
super().__init__(name, type, id, configuration or SolarmaxBatConfiguration())


class SolarmaxMsInverterConfiguration:
def __init__(self, modbus_id: int = 1):
self.modbus_id = modbus_id


class SolarmaxMsInverterSetup(ComponentSetup[SolarmaxMsInverterConfiguration]):
def __init__(self,
name: str = "Solarmax MAX.STORAGE / MAX.STORAGE Ultimate Wechselrichter",
type: str = "inverter_maxstorage",
id: int = 0,
configuration: SolarmaxMsInverterConfiguration = None) -> None:
super().__init__(name, type, id, configuration or SolarmaxMsInverterConfiguration())


class SolarmaxInverterConfiguration:
def __init__(self, modbus_id: int = 1):
self.modbus_id = modbus_id
Expand Down
47 changes: 47 additions & 0 deletions packages/modules/devices/solarmax/solarmax/counter_maxstorage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/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
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.solarmax.solarmax.config import SolarmaxMsCounterSetup


class KwargsDict(TypedDict):
device_id: int
client: ModbusTcpClient_


class SolarmaxMsCounter(AbstractCounter):
def __init__(self,
component_config: SolarmaxMsCounterSetup,
**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) -> None:
unit = self.component_config.configuration.modbus_id
power = self.client.read_input_registers(118, ModbusDataType.INT_32, unit=unit, wordorder=Endian.Little) * -1
imported, exported = self.sim_counter.sim_count(power)

counter_state = CounterState(
power=power,
imported=imported,
exported=exported
)
self.store.set(counter_state)


component_descriptor = ComponentDescriptor(configuration_factory=SolarmaxMsCounterSetup)
24 changes: 20 additions & 4 deletions packages/modules/devices/solarmax/solarmax/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
from modules.common.component_context import SingleComponentUpdateContext
from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, MultiComponentUpdater
from modules.devices.solarmax.solarmax import inverter
from modules.devices.solarmax.solarmax.inverter import SolarmaxInverter
from modules.devices.solarmax.solarmax.bat import SolarmaxBat
from modules.devices.solarmax.solarmax.config import (
Solarmax, SolarmaxBatSetup, SolarmaxConfiguration, SolarmaxInverterSetup)
from modules.devices.solarmax.solarmax.counter_maxstorage import SolarmaxMsCounter
from modules.devices.solarmax.solarmax.inverter_maxstorage import SolarmaxMsInverter
from modules.devices.solarmax.solarmax.config import (Solarmax, SolarmaxConfiguration,
SolarmaxBatSetup, SolarmaxMsCounterSetup,
SolarmaxInverterSetup, SolarmaxMsInverterSetup)

log = logging.getLogger(__name__)

Expand All @@ -24,9 +28,18 @@ def create_bat_component(component_config: SolarmaxBatSetup):

def create_inverter_component(component_config: SolarmaxInverterSetup):
nonlocal client
return inverter.SolarmaxInverter(component_config, device_id=device_config.id, client=client)
return SolarmaxInverter(component_config, device_id=device_config.id, client=client)

def update_components(components: Iterable[Union[SolarmaxBat, inverter.SolarmaxInverter]]):
def create_inverter_ms_component(component_config: SolarmaxMsInverterSetup):
nonlocal client
return SolarmaxMsInverter(component_config, device_id=device_config.id, client=client)

def create_counter_ms_component(component_config: SolarmaxMsCounterSetup):
nonlocal client
return SolarmaxMsCounter(component_config, device_id=device_config.id, client=client)

def update_components(components: Iterable[Union[SolarmaxBat, SolarmaxInverter,
SolarmaxMsCounter, SolarmaxMsInverter]]):
nonlocal client
with client:
for component in components:
Expand All @@ -43,6 +56,9 @@ def initializer():
component_factory=ComponentFactoryByType(
bat=create_bat_component,
inverter=create_inverter_component,
counter_maxstorage=create_counter_ms_component,
inverter_maxstorage=create_inverter_ms_component,

),
component_updater=MultiComponentUpdater(update_components)
)
Expand Down
46 changes: 46 additions & 0 deletions packages/modules/devices/solarmax/solarmax/inverter_maxstorage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
from typing import TypedDict, Any

from pymodbus.constants import Endian
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, ModbusTcpClient_
from modules.common.simcount import SimCounter
from modules.common.store import get_inverter_value_store
from modules.devices.solarmax.solarmax.config import SolarmaxMsInverterSetup


class KwargsDict(TypedDict):
device_id: int
client: ModbusTcpClient_


class SolarmaxMsInverter(AbstractInverter):
def __init__(self,
component_config: SolarmaxMsInverterSetup,
**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="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) -> None:
unit = self.component_config.configuration.modbus_id
power = self.client.read_input_registers(120, ModbusDataType.INT_32, unit=unit, wordorder=Endian.Little) * -1
_, exported = self.sim_counter.sim_count(power)

inverter_state = InverterState(
power=power,
exported=exported
)
self.store.set(inverter_state)


component_descriptor = ComponentDescriptor(configuration_factory=SolarmaxMsInverterSetup)