{"id":19610462,"url":"https://github.com/valiot/modbux","last_synced_at":"2025-04-07T04:19:21.998Z","repository":{"id":62429907,"uuid":"168790337","full_name":"valiot/modbux","owner":"valiot","description":"Elixir Modbus library for network and serial communications.","archived":false,"fork":false,"pushed_at":"2025-03-15T05:07:30.000Z","size":360,"stargazers_count":42,"open_issues_count":3,"forks_count":15,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-05T22:44:32.192Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/modbux","language":"Elixir","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/valiot.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2019-02-02T03:31:50.000Z","updated_at":"2025-03-17T15:02:49.000Z","dependencies_parsed_at":"2024-03-01T03:43:07.693Z","dependency_job_id":"9ba9bb45-21c0-4d1a-aaa7-1c5baa871b0d","html_url":"https://github.com/valiot/modbux","commit_stats":{"total_commits":77,"total_committers":3,"mean_commits":"25.666666666666668","dds":0.5064935064935066,"last_synced_commit":"061c6796c1039c40cd1c4fca4404e2502effd60e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valiot%2Fmodbux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valiot%2Fmodbux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valiot%2Fmodbux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valiot%2Fmodbux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/valiot","download_url":"https://codeload.github.com/valiot/modbux/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247589826,"owners_count":20963025,"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","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":[],"created_at":"2024-11-11T10:29:27.890Z","updated_at":"2025-04-07T04:19:21.962Z","avatar_url":"https://github.com/valiot.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/valiot/modbux/master/assets/images/modbux-logo.png\" alt=\"modbux Logo\" width=\"512\" height=\"151\" /\u003e\n\u003c/div\u003e\n\n***\n\u003cbr\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/valiot/modbux/master/assets/images/valiot-logo-blue.png\" alt=\"Valiot Logo\" width=\"384\" height=\"80\" /\u003e\n\u003c/div\u003e\n\u003cbr\u003e\n\nModbux is a library for network and serial Modbus communications. \n\nThis library currently supports behaviors for TCP (Client \u0026 Server) and RTU (Master \u0026 Slave) protocols.\n\n## Index\n\n* [Features](#features)\n\n* [Installation](#installation)\n\n* [Usage](#usage)\n    * [Modbus RTU](#Slave)\n    * [Modbus TCP](#Server)\n    * [Helpers](#Helpers)\n\n* [Documentation](#documentation)\n\n* [Contributing](#contributing)\n\n* [License](#License)\n\n* [TODO](#todo)\n\n## Features\n\nThe following list is the current supported protocols/behaviors and helpers:\n\n- Modbus RTU:\n  - Master\n  - Slave\n  - Framer\n\n- Modbus TCP:\n  - Client\n  - Server\n\n- Helpers:\n  - IEEE754 Float support\n  - Endianess\n\n\n## Installation\n\nThe package can be installed by adding `modbux` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:modbux, \"~\u003e 0.1.0\"}\n  ]\nend\n```\n\n## Usage\n***\n### Modbus RTU\n\nModbus RTU is an open serial protocol derived from the Master/Slave architecture originally developed by Modicon. This protocol primarily uses an RS-232 or RS-485 serial interfaces for communications.\n\n#### Slave\n\nTo start a Modbus RTU Slave process use `start_link/1`.\n\nThe following options are available:\n- `tty` - defines the serial port to spawn the Slave.\n- `gen_opts` - defines extra options for the Genserver OTP configuration.\n- `uart_opts` - defines extra options for the UART configuration.\n- `model` - defines the DB initial state.\n- `active` - (`true` or `false`) enable/disable DB updates notifications (mailbox).\n\nThe messages (when active mode is `true`) have the following form:\n```elixir\n  {:modbus_rtu, {:slave_request, payload}}\n```\nor\n\n```elixir\n  {:modbus_rtu, {:slave_error, payload, reason}}\n```\n\nThe following are some reasons:\n\n* `:ecrc`  - corrupted message (invalid crc).\n* `:einval`  - invalid function.\n* `:eaddr`  - invalid memory address requested.\n\n#### Model (DB)\n\nThe model or data base (DB) defines the slave/server memory map, the DB is defined by the following syntax:\n```elixir\n%{slave_id =\u003e %{{memory_type, address_number} =\u003e value}}\n```\nwhere:\n* `slave_id` - specifies a unique unit address from 1 to 247.\n* `memory_type` - specifies the memory between:\n    * `:c` - Discrete Output Coils.\n    * `:i` - Discrete Input Contacts.\n    * `:ir` - Analog Input Registers.\n    * `:hr` - Analog Output Registers.\n* `address_number` - specifies the memory address.\n* `value` - the current value from that memory.\n\n### Example\n```elixir\n# DB inital state\nmodel = %{\n    80 =\u003e %{\n      {:c, 1} =\u003e 1,\n      {:c, 2} =\u003e 0,\n      {:i, 1} =\u003e 1,\n      {:i, 2} =\u003e 1,\n      {:ir, 1} =\u003e 0,\n      {:ir, 2} =\u003e 1,\n      {:hr, 1} =\u003e 102,\n      {:hr, 2} =\u003e 103\n    }\n  }\n# Starts the Slave at \"ttyUSB0\"\n{:ok, s_pid} = Modbux.Rtu.Slave.start_link(tty: \"ttyUSB0\", model: model, active: true)\n```\nif needed, the Slave DB can be modified in runtime with elixir code by using `request/2`,\na `cmd` must be used to update the DB, the `cmd` is a 4 elements tuple, as follows:\n  - `{:rc, slave, address, count}` read `count` coils.\n  - `{:ri, slave, address, count}` read `count` inputs.\n  - `{:rhr, slave, address, count}` read `count` holding registers.\n  - `{:rir, slave, address, count}` read `count` input registers.\n  - `{:fc, slave, address, value}` force single coil.\n  - `{:phr, slave, address, value}` preset single holding register.\n  - `{:fc, slave, address, values}` force multiple coils.\n  - `{:phr, slave, address, values}` preset multiple holding registers.\n\n#### Master\n\nTo start a Modbus RTU Master process use `start_link/1`.\n\nThe following options are available:\n\n  * `tty` - defines the serial port to spawn the Master.\n  * `timeout` - defines slave timeout.\n  * `active` - (`true` or `false`) specifies whether data is received as\n      messages (mailbox) or by calling `request/2`.\n  * `gen_opts` - defines extra options for the Genserver OTP configuration.\n  * `uart_opts` - defines extra options for the UART configuration (defaults:\n        [speed: 115200, rx_framing_timeout: 1000]).\n\nThe messages (when active mode is true) have the following form:\n```elixir\n  {:modbus_rtu, {:slave_response, cmd, values}}\n```\nor\n```elixir\n  {:modbus_rtu, {:slave_error, payload, reason}}\n```\nThe following are some reasons:\n\n  * `:ecrc`  - corrupted message (invalid crc).\n  * `:einval`  - invalid function.\n  * `:eaddr`  - invalid memory address requested.\n\nuse `request/2` to send a `cmd` (command) to a Modbus RTU Slave.\n\n### Example\n\n```elixir\n# Starts the Master at \"ttyUSB1\" (in the example is connected to ttyUSB1)\n{:ok, m_pid} = Modbux.Rtu.Master.start_link(tty: \"ttyUSB1\")\n# Read 2 holding registers at 1 (memory address) from the slave 80\nresp = Modbux.Rtu.Master.request(m_pid, {:rhr, 80, 1, 2})\n# resp == {:ok, [102, 103]}\n```\n\n### Modbux TCP\n\nModbus TCP (also Modbus TCP/IP) is simply the Modbus RTU protocol with a TCP interface that runs on a network.\n\n#### Server\n\nTo start a Modbus TCP Server process use `start_link/1`.\n\nThe following options are available:\n\n  * `port` - is the Modbux TCP Server tcp port number.\n  * `timeout` - is the connection timeout.\n  * `model` - defines the DB initial state.\n  * `sup_otps` - server supervisor OTP options.\n  * `active` - (`true` or `false`) enable/disable DB updates notifications (mailbox).\n\nThe messages (when active mode is true) have the following form:\n```elixir\n  {:modbus_tcp, {:slave_request, payload}}\n```\n\n### Example\n\n```elixir\n# DB initial state\nmodel = %{80 =\u003e %{{:c, 20818} =\u003e 0, {:hr, 20818} =\u003e 0}}\n# Starts the Server at tcp port: 2000\nModbux.Tcp.Server.start_link(model: model, port: 2000)\n```\n\n#### Client \n\nTo start a Modbus TCP Client process use `start_link/1`.\n\nThe following options are available:\n\n  * `ip` - is the internet address of the desired Modbux TCP Server.\n  * `tcp_port` - is the desired Modbux TCP Server tcp port number.\n  * `timeout` - is the connection timeout.\n  * `active` - (`true` or `false`) specifies whether data is received as\n      messages (mailbox) or by calling `confirmation/1` each time `request/2` is called.\n\nThe messages (when active mode is true) have the following form:\n\n```elixir\n  {:modbus_tcp, cmd, values}\n```\n\nto connect to a Modbus TCP Server `connect/1`.\n\nUse `request/2` to send a `cmd` (command) to a Modbus TCP Server and `confirmation/1` to parse the server response.\n\n### Example\n\n```elixir\n# Starts the Client that will connect to a Server with tcp port: 2000\n{:ok, cpid} = Modbux.Tcp.Client.start_link(ip: {127,0,0,1}, tcp_port: 2000, timeout: 2000)\n# Connect to the Server\nModbux.Tcp.Client.connect(cpid)\n# Read 1 coil at 20818 from the device 80\nModbux.Tcp.Client.request(cpid, {:rc, 0x50, 20818, 1})\n# Parse the Server response\nresp = Modbux.Tcp.Client.confirmation(cpid) \n# resp == {:ok, [0]}\n```\n\n\n### Helpers\n\n#### IEEE754 Float\n\nSeveral modbus register use IEEE754 float format, therefore this library also provides functions to encode and decode data.\n\n### Example\n\n```elixir\n  # Encode\n  +5.0 = Modbux.IEEE754.from_2_regs(0x40a0, 0x0000, :be)\n  [-5.0, +5.0] = Modbux.IEEE754.from_2n_regs([0xc0a0, 0x0000, 0x40a0, 0x0000], :be)\n  # Decode\n  [0xc0a0, 0x0000] = Modbux.IEEE754.to_2_regs(-5.0)\n  [0xc0a0, 0x0000, 0x40a0, 0x0000] = Modbux.IEEE754.to_2n_regs([-5.0, +5.0])\n```\n\nBased on https://www.h-schmidt.net/FloatConverter/IEEE754.html.\n\n#### Endianess\n\nDepending on the device / server the data can be encoded with different types of endianess, therefore this library also provides functions to encode data.\n\n### Example\n\n```elixir\n  # Encode\n  2.3183081793789774e-41 = Modbux.IEEE754.from_2_regs(0x40a0, 0x0000, :le)\n  [6.910082987278538e-41, 2.3183081793789774e-41] = Modbux.IEEE754.from_2n_regs([0xc0a0, 0x0000, 0x40a0, 0x0000], :le)\n```\n\n\nGood to know:\n- [Erlang default endianess is BIG](http://erlang.org/doc/programming_examples/bit_syntax.html#Defaults)\n- [MODBUS default endianess is BIG (p.34)](http://modbus.org/docs/PI_MBUS_300.pdf)\n- [MODBUS CRC endianess is LITTLE (p.16)](http://modbus.org/docs/PI_MBUS_300.pdf)\n\n\n## Documentation\nThe docs can be found at [https://hexdocs.pm/modbux](https://hexdocs.pm/modbux).\n\nBased on:\n\n- http://modbus.org/docs/PI_MBUS_300.pdf\n- http://modbus.org/docs/Modbux_Messaging_Implementation_Guide_V1_0b.pdf\n- http://modbus.org/docs/Modbux_over_serial_line_V1_02.pdf\n- http://www.simplymodbus.ca/index.html\n\n## Contributing\n  * Fork our repository on github.\n  * Fix or add what is needed.\n  * Commit to your repository.\n  * Issue a github pull request (fill the PR template).\n\n## License\n  See [LICENSE](https://github.com/valiot/modbux/blob/master/LICENSE).\n\n## TODO\n  * Add Modbux ASCII.\n  * Add Modbux UDP.\n  * Add more examples.\n  * Improve error handling.\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvaliot%2Fmodbux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvaliot%2Fmodbux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvaliot%2Fmodbux/lists"}