tjhowse / modbus4mqtt

Modbus TCP <-> MQTT glue. YAML configuration. Robust.
Other
75 stars 33 forks source link

Error with fresh install due to PAHO-Client incomtability #53

Open cheak1974 opened 3 months ago

cheak1974 commented 3 months ago

Hi,

I just wanted to try out this library and before using it with docker I like to use it from the CLI in order to better understand what is happening. So I created a folder with a venv and installed modbus4mqtt into it with pip3 install modbus4mqtt. Then I tried to create a really simple config.yaml.

To test the program I just called the help text with modbus4mqtt --help which worked fine. When I tried to run the program against the config I got:

modbus4mqtt --hostname 192.168.10.5 --config EBYTE_ME31_AAAX2240.yaml

RESULT:

2024-03-28 18:13:21 INFO     Starting modbus4mqtt v0.6.1
Exception ignored in: <function Client.__del__ at 0x0000029263C1C7C0>
Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\paho\mqtt\client.py", line 874, in __del__
    self._reset_sockets()
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\paho\mqtt\client.py", line 1133, in _reset_sockets
    self._sock_close()
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\paho\mqtt\client.py", line 1119, in _sock_close
    if not self._sock:
           ^^^^^^^^^^
AttributeError: 'Client' object has no attribute '_sock'
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "D:\_coding_\modbus4mqtt_testing\venv\Scripts\modbus4mqtt.exe\__main__.py", line 7, in <module>
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\click\core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\click\core.py", line 1078, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\click\core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\click\core.py", line 783, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus4mqtt.py", line 292, in main
    i.connect()
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus4mqtt.py", line 42, in connect
    self.connect_mqtt()
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus4mqtt.py", line 75, in connect_mqtt
    self._mqtt_client = mqtt.Client()
                        ^^^^^^^^^^^^^
TypeError: Client.__init__() missing 1 required positional argument: 'callback_api_version'

So I guessed there has to be something wrong with the underlying mqtt library. I removed PAHO 2.0.0 with pip uninstall paho-mqtt and installed and earlier version of PAHO with pip3 install paho-mqtt==1.6.1.

Afterwards modbus4mqtt is running right away, so you should consider either updating your program to the new API of PAHO-mqtt 2.0.0 or change your requirements.txt to use 1.6.1 version during installation.

P.S.: For me it is difficult to understand how the addresses for the modbus registers are configured in the right way. Is the first number of the address the modbus function? When is the holding and when is the input table used? I think this is the core of modbus configuration and the documentation should be a little more extensive.

HTH

regards from germany

Chris

tjhowse commented 3 months ago

Thanks very much for this – I actually hit this problem at my day job but I never fixed it on this project.

I'll pin paho to <2.0 and put out a release to pypi today.

Device manufacturers have many different interpretations of how modbus should be used. It's difficult to provide universally-accurate guidance. Generally speaking "holding registers" are for configuration values, and "input" registers are either reflections of the state of physical inputs, or software inputs to the logic in the controller. Historically there have also been "coil" and "output" registers, but I haven't seen those outside of industrial Programmable Logic Controllers (PLCs).

Cheers, tjhowse.

cheak1974 commented 3 months ago

Hi tjhowse,

I'll pin paho to <2.0 and put out a release to pypi today.

great.

Device manufacturers have many different interpretations of how modbus should be used. It's difficult to provide universally-accurate guidance. Generally speaking "holding registers" are for configuration values, and "input" registers are either reflections of the state of physical inputs, or software inputs to the logic in the controller. Historically there have also been "coil" and "output" registers, but I haven't seen those outside of industrial Programmable Logic Controllers (PLCs).

Well, as the modbus protocol is comparably simple there are coils (R: FC 01 / W: FC 05/15), holding registers (R: FC 02/03 W: 06/16), input registers (R: FC 04) and even the modbus devices targeting on Smart Home like the E-Byte ones and many others too use still coils.

Modbus Reference: Modbus Reference

I was not able to read a single value from my E-Byte device while reading and writing data to/from it with the very old Modbus Poll Software was very easy. I like the approach of your software very much and it could be a piece of standard software but there should be database for working config.yaml files for known hardware somewhere along with a better documentation of how to create the config.

E-Byte documentation for my device DOC ME31-AAAX2240

I tried the following config:

ip: 192.168.10.99
port: 502
device_address: 1
variant: tcp
update_rate: 1
address_offset: 0
scan_batching: 1

