Bastiaan Slee
Published © GPL3+

Coffee Machine: Amazon Alexa & Raspberry Pi

Order Coffee with your voice!

AdvancedFull instructions providedOver 1 day19,425

Things used in this project

Hardware components

Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
×1
USB Microphone
×1
Philips Senseo Coffee Machine
×1
Creative Labs I-Trigue Speakers
Any speaker set with a 3.5mm jack connector will work
×1
Optocoupler 4n35
×18
Resistor 1k ohm
Resistor 1k ohm
×11
Resistor 221 ohm
Resistor 221 ohm
×7
LED (generic)
LED (generic)
×3
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
×1

Software apps and online services

Alexa Skills Kit
Amazon Alexa Alexa Skills Kit
Alexa Voice Service
Amazon Alexa Alexa Voice Service
AWS IoT
Amazon Web Services AWS IoT
AWS Lambda
Amazon Web Services AWS Lambda

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Voice User Interface

This is the Voice User Interface to show the connection between the Amazon services, the Raspberry Pi and my Coffee Machine. It does also include sample sentences.
File missing, please reupload.

All code used

This RAR file does contain all code I used for this project. Replace the ****** with your own credentials and add your certificates.

Code

AlexaPi.py

Python
The connection between Alexa and the Raspberry Pi. This is a modified version of the version on Github, see comments in the text above. (to be installed on the Raspberry Pi)
#! /usr/bin/env python

import os
import time
import RPi.GPIO as GPIO
import alsaaudio
from creds import *
import requests
import json
from memcache import Client
import vlc
import email
import sys
import datetime
import webrtcvad

#Settings
button = 26         # GPIO Pin with button connected
plb_light = 6        # GPIO Pin for the playback light
act_light = 13        # GPIO Pin for the activity light
rec_light = 19        # GPIO Pin for the recording light
device = "plughw:1" # Name of your microphone/sound card in arecord -L
debug = True

#Set the GPIO for the LEDs and the button
GPIO.setmode(GPIO.BCM)

GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.setup(plb_light, GPIO.OUT)
GPIO.output(plb_light, GPIO.LOW)

GPIO.setup(act_light, GPIO.OUT)
GPIO.output(act_light, GPIO.LOW)

# The red LED (recording) is set to PWM as I want 2 grades in light; 20% for recording, 100% for recognizing voice
rec_dim = 20         # the brightness of the LED in dimmed mode
GPIO.setup(rec_light, GPIO.OUT)
rec_light_pwm = GPIO.PWM(rec_light, 100)    # create object for PWM at 100 Hertz  
rec_light_pwm.start(1) #Start very dim to show that Alexa is awake


#Setup Alexa
recorded = False
servers = ["127.0.0.1:11211"]
mc = Client(servers, debug=1)
path = os.path.realpath(__file__).rstrip(os.path.basename(__file__))

#Variables
p = ""
position = 0
audioplaying = False
button_pressed = False
start = time.time()
vad = webrtcvad.Vad(2)
currVolume = 100

# constants 
VAD_SAMPLERATE = 16000
VAD_FRAME_MS = 30
VAD_PERIOD = (VAD_SAMPLERATE / 1000) * VAD_FRAME_MS
VAD_SILENCE_TIMEOUT = 1000
MAX_RECORDING_LENGTH = 8 

#Colors for logging
class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

def internet_on():
    print("Checking Internet Connection...")
    try:
        r =requests.get('https://api.amazon.com/auth/o2/token')
        print("Connection {}OK{}".format(bcolors.OKGREEN, bcolors.ENDC))
        return True
    except:
        print("Connection {}Failed{}".format(bcolors.WARNING, bcolors.ENDC))
        return False

def gettoken():
    token = mc.get("access_token")
    refresh = refresh_token
    if token:
        return token
    elif refresh:
        payload = {"client_id" : Client_ID, "client_secret" : Client_Secret, "refresh_token" : refresh, "grant_type" : "refresh_token", }
        url = "https://api.amazon.com/auth/o2/token"
        r = requests.post(url, data = payload)
        resp = json.loads(r.text)
        mc.set("access_token", resp['access_token'], 3570)
        return resp['access_token']
    else:
        return False

def alexa_speech_recognizer():
    # https://developer.amazon.com/public/solutions/alexa/alexa-voice-service/rest/speechrecognizer-requests
    GPIO.output(act_light, GPIO.HIGH)
    if debug: print("{}Sending Speech Request...{}".format(bcolors.OKBLUE, bcolors.ENDC))
    url = 'https://access-alexa-na.amazon.com/v1/avs/speechrecognizer/recognize'
    headers = {'Authorization' : 'Bearer %s' % gettoken()}
    d = {
        "messageHeader": {
            "deviceContext": [
                {
                    "name": "playbackState",
                    "namespace": "AudioPlayer",
                    "payload": {
                    "streamId": "",
                        "offsetInMilliseconds": "0",
                        "playerActivity": "IDLE"
                    }
                }
            ]
        },
        "messageBody": {
            "profile": "alexa-close-talk",
            "locale": "en-us",
            "format": "audio/L16; rate=16000; channels=1"
        }
    }
    with open(path+'recording.wav') as inf:
        files = [
                ('file', ('request', json.dumps(d), 'application/json; charset=UTF-8')),
                ('file', ('audio', inf, 'audio/L16; rate=16000; channels=1'))
                ]
        r = requests.post(url, headers=headers, files=files)
    GPIO.output(act_light, GPIO.LOW)
    process_response(r)
    

def alexa_playback_progress_report_request(requestType, playerActivity, streamid):
    # https://developer.amazon.com/public/solutions/alexa/alexa-voice-service/rest/audioplayer-events-requests
    # streamId                  Specifies the identifier for the current stream.
    # offsetInMilliseconds      Specifies the current position in the track, in milliseconds.
    # playerActivity            IDLE, PAUSED, or PLAYING
    if debug: print("{}Sending Playback Progress Report Request...{}".format(bcolors.OKBLUE, bcolors.ENDC))
    headers = {'Authorization' : 'Bearer %s' % gettoken()}
    d = {
        "messageHeader": {},
        "messageBody": {
            "playbackState": {
                "streamId": streamid,
                "offsetInMilliseconds": 0,
                "playerActivity": playerActivity.upper()
            }
        }
    }
    
    if requestType.upper() == "ERROR":
        # The Playback Error method sends a notification to AVS that the audio player has experienced an issue during playback.
        url = "https://access-alexa-na.amazon.com/v1/avs/audioplayer/playbackError"
    elif requestType.upper() ==  "FINISHED":
        # The Playback Finished method sends a notification to AVS that the audio player has completed playback.
        url = "https://access-alexa-na.amazon.com/v1/avs/audioplayer/playbackFinished"
    elif requestType.upper() ==  "IDLE":
        # The Playback Idle method sends a notification to AVS that the audio player has reached the end of the playlist.
        url = "https://access-alexa-na.amazon.com/v1/avs/audioplayer/playbackIdle"
    elif requestType.upper() ==  "INTERRUPTED":
        # The Playback Interrupted method sends a notification to AVS that the audio player has been interrupted. 
        # Note: The audio player may have been interrupted by a previous stop Directive.
        url = "https://access-alexa-na.amazon.com/v1/avs/audioplayer/playbackInterrupted"
    elif requestType.upper() ==  "PROGRESS_REPORT":
        # The Playback Progress Report method sends a notification to AVS with the current state of the audio player.
        url = "https://access-alexa-na.amazon.com/v1/avs/audioplayer/playbackProgressReport"
    elif requestType.upper() ==  "STARTED":
        # The Playback Started method sends a notification to AVS that the audio player has started playing.
        url = "https://access-alexa-na.amazon.com/v1/avs/audioplayer/playbackStarted"
    
    r = requests.post(url, headers=headers, data=json.dumps(d))
    if r.status_code != 204:
        print("{}(alexa_playback_progress_report_request Response){} {}".format(bcolors.WARNING, bcolors.ENDC, r))
    else:
        if debug: print("{}Playback Progress Report was {}Successful!{}".format(bcolors.OKBLUE, bcolors.OKGREEN, bcolors.ENDC))

