Reading Maxim 1-Wire Temperature Sensors
By
Noah Crowley /
Use Cases, Product, Developer
Sep 05, 2019
Navigate to:
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
Telegraf’s 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 /etc/telegraf/telegraf.conf
:
# # 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.
When reading temperatures using gopsutil, the library generates a SensorKey using data from the filesystem, including a label
file. This is what the kernel documentation has to say about those files:
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 commands
parameter:
# # 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.
Future improvements
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!