Controlling an electric heater with a Raspberry Pi

In this article, we will demonstrate how to control an electrical heater using the following:

  • A Raspberry Pi
  • A one-wire temperature sensor DS18B20
  • A wifi-controlled electricity socket (we used the Edimax SP-1101W smart plug)

Installation was performed in Belgium but should work everywhere. Edimax plugs are rated 100-240VAC, 50-60Hz and support the following current: EU:16A/230VAC; UK: 13A/240VAC; AU:10A/240VAC; US:15A/120VAC

This article only describes the bare-basics, allowing you to control your heating system at a pre-set and constant temperature (in this example 20°C). The setup can readily be extended to allow for user-input (e.g. through a web-interface).

Installing the one-wire sensor

Connecting the one-wire sensor to the IO-port of the raspberry and installing the needed software is discussed at length in other articles and will not be elaborated upon here. Simply search for DS18B20 and raspberry.

In the remainder of this article, we will assume the temperature sensor has been correctly installed and can be read using the following command on the linux prompt (replace ‘X’-es by the ID of your own DS18B20):

cat /sys/devices/w1_bus_master1/28-00000XXXXXXX/w1_slave

The output should look something like this, with the example indicating a temperature of 24.750°C:

8c 01 4b 46 7f ff 04 10 2e : crc=2e YES
8c 01 4b 46 7f ff 04 10 2e t=24750

Installing the wifi-plug

Simply follow the instructions that come with your Edimax smart plug to connect the plug to your network. After installation, you should be able to operate the plug using the software provided by Edimax such as their iOS and Android-app. Make sure you write down the user-name and password as you will need them later.

Note that we will in the end not be using the official software to control the plug but rather control it by sending it a small XML-fragment directly over the local network. Nevertheless, the official software will continue to operate should this for any reason still be necessary.

Important: make sure the plug gets a fixed IP address in your local network. You will probably need to configure a static DHCP address in your router to make this happen (i.e. tell your router to always supply the same IP address to the plug when it asks for one)

Controlling the wifi-plug

The Edimax smart-plug has an HTTP-service open at port 10.000 and can be switched on by posting the following XML command to http://X.X.X.X:10000/smartplug.cgi:

<SMARTPLUG id="edimax">
  <CMD id="setup">
    <Device.System.Power.State>ON</Device.System.Power.State>
  </CMD>
</SMARTPLUG>

Switching the plug off requires the same code, except for replacing ON by OFF.The current state of the plug can be read as follows:

<SMARTPLUG id="edimax">
  <CMD id="get"></CMD>
</SMARTPLUG>

, which will return a short XML command including the current Device.System.Power.State.

PHP-code to perform the post-command and read the result is presented at the bottom of this article. Code for other programming languages like Python can be found elsewhere on the internet (search for “edimax smart plug port 10000” or related subjects). In the remainder of this article we will assume you use PHP.

Installing PHP and Apache (webserver)

Installation of PHP and Apache on your raspberry can be performed used the apt-get command and should look something like this (assuming PHP5 and Apache2 here):

sudo apt-get install php5
sudo apt-get install apache2

Putting it all together

The final setup will do the following:

  • Read-out the temperature sensor once every minute
  • Compare the temperature to a pre-set min and max-value
  • Switch the heater on and off depending on current temperature

We will perform these operations with a scheduled CRON-job.

Edit your crontab-file;

crontab -e

, and add the following line:

# m h  dom mon dow   command
*/1 * * * * /var/www/html/auto_heater.php

Finally, place the auto_heater.php -script displayed below in /var/www/html, replace the code marked in red where necessary to match your own desired setup, render the file executable and reboot your system:

sudo chmod a+x auto_heater.php
reboot

The “auto_heater.php”-file

#!/usr/bin/php

<?php
function post_command($command, $host, $port, $username, $password, $state)
{
    $data = "";
    srand((double)microtime()*1000000);
    $boundary = substr(md5(rand(0,32000)),0,10);
 
    $remote_url = "/smartplug.cgi";
    $remote_server = $host.":".$port;
    $value = "<?xml version=\"1.0\" ?><SMARTPLUG id=\"edimax\"><CMD id=\"".$command."\"><Device.System.Power.State>".$state."</Device.System.Power.State></CMD></SMARTPLUG>";
 
    // Build the header
    $header = "POST ".$remote_url." HTTP/1.1\r\n";
    $header .= "Host: ".$remote_server."\r\n";
    // Add authentication
    $cred = sprintf('Authorization: Basic %s', base64_encode("$username:$password") );
    $header .= $cred."\r\n";
    // Add content and type
    $header .= "Content-type: multipart/form-data; boundary=".$boundary."\r\n";
 
    // attach post vars
    $data .="--".$boundary."\r\n";
    $data .= "Content-Disposition: form-data; name=\"file\"; filename=\"file\"\r\n";
    $data .= "\r\n".$value."\r\n";
 
    // and attach the file
    $data .= "--".$boundary."--\r\n";
    $header .= "Content-length: " . strlen($data) . "\r\n\r\n";
 
    // Open the connection
    $fp = fsockopen($remote_server, $port);
    // then just
    fputs($fp, $header.$data);
    flush();
 
    // Get contenst
    $result = fread($fp, 1000000);
    fclose($fp);

    return $result;
}
 
$device = "192.168.1.254";
$port = 10000;
$username = "XXXXXXXX";
$password = "XXXXXXXX";

$output = post_command("get", $device, $port, $username, $password, "");
if (strpos($output, "<Device.System.Power.State>ON</Device.System.Power.State>") > 0)
    $output = "ON";
else
    $output = "OFF";

$temp = file_get_contents("/sys/devices/w1_bus_master1/28-00000XXXXXXX/w1_slave");
$temp = substr($temp,-6);

$target_temp = "20000"; //hard-coded to 20C in this example

echo $temp; echo "/"; echo $target_temp;

if ($temp < $target_temp-0) { //No hysteresis in this example 
  echo "switch_on";
  $output = post_command("setup", $device, $port, $username, $password, "ON");
};

if ($temp > $target_temp+0) { //No hysteresis in this example
  echo "switch off";
  $output = post_command("setup", $device, $port, $username, $password, "OFF");
};

?>

Extensions

Various extensions are possible:

  • Rather than hard-coding $target_temp, read it from a file that you update with a separate application or through a web-interface.
  • Work with a min- and max-temperature rather than simply a target or experiment with higher values for the hysteresis. Edimax smart-plugs are mechanical devices meaning frequent switching is likely to lead to reduced lifetime even though I have been operating them for many months now in the setup described above without any problems.
  • Connect multiple sensors and plugs in multiple rooms to optimise heating throughout the house.
  • Interface with an online weather-service to read the outside temperature and wind and control the amount of heating you need.