SwiftLibModbus is a modern Swift wrapper around the libmodbus C library, providing a convenient, type-safe interface for communicating with Modbus devices using Swift Concurrency features.
SwiftLibModbus leverages Swift Concurrency (async/await) to provide a clean, efficient API for Modbus RTU and TCP communication. The library is designed for ease of use while maintaining the full power of the underlying libmodbus implementation.
Key features:
- Swift Concurrency support (async/await)
- Support for Modbus RTU (serial) and Modbus TCP connections
- Type-safe register/coil reading and writing
- Automatic connection management
- Swift actor model for thread safety
- Easy handling of endianness
- Swift 6.1+
- iOS 18+ or macOS 15+
Add SwiftLibModbus as a dependency to your Package.swift file:
dependencies: [ .package(url: "https://github.com/jollyjinx/SwiftLibModbus.git", from: "2.0.0") ]Then add the dependency to your target:
.target( name: "YourTarget", dependencies: ["SwiftLibModbus"] )import SwiftLibModbus // Connect to a Modbus TCP device let device = try ModbusDevice( networkAddress: "192.168.1.100", port: 502, deviceAddress: 1 ) // Read holding registers let holdingRegisters: [UInt16] = try await device.readHoldingRegisters( from: 0x1000, count: 16 ) // Write to holding registers try await device.writeRegisters( to: 0x1000, arrayToWrite: [UInt16(1), UInt16(2), UInt16(3)] )import SwiftLibModbus // Connect to a Modbus RTU (serial) device let device = try ModbusDevice( device: "/dev/tty.usbserial-42340", slaveid: 1, baudRate: 9600, dataBits: 8, parity: .none, stopBits: 1 ) // Read coils let coils = try await device.readInputCoilsFrom( startAddress: 0x00, count: 10 ) // Read input registers let inputRegisters: [UInt16] = try await device.readInputRegisters( from: 0x00, count: 10 )The library supports reading various fixed-width integer types as well as floating point values:
// Read as 16-bit unsigned integers let uint16Values: [UInt16] = try await device.readRegisters( from: 0x1000, count: 10, type: .holding ) // Read as 32-bit unsigned integers let uint32Values: [UInt32] = try await device.readRegisters( from: 0x1000, count: 5, type: .holding ) // Read as IEEE-754 floating point let floatValues: [Float] = try await device.readRegisters( from: 0x1000, count: 5, type: .holding ) // Read as ASCII string let asciiString = try await device.readASCIIString( from: 0x1000, count: 10, type: .holding )You can specify endianness when reading or writing registers:
// Read registers with little endian byte order let values: [UInt32] = try await device.readRegisters( from: 0x1000, count: 10, type: .holding, endianness: .littleEndian )The library has built-in management for connections:
// Connect with auto-reconnect after 1 hour and disconnect when idle for 30 seconds let device = try ModbusDevice( networkAddress: "example.com", port: 502, deviceAddress: 1, autoReconnectAfter: 3600.0, // 1 hour in seconds disconnectWhenIdleAfter: 30.0 // 30 seconds )For more complete examples, see:
- swift-modbus-2-mqtt-bridge - A bridge converting Modbus to MQTT
SwiftLibModbus Version 2 has been developed by @jollyjinx for Swift Concurrency Support and is available under the MIT license. The underlying libmodbus C library is licensed under LGPL.