Takes hours to set a Modbus register

I’ve connected a Nibe S1255 to HA through Modbus. Reading data from the connection is rather swift but writing to its registers takes forever. Last night I run some test through the Service tester in Development Tools. I went to bed about 11:30. Now checking it this morning the update was performed at 2:10. I.e. it took 2 hours and 40 minutes to get the update through. However using the PyModbus console on the HA host the updates are almost instant (can’t really measure it but we’re talking about milliseconds here).

Is it some intrinsic problem with the HA Modbus when doing updates? Or are there any priority or timeout parameters that are important? Or should I just skip using the Modbus integration and be looking at an external update script?

Regards,

Jörgen

I found a work-round.

I wrote a Python Modbus script and placed it on a the hosting server. Then used the shell_command integration to call the Python script through SSH.

Hi Jorgen,

Do you have a list of registers you can write to?

I was able to configure a switch for the more hot water function (with the help of others) and works fine.

Hi wgumaa!

Yes, it’s possible to dump all available and unavailable Modbus registers from the Nibe S1255 to USB memory stick (resulting format is CSV). Some of them are input registers others are holding one. The latter you can write to.

I’ve used Python Modbus as well as Perl MBclient module successfully towards my S1255 heat pump. The problem seems to be that HA is running under Docker. I’ve very little experience with Docker so I guess it may have to do with its network setup. But I would then expect it to fail totally and not succeeding after a couple of hours. Using a Modbus library on the hosts updates the Modbus registers on the S1255 “instantly”.

Regards,

Jörgen

1 Like

Thanks for the reply, I am not running through docker (running on Pi) and was able to configure the set up through yaml.

Here is the “more hot water” switch example I used

  switches:
  - name: "More Hot Water"
    unique_id: "More Hot Water"
    write_type: holding # R/W
    address: 697
    slave: 1
    command_on: 3
    command_off: 0 

I have identified the entities I wish to control, but no idea how to write the code in yaml for them.

  - name: "Heatpump - Operating Mode"  
    # 0: auto, 1: manual, 2: additional heating only
    unique_id: "operating_mode"
    data_type: int16  # uint8
    address: 237
    input_type: holding # R/W
    scale: 1
    precision: 0
    state_class: measurement
    slave: 1

  - name: "Heatpump - Heating Curve Offset"  # 1.30.1
    unique_id: "heating_curve_offset"
    data_type: int16  # int8
    address: 30
    input_type: holding # R/W
    scale: 1
    precision: 0
    state_class: measurement
    slave: 1

Do you have any ideas?

Hi wgumaa!

I’ve only needed to update the main fuse value so far. This because the monitor clamps used by the Nibe S1255 can’t detect what “way” the current is flowing and this became a problem when I installed our solar panels. So I face a problem during high levels of sunshine where the Nibe refuses to heat any hot water as it’s thinking that there’s no room left for any additional load.

I have 20 A fuse and it’s controlled by the 103 holding register. I’ve setup a small Python script on the host:

#!/usr/bin/env python3
"""
Pymodbus write holding register
--------------------------------------------------------------------------
Author: Jörgen Andreasen <[email protected]>

"""
# --------------------------------------------------------------------------- #
# import the various client implementations
# --------------------------------------------------------------------------- #
from pymodbus.client.sync import ModbusTcpClient as ModbusClient

# --------------------------------------------------------------------------- #
# configure the client logging
# --------------------------------------------------------------------------- #
import logging

import sys, getopt

