Friday, December 30, 2016

More Adventures With My Freezer

Last post I described how I managed to screw up my freezer defrost controller <link>. This is the latest chapter in that escapade.

I started up Eagle and created a board to hold a higher power relay and XBee to overcome the problems with the small relays that are generally available for Arduinos. The board got overly complicated and the cost of the various parts got to the point where it was just silly to continue. Then I got a brainstorm: why not just use a relay board as a module similar to what I did with the XBee.

I started up Eagle again and took that tactic; it worked really well --- at least on paper. Here's the schematic I came up with:


For those of you that aren't used to Eagle schematics, each of the signal lines has a name and you just match up the names to see where things hook together. It makes for a really simple looking schematic that is a bit hard to follow. The idea is that the set of plugs on the right are the pins on an Arduino, the two modules in the middle are an XBee and a relay module that is readily available all over the place:
These little boards are available for less than $5.00 and can handle motors. It should be exactly what I need for this project. Where I ran into trouble was all the parts necessary to support one of the relays. Things like buffer transistors, optoisolators, LEDs and such are a real pain to keep stock of and you can't really order just a couple. I'd have parts piled all over the place if I tried to build up everything necessary; so I took the easy way out and just mounted the relay on a board I designed along with the pins for the temperature sensor, XBee, some lights and some buttons. Basically, my new board would be a holding device for the stuff I needed for this project.

Cool huh? This is the board layout I came up with:


I added some LEDs at the front of the board so I could see that it was alive at a glance, matched holes on the board to the holes on the relay module and added a couple of buttons to control reset and defrost for testing. Heck, I even put a Saguaro cactus on it as a kind of indicator that it was designed by me.

I sent the gerber files to Seeed Fusion because I haven't used them before. About 4 weeks later the boards arrived. I say boards because you get 10 of them for the same price, but the shipping was high. To offset the shipping I included the rest of the temperature sensors I need for my house monitoring project. So, for around $38 I got ten of the defrost controller boards and ten more of the room sensor boards for later.

Here's what the boards look like:


I chose yellow because I've never messed with a yellow board before. I labeled every stinking thing because I can't ever remember where stuff goes after a few weeks of not looking at it. I also stuck the LEDs on the front of the board so they could be seen by peeking through a vent area on the freezer. My way of showing off that I modified the freezer.

Here's the board assembled:


I pulled the screw connectors for the digital signals off the board and replaced them with pins so I could plug the relay module into the board. I bent the LEDs over for that day when I actually make an enclosure for the board. I used Arduino-like pins for connecting to an Arduino, but that was a mistake. Somehow I thought I might someday mount something above this board. Notice that's not possible. Oh well, they may serve as test points some day.

Here it is mounted to the Arduino:


Yep, it's bigger than the Arduino. I considered using one of the really tiny Arduino devices and just having a board that connects the various modules together, but decided to just use what I already had. It won't matter when I get it into an enclosure because only the wires going in and the LEDs will be visible.

I powered it up and everything worked first try. Amazing. I actually got something like this to work without another hitch.

Some tricks you can use if you decide to do something like this: Print the board on paper and try the various parts on the paper. This is how I managed to get the holes for mounting the relay module in the right spot. First I measured them as close as I could, then I printed the board and put the module on top of it to be sure the holes lined up correctly; they didn't. I was a tenth of an inch off. A little moving of stuff and they lined up perfectly. I did the same thing for the pins for the digital signals to the relay module also. I used the same technique to be sure the Arduino pins lined up as well. When I got the boards in I was almost afraid to try it out for real, but it worked perfectly.

Lining up something like this is a real pain, but using the printed version of the board takes almost all of the anxiety out of the process. Another trick is to label every thing in sight. The values of the components, the direction things point, which way a diode goes in, these are the things you forget while you wait for the board to arrive. Just label them in the silk screen so you don't have to wonder what goes in that hole and which way it points.

This is the third board I've had made for one of my projects and I think I'll do more over time. It's just too easy to mess up a tiny wire from one component to another and it makes the end result very fragile. The other thing I learned is just using the inexpensive components that are available to us for projects. I could use multiple relay modules like this in a project and have a board made to mount and wire all of them making the end result pretty and easier to work with. It should make troubleshooting easier as well; I won't have to follow a wire from place to place to see what went wrong.

Now to install it and watch it work for a while. I also have to figure out what to do with the other nine boards I don't really need.

Edit: After it was installed and tested once, it failed. Seems the relay wouldn't close; it got the signal to close just fine, but the relay just wouldn't activate. I chased the problem to the power line going from the wall wart to the Arduino, and changing that cord fixed the problem.

A lot of us have encountered this problem. We get a USB cable from somewhere and they use tiny wires that can't even carry a half amp three feet; it can drive you nuts trying to troubleshoot the problem because it looks just fine until you try to drive a relay or a set of LEDs. When you try and pull power, the voltage drop through the cable shuts things down.

