Tuesday, November 18, 2014

Raspberry Pi, CherryPy, Process Communication, Part 2

Part 1 of this project is here <link>

Last post I talked about experimenting with a different method of process communication: using HTTP between the processes.  This will allow me to move some of my work to another machine, and increase my ability to monitor the various items.

I got into this mess because of the plethora of different devices and protocols I'm messing with.  Each set of devices has a different protocol, some invented by me, others invented by industry.  If you have two different ZigBee devices that can't talk to each other, you need something to translate in the middle.  This isn't too hard, but it gets complex when you're chasing a bug around and can't poke the pieces to see what happens.  So, I started with my Wemo devices, and added a minimal webserver to the code.  This allows me to talk to and check the status of the switches using a browser as well as a separate process that collects the data.

It turned out to be relatively easy, but I (again) had to learn a new jargon.  I'm finding over and over that the key to doing anything in the home automation realm is the language.  When you look at a library or implementation, be prepared for a few hours with google to understand what they're saying.

CherryPy turned out to be pretty slick.  It works differently than the big servers like Apache, but it can be used pretty easily.  I started off with the CherryPy tutorial and just started adding things I needed until I had a skeleton.  That's described in the last post.  Then I took the skeleton in one window and the existing code in another and started the cut-and-paste process of combining them.  It turned out pretty well.  I have several web-like interfaces to the Wemo code that I can interact with, and so far, it's holding up pretty well.  For example, I have a human interface that is really easy to use; I just type in 192.168.0.205:51001 as a URL and I get back:

Current Wemo Light Switch Status

Front Porch is Off  
Outside Garage Lights are Off  
Cactus Spot Lights are Off  
West Patio Lights are Off  

The status is immediate, meaning I actually send off a UPNP request and get the state.  The buttons work and will operate the lights.  It's basically a tiny web server to control the lights without all the hassle of bringing up Apache and a ton of other things.  Yes, it could be extended to use pictures and really cool looking interfaces, but that wasn't what I was going for, this is a nice side effect.

The machine interface is different.  If I type in 192.168.0.205:51001/status, I get:

[{"cactusspot": "Off"}, {"frontporch": "Off"}, {"patio": "Off"}, {"outsidegarage": "Off"}]

Just the bare essentials: the names of the switches and their states right now.  Notice that I have to type in less characters for the human interaction than I do for the machine interaction?  Yep, that's on purpose, I'm lazy.  If you want to see how lazy I am, I have to type in:

192.168.0.205:51001/pCommand?command=OutsideLightsOn

To turn on a single light with the process interface, and it doesn't return anything because it updates the SQLite3 database I use instead.  Sure, it's a painful thing to do, but who cares?  I don't have to type it, it's constructed by code.  To illustrate how a web page can be constructed, here is the code for the human readable page I put up:

    @cherrypy.expose
    def index(self):
        status = "<strong>Current Wemo Light Switch Status</strong><br /><br />"
        status += "Front Porch is " + get("frontporch") + "&nbsp;&nbsp;"
        status += '<a ><button>Toggle</button></a>'
        status += "<br />"
        status += "Outside Garage Lights are " + get("outsidegarage") + "&nbsp;&nbsp;"
        status += '<a ><button>Toggle</button></a>'
        status += "<br />"
        status += "Cactus Spot Lights are " + get("cactusspot") + "&nbsp;&nbsp;"
        status += '<a "><button>Toggle</button></a>'
        status += "<br />"
        status += "West Patio Lights are " + get("patio") + "&nbsp;&nbsp;"
        status += '<a "><button>Toggle</button></a>'
        status += "<br />"
        return status

The entire page is constructed as a string and just sent back to my browser.  I used the simplest buttons and web techniques I could to make it as easy as possible.  Still, it works and doesn't look bad.  Notice that when you click on a button, it goes for the URL ./wemocommand ?  That's the code that will toggle a particular light.  I also use URL parameters (that's what the '?' is for) because they turned out to be easy to parse out.  I could have made this smaller by using a list, and I may some day, but this is much easier to understand for folk that are trying to copy the idea.  It also makes it simple to code for acting on the incoming HTML request:

    @cherrypy.expose
    def wemocommand(self, whichone):
        # first change the light state
        toggle(whichone)
        # now reload the index page to tell the user
        raise cherrypy.InternalRedirect('/index')

Yes, that's all there was to it.  I already had the toggle() routine to support the old interface and I simply redisplay the first page because it will go get the new state of the switches.  At this point in my experiment, I was beginning to really like CherryPy.

Just to round out this a bit, here is the code for the JSON string return I do for the process interface:

    @cherrypy.expose
    @cherrypy.tools.json_out() # This allows a dictionary input to go out as JSON
    def status(self):
        status = []
        for item in lightSwitches:
            status.append({item["name"]:get(item["name"])})
        return status

Notice that CherryPy already has a JSON translator built in?  Is that cool or what?  All I had to do was get the lights state in a list and then return it.  It makes the code a little hard to understand, but it was so simple to put together.

If you want to see the entire module, it's under the branch wemoHTML in my GitHub repository.  If you haven't figured out how to get to that yet (took me some time), here's a link <link> that should get you directly to it.  The module is wemocontrol.py in the house directory.

I still haven't adapted the other pieces necessary to fully implement the idea.  I have to change the web code (php) that handles commands and also the presentation page for my control web page.  I don't expect to have too much trouble with it, but I'll probably have to learn the meaning of some new words.

Part 3 of this project is here <link>

2 comments:

  1. Dave:

    Were are you controlling things like lights turning on at dusk and going off at bedtime?

    Glenn.

    ReplyDelete
    Replies
    1. I have a completely separate process that does things on a schedule. It sends (currently) sys V messages to the other processes to do things. So, at a set time, it sends a message to the wemo code to turn on the outside lights, and then again at 10PM, it turns them off. This same process turns off the pool motor if I forget, sets the temperature of the house for bedtime, etc.

      It's basically nothing but a set of timers (using APScheduler) that sends commands. It will eventually use an HTML interaction to do this based on the stuff I did here. I just haven't gotten that far yet.

      Delete