I want to implement a Raspberry Pi controlled heating and hot water system. On the hot water side, the objectives are
The first step in this plan was to instrument our hot water system, see here for the details of that exercise.
As objective of this project is to switch on the hot water system, it follows that 240 volts would be involved somewhere down the line. So the relay(s) switching the boiler on would need to be located where it would not be possible for anyone to encounter them unexpectedly.
So to house the Raspberry Pi and associated relays I bought a suitable box from our local electrical component shop, to contain the following items.
The modifications made to the box are shown to the right, and are
I made extensive use of Aruldite to locate the box contents. The "feet" for the relay board were made out of the "crosses" designed for spacing tiles when tiling, with one leg of the X/cross cut off.
With the protruding leg pared back just enough to pursuade the board over each leg, the board was not about to fall off, but it might be possible to remove the board in the future should the need arise.
The RJ45 sockets were a tolerance fit, but as the box gauge was too great for the socket clips to locate them securely, I ran arudite on the inside of each sockets to ensured that they would not fall out.
The wiring diagram provided by the manufacturer for the Opto Isolating Relay board is shown below.
Not
shown above, is that the relay (K1) requires 5 volts. As the Raspberry Pi GPIO pins provide 3.3 volts,
I needed to connect terminal 3/JD-VCC above (red in the picture to the right) to one of the Raspberry Pi +5v pins.
The opto-isolating part of the circuit above is powered by a Raspberry Pi +3.3v pin (terminal 2 above, and orange to the right).
For hot water and central heating control purposes, I connected IN1 and IN2 to GPIO 23 and GPIO 24 on the Raspberry Pi.
As the wiring of 1-wire (DS18D20) temperature probes is described in numerous places on the web, I will not detail here. For now I will just point out that the variboard in the top right of the busy picture below provides a place for the 4.7K resistor, and a means of connecting the two RJ45 sockets used for 1-wire probes to the GPIO 4 pin (and GND and 3.3v pins) on the Raspberry Pi.
The other connections made in the busy picture below are
The two options I considered for implementing Pi control over the heating and hot water are
|
The first option has the benefit that the existing timeswitch can have a sensible time regime still set up. So in the event that the Raspberry Pi is unavailable for some reason, the traditional central heating control is defaulted back into service (hot water still gets hot, and heating still comes on).
I implemented the second option though, as it allows one to still use the existing timeswitch buttons to boost the hot water or heating without first having to find a computer/tablet/smart phone.
I thus implemented the Raspberry Pi relays in parallel to the existing timeswitch, to effectively let the Pi "override" the existing timeswitch,...,. and changed the existing timeswitch time pattern regimes to "always off".
To configure a GPIO pin to control a relay, one first needs to tell the Raspberry Pi that one wishes to use the GPIO pin, and then whether one wishes to use it as in input or output pin. The following three lines of script will set up GPIO 23 for controlling a relay, and then set the relay to off (slightly confusingly, 1 is off and 0 is on):
echo 23 >/sys/class/gpio/export echo out >/sys/class/gpio/gpio23/direction echo 1 >/sys/devices/virtual/gpio/gpio23/value
By way of a utility, I have a little script called relay_status
which contains the following
to enable me to quickly see how the Pi relays are current configured. (If the GPIO port is not configured,
the response of the cat /sys/devices/virtual/gpio/gpio23/value
will not be 0, so the
script works whether or not the GPIO ports have been configured.)
#!/bin/bash # CH=$(cat /sys/devices/virtual/gpio/gpio23/value) HW=$(cat /sys/devices/virtual/gpio/gpio24/value) if [ "$CH" = 0 ] then echo "Central Heating is on" else echo "Central Heating is off" fi if [ "$HW" = 0 ] then echo "Hot Water is on" else echo "Hot Water is off" fi
The initial version of control implemented is based on a simple config as below.
0000 off 0700 top3 45 0900 top3 42 1100 top2 40 1630 all 55 1730 top3 45 1900 top3 42 2200 top2 40 2300 off
Essentially, from each time in the config file, the hot water will either be off, or will have a target. The line 0700 top3 45 indicates that from 07:00 (until 09:00) the Pi will ensure that the top three temperature probes in the hot water cylinder have an average temperature of at least 45C.
The script initially used to implement hot water control using this config file is shown below. The script below is started by a cron job (just after midnight) and has it's output directed to a file in /var/log (so that using ramlog accumulates all SD card writes up, performing just a single real write per day).
#!/bin/bash # export PATH=/home/pi/script:/home/pi/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin today=$(date +"%Y%m%d") w1_file=/var/log/w1_logs/w1.processed.$today config_file=/home/pi/hw_config ################################################################################ function msg { echo $(date +"%Y%m%d %H:%M:%S") $* } function fudge_cyl_temps { cat $w1_file | awk ' BEGIN { fudge_factor[1] = 1.912014231; fudge_factor[2] = 2.2290226523; fudge_factor[3] = 2.1228034638; fudge_factor[4] = 1.835252397; fudge_factor[5] = 2.2397413977; fudge_factor[6] = 1.4193471931; fudge_factor[7] = 1.9187531469; fudge_factor[7] = 1.75; } /[0-9][0-9]:[0-9][0-9]:[0-9][0-9]/ { loft_temp_agg += $11; loft_temp_array[num_proc++] = $11; if (num_proc > 12) { loft_temp_agg -= loft_temp_array[num_proc-12]; last_hour_average = loft_temp_agg / 12; } else { last_hour_average = loft_temp_agg / num_proc; } for (i=1; i<=7; i++) { printf("%7.3f ", fudge_factor[i] * ($(i+1) - last_hour_average) + last_hour_average); } printf("\n"); } ' |tail -1 } function get_latest_temps_from_loft_pi { sudo /usr/bin/rsync -aPv rsync://192.168.0.17/w1/*proc* /var/log/w1_logs 2>&1 >/dev/null } function average_cylinder_temp { fudge_cyl_temps | awk '{ print int(($1 + $2 + $3 + $4 + $5 + $6 + $7)/7 + 0.5); }' } function average_top_two { fudge_cyl_temps | awk '{ print int(($1 + $2)/2 + 0.5); }' } function average_top_three { fudge_cyl_temps | awk '{ print int(($1 + $2 + $3)/3 + 0.5); }' } function next_refresh_time { date +"%M %S" |awk ' { min = $1 % 5; sec = $2; # Wait until 15 seconds after the next temperature reading cron should have occurred in the loft print 315 - (min * 60 + sec); } ' } function get_current_target { cat $config_file |awk -v now=$(date +"%H%M") ' BEGIN { action = "off"; target = "off"; } $1 <= now { action = $2; target = $3; } END { print action, target; } ' } ################################################################################ msg "Process $$ running" CH=$(cat /sys/devices/virtual/gpio/gpio23/value) HW=$(cat /sys/devices/virtual/gpio/gpio24/value) if [ "$CH" = 0 ] then msg "Central Heating is on" else msg "Central Heating is off" fi if [ "$HW" = 0 ] then msg "Hot Water is on" else msg "Hot Water is off" fi msg "Config file ($config_file):" cat $config_file msg "Current target:" $(get_current_target) while [ $today = $(date +"%Y%m%d") ] do # Get current target current_action=$(get_current_target |cut -d" " -f 1) current_target=$(get_current_target |cut -d" " -f 2) # echo "Action $current_action, target $current_target" get_latest_temps_from_loft_pi # Assess target criteria case $current_action in off) hw=off currval="n/a" ;; top2) currval=$(average_top_two) if [ $currval -lt $current_target ] then hw=on else hw=off fi ;; top3) currval=$(average_top_three) if [ $currval -lt $current_target ] then hw=on else hw=off fi ;; all) currval=$(average_cylinder_temp) if [ $currval -lt $current_target ] then hw=on else hw=off fi ;; *) msg "Action \"$current_action\" unknown" hw=off currval="n/a" ;; esac HW=$(cat /sys/devices/virtual/gpio/gpio24/value) # Debug information ( echo date echo Target: $current_action $current_target, HW = $HW, hw = $hw, currval = $currval ) >>/var/log/hw_controller/hw.$(date +"%Y%m%d").debug if [ $HW = 1 -a $hw = on ] then msg "Turning hot water on (target $current_action $current_target, current $currval)" echo 0 >/sys/devices/virtual/gpio/gpio24/value msg "Cyl temps:" $(fudge_cyl_temps) else if [ $HW = 0 -a $hw = off ] then msg "Turning hot water off (target $current_action $current_target, current $currval)" echo 1 >/sys/devices/virtual/gpio/gpio24/value msg "Cyl temps:" $(fudge_cyl_temps) fi fi sleep $(next_refresh_time) done msg "Process $$ exiting" exit 0
Sample log file contents are
20140624 00:06:02 Process 13527 running 20140624 00:06:02 Central Heating is off 20140624 00:06:02 Hot Water is off 20140624 00:06:02 Config file (/home/pi/hw_config): 0000 off 0700 top3 45 0900 top3 42 1100 top2 40 1630 all 55 1730 top3 45 1900 top3 42 2200 top2 40 2300 off 20140624 00:06:02 Current target: off 20140624 07:00:16 Turning hot water on (target top3 45, current 33) 20140624 07:00:16 Cyl temps: 32.943 33.375 33.265 32.339 31.616 29.961 29.348 20140624 07:30:16 Turning hot water off (target top3 45, current 47) 20140624 07:30:16 Cyl temps: 45.486 47.425 47.131 46.760 46.189 45.142 37.771 20140624 16:30:16 Turning hot water on (target all 55, current 30) 20140624 16:30:16 Cyl temps: 43.184 38.692 31.910 27.747 22.314 22.925 20.150 20140624 17:30:16 Turning hot water off (target top3 45, current 55) 20140624 17:30:16 Cyl temps: 55.961 54.654 53.488 53.863 52.715 55.426 48.373 20140625 00:00:15 Process 13527 exiting
A fragment of the debug file is
Tue Jun 24 16:20:16 BST 2014 Target: top2 40, HW = 1, hw = off, currval = 41 Tue Jun 24 16:25:16 BST 2014 Target: top2 40, HW = 1, hw = off, currval = 41 Tue Jun 24 16:30:16 BST 2014 Target: all 55, HW = 1, hw = on, currval = 30 Tue Jun 24 16:35:17 BST 2014 Target: all 55, HW = 0, hw = on, currval = 30 Tue Jun 24 16:40:16 BST 2014 Target: all 55, HW = 0, hw = on, currval = 32 Tue Jun 24 16:45:16 BST 2014 Target: all 55, HW = 0, hw = on, currval = 35 Tue Jun 24 16:50:16 BST 2014 Target: all 55, HW = 0, hw = on, currval = 38
As I have set up ssh (secure shell) access to the Raspberry Pi from the internet, the secondary objective is implemented the moment the Pi has control over the hot water circuit.
A more user friendly interface will follow for remote control will follow, but for now the ssh access is more than adequate for my purposes.
Over the summer months of July and August this year (since commissioning the Raspberry Pi hot water control), our gas consumption has reduced by 39.6% compared to the same two months last summer.
I was pretty impressed by that saving. I concede that not all of the saving could be attributed to the new control logic, as once I could demonstrate to a member of the family that their shower was using most of a cylinder of hot water, that member of the family reduced their shower hot water usage by a factor of about four! So some of the savings made would be behavioural change related rather than as a consequence of the control logic.
Based on the above figure, I am more than happy that the electricity cost of having the two Raspberry Pies running 24x7 is saved many times over by the consequential gas consumption savings.