Anyway, it's working just fine now and the stupid cable has been labeled so I'll know next time.

Sunday, December 4, 2016

Adventures With My Freezer (the one in the house)

Over the years I've been doing modifications to the freezer in my kitchen. It all started way back in 2014 when I decided to not only measure the power usage of this device <link>, but to also control when the defroster runs <link>.

A tiny bit of background for folk that haven't been following my silliness for very long: I'm trying to lower my electricity bills here in the Arizona desert, and have a power company that offers a lower rate during off hours. What I do is try to keep all my major usage in the non-peak hours, and having the defroster run whenever it wants to sometimes leads to defrosting in the middle of the peak period. Also, I bought this freezer because it is simple, really simple. There's no huge electronic package in there that is designed to save power, hook to the internet, take pictures, call my Mom, etc. It's just the basic freezer, albeit a high capability, and repairable model that looks really good.

I also added the ability to monitor the temperature inside the freezer <link> after my 'wonderful' defrost controller crapped out. While I was fixing that I decided to combine the two relays on the Arduino shield I was using to parallel the contacts, hoping to extend the life of the relays.

Don't ever do that !!

I totally forgot that doubling the number of components also doubles the possibility of failure, as well as doubling the ways they can fail. This is a great story of doing the wrong thing, so I'm going to teach you a bit about the defrost cycle on a freezer so you understand what I got myself into. Since I have the ability to chart the actual action of my freezer, you get to have real examples of my (seemingly infinite) ability to screw up.

This is what a normal defrost cycle looks like when you can observe both temperature and power usage.


Ignore point A, that's the icemaker running to dump ice in the tray, and the tiny bump next to it is the lights in there when I open the door.

Point B is the start of the defrost cycle, this happens on a timer that closed a SPDT set of contacts that shuts off the compressor and kicks on a heater that is actually attached to the evaporator at the bottom of my fridge.

Point C is where the heater is running, and it will run until a temperature sensor (also mounted on the evaporator) reaches a built-in temperature that the manufacturer thinks is the best to clear the frost away. In my particular case this thermostat is 37F.

Point D is where the heater shut off and the freezer just sits there until the timer runs out after 30 minutes. This is to allow the water to drain out the bottom into an evaporation tray and away from the freezing area of the freezer.

Point E is where the compressor kicks back on, the spike is the usual one you get from the run capacitor letting a lot of power through to get things going.

Point F is the normal compressor run cycle. It runs until the Freezer gets to operating temperature and then shuts off. On freezers the compressor runs a long time, but that's OK because these things only use around 100W. In the days before LED lights in appliances, the lights used a lot more power than the compressor did.

So, the heater pulls around 400W, but should only run for around 15 minutes, however once in a while it because of high local humidity, someone holding the door open too long, trying to freeze a gallon of hot water, or something like that, the heater will run the entire 30 minute cycle time. When this happens, the next defrost cycle will take care of the left over buildup.

Unless something is broken, or you've got someone in the house that messed things up.

I noticed that the temperature in my freezer was gradually rising and the compressor seemed to be running too long. Here's a chart of what I saw when I looked at it:


Once again, the sharp peaks are the icemaker doing its thing, but let me step through the other parts I pointed out:

A is where the defrost heater started. This part appears perfectly normal.

B is where the defrost heater should have leveled off at around 400 watts. Notice it's up around six hundred and climbs after that.

C is the defrost heater shutting off after the full thirty minutes of time allowed by the timer. It didn't shut off early and coast.

D the big spike of power should have shown up, it didn't. The spike there is the ice maker dumping ice.

What was happening? After a bunch of troubleshooting and scratching of my head, I figured it out; one of the relays had a frozen up contact and the compressor was running during the defrost cycle. The other relay was working just fine, but it couldn't stop the compressor with the other one bad.

I gutted the relays to double check (sorry I forgot to get a picture) and one of them had the contacts welded together and was the culprit in this mystery. I pulled it loose and let it go. About two days later, the remaining relay gave up the ghost as well. So much for those relays. I've got my eyes on one of the 30 amp relays now and have an order off for a circuit board that will hold it and an XBEE in my own designed Arduino shield.

Yes, I feel a bit stupid. But, isn't the ability to chart the performance of my freezer cool? Looking at the database of freezer data I was able to tell exactly which day it happened and how much the temperature rose over time as the defroster competed unsuccessfully with the compressor. Even the fancy internet connected freezers can't do that.

Right now, the freezer has the old mechanical defrost control in it that has had to be replaced twice because the mechanical clock in it doesn't hold up over time, and the defroster turns on whenever it feels like it. I had to get out the heat gun and melt the frost off of the evaporator by hand to give it a head start, that wasn't hard, but it did let the ice cream get soft.

More later, I'm not giving up on this.


Friday, December 2, 2016

Amazon Dot: Oops, Forgot Something

