Home Dashboard using a Raspberry Pi

After creating a desktop home automation dashboard and, later, a live stream “digital picture frame”, I got the idea to combine the two into an always-on control panel that condenses everything I care about into a single kiosk which can sit on my end table or nightstand.

What it does

It’s essentially a condensed UI of the desktop version linked above which uses the same databases and processes.

  • Current indoor temperature and humidity (via DHT11 sensor)
  • If my Amazon Echo is playing music, it’ll display the artist, song, and album
  • If I’m watching TV, it’ll show the title, channel, and image/movie poster
  • Display unique icons for each person in the house (by sniffing for their phone’s bluetooth signal)
  • It’ll show the status of my lights (on/off) and update if that status changes (using the Wink API)
  • Through touch screen, allow me to control my lights in near real-time.

Materials Used

How it works

Much of this (temperature, humidty, DirecTv and Wink control) is covered in “The Foundation” post.  Specific to collecting information from the Amazon Echo, I use IfTTT and the Maker channel.  Each time my Echo plays a song, I POST to a script similar to the one below which stores the song in a MySQL database.  I can then query that, determine if the song is still playing, and publish it to the UI.

<?php
$conn = mysqli_connect(<credentials>);
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$song=$_REQUEST['song'];
$artist=$_REQUEST['artist'];
$album=$_REQUEST['album'];
$timestamp=$_REQUEST['timestamp'];
$sql = "INSERT INTO echo_history (artist, song, album, timestamp)
VALUES ('$artist', '$song', '$album', '$timestamp')";
if (mysqli_query($conn, $sql)) {
echo "New record created successfully";
} else {
echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
mysqli_close($conn);
?>

My Maker recipe looks something like this: IF then to URL

recordmusic.php?artist= {{ArtistName}}&song={{SongName}} &album={{AlbumName}} &timestamp={{PlayDateTime}}

Method POST.
That’s about it for the controller – quite simple and is probably the most practical project I’ve done thus far.

Using a Pi to measure TV habits

As noted here, I’m using the the DirecTV SHEF API and a Raspberry Pi to poll my DirecTV receivers every minute and store what they’re doing into a MySQL database. After ~6 months of storing that data, I thought it’d be interesting to analyze some of it.  After all, do I really watch enough HBO and Starz to warrant paying for them every month?

Channel Preferences

  • 25,900 minutes of TV watched (~2.25 hours per day…eek; still less than the national average!).
  • 2,612 minutes of that was recorded (10%).
  • NBC is our favorite channel (3,869 minutes watched, 15%).
  • E! is our second favorite channel (1,911 minutes watched, 7.37%). Gotta keep up with those Kardashians.
  • Premium movie channels (HBO, Starz, Encore, Cinemax, etc) were watched 6,870 minutes (26.52%) – apparently worth the money.
  • Premium movie channels were recorded only 571 minutes (lots of ad hoc movie watching, I guess).
  • NBC is our most recorded channel (479 minutes) followed by HGTV (391 minutes) and ABC (330).

Time Habits

  • Sunday is the most watched day (no surprise here) with 7,157 minutes watched (28%)
  • Saturday is the second with 5,385 (21%)
  • Wednesday is the least watch with 1,144 (4.4%)
  • April was our biggest TV month with 6,413 minutes watched (24.76%)
  • June was our lowest month with 1,197 (4.62%) — July is around 10%.  The excitement of summer faded fast, apparently.
  • 8PM is our biggest TV hour with 1,312 minutes (15.14%).  This is followed by 7pm (13%) and 6pm (10%).
  • 6AM is our lowest TV hour with 68 minutes watched (0.26%).  This is followed by 5am (0.49%) and 4am (0.90%).

This is pointless data but it’s always interesting to assess your own habits.  And if you’re wondering, it took roughly 60 minutes (0.23%) to query and publish this post :).

Webcam Stream as Digital Picture Frame

