Coder Social home page Coder Social logo

gavinying / modpoll Goto Github PK

View Code? Open in Web Editor NEW
64.0 4.0 15.0 12.39 MB

A New Command-line Tool for Modbus and MQTT

Home Page: https://helloysd.gitlab.io/modpoll

License: MIT License

Dockerfile 0.62% Python 99.30% Shell 0.08%
iot modbus mqtt python docker gateway iiot modpoll

modpoll's Introduction

modpoll - A New Command-line Tool for Modbus and MQTT

pipeline status License Downloads

Learn more about modpoll usage at documentation site.

Motivation

The initial idea of creating this tool is to help myself debugging new devices during site survey. A site survey usually has limited time and space, working on-site also piles up some pressures. At that time, a portable swiss-knife toolkit is our best friend.

This program can be easily deployed to Raspberry Pi or similar embedded devices, polling data from modbus devices, users can choose to log data locally or publish to a MQTT broker for further debugging.

The MQTT broker can be setup on the same Raspberry Pi or on the cloud. Once data successfully published, users can subscribe to a specific MQTT topic to view the data via a smartphone at your fingertip.

Moreover, you can also run this program continuously on a server as a Modbus-MQTT gateway, i.e. polling from local Modbus devices and forwarding data to a centralized cloud service.

In fact, modpoll helps to bridge between the traditional field-bus world and the new IoT world.

This program is designed to be a standalone tool, it works out-of-the-box on Linux/macOS/Windows.

If you are looing for a modbus python library, please consider the following great open source projects, pymodbus or minimalmodbus

Feature

  • Support Modbus RTU/TCP/UDP devices
  • Show polling data for local debugging, like a typical modpoll tool
  • Publish polling data to MQTT broker for remote debugging, especially on smart phone
  • Export polling data to local storage for further investigation
  • Provide docker solution for continuous data polling use case

Installation

This program tested on python 3.8+, the package is available in the Python Package Index, users can easily install it using pip or pipx.

Using PIP

Python3 is supported by most popular platforms, e.g. Linux/macOS/Windows, on which you can install modpoll using pip tool,

pip install modpoll

Optionally, pyserial library can be installed for Modbus-RTU communication,

pip install 'modpoll[serial]'

Upgrade the tool via the following command,

pip install -U modpoll

On Windows

It is recommended to use pipx for installing modpoll on Windows, refer to here for more information about pipx.

Once pipx installed, you can run the following command in a Command Prompt terminal.

pipx install modpoll

Upgrade the tool via the following command,

pipx upgrade modpoll

Quickstart

modpoll is a python tool for communicating with Modbus devices, so ideally it makes more sense if you have a real Modbus device on hand for the following test, but it is OK if you don't, we provide a virtual Modbus TCP device deployed at modsim.topmaker.net:502 for your quick testing purpose.

Let's start exploring modpoll with modsim device, run the following command to get a first glimpse,

modpoll \
  --tcp modsim.topmaker.net \
  --config https://raw.githubusercontent.com/gavinying/modpoll/master/examples/modsim.csv

the modsim code is also available here

Prepare Modbus configure file

The reason we can magically poll data from the online device modsim is because we have already provided the Modbus configure file for modsim device as following,

device,modsim001,1,,
poll,coil,0,16,BE_BE
ref,coil01-08,0,bool8,rw
ref,coil09-16,1,bool8,rw
poll,discrete_input,10000,16,BE_BE
ref,di01-08,10000,bool8,rw
ref,di09-16,10001,bool8,rw
poll,input_register,30000,20,BE_BE
ref,input_reg01,30000,uint16,rw
ref,input_reg02,30001,uint16,rw
ref,input_reg03,30002,uint16,rw
ref,input_reg04,30003,uint16,rw
ref,input_reg05,30004,int16,rw
ref,input_reg06,30005,int16,rw
ref,input_reg07,30006,int16,rw
ref,input_reg08,30007,int16,rw
ref,input_reg09,30008,uint32,rw
ref,input_reg10,30010,uint32,rw
ref,input_reg11,30012,int32,rw
ref,input_reg12,30014,int32,rw
ref,input_reg13,30016,float32,rw
ref,input_reg14,30018,float32,rw
poll,holding_register,40000,20,BE_BE
ref,holding_reg01,40000,uint16,rw
ref,holding_reg02,40001,uint16,rw
ref,holding_reg03,40002,uint16,rw
ref,holding_reg04,40003,uint16,rw
ref,holding_reg05,40004,int16,rw
ref,holding_reg06,40005,int16,rw
ref,holding_reg07,40006,int16,rw
ref,holding_reg08,40007,int16,rw
ref,holding_reg09,40008,uint32,rw
ref,holding_reg10,40010,uint32,rw
ref,holding_reg11,40012,int32,rw
ref,holding_reg12,40014,int32,rw
ref,holding_reg13,40016,float32,rw
ref,holding_reg14,40018,float32,rw