Just when I thought I could put this series of posts on the Amazon Dot and using it at my house aside for a while, I realized I forgot something last time <link>. I didn't show what a session with the example code I gave you last time looked like and what it was doing. So:

pi@housemonitor:~/src/alexa$ alexaIllustration.py
did the connect to AWSIoT
mqtt loop started
Alexa Handling started
mqtt connection to AWSIoT returned result: 0
Variable states:  79.1 1234.5 on
On Tick:  { "state" : { "reported": {"temp": "79", "barometer": "1235", "eastPatioLight": "on", "lastEntry": "isHere" } } }
Variable states:  79.1 1234.5 on
On Tick:  { "state" : { "reported": {"temp": "79", "barometer": "1235", "eastPatioLight": "on", "lastEntry": "isHere" } } }
{ u'eastPatioLight': u'off'}
got a delta
{ u'eastPatioLight': u'off'}
got command for east patio light:  off
Variable states:  79.1 1234.5 off
On Tick:  { "state" : { "reported": {"temp": "79", "barometer": "1235", "eastPatioLight": "off", "lastEntry": "isHere" } } }
{ u'eastPatioLight': u'off'}
found left over desire at eastPatioLight
sending: { "state" : { "desired": {"eastPatioLight": null} } }
Variable states:  79.1 1234.5 off
On Tick:  { "state" : { "reported": {"temp": "79", "barometer": "1235", "eastPatioLight": "off", "lastEntry": "isHere" } } }


Above is a session where I start the process and give it a command. The first thing that happens is that a connection to AWSIot is established. This is really a normal ol' mqtt connect, and then an mqtt loop is started. This is an asynchronous loop that will return control back to the code so other things can be done.

When the connection calls back the code subscribes to the two topics and prints the connection message, "mqtt connection to AWSIoT returned result: 0." This means that we are all set up and ready to receive messages from Amazon. I printed the starting state of the variables next and the interesting one is the eastPatioLight which I initialized to 'on'.

The 'On Tick' messages are the reports we're sending up to Amazon. I have this set up for every ten seconds so we don't have to wait long to see something. Scan down a bit and look for, "got a delta," because that is the point where a command came in from Amazon. In this case it's a command to turn the eastPatioLight off.

The next 'On Tick' message says that the light is now 'off' and should change the Shadow document to reflect that. Then, the code sees another delta message and checks to see if it has already been satisfied and decides that it's simply a leftover desire and sends back a JSON string:

{ "desired": {"eastPatioLight": null} } }

This will remove the desired entry from the Shadow and therefore, the delta message will stop.

And it's done. The variable has been changed to 'off' and if you had code there to turn off your lights, so would be the light.

After you work with the interaction a bit, it will all make sense and will be MUCH easier to modify for your particular use and add stuff to.

Have fun.

Thursday, December 1, 2016

Amazon Dot: Now for the code on the Raspberry Pi

Last post <link> I stepped through creating the voice model and the Lambda function in Amazon Web Services (AWS) that got my request to manipulate the light on my East patio light out to Amazon's mqtt server for this service that they call, AWSIot (Amazon Web Services Internet of Things). Yes, it's a big name for something like this, but how else are you going to sell it? Gotta have a lot of marketing hype to impress the Harvard School of Business Managment.

At any rate, it's a good implementation of mqtt that reacts pretty quickly and will send the mqtt message containing the data I need to control the light. When you do this, you'll need something on the Pi to receive the message and do something with something real.

Unfortunately, I can't do that part for you.

I can show you how to receive the message and take it apart, but the actual twiddling of bits, or however you control your devices is up to you. I use a mix of XBees and web based devices and they certainly won't fit in with what you do. So, I'm going to use a couple of variables and just change them. You can take that and run with it since we all have variables.

Let's do this with code I put together special for just this purpose. In the code I initialize the variable to something so I can tell they changed, get and respond to the messages from Amazon that were initiated by voice command to the Dot, then change the values based on that. I'll build on the example I provided previously to get the temperature at my house, so if you don't remember what I did there (I wouldn't) go back a glance at it for a minute <link>; I'll wait.

Here's the python code:

#!/usr/bin/python
import os
import sys
import time
import paho.mqtt.client as mqtt
import ssl
import json
import pprint
from houseutils import timer, checkTimer

pp = pprint.PrettyPrinter(indent=2)

def on_awsConnect(client, userdata, flags, rc):
    print("mqtt connection to AWSIoT returned result: " + str(rc) )
    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed. You still have to do the
    # reconnect in code because that doesn't happen automatically
    client.subscribe ([(awsShadowDelta , 1 ),
                      (awsShadowDocuments, 1)])
                      
