summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 21f35cd)
raw | patch | inline | side by side (parent: 21f35cd)
author | Eric Sandeen <sandeen@sandeen.net> | |
Wed, 10 Dec 2014 21:38:09 +0000 (15:38 -0600) | ||
committer | Marc Fournier <marc.fournier@camptocamp.com> | |
Fri, 16 Jan 2015 21:46:08 +0000 (22:46 +0100) |
This allows access to a local RS-485 serial port
via the modbus plugin by specifying i.e.
Device "/dev/ttyUSB0"
Baudrate 38400
in a <Host> block.
For now it assumes 8N1; adding another config option
to support other configurations could be done later.
Lightly tested on my local setup.
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
via the modbus plugin by specifying i.e.
Device "/dev/ttyUSB0"
Baudrate 38400
in a <Host> block.
For now it assumes 8N1; adding another config option
to support other configurations could be done later.
Lightly tested on my local setup.
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
src/collectd.conf.pod | patch | blob | history | |
src/modbus.c | patch | blob | history |
diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
index 1802d5aef8ec5a164794873e2f9b212b916570ad..12269ae1f67d5e082b5f2081b928e4bc75af2c87 100644 (file)
--- a/src/collectd.conf.pod
+++ b/src/collectd.conf.pod
=head2 Plugin C<modbus>
-The B<modbus plugin> connects to a Modbus "slave" via Modbus/TCP and reads
-register values. It supports reading single registers (unsigned 16E<nbsp>bit
+The B<modbus plugin> connects to a Modbus "slave" via Modbus/TCP or Modbus/RTU and
+reads register values. It supports reading single registers (unsigned 16E<nbsp>bit
values), large integer values (unsigned 32E<nbsp>bit values) and floating point
values (two registers interpreted as IEEE floats in big endian notation).
Instance "input-2"
</Data>
+ <Data "supply-temperature-1">
+ RegisterBase 0
+ RegisterType Int16
+ ModbusRegisterType holding
+ Type temperature
+ Instance "temp-1"
+ </Data>
+
<Host "modbus.example.com">
Address "192.168.0.42"
Port "502"
</Slave>
</Host>
+ <Host "localhost">
+ Device "/dev/ttyUSB0"
+ Baudrate 38400
+ Interval 20
+
+ <Slave 1>
+ Instance "temperature"
+ Collect "supply-temperature-1"
+ </Slave>
+ </Host>
+
=over 4
=item E<lt>B<Data> I<Name>E<gt> blocks
=item B<Address> I<Hostname>
-Specifies the node name (the actual network address) used to connect to the
-host. This may be an IP address or a hostname. Please note that the used
-I<libmodbus> library only supports IPv4 at the moment.
+For Modbus/TCP, specifies the node name (the actual network address) used to
+connect to the host. This may be an IP address or a hostname. Please note that
+the used I<libmodbus> library only supports IPv4 at the moment.
=item B<Port> I<Service>
-Specifies the port used to connect to the host. The port can either be given as
-a number or as a service name. Please note that the I<Service> argument must be
-a string, even if ports are given in their numerical form. Defaults to "502".
+for Modbus/TCP, specifies the port used to connect to the host. The port can
+either be given as a number or as a service name. Please note that the
+I<Service> argument must be a string, even if ports are given in their numerical
+form. Defaults to "502".
+
+=item B<Device> I<Devicenode>
+
+For Modbus/RTU, specifies the path to the serial device being used.
+
+=item B<Baudrate> I<Baudrate>
+
+For Modbus/RTU, specifies the baud rate of the serial device.
+Note, connections currently support only 8/N/1.
=item B<Interval> I<Interval>
=item E<lt>B<Slave> I<ID>E<gt>
-Over each TCP connection, multiple Modbus devices may be reached. The slave ID
+Over each connection, multiple Modbus devices may be reached. The slave ID
is used to specify which device should be addressed. For each device you want
to query, one B<Slave> block must be given.
diff --git a/src/modbus.c b/src/modbus.c
index 795465f041d2a1962ea270ff40cd456771089394..589193811c3a827514a9a5d008ea6c3be419cb8e 100644 (file)
--- a/src/modbus.c
+++ b/src/modbus.c
* <Host "name">
* Address "addr"
* Port "1234"
+ * # Or:
+ * # Device "/dev/ttyUSB0"
+ * # Baudrate 38400
+ * # (Assumes 8N1)
* Interval 60
*
* <Slave 1>
typedef enum mb_register_type_e mb_register_type_t;
typedef enum mb_mreg_type_e mb_mreg_type_t;
+/* TCP or RTU depending on what is specified in host config block */
+enum mb_conntype_e /* {{{ */
+{
+ MBCONN_TCP,
+ MBCONN_RTU
+}; /* }}} */
+typedef enum mb_conntype_e mb_conntype_t;
+
struct mb_data_s;
typedef struct mb_data_s mb_data_t;
struct mb_data_s /* {{{ */
struct mb_host_s /* {{{ */
{
char host[DATA_MAX_NAME_LEN];
- char node[NI_MAXHOST];
+ char node[NI_MAXHOST]; /* TCP hostname or RTU serial device */
/* char service[NI_MAXSERV]; */
- int port;
+ int port; /* for Modbus/TCP */
+ int baudrate; /* for Modbus/RTU */
+ mb_conntype_t conntype;
cdtime_t interval;
mb_slave_t *slaves;
/* We'll do the error handling ourselves. */
modbus_set_error_handling (&host->connection, NOP_ON_ERROR);
- if ((host->port < 1) || (host->port > 65535))
- host->port = MODBUS_TCP_DEFAULT_PORT;
+ if (host->conntype == MBCONN_TCP)
+ {
+ if ((host->port < 1) || (host->port > 65535))
+ host->port = MODBUS_TCP_DEFAULT_PORT;
- DEBUG ("Modbus plugin: Trying to connect to \"%s\", port %i.",
- host->node, host->port);
+ DEBUG ("Modbus plugin: Trying to connect to \"%s\", port %i.",
+ host->node, host->port);
- modbus_init_tcp (&host->connection,
- /* host = */ host->node,
- /* port = */ host->port);
+ modbus_init_tcp (&host->connection,
+ /* host = */ host->node,
+ /* port = */ host->port);
+ }
+ else /* MBCONN_RTU */
+ {
+ DEBUG ("Modbus plugin: Trying to connect to \"%s\".", host->node);
+
+ modbus_init_rtu (&host->connection,
+ /* device = */ host->node,
+ /* baudrate = */ host->baudrate,
+ 'N', 8, 1, 0);
+ }
status = modbus_connect (&host->connection);
if (status != 0)
{
ERROR ("Modbus plugin: modbus_connect (%s, %i) failed with status %i.",
- host->node, host->port, status);
+ host->node, host->port ? host->port : host->baudrate, status);
return (status);
}
if (host->connection != NULL)
return (0);
- if ((host->port < 1) || (host->port > 65535))
- host->port = MODBUS_TCP_DEFAULT_PORT;
+ if (host->conntype == MBCONN_TCP)
+ {
+ if ((host->port < 1) || (host->port > 65535))
+ host->port = MODBUS_TCP_DEFAULT_PORT;
- DEBUG ("Modbus plugin: Trying to connect to \"%s\", port %i.",
- host->node, host->port);
+ DEBUG ("Modbus plugin: Trying to connect to \"%s\", port %i.",
+ host->node, host->port);
- host->connection = modbus_new_tcp (host->node, host->port);
- if (host->connection == NULL)
+ host->connection = modbus_new_tcp (host->node, host->port);
+ if (host->connection == NULL)
+ {
+ ERROR ("Modbus plugin: Creating new Modbus/TCP object failed.");
+ return (-1);
+ }
+ }
+ else
{
- ERROR ("Modbus plugin: Creating new Modbus/TCP object failed.");
- return (-1);
+ DEBUG ("Modbus plugin: Trying to connect to \"%s\", baudrate %i.",
+ host->node, host->baudrate);
+
+ host->connection = modbus_new_rtu (host->node, host->baudrate, 'N', 8, 1);
+ if (host->connection == NULL)
+ {
+ ERROR ("Modbus plugin: Creating new Modbus/RTU object failed.");
+ return (-1);
+ }
}
modbus_set_debug (host->connection, 1);
if (status != 0)
{
ERROR ("Modbus plugin: modbus_connect (%s, %i) failed with status %i.",
- host->node, host->port, status);
+ host->node, host->port ? host->port : host->baudrate, status);
modbus_free (host->connection);
host->connection = NULL;
return (status);
{
status = EBADF;
}
- else
+ else if (host->conntype == MBCONN_TCP)
{
struct sockaddr sockaddr;
socklen_t saddrlen = sizeof (sockaddr);
status = cf_util_get_string_buffer (child, buffer, sizeof (buffer));
if (status == 0)
status = mb_config_set_host_address (host, buffer);
+ if (status == 0)
+ host->conntype = MBCONN_TCP;
}
else if (strcasecmp ("Port", child->key) == 0)
{
if (host->port <= 0)
status = -1;
}
+ else if (strcasecmp ("Device", child->key) == 0)
+ {
+ status = cf_util_get_string_buffer (child, host->node, sizeof (host->node));
+ if (status == 0)
+ host->conntype = MBCONN_RTU;
+ }
+ else if (strcasecmp ("Baudrate", child->key) == 0)
+ status = cf_util_get_int(child, &host->baudrate);
else if (strcasecmp ("Interval", child->key) == 0)
status = cf_util_get_cdtime (child, &host->interval);
else if (strcasecmp ("Slave", child->key) == 0)
} /* for (i = 0; i < ci->children_num; i++) */
assert (host->host[0] != 0);
- if (host->host[0] == 0)
+ if (host->node[0] == 0)
{
- ERROR ("Modbus plugin: Data block \"%s\": No type has been specified.",
+ ERROR ("Modbus plugin: Data block \"%s\": No address or device has been specified.",
+ host->host);
+ status = -1;
+ }
+ if (host->conntype == MBCONN_RTU && !host->baudrate)
+ {
+ ERROR ("Modbus plugin: Data block \"%s\": No serial baudrate has been specified.",
+ host->host);
+ status = -1;
+ }
+ if ((host->conntype == MBCONN_TCP && host->baudrate) ||
+ (host->conntype == MBCONN_RTU && host->port))
+ {
+ ERROR ("Modbus plugin: Data block \"%s\": You've mixed up RTU and TCP options.",
host->host);
status = -1;
}