├── pictures └── ksem_in_victronui.png ├── helpers ├── readme.md └── read_modbus_tcp_register.py ├── Kostal_SmartEnergyMeter.py └── readme.md /pictures/ksem_in_victronui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmcgn/dbus-modbus-client-kostal-smartmeter/HEAD/pictures/ksem_in_victronui.png -------------------------------------------------------------------------------- /helpers/readme.md: -------------------------------------------------------------------------------- 1 | # Development helpers 2 | 3 | These files are not intended to run on a Vanus OS device. I used the python script to read and validate some registers via my development machine. -------------------------------------------------------------------------------- /helpers/read_modbus_tcp_register.py: -------------------------------------------------------------------------------- 1 | from pymodbus.client.tcp import ModbusTcpClient as ModbusClient 2 | import ipaddress 3 | from pymodbus.exceptions import ConnectionException, ModbusIOException 4 | 5 | ksemIP = input("IP (v4) Address of your KOSTAl SMart Energy Meter (KSEM): ") 6 | 7 | try: 8 | if ipaddress.IPv4Address(ksemIP): 9 | client = ModbusClient(method='tcp', host=ksemIP, port=502) 10 | 11 | try: 12 | client.connect() 13 | 14 | try: 15 | read=client.read_holding_registers(address = 0x2001, count = 1, slave = 1) 16 | 17 | for value in read.registers: 18 | print("KSEM Device ID (Decimal): ", value) 19 | # print("DEC: ", value, ", HEX: ", hex(value)) 20 | 21 | except ModbusIOException as modbus_io_exception: 22 | print(f"Modbus error while reading the register: {modbus_io_exception}") 23 | 24 | except ConnectionException as connection_exception: 25 | print(f"TCP connection can't be established. Check KSEM IP. Check if Modbus Server is enabled on the KSEM.") 26 | 27 | finally: 28 | client.close() 29 | 30 | else: 31 | print(f"The provided address {ksemIP} is not a valid IPv4 address. Aborting.") 32 | exit(1) 33 | 34 | except ValueError as value_error: 35 | print(f"Invalid IP address format: {value_error}") 36 | exit(1) 37 | -------------------------------------------------------------------------------- /Kostal_SmartEnergyMeter.py: -------------------------------------------------------------------------------- 1 | # VenusOS module for support of KOSTAL Smart Energy Meter 2 | # Community contribution by Philipp Mahler 3 | 4 | import logging 5 | import device 6 | import probe 7 | from register import * 8 | 9 | log = logging.getLogger() 10 | 11 | class Kostal_SmartEnergyMeter(device.EnergyMeter): 12 | productid = 0x00 13 | productname = 'KOSTAL Smart Energy Meter' 14 | min_timeout = 0.5 15 | 16 | def __init__(self, *args): 17 | super(Kostal_SmartEnergyMeter, self).__init__(*args) 18 | 19 | self.info_regs = [ 20 | Reg_u16(0x2002, '/HardwareVersion'), 21 | Reg_u16(0x2003, '/FirmwareVersion'), 22 | Reg_text(0x2024, 4, '/Serial'), 23 | ] 24 | 25 | def device_init(self): 26 | self.read_info() 27 | 28 | regs = [ 29 | Reg_u32b(0x001A, '/Ac/Frequency', 1000, '%.1f Hz'), 30 | Reg_u64b(0x0200, '/Ac/Energy/Forward', 10000, '%.1f kWh'), 31 | Reg_u64b(0x0204, '/Ac/Energy/Reverse', 10000, '%.1f kWh'), 32 | 33 | Reg_u32b(0x003E, '/Ac/L1/Voltage', 1000, '%.1f V'), 34 | Reg_u32b(0x003C, '/Ac/L1/Current', 1000, '%.3f A'), 35 | Reg_u64b(0x0250, '/Ac/L1/Energy/Forward', 10000, '%.1f kWh'), 36 | Reg_u64b(0x0254, '/Ac/L1/Energy/Reverse', 10000, '%.1f kWh'), 37 | 38 | Reg_u32b(0x0066, '/Ac/L2/Voltage', 1000, '%.1f V'), 39 | Reg_u32b(0x0064, '/Ac/L2/Current', 1000, '%.3f A'), 40 | Reg_u64b(0x02A0, '/Ac/L2/Energy/Forward', 10000, '%.1f kWh'), 41 | Reg_u64b(0x02A4, '/Ac/L2/Energy/Reverse', 10000, '%.1f kWh'), 42 | 43 | Reg_u32b(0x008E, '/Ac/L3/Voltage', 1000, '%.1f V'), 44 | Reg_u32b(0x008C, '/Ac/L3/Current', 1000, '%.3f A'), 45 | Reg_u64b(0x02F0, '/Ac/L3/Energy/Forward', 10000, '%.1f kWh'), 46 | Reg_u64b(0x02F4, '/Ac/L3/Energy/Reverse', 10000, '%.1f kWh'), 47 | 48 | # Power data from KSEM internal registers, different ones for pos/neg values 49 | 50 | Reg_u32b(0x0000, '/Ac/Power', 10, '%.1f W'), # positive value register total power 51 | Reg_u32b(0x0002, '/Ac/Power', -10, '%.1f W'), # negative value register total power 52 | Reg_u32b(0x0028, '/Ac/L1/Power', 10, '%.1f W'), # positive value register L1 power 53 | Reg_u32b(0x002A, '/Ac/L1/Power', -10, '%.1f W'), # negative value register L1 power 54 | Reg_u32b(0x0050, '/Ac/L2/Power', 10, '%.1f W'), # positive value register L2 power 55 | Reg_u32b(0x0052, '/Ac/L2/Power', -10, '%.1f W'), # negative value register L2 power 56 | Reg_u32b(0x0078, '/Ac/L3/Power', 10, '%.1f W'), # positive value register L3 power 57 | Reg_u32b(0x007A, '/Ac/L3/Power', -10, '%.1f W'), # negative value register L3 power 58 | 59 | # Power data from SunSpec registers alternatively 60 | # 61 | # Drawbacks: 62 | # - lower resolution (10W instead of 0.1W) 63 | # - requires consideration of power scale factor (e.g. -1 to shift decimal point one to the left, see SunSpec specification section 4.2.8) 64 | 65 | # Reg_u16(0x9C9C, '/Ac/PowerFactor'), 66 | # Reg_s16(0x9C98, '/Ac/Power', 1, '%.0f W'), 67 | # Reg_s16(0x9C99, '/Ac/L1/Power', 1, '%.0f W'), 68 | # Reg_s16(0x9C9A, '/Ac/L2/Power', 1, '%.0f W'), 69 | # Reg_s16(0x9C9B, '/Ac/L3/Power', 1, '%.0f W'), 70 | ] 71 | 72 | self.data_regs = regs 73 | 74 | def get_ident(self): 75 | return 'cg_%s' % self.info['/Serial'] 76 | 77 | 78 | models = { 79 | 18498: { 80 | 'model': 'KOSTAL_KSEM', 81 | 'handler': Kostal_SmartEnergyMeter, 82 | }, 83 | 18514: { 84 | 'model': 'KOSTAL_KSEM', 85 | 'handler': Kostal_SmartEnergyMeter, 86 | }, 87 | 18530: { 88 | 'model': 'KOSTAL_KSEM', 89 | 'handler': Kostal_SmartEnergyMeter, 90 | }, 91 | } 92 | 93 | 94 | 95 | #VenusOS < 2.92 96 | #probe.add_handler(probe.ModelRegister(0x2001, models, methods=['tcp'], units=[1])) 97 | 98 | #VenusOS >= 2.92 99 | probe.add_handler(probe.ModelRegister(Reg_u16(0x2001), models, methods=['tcp'], units=[1])) 100 | 101 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Use KOSTAL Smart Energy Meter with Victron Systems 2 | 3 | This project enables the use of KOSTAL Smart Energy Meters (KSEM) within an Victron Envrionment. After installing this module on an VenusOS Device (like the Cerbo GX), the GX device will be able to identify and use the data of a KSEM. For example, an existing Kostal Photovoltaic System shall be extenden with a battery, controlled by a Multiplus II, there is no need of an additional Energy Meter, as the live values from the Kostal System can be used inside the Victron System. 4 | 5 | ![Kostal Smart Energy Meter detected by Cerbo GX](pictures/ksem_in_victronui.png?raw=true) 6 | 7 | ## Getting Started 8 | 9 | To be able to communicate with the KSEM, the KSEM must be directly connected to the local network via it's LAN port. It is not enough, that the PV Inverter is connected via LAN. Make sure that the Modbus TCP port is open (on the Webinterface of the KSEM: Settings -> Modbus TCP Settings -> Slave -> Enable TCP Slave = ON). Also, please ensure the the KSEM has always the same IP (either static IP or statically assigned by DHCP server!). 10 | In addition, you need root access to the GX device. The procedure is descibed in the [Venus OS Documentation](https://www.victronenergy.com/live/ccgx:root_access). 11 | This readme assumes, that you are familiar with basic file operations and SSH usage. I may improve the description later. 12 | 13 | ### Installation 14 | 15 | 1. SSH into the GX device 16 | 2. Navigate to the modbus client folder: `cd /opt/victronenergy/dbus-modbus-client` 17 | 3. Download the module: `wget https://raw.githubusercontent.com/pmcgn/dbus-modbus-client-kostal-smartmeter/main/Kostal_SmartEnergyMeter.py` 18 | 4. Open the file dbus-modbus-client.py in a text editor: `vi dbus-modbus-client.py` 19 | 5. Add the instruction `import Kostal_SmartEnergyMeter` behind the other imports (before typing, press `i` to switch to input mode 20 | 6. Save and exit vi: Press `ESC` then type `:wq` and press `Enter` 21 | 7. Delete python cache: `rm /opt/victronenergy/dbus-modbus-client/__pycache__/dbus-modbus-client.cpython-38.pyc` 22 | 8. Restart the GX device via `reboot` 23 | 24 | ## Usage 25 | 26 | Open the GX Webinterface and navigate to Settings -> Modbus TCP Devices and trigger a Scan. It should now be able to find the KSEM. If the automatic detection does not work, go to Devices and press Add, to add the KSEM IP manually. 27 | 28 | ## Known Limitations 29 | 30 | 1. Serial number not shown in victron. This is an Issue of the KSEM, as it does not provide a correct value for the serial number. 31 | 2. Power precision is 10W. This is a limitation of the used SunSpec register. There are internal registers which provide higher precision, but they don't propagate positive and negative values on the same register. 32 | 33 | ## Troubleshooting 34 | 35 | - Check that the file Kostal_SmartEnergyMeter.py exists and that it is placed into the correct dorectory 36 | - Check if the import instruction in the file dbus-modbus-client.py has been saved 37 | - Check if the KSEM IP is reachable from the local network 38 | - Check if the Modbus TCP Service is running on the KSEM (either by checking the configuration or using Modbus TCP test tools). 39 | - Ensure that the IP of the KSEM does not change after adding it to the GX device. Otherwise the communication will fail after a while. 40 | - Check logfile `/var/log/dbus-modbus-client/current` on VenusOS device. Expectation is to see a line containing `Found KOSTAL_KSEM at tcp::502:1` 41 | - It seems that KOSTAL is changing the identifier of the KSEM with some updates. This identifier is used by Victron to ensure that the target device is really a Kostal Smart Energy Meter. To check if you are affected by the change, please execute the following steps: 42 | - Install python on your computer via https://www.python.org/downloads/ (Sorry, currently the next script does not run directly on VenusOS, Pull requests are welcome) 43 | - Download the helper script `https://raw.githubusercontent.com/pmcgn/dbus-modbus-client-kostal-smartmeter/main/helpers/read_modbus_tcp_register.py` to your windows machine 44 | - Execute it with `python \read_modbus_tcp_register.py` 45 | - The script will ask for the KSEM IP Address, enter it and hit enter 46 | - If everything is ok, the script will tell you the Identifier of your KSEM (`KSEM Device ID (Decimal): 18498`) 47 | - Open the file Kostal_SmartEnergyMeter.py on the KSEM (Downloaded during installation), and make sure that the identifier from the previous step is listed at the end. For Example: `models = { 18498: ...` 48 | - If your identifier does not appear here, change the default of 18498 to the value from the helper script 49 | - Reboot the VenusOS device after changing the identifier 50 | - If it works, please let me know your identifier. The easiest way is to create a github issue (mention your value!). 51 | --------------------------------------------------------------------------------