Friday, May 22, 2015

IOT AC Reboot


After about a week and a half, the python app crashes requiring a reboot. I rather like Randall Munroe's solution:



How did I know the python app was crashed? First, I was able to SSH into the Pi. This means that Wi-Fi and the Pi itself are both fine. Then I checked the running processes:

$ ps aux

This showed that the python app was no longer running. For some reason it quit on its own. Without running diagnostics, there's no real way to know.

So, rather than using a light timer, I changed the python app so that it performs only one reading and quits. Crontab now calls it every minute instead of once at reboot. 


$ sudo crontab -e

# m h  dom mon dow   command
  * *  *   *   *     sudo python /home/pi/Adafruit_Python_DHT/examples/ac_once.py


What could be done for more reliability? A diagnostic memory monitor for one. And also a regular reboot performed by crontab or maybe a light timer.

Tuesday, May 19, 2015

Air Conditioning on the Internet

IOT is the Internet Of Things. Not only are people using the Internet, but appliances and other devices are using the Internet too. Here’s how I put an air conditioner on the Internet.


This project remotely monitors the temperature of an air conditioning outlet vent. The purpose purpose is two-fold. The first is to make sure the room temperature is safe for my cat when I’m away.  The second is to identify air conditioner performance problems early on. When the air conditioner is off, the the vent temperature is a few degrees above the room temperature at floor level - where the cat lives when she’s not on top of the book case. When the air conditioner is on, the vent temperature minus the air conditioner set-point is a measure of the air conditioner performance. I found several posts from HVAC technicians who say that the outlet minus the inlet temperature of a properly functioning air conditioner should be 18 to 20 degrees F. I’m using the air conditioner’s thermostat set point as a proxy for the inlet temperature since the thermostat is near the inlet.


All measurements were made with a single DHT-22 temperature/humidity sensor sensor, available from Sparkfun or Adafruit. This sensor has a difficult non-standard one-wire interface, but fortunately Adafruit has a ready-to-go Raspberry Pi library on GitHub. They also have a wiring diagram to interface the DHT-22 to the Pi.


Here’s a condensation of the steps I used from the Adafruit tutorial.


Wire the sensor to the Pi as follows:

Sensor pin   PI pin   Function
1            1        Power
2            7        Data
4            6        Ground


Connect a 10K ohm resistor between sensor pins 1 and 2.

The pins are numbered from left to right when looking at the front of the sensor with the pins down.


The steps to download and install are as follows:

  1. git clone https://github.com/adafruit/Adafruit_Python_DHT.git
  2. cd Adafruit_Python_DHT
  3. sudo apt-get update
  4. sudo apt-get install build-essential python-dev
  5. sudo python setup.py install


To store this data with a minimum of effort, I took advantage of data.sparkfun.com which is a free service with an easy, well documented interface. The first thing needed to communciate with data.sparkfun.com is pycurl - an python interface to cURL. It's usually installed this way:

sudo pip install pycurl


But the install hit an error:

__main__.ConfigurationError: Could not run curl-config: [Errno 2] No such file or directory

StackOverflow provided an answer. This had to be done first:


sudo apt-get install libcurl4-openssl-dev

Now for the code. Just loop forever, constructing a URL and sending it once every minute:

pi@raspberrypi ~/Adafruit_Python_DHT/examples $ cat ac_vent03.py
#!/usr/bin/python
import time
import Adafruit_DHT
import pycurl
from StringIO import StringIO

sensor = Adafruit_DHT.DHT22
pin = 4

while True:
    humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
    temperature = temperature * 9 / 5 + 32
    if humidity is not None and temperature is not None:
        print 'Temp={0:0.1f}*F  Humidity={1:0.1f}%'.format(temperature, humidity)
        url = 'https://data.sparkfun.com/input/secret?private_key=anothersecret'
        url += '&temp=' + "{:.1f}".format(temperature)
        url += '&humidity=' + "{:.1f}".format(humidity)
        print url
        buffer = StringIO()
        c = pycurl.Curl()
        c.setopt(c.URL, url)
        c.setopt(c.WRITEDATA, buffer)
        c.perform()
        c.close()
        body = buffer.getvalue()
        print(body)
    else:
        print 'Failed to get reading. Try again!'
   
    time.sleep(60)


Next, we want this python app to start when the Pi reboots. This post in Raspberry Pi Spy was helpful in learning how to assemble a cron job that starts on reboot:


$sudo su
#crontab -e
@reboot sudo python /home/pi/Adafruit_Python_DHT/examples/ac_vent03.py &


To view the data, data.sparkfun.com has a tabular display, but I’m a nut for charts. Sparkfun has some nice examples of JavaScript that use the Google Chart API. Using those examples, I assembled the following HTML file which I saved to my local drive and open with a browser.
  
<!DOCTYPE html>
<html>
  <head>
    <!-- EXTERNAL LIBS-->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="https://www.google.com/jsapi"></script>

    <!-- EXAMPLE SCRIPT -->
    <script>

      // onload callback
      function drawChart() {

        var public_key = 'secret';

        // JSONP request
        var jsonData = $.ajax({
          url: 'https://data.sparkfun.com/output/' + public_key + '.json',
          data: {page: 1},
          dataType: 'jsonp',
        }).done(function (results) {

          var data = new google.visualization.DataTable();

          data.addColumn('datetime', 'Time');
          data.addColumn('number', 'Humidity');
          data.addColumn('number', 'Temperature');

          $.each(results, function (i, row) {
            data.addRow([
              (new Date(row.timestamp)),
              parseFloat(row.humidity),
              parseFloat(row.temp)
            ]);
          });

          var chart = new google.visualization.LineChart($('#chart').get(0));

          chart.draw(data, {
            title: 'AC Vent','height':1024
          });

        });

      }

      // load chart lib
      google.load('visualization', '1', {
        packages: ['corechart']
      });

      // call drawChart once google charts is loaded
      google.setOnLoadCallback(drawChart);

    </script>

  </head>
  <body>
    <div id="chart" style="width: 100%;"></div>
  </body>
</html>



Here's the result. You can see temperature spikes down in an exponential curve when the air conditioner comes on.


This ran great for almost two weeks until it stopped posting data. Without thinking, I power-cycled the Pi. It started posting again, but I had no way to troubleshoot the failure. Did the app crash, did the Wi-Fi driver crash, or did the Pi run out of memory? Rather than having the app run continuously would it be better to have an app that only posts once and is triggered every minute by a cron job? In the next blog post, I'll write about troubleshooting and diagnostics for the internet of air conditioning.