Skip to content
Merged

UPower #2234

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
Empty file.
Empty file.
53 changes: 53 additions & 0 deletions packages/modules/devices/upower/upower/bat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
from typing import Dict, Union

from dataclass_utils import dataclass_from_dict
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, ModbusTcpClient_
from modules.common.simcount import SimCounter
from modules.common.store import get_bat_value_store
from modules.devices.upower.upower.config import UPowerBatSetup
from modules.devices.upower.upower.version import UPowerVersion


class UPowerBat(AbstractBat):
def __init__(self,
component_config: Union[Dict, UPowerBatSetup],
version: UPowerVersion,
modbus_id: int) -> None:
self.component_config = dataclass_from_dict(UPowerBatSetup, component_config)
self.__modbus_id = modbus_id
self.version = version
self.store = get_bat_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="speicher")

def update(self, client: ModbusTcpClient_) -> None:
if self.version == UPowerVersion.GEN_1:
power = client.read_input_registers(30258, ModbusDataType.INT_32, unit=self.__modbus_id) * -1
soc = client.read_input_registers(33000, ModbusDataType.UINT_16, unit=self.__modbus_id)
imported = client.read_input_registers(
31108, ModbusDataType.UINT_32, unit=self.__modbus_id) * 100
exported = client.read_input_registers(
31110, ModbusDataType.UINT_32, unit=self.__modbus_id) * 100
else:
# 1221 Total Bat Power
# 1427 Battery 1 current power
# Bat 1 (additional batteries offset by 50)
power = client.read_input_registers(1427, ModbusDataType.INT_16, unit=self.__modbus_id)
soc = client.read_input_registers(1402, ModbusDataType.UINT_16, unit=self.__modbus_id) / 10
imported, exported = self.sim_counter.sim_count(power)

bat_state = BatState(
power=power,
soc=soc,
imported=imported,
exported=exported
)
self.store.set(bat_state)


component_descriptor = ComponentDescriptor(configuration_factory=UPowerBatSetup)
67 changes: 67 additions & 0 deletions packages/modules/devices/upower/upower/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from typing import Optional

from modules.common.component_setup import ComponentSetup
from ..vendor import vendor_descriptor


class UPowerConfiguration:
def __init__(self, modbus_id: int = 1, ip_address: Optional[str] = None, port: int = 502, version: int = 1):
self.modbus_id = modbus_id
self.ip_address = ip_address
self.port = port
self.version = version


class UPower:
def __init__(self,
name: str = "UPower",
type: str = "upower",
id: int = 0,
configuration: UPowerConfiguration = None) -> None:
self.name = name
self.type = type
self.vendor = vendor_descriptor.configuration_factory().type
self.id = id
self.configuration = configuration or UPowerConfiguration()


class UPowerBatConfiguration:
def __init__(self):
pass


class UPowerBatSetup(ComponentSetup[UPowerBatConfiguration]):
def __init__(self,
name: str = "UPower Speicher",
type: str = "bat",
id: int = 0,
configuration: UPowerBatConfiguration = None) -> None:
super().__init__(name, type, id, configuration or UPowerBatConfiguration())


class UPowerCounterConfiguration:
def __init__(self):
pass


class UPowerCounterSetup(ComponentSetup[UPowerCounterConfiguration]):
def __init__(self,
name: str = "UPower Zähler",
type: str = "counter",
id: int = 0,
configuration: UPowerCounterConfiguration = None) -> None:
super().__init__(name, type, id, configuration or UPowerCounterConfiguration())


class UPowerInverterConfiguration:
def __init__(self):
pass


class UPowerInverterSetup(ComponentSetup[UPowerInverterConfiguration]):
def __init__(self,
name: str = "UPower Wechselrichter",
type: str = "inverter",
id: int = 0,
configuration: UPowerInverterConfiguration = None) -> None:
super().__init__(name, type, id, configuration or UPowerInverterConfiguration())
57 changes: 57 additions & 0 deletions packages/modules/devices/upower/upower/counter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
from typing import Dict, Union

from dataclass_utils import dataclass_from_dict
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.upower.upower.config import UPowerCounterSetup
from modules.devices.upower.upower.version import UPowerVersion


class UPowerCounter(AbstractCounter):
def __init__(self,
component_config: Union[Dict, UPowerCounterSetup],
version: UPowerVersion,
modbus_id: int) -> None:
self.component_config = dataclass_from_dict(UPowerCounterSetup, component_config)
self.__modbus_id = modbus_id
self.version = version
self.store = get_counter_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="bezug")

def update(self, client: ModbusTcpClient_):
if self.version == UPowerVersion.GEN_1:
power = client.read_holding_registers(1000, ModbusDataType.INT_32, unit=self.__modbus_id) * -1
frequency = client.read_holding_registers(11015, ModbusDataType.UINT_16, unit=self.__modbus_id)