This configuration tells modpoll to do the following for each poll,

  • Read 16 coils from the address starting from 0 and parse the response as two 8-bits boolean values;
  • Read 16 discrete inputs from the address starting from 10000 and parse the response as two 8-bits boolean values;
  • Read 20 input registers from the address starting from 30000 and parse data accordingly;
  • Read 20 holding registers from the address starting from 40000 and parse data accordingly;

In practical, you usually need to customize a Modbus configuration file for your own device before running modpoll tool, which defines the optimal polling patterns and register mappings according to device vendor's documents.

You can also take a look at contrib folder, which collects a few types of device configuration shared by contributors.

The configuration can be either a local file or a remote public URL resource.

Refer to the documentation site for more details.

Poll local device (modsim)

If you are blocked by company firewall for online device or prefer a local test, you can launch your own device simulator by running modsim locally,

docker run --rm -p 5020:5020 helloysd/modsim

It will create a virtual Modbus TCP device running at localhost:5020, and you can open a new terminal, poll the virtual device using modpoll tool,

modpoll \
  --tcp localhost \
  --tcp-port 5020 \
  --config https://raw.githubusercontent.com/gavinying/modpoll/master/examples/modsim.csv

Use sudo before the docker command if you want to use the standard port 502.

sudo docker run --rm -p 502:5020 helloysd/modsim

In a new terminal,

modpoll \
  --tcp localhost \
  --config https://raw.githubusercontent.com/gavinying/modpoll/master/examples/modsim.csv

Publish data to MQTT broker

This is a useful function of this new modpoll tool, which provides a simple way to publish collected modbus data to MQTT broker, so users can view data from a smart phone via a MQTT client.

The following example uses a public MQTT broker mqtt.eclipseprojects.io for test purpose. You can also set up your own MQTT broker locally using mosquitto.

modpoll \
  --tcp modsim.topmaker.net \
  --mqtt-host mqtt.eclipseprojects.io \
  --config https://raw.githubusercontent.com/gavinying/modpoll/master/examples/modsim.csv

With successful data polling and publishing, you can subscribe the topic modpoll/modsim on the same MQTT broker mqtt.eclipseprojects.io to view the collected data.

The MQTT topic uses <mqtt_topic_prefix>/<deviceid> pattern, <mqtt_topic_prefix> is provided by --mqtt-topic-prefix argument, the default value is modpoll/ and is provided by the Modbus configure file.

Write registers via MQTT publish

The modpoll tool will subscribe to the topic <mqtt_topic_prefix>/<deviceid>/set once it successfully connected to MQTT broker, user can write device register(s) via MQTT publish,

  • To write a single holding register (address at 40001)

    {
      "object_type": "holding_register",
      "address": 40001,
      "value": 12
    }
  • To write multiple holding registers (address starting from 40001)

    {
      "object_type": "holding_register",
      "address": 40001,
      "value": [12, 13, 14, 15]
    }

Run with docker

A docker image has been provided for user to directly run the program without local installation,

docker run --rm helloysd/modpoll

It shows the version of the program by default.

Similar to the above modsim test, we can poll data with docker run, in order to avoid printing out received data, the argument --daemon or -d is recommended to use with docker.

docker run --rm helloysd/modpoll \
  modpoll -d \
    --tcp modsim.topmaker.net \
    --config https://raw.githubusercontent.com/gavinying/modpoll/master/examples/modsim.csv

If you want to load a local configure file, you need to mount a local folder onto container volume, for example, if the child folder examples contains the config file modsim.csv, we can use it via the following command,

docker run --rm -v $(pwd)/examples:/app/examples helloysd/modpoll \
  modpoll -d \
    --tcp modsim.topmaker.net \
    --config /app/examples/modsim.csv

Basic Usage

  • Connect to Modbus TCP device

    modpoll \
      --tcp 192.168.1.10 \
      --config examples/modsim.csv
  • Connect to Modbus RTU device

    modpoll \
      --rtu /dev/ttyUSB0 \
      --rtu-baud 9600 \
      --config contrib/eniwise/scpms6.csv
  • Connect to Modbus TCP device and publish data to MQTT broker

    modpoll \
      --tcp modsim.topmaker.net \
      --tcp-port 5020 \
      --mqtt-host mqtt.eclipseprojects.io \
      --config examples/modsim.csv
  • Connect to Modbus TCP device and export data to local csv file

    modpoll \
      --tcp modsim.topmaker.net \
      --tcp-port 5020 \
      --export data.csv \
      --config examples/modsim.csv

Refer to the documentation site for more details about the configuration and examples.

Credits

The implementation of this project is heavily inspired by the following two projects:

Thanks to Max Brueggemann and Oliver Wagner for their great work.

License

MIT © helloysd