I don’t have a quality window view in my office building and found myself checking the local news’ weather cams throughout the day so I thought it’d be cool to have a live outdoor view streaming to my desk.  Using a Pi 3, Pi Displaya case, and camera, I built a digital picture frame which streams a live video feed from my apartment window to my desk at work.  While going through the process, I hit a few hiccups and a ton of outdated resources online so I thought I’d share my learnings and provide documentation for anyone wishing to recreate.


The following will setup a Pi to run Chromium in Kiosk mode on startup while silencing errors and hiding your cursor.  The assumptions made before beginning are that you’re able to SSH into both of the Pis and your Pis are connected to WiFi.  The guide I followed to setup my cam stream is solid so no need to re-invent the wheel – use this guide to setup your first Pi to stream your cam image.  The obvious callout is to make sure your stream resolution matches your display’s resolution.  The steps below will be for your picture frame Pi and assume you’ve already got your stream up and running…
Step 1
Run the update/upgrade and install Chromium (as explained here).
sudo apt-get update
sudo apt-get upgrade
Step 2
Install x11 server utilities and unclutter.
sudo apt-get install x11-xserver-utils unclutter
Step 3
Since we want this to be as hands-off as possible and to silence any power-saving settings or error messages on power cycles, we’ll edit the LXDE startup to disable this stuff.
sudo nano ~/.config/lxsession/LXDE-pi/autostart
and add the following lines (not the screensaver commented out):
#@xscreensaver -no-splash
@xset s off
@xset -dpms
@xset s noblank
@sed -i ‘s/”exited_cleanly”: false/”exited_cleanly”: true/’ ~/.config/chromium/Default/Preferences
The last line we’ll add in this file will be the address we want to display.  In the example below, we’ll sinply load Google.com.  We use the incognito tag to prevent Chromium from showing an error in the event of a power cycle.
@chromium-browser –noerrdialogs –kiosk http://www.google.com –incognito
Now, exit and write.
Step 4
Let’s reboot and apply the changes to see the results
sudo reboot

A month of tinkering

New Design

The original design wasn’t “clean” feeling and didn’t function too well on mobile or even tablet displays.  I changed that up a bit and the new design has a lot of transparent divs, bokeh background images, and some jquery to make actions a bit smoother.
new ui

Wink Integration Improvements

The initial integration of the Wink API wasn’t that great.  I was using PHP to trigger shell scripts which would then make the API call – quite messy and had several opportunities for failure.  This method also made a new request for a bearer token each time an action was taken so if I turned on three lights, I requested three unique tokens from the API.  I’ve since cleaned that up and now use a single token per session and the API calls are all made in a single PHP file.  This still isn’t the cleanest or safest way to do this but it works for my usecase.
While doing this, I also added the ability to dim some lights (such as the kitchen light which we leave on during the night).  The next step is to fetch the current state of the lights so that we can eliminate the on/off option and simply toggle it.  The problem with that is that the Wink Hub struggles to maintain accurate states for its devices.
dim.PNG
Gaining my Wink bearer token for the session:

<?php
$ch_token = curl_init();
curl_setopt($ch_token, CURLOPT_URL, "https://api.wink.com/oauth2/token");
curl_setopt($ch_token, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch_token, CURLOPT_HEADER, FALSE);
curl_setopt($ch_token, CURLOPT_POST, TRUE);
curl_setopt($ch_token, CURLOPT_POSTFIELDS, "{
  \"client_id\": \"<insert_here>\",
  \"client_secret\": \"<insert_here>\",
  \"username\": \"<insert_here>\",
  \"password\": \"<insert_here>\",
  \"grant_type\": \"password\"
}");
curl_setopt($ch_token, CURLOPT_HTTPHEADER, array(
  "Content-Type: application/json"
));
$ch_token_response = curl_exec($ch_token);
curl_close($ch_token);
$ch_token_json = json_decode($ch_token_response, true);
$bearer_token=$ch_token_json['access_token'];
?>

Wink Control:

<?php
$device_id=$_GET["device_id"];
$new_state=$_GET["new_state"];
$bearer_token=$_GET["bearer_token"];
if(is_numeric($new_state)){$action="brightness";} else {$action="powered";}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.wink.com/light_bulbs/".$device_id."/desired_state");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, "{
  \"desired_state\": {
    \"".$action."\": ".$new_state."
  }
}");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
  "Content-Type: application/json",
  "Authorization: Bearer ".$bearer_token.""
));
$response = curl_exec($ch);
curl_close($ch);
if($new_state=="true"){echo "Turned On"; } else if($new_state=="false") { echo "Turned Off"; } else { echo "Light Dimmed: $new_state"; }
?>

DirecTv Changes

I integrated TheMovieDB.org‘s API to pull images of the movies or shows that are currently on.  This currently works very well for movies but it often fails to find images for shows so I’ll loop back to fix that at some point in the future.  I also added in a link to view the title on IMDB for easy access.  An alarm was added to trigger a notification if the DVR is nearly full.

Mapping GPS Coordinates

Out of sheer curiosity, I decided to push my phone’s GPS coordinates to my server and plot them on a map.  I’m using the SendLocation app to push the coordinates to a script I have setup to listen to the app.  This may, perhaps, help me locate my phone one day if I ever lose it.  For now, though, it’s merely something for me to play with.  I’m also capturing things like speed so I can view when I’m in transit.  Essentially, this traces my steps.
gps

MQ2 Sensor (Gas/Smoke)

I added an MQ2 sensor to the PI and set it up to store the current state as well as send me a text message and email if it detects something.  Overall, the setup is pretty simple and certainly isn’t life-saving but does serve the goal of being able to monitor home while away.
Here’s my Python file I use which I simply schedule a cron job to ensure it’s monitoring frequently enough to be useful (note the loop of 20 and sleep of 3 seconds so it runs for the entire minute before the cron fires again):

import time, sys
import RPi.GPIO as GPIO
import MySQLdb
import smtplib
def sendemail(from_addr, to_addr_list, cc_addr_list,
              subject, message,
              login, password,
              smtpserver='smtp.gmail.com:587'):
    header  = 'From: %s\n' % from_addr
    header += 'To: %s\n' % ','.join(to_addr_list)
    header += 'Cc: %s\n' % ','.join(cc_addr_list)
    header += 'Subject: %s\n\n' % subject
    message = header + message

    server = smtplib.SMTP(smtpserver)
    server.starttls()
    server.login(login,password)
    problems = server.sendmail(from_addr, to_addr_list, message)
    server.quit()
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
n = 20
def action(pin):
    print 'Sensor detected action!'
    db = MySQLdb.connect("","","","" )
    cursor = db.cursor()
    cursor.execute( 'insert into mq2(event) values("Gas detected")')
    db.commit()
    db.close()
    sendemail(from_addr    = '',
          to_addr_list = ['att phone email address'],
          cc_addr_list = [''],
          subject      = 'Gas Detected',
          message      = 'Elevated levels of gas or smoke detected.',
          login        = '',
          password     = '')
    return
GPIO.add_event_detect(11, GPIO.RISING)
GPIO.add_event_callback(11, action)
try:
    while n > 0:
#        print 'alive'
#        print n
        n = n-1
        time.sleep(3)
except KeyboardInterrupt:
    GPIO.cleanup()
    sys.exit()

Other Changes

  • I’ve changed the interior camera to disable itself if anyone is home.  There’s no need for it to run if during that time and it also ensures an additional layer of security/privacy.
  • The date formats were updated to provide “friendlier” outputs.  I also added a time of day greeting for the active user – “Good morning/afternoon/evening/night”…
  • My favorite Google News RSS feeds were added to the left and a weather forecast link was added.  I also included a calendar with the eventual goal of integrating the Google Calendar API (I use Google Calendar quite heavily).  These are hidden by default in order to maintain the “clean” UI I’m going for.news.png

