1-wire with MQTT

Background

Over the last few weeks I’ve been experimenting with the Dallas 1-wire system for sensors around the house/garden. Although I originally thought of using Arduino/JeeNodes I couldn’t make the figures work. 1-wire may not be wireless, but it’s inexpensive, simple and robust. Basically, you need a run of 2/3-core wire with sensors on it where you need them: most people seem to use phone cable and RJ12 connectors. Each sensor has a unique address and for short’ish runs can all work on parasitic power from the bus – I got mine from HomeChip. They also do the bus controller that sits on one-end of the wire and has a usb connector so you can talk to the sensors on your server. By the way, it’s not all sensors, there’s A/D converters, switches etc and the bus is of course 2-way. See here for some idea of the things you can do.

Now this is great, and don’t get me wrong, of course you could run 1-wire sensors from an Arduino. What sold the more retro solution to me was the OWFS or 1-wire file system. This is a rather neat bit of software that turns your 1-wire bus sensor data into a file system. Neat! Now instead of an API etc, all the normal tools, scripts etc that work with files work with 1-wire and getting a temperature is as simple as reading the contents of

 /mnt/1wire/28.E1A6CC030000/temperature

Publishing to MQTT

A bit of installing and a modicum of soldering got me a working system on my Viglen MPC with a couple of sensors up and running. The common place to put the resulting data was into RDDTool, however it struck me that the filesystem idea in OWFS is a good match for the topic system in MQTT. I could simply push the file structure into MQTT and then subscribe to the topics that interest me, again using tools I already have and various cool ideas that I’ve read about on mqtt.org . And, as it’s two way, there’s nothing to stop me later using MQTT to publish data myself back to those same sensors or switches. Nothing of course stops me doing something else as well. In fact I’ve a cron job that spits everything into MySQL every 10 mins as well so I can analyse it in R stats later.

For the MQTT side, the only issue I had was to write a small Tcl library so that I could publish the data. That’s only because I like to use Tcl, there are already  libraries for Java, Perl and numerous others on Mqtt.org. Once I had a simple lib that could publish data at Qos 0, I just needed a simple script to find all the temperture sensors and publish their paths and values:

#!/usr/bin/env tclsh
lappend auto_path [pwd]
package require mqtt 1.0
#Using tcllib for 'cat', you could use open instead
package require fileutil
#Mount for 1-wire
set base "/mnt/1wire"
set mqtt_conn ""

#Get paths in this dir that are files
proc get_tree {d} {
 foreach s [glob -directory $d -types f *] {get_file $s}
 }
#Get contents of path
proc get_file {d} {
 global mqtt_conn
 set reading [string trim [fileutil::cat $d]]
 puts "Publishing $reading to $d"
 mqtt publish $mqtt_conn $d $reading
}

#Get all thermometers i.e. 28.xxxxxxxxxxx
proc get_thermometers {} {
global base
puts "Getting directories"
foreach d [exec find $base -maxdepth 1 -name 28.* ] {
#Get tree for each dir
 puts "Looking for $d"
 get_tree $d
 }
}

set mqtt_conn [mqtt connect localhost 1883 1Wire]
mqtt publish $mqtt_conn $base "[clock format [clock seconds]]"
get_thermometers
mqtt disconnect $mqtt_conn

With the RSMB broker running on the little Viglen MPC, which is called byron, which also has OWFS on, I could now publish my OWFS data and a test with stdoutsub tool on the laptop showed that I could see all the topics and data if I subscribed to /mnt/# .

./stdoutsub /mnt/# --host byron --qos 0

Fixing Aliases

One problem in the initial data was sensors are by default named by id and 28.2823FBE00300008A isn’t very semantic. Luckily, OWFS has an alias system that lets you link ids to human-readable names with a simple file. Once setup, it changes the OWFS file system and the folders magically get renamed to /office, /outside etc. Handily, if you’ve already got scripts talking sensor ids instead, they’ll still work as well!

All the Tcl script needed to use aliases was an initial look in /settings/alias/list for the list of sensors, rather than finding everything starting 28.* This gives a replacement get_thermometer() function like so:

proc get_thermometer {} {
global base
foreach d [exec cat "$base/settings/alias/list"] {
  set alias_dir "$base/[lindex [split $d =] 1]"
  get_tree $alias_dir
  }
}

If you run the script again you’ll get the more readable listing like so:

Publishing 28E1A6CC03000060 to /mnt/1wire/office/address
Publishing office to /mnt/1wire/office/alias
Publishing 60 to /mnt/1wire/office/crc8
Publishing 28 to /mnt/1wire/office/family
Publishing 21.5 to /mnt/1wire/office/fasttemp
Publishing E1A6CC030000 to /mnt/1wire/office/id
Publishing FFFFFFFFFFFFFFFF to /mnt/1wire/office/locator
Publishing 0 to /mnt/1wire/office/power
Publishing 60000003CCA6E128 to /mnt/1wire/office/r_address
Publishing 000003CCA6E1 to /mnt/1wire/office/r_id
Publishing FFFFFFFFFFFFFFFF to /mnt/1wire/office/r_locator
Publishing 21.4375 to /mnt/1wire/office/temperature
Publishing 21.5 to /mnt/1wire/office/temperature10
Publishing 21.5 to /mnt/1wire/office/temperature11
Publishing 21.4375 to /mnt/1wire/office/temperature12
Publishing 21.5 to /mnt/1wire/office/temperature9
Publishing 75 to /mnt/1wire/office/temphigh
Publishing 70 to /mnt/1wire/office/templow
Publishing DS18B20 to /mnt/1wire/office/type

As you can see, even a small temperature sensor puts out all sorts of data as well as the temperature in various resolutions. One of the beauties of the MQTT side is this complexity can be  simplified to just what’s required. So, by subscribing to /mnt/1wire/+/fasttemp for instance you get:

/mnt/1wire/outside/fasttemp 1
/mnt/1wire/office/fasttemp 21.5

Left to do.

There’s a few things left to do:

  • I’m only sending in Qos 0. It really needs to be Qos 1.
  • I need to set the Retained flag so last temperature is held.
  • I’m not sure I need everything from a sensor.
  • Subscribing is only the beginning – publishing is the end goal so I can interact with the 1-wire system.

But, it’s a start.

Resources.

If you’re interested in 1-wire and you’ve got Debian/Ubuntu, then be grateful to Cyril Lavier (@davromaniak) who has a neatly packaged repository otherwise get the sources from OWFS below and break out the build tools.

The Tcl script and simple MQTT lib at all here.

All the MQTT stuff is over at MQTT.org

All the OWFS stuff is at OWFS.org

I’ve since found out via Twitter that Nicholas Humphrey (@njh) has a fine daemon that does this directly. You can get his code from GitHub here.