def on_awsMessage(client, userdata, msg):
    global eastPatioLight
    
    # If you want to see the shadow documents to observe what is going on
    # uncomment the prints below.
    #print "TOPIC = ",
    #print msg.topic
    #print "PAYLOAD = ",
    payload = {}
    payload = json.loads(msg.payload)
    #pp.pprint (payload)
    #print ""
    
    # The 'delta' message is the difference between the 'desired' entry and
    # the 'reported' entry. It's the way of telling me what needs to be changed
    # because I told alexa to do something. What I tell alexa to do goes into
    # the desired entry and the delta is then created and published. Note that
    # the delta is not removed, it has to be done specifically, hence the 
    # code further down.
    
    if msg.topic == awsShadowDelta:
        print "got a delta"
        pp.pprint(payload["state"])
        for item in payload["state"].keys():
            if item == "eastPatioLight":
                command = str(payload["state"][item])
                print "got command for east patio light: ", command
                # This is where you would actually do something to
                # change the state of a device.
                eastPatioLight = command
            else:
                print("I don't know about item ", item)
                
    # Right under here I get the entire document and compare the 'desire' part
    # to the corresponding items in the 'reported' part. When I find something in
    # the desire that is the same as something in the reported, I remove the entry
    # from the desire. If you get rid of all the entries in desire, the entire
    # desire part of the document is removed and just disappears until it's 
    # needed later.
    
    # The reason for this is because when the desire stays around and you walk
    # over and change something by hand, AWS will generate a delta because the
    # reported is suddenly different from the desired. That means you open the
    # garage door by hand, aws senses that the desire is closed, sends a delta
    # and closes the garage door on you.
    
    # Fortunately, I discovered this with a light, not a garage door.
        
    elif msg.topic == awsShadowDocuments:
        #print "got full thing"
        
        # AWSIoT sends the 'reported' state back to you so you can
        # do something with it if you need to. I don't need to deal 
        # with it ... yet.
        if "desired" not in payload["current"]["state"]:
            #print "'desired' not there"
            return
        desired = payload["current"]["state"]["desired"]
        reported = payload["current"]["state"]["reported"]
        #pp.pprint (reported)
        
        # This is probably a left over 'desired' state, which means
        # you've already changed something, but the desire is still
        # left hanging around, so compare it with the reported state
        # and if it has been satisfied, remove the desire from AWSIoT
        pp.pprint (desired)
        fixit = False
        fixitString = "{ \"state\" : { \"desired\": {"
        for item in desired.keys():
            # when updating this, you'll often encounter
            # items that aren't fully implemented yet
            # (because you're still working on them)
            # this not reported it's just to keep from dying
            if not reported.get(item):
                print ("found odd item " + item)
                break
            if desired[item] == reported[item]:
                fixit = True
                print "found left over desire at", item
                # to get rid of a desire, set it to null
                fixitString += "\"" + item + "\": null,"
        if not fixit:
            return
        fixitString = fixitString[:-1] #remove the trailing comma JSON doesn't like it
        fixitString +="} } }"
        print "sending:", fixitString
        err = awsMqtt.publish("$aws/things/house/shadow/update",fixitString)
        if err[0] != 0:
            print("got error {} on publish".format(err[0]))
    else:
        print "I don't have a clue how I got here"

# This keeps the Shadow updated with the latest state of the devices
# If you go over and push a button to turn on a light, you want the shadow
# to know so everything can work properly.        
def updateIotShadow():
    global temperature 
    global barometer
    global eastPatioLight
    print "Variable states: ", temperature, barometer, eastPatioLight
    # Create report in JSON format; this should be an object, etc.
    # but for now, this will do.
    report = "{ \"state\" : { \"reported\": {"
    report += "\"temp\": \"%s\", " %(int(round(temperature)))
    report += "\"barometer\": \"%s\", " %(int(round(barometer)))
    report += "\"eastPatioLight\": \"%s\", " %(eastPatioLight.lower())
    report += "\"lastEntry\": \"isHere\" " #This entry is only to make it easier on me
    report += "} } }" 
    # Print something to show it's alive
    print "On Tick: ", report
    err = awsMqtt.publish(awsShadowUpdate,report)
    if err[0] != 0:
        print("got error {} on publish".format(err[0]))

# These are the three items we'll deal with in this example
# They represent real devices that measure or change something
# that have been implemented somewhere.
temperature = 79.1
barometer = 1234.5
eastPatioLight = "on"

def updateWeather():
    global temperature
    global barometer
    # if you had a real device, this is where you read its status
    # and update the variables so the values would be reported back
    # to AWSIoT
    temperature = temperature;
    barometer = barometer;