The Foundation

Purpose

Let’s just get it out of the way now — there’s no true practical purpose or value in doing this.  I took this on as an experiment and opportunity to learn something new.

What is it?

Using a Raspberry Pi, some sensors, and a lot of Googling with trial and error, I took my first step into custom home automation (Wikipedia).  I can control lights, DirecTv receivers, some appliances, measure indoor temperature and humidity, determine who is home, and view indoor/outdoor webcams through a single UI.

Materials and Cost

Screenshots

image

 

image

Control

Lighting Control
Each tailed light uses a GE Link bulb which is connected to a Wink hub.  This allows for on/off control, dimming control, on/off scheduling, and dimming scheduling (such as gradual increases in brightness in the mornings).  Wink comes with a nice app but I opted to use their API so I could incorporate it into the custom UI/dashboard along with everything else.
Cameras
I’m using an old D-Link camera to gain outdoor views and the RPI camera for inside the apartment, I setup scripts to take snapshots once every minute and dump them into a MySQL db running on the Pi and also update the snapshot to include in the UI.
Weather Reporting
Outdoor weather (temperature, “feels like” temperature, humidity, pressure, and windspeed) is pulled from Yahoo! XML weather feeds.
Indoor temperature and humidity is polled every minute using a DHT11 sensor attached to the RPi.  Historicals for all of these are stored in a MySQL database with the intention of graphing these some time in the future.  I’d like to incorporate a Nest-style thermostat for indoor climate control but, alas, I’m a renter and don’t want to deal with that.
Who’s Home?
Using a Bluetooth dongle attached to the RPi, I poll for cell phones to determine who is home and who is away.  Every minute, I log the status of all detected Bluetooth devices so we can see who’s around.  This is also stored in a MySQL db so I can go back in time.
DirecTV Control
Using the DirecTV SHEF API, I currently poll the current program title, the channel number, the station ID (ie NBC or HBO), the program rating, whether or not the DVR is recording.  The API allows you to take full control of the receiver and do all actions you can with the remote but I don’t see much value in that as I can’t watch it while I’m away so why have the functionality…
Appliance Control
Using WEMO plugs, I can power on/off appliances.  This came in handy at Christmas when the outlet was located directly behind the Christmas tree.  At this point, though, there aren’t many appliances I want to control with the Wemo so I have a few of these sitting idle.

Automation and Availability

Amazon Echo Integration
All of these devices have been integrated with the Amazon Echo device either via Echo skills or via IFTT integration.  This allows all of the functionality above to be controlled via voice recognition.  There’s some trial and error getting these setup correctly but I think that’s mostly with the Echo’s voice recognition quality.
IFTT
With integration of IFFT, I can do any number of things if desired.  One of the more useful IFFT setups I’ve found is simply turning on the bedroom lamp ~8 minutes after my alarm goes off and gradually increasing the bulb’s brightness every minute.  Another possible option is to turn some lights on when the Pi’s bluetooth dongle detects that I’m nearby.
Web Server
In order to make this valuable, I installed Apache on the Pi and used ngrok to tunnel to localhost so that I don’t have to worry about the vulnerabilities of port forwarding on my router.  I have this forwarded over to a domain name I wasn’t using and added some .htaccess protection (among other things) to keep it private.

Future Plans

Living in a small apartment limits the value and the opportunities of home automation.  Things like adding reed switches to windows and door don’t make sense in my scenario as I doubt anyone will be climbing through my 7th floor window or trying to break into my door.  Some more practical things I’ll be doing, though, is adding a gas, CO2, and smoke sensor to the Pi so that I’m alerted via text message and push notification if the Pi detects any of those levels becoming elevated…better than waiting on the neighbors to call the fire department, no?  I’d also like to add a PIR motion detector to trigger the Pi Cam to start capturing video instead of still snapshots if motion is detected during hours that I’m normally away from home.  I’ve had some troubles getting the motion detector to work but I’ll loop back to that eventually.