modpoll's People

Contributors

ennui2342 avatar exeba avatar freakern avatar gavinying avatar giig1967g avatar mitchell-pioneer avatar mr-manuel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

modpoll's Issues

Add support for Daniel/Enron single register 32-bit mode

Hi,

I'm incredibly excited about the potential of this project given the many limitations of pymodbus and its integration in the Home Assistant project. The MQTT integration makes it a great candidate for IoT projects.

I was testing your library and I've noticed it also lacks support for the so called "Enron Modbus", or 32-bit values as one register instead of two. This is a particularly common modbus mode in Portuguese Smart Meters. It has been implemented in other python libs like https://github.com/u9n/enron-modbus.

Is this something you could consider implementing?

Thanks!

Add Option for Remove Local Echo

Hi,
thank you for this great project.
I found out today that my converter generates a local echo and it can't be turned off.
So my question is if an option can be added to remove local echoes.
Thanks!

Consider update dependency of `pymodbus` to v3.5.2

Hello Shaodong,
I'm using modpoll for some time on a 24x7 server and have an issue, that after about 3 days of continues readings and if the modbus PLC fails communication for more than about 10 times the async pymodbus v3.4.1 call crash and aborts the task, because it does not re-raise the exception.

log example

2023-09-06 23:03:40,083 WARNING  iomodbus.modbus_poll           Reading device: ETAR                 func_code:03 start_address:001901 size:004 ... FAILED
2023-09-06 23:03:40,087 INFO     iomodbus.modbus_poll           Reading device: AZOTO                func_code:03 start_address:000001 size:016 ... SUCCESS
2023-09-06 23:03:43,023 INFO     iomodbus.modbus_poll           Reading device: QE2.2-VALUES         func_code:03 start_address:050514 size:060 ... SUCCESS
(...)
2023-09-06 23:03:45,846 INFO     iomodbus.modbus_poll           Reading device: QE2.2-
2023-09-06 23:04:12,857 ERROR    iomodbus.modbus_poll           CanceledError on task modpoll
2023-09-06 23:04:12,858 CRITICAL iomodbus.modbus_poll           Aborting iomodbus!