# Actually starts here      
if __name__ == "__main__":
    # these are the two aws subscriptions you need to operate with
    # the 'delta' is for changes that need to be taken care of
    # and the 'documents' is where the various states and such
    # are kept
    awsShadowDelta = "$aws/things/house/shadow/update/delta"
    awsShadowDocuments = "$aws/things/house/shadow/update/documents"
    # this is the mqtt resource that you respond to when you change 
    # something.
    awsShadowUpdate = "$aws/things/house/shadow/update"
    # create an aws mqtt client and set up the connect handlers
    awsMqtt = mqtt.Client()
    awsMqtt.on_connect = on_awsConnect
    awsMqtt.on_message = on_awsMessage
    # certificates, host and port to use
    awsHost = "data.iot.us-east-1.amazonaws.com"
    awsPort = 8883
    caPath = "/home/pi/src/house/keys/aws-iot-rootCA.crt"
    certPath = "/home/pi/src/house/keys/cert.pem"
    keyPath = "/home/pi/src/house/keys/privkey.pem"
    # now set up encryption and connect
    awsMqtt.tls_set(caPath, certfile=certPath, keyfile=keyPath, cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
    awsMqtt.connect(awsHost, awsPort, keepalive=60)
    print ("did the connect to AWSIoT")
    
    # Now that everything is ready start the mqtt loop
    awsMqtt.loop_start()
    print ("mqtt loop started")

    # this timer fires every so often to update the
    # Amazon alexa device shadow; check 'seconds' below
    shadowUpdateTimer = timer(updateIotShadow, seconds=10)
    weatherUpdate = timer(updateWeather, seconds=3)
    print("Alexa Handling started")

    # The main loop
    while True:
        # Wait a bit
        checkTimer.tick()
        time.sleep(0.5)

Now, as usual, I'm going to step you through it so you have a chance of understanding what is going on. You'll have to adapt this to your devices and it's best if you understand it instead of copy and paste.

So, let's go to the bottom of the code where it says "Actually starts here," and see how to set things up. I start off with creating a couple of variables that hold the subscriptions that will be used. These will certainly be different from yours, so put your own device name in here where mine says 'house'. Then I create another one for the mqtt topic that we will be responding to. Same thing, change it to match yours.

Take special note here that this is a regular old mqtt client implementation, I DID NOT use their special library because of problems I encountered with it.

The next hunk of code we've seen and gone through the explanation already when we set up to send sensor data up to AWSIot, so I'm not going to repeat myself here <link>. Down at the line where I talk about timers, you'll see two of them; one is for updating the Shadow and the other is for updating the variables that I'm using to simulate real sensor devices. That code is so you can slip in whatever code you need to get the values and save them for updating AWSIoT. I do a lot of stuff with timers since it allows other processes to get time to run. That way I leverage all the power I can out of a little Raspberry Pi.

Below that, I just sleep for a half-second and update my timer and go back to sleep. Every 3 seconds I update the sensor variables and every 10 seconds I update AWSIot. Those numbers seem to work reasonably well for a demo, but you may want to play with them in your particular situation.

So, now that I'm hung up in a loop waiting for events (timers and such), I'll get a call to on_awsConnect() that is the result of the awsMqtt.connect() call I did a little up the page. The handler awsConnect() is up at the top of the file and that's where we'll subscribe to the two mqtt topics we need to listen to:

client.subscribe ([(awsShadowDelta , 1 ),
                      (awsShadowDocuments, 1)])

The Delta one is where commands come from and the Documents is where you get a report on the actual contents of the Shadow; we'll use both of them in this. 

Once we have subscribed, the timer will expire for updating the Shadow and we'll compose a JSON message to AWSIot that holds the state of the items we're reporting. This is done in the routine updateIotShadow() and covered in the other post I mentioned (twice now) and is sent to the 'update' topic:

 err = awsMqtt.publish(awsShadowUpdate,report)
 if err[0] != 0:
     print("got error {} on publish".format(err[0]))

And, the shadow now contains the latest information for Alexa to grab and report back to you through the Dot. Notice that I added the patio light in there.

Now we get to the good part, tell the Dot to turn on the east patio light and the voice service will compose an intent, and send it to the Lambda function which will format a 'desire' into the Shadow document. AWSIot will look at this desire and notice that it's different from what the Shadow currently is and create a 'delta'. Remember that all this is just JSON text inside the Shadow document, there's nothing magical going on.

The 'delta' portion of the JSON is sent to the mqtt topic I stuffed in the variable awsShadowDelta and the Pi code will be called at on_awsMessage() and handed the message. The code in the message handler is totally new, so let's step through it a bit closer.

    # If you want to see the shadow documents to observe what is going on
    # uncomment the prints below.
    #print "TOPIC = ",
    #print msg.topic
    #print "PAYLOAD = ",
    payload = {}
    payload = json.loads(msg.payload)
    #pp.pprint (payload)
    #print ""

Like it says, there's the opportunity to get further debugging as you need it here, but all this basically does is get the contents of the delta into a variable called 'payload'.

    if msg.topic == awsShadowDelta:
        print "got a delta"
        pp.pprint(payload["state"])
        for item in payload["state"].keys():
            if item == "eastPatioLight":
                command = str(payload["state"][item])
                print "got command for east patio light: ", command
                # This is where you would actually do something to
                # change the state of a device.
                eastPatioLight = command
            else:
                print("I don't know about item ", item)

I look at the mqtt topic and see if it's a delta message, print it so you can see what you got and then step through each (there can be more than one) item and change that came in. I index into payload and grab the command for eastPatioLight and set the variable to whatever came in. Seems simple right? Frankly, this was a real pain to figure out, but I finally got there.

That's it for handling the delta and turning on the patio light, but there's a ton of code just below that handles cleaning up after the command has been processed. What's going on is that the delta message keeps coming until it has been removed. This makes perfect sense when you consider that something may happen to the original message and it may need to be resent to accomplish whatever is needed. However, it does need to be taken care of.

What I do here is get the delta from a different mqtt subscription I called awsShadowDocuments which has all three sections in it. It has the desire, reported and delta all in one neat package. So, I just get the desired entry, look for it in the reported JSON and remove it if it's already been reported back in the correct state.

    elif msg.topic == awsShadowDocuments:
        #print "got full thing"
        
        # AWSIoT sends the 'reported' state back to you so you can
        # do something with it if you need to. With the exception of
        # this code, I don't need to deal with it ... yet.
        if "desired" not in payload["current"]["state"]:
            #print "'desired' not there"
            return
        desired = payload["current"]["state"]["desired"]
        reported = payload["current"]["state"]["reported"]
        #pp.pprint (reported)
        
        # This is probably a left over 'desired' state, which means
        # you've already changed something, but the desire is still
        # left hanging around, so compare it with the reported state
        # and if it has been satisfied, remove the desire from AWSIoT
        pp.pprint (desired)
        fixit = False
        fixitString = "{ \"state\" : { \"desired\": {"
        for item in desired.keys():
            # when updating this, you'll often encounter
            # items that aren't fully implemented yet
            # (because you're still working on them)
            # this not reported it's just to keep from dying
            if not reported.get(item):
                print ("found odd item " + item)
                break
            if desired[item] == reported[item]:
                fixit = True
                print "found left over desire at", item
                # to get rid of a desire, set it to null
                fixitString += "\"" + item + "\": null,"
        if not fixit:
            return
        fixitString = fixitString[:-1] #remove the trailing comma JSON doesn't like it
        fixitString +="} } }"
        print "sending:", fixitString
        err = awsMqtt.publish("$aws/things/house/shadow/update",fixitString)
        if err[0] != 0:
            print("got error {} on publish".format(err[0]))


Pay special attention to the above where I iterated through the desire JSON because there may be more than one thing in there; especially if you've been testing various items. And, of course, there's the usual catch all else statement:

    else:
        print "I don't have a clue how I got here"

And, that's it. We've covered the entire code that runs on the Pi to catch requests sent by the Lambda function created in the last post. Cool.

Also, we've actually stepped through a full build of the voice system. You can now actually control something in your house using voice; way better than a 'Clapper' (if you don't know, google it).

