Heatmapping your home with digitemp

by Robin
May 30, 2014

After spending some time (quite a bit of it improving on my rusty soldering iron skills) setting up some temperature sensors around the home I came to the realization that I don't really care about graphs plotting the past temperature - I just want a pretty picture telling me how warm it is.

If this interests you, here are some pointers (instructions is really to big a word) to get you on your way to something similar.

My goal was to set up digitemp so that the output could be parsed into a scalable vector graphic representing my floor layout. This image would then be returned by my webserver whenever someone wants to see the temperature.

Set up your sensors and get some readouts

For some excellent instructions on setting up the sensors see here: http://www.instructables.com/id/Temperature-sensor--weatherstation/?ALLSTEPS. I can only recommend using the DS1820 sensors and digitemp, as getting everything running is really cheap - I bought everything twice not trusting my soldering skills and still had a BOM of < 20€. Also using telephone cable to wire everything up is also simple to do.

I ended up building the 'improved' serial connector which supplies power on a separate line instead of on the data line - as I wanted to make sure even if I run wires all over the place I will still get a stable connection. And because (as stated) using telephone cable meant I had some cables spare for the power line. See instructions here (German - but the schematics should be understandable): http://www.lax.priv.at/digitemp/

Once you are finished you should be able to run the folowing command to read the temperature output of your connected sensors.

----

digitemp -a

----

Create a SVG of your floor layout

A SVG is a scaleable vector graphic. The good thing about them is, that - uncompressed - they are simply xml files, which makes them extremely easy to change on the fly. Using Inkscape, I drew some lines representing my outer walls and then created grey rectangles for each room. The colour will be replaced by the temperature colour later. Make sure you only create one shape for each room - as that will make things easier later.

Then enter some text (e.g. two question marks) in each room - this will be replaced by the temperature as number.

Finally (not really necessary) I added a scale, displaying each temperature in 1 degree steps on top of a colour range representing each temperature.

If you are using Inkscape (or probably any SVG editor) you should now edit the IDs of your room shapes/rectangles to title<number> and tspan_<number>. Here each number corresponds to a room as identified by digitemp. (Just start with 0 and add 1 for each room - more on that later).

Because I am calling cthulhu and parsing the svg xml using a regex, we will need to make sure that the XML attributes are in the right order. The 'fill' attribute for the room shapes/rectangles needs to be just in front of their 'title id=title<number>' element.

My resulting SVG can be downloaded here, I assume that will clear things up.

Aside - convert temperature into a colour range

To make the temperature nice and easy to read, I wanted to replace the background colour of each room with a corresponding colour - red for hot, green for warm and blue for cold.

I did this by plotting the RGB values of the colour range I added to my SVG above and then created several linear functions to increase/decrease the individual RGB values to stay as close to the colour range as above. The following table describes my colour steps (which are entirely arbitrary)

Temperature

Red Value

Green Value

Blue Value

<11 FF 00 FF
<15.8 FF->00 00 FF
<19.82 00 00->FF FF
<21.41 00 FF FF->00
<26.92 00->FF FF 00
<32.11 FF FF->00 00
else FF 00 00

Combine everything for your webserver

To make it easier to read the digitemp output, I reconfigured the digitemprc file slightly to produce a very minimal output: <room number>:<temperature>.

----

TTY /dev/ttyUSB0
READ_TIME 1000
LOG_TYPE 1
LOG_FORMAT "%s:%.2C"
CNT_FORMAT "%m %d %H:%M:%S Sensor %s #%n %C"
HUM_FORMAT "%m %d %H:%M:%S Sensor %s C: %.2C H: %h%%"
SENSORS 4
ROM 0 0xAB 0xCD 0xEF 0x01 0x02 0x03 0x04 0x05 
ROM 1 0xAB 0xCD 0xEF 0x01 0x02 0x03 0x04 0x06 
ROM 2 0xAB 0xCD 0xEF 0x01 0x02 0x03 0x04 0x07
ROM 3 0xAB 0xCD 0xEF 0x01 0x02 0x03 0x04 0x08 

----

You will need to rearrange your sensors to fit in with the room numbering that you used in your svg above. To make that easier just hold each sensors in your hand for a few minutes before taking a new readout. The warm sensor will be in the room you are in.

As this was a quick hack, I simply ended up hooking up a bash script as a cgi response for my webserver.

The script calls digitemp using the config file above, and then creates color values for each temperature response.

The result is then passed into the svg which it assumes to be in the same directory.

----

#!/bin/bash

echo "Content-type: image/svg+xml; charset=UTF-8"
echo ""

# Get the SVG into a var
image=$(cat ./Grundriss.svg)

# First get temperatures into array temps
#digitemp -q -a -c /<location of your config file>/digitemprc
temps=$(digitemp -q -a -c /<location of your config file>/digitemprc)

# Now we build up a regex using these strings.
# fill:#949494">\n<title id="title0
# and id="tspan_0">??</tspan
for x in $temps
do
	id=$(echo $x | cut -f1 -d:)
	temp=$(echo $x | cut -f2 -d: | sed 's/\./\\./g')
	temp_num=$(echo $x | cut -f2 -d:)
	red="00"
	green="00"
	blue="00"
	if (( $(bc <<< "$temp_num < 11") == 1 )); then
		red="FF"
		green="00"
		blue="FF"
	elif (( $(bc <<< "$temp_num < 15.8") == 1)); then
		red=$(echo "obase=16; 255*-($temp_num-15.8)/4.8" | bc)
		printf -v red "%02X" "0x"$red
		green="00"
		blue="FF"
	elif (( $(bc <<< "$temp_num < 19.82") == 1)); then
		red="00"
		green=$(echo "obase=16; 255*($temp_num-15.8)/4.02" | bc)
		printf -v green "%02X" "0x"$green
		blue="FF"
	elif (( $(bc <<< "$temp_num < 21.41") == 1)); then 
		red="00"
		green="FF"
		blue=$(echo "obase=16; 255*-($temp_num-21.41)/1.59" | bc)
		printf -v blue "%02X" "0x"$blue
	elif (( $(bc <<< "$temp_num < 26.96") == 1)); then 
		red=$(echo "obase=16; 255*($temp_num-21.41)/5.55" | bc)
		printf -v red "%02X" "0x"$red
		green="FF"
		blue="00"
	elif (( $(bc <<< "$temp_num < 32.11") == 1)); then 
		red=="FF"
		green=$(echo "obase=16; 255*-($temp_num-32.11)/5.15" | bc)
		printf -v green "%02X" "0x"$green
		blue="00"
	else
		red="FF"
		green="00"
		blue="00"
	fi
	patterncf='fill:#949494"><title id="title'$id'">'
	patterncr='fill:#'$red$green$blue'"><title id="title'$id'">'
#	echo $patterncf
#	echo $patterncr
	image=$(sed -e s/"$patterncf"/"$patterncr"/g <(echo $image)) 
	
	patternf='id="tspan_'$id'">??<\/tspan'
	patternr='id="tspan_'$id'">'$temp'<\/tspan'
	image=$(sed -e s/"$patternf"/"$patternr"/g <(echo $image)) 
done

echo $image

exit 0

----

I have embedded the output as image in a web page. You can of course do something else with it.