The problem was solved using pymodbus v3.5.0
https://github.com/pymodbus-dev/pymodbus/blob/dev/CHANGELOG.rst

  • Async retry (#1752)

There are some minor fixes in modpoll with (Endian.LITTLE, Endian.BIG)

Best regards,

Ommiting Addresses Prior to a Specified Coil

Config file:

device,relay1,1
poll,discrete_input,4,1,LE_LE
ref,relay1,4,bool8,r

Expected Output:

+--------+------+---------+---------------------------------------------------------+
| name | unit | address | value |
+--------+------+---------+---------------------------------------------------------+
| relay1 | None | 4 | [False] |
+--------+------+---------+---------------------------------------------------------+

Observed Output:

+--------+------+---------+---------------------------------------------------------+
| name | unit | address | value |
+--------+------+---------+---------------------------------------------------------+
| relay1 | None | 4 | [False, False, True, False, False, False, False, False] |
+--------+------+---------+---------------------------------------------------------+

Any change to the config either discrete_input or coil, etc results in a [NONE] value if I can manage to get it to filter out the rest of the addresses. The polling is working fine its just that there should be a way to obtain a single coil's state. The output above makes for MQTT messaging impossible as other relay states will ruin the succcess parameters.

Exceptions when calling local config file

On fresh install of Raspbian Bookworm and in a fresh venv, calling modpoll results in the following traceback:

$modpoll --tcp 192.168.1.50 --config $PWD/modfelix.csv

modpoll - A New Command Line Tool for Modbus

2024-01-26 12:20:24,938 | I | modpoll.main | No MQTT host specified, skip MQTT setup.
2024-01-26 12:20:24,938 | I | modpoll.modbus_task | Loading config from: /home/pi/modfelix.csv
Traceback (most recent call last):
  File "/home/pi/modpollviron/lib/python3.11/site-packages/modpoll/modbus_task.py", line 377, in load_config
    response = s.get(file)
               ^^^^^^^^^^^
  File "/home/pi/modpollviron/lib/python3.11/site-packages/requests/sessions.py", line 602, in get
    return self.request("GET", url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/modpollviron/lib/python3.11/site-packages/requests/sessions.py", line 575, in request
    prep = self.prepare_request(req)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/modpollviron/lib/python3.11/site-packages/requests/sessions.py", line 486, in prepare_request
    p.prepare(
  File "/home/pi/modpollviron/lib/python3.11/site-packages/requests/models.py", line 368, in prepare
    self.prepare_url(url, params)
  File "/home/pi/modpollviron/lib/python3.11/site-packages/requests/models.py", line 439, in prepare_url
    raise MissingSchema(
requests.exceptions.MissingSchema: Invalid URL '/home/pi/modfelix.csv': No scheme supplied. Perhaps you meant https:///home/pi/modfelix.csv?

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/modpollviron/bin/modpoll", line 8, in <module>
    sys.exit(app())
             ^^^^^
  File "/home/pi/modpollviron/lib/python3.11/site-packages/modpoll/main.py", line 63, in app
    if not modbus_setup(args, event_exit):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/modpollviron/lib/python3.11/site-packages/modpoll/modbus_task.py", line 398, in modbus_setup
    load_config(args.config)
  File "/home/pi/modpollviron/lib/python3.11/site-packages/modpoll/modbus_task.py", line 385, in load_config
    parse_config(csv_reader)
  File "/home/pi/modpollviron/lib/python3.11/site-packages/modpoll/modbus_task.py", line 291, in parse_config
    device_name = row[1]
                  ~~~^^^
IndexError: list index out of range


docker compose file example is missing

Hello,

Could you add a Docker compose file in your description?

which I would find good in the compose file:

  • volume for the config file
  • network host

Thank you in advance.

regards
Martin

Output should be rounded with multiplication factor

On using mopoll with Hager SM101C and apply factor the output should be rounded
Many thanks for you work. Very useful

config csv

device,sm101c,21,,,
poll,holding_register,50514,60,BE_BE

ref,U12,50514,uint32,r,V,0.01
ref,U23,50516,uint32,r,V,0.01
ref,U31,50518,uint32,r,V,0.01
ref,V1,50520,uint32,r,V,0.01
ref,V2,50522,uint32,r,V,0.01
ref,V3,50524,uint32,r,V,0.01

ref,Freq,50526,uint32,r,Hz,0.01

output

2023-01-13 15:56:14,905 | I | modpoll.modbus_task | Reading device:sm101c, FuncCode:3, Start_address:50514, Size:60... SUCCESS
===== references from device: sm101c =====
+----------------+------+---------+--------------------+
|      name      | unit | address |       value        |
+----------------+------+---------+--------------------+
|      U12       |  V   |  50514  |       237.35       |
|      U23       |  V   |  50516  |       410.38       |
|      U31       |  V   |  50518  |       236.18       |
|       V1       |  V   |  50520  |        0.0         |
|       V2       |  V   |  50522  | 237.73000000000002 |
|       V3       |  V   |  50524  | 236.64000000000001 |
|      Freq      |  Hz  |  50526  |        0.0         |
|       I1       |  A   |  50528  |        23.2        |
|       I2       |  A   |  50530  | 12.700000000000001 |
|       I3       |  A   |  50532  |        12.8        |
|       IN       |  A   |  50534  | 14.200000000000001 |

polling coils with 2 bits possible

Hello,

your examples show polling of coils with 8 or 16 bits (i.e. aligned to full bytes length):

poll,coil,1,16,BE_BE
ref,coil1-8,1,bool,rw,
ref,coil9-16,2,bool,rw,

Because our device only supports 2 bits coils, I tried polling only these 2 bits (instead of polling 8 bits), using this config lines:

poll,coil,20,2,BE_BE
ref,coil20,20,bool,rw,
ref,coil21,21,bool,rw,

Calling modpoll produces this error:

> modpoll --tcp 192.168.16.100 --config device.csv --rate 1 --interval 0.01 --timeout 0.2
modpoll - A New Command Line Tool for Modbus

2023-08-21 07:49:46,909 | I | modpoll.main | No MQTT host specified, skip MQTT setup.
2023-08-21 07:49:46,909 | I | modpoll.modbus_task | Loading config from: device.cfg
2023-08-21 07:49:46,912 | I | modpoll.modbus_task | Added new device mydevice
2023-08-21 07:49:46,912 | I | modpoll.modbus_task | Add poller (start_address=20, size=2) to device mydevice
2023-08-21 07:49:46,912 | W | modpoll.modbus_task | Reference coil20 failed to pass sanity check, ignoring it.
2023-08-21 07:49:46,913 | W | modpoll.modbus_task | Reference coil21 failed to pass sanity check, ignoring it.
2023-08-21 07:49:46,913 | I | modpoll.modbus_task | Add poller (start_address=10, size=1) to device mydevice
2023-08-21 07:49:46,913 | I | modpoll.main |  ====== modpoll polling at rate:1.0s, actual:1.0s ======
Traceback (most recent call last):
  File "c:\program files\python38\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\program files\python38\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "c:\users\...\.local\bin\modpoll.exe\__main__.py", line 7, in <module>
  File "C:\Users\...\.local\pipx\venvs\modpoll\lib\site-packages\modpoll\main.py", line 75, in app
    modbus_poll()
  File "C:\Users\...\.local\pipx\venvs\modpoll\lib\site-packages\modpoll\modbus_task.py", line 384, in modbus_poll
    p.poll()
  File "C:\Users\...\.local\pipx\venvs\modpoll\lib\site-packages\modpoll\modbus_task.py", line 157, in poll
    self.device.update_reference(ref)
UnboundLocalError: local variable 'ref' referenced before assignment
>modpoll --version
modpoll - A New Command Line Tool for Modbus
modpoll v0.5.4

>python --version
Python 3.8.5

>ver
Microsoft Windows [Version 10.0.19045.3324]

Attached Wireshark output MODBUS/TCP shows the response containing 2 bits coded into 1 byte, but modpoll cannot handle this.
Are there mistakes in config file (attached)? Did anyone try polling similar coils with single bits - not bytes? Do you have any examples to poll single bits (coils)?

Thanks in advance and best regards
Jan

2bit-coils
2bit-coils.zip
device.csv

Move to RS485 breaks implementation

A while back I added a config for the foxess inverter based on connecting to its ethernet port. In recent updates they've disabled the ethernet port on the inverter, so I have wired into the RS485 serial connection with an Elfin EW11 RS485 Modbus to WiFi.

The recommended test for the other modpoll works as follows:

./modpoll -m tcp -p 502 -a 247 -t 3 -0 -1 -c 16 -r 11000 192.168.0.188
modpoll 3.11 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright (c) 2002-2024 proconX Pty Ltd
Visit https://www.modbusdriver.com for Modbus libraries and tools.

Protocol configuration: MODBUS/TCP, FC4
Slave configuration...: address = 247, start reference = 11000 (PDU), count = 16
Communication.........: 192.168.0.188, port 502, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, input register table

-- Polling slave...
\[11000]: 1963
[11001]: 0
[11002]: 4
[11003]: 201
[11004]: 0
[11005]: 0
[11006]: 1561
[11007]: 0
[11008]: 0
[11009]: 2415
[11010]: 7
[11011]: -53
[11012]: -21
[11013]: 175
[11014]: 5002
[11015]: 0

But for the life of me I cannot get the python version working. Trying with a simple configuration file of:

device,foxess,1,,
poll,holding_register,11000,1,BE_BE
ref,pv1-voltage,11000,int16,rw,

I get:

python3 -m modpoll --tcp 192.168.0.188 --config a

modpoll - A New Command Line Tool for Modbus

2024-03-10 18:03:23,204 | I | modpoll.main | No MQTT host specified, skip MQTT setup.
2024-03-10 18:03:23,204 | I | modpoll.modbus_task | Loading config from: a
2024-03-10 18:03:23,206 | I | modpoll.modbus_task | Adding new device foxess
2024-03-10 18:03:23,207 | I | modpoll.modbus_task | Add poller (start_address=11000, size=1) to device foxess
2024-03-10 18:03:23,207 | I | modpoll.modbus_task | Polling 1 device(s)...
2024-03-10 18:03:23,208 | I | modpoll.main |  ====== modpoll polling at rate:10.0s, actual:10.0s ======
2024-03-10 18:03:26,263 | E | modpoll.modbus_task | Reading device:foxess, FuncCode:3, Start_address:11000, Size:1... ERROR

I've tried a lot of variations but can't get past this. Do you have any ideas for what's happening here? I'd love to contribute an updated config.

-Mark

struct.error: 'H' format requires 0 <= number <= 65535

Hello,

thanks for this great piece of code!

Unfortunately I have a small problem, when writing data to Modbus. The value is received, but when publishing to Modbus something goes wrong.

2023-02-27 15:05:41,676 | I | modpoll.mqtt_task | Receive message (modpoll/must-ph18-5548-plus/set): b'{"object_type": "holding_register","address": 101011,"value": 570}'
2023-02-27 15:05:48,077 | I | modpoll.modbus_task | Writing register(s): device=must-ph18-5548-plus, address=101011, value=570
Traceback (most recent call last):
  File "/usr/bin/modpoll", line 8, in <module>
    sys.exit(app())
  File "/usr/lib/python3.8/site-packages/modpoll/main.py", line 100, in app
    modbus_write_register(device_name, reg["address"], reg["value"])
  File "/usr/lib/python3.8/site-packages/modpoll/modbus_task.py", line 422, in modbus_write_register
    result = master.write_register(address, value, slave=d.devid)
  File "/usr/lib/python3.8/site-packages/pymodbus/client/mixin.py", line 148, in write_register
    return self.execute(
  File "/usr/lib/python3.8/site-packages/pymodbus/client/base.py", line 192, in execute
    return self.transaction.execute(request)
  File "/usr/lib/python3.8/site-packages/pymodbus/transaction.py", line 159, in execute
    response, last_exception = self._transact(
  File "/usr/lib/python3.8/site-packages/pymodbus/transaction.py", line 273, in _transact
    packet = self.client.framer.buildPacket(packet)
  File "/usr/lib/python3.8/site-packages/pymodbus/framer/rtu_framer.py", line 245, in buildPacket
    data = message.encode()
  File "/usr/lib/python3.8/site-packages/pymodbus/register_write_message.py", line 35, in encode
    packet = struct.pack(">H", self.address)
struct.error: 'H' format requires 0 <= number <= 65535

Can you help me with that?

Modbus TCP RTU Framer

I'm having issues reading a serial device that is plugged into a TCP Serial Server with Modpoll
I can get it to work with plain pymodbus in VSCode with the attached code, not sure if I'm missing an option, doing something wrong, or if this type of device doesn't work by default.

#Python

import time
import pymodbus
from pymodbus.client import ModbusBaseClient, ModbusTcpClient, ModbusSerialClient
from pymodbus.framer import ModbusFramer, ModbusRtuFramer

client = ModbusTcpClient('192.168.0.63', port=502, framer=ModbusRtuFramer)

client.connect()
print(f'Connected\n')
while True:
    data = client.read_input_registers(address=0, count=10, slave=40)
    
    voltage = data.registers[0] / 10.0 # [V]
    current = (data.registers[1] + (data.registers[2] << 16)) / 1000.0 # [A]
    power = (data.registers[3] + (data.registers[4] << 16)) / 10.0 # [W]
    energy = data.registers[5] + (data.registers[6] << 16) # [Wh]
    frequency = data.registers[7] / 10.0 # [Hz]
    powerFactor = data.registers[8] / 100.0
    alarm = data.registers[9]

    print('Voltage: ', voltage)
    print('Current: ', current)
    print('Power: ', power) # active power (V * I * power factor)
    print('Energy: ', energy)
    print('Frequency: ', frequency)
    print('Power factor: ', powerFactor)
    print(f'Alarm: {alarm}\n')
    time.sleep(1)

#CSV (I have tried both Input and Holding)

device,desk_ac_current,40,,
poll,input_register,0,10,BE_BE
ref,input_reg00,0,int16,r,V,.1

#Command
modpoll --tcp 192.168.0.63 --config desk_ac_current.csv

unable to run modpoll

Hi,

On Ubuntu 22.04 (Python 3.10) I'm trying to install and run modpoll. The installation works, but the command doesn't start:

ilko@msibox:~/work/modpoll$ pip install modpoll
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: modpoll in /usr/local/lib/python3.10/dist-packages (0.6.1)
Requirement already satisfied: requests<3.0.0,>=2.28.1 in /home/ilko/.local/lib/python3.10/site-packages (from modpoll) (2.31.0)
Requirement already satisfied: prettytable<4.0.0,>=3.6.0 in /home/ilko/.local/lib/python3.10/site-packages (from modpoll) (3.9.0)
Requirement already satisfied: paho-mqtt<2.0.0,>=1.6.1 in /home/ilko/.local/lib/python3.10/site-packages (from modpoll) (1.6.1)
Requirement already satisfied: pymodbus<4.0.0,>=3.5.2 in /home/ilko/.local/lib/python3.10/site-packages (from modpoll) (3.5.2)
Requirement already satisfied: wcwidth in /usr/lib/python3/dist-packages (from prettytable<4.0.0,>=3.6.0->modpoll) (0.2.5)
Requirement already satisfied: certifi>=2017.4.17 in /usr/lib/python3/dist-packages (from requests<3.0.0,>=2.28.1->modpoll) (2020.6.20)
Requirement already satisfied: idna<4,>=2.5 in /usr/lib/python3/dist-packages (from requests<3.0.0,>=2.28.1->modpoll) (3.3)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/lib/python3/dist-packages (from requests<3.0.0,>=2.28.1->modpoll) (1.26.5)
Requirement already satisfied: charset-normalizer<4,>=2 in /home/ilko/.local/lib/python3.10/site-packages (from requests<3.0.0,>=2.28.1->modpoll) (3.2.0)

ilko@msibox:~/work/modpoll$ modpoll
Traceback (most recent call last):
  File "/usr/local/bin/modpoll", line 5, in <module>
    from modpoll import app
ImportError: cannot import name 'app' from 'modpoll' (/usr/local/lib/python3.10/dist-packages/modpoll/__init__.py)

What is wrong?

Issue specifying <object_type>+<start_address>

Unless Im missing something, here is whats happening:
When preparing the config file, it appears that its pulling an offset in the modbus addresses from the object type, and adding the starting_address value to it. So, if you specify:

poll,holding_register,40001,10,BE_BE
ref,objectname,40001,uint16,r

It throws an error. It appears that it might be adding 40001 from the type=holding_register to the specified address (40001) to be polling at the wrong place.
If you specify:

poll,holding_register,1,10,BE_BE
ref,objectname,1,uint16,r

It pulls from 40001 (the first holding_register).

Problem:
This conflicts with the documentation: helloysd

Suggested Resolution:
Should either pull offset from object_type and be documented as such, or ignore type and only pull from specified start_address.
outputwith40001
configwith40001
configwith1
outputwith1

Uploading config files and screen shots to demonstrate.

pip install modpoll - dosn't work

Hello everyone,

I'm trying to install the program in the docker image, but that doesn't work.

pip install modpoll
shows the problem:
Could not find a version that satisfies the requirement modpoll (from versions: ) No matching distribution found for modpoll
Docker image:
FROM debian:stretch-slim

Do you now why the issue exists?

regards
Martin

pyserial missing in dockerimage

pyserial is missing in dockerimage, so no searial connection can be established.

pip list
Package            Version
------------------ --------
certifi            2024.2.2
charset-normalizer 3.3.2
idna               3.6
modpoll            0.7.0
paho-mqtt          1.6.1
pip                23.0.1
prettytable        3.9.0
pymodbus           3.6.4
requests           2.31.0
setuptools         57.5.0
urllib3            2.2.0
wcwidth            0.2.13
wheel              0.42.0
[notice] A new release of pip is available: 23.0.1 -> 24.0
[notice] To update, run: pip install --upgrade pip

How must the config file look like?

I use a modpoll program on Windows.

with modpoll -h i receive the following help information:

Usage: modpoll [OPTIONS] SERIALPORT|HOST [WRITEVALUES...]
Arguments:
SERIALPORT Serial port when using Modbus ASCII or Modbus RTU protocol
COM1, COM2 ... on Windows
/dev/ttyS0, /dev/ttyS1 ... on Linux
HOST Host name or dotted IP address when using MDBUS/TCP protocol
WRITEVALUES List of values to be written. If none specified (default) modpoll reads data.
General options:
-m ascii Modbus ASCII protocol
-m rtu Modbus RTU protocol (default if SERIALPORT contains \ or COM)
-m tcp MODBUS/TCP protocol (default otherwise)
-m udp MODBUS UDP
-m enc Encapsulated Modbus RTU over TCP
-a # Slave address (1-247 for serial, 0-255 for TCP, 1 is default)
-r # Start reference (1-65536, 100 is default)
-c # Number of values to read (1-125, 1 is default), optional for writing (use -c 1 to force FC5 or FC6)
-t 0 Discrete output (coil) data type
-t 1 Discrete input data type
-t 3 16-bit input register data type
-t 3:hex 16-bit input register data type with hex display
-t 3:int 32-bit integer data type in input register table
-t 3:mod 32-bit module 10000 data type in input register table
-t 3:float 32-bit float data type in input register table
-t 4 16-bit output (holding) register data type (default)
-t 4:hex 16-bit output (holding) register data type with hex display
-t 4:int 32-bit integer data type in output (holding) register table
-t 4:mod 32-bit module 10000 type in output (holding) register table
-t 4:float 32-bit float data type in output (holding) register table
-i Slave operates on big-endian 32-bit integers
-f Slave operates on big-endian 32-bit floats
-e Use Daniel/Enron single register 32-bit mode (implies -i and -f)
-0 First reference is 0 (PDU addressing) instead 1
-1 Poll only once only, otherwise every poll rate interval
-l # Poll rate in ms, (1000 is default)
-o # Time-out in seconds (0.01 - 10.0, 1.0 s is default)
Options for MODBUS/TCP, UDP and RTU over TCP:
-p # IP protocol port number (502 is default)
Options for Modbus ASCII and Modbus RTU:
-b # Baudrate (e.g. 9600, 19200, ...) (19200 is default)
-d # Databits (7 or 8 for ASCII protocol, 8 for RTU)
-s # Stopbits (1 or 2, 1 is default)
-p none No parity
-p even Even parity (default)
-p odd Odd parity
-4 # RS-485 mode, RTS on while transmitting and another # ms after

if i use the following command:

modpoll.exe -l 5000 -t 4 -p 502 -m enc -a 247 -r 769 -c 124 192.168.178.88

i receive data from the modbus device like following

Protocol configuration: Encapsulated RTU over TCP, FC3
Slave configuration...: address = 247, start reference = 769, count = 124
Communication.........: RS485-TO-ETH, port 502, t/o 1.00 s, poll rate 5000 ms
Data type.............: 16-bit register, output (holding) register table

-- Polling slave... (Ctrl-C to stop)
[769]: 3810
[770]: 3596
[771]: 4
[772]: 3
[773]: 2264
[774]: 2283
[775]: 2272
[776]: 14
[777]: 14
[778]: 16
[779]: 4999
[780]: 4999
[781]: 4999
[782]: 0
[783]: 1
[784]: 431
[785]: 0
[786]: 0
[787]: 4
[788]: 21263
[789]: 0
[790]: 5208
[791]: 909
[792]: 0
[793]: 0
[794]: 202
[795]: 0
[796]: 0
[797]: 5984
[798]: 2978
[799]: 0
[800]: 2
[801]: 1521
[802]: 0
[803]: 0
[804]: 0
[805]: 0
[806]: 0
[807]: 0
[808]: 0
[809]: 0
[810]: 0
[811]: 0
[812]: 0
[813]: 0
[814]: 0
[815]: 0
[816]: 0
[817]: 0
[818]: 0
[819]: 0
[820]: 0
[821]: 0
[822]: 0
[823]: 0
[824]: 0
[825]: 0
[826]: 0
[827]: 0
[828]: 5895
[829]: 2325
[830]: 8505
[831]: 154
[832]: 105
[833]: 0
[834]: 0
[835]: 0
[836]: 0
[837]: 0
[838]: 0
[839]: 0
[840]: 0
[841]: 0
[842]: 0
[843]: 0
[844]: 0
[845]: 0
[846]: 0
[847]: 0
[848]: 0
[849]: 0
[850]: 0
[851]: 0
[852]: 0
[853]: 13
[854]: 0
[855]: 0
[856]: 0
[857]: 0
[858]: 0
[859]: 0
[860]: 0
[861]: 6
[862]: 0
[863]: 5
[864]: 0
[865]: 4
[866]: 0
[867]: 0
[868]: 0
[869]: 0
[870]: 0
[871]: 0
[872]: 0
[873]: 0
[874]: 0
[875]: 0
[876]: 0
[877]: 0
[878]: 0
[879]: 0
[880]: 0
[881]: -1
[882]: 0
[883]: 0
[884]: 0
[885]: 0
[886]: 25000
[887]: 0
[888]: 18263
[889]: 12853
[890]: 19245
[891]: 19796
[892]: 8224
-- Polling slave... (Ctrl-C to stop)

can someone explain me how the config file of modpoll must look so that I get data?

Add poll interval/rate for every single poll

Hello,

would it be possible to add a polling interval/rate for every single poll in the CSV?

The reason is that I have some data that is rarely changing (e.g. every hour) and other data that is chaning every second. To reduce load I like to be able to add a polling interval/rate for a specific poll by adding the interval/rate in seconds to the end of the CSV line.

If nothing specified in the CSV, then the default value (specified by -r or --rate) is used. This makes the script also backward compatible without the user having to change someting.

Example

Default rate: 1.2 s
Rate for poll,holding_register,10103 and ref,charger-rated-current,15216 is 3600 s

modpoll \
    --config /data/etc/must-solar-inverter/modpoll-registers.csv \
    --rate 1.200 \
    --interval 0.000 \
    --timeout 0.150 \
    --rtu /dev/ttyUSB0 \
    --rtu-baud 19200 \
    --rtu-parity none \
    --mqtt-host 127.0.0.1 \
    --mqtt-port 1883 \
    --mqtt-clientid modbus \
    --loglevel WARNING \
    --delay 0
device,must-ph18-5548-plus,4
poll,holding_register,10103,9,BE_BE,3600
ref,charger-voltage-float,10103,int16,rw,,0.1
...
ref,battery-ah,10111,int16,rw
poll,holding_register,15201,21,BE_BE
ref,charger-work-state,15201,int16,r
...
ref,charger-rated-current,15216,int16,r,,0.1
poll,holding_register,20101,44,BE_BE,3600
ref,inverter-offgrid-work,20101,int16,rw
...
ref,solar-power-balance,20144,int16,rw
poll,holding_register,25201,79,BE_BE
ref,inverter-work-state,25201,int16,r
...

Please let me know, what you think.

writing registers with modpoll - how to do....? ...reading works fine !

Hello together,
i use modpoll many time to read chinese inverters. ...works fine....
Next step - to give parameters to the inverters.
i understand csv-file....but i receive error messages from modpoll....
"UnboundLocalError: local variable 'ref' referenced before assignment"
The csv is:

device,wr1,1,,
poll holding_register, 300, 50, BE_BE
ref,cmax,332,Uint16,w

...it should write in Register 332 what on mqtt-broker is.... !?

someone have a idea....?
Thanks......

Consider add device 'IP ADDR' and 'port' to .csv file

I think it would a benefit to add ip addr and port to device line in config file (.csv)

example: sm101.csv

device,QE2.2,21,192.168.50.68,502
poll,holding_register,50514,60,BE_BE

ref,U12,50514,uint32,r,V,0.01
ref,U23,50516,uint32,r,V,0.01
ref,U31,50518,uint32,r,V,0.01

ref,V1,50520,uint32,r,V,0.01
ref,V2,50522,uint32,r,V,0.01
ref,V3,50524,uint32,r,V,0.01

This will allow to simple call $ modpoll -f sm101.csv. The main objective is to record on the .csv file the device origin for easy polling multiple devices.
Many thanks again
cf

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.