Sunday, December 18, 2016

Home automation - Etekcity outlets meet Raspberry Pi meets Amazon Echo

I came across Sam Kear's beautiful article on controlling power outlets wirelessly and couldn't wonder about what it would take to take the next step of enabling this interaction in Amazon Echo.

It seems the universe is one boundless crucible of creativity and ideas - Chris Derossi at makermusings has already done the hard work of figuring it out.

The idea is simple:

  • Echo automatically detects Wemo devices
  • Use wireshark to reverse engineer the conversation taking place once you trigger "Discover Devices" 
  • Use fauxmo to mimic a Belkin hub and direct the request to your RESTful service that will do the needful
  • Implement your on/off behaviour via the RESTful service, internally making a system call via codesend (described in Sam Kear's posting).




This is how I went about it.

The ingredients in the recipe:
  1. Etekcity Wireless Remote Control Electrical Outlet Switch for Household Appliances: This device came on sale recently with a coupon, dropping the price to $21.48.
  2. A Raspberry Pi: I set out building it with the Model B and I hit one of the troubles he mentions in Troubleshooting,  an observation that the receiver was not super sensitive when you press the buttons on the Etekcity remote. My feeling was that the Model B is a bit underpowered for this, the frustration made me use a Model 3 (yes, Frys have it now) which was remarkably sensitive to the clicks on the receiver. Using the Model 3 also obviates the need for a Wifi dongle.
  3. Receiver transmitter
  4. A micro SD card, at least 16 GB in capacity(Elementary tip: if you want to reuse the cards on which you've written the images, you'd see a drive with reduced capacity. See the fix here.)
  5. Power adapter for the Pi (one lying around from a retired iPad came handy)
  6. GPIO Breakout and Cable for Raspberry Pi
  7. Breadboard, jumper wires, soldering iron,solder etc
  8. Wire for antenna - I used an old coat hanger connected to a wire that was soldered on to the transmitter. Works at least over 30 ft and across at least 1 floor.

Steps:
  1. Set up your Pi using Sam's posting. I don't think I can improve on something that is so well done.
  2. Find and note the on/off codes using RFSniffer.
  3. Set up fauxmo. I used the steps detailed here. 
  4. At this point, Echo should be able to find the dummy devices setup in config.json (use the Smart Home->Discover Devices link in the Alexa app). Try saying "Alexa, turn on fake switch one" and Alexa will start blinking with the blue light moving round and round, making every effort to fulfill your request, but will fail with a fairly verbose message.
  5. Install/configure flask.
    1. Create the virtual env (install virtualenv with "sudo pip install virtualenv" if you do not already have it).

      • pi@raspberrypi:~/projects/flaskserver $ virtualenv flaskvenv
        New python executable in /home/pi/projects/flaskserver/flaskvenv/bin/python
        Installing setuptools, pip, wheel...done.
        pi@raspberrypi:~/projects/flaskserver $
    2. Activate the virtual env and then install flask.
      • (flaskvenv) pi@raspberrypi:~/projects/flaskserver $ pip install Flask
    3. (This step is a placeholder for a future refinement and is not necessary). Create a directory called template and drop the index.html file here.
    4. Create your flask app . Here's mine.
    5. Create a shell script that initializes and starts flask. This will come in handy later once we start using systemd to automate flask initialization on startup.
  6. Edit the config.json file for fauxmo. Set up the codes you recorded in Step 2. Use a different port number for each device. Modify for ip address and port numbers per your setup. I've followed a format of http://ipaddress:port/<device group>/<device>/<code>. I have no idea at this point on what I might do with the device group and device values, but something tells me that some sort of grouping might be useful once I drift into tools like Home Assistant etc.
  7. Restart fauxmo. Rediscover the devices. You should see your devices from the changed config.json file now.
  8. Test with "Alexa, turn on <your device name>" and "Alexa, turn off <your device name>"
  9. If everything works all right, setup fauxmo and flask for initialization during startup. Create the service file (my samples here) and enable them with systemd (good tutorial here ):
    • sudo systemctl enable fauxmo@pi.service

Happy automating!

Saturday, November 12, 2016

A pill reminder skill


If I were to put in a time lapse photo on my journey with developing skills for the Echo, I think I would see myself poring through Amazon documentation, copying and pasting one of the skills and getting a T-shirt, writing the first set of lambda functions, making some feeble efforts at learning javascript/node and then deciding to stick with Python, figuring out how to update sets,lists and maps, in DynamoDB entities, session management, control flow for intents....and finally concluding that I'd become just about educated enough to be dangerous.

So, with a big TH to the folks at DaVincian Healthcare, who won the overall Pymnts/Alexa Challenge, I set out to build a pill reminder skill. (check out their awesome video here )

Considering that I couldn't possibly integrate with a pharmacy to just read out prescriptions and add them once prescribed by a doctor(which would have made life infinitely easier), I took the easy way out by just speaking out the names of medicines to add or remove them.

Straight off the bat, I realized a problem with this - my pronunciation of a medicine had to be identical through the life cycle of the existence of that medicine in my schedule. Variations would just add it on as a new medication, a request to remove it from my schedule would stump Alexa and have her go boing-boing at me etc. (Why am I now not surprised that, while Alexa lets me add things to my To-Do list, any removals would have to be through the app?)

Note to self:  is there a service out there that can validate text of a medicine name? If so, integrate with such service.

Secondly, a voice based interaction needs to be designed and built very differently from a screen-based interaction. eg once one start using the skill , how do they know what all they can do? Do we go, for adding a medicine, say 1, for deleting a medicine, say 2 and so on. To listen to options like those, one is better off calling Comcast - an Alexa skill needs to be a lot more friendly, engaging and intuitive. You should basically be able to have a conversation with Alexa.


But since this was an effort to be just dangerous and learn, I boldly ventured forward. I planned on developing these intents:

  • add a medicine to my schedule(which, in this case, was driven off the day of the week)
  • remove a medicine from my schedule(for a particular day of the week)
  • list all medications in my schedule
  • list medications from my schedule for a particular day of the week
  • remove all my medications from my schedule
No effort would be made to retain history of the users interactions. The last intent listed above would blow away all traces of the existence of the last known schedule for the user.

Of course, any time, you're adding or removing medicines, Alexa should prompt for a confirmation, which is where the built-in YesIntent and NoIntent intents come handy.

So, without further ado, lets get started.

  • Set up your environment (this has been discussed thread bare in all the awesome tutorials out there. Here's one in case you're still looking)
  • Attach Dynamo DB access Policy in IAM to the role you're using


  • Create a table in DynamoDB 











  • Create the lambda function. The steps are very well detailed in tutorial referenced earlier, replace the code in the handler function with code from pillButler.py
  • Setup the skill in developer portal. Use the intent schema from IntentSchema.json
  • Create the slot types
 








  • Add sample utterances from SampleUtterances.txt
  • Invoke your skill from Alexa by saying "Alexa, open pill butler"

I'd like to reiterate that this was an exercise purely for fun and learning - no effort has been made to develop a complete solution. There are many corner(and not so corner) cases that would not pass muster and I am sure that this certainly will NOT win a T-shirt from the Alexa folks at Amazon if I were to submit this for publication.There is no practical use of this skill in this shape and form, unless integrated with a pharmacy and hence, not publishing it.


Happy Echo-ing!

Wednesday, October 19, 2016

Simple behavioral changes via "Tiny Habits"


I read a book once that convinced me that habits can only be replaced, not created. To me, that was extremely convenient and served as the rationale for not changing things that worked well for me, but not so much for others.

Till I came across Dr B J Fogg and his "tiny habits". Its a very simple approach, basically trying to engender small behavioral changes by weaving in what he calls "tiny habits", and repeating them till they are ingrained.

For these to be successful, a tiny habit :
  • has an anchor .
  • is what it is - tiny. Involves an activity that can be done in less than 30 seconds and you're seeking to make a habit 
With gusto, I signed up for his session on Tiny Habits, looking to change my world, before I changed other's. Have to admit, for a free coaching session that was trying to effect behavioral change, the process was remarkably efficient.

I set out to change 3 of my behaviors that I noticed was - surprisingly - annoying others.

  • inject some positivism into my day by reminding myself, first thing in the morning, of the great day I was going to have.
  • put my shoes away once home from work
  • load my lunch box in the dishwasher once home from work.


What surprised me the most was how the changes threw up the inefficiencies around how I was organized. eg with the goal of putting away my shoes on walking in, I realized that my prevailing approach was rooted in where I'd park my car once home( in the driveway), where the shoe rack was(in the garage) and how I'd enter my home(via the front door rather than the garage!).And once I walk in thru the door, I dislike walking around the house with my shoes on, so it needs to be off and there it would lie till the next day.

Cultivating this tiny habit called for:

  • taking off shoes on walking in
  • picking them up and walking into the garage thru the connecting door(which is slightly jammed)
  • bend down to stow away the shoes on the lowest spots(age, bad back etc) - the upper ones are taken by whoever came in before me.

I think the key is to determine the sequences that help or hinder the development of a habit. And address them one by one.

Having encountered success with this, I set out to try it and help Junior who was having a hard time memorizing words to strengthen his vocabulary. So once the flash cards showed up from Walmart, we loaded a few cards on the ring that came with the set and I sat back while the process of goal-setting to cram the set of cards playing out.


The ring hardly saw any movement in the following days.

Tiny habits to the rescue. What would be a good anchor and goal to develop this tiny habit?

Anchor: ?

After a lot of deliberation, we anchored on "After I hit the bed at the end of my day". Now onto the goal.

First iteration: I will go through my set of flash cards.

Fails the sniff test. Takes more than 30 seconds and is not really tiny.

Second iteration: Reduce the number of cards to , say , 10. Still fails. It takes about 5 seconds to go through a word, especially if its new.

Third iteration: I will pick up the ring the cards are on.

Eureka!  If you've managed to remember to pick up the ring, the rest is a matter of course.


Monday, October 10, 2016

Simplest bread ever...

Since watching Heather Pierce Giannone educate me on what went into bread, I've been reading the ingredients in what I buy more carefully.

This is particularly true of bread and I think now I've found the simplest of breads in the market. Check out Trader Joe's Petit Pain Pauline. They used to have a round loaf about twice this size(I dont  think they call it "Petit" - could be wrong -  but seem to have retired it in favor of this smaller size).



How simple can it get?


Just 3 ingredients:

  • Whole wheat flour
  • Water
  • Salt
(How in the world did they manage without yeast? Defies every cooking book I've read since elementary school!)

And here's the list of ingredients on the bread that it has replaced on the menu:




Sunday, October 9, 2016

My experiments with DynamoDB:



Been playing with this amazing machine called the Amazon Echo and I too am blown away at the way the future has talked back to me.

During the course of my travels, I discovered that while the documentation is extensive, I've come face to face with a paucity of good examples on how to do CRUD operations in DynamoDB.

My experiments involved maps, lists and sets and here are some snippets from what I could get to work by going thru the documentation and the limited content available out there. All examples were tried via Lambda functions executing in AWS, writing and reading from a DynamoDB instance in AWS.

Here is the table structure against which these were performed:



With lists:


Create:


from __future__ import print_function
import logging,time
import boto3
import botocore
import json
import decimal
import sys
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError


dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Test2')

def insert_data():
    actors=["A","B","C"]

    response = table.update_item(
   Key={
        "name":"SOME_RANDOM_KEY"
   },
   UpdateExpression="set partners = :v",
   ExpressionAttributeValues={
       ':v': actors
   },
   ReturnValues="UPDATED_NEW"
    )

    print ("Insert successful!",response)



def lambda_handler(event, context):
    # TODO implement
    insert_data()
    return 'Hello from Lambda'


..gives us...


Modify:

from __future__ import print_function
import logging,time
import boto3
import botocore
import json
import decimal
import sys
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError


dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Test2')


def modify_data():
    response = table.update_item(
        Key={
             "name":"SOME_RANDOM_KEY"
        },
        UpdateExpression="SET #p = list_append(#p, :v)",  
        ExpressionAttributeNames={
            '#p': 'partners'
        },
        ExpressionAttributeValues={
            ':v': ["99"]
        },
        ReturnValues="UPDATED_NEW"
    )
    print ("Update successful!",response)


def lambda_handler(event, context):
    # TODO implement
    modify_data()
    return 'Hello from Lambda'

..gives us...



Delete:


from __future__ import print_function
import logging,time
import boto3
import botocore
import json
import decimal
import sys
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Test2')
def remove_data():
    response = table.update_item(
        Key={
             "name":"SOME_RANDOM_KEY"
        },
        UpdateExpression="REMOVE partners[1]",
        ReturnValues="UPDATED_NEW"
    )
    print ("Del successful!",response)
 
def lambda_handler(event, context):
    # TODO implement
    remove_data()
    return 'Hello from Lambda'


..gives us...




With Sets:


Create:


from __future__ import print_function
import logging,time
import boto3
import botocore
import json
import decimal
import sys
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError


dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Test2')

def insert_data():
    actors={"A","B","C"}

    response = table.update_item(
   Key={
        "name":"SOME_RANDOM_KEY"
   },
   UpdateExpression="set partners = :v",
   ExpressionAttributeValues={
       ':v': actors
   },
   ReturnValues="UPDATED_NEW"
    )

    print ("Insert successful!",response)

    
def lambda_handler(event, context):
    # TODO implement
    insert_data()
    return 'Hello from Lambda'

..gives us..


Modify:

from __future__ import print_function
import logging,time
import boto3
import botocore
import json
import decimal
import sys
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError


dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Test2')


def modify_data():
    response = table.update_item(
        Key={
             "name":"SOME_RANDOM_KEY"
        },
        UpdateExpression="ADD partners :v",  
        ExpressionAttributeValues={
            ':v': {"99"}
        },
        ReturnValues="UPDATED_NEW"
    )
    print ("Update successful!",response)

def lambda_handler(event, context):
    # TODO implement
    modify_data()
    return 'Hello from Lambda'

..gives us..


Delete:

from __future__ import print_function
import logging,time
import boto3
import botocore
import json
import decimal
import sys
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError


dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Test2')

def remove_data():
    response = table.update_item(
    Key={
        "name":"SOME_RANDOM_KEY"
    },
    UpdateExpression="DELETE partners  :v ",  
    ExpressionAttributeValues={
       ':v': {"A"}    
    } ,
    ReturnValues="UPDATED_NEW"
)
    print ("Del successful!",response)
    
def lambda_handler(event, context):
    # TODO implement
    remove_data()
    return 'Hello from Lambda'

...gives us..


Saturday, July 30, 2016

A beautiful morning, a beautiful creature and a simple photo touching tool

On a bright, pleasant  summer morning, I ran into this fellow who seemed to be enjoying the day as much as I was.

My first attempt at touching up a photo with Gimp left a lasting impression.