One of my favorite sensors is the Maxim DS18*20 series, a variety of inexpensive temperature sensors which communicate over a “single contact serial interface” called 1-Wire. I’ve been integrating them into a variety of projects for years now, and they’ve always been reliable, accurate, and extremely easy to use. That’s partly due to their use of a single contact for communication — valuable when you’re looking to save pins on an embedded computer or microcontroller — but also because of the built in
w1_therm driver in the Linux kernel, which means they’ll work on any Linux machine with the appropriate physical interface.
For the sake of example, we’ll use a Raspberry Pi with a DS18B20 connected to the GPIO pins. You can find a wiring diagram in this blog post. We’ll load the
w1_therm kernel module as well as the
w1_gpio module, which uses the GPIO API to provide a 1-Wire interface:
modprobe w1_gpio modprobe w1_therm
With the kernel modules enabled, the sensor is now accessible through the sysfs interface as individual directories. We can use the
ls command with some wildcards to find information about our sensors:
$ ls -laH /sys/class/hwmon/hwmon* total 0 drwxr-xr-x 3 root root 0 Apr 24 23:59 . drwxr-xr-x 3 root root 0 Apr 24 23:59 .. lrwxrwxrwx 1 root root 0 Apr 24 23:59 device -> ../../../28-000002e36be9 -r--r--r-- 1 root root 4096 Apr 24 23:59 name drwxr-xr-x 2 root root 0 Apr 24 23:59 power lrwxrwxrwx 1 root root 0 Apr 24 23:59 subsystem -> ../../../../../class/hwmon -r--r--r-- 1 root root 4096 Apr 24 23:59 temp1_input -rw-r--r-- 1 root root 4096 Apr 24 23:59 uevent
Within this directory you’ll find a variety of files, including a symlink to the device itself, the sensor name, and a file called
temp1_input, which you can read to get the temperature of the sensor in units of Celsius*1000:
$ cat /sys/class/hwmon/hwmon0/temp1_input 27562
In addition, you can access more info about the sensor by reading the
/sys/class/hwmon/hwmon0/device/w1_slave file, which looks something like this:
$ cat /sys/class/hwmon/hwmon0/device/w1_slave bb 01 4b 46 7f ff 05 10 c6 : crc=c6 YES bb 01 4b 46 7f ff 05 10 c6 t=27678
This shows the output of the device in hex on the left, with the results of the CRC error checking and temperature reading on the right.
Telegraf’s Temp plugin
temp input plugin reads data about temperature sensors from the filesystem during each collection. You can install Telegraf and InfluxDB on a Raspberry Pi using the official InfluxData repositories. Once installed, we can configure Telegraf by uncommenting the following section in
# # Read metrics about temperature [[inputs.temp]] # # no configuration
Since there is no configuration beyond enabling the plugin, we can restart Telegraf and we should see data begin to appear in the
temp measurement of the
telegraf database (since we’re using the configuration defaults.)
Using multiple sensors
Unfortunately, there is one shortcoming with the current implementation of the temp plugin: it only supports a single sensor. This is because of an issue with the DS18*20 sensors and the library that Telegraf’s
temp plugin uses to access the filesystem: gopsutil.
temp[1-*]_label Suggested temperature channel label. Text string Should only be created if the driver has hints about what this temperature channel is being used for, and user-space doesn't. In all other cases, the label is provided by user-space. RO
Because the application of a DS18B20 and other similar sensors can vary, the driver is generic and does not have any information about what the temperature channel is being used for, so this file is not created. That means when Telegraf collects data from multiple sensors their tag values are identical, as they all have the same
SensorKey. So even though we’re collecting data from each sensor, the data points have the same metadata and timestamp, and so will overwrite one another. We can verify this by running Telegraf using the
--test argument, which will print the line protocol to the command line.
Multiple sensor workaround using Python
One way we can work around this issue is by using a Python script to read the data (you can find an example gist here), and Telegraf’s
exec plugin to execute the script.
Download the script and copy it to a more permanent location; for now, let’s drop the file in
/usr/local/bin. Because we installed Telegraf using the official InfluxData repository, Telegraf runs as the
telegraf user, which means we’ll also want to change the permissions on the script so it can be executed by Telegraf, as follows:
sudo chown telegraf:telegraf /usr/local/bin/read_multiple_ds18b20.py $ sudo chmod 755 /usr/local/bin/read_multiple_ds18b20.py
Then we can configure Telegraf’s
exec plugin to execute the script by enabling the plugin and adding the file to the
# # Read metrics from one or more commands that can output to stdout [[inputs.exec]] # ## Commands array commands = [ "/usr/local/bin/read_multiple_ds18b20.py" ]
The full configuration file is here, and includes the comments that describe the default values. Since multiple DS18B20s can share a single data line, connecting an additional device is fairly straightforward: it will share the connections to ground, power, and data that the first sensor uses. Restart telegraf and it should start collecting data from each device.
I have a few applications in mind that use multiple temperature sensors per device, so it would be nice to iterate on the built-in
temp plugin if possible, rather than relying on our Python script workaround.
One possibility would be to make a small change to the gopsutil library which would add an additional field to the
SensorKey struct for the device name (unique for each DS18*20). Telegraf could then use that field to add an additional tag to the data and prevent the points from overwriting each other. I’m going to put together a Pull Request and get some feedback from the gopsutil maintainers. In the meantime, feel free to use my Python script, and reach out on our community site or to me directly at [email protected] or on Twitter @noahcrowley if you have any issues!