# # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. # These materials are licensed under the Amazon Software License in connection with the Alexa Gadgets Program. # The Agreement is available at https://aws.amazon.com/asl/. # See the Agreement for the specific terms and conditions of the Agreement. # Capitalized terms not defined in this file have the meanings given to them in the Agreement. # import json import logging import sys import threading import time from enum import Enum from datetime import datetime import dateutil.parser import traceback import webcolors import board import neopixel from agt import AlexaGadget from smart_mirror import SmartMirror from parameter_store_helper import fetch_and_store_parameters, get_parameters, SmartMirrorConfig logging.basicConfig(stream=sys.stdout, level=logging.INFO) logger = logging.getLogger(__name__) class Actions(Enum): Off = 0 Rainbow = 1 Breathe = 2 ShowColor = 3 class SmartMirrorGadget(AlexaGadget): """ An Alexa Gadget for your simple smart mirror. """ def __init__(self): super().__init__() self.config = self.get_parameters() self.smart_mirror = SmartMirror(self.config) #This sets what action is starte when the mirror starts self.defaultAction = Actions.Rainbow self.currentAction = self.defaultAction self.lastAction = self.defaultAction # Boolean that tells the loop if it should execute actions or not - default is True which means that the configured default action (self.defaultAction) # will be used self.keep_cycling = True #default options for show color as a reference self.showColorOptions = { 'color': webcolors.name_to_rgb('yellow') } # Setup a lock to be used for avoiding race conditions # during color animation state updates self.lock = threading.Lock() self.loop_thread = threading.Thread(target=self.loop) self.loop_thread.start() def get_parameters(self): """ Gets the parameters from parameter store """ try: fetch_and_store_parameters() parameters = get_parameters() return SmartMirrorConfig(parameters) except: return SmartMirrorConfig({}) def startAction(self, action): """ Call this function to start a specific action """ logger.info(f'Starting Action {action}') self.lock.acquire() self.lastAction = self.currentAction self.currentAction = action self.keep_cycling = True self.lock.release() def stopAction(self): """ Call this action to end the current action - turn all LEDs off """ self.lock.acquire() self.lastAction = Actions.Off self.currentAction = Actions.Off self.keep_cycling = False self.lock.release() def loop(self): """ Main function of this class. This is an endless loop running in a separate thread. It will check what action to run on each iteration. """ while True: # Check if anything should be visualized if self.keep_cycling: logger.info('Something is on') try: if self.currentAction == Actions.Off: time.sleep(0.1) if self.currentAction == Actions.Rainbow: self.smart_mirror.rainbow_cycle(0.001) if self.currentAction == Actions.Breathe: self.smart_mirror.breathe() if self.currentAction == Actions.ShowColor: self.smart_mirror.showColor( self.showColorOptions['color']) except Exception as e: logger.info(f'Error in loop: {e}') logger.error(f'Stack: {traceback.format_exc()}') time.sleep(0.1) else: logger.info('Nothing is on') self.smart_mirror.reset() time.sleep(0.1) def on_alexa_gadget_statelistener_stateupdate(self, directive): """ This will trigger when your connected Alexa device changes state. Here we listening for your Alexa to react to you saying "Alexa..." or "Echo..." """ for state in directive.payload.states: if state.name == 'wakeword': if state.value == 'active': logger.info('Wake word active') self.showColorOptions['color'] = webcolors.name_to_rgb('yellow') self.startAction(Actions.ShowColor) elif state.value == 'cleared': logger.info('Wake word cleared') self.startAction(self.lastAction) # this matches the namespace that the skill adds in the payload (see lambda_function.py): (namespace='Custom.SmartMirror', name='Rainbow'), def on_custom_smartmirror_rainbow(self, directive): """ Handles Custom.SmartMirror.Rainbow directive """ logger.info('show rainbow directive called') self.startAction(Actions.Rainbow) def on_custom_smartmirror_stopled(self, directive): """ Handles Custom.ColorCyclerGadget.StopLED directive sent from skill by stopping the LED animations """ logger.info('StopLED directive received: Turning off LED') self.stopAction() def reset(self): """ Turn off all LEDs by calling the reset function """ try: self.smart_mirror.reset() except: print(f'failed to reset') if __name__ == '__main__': gadget = SmartMirrorGadget() try: gadget.main() finally: gadget.reset()