{"id":24811163,"url":"https://github.com/thin-edge/modbus-plugin","last_synced_at":"2025-10-13T12:31:38.852Z","repository":{"id":104907833,"uuid":"551448785","full_name":"thin-edge/modbus-plugin","owner":"thin-edge","description":"Community developed modbus plugin for thin-edge.io","archived":false,"fork":false,"pushed_at":"2025-09-30T08:43:39.000Z","size":710,"stargazers_count":3,"open_issues_count":4,"forks_count":9,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-30T10:28:10.489Z","etag":null,"topics":["community","plugin","thin-edge"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thin-edge.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-10-14T12:23:11.000Z","updated_at":"2025-09-30T08:43:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"1b220f46-5d31-4cb6-9479-4579e654a641","html_url":"https://github.com/thin-edge/modbus-plugin","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/thin-edge/modbus-plugin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thin-edge%2Fmodbus-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thin-edge%2Fmodbus-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thin-edge%2Fmodbus-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thin-edge%2Fmodbus-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thin-edge","download_url":"https://codeload.github.com/thin-edge/modbus-plugin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thin-edge%2Fmodbus-plugin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279015056,"owners_count":26085643,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["community","plugin","thin-edge"],"created_at":"2025-01-30T12:19:32.432Z","updated_at":"2025-10-13T12:31:38.841Z","avatar_url":"https://github.com/thin-edge.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tedge-modbus-plugin\n\nthin-edge.io Modbus community plugin.\nPlugin for polling Modbus devices and publishing the data to thin-edge.io. If used with Cumulocity IoT, the plugin can be managed via software configuration management. The Plugin also supports some of the [Cloud Fieldbus](https://cumulocity.com/guides/protocol-integration/cloud-fieldbus/) operations to set the Modbus mapping via Cumulocity IoT UI.\n\n## Table of contents\n\n- [Overview](#overview)\n- [Requirements](#requirements)\n- [Demo](#demo)\n- [Config files](#config-files)\n  - [modbus.toml](#modbustoml)\n  - [devices.toml](#devicestoml)\n  - [Updating the config files](#updating-the-config-files)\n- [Logs and systemd service](#logs-and-systemd-service)\n- [Cumulocity Integration](#cumulocity-integration)\n\n  - [Installation via Software Management](#installation-via-software-management)\n  - [Log file access](#log-file-access)\n  - [Config management](#config-management)\n  - [Cloud Fieldbus](#cloud-fieldbus)\n  - [Writing operations](#writing-operations)\n\n- [Testing](#testing)\n- [Build](#build)\n  - [Debian package](#debian-package)\n- [Deployment](#deployment)\n  - [As Python script (for dev only)](#as-python-script-for-dev-only)\n  - [As deb file](#as-deb-file)\n\n## Overview\n\nThe plugin regularly polls Modbus devices and publishes the data to the thin-edge.io broker. The plugin is based on the [pymodbus](https://pymodbus.readthedocs.io/en/latest/) library. After installing, the plugin can be configured by changing the `modbus.toml` and `devices.toml` files. The plugin comes with an example config [4] with comments to get you started. Adding multiple servers should also be as simple as adding additional `[[device]]` sections for each IP address or serial address you want to poll.\n\n## Requirements\n\n- Ubuntu \u003e= 22.04 or Debian \u003e= 11.0\n- Python \u003e= 3.8\n- systemd\n- for operations support: thin-edge.io \u003e= 1.x\n- for demo purposes: docker-compose\n\n## Demo\n\nYou can run the thin-edge.io with the plugin and a Modbus simulator locally via Docker containers. To start the demo, run 'just up' in the root folder of the repository. This will start the tedge container and the Modbus simulator.\nThe Modbus simulator runs a Modbus server with some example registers. The simulator is based on the [pymodbus](https://pymodbus.readthedocs.io/en/latest/) library and can be found and changed in the [images/simulator](./images/simulator/) folder.\n\nThe demo includes a example device that maps an integer and float register to a child device. The device configuration can be found in the [images/tedge/config](./images/tedge/config) folder.\n\nTo start the containers, you need to have docker-compose installed. You can start the containers with:\n\n```sh\njust up\n```\n\nAfter starting the containers, you need to register the thin-edge.io on your tenant. You can do this by running the following command:\n\n```sh\njust bootstrap\n```\n\nThis will create a device certificate in the tedge container and upload it to your tenant. To skip the manual input of your credentials, you create a .env file in your working directory:\n\n```sh\nC8Y_BASEURL=https://\u003ctenant\u003e.cumulocity.com\nC8Y_USER=\u003cuser\u003e\nC8Y_PASSWORD=\u003cpassword\u003e\nDEVICE_ID=\u003cExternal ID of your Test Device\u003e\n```\n\nYou can skip the manual bootstrap process by running:\n\n    just bootstrap --no-prompt\n\n## Config files\n\nThere are two configuration files you need to edit for your use case. Any changes to the files will restart the polling of the Modbus servers automatically, so you don’t have to worry about restarting any services.\nAll config files are expected to be in the /etc/tedge/plugins/modbus folder.\nAs an alternative the directory can be based with -c or --configdir to the python script like so:\n\n`python3 -m tedge_modbus.reader --configdir \u003cconfigfolder\u003e`\n\nIf used with Cumulocity IoT, the plugins can be managed via the Device Management or created with the Cloud Fieldbus operations.\n\n### modbus.toml\n\nThis includes the basic configuration for the plugin such as poll rate and the connection to thin-edge.io (the MQTT broker needs to match the one of tedge and is probably the default `localhost:1883`). It also includes the configuration of the main serial port used by modbus RTU devices. Make sure the serial port is properly configured to for the hardware in use.\n\n- poll rate\n- serial configuration\n- connection to thin-edge.io (MQTT broker needs to match the one of tedge)\n- log level (e.g. INFO, WARN, ERROR)\n- measurement combination (opt-in feature to reduce the amount of created measurements in the cloud)\n\n### devices.toml\n\nThis file includes the information for the connection(s) to the Modbus server(s) and how the Modbus Registers and Coils map to thin-edge’s Measurements, Events and Alarms. It's also possible to overwrite the measurement combination on a device level and on every single measurement mapping.\n\nThe device config can be managed via Cumulocity IoT or created with the Cloud Fieldbus operations.\n\n### Updating the config files\n\nA watchdog observer will take care of restarting the MQTT and Modbus connection when either\ndevices.toml or modbus.toml changes. So there should be no need to manually restart the\npython script / service.\n\n## Logs and systemd service\n\nRunning the deb installer will place the config files into `/etc/tedege/plugins/modbus/`.\nIf systemd is installed, it will enable and start the service as part of the post-installation routine.\n\nCheck the status of the systemd service with `sudo systemctl status tedge-modbus-plugin.service`\nWhen running as a service, the default log output goes to `/var/log/tedge-modbus-plugin/modbus.log`.\n\n## Cumulocity Integration\n\n### Installation via Software Management\n\nYou can use the Software Repository of Cumulocity IoT and thin-edge.io Software Management plugin to install the deb remotely:\nUpload the deb package to the Cumulocity Software Repository. The name **must** be `tedge-modbus-plugin` and\nthe version **must** match the version in the \\*.deb package name (e.g. 1.0.0). The rest of the fields can be set as necessary.\nGo to the Software tab of the target device and select the package for installation. After the operation is successful the plugin will start automatically on the device.\n\n![Image](./doc/sm.png)\n\n### Log file access\n\nFor integration with the Cumulocity IoT log plugin add the following line to the /etc/tedge/plugins/tedge-log-plugin.toml\n\n```toml\n{ type = \"modbus\", path = \"/var/log/tedge-modbus-plugin/modbus.log\" },\n```\n\n![Image](./doc/log.png)\n\n### Config management\n\nBoth config files can either be updated in-place (i.e. simply editing with an editor) or\nby using thin-edge.io. Add the following lines to the `tedge-configuration-plugin.toml`\nto be able to access them from the Cumulocity Configuration UI:\n\n```toml\n{ path = '/etc/tedge/plugins/modbus/modbus.toml', type='modbus', owner='tedge', group='tedge', mode=0o644 },\n{ path = '/etc/tedge/plugins/modbus/devices.toml', type='modbus-devices', owner='tedge', group='tedge', mode=0o644 },\n```\n\nTo replace the files with a version from the Cumulocity Configuration Repository you have to download a copy,\nedit it and upload it to the repository. The device type **must** be set to _thin-edge.io_ and the config type must match\nthe definition in your tedge-configuration-plugin.toml. I.e either _modbus_ (for modbus.toml) or _modbus-devices_ for (devices.toml)\n\n![Image](./doc/cm.png)\n\n### Cloud Fieldbus\n\nThe plugin supports the [Cloud Fieldbus](https://cumulocity.com/guides/protocol-integration/cloud-fieldbus/) operations to set the Modbus mapping via Cumulocity IoT UI.\nAs of now, the plugin only supports the following operations:\n\n- c8y_ModbusDevice\n- Mapping of registers to Measurements with c8y_ModbusConfiguration\n- c8y_SerialConfiguration\n\nTo create a Cloud Fieldbus Device in Cumulocity IoT, you need first to create a Modbus protocol. Open the Device protocols page in your Device Management and add a new Modbus protocol.\nThe configuration of your protocol depends on your Modbus Server. If you are using the Modbus Demo simulator, the you can use the following configuration:\n\n![Image](./doc/protocol.png)\n\nAfter creating the protocol, you can add a new Cloud Fieldbus Device. Select the Modbus Tab on your thin-edge.io and add a new tcp device. If you are using the Modbus Demo simulator, you need to add the IP-Address of your Docker host, as host names are not supported by the UI.\n\n![Image](./doc/tcp_device.png)\n\nFor adding a modbus RTU device you need to use unit-ID of the slave device in the configuration.\n\n### Write operations\n\nThe plugin supports writing to Modbus registers and coils through Cumulocity IoT operations.\n\n#### Write to Register (c8y_SetRegister)\n\nWrite values to Modbus registers requires the following json to be included in the operation:\n\n```json\n{\n  \"c8y_SetRegister\": {\n    \"input\": false,\n    \"address\": 1,\n    \"register\": 3,\n    \"startBit\": 0,\n    \"noBits\": 16,\n    \"value\": 23,\n    \"ipAddress\": \"192.168.1.100\"\n  }\n}\n```\n\nTo create an operation to write a value to a Modbus register using Cumulocity, you can use the [go-c8y-cli](https://goc8ycli.netlify.app/docs/cli/c8y/operations/c8y_operations_create/) tool:\n\n```\nc8y operations create --device 12345 --template '{\"c8y_SetRegister\": { \"input\": false, \"address\": 1, \"startBit\": 0, \"noBits\": 16, \"ipAddress\": \"192.168.1.2\", \"value\": 23, \"register\": 3 }}' --description 'Writing a register'\n```\n\nOr use [REST API](https://cumulocity.com/api/core/#operation/postOperationCollectionResource).\n\nIn the Cumulocity UI, the widget '[Asset table](https://cumulocity.com/docs/cockpit/widgets-collection/#asset-table)' can be used to create operations for the device. \n\n![Image](./doc/write-register-asset-table.png)\n\n\n#### Write to Coil (c8y_SetCoil)\n\nWrite values to Modbus coils requires the following json to be included in the operation:\n:\n\n```json\n{\n  \"c8y_SetCoil\": {\n    \"input\": false,\n    \"address\": 1,\n    \"coil\": 48,\n    \"value\": 1,\n    \"ipAddress\": \"192.168.1.100\"\n  }\n}\n```\n\nTo create an operation to write a value to a Modbus coil using Cumulocity, you can use the [go-c8y-cli](https://goc8ycli.netlify.app/docs/cli/c8y/operations/c8y_operations_create/) tool:\n\n```\nc8y operations create --device 12345 --template '{\"c8y_SetCoil\": { \"input\": false, \"coil\": 48, \"address\": 1, \"value\": 1, \"ipAddress\": \"192.168.1.100\" } }' --description 'Writing a coil'\n```\n\nOr use the [Cumulocity REST API](https://cumulocity.com/api/core/#operation/postOperationCollectionResource).\n\nIn the Cumulocity UI, the widget [Asset table](https://cumulocity.com/docs/cockpit/widgets-collection/#asset-table) can be used to create operations for the device. \n\n![Image](./doc/write-coil-asset-table.png)\n\n\n:construction: The plugin does not yet support Cumulocity Fieldbus device widget. Please follow the above instrucstions to create operations. \n\n\n## Testing\n\nTo run the tests locally, you need to provide your Cumulocity credentials as environment variables in a .env file:\n\n```sh\nC8Y_BASEURL=https://\u003ctenant\u003e.cumulocity.com\nC8Y_USER=\u003cuser\u003e\nC8Y_PASSWORD=\u003cpassword\u003e\nDEVICE_ID=\u003cExternal ID of your Test Device\u003e\n```\n\nIf you have the simulator and the tedge container running, you can run the tests with:\n\n```sh\njust venv\njust setup\njust test\n```\n\n## Build\n\nA package of the plugin, including the Modbus polling service and the Cloud Fieldbus operations, can be build with nfpm. To build the packages locally, make sure to install nfpm first.\nThe package requires a python3 installation on your device.\n\nTo create the packages, you need to install nfpm first:\n\n[Install nfpm](https://nfpm.goreleaser.com/install/)\n\n### Debian package\n\nAfter installing, you can build the Debian package with:\n\n```\nnfpm pkg --packager deb --target /tmp/\n```\n\n## Deployment\n\n### As Python script (for dev only)\n\n- copy modbus-plugin folder to target device\n- ssh into device and go to the plugin folder\n- create the virtual environment with `python3 -m venv venv`\n- activate the virtual environment with `source ./venv/bin/activate`\n- install all dependencies with `python3 -m pip install -r requirements.txt`\n- run the reader with `python3 tedge_modbus/reader/reader.py -c ./config`\n\n### As deb file\n\nInstall the debian package using the following command:\n\n```sh\nsudo dpkg -i tedge-modbus-plugin-\u003cversion\u003e-\u003carch\u003e.deb\n```\n\n## Contributing\n\n### Coding Style\n\nThe python project uses both black and pylint to enforce a specific coding style.\n\nBefore you submit a PR you should run the following commands, otherwise your PR will not be merged:\n\n1. Format all of the python code\n\n    ```sh\n    just format\n    ```\n\n2. Check python linting\n\n    ```sh\n    just lint\n    ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthin-edge%2Fmodbus-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthin-edge%2Fmodbus-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthin-edge%2Fmodbus-plugin/lists"}