This is the last post where I'll work through the various topics, I'm going to put together an Errata post where I'll list some of the gotchas that can creep up and get you, but that may be a while. Also, understand something, you can't just say, "Turn on East patio light," it doesn't work that way. Using the code and methods I presented you have two methods of controlling things. For example:

Alexa (wait for it to hear you and wake up)
ask (or tell) desert home turn on east patio light
(it will respond back whatever you put in the Lambda function)

or

Alexa (wait for it to hear you and wake up)
Desert home (wait for it to respond with text from your Lambda function)
east patio light on

The first will get you there in one sentence, the other takes two, but is more fun. Due to the way I coded it, both will keep the session open for 10 seconds so you can do another command. I generally check the temperature and something else in one session, then tell it to "stop". Yes, I have code in there to handle the "stop" command.

Yes, you DO have to say both Alexa and your thing name (desert home in my case); this isn't Star Trek yet. However, once you get in session you can say a command over and over as long as you don't wait 10 seconds and the automatic session tear down happens. So:

Alexa
Desert home (wait for response)
East patio light on (wait for response)
What is the temperature? (wait)
What is the windspeed? (wait)
Turn off outside lights (wait)
etc.

The automatic session tear down is 10 seconds and can't be changed. Otherwise, someone out there would set it for hours eating up Amazon resources.

Another thing, remember back a bunch of postings ago where I told you that they change the interface often and without warning? Well during the period of putting together these posts they implemented an entirely new interface for AWSIoT and I had to prowl around it for about thirty minutes to get any information about what was going on with my implementation. You'll probably have to prowl a bit also.

Like I said, there hundreds of them spread around the world and only one of me out here in the desert.

Sigh.

Yet another post (I forgot something) <link>

Monday, November 21, 2016

Amazon Dot: Let's Turn Something On

Last post <link> we got data all the way from a Raspberry Pi up to Amazon and back to the Dot and it was able to say,  "The temperature is 79 degrees, " and we were excited. What, you got an error? How the heck do you troubleshoot this thing?

Fortunately, there actually is a way of doing this, even with the fact that they pass complex JSON strings around to carry data from one subsystem to another. The screen you got last time:


