This package is a go implementation of the modbus protocol. It aims to provide a simple-to-use, high-level API to interact with modbus devices using native Go types.
Both client and server components are available.
The client supports the following modes:
- modbus RTU (serial, over both RS-232 and RS-485),
- modbus TCP (a.k.a. MBAP),
- modbus TCP over TLS (a.k.a. MBAPS or Modbus Security),
- modbus RTU over TCP (RTU tunneled in TCP for use with e.g. remote serial ports or cheap TCP to serial bridges).
The server supports:
- modbus TCP (a.k.a. MBAP),
- modbus TCP over TLS (a.k.a. MBAPS or Modbus Security).
A CLI client is available in cmd/modbus-cli.go and can be built with
$ go build -o modbus-cli cmd/modbus-cli.go
$ ./modbus-cli --help
$ go get github.com/simonvetter/modbus
import (
"github.com/simonvetter/modbus"
)
func main() {
var client *modbus.ModbusClient
var err error
// for a TCP endpoint
// (see examples/tls_client.go for TLS usage and options)
client, err = modbus.NewClient(&modbus.ClientConfiguration{
URL: "tcp://hostname-or-ip-address:502",
Timeout: 1 * time.Second,
})
// for an RTU (serial) device/bus
client, err = modbus.NewClient(&modbus.ClientConfiguration{
URL: "rtu:///dev/ttyUSB0",
Speed: 19200, // default
DataBits: 8, // default, optional
Parity: modbus.PARITY_NONE, // default, optional
StopBits: 2, // default if no parity, optional
Timeout: 300 * time.Millisecond,
})
// for an RTU over TCP device/bus (remote serial port or
// simple TCP-to-serial bridge)
client, err = modbus.NewClient(&modbus.ClientConfiguration{
URL: "rtuovertcp://hostname-or-ip-address:502",
Speed: 19200, // serial link speed
Timeout: 1 * time.Second,
})
if err != nil {
// error out if client creation failed
}
// now that the client is created and configured, attempt to connect
err = client.Open()
if err != nil {
// error out if we failed to connect/open the device
// note: multiple Open() attempts can be made on the same client until
// the connection succeeds (i.e. err == nil), calling the constructor again
// is unnecessary.
// likewise, a client can be opened and closed as many times as needed.
}
// read a single 16-bit holding register at address 100
var reg16 uint16
reg16, err = client.ReadRegister(100, modbus.HOLDING_REGISTER)
if err != nil {
// error out
} else {
// use value
fmt.Printf("value: %v", reg16) // as unsigned integer
fmt.Printf("value: %v", int16(reg16)) // as signed integer
}
// read 4 consecutive 16-bit input registers starting at address 100
var reg16s []uint16
reg16s, err = client.ReadRegisters(100, 4, modbus.INPUT_REGISTER)
// read the same 4 consecutive 16-bit input registers as 2 32-bit registers
var reg32s []uint32
reg32s, err = client.ReadUint32s(100, 2, modbus.INPUT_REGISTER)
// read the same 4 consecutive 16-bit registers as a single 64-bit register
var reg64 uint64
reg64, err = client.ReadUint64(100, modbus.INPUT_REGISTER)
// by default, 16-bit registers are decoded as big-endian and 32-bit registers
// as big-endian with the high word first.
// change the byte/word ordering of subsequent requests to little endian, with
// the low word first (note that the second argument only affects 32-bit registers)
client.SetEncoding(modbus.LITTLE_ENDIAN, modbus.LOW_WORD_FIRST)
// read the same 4 consecutive 16-bit input registers as 2 32-bit floats
var fl32s []float32
fl32s, err = client.ReadFloat32s(100, 2, modbus.INPUT_REGISTER)
// write -200 to 16-bit (holding) register 100, as a signed integer
var s int16 = -200
err = client.WriteRegister(100, uint16(s))
// Switch to unit ID (a.k.a. slave ID) #4
client.SetUnitId(4)
// write 3 floats to registers 100 to 105
err = client.WriteFloat32s(100, []float32{
3.14,
1.1,
-783.22,
})
// close the TCP connection/serial port
client.Close()
}
See:
- examples/tcp_server.go for a modbus TCP example
- examples/tls_server.go for TLS and Modbus Security features
Function codes:
- Read coils (0x01)
- Read discrete inputs (0x02)
- Read holding registers (0x03)
- Read input registers (0x04)
- Write single coil (0x05)
- Write single register (0x06)
- Write multiple coils (0x0f)
- Write multiple registers (0x10)
Go object types:
- Booleans (coils and discrete inputs)
- Signed/Unisgned 16-bit integers (input and holding registers)
- Signed/Unsigned 32-bit integers (input and holding registers)
- 32-bit floating point numbers (input and holding registers)
- Signed/Unsigned 64-bit integers (input and holding registers)
- 64-bit floating point numbers (input and holding registers)
Byte encoding/endianness/word ordering:
- Little and Big endian for 16-bit integers
- Little and Big endian, with and without word swap for 32 and 64-bit integers and floating point numbers.
- Add RTU (serial) support to the server
- Add more tests
- Add diagnostics register support
- Add fifo register support
- Add file register support
- github.com/goburrow/serial for access to the serial port (thanks!)
MIT.