def process_response(r):
    global currVolume, isMute
    if debug: print("{}Processing Request Response...{}".format(bcolors.OKBLUE, bcolors.ENDC))
    if r.status_code == 200:
        data = "Content-Type: " + r.headers['content-type'] +'\r\n\r\n'+ r.content
        msg = email.message_from_string(data)        
        for payload in msg.get_payload():
            if payload.get_content_type() == "application/json":
                j =  json.loads(payload.get_payload())
                if debug: print("{}JSON String Returned:{} {}".format(bcolors.OKBLUE, bcolors.ENDC, json.dumps(j)))
            elif payload.get_content_type() == "audio/mpeg":
                filename = path + "tmpcontent/"+payload.get('Content-ID').strip("<>")+".mp3" 
                with open(filename, 'wb') as f:
                    f.write(payload.get_payload())
            else:
                if debug: print("{}NEW CONTENT TYPE RETURNED: {} {}".format(bcolors.WARNING, bcolors.ENDC, payload.get_content_type()))
        
        # Now process the response
        if 'directives' in j['messageBody']:
            if len(j['messageBody']['directives']) == 0:
                if debug: print("0 Directives received")
                for x in range(0, 3):
                    time.sleep(.1)
                    GPIO.output(act_light, GPIO.HIGH)
                    time.sleep(.1)
                    GPIO.output(act_light, GPIO.LOW)
            for directive in j['messageBody']['directives']:
                if directive['namespace'] == 'SpeechSynthesizer':
                    if directive['name'] == 'speak':
                        GPIO.output(plb_light, GPIO.HIGH)
                        play_audio(path + "tmpcontent/"+directive['payload']['audioContent'].lstrip("cid:")+".mp3")
                        GPIO.output(plb_light, GPIO.LOW)
                    for directive in j['messageBody']['directives']: # if Alexa expects a response
                        if directive['namespace'] == 'SpeechRecognizer': # this is included in the same string as above if a response was expected
                            if directive['name'] == 'listen':
                                if debug: print("{}Further Input Expected, timeout in: {} {}ms".format(bcolors.OKBLUE, bcolors.ENDC, directive['payload']['timeoutIntervalInMillis']))

                                #play_audio(path+'audio/sound_beep.wav', 0, 100)
                                timeout = directive['payload']['timeoutIntervalInMillis']/116
                                # listen until the timeout from Alexa
                                silence_listener(timeout)
                                # now process the response
                                alexa_speech_recognizer()
        return
    elif r.status_code == 204:
        GPIO.output(rec_light, GPIO.LOW)
        for x in range(0, 3):
            time.sleep(.2)
            GPIO.output(plb_light, GPIO.HIGH)
            time.sleep(.2)
            GPIO.output(plb_light, GPIO.LOW)
        if debug: print("{}Request Response is null {}(This is OKAY!){}".format(bcolors.OKBLUE, bcolors.OKGREEN, bcolors.ENDC))
    else:
        print("{}(process_response Error){} Status Code: {}".format(bcolors.WARNING, bcolors.ENDC, r.status_code))
        r.connection.close()
        GPIO.output(lights, GPIO.LOW)
        for x in range(0, 3):
            time.sleep(.2)
            GPIO.output(rec_light, GPIO.HIGH)
            time.sleep(.2)
            GPIO.output(lights, GPIO.LOW)

def play_audio(file, offset=0, overRideVolume=0):
    global currVolume
    global p, audioplaying
    k = file.rfind("/") #find the start of the filename from the full path
    new_file = file[k+1:] #filname only
    if debug: print("{}Play_Audio Request for:{} {}".format(bcolors.OKBLUE, bcolors.ENDC, new_file))
    i = vlc.Instance('--aout=alsa') # , '--alsa-audio-device=mono', '--file-logging', '--logfile=vlc-log.txt')
    m = i.media_new(file)
    p = i.media_player_new()
    p.set_media(m)
    mm = m.event_manager()
    mm.event_attach(vlc.EventType.MediaStateChanged, state_callback, p)
    audioplaying = True
    if (overRideVolume == 0):
        p.audio_set_volume(currVolume)
    else:
        p.audio_set_volume(overRideVolume)
    p.play()
    while audioplaying:
        continue


def state_callback(event, player):
    global nav_token, audioplaying, streamurl, streamid
    state = player.get_state()
    #0: 'NothingSpecial'
    #1: 'Opening'
    #2: 'Buffering'
    #3: 'Playing'
    #4: 'Paused'
    #5: 'Stopped'
    #6: 'Ended'
    #7: 'Error'
    #if debug: print("{}Player State:{} {}".format(bcolors.OKGREEN, bcolors.ENDC, state))
    if state == 5:    #Stopped
        audioplaying = False
    elif state == 6:    #Ended
        audioplaying = False
    elif state == 7:
        audioplaying = False


def detect_button(channel):
    global button_pressed
    button_pressed = True
    if debug: print("{}Button Pressed!{}".format(bcolors.OKBLUE, bcolors.ENDC))
    time.sleep(.5) # time for the button input to settle down
    while (GPIO.input(button)==0): #button seems to still be pressed
        button_pressed = True
        time.sleep(.1)
    button_pressed = False
    time.sleep(.5) # more time for the button to settle down
        
def silence_listener(MaxRecordingLength):
    global rec_light_pwm

    rec_light_pwm.ChangeDutyCycle(rec_dim)
    print("{}Recording...{}".format(bcolors.OKBLUE, bcolors.ENDC))
    play_audio(path+"audio/sound_start.mp3")

    # Reenable reading microphone raw data
    inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, device)
    inp.setchannels(1)
    inp.setrate(VAD_SAMPLERATE)
    inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
    inp.setperiodsize(VAD_PERIOD)
    audio = ""

    # Buffer as long as we haven't heard enough silence or the total size is within max size
    thresholdSilenceMet = False
    frames = 0
    numSilenceRuns = 0
    silenceRun = 0
    start = time.time()
    isSpeech = False

    # Use VAD to find out when the user STARTS talking
    while (isSpeech == False and ((time.time() - start) < MaxRecordingLength)):
        l, data = inp.read()
        if l:
            isSpeech = vad.is_speech(data, VAD_SAMPLERATE)
            if (isSpeech == True):
                audio += data
                rec_light_pwm.ChangeDutyCycle(100)
            else:
                rec_light_pwm.ChangeDutyCycle(rec_dim)


    # now do VAD to find when the user STOPS talking
    while ((thresholdSilenceMet == False) and ((time.time() - start) < MaxRecordingLength)):
        l, data = inp.read()
        if l:
            audio += data

            if (l == VAD_PERIOD):
                isSpeech = vad.is_speech(data, VAD_SAMPLERATE)

                if (isSpeech == False):
                    silenceRun = silenceRun + 1
                    rec_light_pwm.ChangeDutyCycle(rec_dim)
                else:
                    silenceRun = 0
                    numSilenceRuns = numSilenceRuns + 1
                    rec_light_pwm.ChangeDutyCycle(100)

        # only count silence runs after the first one 
        # (allow user to speak for total of max recording length if they haven't said anything yet)
        if (numSilenceRuns != 0) and ((silenceRun * VAD_FRAME_MS) > VAD_SILENCE_TIMEOUT):
            thresholdSilenceMet = True


    # User stopped talking, save record
    rf = open(path+'recording.wav', 'w')
    rf.write(audio)
    rf.close()
    inp.close()

    print("{}Recording Finished.{}".format(bcolors.OKBLUE, bcolors.ENDC))
    play_audio(path+"audio/sound_stop.mp3")
    rec_light_pwm.ChangeDutyCycle(0)


def start():
    global audioplaying, p, vad, button_pressed
    GPIO.add_event_detect(button, GPIO.FALLING, callback=detect_button, bouncetime=100) # threaded detection of button press

    while True:
        record_audio = False

        while record_audio == False:
            time.sleep(.1)

            if button_pressed:
                if audioplaying: p.stop()
                record_audio = True

        silence_listener(MAX_RECORDING_LENGTH) # start listener and wait for a silence
        alexa_speech_recognizer() # then process to Alexa
        


def setup():
    while internet_on() == False:
        print(".")
    token = gettoken()
    if token == False:
        while True:
            for x in range(0, 5):
                time.sleep(.1)
                GPIO.output(act_light, GPIO.HIGH)
                time.sleep(.1)
                GPIO.output(act_light, GPIO.LOW)

    for x in range(0, 5):
        time.sleep(.1)

        GPIO.output(plb_light, GPIO.HIGH)
        GPIO.output(act_light, GPIO.HIGH)
        rec_light_pwm.ChangeDutyCycle(100)
        time.sleep(.1)

        GPIO.output(plb_light, GPIO.LOW)
        GPIO.output(act_light, GPIO.LOW)
        rec_light_pwm.ChangeDutyCycle(rec_dim)

    rec_light_pwm.ChangeDutyCycle(0)
    play_audio(path+"audio/alexa_hello.mp3")


if __name__ == '__main__':
    try:
        print 'AlexaPi started, Press Ctrl-C to quit.'
        setup()
        start()
    finally:
        rec_light_pwm.stop()
        GPIO.cleanup()
        if debug == False: os.system("rm "+path+"tmpcontent/*")
        print 'AlexaPi stopped.'

CoffeeMachine.py

