Lin Ochoa
Created December 24, 2019 © LGPL

LEGO Cuckoo Clock Alarm

Using LEGO Cuckoo Clock as Amazon Alexa Alarm

IntermediateFull instructions provided20 hours36

Things used in this project

Hardware components

EV3 Programming Brick / Kit
LEGO MindStorms EV3 Programming Brick / Kit
×1
LEGO MindStorms Heavy Lift Helicopter 42052
×1
Echo Show (2nd Gen)
Amazon Alexa Echo Show (2nd Gen)
×1

Software apps and online services

Microsoft Visual Studio Code
Alexa Gadgets Toolkit
Amazon Alexa Alexa Gadgets Toolkit
Alexa Skills Kit
Amazon Alexa Alexa Skills Kit
Alexa Voice Service
Amazon Alexa Alexa Voice Service

Story

Read more

Schematics

LEGO Cuckoo Clock Build Instructions

LEGO Cuckoo Clock Build Instructions

Schematic for the clock

Electric Schematics

Code

cuckoo.py

Python
Python code for ev3dev2
import os
import sys
import time
import datetime
import logging
import threading
import random

from agt import AlexaGadget

from ev3dev2.led import Leds
from ev3dev2.sound import Sound
from ev3dev2.motor import OUTPUT_A, OUTPUT_B, OUTPUT_D, LargeMotor, MediumMotor, SpeedPercent
from ev3dev2.sensor.lego import TouchSensor
from ev3dev2.sensor.lego import InfraredSensor

# Set the logging level to INFO to see messages from AlexaGadget
logging.basicConfig(level=logging.INFO, stream=sys.stdout, format='%(message)s')
logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
logger = logging.getLogger(__name__)

class MindstormsGadget(AlexaGadget):
    """
    A Mindstorms gadget that performs movement in sync with music tempo.
    """

    def __init__(self):
        """
        Performs Alexa Gadget initialization routines and ev3dev resource allocation.
        """
        super().__init__()
        
        self.leds = Leds()
        self.sound = Sound()

        #Initilize sensors and motors
        self.ir = InfraredSensor()
        self.stopper = TouchSensor()
        self.minutehand = MediumMotor(OUTPUT_A)
        self.cuckoo = LargeMotor(OUTPUT_B)
        
        #time
        self.current = datetime.datetime.now()
        hour = self.current.strftime("%I")
        minute = self.current.strftime("%M")
        rotation = int(hour) + int(minute)/60
        print(hour)
        print(minute)
        print(rotation)

        #cuckoo flag
        self.cuckoobird = False        
        
        #calibrate
        self.minutehand.on_for_rotations(SpeedPercent(50), 12)
        #self current time
        self.minutehand.on_for_rotations(SpeedPercent(50), rotation)

        threading.Thread(target=self._auto_minute_thread, daemon=True).start()
        threading.Thread(target=self._auto_cuckoo_thread, daemon=True).start()
    def on_connected(self, device_addr):
        """
        Gadget connected to the paired Echo device.
        :param friendly_name: the friendly name of the gadget that has connected to the echo device
        """
        self.leds.set_color("LEFT", "GREEN")
        self.leds.set_color("RIGHT", "GREEN")
        logger.info("{} connected to Echo device".format(self.friendly_name))

    def on_disconnected(self, device_addr):
        """
        Gadget disconnected from the paired Echo device.
        :param friendly_name: the friendly name of the gadget that has disconnected from the echo device
        """
        self.leds.set_color("LEFT", "BLACK")
        self.leds.set_color("RIGHT", "BLACK")
        logger.info("{} disconnected from Echo device".format(self.friendly_name))

    def on_alexa_gadget_statelistener_stateupdate(self, directive):
        """
        Listens for the wakeword state change and react by turning on the LED.
        :param directive: contains a payload with the updated state information from Alexa
        """
        for state in directive.payload.states:
            print(state.name, file=sys.stderr)
            #print(directive.payload)
            if state.name == 'timers':
               if state.value == 'active':
                   self.cuckoobird = True
            elif state.value == 'cleared':
                #currently timer does not provide clear status, I think it's a bug so I m gona use wake word's clear here to clear the bird
                self.cuckoobird = False
    def _auto_minute_thread(self):
        while True:
            time.sleep(60)
            self.minutehand.on_for_rotations(SpeedPercent(50), 1/60)

    def _auto_cuckoo_thread(self):
        while True:
            if self.cuckoobird == True:
                print('cuckoo')
                if self.stopper.is_pressed == True:
                    print(self.ir.proximity)
                    self.cuckoo.on_for_seconds(SpeedPercent(30), 1)
                elif self.ir.proximity < 30:
                    self.sound.play_file("cuckoo.wav")
                    print(self.ir.proximity)
                    self.cuckoo.on_for_seconds(SpeedPercent(-30), 1)
            else:
                if self.stopper.is_pressed == False:
                    self.sound.play_file("cuckoo.wav")
                    print(self.ir.proximity)
                    self.cuckoo.on_for_seconds(SpeedPercent(-30), 1)
            
if __name__ == '__main__':

    gadget = MindstormsGadget()

    # Set LCD font and turn off blinking green LEDs
    os.system('setfont Lat7-Terminus12x6')
    gadget.leds.set_color("LEFT", "BLACK")
    gadget.leds.set_color("RIGHT", "BLACK")

    # Startup sequence 
    gadget.sound.play_song((('C4', 'e'), ('D4', 'e'), ('E5', 'q')))
    gadget.leds.set_color("LEFT", "GREEN")
    gadget.leds.set_color("RIGHT", "GREEN")

    # Gadget main entry point
    gadget.main()

    # Shutdown sequence
    gadget.sound.play_song((('E5', 'e'), ('C4', 'e')))
    gadget.leds.set_color("LEFT", "BLACK")
    gadget.leds.set_color("RIGHT", "BLACK")

cuckoo.ini

INI
the setting file for amazon gadget
[GadgetSettings]
amazonId = [YOUR_AMAZON_ID]
alexaGadgetSecret = [YOUR_ALEXA_GADGET_SECRET]

[GadgetCapabilities]
Alexa.Gadget.StateListener = 1.0 - timers, wakeword

calibrate.py

Python
Clock calibration and cuckoo bird testing
import datetime
from ev3dev2.sound import Sound
from ev3dev2.sensor.lego import TouchSensor
from ev3dev2.sensor.lego import InfraredSensor

from ev3dev2.motor import OUTPUT_A, OUTPUT_B, MediumMotor, LargeMotor, SpeedPercent

#time
current = datetime.datetime.now()
hour = current.strftime("%I")
minute = current.strftime("%M")
rotation = int(hour) + int(minute)/60
print(hour)
print(minute)
print(rotation)

#calibrate
minutehand = MediumMotor(OUTPUT_A)
minutehand.on_for_rotations(SpeedPercent(100), 12)

minutehand.on_for_rotations(SpeedPercent(100), rotation)

ir = InfraredSensor()
sound = Sound()
stopper = TouchSensor()
cuckoo = LargeMotor(OUTPUT_B)

while True:
    if stopper.is_pressed:
        cuckoo.on_for_seconds(SpeedPercent(30), 1)
    elif ir.proximity < 30:
        print(ir.proximity)
        sound.play_file("cuckoo.wav")
        cuckoo.on_for_seconds(SpeedPercent(-30), 1)

Credits

Lin Ochoa

Lin Ochoa

2 projects • 4 followers
Queens College Computer Science Student

Comments