We have installed underfloor heating in our House-on-Hudson, there are 14 independent loops, of various length, and one circulation pump. Two Manifolds with individual valves connects the input and output for each loop, each have a very bad flow-meter, and possibility for a motor-valves. Hence it would be possible to control the heat delivery independently for each loop under computer control, if you so desire, I don’t (at the moment).
Normally what people do is to tune the system once, when it is installed, so that heat is distributed evenly to all loops, using the flow meters as guide. I do this by adjusting the system so that the return temperature on all the loops will be more or less the same. This has the added benefit that the temperature of the water returning to the boiler is as low as possible, on a condensing-boiler, this gives a very good economy.
I read the temperatures with 14 ds18b20, you can get them on amazon or ebay for less than $2 a piece, The brain is a Raspberry Pi $20-$35 (any A/A+/B/B+ will do), USB wifi $3 on Ebay, SD-card $5, USB-charger $5. The total is less than $60. If you want a screen on it too, a 4.3″ car dvd-lcd will set you back less than $15.
Linux and the Raspberry Pi has good support for one-wire devices, just connect them to the right pin, all in parallel, add a pullup resistor and the hardware part is done with.
For the software, I like to do most of my work on the commandline, using one-liners, It is amazing what you can do in one line. Let us play around a bit:
pi@raspa ~ $ cd /sys/bus/w1/devices pi@raspa /sys/bus/w1/devices $ ls -l total 0 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e1305b -> ../../../devices/w1_bus_master1/28-000003e1305b lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e13462 -> ../../../devices/w1_bus_master1/28-000003e13462 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e139e2 -> ../../../devices/w1_bus_master1/28-000003e139e2 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e13cf9 -> ../../../devices/w1_bus_master1/28-000003e13cf9 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e144b0 -> ../../../devices/w1_bus_master1/28-000003e144b0 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e147b1 -> ../../../devices/w1_bus_master1/28-000003e147b1 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e15681 -> ../../../devices/w1_bus_master1/28-000003e15681 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e15f03 -> ../../../devices/w1_bus_master1/28-000003e15f03 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e16853 -> ../../../devices/w1_bus_master1/28-000003e16853 lrwxrwxrwx 1 root root 0 Nov 10 12:17 28-000003e169ff -> ../../../devices/w1_bus_master1/28-000003e169ff lrwxrwxrwx 1 root root 0 Nov 10 12:50 28-000003e1729e -> ../../../devices/w1_bus_master1/28-000003e1729e lrwxrwxrwx 1 root root 0 Nov 10 12:50 28-000003e173a0 -> ../../../devices/w1_bus_master1/28-000003e173a0 lrwxrwxrwx 1 root root 0 Nov 10 12:50 28-000003e1752d -> ../../../devices/w1_bus_master1/28-000003e1752d lrwxrwxrwx 1 root root 0 Nov 10 12:50 28-000003e17b6c -> ../../../devices/w1_bus_master1/28-000003e17b6c lrwxrwxrwx 1 root root 0 Nov 10 12:17 w1_bus_master1 -> ../../../devices/w1_bus_master1 pi@raspa /sys/bus/w1/devices $ cat 28-000003e1305b/w1_slave 40 01 4b 46 7f ff 10 10 1d : crc=1d YES 40 01 4b 46 7f ff 10 10 1d t=20000 pi@raspa /sys/bus/w1/devices $
You see 14 sensors, the temperature on the first one is 20 degree Celcius.
I have made a little script which also does a little data-compression, in a still human-readable way. The main reason is that if there is activity on a single sensor, it is easy to spot.
#!/bin/bash # Read all the ds18b20 and append data to templog # Trying to be nice to flash-drive we work in /tmp/ow which is supposed to be on ramdisk # we copy data to permanent storage every hour. # # IDS:ID_1:ID_2:... where ID_? is the last 4 digits of the ds18b20 address # epoch:t1*1000:t2*1000:... # +12:+1:-3 difference since last full reading, -3 = -3*62.5 # # the following awk-script will "unpack" it # awk -F: ' # /^[0-9]/ { # epoch=$1; # print $0; # for (i=2;i<=NF;i++) base[i]=$i; # } # /^+/ { # printf("%d",epoch+$1); # for (i=2;i<=NF;i++) printf(":%d",base[i]+$i*62.5); # printf "\n"; # }' # WORK=/tmp/ow PERM=/home/ow MAX_DIFF=500 # +/- 0.5 Celcius MAX_SECS=600 # 10 minutter DS18B20_BASE=28-000003e1 declare -g -A TEMPS save_and_roll_log() # $HOUR_last $HOUR { DIR=`dirname $1` FILE=`basename $1` mkdir -p $PERM/$DIR if [ -L $PERM/$1 ]; then rm -f $PERM/$1 fi if [ -f $WORK/$FILE ]; then mv $WORK/$FILE $PERM/$1 fi DIR=`dirname $2` FILE=`basename $2` mkdir -p $WORK mkdir -p $PERM/$DIR rm -f $PERM/$2 ln -s $WORK/$FILE $PERM/$2 LOG=$WORK/$FILE } wr_log() { if [ x$VERBOSE != x ]; then echo $* fi echo $* >> $LOG } cd /sys/bus/w1/devices IDS_last=x HOUR_last=x ATTEMPT_last=x EPOCH_last=`date +%s` sec=0 while true;do ATTEMPT=`cat w1_bus_master1/w1_master_attempts` if [ $ATTEMPT = $ATTEMPT_last ];then sleep 1 continue fi ATTEMPT_last=$ATTEMPT EPOCH=`date +%s` HOUR=`date +%Y/%m/%d/%Y%m%d%H` if [ $HOUR != $HOUR_last ]; then save_and_roll_log $HOUR_last $HOUR HOUR_last=$HOUR IDS_last=x # start new fi DEVS=`sort w1_bus_master1/w1_master_slaves` IDS=`echo $DEVS | sed -e "s,$DS18B20_BASE,,g" -e 's/ /:/g'` sec=$(($EPOCH - $EPOCH_last)) if [ $IDS != $IDS_last -o $sec -gt $MAX_SECS ]; then ALL=1 else ALL=0 fi TS="" IDS_="" CHANGED=0 for i in $DEVS; do ID="" T=`awk -F= '/NO/ {print "%";exit} /t=/ {print $2}' < $i/w1_slave` if [ x$T = x -o x$T = x% ]; then T="%" elif [ x$T = x85000 ]; then T="%" elif [ $ALL = 1 ]; then TEMPS[$i]=$T elif [ x${TEMPS[$i]} != x ]; then # differential coding DIFF=$(($T-${TEMPS[$i]})) #echo "$i: $T-${TEMPS[$i]}=$DIFF" if [ $DIFF = 0 ]; then T="" elif [ $DIFF -gt -$MAX_DIFF -a $DIFF -lt $MAX_DIFF ]; then T="$(($DIFF/62))" else TEMPS[$i]=$T # only update when change is more than $MAX_DIFF ID=`echo $i | sed "s,$DS18B20_BASE,,g"` CHANGED=1 fi else TEMPS[$i]=$T fi TS=$TS:$T IDS_=$IDS_:$ID done if [ $CHANGED = 1 ]; then wr_log IDS_$IDS_ fi if [ $IDS != $IDS_last ]; then wr_log IDS:$IDS IDS_last="$IDS" fi if [ $ALL = 1 ]; then wr_log "$EPOCH$TS" EPOCH_last=$EPOCH else wr_log "+$sec$TS" fi done
Here is how the output looks like
pi@raspa ~ $ head -24 ../ow/2014/12/03/2014120305 IDS:305b:3462:39e2:3cf9:44b0:5681:5f03:6853:69ff:729e:73a0:752d:7b6c 1417600809:19437:19437:36687:19500:36562:19437:19625:19437:19562:19812:19312:18750:19437 +11:1::1::1:::1:-1:::: +22:1::1::1:::1::::1: +33:1::2::1:::1::::: +44:1::2::2:1::1::::1: +56:1::3::2:1:%:::::1:1 +67:1::3::2:1:1:1:::1:1:1 +78:1::3::3:1:1:1:::1:1:1 +89:1:1:4:1:3:1:1:1:1:::1:1 +100:2:1:%:1:3:1:1:1:1:1::1:1 +111:1:1:4:1:4:1:1:1:1:1:1:1:1 +123:2:1:5:1:4:1:1:2:1:1::1:1 +134:2:2:5:1:4:2:1:2:1:1:%:1:2 +145:2:2:6:1:5:2:2:1:1:1:1:1:1 +156:2:1:6:1:5:2:2:2:1:1:1:1:% +167:2:2:7:1:5:2:2:2:1:1:1:2:2 +178:2:2:7:1:%:2:2:2:%:1:1:2:2 +190:2:1:7:2:6:%:2:2:2:2:2:2:1 IDS_:::39e2:::::::::: +201:2:2:37187:2:6:2:2:3:2:1:1:1:2 +212:3:2::2:6:2:2:2:2:2:2:2:2 +223:3:2::2:6:2:2:3:2:2:2:2:2 +234:3:2::2:6:3:2:3:2:2:2:2:3
You see that every 11-12 seconds a new set of values is ready, and not much is changing, only sensor 39e2 has changed more than half a degree Celcius.
Below decoder in awk, and the result:
pi@raspa ~ $ head -24 ../ow/2014/12/03/2014120305 |awk -F: ' /^I/ { print $0; } /^[0-9]/ { epoch=$1; print $0; for (i=2;i<=NF;i++) base[i]=$i; } /^+/ { printf("%d",epoch+$1); for (i=2;i<=NF;i++) printf(":%d",(base[i]+$i*62.5)); printf "\n"; }' IDS:305b:3462:39e2:3cf9:44b0:5681:5f03:6853:69ff:729e:73a0:752d:7b6c 1417600809:19437:19437:36687:19500:36562:19437:19625:19437:19562:19812:19312:18750:19437 1417600820:19499:19437:36749:19500:36624:19437:19625:19499:19499:19812:19312:18750:19437 1417600831:19499:19437:36749:19500:36624:19437:19625:19499:19562:19812:19312:18812:19437 1417600842:19499:19437:36812:19500:36624:19437:19625:19499:19562:19812:19312:18750:19437 1417600853:19499:19437:36812:19500:36687:19499:19625:19499:19562:19812:19312:18812:19437 1417600865:19499:19437:36874:19500:36687:19499:19625:19437:19562:19812:19312:18812:19499 1417600876:19499:19437:36874:19500:36687:19499:19687:19499:19562:19812:19374:18812:19499 1417600887:19499:19437:36874:19500:36749:19499:19687:19499:19562:19812:19374:18812:19499 1417600898:19499:19499:36937:19562:36749:19499:19687:19499:19624:19812:19312:18812:19499 1417600909:19562:19499:36687:19562:36749:19499:19687:19499:19624:19874:19312:18812:19499 1417600920:19499:19499:36937:19562:36812:19499:19687:19499:19624:19874:19374:18812:19499 1417600932:19562:19499:36999:19562:36812:19499:19687:19562:19624:19874:19312:18812:19499 1417600943:19562:19562:36999:19562:36812:19562:19687:19562:19624:19874:19312:18812:19562 1417600954:19562:19562:37062:19562:36874:19562:19750:19499:19624:19874:19374:18812:19499 1417600965:19562:19499:37062:19562:36874:19562:19750:19562:19624:19874:19374:18812:19437 1417600976:19562:19562:37124:19562:36874:19562:19750:19562:19624:19874:19374:18875:19562 1417600987:19562:19562:37124:19562:36562:19562:19750:19562:19562:19874:19374:18875:19562 1417600999:19562:19499:37124:19625:36937:19437:19750:19562:19687:19937:19437:18875:19499 IDS_::::39e2:::::::::: 1417601010:19562:19562:2360874:19625:36937:19562:19750:19624:19687:19874:19374:18812:19562 1417601021:19624:19562:36687:19625:36937:19562:19750:19562:19687:19937:19437:18875:19562 1417601032:19624:19562:36687:19625:36937:19562:19750:19624:19687:19937:19437:18875:19562 1417601043:19624:19562:36687:19625:36937:19624:19750:19624:19687:19937:19437:18875:19624 pi@raspa ~ $
This little awk-script will format it even more human readable
#!/bin/sh cat $* |awk -F: ' /^[0-9]/ {sec=epoch=$1} /^+/ {sec=epoch+$1} /^IDS/ { changed=1; for (i=2;i<=NF;i++) { sensor[i]=$i; } next } changed==1 { changed=0; printf("%s ",strftime("%H:%M %d.%b %Y ", sec)); for (i=2;i<=NF;i++) { if (sensor[i] != "") { printf("%4s=%2.1f ", sensor[i], $i/1000); sensor[i]=""; } else { printf(" "); } } printf("\n"); }'
You must be logged in to post a comment.