has the json string you need to test directly into the Lamba function we created in a previous post <link>. Simply copy the entire 'Lambda Request' and then paste it into the test screen for the Lambda function. I know this description leaves a lot of questions, so let's look a bit closer:

First copy the entire text from the Lambda Request shown above, then go to the Lambda Management Console:


Then select Actions -> Configure Test Event


They don't have a blank test event or something really close to what you need, so just chooses the first one 'GetNextFact' and replace ALL the text inside the edit box with what you saved above. This will replace the default with what you want. Save it; you have to scroll down on the page to get the save button to show.

Now, you're ready to actually feed the JSON to your Lambda function. You can now press the 'Test' button and see what happens. I can't really be much help on specific errors because I can't know in advance what kinds of problems you'll hit, but there should be enough information to get you started.

You can also edit the test event you just created to test other things, I used one test event to test most of my information requests; things like 'temperature', 'rainfall', by just changing the intent name inside the JSON string.

Now you have some hope of being able to debug this thing, so let's walk through adding control of something from the Dot. This time I'm going to start with the voice interaction and work down to the Raspberry Pi at my house instead of the other way around. The reason for doing it this way is because we now have the basic infrastructure in place and adding things is easier from the Dot back to the Pi. We'll start at the Alexa Interaction Model which looks like this:


There needs to be an intent added and I'm using the one I added first to my setup. The intent is ControlEastPatioLight and it has two 'slots', on and off, so I named the type onOff. Very clever of me. Just below the intent window, I added a new slot called (duh) onOff:


And the contents of the slot is:


What's happening is that Alexa doesn't send the actual text that is spoken, it sends intents which may contain enumerations to the Lambda function. Enumerations are simply things that can be chosen from a pre-defined list. In this case the two slot values I chose were 'on' and 'off'. I could have used 0 and 1, or Fred and Mary, it doesn't matter what they are, what matters is that they make sense to you because you have to use them later in actually controlling your devices.

Now, for the utterances, I used the simplest ones I could think of:


I highlighted the two above that I use for the light. The '{state}' refers back to the intent I created above and will be replaced with either on or off from the slot definition based on what you actually say to the Dot. Alexa actually parses through the sound and inserts its best guess about you said into the JSON string that will be sent to the Lambda function. So, save this work and go test it in the test screen:


Your Lambda Response will be an error because you haven't added the code yet, but the test generated the Lambda Request you'll need to test the new capability you're adding, so copy it out of the Request window and go over to the Lambda function and paste it into the test configuration before it gets lost:


It's not ready to test yet since we don't have any code to support it, but save it now for uses later. We're going to add code now to support the new intent. In the code window which you will see after you save the  event template you want to add the code. The window is small and hard to use, but you can scroll all the way down to the bottom of the little code window and there will be a button to expand it to full screen, I use this to edit since there just isn't enough visible to get proper context for changes:


The button is in the image above over on the right; I put the cursor there so you could find it. I searched for this for about 20 minutes the first time.

Add a couple of lines into the intent handling to get you to a routine that will format the mqtt request that the AWSIoT needs:


I highlighted the lines in the picture above. Now you need the code to create the mqtt request:


It just barely fit on the screen. Since you've already done this once, it should be easily recognized with the difference being the payload object and a call to updateThingShadow(). I think it's pretty intuitive what is going on here. A JSON fragment string is created with the content of the slot created above and passed off to the shadow as a 'desired' item. Now you're starting to understand why I described the operation of a 'Device Shadow' so carefully back a few posts ago <link>; the interaction of the shadow and the code on the Raspberry Pi is very important to getting this stuff working.  I know how big a pain in the bottom it is to read from a post and try to type it in, so here's the code above you can copy and paste with:

function controlEastPatioLight (intent, session, callback) {
    var repromptText = null;
    var sessionAttributes = {};
    var shouldEndSession = false;
    var speechOutput = "";
    var newstate = intent.slots.state.value;

    //Set the light to 0 to turn it off
    var payloadObj={ "state":
                        { "desired":
                            {"eastPatioLight":newstate}
                        }
                 };
    //Prepare the parameters of the update call
    var paramsUpdate = {
        "thingName" : config.IOT_THING_NAME,
        "payload" : JSON.stringify(payloadObj)
    };

    //Update Device Shadow
    iotData.updateThingShadow(paramsUpdate, function(err, data) {
        if (err){
           console.log(err, err.stack); // an error occurred
        }
        else {
            speechOutput = "The east patio light has been turned " + newstate + "!";
            console.log(data);
            callback(sessionAttributes,buildSpeechletResponse(intent.name, speechOutput, repromptText, shouldEndSession));
        }    
    });
}


Be sure to change the various names to something you'll understand later.

Once again, we don't actually send a command to the Pi to change something, we send a desire. That desire is pulled off the mqtt queue and used to do the actual change, then we publish back the new state. But, if you get confused, go back and read the explanation I linked to in the last paragraph.

