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") + " " status += '<a ><button>Toggle</button></a>' status += "<br />" status += "Outside Garage Lights are " + get("outsidegarage") + " " status += '<a ><button>Toggle</button></a>' status += "<br />" status += "Cactus Spot Lights are " + get("cactusspot") + " " status += '<a "><button>Toggle</button></a>' status += "<br />" status += "West Patio Lights are " + get("patio") + " " 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')
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
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>
Dave:
ReplyDeleteWere are you controlling things like lights turning on at dusk and going off at bedtime?
Glenn.
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.
DeleteIt'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.