From: Florian Forster Date: Wed, 23 Jul 2008 14:44:40 +0000 (+0200) Subject: onewire plugin: Add a plugin to read onewire sensors. X-Git-Tag: collectd-4.5.0~94^2~1 X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=11ba6e7c5a57c9bb73f389cfaf79b50b56b7544f;p=collectd.git onewire plugin: Add a plugin to read onewire sensors. This plugin allows to read _temperature_ sensors connected over a onewire bus using the `owcapi' library from the `owfs' project. Other sensors can be added easily, but without hardware to test this it's kind of hard to be sure it all works. ToDo's: Document the plugin, make the `Alias' configuration option work. --- diff --git a/configure.in b/configure.in index 2be53f65..a67f2a11 100644 --- a/configure.in +++ b/configure.in @@ -1450,6 +1450,52 @@ fi AM_CONDITIONAL(BUILD_WITH_LIBOPING, test "x$with_liboping" = "xyes") AM_CONDITIONAL(BUILD_WITH_OWN_LIBOPING, test "x$with_own_liboping" = "xyes") +with_libowcapi_cppflags="" +with_libowcapi_libs="-lowcapi" +AC_ARG_WITH(libowcapi, [AS_HELP_STRING([--with-libowcapi@<:@=PREFIX@:>@], [Path to libowcapi.])], +[ + if test "x$withval" != "xno" && test "x$withval" != "xyes" + then + with_libowcapi_cppflags="-I$withval/include" + with_libowcapi_libs="-L$withval/lib -lowcapi" + with_libowcapi="yes" + else + with_libowcapi="$withval" + fi +], +[ + with_libowcapi="yes" +]) +if test "x$with_libowcapi" = "xyes" +then + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$with_libowcapi_cppflags" + + AC_CHECK_HEADERS(owcapi.h, [with_libowcapi="yes"], [with_libowcapi="no (owcapi.h not found)"]) + + CPPFLAGS="$SAVE_CPPFLAGS" +fi +if test "x$with_libowcapi" = "xyes" +then + SAVE_LDFLAGS="$LDFLAGS" + SAVE_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$with_libowcapi_libs" + CPPFLAGS="$with_libowcapi_cppflags" + + AC_CHECK_LIB(owcapi, OW_get, [with_libowcapi="yes"], [with_libowcapi="no (libowcapi not found)"]) + + LDFLAGS="$SAVE_LDFLAGS" + CPPFLAGS="$SAVE_CPPFLAGS" +fi +if test "x$with_libowcapi" = "xyes" +then + BUILD_WITH_LIBOWCAPI_CPPFLAGS="$with_libowcapi_cppflags" + BUILD_WITH_LIBOWCAPI_LIBS="$with_libowcapi_libs" + AC_SUBST(BUILD_WITH_LIBOWCAPI_CPPFLAGS) + AC_SUBST(BUILD_WITH_LIBOWCAPI_LIBS) +fi + + AC_ARG_WITH(libpcap, [AS_HELP_STRING([--with-libpcap@<:@=PREFIX@:>@], [Path to libpcap.])], [ if test "x$withval" != "xno" && test "x$withval" != "xyes" @@ -2618,6 +2664,7 @@ AC_PLUGIN([nginx], [$with_libcurl], [nginx statistics]) AC_PLUGIN([notify_email], [$with_libesmtp], [Email notifier]) AC_PLUGIN([ntpd], [yes], [NTPd statistics]) AC_PLUGIN([nut], [$with_libupsclient], [Network UPS tools statistics]) +AC_PLUGIN([onewire], [$with_libowcapi], [OneWire sensor statistics]) AC_PLUGIN([perl], [$plugin_perl], [Embed a Perl interpreter]) AC_PLUGIN([ping], [$with_liboping], [Network latency statistics]) AC_PLUGIN([postgresql], [$with_libpq], [PostgreSQL database statistics]) @@ -2785,6 +2832,7 @@ Configuration: notify_email . . . . $enable_notify_email ntpd . . . . . . . . $enable_ntpd nut . . . . . . . . . $enable_nut + onewire . . . . . . . $enable_onewire perl . . . . . . . . $enable_perl ping . . . . . . . . $enable_ping postgresql . . . . . $enable_postgresql diff --git a/src/Makefile.am b/src/Makefile.am index 3d8b1466..9962c0d0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -507,6 +507,17 @@ collectd_LDADD += "-dlopen" nut.la collectd_DEPENDENCIES += nut.la endif +if BUILD_PLUGIN_ONEWIRE +pkglib_LTLIBRARIES += onewire.la +onewire_la_SOURCES = onewire.c +onewire_la_CFLAGS = $(AM_CFLAGS) +onewire_la_CPPFLAGS = $(BUILD_WITH_LIBOWCAPI_CPPFLAGS) +onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS) +onewire_la_LDFLAGS = -module -avoid-version +collectd_LDADD += "-dlopen" onewire.la +collectd_DEPENDENCIES += onewire.la +endif + if BUILD_PLUGIN_PERL pkglib_LTLIBRARIES += perl.la perl_la_SOURCES = perl.c diff --git a/src/onewire.c b/src/onewire.c new file mode 100644 index 00000000..2b670de0 --- /dev/null +++ b/src/onewire.c @@ -0,0 +1,306 @@ +/** + * collectd - src/owfs.c + * Copyright (C) 2008 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" +#include "utils_ignorelist.h" + +#include + +#define OW_FAMILY_MAX_FEATURES 2 +struct ow_family_features_s +{ + char *family; + struct + { + char filename[DATA_MAX_NAME_LEN]; + char type[DATA_MAX_NAME_LEN]; + char type_instance[DATA_MAX_NAME_LEN]; + } features[OW_FAMILY_MAX_FEATURES]; + size_t features_num; +}; +typedef struct ow_family_features_s ow_family_features_t; + +/* see http://owfs.sourceforge.net/ow_table.html for a list of families */ +static ow_family_features_t ow_family_features[] = +{ + { + /* family = */ "10", + { + { + /* filename = */ "temperature", + /* type = */ "temperature", + /* type_instance = */ "" + } + }, + /* features_num = */ 1 + } +}; +static int ow_family_features_num = STATIC_ARRAY_SIZE (ow_family_features); + +static char *device_g = NULL; + +static const char *config_keys[] = +{ + "Alias", + "Device", + "IgnoreSelected", + "Sensor", +}; +static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); + +static ignorelist_t *sensor_list; + +static int cow_load_config (const char *key, const char *value) +{ + if (sensor_list == NULL) + sensor_list = ignorelist_create (1); + + if (strcasecmp (key, "Sensor") == 0) + { + if (ignorelist_add (sensor_list, value)) + { + ERROR ("sensors plugin: " + "Cannot add value to ignorelist."); + return (1); + } + } + else if (strcasecmp (key, "IgnoreSelected") == 0) + { + ignorelist_set_invert (sensor_list, 1); + if ((strcasecmp (value, "True") == 0) + || (strcasecmp (value, "Yes") == 0) + || (strcasecmp (value, "On") == 0)) + ignorelist_set_invert (sensor_list, 0); + } + else if (strcasecmp (key, "Device") == 0) + { + char *temp; + temp = strdup (value); + if (temp == NULL) + { + ERROR ("onewire plugin: strdup failed."); + return (1); + } + sfree (device_g); + device_g = temp; + } + else if (strcasecmp (key, "Alias") == 0) + { + /* azogtodo alias-list */ + } + else + { + return (-1); + } + + return (0); +} + +static int cow_init (void) +{ + int status; + + if (device_g == NULL) + { + ERROR ("onewire plugin: cow_init: No device configured."); + return (-1); + } + + status = (int) OW_init (device_g); + if (status != 0) + { + ERROR ("onewire plugin: OW_init(%s) failed: %i.", device_g, status); + return (1); + } + + return (0); +} /* int cow_init */ + +static int cow_read_values (const char *path, const char *name, + const ow_family_features_t *family_info) +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + int success = 0; + size_t i; + + if (sensor_list != NULL) + { + DEBUG ("onewire plugin: Checking ignorelist for `%s'", name); + if (ignorelist_match (sensor_list, name) != 0) + return 0; + } + + vl.values = values; + vl.values_len = 1; + vl.time = time (NULL); + + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "onewire", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, name, sizeof (vl.plugin_instance)); + + for (i = 0; i < family_info->features_num; i++) + { + char *buffer; + size_t buffer_size; + int status; + + char file[4096]; + char *endptr; + + snprintf (file, sizeof (file), "%s/%s", + path, family_info->features[i].filename); + file[sizeof (file) - 1] = 0; + + buffer = NULL; + buffer_size = 0; + status = OW_get (file, &buffer, &buffer_size); + if (status < 0) + { + ERROR ("onewire plugin: OW_get (%s/%s) failed. status = %#x;", + path, family_info->features[i].filename, status); + return (-1); + } + + endptr = NULL; + values[0].gauge = strtod (buffer, &endptr); + if (endptr == NULL) + { + ERROR ("onewire plugin: Buffer is not a number: %s", buffer); + status = -1; + continue; + } + + sstrncpy (vl.type, family_info->features[i].type, sizeof (vl.type)); + sstrncpy (vl.type_instance, family_info->features[i].type_instance, + sizeof (vl.type_instance)); + + plugin_dispatch_values (&vl); + success++; + + free (buffer); + } /* for (i = 0; i < features_num; i++) */ + + return ((success > 0) ? 0 : -1); +} /* int cow_read_values */ + +static int cow_read_bus (const char *path) +{ + char *buffer; + size_t buffer_size; + int status; + + char *buffer_ptr; + char *dummy; + char *saveptr; + char subpath[4096]; + char family_dummy[3]; /* a family only has 2 digits */ + + status = OW_get (path, &buffer, &buffer_size); + if (status < 0) + { + ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;", + path, status); + return (-1); + } + + dummy = buffer; + saveptr = NULL; + while ((buffer_ptr = strtok_r (dummy, ",/", &saveptr)) != NULL) + { + int i; + + dummy = NULL; + + snprintf (subpath, sizeof (subpath), "%s/%s", path, buffer_ptr); + subpath[sizeof (subpath) - 1] = 0; + + for (i = 0; i < ow_family_features_num; i++) + { + snprintf (family_dummy, sizeof (family_dummy), "%s%s", ow_family_features[i].family, "."); + if (strncmp (family_dummy, buffer_ptr, strlen (family_dummy)) != 0) + continue; + + cow_read_values (subpath, buffer_ptr + 3, ow_family_features + i); + } + } /* while (strtok_r) */ + + free (buffer); + return (0); +} /* int cow_read_bus */ + +static int cow_read (void) +{ + char *buffer; + size_t buffer_size; + int status; + + char *buffer_ptr; + char *dummy; + char *saveptr; + + status = OW_get ("/uncached/", &buffer, &buffer_size); + if (status < 0) + { + ERROR ("onewire plugin: OW_get (\"/\") failed. status = %#x;", + status); + return (-1); + } + + printf ("-- 8< --\n"); + + dummy = buffer; + saveptr = NULL; + while ((buffer_ptr = strtok_r (dummy, ",/", &saveptr)) != NULL) + { + dummy = NULL; + if (strncmp ("bus", buffer_ptr, strlen ("bus")) == 0) + { + cow_read_bus (buffer_ptr); + } + } /* while (strtok_r) */ + + printf ("-- >8 --\n"); + + free (buffer); + + return (0); +} /* int cow_read */ + +static int cow_shutdown (void) +{ + OW_finish (); + ignorelist_free (sensor_list); + return (0); +} /* int cow_shutdown */ + +void module_register (void) +{ + plugin_register_init ("onewire", cow_init); + plugin_register_read ("onewire", cow_read); + plugin_register_shutdown ("onewire", cow_shutdown); + plugin_register_config ("onewire", cow_load_config, + config_keys, config_keys_num); +} + +/* vim: set sw=2 sts=2 ts=8 et fdm=marker cindent : */