FORMAT = ('%(asctime)-15s %(threadName)-15s '
          '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.INFO)

UNIT     = 0x1

def write_register(argv):
   host     = 'localhost'
   port     = 502
   register = -1
   value    = -1
   
   try:
      opts, args = getopt.getopt(argv,"h:p:r:v:d",["host=","port=","register=", "value=", "debug"])
   except getopt.GetoptError:
      print('pymodbus.write_register -h <host> -p <port> -r <register> -v value')
      sys.exit(2)

   for opt, arg in opts:
      if opt in ("-h", "--host"):
         host = arg
      elif opt in ("-p", "--port"):
         port = int(arg)
      elif opt in ("-r", "--register"):
         register = int(arg)
      elif opt in ("-v", "--value"):
         value = int(arg)
      elif opt in ("-d", "--debug"):
         log.setLevel(logging.DEBUG)


   client = ModbusClient(host, port=port)
   client.connect()
   log.debug("Write to a holding register and read back")
   log.debug("register = " + str(register) + "  value = " + str(value) )
   rq = client.write_register(register, value, unit=UNIT)
   rr = client.read_holding_registers(register, 1, unit=UNIT)
   assert(not rq.isError())     # test that we are not an error
   assert(not rr.isError())     # test that we are not an error
   assert(rr.registers[0] == value)       # test the expected value

if __name__ == "__main__":
   write_register(sys.argv[1:])

That can update a single holding register. The script is called pymodbus.write_register and was installed in the /usr/local/bin directory on the host running the Docker containers.
The I created a wrapper script, called set_main_fuse, with the content:

#!/bin/bash
Fuse=$1
Server=<host name>
DataDir=/config/modbus
SSH="ssh -i $DataDir/ssh-id -oStrictHostKeyChecking=no -oUserKnownHostsFile=$DataDir/known_hosts"

$SSH $Server pymodbus.write_register --host=<Nibe host> --register=103 --value=$Fuse

The SSH public key corresponding to the SSH private key,ssh-id, needs to be present the authorized_keys file of the target account, in my case I’ve just used the system root account. The set_main_fuse wrapper script is present in the modbus sub directory of the HA configuration directory, normally /usr/share/hassio/homeassistant on the host (which corresponds to /config within the Docker container)

Two commands where then setup in the HA configuration:

shell_command:
   solar_export_fuse: /config/modbus/set_main_fuse 40
   no_solar_export_fuse: /config/modbus/set_main_fuse 20

The solar_export_fuse command raises the fuse the Nibe sees to 40 A whereas no_solar_export_fuse lowers it back to the original value. I then have two automations for raising and lowering the fuse depending on if I’m exporting energy or not. These automations are using the two defined commands.

Best regards,

Jörgen

Hi again wgumaa!

If you’re not using Docker I guess using the Modbus: Write register service is what you need. I tried to use it for my automations but it took several hours before the service actually sent any Modbus packages to the heat pump. I suppose that this might work for you as you’ve installed HA directly on a host. Just using a sensor wont work as it will only update the internal state. You can try this out in the developer tools where you can set the value of a sensor. These settings will not have an effect on the Modbus register on your heat pump. In fact reloading the sensor value will just pull the value from the heat pump and you’re back where you started.

I guess you can use the Button Card in a Dashboard configuration. I’ve never used this card myself but it seems to allow you to connect a dashboard button to a service, in your case the Modbus: Write register service. Most of the fields are easy to understand. One was a bit tricky, the Hub field (Modbus hub name). Apparently this is the name field assigned to your heat pump in the modbus configuration. This then expands to the host and TCP port the Mobus service will use to set the register.

I hope the above will help you a bit.

Best regards,

Jörgen

1 Like

It seems the new Nibe integration, with support for Modbus over TCP, doesn’t have the problems I’ve experienced. You can set the heat pump parameters directly through each HA sensor and they are effectuated immediately.

Further the Nibe integration saves you the trouble of adding all Modbus registers manually. It also seem to have many more, undocumented ones (in the Nibe Modbus documentation), Modbus registers drawn out as sensors. The only snag is that the Nibe integration supports a lot of different Nibe heat pumps and modules and it can sometimes be a bit tricky to find the correct one (especially when you, as I, have used the Swedish names).

To date I’ve failed to spot a Modbus register, I’ve used in the past, that isn’t supported by the Nibe integration.

Anyway, I’ve started converting my setup from the Modbus to the Nibe integration. I need to retain at least some old sensors as they are tied to the statistical data in the Energy dashboard.

Hi jorgen-zafir,

The Nibe integration works quite well for me except figuring out which registers are actually connected to my heatpump, haha.

But the information I’m interested in is the ‘energy log’ that you see on the machine in I believe the 2nd or 3rd start screen. If I understand you correct you have figured out how to fetch this statistical data. I’ve tried to connect to my system with the pymodbus python package but I just can’t get it to work (tried both from the server/docker and my desktop). Do you have any tips for me to help me on my way? :slight_smile:

Tack på förhand!

Hi Albastraoz!

Sorry for the late answer. :frowning:

I’m not sure about what you mean with “energy log” but I’ve connected the energy production sensors from the heat pump to the HA Energy dashboard “Gas” entities. In my case they are called “S1255 Heating, including int. add. heat” and “S1255 Heating, including int. add. heat”. As I have a built-in hot-water heater I can see this separately from the heat generation. You also get production total for the heat-pump in the dashboard. To see the heat-pump consumption I’ve added a consumption entity in the dashboard using the Riemann integration over the “S1255 Instantaneous used power” Nibe integration sensor.

Further I use the Influxdb to log all HA sensors for getting a better view of long term trends. Then I use Graphana to produce diagrams which includes all three above entities plus calculating the COP (using Graphana built-in calculation feature) for the time-period displayed. It works rather good. Although I have problems with the year report due to some misalignment in Graphana. It doesn’t detect where the months begin. Also, I haven’t made an attempt on letting Graphana calculate the SCOP yet, this I keep in a separate spreadsheet.

The only problem I’ve seen with this setup is that when using the passive cooling system, which is connected to the heat-pump, it needs to run the brine-pump. As I don’t have any sensors connected to the cooling convector and hence can’t calculate the amount of cooling energy produced it skews the COP calculations. This makes the COP worse than it really is.

When it comes to the direct Modus controls, outside of the Nibe integration, I’m not using it anymore for the heat-pump. I have, though, HA automations to raise the fuse level in the heat-pump when I’m exporting a lot of solar. The reason for this is that the current detectors doesn’t really detect what direction the energy is flowing. And the HA automations circumvents any problems making hot water when exporting a lot of solar.

However, I do use direct Modbus control for the PV system. Especially the battery control. Primarily I use HA automations using the Modbus integration to turn off battery discharge when the EV is charging. But I also have an external override in the form of a Perl based Modbus script I’ve written. This script is rather simple but allows you to send Modbus commands to any attached unit on my LAN. The script is using the MBclient CPAN module. You can do the same in Python and I used in the past but existing scripts are more complex and I needed to strip them down from using any user interface as I needed to execute these script unattended and scheduled from the Cron system.

/Jörgen

I’m experiencing the exact same issue now after almost a year of working writing and reading my inverter through a modbus gateway…

The reading is excellent but the writing is almost not working at all, if I reboot ha it seems to work for a few minutes but then stops working again. One of my inverter gateways keeps it up for a bit longer for some reason.

Most annoying is that it worked like a charm before for many months, and I’m running ha in a standard docker image… I dont really want to fiddle with scripts and so on tho… just wanted to lift the issue…