registers:
  - pub_topic: "test/di01"
    address: 020000                           # Digital Input 01:   Input Register 0000  (see Page 25 of E-Byte docs)
    table: 'input'

  - pub_topic: "test/do01"
    set_topic: "test/do01/set"
    address: 050000                          # Digital Output 01 (Relay):  Coil Register 0000  (see Page 26 of E-Byte docs)
    table: 'holding'

It's tested before with Modbus Poll that the device is reachable and the registers work as documentated.

With this config I get the following error.

(venv) D:\_coding_\modbus4mqtt_testing>modbus4mqtt --hostname 192.168.10.5 --config ebyte.yaml
2024-03-29 13:30:05 INFO     Starting modbus4mqtt v0.6.1
2024-03-29 13:30:05 INFO     Connected to MQTT.
Subscribed to modbus4mqtt/test/do01/set
2024-03-29 13:30:05 ERROR    Failed to read 1 input table registers starting from 20000: Exception Response(132, 4, IllegalAddress)
Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 181, in _scan_value_range
    return result.registers
           ^^^^^^^^^^^^^^^^
AttributeError: 'ExceptionResponse' object has no attribute 'registers'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 88, in poll
    values = self._scan_value_range(table, group, self._scan_batching)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 184, in _scan_value_range
    raise ValueError("Failed to read {} {} table registers starting from {}: {}".format(count, table, start, result))
ValueError: Failed to read 1 input table registers starting from 20000: Exception Response(132, 4, IllegalAddress)
2024-03-29 13:30:05 ERROR    Failed to read 1 holding table registers starting from 50000: Exception Response(131, 3, IllegalAddress)
Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 181, in _scan_value_range
    return result.registers
           ^^^^^^^^^^^^^^^^
AttributeError: 'ExceptionResponse' object has no attribute 'registers'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 88, in poll
    values = self._scan_value_range(table, group, self._scan_batching)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 184, in _scan_value_range
    raise ValueError("Failed to read {} {} table registers starting from {}: {}".format(count, table, start, result))
ValueError: Failed to read 1 holding table registers starting from 50000: Exception Response(131, 3, IllegalAddress)
2024-03-29 13:30:05 WARNING  Couldn't get value from register 20000 in table input
2024-03-29 13:30:05 WARNING  Couldn't get value from register 50000 in table holding

Completely leaving out the last Datapoint as it is a coil leads to:

(venv) D:\_coding_\modbus4mqtt_testing>modbus4mqtt --hostname 192.168.10.5 --config ebyte.yaml
2024-03-29 13:31:46 INFO     Starting modbus4mqtt v0.6.1
2024-03-29 13:31:46 INFO     Connected to MQTT.
2024-03-29 13:31:46 ERROR    Failed to read 1 input table registers starting from 20000: Exception Response(132, 4, IllegalAddress)
Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 181, in _scan_value_range
    return result.registers
           ^^^^^^^^^^^^^^^^
AttributeError: 'ExceptionResponse' object has no attribute 'registers'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 88, in poll
    values = self._scan_value_range(table, group, self._scan_batching)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 184, in _scan_value_range
    raise ValueError("Failed to read {} {} table registers starting from {}: {}".format(count, table, start, result))
ValueError: Failed to read 1 input table registers starting from 20000: Exception Response(132, 4, IllegalAddress)
2024-03-29 13:31:46 WARNING  Couldn't get value from register 20000 in table input
2024-03-29 13:31:47 ERROR    Failed to read 1 input table registers starting from 20000: Exception Response(132, 4, IllegalAddress)
Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 181, in _scan_value_range
    return result.registers
           ^^^^^^^^^^^^^^^^
AttributeError: 'ExceptionResponse' object has no attribute 'registers'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 88, in poll
    values = self._scan_value_range(table, group, self._scan_batching)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\_coding_\modbus4mqtt_testing\venv\Lib\site-packages\modbus4mqtt\modbus_interface.py", line 184, in _scan_value_range
    raise ValueError("Failed to read {} {} table registers starting from {}: {}".format(count, table, start, result))
ValueError: Failed to read 1 input table registers starting from 20000: Exception Response(132, 4, IllegalAddress)
2024-03-29 13:31:47 WARNING  Couldn't get value from register 20000 in table input

I mean the configuration could not be easier and I can't get it to work.

Can you give me a hit what I am doing wrong?

regards

Chris