Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFE: Support Helios KWL Modbus implementation #5185

Closed
nodomain opened this issue Jan 5, 2017 · 4 comments
Closed

RFE: Support Helios KWL Modbus implementation #5185

nodomain opened this issue Jan 5, 2017 · 4 comments

Comments

@nodomain
Copy link

nodomain commented Jan 5, 2017

Please support the fancy Helios KWL implementation of Modbus. https://www.heliosventilatoren.de/mbv/kwl-modbus_gateway_82269_0714_d_e_f.pdf
They require that at first the desired variable is written into a register and with the subsequential read from the holding registers, the value is returned.
Setting of values looks similar, just enter the variable name = value, e.g. v00102=1 to set the fan to level 1.
helios.txt

Example:
Temperatur Zuluft = v00105
First step: Write this into the register after the payload has been encoded. The documentation about the number of registers to read is either wrong or I don't get it ;-)

builder = BinaryPayloadBuilder(endian=Endian.Little)
builder.add_string('v00105\0')
REGISTERS_TO_READ = 32
payload = builder.build()
client.write_registers(FIRST_REGISTER_ADDR, payload, skip_encode=True, unit=SLAVE_ID)

Second step: retrieve values:

result = client.read_holding_registers(FIRST_REGISTER_ADDR, REGISTERS_TO_READ, unit=SLAVE_ID)
print(BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Little).decode_string(REGISTERS_TO_READ))

Output:

homeassistant@homeassistant:~/.homeassistant/helios$ python helios.py 
v00105=17.7

Working example file attached.

@nodomain
Copy link
Author

nodomain commented Jan 5, 2017

Updated version of my script. Python noob, please excuse 😄

#!/usr/bin/env python

from pymodbus.client.sync import ModbusTcpClient as ModbusClient
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder
import logging
import argparse
import fcntl, sys, os
import re

SLAVE_ID = 180
FIRST_REGISTER_ADDR = 0x01

# testing modbus communication
def main(ip, variable, rtr):
    logging.basicConfig()
    log = logging.getLogger()
    log.setLevel(logging.ERROR)

    # stupid workaround to use the correct number of registers
    rtr = rtr + 3
    if rtr < 8:
	rtr = 8

    client = ModbusClient(ip, 502)
    client.connect()

    builder = BinaryPayloadBuilder(endian=Endian.Little)
    builder.add_string(variable + '\0')

    payload = builder.build()
    client.write_registers(FIRST_REGISTER_ADDR, payload,
                           skip_encode=True, unit=SLAVE_ID)

    result = client.read_holding_registers(
        FIRST_REGISTER_ADDR, rtr, unit=SLAVE_ID)

    output = BinaryPayloadDecoder.fromRegisters(result.registers,
                                             endian=Endian.Little).decode_string(rtr)

    # get rid of null bytes http://chase-seibert.github.io/blog/2011/05/20/stripping-control-characters-in-python.html 
    output = re.sub(u'([\u0000])', "", output)
    print(output)

if __name__ == "__main__":
    pid_file = '/tmp/helios.pid'
    fp = open(pid_file, 'w')
    try:
        fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
    except IOError:
        # another instance is running
        sys.exit(1)
    fp.write(str(os.getpid()))

    parser = argparse.ArgumentParser(description = 'Helios KWL Modbus interface')
    parser.add_argument('ip', help='IP address of Modbus slave')
    parser.add_argument('registers', help='Number of registers to read. Can be obtained from the KWL documentation.')
    parser.add_argument('variable', help='Variable to read. If value should be set, append =value, e.g. v00102=1 to set fan to level 1.')

    args = parser.parse_args()
    main(args.ip, args.variable, int(args.registers))
    fp.close()
    os.unlink(pid_file)

Working with this sensor config:

# documentation: https://www.heliosventilatoren.de/mbv/kwl-modbus_gateway_82269_0714_d_e_f.pdf
- platform: command_line
  name: Betriebsart
  value_template: "{% if value.split ('=')[1] == '1' %}manuell{% elif value.split ('=')[1] == '0' %}automatisch{% endif %}"
  command: '/home/homeassistant/.homeassistant/helios/helios.py helios.fritz.box 5 v00101'
- platform: command_line
  name: Lüfterstufe
  value_template: "{{value.split ('=')[1]}}"
  command: '/home/homeassistant/.homeassistant/helios/helios.py helios.fritz.box 5 v00102'
- platform: command_line
  name: Temperatur Außenluft
  value_template: "{{value.split ('=')[1]}}"
  unit_of_measurement: '°C'
  command: '/home/homeassistant/.homeassistant/helios/helios.py helios.fritz.box 8 v00104'
- platform: command_line
  name: Temperatur Zuluft
  value_template: "{{value.split ('=')[1]}}"
  unit_of_measurement: '°C'
  command: '/home/homeassistant/.homeassistant/helios/helios.py helios.fritz.box 8 v00105'
- platform: command_line
  name: Temperatur Fortluft
  value_template: "{{value.split ('=')[1]}}"
  unit_of_measurement: '°C'
  command: '/home/homeassistant/.homeassistant/helios/helios.py helios.fritz.box 8 v00106'
- platform: command_line
  name: Temperatur Abluft
  value_template: "{{value.split ('=')[1]}}"
  unit_of_measurement: '°C'
  command: '/home/homeassistant/.homeassistant/helios/helios.py helios.fritz.box 8 v00107'
- platform: command_line
  name: Lüfter Zuluft RPM
  value_template: "{{value.split ('=')[1]}}"
  command: '/home/homeassistant/.homeassistant/helios/helios.py helios.fritz.box 8 v00348'
- platform: command_line
  name: Lüfter Abluft RPM
  value_template: "{{value.split ('=')[1]}}"
  command: '/home/homeassistant/.homeassistant/helios/helios.py helios.fritz.box 8 v00349'

Nevertheless it would be nice if there existed a better way of doing this.

Home Assistant is great 😃

@nodomain
Copy link
Author

nodomain commented Jan 5, 2017

Important fact: due to the fancy nature of the Helios KWL Modbus implementation, only one script at a time must be executed. Otherwise the values are overwritten in the register and hence wrong values retrieved. This is the reason for the locking mechanism in the python script - If this gets implemented into HA, this needs to be maintained as well!

@balloobbot
Copy link

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.

Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍

@nodomain
Copy link
Author

I am also fine if this is closed and can be found here as a reference. Demand does not seem too high ;-)

@home-assistant home-assistant locked and limited conversation to collaborators Jul 17, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants