0

I have an AWS IOT button set up and working with IFTTT and SmartLife to turn a device on/off. Currently I have it set up to use single and double click to turn on and off, because IFTTT doesn't seem to have a toggle app (at least, not for use with SmartLife.)

How can I make it a toggle, so I can use a single click to alternately turn on and off?

Looking for a free solution.

Jeff Learman
  • 2,914
  • 1
  • 22
  • 31

1 Answers1

0

There is a solution using apilio, but it's not a free solution: Create a toggle between two actions in IFTTT .

For a free solution, use DynamoDB from Lambda to save the button state, and invert the state each invocation. It either sends "IotButton2" or "IotButton2Off" to IFTTT.

'''
Example Lambda IOT button IFTTT toggle

Test payload:
{
    "serialNumber": "GXXXXXXXXXXXXXXXXX",
    "batteryVoltage": "990mV",
    "clickType": "SINGLE" # or "DOUBLE" or "LONG"
}
'''

from __future__ import print_function

import boto3
import json
import logging
import urllib2

import boto3
from botocore.exceptions import ClientError

logger = logging.getLogger()
logger.setLevel(logging.INFO)

maker_key = 'xxxxxxxxxxxxxxxxx'  # change this to your Maker key

def get_button_state(db, name):
    table = db.Table('toggles')
    try:
        response = table.get_item(Key={'name': name})
    except ClientError as e:
        print(e.response['Error']['Message'])
    else:
        # response['item'] == {u'name': u'IotButton2', u'on': False}
        if 'Item' in response:
            return response['Item']['on']
    return False

def set_button_state(db, name, state):
    table = db.Table('toggles')
    try:
        response = table.put_item(Item={'name': name, 'on': state})
    except ClientError as e:
        print(e.response['Error']['Message'])
    
def lambda_handler(event, context):
    logger.info('Received event: ' + json.dumps(event))
    
    db = boto3.resource('dynamodb')

    maker_event = "IotButton2"
    # maker_event += ":" + event["clickType"]

    state = get_button_state(db, maker_event)
    logger.info(maker_event + " state = " + ("on" if state else "off"))

    response = set_button_state(db, maker_event, not state)

    if state:
        maker_event += "Off"

    logger.info('Maker event: ' + maker_event)
    url = 'https://maker.ifttt.com/trigger/%s/with/key/%s' % (maker_event, maker_key)
        f = urllib2.urlopen(url)
        response = f.read()
        f.close()
        logger.info('"' + maker_event + '" event has been sent to IFTTT Maker channel')
        return response

The above version responds to any type of click (single, double, long.) You can control 3 different switches by uncommenting this line:

maker_event += ":" + event["clickType"]

which would translate to these IFTTT events:

IotButton2:SINGLE
IotButton2:SINGLEOff
IotButton2:DOUBLE
IotButton2:DOUBLEOff
IotButton2:LONG
IotButton2:LONGOff

Create the DynamoDB table. For my example, the table name is "toggles" with one key field "name" and one boolean field "on". The table has to exist, but if the entry does not, it gets created the first time you click the button or test the Lambda function.

You have to update the Lambda function role to include your DynamoDb permissions. Add the following lines to the policy:

    {
        "Effect": "Allow",
        "Action": [
            "dynamodb:GetItem",
            "dynamodb:PutItem"
        ],
        "Resource": [
            "arn:aws:dynamodb:us-east-1:xxxxxxxx:table/toggles"
        ]
    }

(Get the ARN from AWS console DynamoDB -> table -> toggles -> Additional information.)

You can also edit the above function to handle multiple buttons, by checking the serial number.

Jeff Learman
  • 2,914
  • 1
  • 22
  • 31