Skip to content

Commit 34679da

Browse files
authored
add Kaco Inverter (Tx1 & Tx3 Series) (#2349)
* add Kaco Tx inverter * remove unused variables
1 parent 66c4191 commit 34679da

5 files changed

Lines changed: 179 additions & 0 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from modules.common.component_setup import ComponentSetup
2+
from ..vendor import vendor_descriptor
3+
4+
5+
class KacoConfiguration:
6+
def __init__(self,
7+
port: int = 502,
8+
ip_address=None):
9+
self.port = port
10+
self.ip_address = ip_address
11+
12+
13+
class Kaco:
14+
def __init__(self,
15+
name: str = "Kaco Tx1 & Tx3 Serie",
16+
type: str = "kaco",
17+
id: int = 0,
18+
configuration: KacoConfiguration = None) -> None:
19+
self.name = name
20+
self.type = type
21+
self.vendor = vendor_descriptor.configuration_factory().type
22+
self.id = id
23+
self.configuration = configuration or KacoConfiguration()
24+
25+
26+
class KacoInverterConfiguration:
27+
def __init__(self, modbus_id: int = 1):
28+
self.modbus_id = modbus_id
29+
30+
31+
class KacoInverterSetup(ComponentSetup[KacoInverterConfiguration]):
32+
def __init__(self,
33+
name: str = "Kaco Wechselrichter",
34+
type: str = "inverter",
35+
id: int = 0,
36+
configuration: KacoInverterConfiguration = None) -> None:
37+
super().__init__(name, type, id, configuration or KacoInverterConfiguration())
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env python3
2+
import logging
3+
from typing import Iterable
4+
5+
from modules.common import modbus
6+
from modules.common.abstract_device import DeviceDescriptor
7+
from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, MultiComponentUpdater
8+
from modules.devices.kaco.kaco_tx.inverter import KacoInverter
9+
from modules.devices.kaco.kaco_tx.config import (Kaco, KacoInverterSetup)
10+
11+
log = logging.getLogger(__name__)
12+
13+
reconnect_delay = 1.2
14+
15+
16+
def create_device(device_config: Kaco):
17+
client = None
18+
19+
def create_inverter_component(component_config: KacoInverterSetup):
20+
nonlocal client
21+
return KacoInverter(component_config, client=client)
22+
23+
def update_components(components: Iterable[KacoInverter]):
24+
nonlocal client
25+
with client:
26+
for component in components:
27+
component.update()
28+
29+
def initializer():
30+
nonlocal client
31+
client = modbus.ModbusTcpClient_(device_config.configuration.ip_address,
32+
device_config.configuration.port,
33+
reconnect_delay=reconnect_delay)
34+
35+
device = ConfigurableDevice(
36+
device_config=device_config,
37+
initializer=initializer,
38+
component_factory=ComponentFactoryByType(
39+
inverter=create_inverter_component
40+
),
41+
component_updater=MultiComponentUpdater(update_components)
42+
)
43+
return device
44+
45+
46+
device_descriptor = DeviceDescriptor(configuration_factory=Kaco)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env python3
2+
from typing import TypedDict, Any
3+
4+
from modules.common import modbus
5+
from modules.common.abstract_device import AbstractInverter
6+
from modules.common.component_state import InverterState
7+
from modules.common.component_type import ComponentDescriptor
8+
from modules.common.fault_state import ComponentInfo, FaultState
9+
from modules.common.modbus import ModbusDataType
10+
from modules.common.store import get_inverter_value_store
11+
from modules.devices.kaco.kaco_tx.config import KacoInverterSetup
12+
from modules.devices.kaco.kaco_tx.scale import create_scaled_reader
13+
14+
15+
class KwargsDict(TypedDict):
16+
client: modbus.ModbusTcpClient_
17+
18+
19+
class KacoInverter(AbstractInverter):
20+
def __init__(self,
21+
component_config: KacoInverterSetup,
22+
**kwargs: Any) -> None:
23+
self.component_config = component_config
24+
self.kwargs: KwargsDict = kwargs
25+
26+
def initialize(self) -> None:
27+
self.__tcp_client = self.kwargs['client']
28+
self.store = get_inverter_value_store(self.component_config.id)
29+
self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config))
30+
self._read_scaled_int16 = create_scaled_reader(
31+
self.__tcp_client, self.component_config.configuration.modbus_id, ModbusDataType.INT_16
32+
)
33+
self._read_scaled_int32 = create_scaled_reader(
34+
self.__tcp_client, self.component_config.configuration.modbus_id, ModbusDataType.INT_32
35+
)
36+
37+
def update(self) -> None:
38+
self.store.set(self.read_state())
39+
40+
def read_state(self):
41+
# 40084 | Total AC Power | int16
42+
# 40085 | AC Power scale factor | sunssf
43+
power = self._read_scaled_int16(40084, 1)[0] * -1
44+
45+
# 40094 | AC Energy | acc32
46+
# 40096 | AC Energy scale factor | sunssf
47+
exported = self._read_scaled_int32(40094, 1)[0]
48+
49+
return InverterState(
50+
power=power,
51+
exported=exported
52+
)
53+
54+
55+
component_descriptor = ComponentDescriptor(configuration_factory=KacoInverterSetup)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import logging
2+
import math
3+
from typing import List
4+
5+
from modules.common.modbus import ModbusDataType, ModbusTcpClient_, Number
6+
7+
log = logging.getLogger(__name__)
8+
9+
# Registers that are not applicable to a meter class return the unsupported value. (e.g. Single Phase
10+
# meters will support only summary and phase A values):
11+
12+
UINT16_UNSUPPORTED = 0xFFFF
13+
14+
15+
def scale_registers(registers: List[Number]) -> List[float]:
16+
log.debug("Registers %s, Scale %s", registers[:-1], registers[-1])
17+
scale = math.pow(10, registers[-1])
18+
return [register * scale if register != UINT16_UNSUPPORTED else 0 for register in registers[:-1]]
19+
20+
21+
def create_scaled_reader(client: ModbusTcpClient_, modbus_id: int, type: ModbusDataType):
22+
def scaled_reader(address: int, count: int):
23+
return scale_registers(
24+
client.read_holding_registers(address, [type] * count + [ModbusDataType.INT_16], unit=modbus_id)
25+
)
26+
27+
return scaled_reader
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from pathlib import Path
2+
3+
from modules.common.abstract_device import DeviceDescriptor
4+
from modules.devices.vendors import VendorGroup
5+
6+
7+
class Vendor:
8+
def __init__(self):
9+
self.type = Path(__file__).parent.name
10+
self.vendor = "Kaco"
11+
self.group = VendorGroup.VENDORS.value
12+
13+
14+
vendor_descriptor = DeviceDescriptor(configuration_factory=Vendor)

0 commit comments

Comments
 (0)