modpoll2mqtt 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-2026 Ying Shaodong
4
+ Copyright (c) 2026 yoch
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.1
2
+ Name: modpoll2mqtt
3
+ Version: 2.0.0
4
+ Summary: Modbus to MQTT gateway — fork of modpoll
5
+ Home-page: https://github.com/yoch/modpoll2mqtt
6
+ License: MIT
7
+ Author: yoch
8
+ Author-email: yoch.melka@gmail.com
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Home Automation
21
+ Classifier: Topic :: System :: Networking
22
+ Provides-Extra: serial
23
+ Requires-Dist: paho-mqtt (>=2.1.0,<3.0.0)
24
+ Requires-Dist: prettytable (>=3.9.0,<4.0.0)
25
+ Requires-Dist: pymodbus (>=3.10,<4.0)
26
+ Requires-Dist: pyserial (>=3.5,<4.0) ; extra == "serial"
27
+ Requires-Dist: requests (>=2.32.5,<3.0.0)
28
+ Project-URL: Documentation, https://yoch.github.io/modpoll2mqtt
29
+ Project-URL: Repository, https://github.com/yoch/modpoll2mqtt
30
+ Description-Content-Type: text/markdown
31
+
32
+ # modpoll2mqtt — Modbus to MQTT Gateway
33
+
34
+ [![Release](https://img.shields.io/github/v/release/yoch/modpoll2mqtt)](https://github.com/yoch/modpoll2mqtt/releases)
35
+ [![Build status](https://img.shields.io/github/actions/workflow/status/yoch/modpoll2mqtt/main.yml?branch=main)](https://github.com/yoch/modpoll2mqtt/actions/workflows/main.yml?query=branch%3Amain)
36
+ [![License](https://img.shields.io/github/license/yoch/modpoll2mqtt)](https://github.com/yoch/modpoll2mqtt/blob/main/LICENSE)
37
+ [![Downloads](https://static.pepy.tech/badge/modpoll2mqtt/week)](https://pepy.tech/project/modpoll2mqtt)
38
+
39
+ > Documentation: [yoch.github.io/modpoll2mqtt](https://yoch.github.io/modpoll2mqtt)
40
+
41
+ **modpoll2mqtt** is a command-line Modbus-to-MQTT gateway. It polls Modbus devices (RTU, TCP, UDP) using CSV configuration files, publishes values to an MQTT broker, and accepts write commands by CSV reference name.
42
+
43
+ Install the PyPI package as `modpoll2mqtt`; the executable command remains `modpoll`.
44
+
45
+ Fork of [modpoll](https://github.com/gavinying/modpoll), with semantic MQTT writes by `ref` + `value` and CTA (air handling unit) examples.
46
+
47
+ ## Features
48
+
49
+ - Modbus RTU, TCP, and UDP (CSV configuration files)
50
+ - Local display of polled data (debug mode)
51
+ - MQTT publishing of references (configurable topics)
52
+ - MQTT writes by CSV reference name (`modpoll/<device>/set`)
53
+ - Local CSV export of polled data
54
+ - Bit-level access on registers and coils
55
+
56
+ ## Installation
57
+
58
+ Python 3.10+ required.
59
+
60
+ ```bash
61
+ pip install modpoll2mqtt
62
+ ```
63
+
64
+ Optional serial support (pyserial):
65
+
66
+ ```bash
67
+ pip install 'modpoll2mqtt[serial]'
68
+ ```
69
+
70
+ Upgrade:
71
+
72
+ ```bash
73
+ pip install -U modpoll2mqtt
74
+ ```
75
+
76
+ On Windows, [pipx](https://pypa.github.io/pipx/installation/) is recommended:
77
+
78
+ ```powershell
79
+ pipx install modpoll2mqtt
80
+ ```
81
+
82
+ ## Quickstart
83
+
84
+ Single poll of a Modbus TCP device (replace the IP address with yours):
85
+
86
+ ```bash
87
+ modpoll --once \
88
+ --tcp 192.168.1.10 \
89
+ --config examples/modsim.csv
90
+ ```
91
+
92
+ Publish to an MQTT broker:
93
+
94
+ ```bash
95
+ modpoll \
96
+ --tcp 192.168.1.10 \
97
+ --mqtt-host broker.emqx.io \
98
+ --config examples/modsim.csv
99
+ ```
100
+
101
+ Data is published to `modpoll/<device_name>/data` by default.
102
+
103
+ ### MQTT write by reference
104
+
105
+ Once connected to the broker, `modpoll` subscribes to `modpoll/+/set`. Publish to `modpoll/<device>/set`:
106
+
107
+ ```json
108
+ {
109
+ "ref": "PID_V3V_EC_Consigne_reprise",
110
+ "value": 21.5
111
+ }
112
+ ```
113
+
114
+ Example with [`examples/CTA/cta_conf_restaurant.csv`](examples/CTA/cta_conf_restaurant.csv): an `int16` reference with scale `0.1` accepts `21.5` as input; the raw register value `215` is written.
115
+
116
+ **Migration from modpoll 1.6.x:** the low-level format (`object_type`, `address`, `value`) is no longer supported.
117
+
118
+ ### Configuration pitfalls
119
+
120
+ - On **coil** or **discrete_input** pollers, use `bool` with the **absolute Modbus coil address** for a single boolean.
121
+ - `bool8` / `bool16`: legacy grouped reads (group index, not a direct coil address).
122
+ - On **holding_register** or **input_register**, use `bool` with `address:bit` (0–15), e.g. `40019:15,bool`.
123
+ - `<endian>` must be `BE_BE`, `LE_BE`, `LE_LE`, or `BE_LE` only.
124
+ - `--autoremove` disables a poller after 3 consecutive Modbus failures.
125
+
126
+ ## Examples
127
+
128
+ ```bash
129
+ # Modbus TCP
130
+ modpoll --tcp 192.168.1.10 --config examples/modsim.csv
131
+
132
+ # Modbus serial
133
+ modpoll --serial /dev/ttyUSB0 --serial-baud 9600 --config contrib/eniwise/scpms6.csv
134
+
135
+ # MQTT + CSV export
136
+ modpoll --tcp 192.168.1.10 --mqtt-host localhost --export data.csv --config examples/modsim.csv
137
+
138
+ # Multiple config files
139
+ modpoll --tcp 192.168.1.10 --config examples/modsim.csv examples/modsim2.csv
140
+
141
+ # CTA (building automation example)
142
+ modpoll --tcp 192.168.1.20 --mqtt-host localhost --config examples/CTA/cta_conf_restaurant.csv
143
+ ```
144
+
145
+ See [`examples/`](examples/) and [`contrib/`](contrib/) for more device configurations.
146
+
147
+ ## Credits
148
+
149
+ This project builds on:
150
+
151
+ - [modpoll](https://github.com/gavinying/modpoll) — Ying Shaodong (MIT)
152
+ - [modbus2mqtt](https://github.com/owagner/modbus2mqtt) — Oliver Wagner (MIT)
153
+ - [spicierModbus2mqtt](https://github.com/mbs38/spicierModbus2mqtt) — Max Brueggemann (MIT)
154
+
155
+ ## License
156
+
157
+ MIT — see [LICENSE](LICENSE).
158
+
@@ -0,0 +1,126 @@
1
+ # modpoll2mqtt — Modbus to MQTT Gateway
2
+
3
+ [![Release](https://img.shields.io/github/v/release/yoch/modpoll2mqtt)](https://github.com/yoch/modpoll2mqtt/releases)
4
+ [![Build status](https://img.shields.io/github/actions/workflow/status/yoch/modpoll2mqtt/main.yml?branch=main)](https://github.com/yoch/modpoll2mqtt/actions/workflows/main.yml?query=branch%3Amain)
5
+ [![License](https://img.shields.io/github/license/yoch/modpoll2mqtt)](https://github.com/yoch/modpoll2mqtt/blob/main/LICENSE)
6
+ [![Downloads](https://static.pepy.tech/badge/modpoll2mqtt/week)](https://pepy.tech/project/modpoll2mqtt)
7
+
8
+ > Documentation: [yoch.github.io/modpoll2mqtt](https://yoch.github.io/modpoll2mqtt)
9
+
10
+ **modpoll2mqtt** is a command-line Modbus-to-MQTT gateway. It polls Modbus devices (RTU, TCP, UDP) using CSV configuration files, publishes values to an MQTT broker, and accepts write commands by CSV reference name.
11
+
12
+ Install the PyPI package as `modpoll2mqtt`; the executable command remains `modpoll`.
13
+
14
+ Fork of [modpoll](https://github.com/gavinying/modpoll), with semantic MQTT writes by `ref` + `value` and CTA (air handling unit) examples.
15
+
16
+ ## Features
17
+
18
+ - Modbus RTU, TCP, and UDP (CSV configuration files)
19
+ - Local display of polled data (debug mode)
20
+ - MQTT publishing of references (configurable topics)
21
+ - MQTT writes by CSV reference name (`modpoll/<device>/set`)
22
+ - Local CSV export of polled data
23
+ - Bit-level access on registers and coils
24
+
25
+ ## Installation
26
+
27
+ Python 3.10+ required.
28
+
29
+ ```bash
30
+ pip install modpoll2mqtt
31
+ ```
32
+
33
+ Optional serial support (pyserial):
34
+
35
+ ```bash
36
+ pip install 'modpoll2mqtt[serial]'
37
+ ```
38
+
39
+ Upgrade:
40
+
41
+ ```bash
42
+ pip install -U modpoll2mqtt
43
+ ```
44
+
45
+ On Windows, [pipx](https://pypa.github.io/pipx/installation/) is recommended:
46
+
47
+ ```powershell
48
+ pipx install modpoll2mqtt
49
+ ```
50
+
51
+ ## Quickstart
52
+
53
+ Single poll of a Modbus TCP device (replace the IP address with yours):
54
+
55
+ ```bash
56
+ modpoll --once \
57
+ --tcp 192.168.1.10 \
58
+ --config examples/modsim.csv
59
+ ```
60
+
61
+ Publish to an MQTT broker:
62
+
63
+ ```bash
64
+ modpoll \
65
+ --tcp 192.168.1.10 \
66
+ --mqtt-host broker.emqx.io \
67
+ --config examples/modsim.csv
68
+ ```
69
+
70
+ Data is published to `modpoll/<device_name>/data` by default.
71
+
72
+ ### MQTT write by reference
73
+
74
+ Once connected to the broker, `modpoll` subscribes to `modpoll/+/set`. Publish to `modpoll/<device>/set`:
75
+
76
+ ```json
77
+ {
78
+ "ref": "PID_V3V_EC_Consigne_reprise",
79
+ "value": 21.5
80
+ }
81
+ ```
82
+
83
+ Example with [`examples/CTA/cta_conf_restaurant.csv`](examples/CTA/cta_conf_restaurant.csv): an `int16` reference with scale `0.1` accepts `21.5` as input; the raw register value `215` is written.
84
+
85
+ **Migration from modpoll 1.6.x:** the low-level format (`object_type`, `address`, `value`) is no longer supported.
86
+
87
+ ### Configuration pitfalls
88
+
89
+ - On **coil** or **discrete_input** pollers, use `bool` with the **absolute Modbus coil address** for a single boolean.
90
+ - `bool8` / `bool16`: legacy grouped reads (group index, not a direct coil address).
91
+ - On **holding_register** or **input_register**, use `bool` with `address:bit` (0–15), e.g. `40019:15,bool`.
92
+ - `<endian>` must be `BE_BE`, `LE_BE`, `LE_LE`, or `BE_LE` only.
93
+ - `--autoremove` disables a poller after 3 consecutive Modbus failures.
94
+
95
+ ## Examples
96
+
97
+ ```bash
98
+ # Modbus TCP
99
+ modpoll --tcp 192.168.1.10 --config examples/modsim.csv
100
+
101
+ # Modbus serial
102
+ modpoll --serial /dev/ttyUSB0 --serial-baud 9600 --config contrib/eniwise/scpms6.csv
103
+
104
+ # MQTT + CSV export
105
+ modpoll --tcp 192.168.1.10 --mqtt-host localhost --export data.csv --config examples/modsim.csv
106
+
107
+ # Multiple config files
108
+ modpoll --tcp 192.168.1.10 --config examples/modsim.csv examples/modsim2.csv
109
+
110
+ # CTA (building automation example)
111
+ modpoll --tcp 192.168.1.20 --mqtt-host localhost --config examples/CTA/cta_conf_restaurant.csv
112
+ ```
113
+
114
+ See [`examples/`](examples/) and [`contrib/`](contrib/) for more device configurations.
115
+
116
+ ## Credits
117
+
118
+ This project builds on:
119
+
120
+ - [modpoll](https://github.com/gavinying/modpoll) — Ying Shaodong (MIT)
121
+ - [modbus2mqtt](https://github.com/owagner/modbus2mqtt) — Oliver Wagner (MIT)
122
+ - [spicierModbus2mqtt](https://github.com/mbs38/spicierModbus2mqtt) — Max Brueggemann (MIT)
123
+
124
+ ## License
125
+
126
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,6 @@
1
+ import importlib.metadata as importlib_metadata
2
+
3
+ try:
4
+ __version__ = importlib_metadata.version("modpoll2mqtt")
5
+ except importlib_metadata.PackageNotFoundError:
6
+ __version__ = "0.0.0"
@@ -0,0 +1,3 @@
1
+ from .main import app
2
+
3
+ app()
@@ -0,0 +1,209 @@
1
+ import argparse
2
+
3
+ from . import __version__
4
+
5
+ _CSV_DELIMITER_CHOICES = ("comma", "tab")
6
+
7
+
8
+ def get_parser():
9
+ parser = argparse.ArgumentParser(
10
+ description=f"modpoll2mqtt v{__version__} - Modbus to MQTT gateway"
11
+ )
12
+ parser.add_argument(
13
+ "-v",
14
+ "--version",
15
+ action="version",
16
+ version=f"v{__version__}",
17
+ )
18
+ parser.add_argument(
19
+ "-f",
20
+ "--config",
21
+ required=True,
22
+ help="A local path or URL of Modbus configuration file. Required!",
23
+ nargs="+",
24
+ )
25
+ parser.add_argument(
26
+ "--csv-delimiter",
27
+ default="comma",
28
+ choices=_CSV_DELIMITER_CHOICES,
29
+ help=(
30
+ "Column delimiter code for Modbus config files "
31
+ f"({', '.join(_CSV_DELIMITER_CHOICES)}). Defaults to comma"
32
+ ),
33
+ )
34
+ parser.add_argument(
35
+ "-d",
36
+ "--daemon",
37
+ action="store_true",
38
+ help="Run in daemon mode without printing result",
39
+ )
40
+ parser.add_argument(
41
+ "-r",
42
+ "--rate",
43
+ type=float,
44
+ default=10.0,
45
+ help="The sampling rate (s) to poll modbus device, Defaults to 10.0",
46
+ )
47
+ parser.add_argument(
48
+ "-1", "--once", action="store_true", help="Only run polling at one time"
49
+ )
50
+ parser.add_argument(
51
+ "--interval",
52
+ type=float,
53
+ default=0.5,
54
+ help="The time interval in seconds between two polling, Defaults to 0.5",
55
+ )
56
+ parser.add_argument(
57
+ "--tcp", help="Act as a Modbus TCP master, connecting to host TCP"
58
+ )
59
+ parser.add_argument(
60
+ "--tcp-port", type=int, default=502, help="Port for MODBUS TCP. Defaults to 502"
61
+ )
62
+ parser.add_argument(
63
+ "--udp", help="Act as a Modbus UDP master, connecting to host UDP"
64
+ )
65
+ parser.add_argument(
66
+ "--udp-port", type=int, default=502, help="Port for MODBUS UDP. Defaults to 502"
67
+ )
68
+ parser.add_argument(
69
+ "--serial",
70
+ "--rtu",
71
+ dest="serial",
72
+ help="pyserial URL (or port name) for serial transport (alias: --rtu)",
73
+ )
74
+ parser.add_argument(
75
+ "--serial-baud",
76
+ "--rtu-baud",
77
+ dest="serial_baud",
78
+ type=int,
79
+ default=9600,
80
+ help="Baud rate for serial port. Defaults to 9600",
81
+ )
82
+ parser.add_argument(
83
+ "--serial-parity",
84
+ "--rtu-parity",
85
+ dest="serial_parity",
86
+ choices=["none", "odd", "even"],
87
+ default="none",
88
+ help="Parity for serial port. Defaults to none",
89
+ )
90
+ parser.add_argument(
91
+ "--timeout",
92
+ type=float,
93
+ default=3.0,
94
+ help="Response time-out seconds for MODBUS devices, Defaults to 3.0",
95
+ )
96
+ parser.add_argument(
97
+ "-o",
98
+ "--export",
99
+ default=None,
100
+ help="The file name to export references/registers",
101
+ )
102
+ parser.add_argument(
103
+ "--mqtt-version",
104
+ choices=["3.1.1", "5.0"],
105
+ default="3.1.1",
106
+ help="MQTT version. Defaults to MQTT v3.1.1",
107
+ )
108
+ parser.add_argument(
109
+ "--mqtt-host",
110
+ default=None,
111
+ help="MQTT server address. Skip MQTT setup if not specified",
112
+ )
113
+ parser.add_argument(
114
+ "--mqtt-port",
115
+ type=int,
116
+ default=1883,
117
+ help="1883 for non-TLS or 8883 for TLS, Defaults to 1883",
118
+ )
119
+ parser.add_argument(
120
+ "--mqtt-clientid",
121
+ default=None,
122
+ help="MQTT client name, If qos > 0, set unique name for multiple clients",
123
+ )
124
+ parser.add_argument(
125
+ "--mqtt-publish-topic-pattern",
126
+ default="modpoll/{{device_name}}/data",
127
+ help='Topic pattern for MQTT publish. Use {{device_name}} as placeholder for the device names in Modbus config. Defaults to "modpoll/{{device_name}}/data"',
128
+ )
129
+ parser.add_argument(
130
+ "--mqtt-subscribe-topic-pattern",
131
+ default="modpoll/+/set",
132
+ help='Topic pattern for MQTT write commands. Use + as placeholder for device name. Defaults to "modpoll/+/set"',
133
+ )
134
+ parser.add_argument(
135
+ "--mqtt-diagnostics-topic-pattern",
136
+ default="modpoll/{{device_name}}/diagnostics",
137
+ help="Topic pattern for MQTT diagnostics. Use {{device_name}} as placeholder for the device names in Modbus config. Defaults to modpoll/{{device_name}}/diagnostics",
138
+ )
139
+ parser.add_argument(
140
+ "--mqtt-qos",
141
+ choices=[0, 1, 2],
142
+ type=int,
143
+ default=0,
144
+ help="MQTT QoS value. Defaults to 0",
145
+ )
146
+ parser.add_argument(
147
+ "--mqtt-rx-queue-size",
148
+ type=int,
149
+ default=1000,
150
+ metavar="N",
151
+ help="Max MQTT subscribe messages buffered between polls (default: 1000)",
152
+ )
153
+ parser.add_argument(
154
+ "--mqtt-user", default=None, help="Username for authentication (optional)"
155
+ )
156
+ parser.add_argument(
157
+ "--mqtt-pass", default=None, help="Password for authentication (optional)"
158
+ )
159
+ parser.add_argument("--mqtt-use-tls", action="store_true", help="Use TLS")
160
+ parser.add_argument(
161
+ "--mqtt-insecure",
162
+ action="store_true",
163
+ help="Use TLS without providing certificates",
164
+ )
165
+ parser.add_argument("--mqtt-cacerts", default=None, help="Path to ca keychain")
166
+ parser.add_argument(
167
+ "--mqtt-tls-version",
168
+ choices=["tlsv1.2", "tlsv1.1", "tlsv1"],
169
+ default="tlsv1.2",
170
+ help="TLS protocol version, can be one of tlsv1.2 tlsv1.1 or tlsv1",
171
+ )
172
+ parser.add_argument(
173
+ "--mqtt-single",
174
+ action="store_true",
175
+ help="Publish each value in a single topic. If not specified, groups all values in one topic.",
176
+ )
177
+ parser.add_argument(
178
+ "--diagnostics-rate",
179
+ type=float,
180
+ default=0,
181
+ help="Time in seconds as publishing period for each device diagnostics",
182
+ )
183
+ parser.add_argument(
184
+ "--autoremove",
185
+ action="store_true",
186
+ help="Automatically remove poller if modbus communication has failed 3 times.",
187
+ )
188
+ parser.add_argument(
189
+ "--loglevel",
190
+ choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
191
+ default="INFO",
192
+ help="Set log level, Defaults to INFO",
193
+ )
194
+ parser.add_argument(
195
+ "--timestamp", action="store_true", help="Add timestamp to the result"
196
+ )
197
+ parser.add_argument(
198
+ "--delay",
199
+ type=int,
200
+ default=0,
201
+ help="Time to delay sending first request in seconds after connecting. Default to 0",
202
+ )
203
+ parser.add_argument(
204
+ "--framer",
205
+ default="default",
206
+ choices=["default", "ascii", "rtu", "socket"],
207
+ help="The type of framer for Modbus messages. Serial supports ascii/rtu; TCP/UDP use socket.",
208
+ )
209
+ return parser