{"id":46535271,"url":"https://github.com/gavinying/modpoll","last_synced_at":"2026-03-06T23:32:35.166Z","repository":{"id":43772546,"uuid":"409925688","full_name":"gavinying/modpoll","owner":"gavinying","description":"A New Command-line Tool for Modbus and MQTT","archived":false,"fork":false,"pushed_at":"2025-12-06T11:06:42.000Z","size":16499,"stargazers_count":137,"open_issues_count":4,"forks_count":28,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-12-09T19:32:12.596Z","etag":null,"topics":["docker","gateway","iiot","iot","modbus","modpoll","mqtt","python"],"latest_commit_sha":null,"homepage":"https://gavinying.github.io/modpoll","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gavinying.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-24T10:36:53.000Z","updated_at":"2025-12-06T11:05:19.000Z","dependencies_parsed_at":"2024-03-05T14:54:50.119Z","dependency_job_id":"8f8fe1cc-e1e0-448c-92b9-9f6f9e409fd5","html_url":"https://github.com/gavinying/modpoll","commit_stats":{"total_commits":119,"total_committers":4,"mean_commits":29.75,"dds":0.04201680672268904,"last_synced_commit":"0217fa8d2a2e3a76280297dcd05a85594081136c"},"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"purl":"pkg:github/gavinying/modpoll","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinying%2Fmodpoll","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinying%2Fmodpoll/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinying%2Fmodpoll/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinying%2Fmodpoll/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gavinying","download_url":"https://codeload.github.com/gavinying/modpoll/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinying%2Fmodpoll/sbom","scorecard":{"id":420042,"data":{"date":"2025-08-11","repo":{"name":"github.com/gavinying/modpoll","commit":"ecee03e1ca3e6848e17691f25ac363523a2181b0"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Code-Review","score":1,"reason":"Found 3/26 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/main.yml:27","Info: jobLevel 'contents' permission set to 'read': .github/workflows/main.yml:54","Info: jobLevel 'contents' permission set to 'read': .github/workflows/main.yml:13","Warn: no topLevel permission defined: .github/workflows/main.yml:1","Warn: no topLevel permission defined: .github/workflows/on-release-main.yml:1","Warn: topLevel 'contents' permission set to 'write': .github/workflows/release-please.yml:8","Warn: no topLevel permission defined: .github/workflows/validate.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/on-release-main.yml:33"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:58: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/on-release-main.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/on-release-main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/on-release-main.yml:38: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/on-release-main.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/on-release-main.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/on-release-main.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/on-release-main.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/on-release-main.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/on-release-main.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/on-release-main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/on-release-main.yml:80: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/on-release-main.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/on-release-main.yml:92: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/on-release-main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release-please.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/release-please.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-please.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/release-please.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/validate.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/gavinying/modpoll/validate.yml/master?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:4: pin your Docker image by updating python:3.12-slim-bookworm to python:3.12-slim-bookworm@sha256:42cf2422587a3dac0e0a3674a4d86f01570d5d7260588f3845f51e6176d8134b","Warn: pipCommand not pinned by hash: Dockerfile:9","Warn: pipCommand not pinned by hash: .github/workflows/main.yml:43","Warn: pipCommand not pinned by hash: .github/workflows/main.yml:44","Info:   0 out of   7 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   6 third-party GitHubAction dependencies pinned","Info:   0 out of   1 containerImage dependencies pinned","Info:   0 out of   3 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Vulnerabilities","score":1,"reason":"9 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-cpwx-vrp4-4pq7","Warn: Project is vulnerable to: GHSA-gmj6-6f8f-6699","Warn: Project is vulnerable to: GHSA-q2x7-8rv6-6q7h","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: GHSA-7cx3-6m66-7c5m","Warn: Project is vulnerable to: GHSA-8w49-h785-mj3c","Warn: Project is vulnerable to: GHSA-48p4-8xcf-vxj5","Warn: Project is vulnerable to: GHSA-pq67-6m6q-mj2v"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-19T00:58:07.230Z","repository_id":43772546,"created_at":"2025-08-19T00:58:07.230Z","updated_at":"2025-08-19T00:58:07.230Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30203353,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T19:07:06.838Z","status":"ssl_error","status_checked_at":"2026-03-06T18:57:34.882Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","gateway","iiot","iot","modbus","modpoll","mqtt","python"],"created_at":"2026-03-06T23:32:34.484Z","updated_at":"2026-03-06T23:32:35.046Z","avatar_url":"https://github.com/gavinying.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Modpoll - A New Command-line Tool for Modbus and MQTT\n\n[![Release](https://img.shields.io/github/v/release/gavinying/modpoll)](https://img.shields.io/github/v/release/gavinying/modpoll)\n[![Build status](https://img.shields.io/github/actions/workflow/status/gavinying/modpoll/main.yml?branch=main)](https://github.com/gavinying/modpoll/actions/workflows/main.yml?query=branch%3Amain)\n[![License](https://img.shields.io/github/license/gavinying/modpoll)](https://img.shields.io/github/license/gavinying/modpoll)\n[![Downloads](https://static.pepy.tech/badge/modpoll/week)](https://pepy.tech/project/modpoll)\n\n\u003e 📢 **Announcement:** Since the release of v1.3.0, our official dockerhub namespace has been changed to `topmaker`, you can pull the latest images from [topmaker/modpoll](https://hub.docker.com/repository/docker/topmaker/modpoll) at dockerhub.\n\n\u003e Learn more about *modpoll* usage at [documentation](https://gavinying.github.io/modpoll) site.\n\n## Motivation\n\nThe idea for creating this tool originated from my need to efficiently check new devices during site surveys. These surveys are often time-constrained and space-limited, with on-site work adding to the pressure. In such situations, a portable Swiss Army knife toolkit becomes a valuable companion.\n\nThis tool can be easily deployed on a Raspberry Pi or similar embedded devices, polling data from a Modbus network or connected devices. Users can choose to log the data locally or publish it to an MQTT broker for further troubleshooting.\n\nThe MQTT broker can be set up either on the same Raspberry Pi or in the cloud. Once data is successfully published, users can subscribe to the relevant MQTT topics and conveniently view the data on their smartphones.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/modpoll-usage.png\"\u003e\n\u003c/p\u003e\n\nMoreover, you can also run this tool continuously on a server as a Modbus-MQTT gateway, i.e. polling from local Modbus devices and forwarding data to a centralized cloud service.\n\nIn fact, *modpoll* helps to bridge between the traditional field-bus world and the new IoT world.\n\n\u003e 💡 **Tips:** This tool is designed to be a standalone executable application, which works out-of-the-box on Linux/macOS/Windows. If you are looking for a Modbus python library, please consider the following great open-source projects, [pymodbus](https://github.com/riptideio/pymodbus) or [minimalmodbus](https://github.com/pyhys/minimalmodbus)\n\n\n## Feature\n\n- Support Modbus RTU/TCP/UDP devices\n- Show polling data for local debugging, like a typical modpoll tool\n- Publish polling data to MQTT broker for remote debugging, especially on smart phone\n- Export polling data to local storage for further investigation\n- Provide docker solution for continuous data polling use case\n\n\n## Installation\n\nThis tool tested on Python 3.10+ (Ubuntu 22.04+ or equivalent), the package is available in the [Python Package Index](https://pypi.org/), users can easily install it using `pip` or `pipx`. Ubuntu 20.04 and Python 3.8 are no longer supported.\n\n### Using PIP\n\nInstall *modpoll* using the following command,\n\n```bash\npip install modpoll\n```\n\nOptionally, [pyserial](https://pyserial.readthedocs.io/) library can be installed for Modbus-RTU communication,\n\n```bash\npip install 'modpoll[serial]'\n```\n\nUpgrade the tool via the following command,\n\n```bash\npip install -U modpoll\n```\n\n### On Windows\n\nIt is recommended to use `pipx` for installing *modpoll* on Windows, refer to [here](https://pypa.github.io/pipx/installation/) for more information about `pipx`.\n\nOnce `pipx` installed, you can run the following command in a Command Prompt terminal.\n\n```PowerShell\npipx install modpoll\n```\n\nUpgrade the tool via the following command,\n\n```PowerShell\npipx upgrade modpoll\n```\n\n## Quickstart\n\n*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.\n\nLet's start exploring *modpoll* with *modsim* device, run the following command to get a first glimpse,\n\n```bash\nmodpoll --once \\\n  --tcp modsim.topmaker.net \\\n  --config https://raw.githubusercontent.com/gavinying/modpoll/main/examples/modsim.csv\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/screenshot-modpoll.png\"\u003e\n\u003c/p\u003e\n\n\u003e the modsim code is also available [here](https://github.com/gavinying/modsim)\n\n### Modbus ASCII and framers\n\n- Serial transports: use `--serial PORT --framer ascii` (alias: `--rtu` still accepted); pyserial URLs such as `socket://host:port` and `rfc2217://host:port` work for serial-over-TCP tunnels.\n- Serial supports framers `ascii` and `rtu` (pymodbus defaults to RTU if `--framer default`). Binary framer is no longer supported in pymodbus 3.9+.\n\n### Prepare Modbus configure file\n\nThe reason we can magically poll data from the online device *modsim* is because we have already provided the [Modbus configure file](https://raw.githubusercontent.com/gavinying/modpoll/main/examples/modsim.csv) for *modsim* device as following,\n\n```CSV\ndevice,modsim01,1,,\npoll,coil,0,16,BE_BE\nref,coil01-08,0,bool8,rw\nref,coil09-16,1,bool8,rw\npoll,discrete_input,10000,16,BE_BE\nref,di01-08,10000,bool8,rw\nref,di09-16,10001,bool8,rw\npoll,input_register,30000,20,BE_BE\nref,input_reg01,30000,uint16,rw\nref,input_reg02,30001,uint16,rw\nref,input_reg03,30002,uint16,rw\nref,input_reg04,30003,uint16,rw\nref,input_reg05,30004,int16,rw\nref,input_reg06,30005,int16,rw\nref,input_reg07,30006,int16,rw\nref,input_reg08,30007,int16,rw\nref,input_reg09,30008,uint32,rw\nref,input_reg10,30010,uint32,rw\nref,input_reg11,30012,int32,rw\nref,input_reg12,30014,int32,rw\nref,input_reg13,30016,float32,rw\nref,input_reg14,30018,float32,rw\npoll,holding_register,40000,44,BE_BE\nref,holding_reg01,40000,uint16,rw\nref,holding_reg02,40001,uint16,rw\nref,holding_reg03,40002,uint16,rw\nref,holding_reg04,40003,uint16,rw\nref,holding_reg05,40004,int16,rw\nref,holding_reg06,40005,int16,rw\nref,holding_reg07,40006,int16,rw\nref,holding_reg08,40007,int16,rw\nref,holding_reg09,40008,uint32,rw\nref,holding_reg10,40010,uint32,rw\nref,holding_reg11,40012,int32,rw\nref,holding_reg12,40014,int32,rw\nref,holding_reg13,40016,float32,rw\nref,holding_reg14,40018,float32,rw\nref,holding_reg15,40020,uint64,rw\nref,holding_reg16,40024,int64,rw\nref,holding_reg17,40028,float64,rw\nref,holding_reg18,40032,float64,rw\nref,holding_reg19,40036,string16,rw\n```\n\nThis configuration tells *modpoll* to do the following for each poll,\n\n- Read `16` coils from the address starting from `0` and parse the response as two 8-bits boolean values;\n- Read `16` discrete inputs from the address starting from `10000` and parse the response as two 8-bits boolean values;\n- Read `20` input registers from the address starting from `30000` and parse data accordingly;\n- Read `44` holding registers from the address starting from `40000` and parse data accordingly;\n\n\u003e Notice the holding registers contain a 16-byte long string, which counts as 8 registers in poll size, because Modbus protocol defines a holding register as 2-byte width.\n\nIn 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.\n\nYou can also take a look at [contrib](https://github.com/gavinying/modpoll/tree/main/contrib) folder, which collects a few types of device configuration shared by contributors.\n\nThe configuration can be either a local file or a remote public URL resource.\n\n\u003e *Refer to the [documentation](https://gavinying.github.io/modpoll/configure.html) site for more details.*\n\n### Poll local device (modsim)\n\nIf 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,\n\n```bash\ndocker run --rm -p 5020:5020 topmaker/modsim\n```\n\nIt 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,\n\n```bash\nmodpoll \\\n  --tcp localhost \\\n  --tcp-port 5020 \\\n  --config https://raw.githubusercontent.com/gavinying/modpoll/main/examples/modsim.csv\n```\n\n\u003e Use `sudo` before the docker command if you want to use the standard port `502`.\n\n```bash\nsudo docker run --rm -p 502:5020 topmaker/modsim\n```\n\nIn a new terminal,\n\n```\nmodpoll \\\n  --tcp localhost \\\n  --config https://raw.githubusercontent.com/gavinying/modpoll/main/examples/modsim.csv\n```\n\n### Publish data to MQTT broker\n\nThis 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.\n\nThe following example uses a public MQTT broker `broker.emqx.io` for test purpose. You can also set up your own MQTT broker locally using [mosquitto](https://mosquitto.org/download/).\n\n```bash\nmodpoll \\\n  --tcp modsim.topmaker.net \\\n  --mqtt-host broker.emqx.io \\\n  --config https://raw.githubusercontent.com/gavinying/modpoll/main/examples/modsim.csv\n```\n\nWith successful data polling and publishing, you can subscribe the default data topic `modpoll/modsim01/data` on the same MQTT broker `broker.emqx.io` to view the collected data.\n\nThe MQTT topics can be customized by providing the following arguments,\n\n  - `mqtt-publish-topic-pattern`\n  - `mqtt-subscribe-topic-pattern`\n  - `mqtt-diagnostics-topic-pattern`\n\nSee [document](https://gavinying.github.io/modpoll/usage.html#Named%20Arguments) for details.\n\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/screencast-modpoll-mqtt.gif\"\u003e\n\u003c/p\u003e\n\n\n### Write registers via MQTT publish\n\nThe *modpoll* tool will subscribe to the topic `modpoll/{{device_name}}/set` by default once it successfully connected to MQTT broker, user can write device register(s) via MQTT publish,\n\n- To write a single holding register (address at `40001`)\n\n  ```json\n  {\n    \"object_type\": \"holding_register\",\n    \"address\": 40001,\n    \"value\": 12\n  }\n  ```\n\n- To write multiple holding registers (address starting from `40001`)\n\n  ```json\n  {\n    \"object_type\": \"holding_register\",\n    \"address\": 40001,\n    \"value\": [12, 13, 14, 15]\n  }\n  ```\n\n\n## Run with docker\n\nA docker image has been provided for user to directly run the tool without local installation,\n\n  ```bash\n  docker run --rm topmaker/modpoll\n  ```\n\nIt shows the version of the tool by default.\n\nSimilar 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.\n\n  ```bash\n  docker run --rm topmaker/modpoll \\\n    modpoll -d \\\n      --tcp modsim.topmaker.net \\\n      --config https://raw.githubusercontent.com/gavinying/modpoll/main/examples/modsim.csv\n  ```\n\nIf you want to load a local configure file, you need to mount a local folder onto container volume,\nfor example, if the child folder `examples` contains the config file `modsim.csv`, we can use it via the following command,\n\n  ```bash\n  docker run --rm -v $(pwd)/examples:/app/examples topmaker/modpoll \\\n    modpoll -d \\\n      --tcp modsim.topmaker.net \\\n      --config /app/examples/modsim.csv\n  ```\n\n\n## Example Use Cases\n\n- Connect to Modbus TCP device\n\n  ```bash\n  modpoll \\\n    --tcp 192.168.1.10 \\\n    --config examples/modsim.csv\n  ```\n\n- Connect to Modbus serial device\n\n  ```bash\n  modpoll \\\n    --serial /dev/ttyUSB0 \\\n    --serial-baud 9600 \\\n    --config contrib/eniwise/scpms6.csv\n  ```\n\n- Connect to Modbus TCP device and publish data to MQTT broker\n\n  ```bash\n  modpoll \\\n    --tcp modsim.topmaker.net \\\n    --mqtt-host broker.emqx.io \\\n    --config examples/modsim.csv\n  ```\n\n- Connect to Modbus TCP device and export data to local csv file\n\n  ```bash\n  modpoll \\\n    --tcp modsim.topmaker.net \\\n    --export data.csv \\\n    --config examples/modsim.csv\n  ```\n\n- Connect to Modbus TCP devices using multiple config files\n\n  ```bash\n  modpoll \\\n    --tcp modsim.topmaker.net \\\n    --config examples/modsim.csv examples/modsim2.csv\n  ```\n\n\n\u003e Refer to the [documentation](https://gavinying.github.io/modpoll) site for more details about the configuration and examples.\n\n\u003e *If you find this tool useful, please support us by starring 🌟 our repository to encourage further improvements.*\n\n## Credits\n\nThe implementation of this project is heavily inspired by the following two projects:\n- https://github.com/owagner/modbus2mqtt (MIT license)\n- https://github.com/mbs38/spicierModbus2mqtt (MIT license)\n\nThanks to Max Brueggemann and Oliver Wagner for their great work.\n\n\n## License\n\nMIT © 2021-2026, Ying Shaodong\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgavinying%2Fmodpoll","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgavinying%2Fmodpoll","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgavinying%2Fmodpoll/lists"}