powers = [-value for value in client.read_holding_registers(
10994, [ModbusDataType.INT_32] * 3, unit=self.__modbus_id)]
exported = client.read_holding_registers(31102, ModbusDataType.UINT_32, unit=self.__modbus_id) * 100
imported = client.read_holding_registers(31104, ModbusDataType.UINT_32, unit=self.__modbus_id) * 100
else:
power = client.read_holding_registers(1219, ModbusDataType.INT_16, unit=self.__modbus_id) * -10
frequency = client.read_holding_registers(
1759, ModbusDataType.UINT_16, unit=self.__modbus_id) / 100

powers = [-10 * value for value in client.read_holding_registers(
1750, [ModbusDataType.INT_16] * 3, unit=self.__modbus_id
)]
imported, exported = self.sim_counter.sim_count(power)

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


component_descriptor = ComponentDescriptor(configuration_factory=UPowerCounterSetup)
56 changes: 56 additions & 0 deletions packages/modules/devices/upower/upower/device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
import logging
from typing import Iterable, Union

from modules.common.abstract_device import DeviceDescriptor
from modules.common.component_context import SingleComponentUpdateContext
from modules.common.configurable_device import ConfigurableDevice, ComponentFactoryByType, MultiComponentUpdater
from modules.common.modbus import ModbusTcpClient_
from modules.devices.upower.upower.bat import UPowerBat
from modules.devices.upower.upower.config import UPower, UPowerBatSetup, UPowerCounterSetup, UPowerInverterSetup
from modules.devices.upower.upower.counter import UPowerCounter
from modules.devices.upower.upower.inverter import UPowerInverter
from modules.devices.upower.upower.version import UPowerVersion

log = logging.getLogger(__name__)


def create_device(device_config: UPower):
def create_bat_component(component_config: UPowerBatSetup):
return UPowerBat(component_config,
UPowerVersion(device_config.configuration.version),
device_config.configuration.modbus_id)

def create_counter_component(component_config: UPowerCounterSetup):
return UPowerCounter(component_config,
UPowerVersion(device_config.configuration.version),
device_config.configuration.modbus_id)

def create_inverter_component(component_config: UPowerInverterSetup):
return UPowerInverter(component_config,
UPowerVersion(device_config.configuration.version),
device_config.configuration.modbus_id)

def update_components(components: Iterable[Union[UPowerBat, UPowerCounter, UPowerInverter]]):
with client as c:
for component in components:
with SingleComponentUpdateContext(component.fault_state):
component.update(c)

try:
client = ModbusTcpClient_(device_config.configuration.ip_address, device_config.configuration.port)

except Exception:
log.exception("Fehler in create_device")
return ConfigurableDevice(
device_config=device_config,
component_factory=ComponentFactoryByType(
bat=create_bat_component,
counter=create_counter_component,
inverter=create_inverter_component,
),
component_updater=MultiComponentUpdater(update_components)
)


device_descriptor = DeviceDescriptor(configuration_factory=UPower)
42 changes: 42 additions & 0 deletions packages/modules/devices/upower/upower/inverter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
from typing import Dict, Union
# from pymodbus.constants import Endian

from dataclass_utils import dataclass_from_dict
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.store import get_inverter_value_store
from modules.devices.upower.upower.config import UPowerInverterSetup
from modules.devices.upower.upower.version import UPowerVersion


class UPowerInverter(AbstractInverter):
def __init__(self,
component_config: Union[Dict, UPowerInverterSetup],
version: UPowerVersion,
modbus_id: int) -> None:
self.component_config = dataclass_from_dict(UPowerInverterSetup, component_config)
self.__modbus_id = modbus_id
self.version = version
self.store = get_inverter_value_store(self.component_config.id)
self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config))

def update(self, client: ModbusTcpClient_) -> None:
if self.version == UPowerVersion.GEN_1:
power = client.read_holding_registers(11028, ModbusDataType.UINT_32, unit=self.__modbus_id) * -1
exported = client.read_holding_registers(11020, ModbusDataType.UINT_32, unit=self.__modbus_id) * 100
else:
power = client.read_holding_registers(1220, ModbusDataType.UINT_16, unit=self.__modbus_id) * -1
exported = client.read_holding_registers(1006, ModbusDataType.UINT_32, unit=self.__modbus_id) * 10

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


component_descriptor = ComponentDescriptor(configuration_factory=UPowerInverterSetup)
6 changes: 6 additions & 0 deletions packages/modules/devices/upower/upower/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from enum import IntEnum


class UPowerVersion(IntEnum):
GEN_1 = 1
GEN_2 = 2
14 changes: 14 additions & 0 deletions packages/modules/devices/upower/vendor.py
Original file line number Diff line number Diff line change
@@ -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 = "UPower"
self.group = VendorGroup.VENDORS.value


vendor_descriptor = DeviceDescriptor(configuration_factory=Vendor)