Heatmapping your home with digitemp
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.