Python
Getting commands from AWS IoT to the Raspberry Pi, and processing these to GPIO connections between the Raspberry PI and the Coffee Machine. (to be installed on the Raspberry Pi)
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient
import sys
import time
import json
import os
import RPi.GPIO as GPIO


# These are my AWS IoT login and certificates
host = "**********.iot.us-east-1.amazonaws.com"
cert_path = os.path.realpath(__file__).rstrip(os.path.basename(__file__)) + "cert/"
rootCAPath = cert_path + "root-CA.crt"
certificatePath = cert_path + "**********-certificate.pem.crt"
privateKeyPath = cert_path + "**********-private.pem.key"
shadowClient = "CoffeeMachine_RaspberryPi"


# Parameters CoffeeMachine
CoffeeChoice = ["", "LATTE", "MACCHIATO", "CAPPUCCINO", "REGULAR"]
CoffeeChoice_Selected = CoffeeChoice.index("")

RegularStrength = ["", "DARK", "MEDIUM", "MILD"]
RegularStrength_Selected = RegularStrength.index("")

NumberOfCups = ["", "ONE", "TWO"]
NumberOfCups_Selected = NumberOfCups.index("")

Base_LED_One_Status = ["READY", "OFF"]
Base_LED_One_StatusSelected = Base_LED_One_Status.index("OFF")

Power_Status = ["OFF", "ON"]
Power_StatusSelected = Power_Status.index("OFF")

Base_LED_Power_Status = ["OFF", "ERROR", "BUSY", "READY"]
Base_LED_Power_StatusSelected = Base_LED_Power_Status.index("OFF")
Base_LED_Power_StatusSelected_last = Base_LED_Power_Status.index("OFF")

Base_LED_Two_Status = ["READY", "OFF"]
Base_LED_Two_StatusSelected = Base_LED_One_Status.index("OFF")

Lid_Status = ["CLOSED", "OPEN"]
Lid_StatusSelected = Lid_Status.index("CLOSED")




def IoT_to_Raspberry_Change_Power(ShadowPayload):
    global Power_StatusSelected, CoffeeChoice_Selected, RegularStrength_Selected, NumberOfCups_Selected
    # Desired = POWER change
    if (ShadowPayload == "ON" and Power_Status[Power_StatusSelected] == "OFF"): #Check if machine is indeed OFF
        GPIO.output(Base_BUT_Power, True) #Button press imitation send to the optocoupler
        time.sleep(0.1)
        GPIO.output(Base_BUT_Power, False)
        time.sleep(0.1)
        CoffeeChoice_Selected_LED() #as the machine is powering ON now, one of the LEDs will turn on, find the status
        RegularStrength_Selected_LED() #as the machine is powering ON now, one of the LEDs will turn on, find the status
        JSONPayload = '{ "state" : {'+\
                            '"reported": {'+\
                                '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                                '"Start": "NO", '+\
                                '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                                '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '", '+\
                                '"NumberOfCups": "' + NumberOfCups[NumberOfCups_Selected] + '" '+\
                            '} '+\
                        '} '+\
                    '}'
        myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values

    elif (ShadowPayload == "OFF" and Power_Status[Power_StatusSelected] == "ON"): #Check if machine is indeed ON
        GPIO.output(Base_BUT_Power, True) #Button press imitation send to the optocoupler
        time.sleep(0.1)
        GPIO.output(Base_BUT_Power, False)
        Power_StatusSelected = Power_Status.index("OFF")
        CoffeeChoice_Selected = CoffeeChoice.index("") #LEDs will now be off
        RegularStrength_Selected = RegularStrength.index("") #LEDs will now be off
        NumberOfCups_Selected = NumberOfCups.index("")
        JSONPayload = '{ "state" : {'+\
                            '"reported": {'+\
                                '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                                '"Start": "NO", '+\
                                '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                                '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '", '+\
                                '"NumberOfCups": "' + NumberOfCups[NumberOfCups_Selected] + '" '+\
                            '}, '+\
                            '"desired": {'+\
                                '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                                '"Start": "NO", '+\
                                '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                                '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '", '+\
                                '"NumberOfCups": "' + NumberOfCups[NumberOfCups_Selected] + '" '+\
                            '} '+\
                        '} '+\
                    '}'
        myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values

        
    
def IoT_to_Raspberry_Change_CoffeeChoice(ShadowPayload):
    global CoffeeChoice_Selected, RegularStrength_Selected
    # Desired = COFFEE CHOICE change
    CoffeeChoice_Selected_LED() #Double check LED status
    if (ShadowPayload <> "" and CoffeeChoice[CoffeeChoice_Selected] <> "" and Power_Status[Power_StatusSelected] == "ON"): #check if status or desired is not an empty value
        while (CoffeeChoice.index(ShadowPayload.upper()) > CoffeeChoice_Selected): #current setting does not match desired (needs to tab down)
            GPIO.output(CoffeeChoice_BUT_Down, True) #Button press imitation send to the optocoupler
            time.sleep(0.1)
            GPIO.output(CoffeeChoice_BUT_Down, False)
            time.sleep(0.1)
            CoffeeChoice_Selected_LED()

        while (CoffeeChoice.index(ShadowPayload.upper()) < CoffeeChoice_Selected): #current setting does not match desired (needs to tab up)
            GPIO.output(CoffeeChoice_BUT_Up, True) #Button press imitation send to the optocoupler
            time.sleep(0.1)
            GPIO.output(CoffeeChoice_BUT_Up, False)
            time.sleep(0.1)
            CoffeeChoice_Selected_LED()

        RegularStrength_Selected_LED() #Double check LED status
        JSONPayload = '{ "state" : {'+\
                            '"reported": {'+\
                                '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                                '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '" '+\
                            '} '+\
                        '} '+\
                    '}'
        myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values
    

def IoT_to_Raspberry_Change_RegularStrength(ShadowPayload):
    global CoffeeChoice_Selected, RegularStrength_Selected
    # Desired = REGULAR STRENGTH change
    CoffeeChoice_Selected_LED() #Double check LED status
    RegularStrength_Selected_LED() #Double check LED status

    if (ShadowPayload <> "" and RegularStrength[RegularStrength_Selected] <> "" and Power_Status[Power_StatusSelected] == "ON"): #check if status or desired is not an empty value
        if (CoffeeChoice.index("REGULAR") == CoffeeChoice_Selected): # Only possible if current selection is Regular
            while (RegularStrength.index(ShadowPayload.upper()) > RegularStrength_Selected): #current setting does not match desired (needs to tab down)
                GPIO.output(RegularStrength_BUT_Down, True) #Button press imitation send to the optocoupler
                time.sleep(0.1)
                GPIO.output(RegularStrength_BUT_Down, False)
                time.sleep(0.1)
                RegularStrength_Selected_LED()
                
            while (RegularStrength.index(ShadowPayload.upper()) < RegularStrength_Selected): #current setting does not match desired (needs to tab up)
                GPIO.output(RegularStrength_BUT_Up, True) #Button press imitation send to the optocoupler
                time.sleep(0.1)
                GPIO.output(RegularStrength_BUT_Up, False)
                time.sleep(0.1)
                RegularStrength_Selected_LED()

            JSONPayload = '{ "state" : {'+\
                                '"reported": {'+\
                                    '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '" '+\
                                '} '+\
                            '} '+\
                        '}'
            myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values



def IoT_to_Raspberry_Change_NumberOfCups(ShadowPayload):
    global NumberOfCups_Selected
    # Desired = number of cups selecction
    # no action required, will be used with Start option
    NumberOfCups_Selected = NumberOfCups.index(ShadowPayload)
    JSONPayload = '{ "state" : {'+\
                        '"reported": {'+\
                            '"NumberOfCups": "' + NumberOfCups[NumberOfCups_Selected] + '" '+\
                        '} '+\
                    '} '+\
                '}'
    myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values



def IoT_to_Raspberry_Change_Start(ShadowPayload):
    global Power_StatusSelected, CoffeeChoice_Selected, RegularStrength_Selected, NumberOfCups_Selected
    # Desired = Start
    if (ShadowPayload == "YES"):
        time.sleep (5)
        while (Base_LED_Power_Status[Base_LED_Power_StatusSelected] <> "READY"): #Only goes through if the machine is in READY state, otherwise it loops waiting for becoming ready
            time.sleep (1)
        else:
            time.sleep (1)
            if (NumberOfCups[NumberOfCups_Selected] == "ONE" and Base_LED_One_Status[Base_LED_One_StatusSelected] == "READY"): #Only goes trhough if the machine is in READY state for 1 cup
                print "Ready for one cup"
                GPIO.output(Base_BUT_One, True) #Button press imitation send to the optocoupler
                time.sleep(0.1)
                GPIO.output(Base_BUT_One, False)
                time.sleep(0.1)
                JSONPayload = '{ "state" : {'+\
                                    '"reported": {'+\
                                        '"Start":"YES" '+\
                                    '} '+\
                                '} '+\
                            '}'
                myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values
            elif (NumberOfCups[NumberOfCups_Selected] == "TWO" and Base_LED_Two_Status[Base_LED_Two_StatusSelected] == "READY"): #Only goes trhough if the machine is in READY state for 2 cups
                print "Ready for two cups"
                GPIO.output(Base_BUT_Two, True) #Button press imitation send to the optocoupler
                time.sleep(0.1)
                GPIO.output(Base_BUT_Two, False)
                time.sleep(0.1)
                JSONPayload = '{ "state" : {'+\
                                    '"reported": {'+\
                                        '"Start":"YES" '+\
                                    '} '+\
                                '} '+\
                            '}'
                myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values
            # Coffee is made, now wait 30 seconds and power off
            time.sleep (60)
            GPIO.output(Base_BUT_Power, True) #Button press imitation send to the optocoupler
            time.sleep(0.1)
            GPIO.output(Base_BUT_Power, False)
            Power_StatusSelected = Power_Status.index("OFF")
            CoffeeChoice_Selected = CoffeeChoice.index("") #LEDs will now be off
            RegularStrength_Selected = RegularStrength.index("") #LEDs will now be off
            NumberOfCups_Selected = NumberOfCups.index("")
            JSONPayload = '{ "state" : {'+\
                                '"reported": {'+\
                                    '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                                    '"Start": "NO", '+\
                                    '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                                    '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '", '+\
                                    '"NumberOfCups": "' + NumberOfCups[NumberOfCups_Selected] + '" '+\
                                '}, '+\
                                '"desired": {'+\
                                    '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                                    '"Start": "NO", '+\
                                    '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                                    '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '", '+\
                                    '"NumberOfCups": "' + NumberOfCups[NumberOfCups_Selected] + '" '+\
                                '} '+\
                            '} '+\
                        '}'
            myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values




# Shadow callback for when a DELTA is received (this happens when Lamda does set a DESIRED value in IoT)
def IoTShadowCallback_Delta(payload, responseStatus, token):
#    global Power_StatusSelected, CoffeeChoice_Selected, RegularStrength_Selected, NumberOfCups_Selected
    print(responseStatus)
    payloadDict = json.loads(payload)
    print("++DELTA++ version: " + str(payloadDict["version"]))

    # Desired = POWER change
    if ("Power" in payloadDict["state"]):
        print("Power: " + str(payloadDict["state"]["Power"]))
        IoT_to_Raspberry_Change_Power(str(payloadDict["state"]["Power"]))

    # Desired = COFFEE CHOICE change
    if ("CoffeeChoice" in payloadDict["state"]):
        print("CoffeeChoice: " + str(payloadDict["state"]["CoffeeChoice"]))
        IoT_to_Raspberry_Change_CoffeeChoice(str(payloadDict["state"]["CoffeeChoice"]))

    # Desired = REGULAR STRENGTH change
    if ("RegularStrength" in payloadDict["state"]):
        print("RegularStrength: " + str(payloadDict["state"]["RegularStrength"]))
        IoT_to_Raspberry_Change_RegularStrength(str(payloadDict["state"]["RegularStrength"]))

    # Desired = number of cups selecction
    if ("NumberOfCups" in payloadDict["state"]):
        print("NumberOfCups: " + str(payloadDict["state"]["NumberOfCups"]))
        IoT_to_Raspberry_Change_NumberOfCups(str(payloadDict["state"]["NumberOfCups"]))

    # Desired = Start
    if ("Start" in payloadDict["state"]):
        print("Start: " + str(payloadDict["state"]["Start"]))
        IoT_to_Raspberry_Change_Start(str(payloadDict["state"]["Start"]))
            



# Shadow callback GET for setting initial status
def IoTShadowCallback_Get(payload, responseStatus, token):
    print(responseStatus)
    payloadDict = json.loads(payload)
    print("++GET++ version: " + str(payloadDict["version"]))
    if ("Power" in payloadDict["state"]["desired"]):
        if(str(payloadDict["state"]["reported"]["Power"]).upper() <> str(payloadDict["state"]["desired"]["Power"]).upper()):
            print("Power: " + str(payloadDict["state"]["desired"]["Power"]))
            IoT_to_Raspberry_Change_Power(str(payloadDict["state"]["desired"]["Power"]))
            
    if ("CoffeeChoice" in payloadDict["state"]["desired"]):
        if(str(payloadDict["state"]["reported"]["CoffeeChoice"]).upper() <> str(payloadDict["state"]["desired"]["CoffeeChoice"]).upper()):
            print("CoffeeChoice: " + str(payloadDict["state"]["desired"]["CoffeeChoice"]))
            IoT_to_Raspberry_Change_CoffeeChoice(str(payloadDict["state"]["desired"]["CoffeeChoice"]))
            
    if ("RegularStrength" in payloadDict["state"]["desired"]):
        if(str(payloadDict["state"]["reported"]["RegularStrength"]).upper() <> str(payloadDict["state"]["desired"]["RegularStrength"]).upper()):
            print("RegularStrength: " + str(payloadDict["state"]["desired"]["RegularStrength"]))
            IoT_to_Raspberry_Change_RegularStrength(str(payloadDict["state"]["desired"]["RegularStrength"]))
            
    if ("NumberOfCups" in payloadDict["state"]["desired"]):
        if(str(payloadDict["state"]["reported"]["NumberOfCups"]).upper() <> str(payloadDict["state"]["desired"]["NumberOfCups"]).upper()):
            print("NumberOfCups: " + str(payloadDict["state"]["desired"]["NumberOfCups"]))
            IoT_to_Raspberry_Change_NumberOfCups(str(payloadDict["state"]["desired"]["NumberOfCups"]))
            
    if ("Start" in payloadDict["state"]["desired"]):
        if(str(payloadDict["state"]["reported"]["Start"]).upper() <> str(payloadDict["state"]["desired"]["Start"]).upper()):
            print("Start: " + str(payloadDict["state"]["desired"]["Start"]))
            IoT_to_Raspberry_Change_Start(str(payloadDict["state"]["desired"]["Start"]))




# Shadow callback for updating the AWS IoT
def IoTShadowCallback_Update(payload, responseStatus, token):
    if responseStatus == "timeout":
        print("++UPDATE++ request " + token + " timed out!")
    if responseStatus == "accepted":
        payloadDict = json.loads(payload)
        print("++UPDATE++ request with token: " + token + " accepted!")
        if ("desired" in payloadDict["state"]):
            print("Desired: " + str(payloadDict["state"]["desired"]))
        if ("reported" in payloadDict["state"]):
            print("Reported: " + str(payloadDict["state"]["reported"]))
    if responseStatus == "rejected":
        print("++UPDATE++ request " + token + " rejected!")






# Init AWSIoTMQTTShadowClient
myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient(shadowClient)
myAWSIoTMQTTShadowClient.configureEndpoint(host, 8883)
myAWSIoTMQTTShadowClient.configureCredentials(rootCAPath, privateKeyPath, certificatePath)

# AWSIoTMQTTShadowClient configuration
myAWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10)  # 10 sec
myAWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5)  # 5 sec

# Connect to AWS IoT
myAWSIoTMQTTShadowClient.connect()

# Create a deviceShadow with persistent subscription
myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)





 

#Now start setting up all GPIO required things like the PINs, and the interrupts
GPIO.setmode(GPIO.BCM)


# Coffee Choice LEDs at the lid
CoffeeChoice_LED_Latte = 7
GPIO.setup(CoffeeChoice_LED_Latte, GPIO.IN, pull_up_down=GPIO.PUD_UP)

CoffeeChoice_LED_Macchiato = 1
GPIO.setup(CoffeeChoice_LED_Macchiato, GPIO.IN, pull_up_down=GPIO.PUD_UP)

CoffeeChoice_LED_Cappuccino = 12
GPIO.setup(CoffeeChoice_LED_Cappuccino, GPIO.IN, pull_up_down=GPIO.PUD_UP)

CoffeeChoice_LED_Regular = 16
GPIO.setup(CoffeeChoice_LED_Regular, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# At start find to which Coffee Choice the machine is set, also of one of these LEDs is ON, the machine is ON
def CoffeeChoice_Selected_LED():
    global Power_StatusSelected, CoffeeChoice_Selected
    if (GPIO.input(CoffeeChoice_LED_Latte) == 0):
        CoffeeChoice_Selected = CoffeeChoice.index("LATTE")
        Power_StatusSelected = Power_Status.index("ON")
    elif (GPIO.input(CoffeeChoice_LED_Macchiato) == 0):
        CoffeeChoice_Selected = CoffeeChoice.index("MACCHIATO")
        Power_StatusSelected = Power_Status.index("ON")
    elif (GPIO.input(CoffeeChoice_LED_Cappuccino) == 0):
        CoffeeChoice_Selected = CoffeeChoice.index("CAPPUCCINO")
        Power_StatusSelected = Power_Status.index("ON")
    elif (GPIO.input(CoffeeChoice_LED_Regular) == 0):
        CoffeeChoice_Selected = CoffeeChoice.index("REGULAR")
        Power_StatusSelected = Power_Status.index("ON")
    else:
        CoffeeChoice_Selected = CoffeeChoice.index("")
        Power_StatusSelected = Power_Status.index("OFF")
CoffeeChoice_Selected_LED()

# Coffee Choice buttons at the lid
CoffeeChoice_BUT_Up = 20
GPIO.setup(CoffeeChoice_BUT_Up, GPIO.OUT)
GPIO.output(CoffeeChoice_BUT_Up, False)

CoffeeChoice_BUT_Down = 21
GPIO.setup(CoffeeChoice_BUT_Down, GPIO.OUT)
GPIO.output(CoffeeChoice_BUT_Down, False)



# Regular Strength LEDs at the lid
RegularStrength_LED_Dark = 18
GPIO.setup(RegularStrength_LED_Dark, GPIO.IN, pull_up_down=GPIO.PUD_UP)

RegularStrength_LED_Medium = 23
GPIO.setup(RegularStrength_LED_Medium, GPIO.IN, pull_up_down=GPIO.PUD_UP)

RegularStrength_LED_Mild = 24
GPIO.setup(RegularStrength_LED_Mild, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# At start find to which Regular Strength the machine is set
def RegularStrength_Selected_LED():
    global RegularStrength_Selected
    if (GPIO.input(RegularStrength_LED_Dark) == 0):
        RegularStrength_Selected = RegularStrength.index("DARK")
    elif (GPIO.input(RegularStrength_LED_Medium) == 0):
        RegularStrength_Selected = RegularStrength.index("MEDIUM")
    elif (GPIO.input(RegularStrength_LED_Mild) == 0):
        RegularStrength_Selected = RegularStrength.index("MILD")
    else:
        RegularStrength_Selected = RegularStrength.index("")
RegularStrength_Selected_LED()

# Regular Strength buttons at the lid
RegularStrength_BUT_Up = 25
GPIO.setup(RegularStrength_BUT_Up, GPIO.OUT)
GPIO.output(RegularStrength_BUT_Up, False)

RegularStrength_BUT_Down = 8
GPIO.setup(RegularStrength_BUT_Down, GPIO.OUT)
GPIO.output(RegularStrength_BUT_Down, False)






# LED in base for ONE cup
Base_LED_One = 5

def LedOne_Interrupt(channel):
    global Base_LED_One_StatusSelected, Base_LED_Power_StatusSelected, Base_LED_Power_StatusSelected_last
    Base_LED_One_StatusSelected = GPIO.input(Base_LED_One)
    if (Base_LED_One_Status[Base_LED_One_StatusSelected] == "READY"):
        Base_LED_Power_StatusSelected = Base_LED_Power_Status.index("READY")
        Base_LED_Power_StatusSelected_last = Base_LED_Power_Status.index("READY")

    JSONPayload = '{ "state" : {'+\
                        '"reported": {'+\
                            '"LedOne":"' + Base_LED_One_Status[Base_LED_One_StatusSelected] + '", '+\
                            '"LedPower":"' + Base_LED_Power_Status[Base_LED_Power_StatusSelected] + '" '+\
                        '} '+\
                    '} '+\
                '}'
    myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5)

GPIO.setup(Base_LED_One, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(Base_LED_One, GPIO.BOTH, callback=LedOne_Interrupt, bouncetime=10)
Base_LED_One_StatusSelected = GPIO.input(Base_LED_One)

# Button in the base for ONE cup
Base_BUT_One = 27
GPIO.setup(Base_BUT_One, GPIO.OUT)
GPIO.output(Base_BUT_One, False)



# LED in base for TWO cups
Base_LED_Two = 9

def LedTwo_Interrupt(channel):
    global Base_LED_Two_StatusSelected, Base_LED_Power_StatusSelected, Base_LED_Power_StatusSelected_last
    Base_LED_Two_StatusSelected = GPIO.input(Base_LED_Two)
    if (Base_LED_Two_Status[Base_LED_Two_StatusSelected] == "READY"):
        Base_LED_Power_StatusSelected = Base_LED_Power_Status.index("READY")
        Base_LED_Power_StatusSelected_last = Base_LED_Power_Status.index("READY")
    JSONPayload = '{ "state" : {'+\
                        '"reported": {'+\
                            '"LedTwo":"' + Base_LED_Two_Status[Base_LED_Two_StatusSelected] + '", '+\
                            '"LedPower":"' + Base_LED_Power_Status[Base_LED_Power_StatusSelected] + '" '+\
                        '} '+\
                    '} '+\
                '}'
    myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5)

GPIO.setup(Base_LED_Two, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(Base_LED_Two, GPIO.BOTH, callback=LedTwo_Interrupt, bouncetime=10)
Base_LED_Two_StatusSelected = GPIO.input(Base_LED_Two)

# Button in the base for TWO cups
Base_BUT_Two = 11
GPIO.setup(Base_BUT_Two, GPIO.OUT)
GPIO.output(Base_BUT_Two, False)






# LED in base for POWER and STATUS
Base_LED_Power_flash_last = time.time()
Base_LED_Power_flash_sec = 0

Base_LED_Power_Pin = 22

def LedPower_Interrupt(channel):
    global Power_StatusSelected, Base_LED_Power_flash_last, Base_LED_Power_flash_sec, Base_LED_Power_StatusSelected_last, Base_LED_Power_StatusSelected
    if (GPIO.input(Base_LED_Power_Pin) == 0):
        Power_StatusSelected = Power_Status.index("ON")
        Base_LED_Power_flash_sec = time.time() - Base_LED_Power_flash_last
        if (Base_LED_Power_flash_sec > 0 and Base_LED_Power_flash_sec < 0.5):
            Base_LED_Power_StatusSelected = Base_LED_Power_Status.index("ERROR")
        elif (Base_LED_Power_flash_sec > 0.5 and Base_LED_Power_flash_sec < 2):
            Base_LED_Power_StatusSelected = Base_LED_Power_Status.index("BUSY")
        elif (Base_LED_Power_flash_sec > 2):
            Base_LED_Power_StatusSelected = Base_LED_Power_Status.index("READY")
            
        if (Base_LED_Power_StatusSelected <> Base_LED_Power_StatusSelected_last):
            Base_LED_Power_StatusSelected_last = Base_LED_Power_StatusSelected
            JSONPayload = '{ "state" : {'+\
                                '"reported": {'+\
                                    '"LedPower":"' + Base_LED_Power_Status[Base_LED_Power_StatusSelected] + '", '+\
                                    '"Power":"' + Power_Status[Power_StatusSelected] + '" '+\
                                '} '+\
                            '} '+\
                        '}'
            myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5)

    else:
        Base_LED_Power_flash_last = time.time()

GPIO.setup(Base_LED_Power_Pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(Base_LED_Power_Pin, GPIO.BOTH, callback=LedPower_Interrupt, bouncetime=10)


# Button in the base for POWER
Base_BUT_Power = 10
GPIO.setup(Base_BUT_Power, GPIO.OUT)
GPIO.output(Base_BUT_Power, False)



# Sensor for LID open/close
Lid_Pin = 0

def Callback_Lid(channel):
    global Lid_StatusSelected
    Lid_StatusSelected = GPIO.input(Lid_Pin)
    JSONPayload = '{ "state" : {'+\
                        '"reported": {'+\
                            '"Lid":"' + Lid_Status[Lid_StatusSelected] + '" '+\
                        '} '+\
                    '} '+\
                '}'
    myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5)

GPIO.setup(Lid_Pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(Lid_Pin, GPIO.BOTH, callback=Callback_Lid, bouncetime=10)
Lid_StatusSelected = GPIO.input(Lid_Pin)




time.sleep(3)
# All pins and defaults initialized, upload all system status parameters
JSONPayload = '{ "state" : {'+\
                    '"reported": {'+\
                        '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                        '"Start": "NO", '+\
                        '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                        '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '", '+\
                        '"NumberOfCups": "' + NumberOfCups[NumberOfCups_Selected] + '", '+\
                        '"LedOne": "' + Base_LED_One_Status[Base_LED_One_StatusSelected] + '", '+\
                        '"LedTwo": "' + Base_LED_Two_Status[Base_LED_Two_StatusSelected] + '", '+\
                        '"Lid": "' + Lid_Status[Lid_StatusSelected] + '"'+\
                    '}, '+\
                    '"desired": {'+\
                        '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                        '"Start": "NO" '+\
                    '} '+\
                '} '+\
            '}'
myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5)





# We will loop through the process to see what the Power LED does, as this tells us more about the status.
# Most of it is done in the Interrupt, as that kicks in when the LED starts shining,
# but sometimes the LED stays ON or OFF. This loop does catch that.
def loop():
    global Base_LED_Power_flash_sec, Base_LED_Power_StatusSelected, Base_LED_Power_StatusSelected_last, Base_LED_Power_flash_last, Power_StatusSelected, Power_StatusSelected, CoffeeChoice_Selected, RegularStrength_Selected

    Base_LED_Power_flash_sec = time.time() - Base_LED_Power_flash_last
    if (Base_LED_Power_flash_sec > 5):
        if (GPIO.input(Base_LED_Power_Pin) == 0):
            Base_LED_Power_StatusSelected = Base_LED_Power_Status.index("READY")
            Power_StatusSelected = Power_Status.index("ON")
        else:
            Base_LED_Power_StatusSelected = Base_LED_Power_Status.index("OFF")
            Power_StatusSelected = Power_Status.index("OFF")
            
        if (Base_LED_Power_StatusSelected <> Base_LED_Power_StatusSelected_last):
            print ("Base_LED_Power_flash_sec: " + str(Base_LED_Power_flash_sec) + " Base_LED_Power_Status: " + Base_LED_Power_Status[Base_LED_Power_StatusSelected])
            Base_LED_Power_StatusSelected_last = Base_LED_Power_StatusSelected
            Base_LED_Power_flash_last = time.time()

            if (Power_StatusSelected == Power_Status.index("ON")):
                CoffeeChoice_Selected_LED() #as the machine is powering ON now, one of the LEDs will turn on, find the status
                RegularStrength_Selected_LED() #as the machine is powering ON now, one of the LEDs will turn on, find the status
                JSONPayload = '{ "state" : {'+\
                                    '"reported": {'+\
                                        '"LedPower":"' + Base_LED_Power_Status[Base_LED_Power_StatusSelected] + '", '+\
                                        '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                                        '"Start": "NO", '+\
                                        '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                                        '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '" '+\
                                    '} '+\
                                '} '+\
                            '}'
                myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values
            elif (Power_StatusSelected == Power_Status.index("OFF")):
                CoffeeChoice_Selected = CoffeeChoice.index("") #LEDs will now be off
                RegularStrength_Selected = RegularStrength.index("") #LEDs will now be off
                JSONPayload = '{ "state" : {'+\
                                    '"reported": {'+\
                                        '"LedPower":"' + Base_LED_Power_Status[Base_LED_Power_StatusSelected] + '", '+\
                                        '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                                        '"Start": "NO", '+\
                                        '"CoffeeChoice": "' + CoffeeChoice[CoffeeChoice_Selected] + '", '+\
                                        '"RegularStrength": "' + RegularStrength[RegularStrength_Selected] + '" '+\
                                    '}, '+\
                                    '"desired": {'+\
                                        '"Power": "' + Power_Status[Power_StatusSelected] + '", '+\
                                        '"Start": "NO" '+\
                                    '} '+\
                                '} '+\
                            '}'
                myDeviceShadow.shadowUpdate(JSONPayload, IoTShadowCallback_Update, 5) #Send the new status as REPORTED values

    time.sleep(3)








# Listen on deltas from the IoT Shadow
myDeviceShadow.shadowGet(IoTShadowCallback_Get, 5)
myDeviceShadow.shadowRegisterDeltaCallback(IoTShadowCallback_Delta)

if __name__ == '__main__':
    try:
        print 'CoffeeMachine started, Press Ctrl-C to quit.'
        while True:
            #pass
            loop()
    finally:
        GPIO.cleanup()
        myAWSIoTMQTTShadowClient.shadowUnregisterDeltaCallback()
        myAWSIoTMQTTShadowClient.disconnect()
        print 'CoffeeMachine stopped.'

lambda_function.py

Python
This is the code with Intents from Amazon Alexa Voice Skills to respond back with Voice, and to process commands to AWS IoT. (to be installed in Lambda)
from __future__ import print_function
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient
import datetime
import json


# These are my AWS IoT login and certificates
host = "**********.iot.us-east-1.amazonaws.com"
cert_path = "cert/"
rootCAPath = cert_path + "root-CA.crt"
certificatePath = cert_path + "**********-certificate.pem.crt"
privateKeyPath = cert_path + "**********-private.pem.key"
shadowClient = "CoffeeMachine_Lambda"

# Init AWSIoTMQTTClient
myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient(shadowClient)
myAWSIoTMQTTShadowClient.configureEndpoint(host, 8883)
myAWSIoTMQTTShadowClient.configureCredentials(rootCAPath, privateKeyPath, certificatePath)

# AWSIoTMQTTClient connection configuration
myAWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10)  # 10 sec
myAWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5)  # 5 sec

def lambda_handler(event, context):
    
    """ Route the incoming request based on type (LaunchRequest, IntentRequest,
    etc.) The JSON body of the request is provided in the event parameter.
    """
    if 'session' in event:
        print("event.session.application.applicationId=" + event['session']['application']['applicationId'])

        """
        Uncomment this if statement and populate with your skill's application ID to
        prevent someone else from configuring a skill that sends requests to this
        function.
        """
        if (event['session']['application']['applicationId'] !=
            "amzn1.ask.skill.**********"):
            raise ValueError("Invalid Application ID")

        if event['session']['new'] and 'requestId' in event['request']:
            on_session_started({'requestId': event['request']['requestId']},event['session'])

    if 'request' in event:
        if event['request']['type'] == "LaunchRequest":
            return on_launch(event['request'], event['session'])
        elif event['request']['type'] == "IntentRequest":
            return on_intent(event['request'], event['session'])
        elif event['request']['type'] == "SessionEndedRequest":
            return on_session_ended(event['request'], event['session'])


def on_session_started(session_started_request, session):
    """ Called when the session starts """

    print("on_session_started requestId=" + session_started_request['requestId'] + ", sessionId=" + session['sessionId'])


def on_launch(launch_request, session):
    """ Called when the user launches the skill without specifying what they want """

    print("on_launch requestId=" + launch_request['requestId'] + ", sessionId=" + session['sessionId'])

    # Dispatch to your skill's launch
    intent = launch_request
    return Welcome_response(intent, session)


def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """

    print("on_intent requestId=" + intent_request['requestId'] + ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    # Dispatch to your skill's intent handlers
    if intent_name == "WelcomeIntent":
        return Welcome_response(intent, session)
    elif intent_name == "CoffeeChoiceIntent":
        return CoffeeChoice_response(intent, session)
    elif intent_name == "RegularStrengthIntent":
        return RegularStrength_response(intent, session)
    elif intent_name == "NumberOfCupsIntent":
        return NumberOfCups_response(intent, session)

    elif intent_name == "ReadyIntent":
        return Ready_response(intent, session)
    elif intent_name == "NotReadyIntent":
        return NotReady_response(intent, session)

    elif intent_name == "StopIntent":
        return Stop_response()
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return Stop_response()

    elif intent_name == "HelpIntent":
        return Help_response(intent, session)
    elif intent_name == "AMAZON.HelpIntent":
        return Help_response()

    else:
        raise ValueError("Invalid intent")


def on_session_ended(session_ended_request, session):
    """ Called when the user ends the session.
    Is not called when the skill returns should_end_session=true
    """
    print("on_session_ended requestId=" + session_ended_request['requestId'] + ", sessionId=" + session['sessionId'])

    # add cleanup logic here
    return Stop_response()

# --------------- Functions that control the skill's behavior ------------------


def Welcome_response(intent, session):
    # Connect to AWS IoT Shadow
    myAWSIoTMQTTShadowClient.connect()
    myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)
    customCallback = ""

    # Set Session Attributes
    CoffeeChoice = ''
    RegularStrength = ''
    NumberOfCups = ''

    # Set other defaults
    card_title = "Welcome"
    should_end_session = False

    # Start the real task
    currentTime = datetime.datetime.now()
    if currentTime.hour < 12:
        printTime = "morning"
    elif 12 <= currentTime.hour < 18:
        printTime = "afternoon"
    else:
        printTime = "evening"
    
    speech_output = "Good " + printTime + ", your Coffee Machine will switch on. " \
                    "What kind of coffee do you want? " \
                    "I have Regular, Cappucino, Macchiato and Latte"
    reprompt_text = "What kind of coffee do you want? " \
                    "I have Regular, Cappucino, Macchiato and Latte"

    if 'slots' in intent:
        if 'CoffeeChoice' in intent['slots']:
            if 'value' in intent['slots']['CoffeeChoice']:
                CoffeeChoice = intent['slots']['CoffeeChoice']['value'].upper()

                if (CoffeeChoice == "REGULAR COFFEE" or CoffeeChoice == "REGULAR"):
                    CoffeeChoice = 'REGULAR'
                    RegularStrength = 'MEDIUM'

                    speech_output = "Good " + printTime + ", your Coffee Machine will switch on. " \
                                    "Excellent choice, I like " + CoffeeChoice + " coffee. " \
                                    "Make your choice between Dark, Medium or Mild"
                    reprompt_text = "Make your choice between Dark, Medium or Mild"

                elif (CoffeeChoice == "CAPPUCCINO" or CoffeeChoice == "MACCHIATO" or CoffeeChoice == "LATTE"):
                    NumberOfCups = 'ONE'

                    speech_output = "Good " + printTime + ", your Coffee Machine will switch on. " \
                                    "Excellent choice, I like " + CoffeeChoice + ". " \
                                    "Did you put in water, milk and one coffee pad?"
                    reprompt_text = "Did you put in water, milk and one coffee pad?"


    # Publish to AWS IoT Shadow
    myJSONPayload = "{ \"state\" : {"\
                                    "\"desired\": {"\
                                                    "\"Power\": \"ON\", "\
                                                    "\"Start\": \"NO\", "\
                                                    "\"CoffeeChoice\": \"" + CoffeeChoice + "\", "\
                                                    "\"RegularStrength\": \"" + RegularStrength + "\", "\
                                                    "\"NumberOfCups\": \"" + NumberOfCups + "\""\
                                                "} "\
                                    ", \"reported\": {"\
                                                    "\"Start\": \"NO\" "\
                                                "} "\
                                    "} "\
                    "}"
    myDeviceShadow.shadowUpdate(myJSONPayload, customCallback, 5)
    myAWSIoTMQTTShadowClient.disconnect()
    
    # Send response back to the Alexa Voice Skill
    session_attributes = create_attributes(CoffeeChoice,RegularStrength,NumberOfCups)
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def Help_response(intent, session):
    # Connect to AWS IoT Shadow
    myAWSIoTMQTTShadowClient.connect()
    myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)
    customCallback = ""

    # Set Session Attributes
    CoffeeChoice = ''
    RegularStrength = ''
    NumberOfCups = ''

    # Set other defaults
    card_title = "Help"
    should_end_session = False

    # Start the real task
    speech_output = "Good " + printTime + ", what kind of coffee do you want? " \
                    "I have Regular, Cappucino, Macchiato and Latte"
    reprompt_text = "What kind of coffee do you want? " \
                    "I have Regular, Cappucino, Macchiato and Latte"
        

    # Publish to AWS IoT Shadow
    myJSONPayload = "{ \"state\" : {"\
                                    "\"desired\": {"\
                                                    "\"Power\": \"ON\", "\
                                                    "\"Start\": \"NO\", "\
                                                    "\"CoffeeChoice\": \"" + CoffeeChoice + "\", "\
                                                    "\"RegularStrength\": \"" + RegularStrength + "\", "\
                                                    "\"NumberOfCups\": \"" + NumberOfCups + "\""\
                                                "} "\
                                    ", \"reported\": {"\
                                                    "\"Start\": \"NO\" "\
                                                "} "\
                                    "} "\
                    "}"
    myDeviceShadow.shadowUpdate(myJSONPayload, customCallback, 5)
    myAWSIoTMQTTShadowClient.disconnect()
    
    # Send response back to the Alexa Voice Skill
    session_attributes = create_attributes(CoffeeChoice,RegularStrength,NumberOfCups)
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))

def CoffeeChoice_response(intent, session):
    # Connect to AWS IoT Shadow
    myAWSIoTMQTTShadowClient.connect()
    myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)
    customCallback = ""
    
    # Set Session Attributes
    if 'attributes' in session:
        if 'CoffeeChoice' in session['attributes']:
            CoffeeChoice = session['attributes']['CoffeeChoice']
        else:
            CoffeeChoice = ''
        if 'RegularStrength' in session['attributes']:
            RegularStrength = session['attributes']['RegularStrength']
        else:
            RegularStrength = ''
        if 'NumberOfCups' in session['attributes']:
            NumberOfCups = session['attributes']['NumberOfCups']
        else: 
            NumberOfCups = ''
    else:
        CoffeeChoice = ''
        RegularStrength = ''
        NumberOfCups = ''

    # Set other defaults
    card_title = "CoffeeChoice"
    should_end_session = False

    speech_output = "I didn't understand. What kind of coffee do you want? " \
                    "I have Regular, Cappucino, Macchiato and Latte"
    reprompt_text = "I have Regular, Cappucino, Macchiato and Latte"

    # Start the real task
    if 'slots' in intent:
        if 'CoffeeChoice' in intent['slots']:
            if 'value' in intent['slots']['CoffeeChoice']:
                CoffeeChoice = intent['slots']['CoffeeChoice']['value'].upper()

                if (CoffeeChoice == "REGULAR COFFEE" or CoffeeChoice == "REGULAR"):
                    CoffeeChoice = 'REGULAR'
                    RegularStrength = 'MEDIUM'

                    speech_output = "Excellent choice, I like " + CoffeeChoice + " coffee. " \
                                    "Make your choice between Dark, Medium or Mild"
                    reprompt_text = "Make your choice between Dark, Medium or Mild"

                elif (CoffeeChoice == "CAPPUCCINO" or CoffeeChoice == "MACCHIATO" or CoffeeChoice == "LATTE"):
                    NumberOfCups = 'ONE'

                    speech_output = "Excellent choice, I like " + CoffeeChoice + ". " \
                                    "Did you put in water, milk and one coffee pad?"
                    reprompt_text = "Did you put in water, milk and one coffee pad?"

        
    # Publish to AWS IoT Shadow
    myJSONPayload = "{ \"state\" : {"\
                                    "\"desired\": {"\
                                                    "\"Power\": \"ON\", "\
                                                    "\"Start\": \"NO\", "\
                                                    "\"CoffeeChoice\": \"" + CoffeeChoice + "\", "\
                                                    "\"RegularStrength\": \"" + RegularStrength + "\", "\
                                                    "\"NumberOfCups\": \"" + NumberOfCups + "\""\
                                                "} "\
                                    ", \"reported\": {"\
                                                    "\"Start\": \"NO\" "\
                                                "} "\
                                    "} "\
                    "}"
    myDeviceShadow.shadowUpdate(myJSONPayload, customCallback, 5)
    myAWSIoTMQTTShadowClient.disconnect()


    # Send response back to the Alexa Voice Skill
    session_attributes = create_attributes(CoffeeChoice,RegularStrength,NumberOfCups)
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))



def RegularStrength_response(intent, session):
    # Connect to AWS IoT Shadow
    myAWSIoTMQTTShadowClient.connect()
    myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)
    customCallback = ""

    # Set Session Attributes
    if 'attributes' in session:
        if 'CoffeeChoice' in session['attributes']:
            CoffeeChoice = session['attributes']['CoffeeChoice']
        else:
            CoffeeChoice = ''
        if 'RegularStrength' in session['attributes']:
            RegularStrength = session['attributes']['RegularStrength']
        else:
            RegularStrength = ''
        if 'NumberOfCups' in session['attributes']:
            NumberOfCups = session['attributes']['NumberOfCups']
        else: 
            NumberOfCups = ''
    else:
        CoffeeChoice = ''
        RegularStrength = ''
        NumberOfCups = ''

    # Set other defaults
    card_title = "RegularStrength"
    should_end_session = False
    speech_output = "Make your choice between Dark, Medium or Mild"
    reprompt_text = "Make your choice between Dark, Medium or Mild"

    # Start the real task
    if 'slots' in intent:
        if 'RegularStrength' in intent['slots']:
            if 'value' in intent['slots']['RegularStrength']:
                RegularStrength = intent['slots']['RegularStrength']['value'].upper()

                # If user did give other but similar phrases
                if RegularStrength == "STRONG":
                    RegularStrength = "DARK"
                if RegularStrength == "NORMAL":
                    RegularStrength = "MEDIUM"

                speech_output = RegularStrength + " it will be. Do you want one or two cups?"
                reprompt_text = "Do you want one or two cups?"

    # Publish to AWS IoT Shadow
    myJSONPayload = "{ \"state\" : {"\
                                    "\"desired\": {"\
                                                    "\"Power\": \"ON\", "\
                                                    "\"Start\": \"NO\", "\
                                                    "\"CoffeeChoice\": \"" + CoffeeChoice + "\", "\
                                                    "\"RegularStrength\": \"" + RegularStrength + "\", "\
                                                    "\"NumberOfCups\": \"" + NumberOfCups + "\""\
                                                "} "\
                                    ", \"reported\": {"\
                                                    "\"Start\": \"NO\" "\
                                                "} "\
                                    "} "\
                    "}"
    myDeviceShadow.shadowUpdate(myJSONPayload, customCallback, 5)
    myAWSIoTMQTTShadowClient.disconnect()

    # Send response back to the Alexa Voice Skill
    session_attributes = create_attributes(CoffeeChoice,RegularStrength,NumberOfCups)
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def NumberOfCups_response(intent, session):
    # Connect to AWS IoT Shadow
    myAWSIoTMQTTShadowClient.connect()
    myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)
    customCallback = ""

    # Set Session Attributes
    if 'attributes' in session:
        if 'CoffeeChoice' in session['attributes']:
            CoffeeChoice = session['attributes']['CoffeeChoice']
        else:
            CoffeeChoice = ''
        if 'RegularStrength' in session['attributes']:
            RegularStrength = session['attributes']['RegularStrength']
        else:
            RegularStrength = ''
        if 'NumberOfCups' in session['attributes']:
            NumberOfCups = session['attributes']['NumberOfCups']
        else: 
            NumberOfCups = ''
    else:
        CoffeeChoice = ''
        RegularStrength = ''
        NumberOfCups = ''

    # Set other defaults
    card_title = "NumberOfCups"
    should_end_session = False
    speech_output = "Do you want one or two cups?"
    reprompt_text = "Do you want one or two cups?"

    # Start the real task
    if 'slots' in intent:
        if 'NumberOfCups' in intent['slots']:
            if 'value' in intent['slots']['NumberOfCups']:
                NumberOfCups = intent['slots']['NumberOfCups']['value'].upper()

                # If user did give other but similar phrasses
                if NumberOfCups == "BIG" or NumberOfCups == "LARGE" or NumberOfCups == "2" or NumberOfCups == "DOUBLE":
                    NumberOfCups = "TWO"
                if NumberOfCups == "SMALL" or NumberOfCups == "1" or NumberOfCups == "SINGLE":
                    NumberOfCups = "ONE"
                    
                if (NumberOfCups == "ONE"):
                    speech_output = "Did you put in water and one coffee pad?"
                    reprompt_text = "Did you put in water and one coffee pad?"
                else:
                    speech_output = "Did you put in water and two coffee pads?"
                    reprompt_text = "Did you put in water and two coffee pads?"
    
    # Publish to AWS IoT Shadow
    myJSONPayload = "{ \"state\" : {"\
                                    "\"desired\": {"\
                                                    "\"Power\": \"ON\", "\
                                                    "\"Start\": \"NO\", "\
                                                    "\"CoffeeChoice\": \"" + CoffeeChoice + "\", "\
                                                    "\"RegularStrength\": \"" + RegularStrength + "\", "\
                                                    "\"NumberOfCups\": \"" + NumberOfCups + "\""\
                                                "} "\
                                    ", \"reported\": {"\
                                                    "\"Start\": \"NO\" "\
                                                "} "\
                                    "} "\
                    "}"
    myDeviceShadow.shadowUpdate(myJSONPayload, customCallback, 5)
    myAWSIoTMQTTShadowClient.disconnect()

    # Send response back to the Alexa Voice Skill
    session_attributes = create_attributes(CoffeeChoice,RegularStrength,NumberOfCups)
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def Ready_response(intent, session):
    # Connect to AWS IoT Shadow
    myAWSIoTMQTTShadowClient.connect()
    myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)
    customCallback = ""

    # Set Session Attributes
    if 'attributes' in session:
        if 'CoffeeChoice' in session['attributes']:
            CoffeeChoice = session['attributes']['CoffeeChoice']
        else:
            CoffeeChoice = ''
        if 'RegularStrength' in session['attributes']:
            RegularStrength = session['attributes']['RegularStrength']
        else:
            RegularStrength = ''
        if 'NumberOfCups' in session['attributes']:
            NumberOfCups = session['attributes']['NumberOfCups']
        else: 
            NumberOfCups = ''
    else:
        CoffeeChoice = ''
        RegularStrength = ''
        NumberOfCups = ''

    # Set other defaults
    card_title = "StartBrewing"
    should_end_session = True

    # Start the real task
    if (((CoffeeChoice <> "" and CoffeeChoice <> "REGULAR") or (CoffeeChoice == "REGULAR" and RegularStrength <> "")) and NumberOfCups <> ""):
        if NumberOfCups == 'TWO':
            CupCups = 'cups'
        else:
            CupCups = 'cup'

        speech_output = "Thank you, I'll now prepare you " + NumberOfCups + " nice " + CupCups + " of " + RegularStrength + " " + CoffeeChoice
        reprompt_text = ""

        # Publish to AWS IoT Shadow
        myJSONPayload = "{ \"state\" : {"\
                                    "\"desired\": {"\
                                                    "\"Power\": \"ON\", "\
                                                    "\"Start\": \"YES\", "\
                                                    "\"CoffeeChoice\": \"" + CoffeeChoice + "\", "\
                                                    "\"RegularStrength\": \"" + RegularStrength + "\", "\
                                                    "\"NumberOfCups\": \"" + NumberOfCups + "\""\
                                                "} "\
                                    "} "\
                    "}"
        myDeviceShadow.shadowUpdate(myJSONPayload, customCallback, 5)
        myAWSIoTMQTTShadowClient.disconnect()

    else:
        speech_output = "Something went wrong, please start over by asking for Help"
        reprompt_text = "Something went wrong, please start over by asking for Help"

    # Send response back to the Alexa Voice Skill
    session_attributes = create_attributes(CoffeeChoice,RegularStrength,NumberOfCups)
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def NotReady_response(intent, session):
    # Connect to AWS IoT Shadow
    myAWSIoTMQTTShadowClient.connect()
    myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)
    customCallback = ""

    # Set Session Attributes
    if 'attributes' in session:
        if 'CoffeeChoice' in session['attributes']:
            CoffeeChoice = session['attributes']['CoffeeChoice']
        else:
            CoffeeChoice = ''
        if 'RegularStrength' in session['attributes']:
            RegularStrength = session['attributes']['RegularStrength']
        else:
            RegularStrength = ''
        if 'NumberOfCups' in session['attributes']:
            NumberOfCups = session['attributes']['NumberOfCups']
        else: 
            NumberOfCups = ''
    else:
        CoffeeChoice = ''
        RegularStrength = ''
        NumberOfCups = ''

    # Set other defaults
    card_title = "NotReady"
    should_end_session = False

    # Start the real task
    speech_output = "Ok, I will wait a little moment, tell me when you are ready."
    reprompt_text = "Hurry up, tell me when you are ready"

    # Send response back to the Alexa Voice Skill
    session_attributes = create_attributes(CoffeeChoice,RegularStrength,NumberOfCups)
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def Stop_response():
    session_attributes = {}
    card_title = "Stop"

    # Setting this to true ends the session and exits the skill.
    should_end_session = True

    CoffeeChoice = ''
    RegularStrength = ''
    NumberOfCups = ''

    speech_output = "Your coffee machine will power off. Have a nice day!"
    reprompt_text = None

    # Connect and publish to AWS IoT Shadow
    myAWSIoTMQTTShadowClient.connect()
    myDeviceShadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("CoffeeMachine", True)
    customCallback = ""
    myJSONPayload = "{ \"state\" : {"\
                                "\"desired\": {"\
                                                "\"Power\": \"OFF\", "\
                                                "\"Start\": \"NO\", "\
                                                "\"CoffeeChoice\": \"\", "\
                                                "\"RegularStrength\": \"\", "\
                                                "\"NumberOfCups\": \"\" "\
                                            "} "\
                                "} "\
                "}"
    myDeviceShadow.shadowUpdate(myJSONPayload, customCallback, 5)

    session_attributes = create_attributes(CoffeeChoice,RegularStrength,NumberOfCups)
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))




# --------------- Helpers that build all of the responses ----------------------

def create_attributes(CoffeeChoice, RegularStrength, NumberOfCups):
    return {"CoffeeChoice": CoffeeChoice.upper(), "RegularStrength": RegularStrength.upper(), "NumberOfCups": NumberOfCups.upper()}


def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': title,
            'content': output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }


def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }

Credits

Bastiaan Slee

Bastiaan Slee

5 projects • 34 followers
Tinkerer in the field of Home Automation, with the main goal: fun! Using Raspberry Pi, Arduino (+clones), LoRaWAN, NodeRed, 3D Printing
Thanks to Sam Machin and Mason Stone.

Comments