That's it for right now, the next post has a bunch of code in it for the raspberry pi to get the desire and do something about it. It's going to get confusing to both read and for me to write, so next post.

Have fun, and feel free to work ahead, you can actually see the desire created and sent over in AWSIot if you want to.

The next post in this series is here <link>

Wednesday, November 16, 2016

Amazon Dot, Let's Connect Alexa to the Lambda Function

Last Post <link> we did one more of the seemingly interminable steps to voice control in our house, the Lambda function, but we couldn't test it because we didn't have the proper input for it.  So, let's get into Alexa and create a voice service so we can actually start talking to it.

For those of you that jumped into the middle of this project, Alexa is the Amazon Voice Service that is the engine behind the Dot, Echo, that silly little switch they just came out with and probably more devices over time. It works pretty well and is actually pretty awesome for picking up voice in a house. I want it to control the items in the house with voice commands, and this is my latest attempt.

The really, really good news is that this is the last chunk of stuff we have to take on before we can get data from the house. We still have to work through the steps to send data, but all the major pieces will be there and we will get to just expand the capabilities.

So, sign into the Amazon Developer Console <link> and look up at the top black bar for 'Alexa' and click on it.


This is a tiny bit tricky because it looks like you want the 'Alexa Voice Service', but you really want the 'Alexa Skills Kit'. The voice service (in this case) is really meant for manufacturers to create interfaces for their devices. It's where folk like Belkin and Philips go to do things. If you have a hundred or so developers to work on this and relatively unlimited funds, by all means, go for it. If you're basically me, one guy trying to do something cool to have fun with, you definitely want the skills kit, so click on it.


This is what it looks like AFTER you create a skill, you want to 'Add a New Skill', which will take you to the next step:


Fill this in and click next. Remember, you want a 'Custom Interaction Model'. But, some advice on the 'Invocation Name', keep it short. Don't use something like, "Bill's really cool interface to the brown house at the corner," because you'll be saying this over, and over, and over. I used "Desert Home" and it's too darn long. 


And here you are at the Interaction Model screen. Now you get to actually do some cool stuff. The top box is for a rather simple set of JSON (of course) strings, and the bottom is for 'utterance' that will use those JSON strings to create requests that will be spoon fed to the Lambda function we just created. Here's the intents for the Lambda function we created previously:


It's a JSON string with a table of  'intent' entries. Now we want to scroll down a bit to put in some utterances:


And 'Save' them. The save function will actually create the model which means you may get an error. So far, the errors I've had were relatively self-explanatory. Things like misspelling a word or forgetting a comma. Each of the lines of  the utterances start off with one of the intents you defined in the first box and the rest of it are regular words that you speak to the Dot. The more of these utterance you put in, the smoother it seems to work when you use it. For now, just put a few in, you can add to them later as you see fit. When you get it saved; I mean really saved, and see the message above, click 'Next'.


The 'Service Endpoint Type' is AWS Lambda of course because we went to all the trouble of creating a Lambda function for it, and you do not want users to link their accounts to this. Linking accounts is for selling services through Amazon. When you click on the Lamba radio button, it will open a couple of items you have to fill in:


Since Alexa only works in North America that button is obvious, the empty field is something to drive you nuts. Notice they don't give you a hint what they want in here? No help button, ... NOTHING!

What they want is the arn (Amazon resource number) of the Lambda we created last post, so go there and get it. Copy it out and paste it in here. I put mine in there so you could see what it looks like. Now, click 'Next'


You're on the TEST SCREEN !! Finally, you get to do something and see something happen. Sure, we saw a little bit happen way back when we were messing with the mqtt interface to the AWSIot, but that was way back there. This time we get to actually try some voice related stuff. Whoo Hoo.

Just ignore the silly blue message about completing the interaction model. That message seems to always be there; click the enable button and watch the glorious test screen expand:


You get a voice simulator where you can type stuff in and have Alexa speak it back to you. There's a service simulator where you can type in text and Alexa will shape it into a JSON string that will be sent to the Lambda function, which will do whatever you told it to do and send back a response (or error) that you see in the other window. If it works, there's a button down the screen that will allow you to play the text from the response. Here's what one interaction (that actually worked) looks like:


The Lambda request window is where you can copy the JSON to use in testing the Lambda function directly, you just configure a test, copy that stuff in and go for it. 

You DON'T want to publish this. If you publish it, you'll be allowing whoever hooks their Dot or Echo to this skill to mess with your house. It'll work just fine with your Dot, go give it a try once you work out whatever kinks that might have kicked in.

So, now we can get the temperature from our house by voice. Next we want to actually control something. That will mean changes to the voice model, the Lambda function and the code on our Pi.

Bet you can't wait for the next installment where I'm going to discuss a little bit about debugging the Lambda function and start down the path to changing something using voice commands to the house. 

Have fun.

The next post in this series is here <link>.