Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
Hand tools and fabrication machines | ||||||
|
Welcome to the world of LEGO R2D2 droid powered by Amazon Alexa. It is a robot made of Lego MINDSTORMS EV3 components and powered by Linux.
These instructions are created to show you how to connect your EV3 Brick to Alexa, and build custom voice-based interactions that incorporate EV3 motors and sensors.
Lego R2D2 is a friendly robot which can sing some songs, say you something if you touch it, and even dance on Amazon music play.
Steps:Follow instructions on the pages below:
- Build R2D2 droid by following the building instructions ( see attachment )
- Install ev3dev for programming your EV3 Brick
- Instal Visual Studio Code for editing code
- Install Alexa Gadgets Python Software on your EV3 Brick
- Register Lego R2D2 as an Alexa gadget
- Prepare your Lego R2D2 to get the software (see attached files)
- Open provided software with Visual Studio Code and run on EV3 ( R2D2 Lego)
- Create custom Alexa skill ( follow the steps here) and paste the Node.js code to implement the Skill Logic
- After you create custom Amazon Alexa Skill, use attached lambda functions to create Lego R2D2 skill. Result should look as below
- Run the python software and Lego R2D2 by following this
- Find and use some R2D2 sounds here https://www.soundboard.com/sb/Portage. I used https://www.jovo.tech/audio-converter to host the audio files to make my video.
Now comes the fun part! Make some room for Lego R2D2, and try the following commands to see how EV3RSTORM reacts:
“Alexa, open LegoR2D2”
Alexa should respond acknowledging the skill session is active and lists all possible commands. The skill must be in session in order for the other following commands to work.
“singa song” - and R2D2 will sing you a song
"Alexa play music" and R2D2 starts to dance.
"Tell me story" and R2D2 tells something about Darth Vader, Maul, or Senator Palpatine.
You can find R2D2 building instruction in the attachment
Helpful resources
#!/usr/bin/env python3
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# You may not use this file except in compliance with the terms and conditions
# set forth in the accompanying LICENSE.TXT file.
#
# THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH
# RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
# THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
import time
import logging
import json
import random
import threading
from enum import Enum
from agt import AlexaGadget
from ev3dev2.led import Leds
from ev3dev2.sound import Sound
from ev3dev2.motor import OUTPUT_A, OUTPUT_B, OUTPUT_C, MoveTank, SpeedPercent, MediumMotor, LargeMotor
from ev3dev2.sensor.lego import InfraredSensor
from ev3dev2.sensor.lego import TouchSensor
# Set the logging level to INFO to see messages from AlexaGadget
logging.basicConfig(level=logging.INFO)
class Direction(Enum):
"""
The list of directional commands and their variations.
These variations correspond to the skill slot values.
"""
FORWARD = ['forward', 'forwards', 'go forward','vor','vorwrts', 'gerade aus','fahre']
BACKWARD = ['back', 'backward', 'backwards', 'go backward','rckwards','fahre zurck','zurck']
LEFT = ['left', 'go left', 'links','nach links']
RIGHT = ['right', 'go right', 'rechts','nach rechts']
STOP = ['stop', 'brake','halt', 'anhalten']
class Command(Enum):
"""
The list of preset commands and their invocation variation.
These variations correspond to the skill slot values.
"""
MOVE_CIRCLE = ['circle', 'spin']
MOVE_SQUARE = ['square']
PATROL = ['patrol']
FIRE_ONE = ['fire', 'shot', '1 shot', 'one shot','feuer','schieen']
FIRE_ALL = ['all shot']
SING = ['song','sing','sing a song']
SECOND_SONG = ['second song']
SENTRY = ['guard', 'protect', 'sentry', 'sentry mode','watch', 'watch mode']
class EventName(Enum):
"""
The list of custom events sent from this gadget to Alexa
"""
SENTRY = "Sentry"
PROXIMITY = "Proximity"
SPEECH = "Speech"
class MindstormsGadget(AlexaGadget):
"""
A Mindstorms gadget that performs movement based on voice commands.
Two types of commands are supported, directional movement and preset.
"""
def __init__(self):
"""
Performs Alexa Gadget initialization routines and ev3dev resource allocation.
"""
super().__init__()
# Gadget state
self.sentry_mode = False
self.patrol_mode = False
# Ev3dev initialization
self.leds = Leds()
self.sound = Sound()
self.ir = InfraredSensor()
self.ts = TouchSensor()
self.head = MediumMotor(OUTPUT_A)
self.left_motor = LargeMotor(OUTPUT_B)
self.right_motor = LargeMotor(OUTPUT_C)
# Gadget states
self.bpm = 0
self.trigger_bpm = "off"
# Start threads
threading.Thread(target=self._patrol_thread, daemon=True).start()
threading.Thread(target=self._proximity_thread, daemon=True).start()
threading.Thread(target=self._touchsensor_thread, daemon=True).start()
def on_connected(self, device_addr):
"""
Gadget connected to the paired Echo device.
:param device_addr: the address of the device we connected to
"""
self.leds.set_color("LEFT", "GREEN")
self.leds.set_color("RIGHT", "GREEN")
# shake ev3 head
threading.Thread(target=self._shakehead).start()
self.sound.speak('R2D2')
def on_disconnected(self, device_addr):
"""
Gadget disconnected from the paired Echo device.
:param device_addr: the address of the device we disconnected from
"""
self.leds.set_color("LEFT", "BLACK")
self.leds.set_color("RIGHT", "BLACK")
print("{} disconnected from Echo device".format(self.friendly_name))
def on_custom_mindstorms_gadget_control(self, directive):
"""
Handles the Custom.Mindstorms.Gadget control directive.
:param directive: the custom directive with the matching namespace and name
"""
try:
payload = json.loads(directive.payload.decode("utf-8"))
print("Control payload: {}".format(payload))
control_type = payload["type"]
if control_type == "move":
# Expected params: [direction, duration, speed]
self._move(payload["direction"], int(payload["duration"]), int(payload["speed"]))
if control_type == "command":
# Expected params: [command]
self._activate(payload["command"])
except KeyError:
print("Missing expected parameters: {}".format(directive))
# On Amazon music play
def on_alexa_gadget_musicdata_tempo(self, directive):
"""
Provides the music tempo of the song currently playing on the Echo device.
:param directive: the music data directive containing the beat per minute value
"""
tempo_data = directive.payload.tempoData
for tempo in tempo_data:
print("tempo value: {}".format(tempo.value))
if tempo.value > 0:
# dance pose
#self.drive.on_for_seconds(SpeedPercent(5), SpeedPercent(25), 1)
self.right_motor.run_timed(speed_sp=750, time_sp=2500)
self.left_motor.run_timed(speed_sp=-750, time_sp=2500)
# shake ev3 head
threading.Thread(target=self._shakehead).start()
self.leds.set_color("LEFT", "GREEN")
self.leds.set_color("RIGHT", "GREEN")
time.sleep(3)
# starts the dance loop
self.trigger_bpm = "on"
threading.Thread(target=self._dance_loop, args=(tempo.value,)).start()
elif tempo.value == 0:
# stops the dance loop
self.trigger_bpm = "off"
self.leds.set_color("LEFT", "BLACK")
self.leds.set_color("RIGHT", "BLACK")
def _dance_loop(self, bpm):
"""
Perform motor movement in sync with the beat per minute value from tempo data.
:param bpm: beat per minute from AGT
"""
color_list = ["GREEN", "RED", "AMBER", "YELLOW"]
led_color = random.choice(color_list)
motor_speed = 400
milli_per_beat = min(1000, (round(60000 / bpm)) * 0.65)
print("Adjusted milli_per_beat: {}".format(milli_per_beat))
while self.trigger_bpm == "on":
# Alternate led color and motor direction
led_color = "BLACK" if led_color != "BLACK" else random.choice(color_list)
motor_speed = -motor_speed
self.leds.set_color("LEFT", led_color)
self.leds.set_color("RIGHT", led_color)
self.right_motor.run_timed(speed_sp=motor_speed, time_sp=150)
self.left_motor.run_timed(speed_sp=-motor_speed, time_sp=150)
time.sleep(milli_per_beat / 1000)
self.left_motor.run_timed(speed_sp=-motor_speed, time_sp=150)
self.right_motor.run_timed(speed_sp=motor_speed, time_sp=150)
time.sleep(milli_per_beat / 1000)
self.right_motor.run_timed(speed_sp=350, time_sp=300)
self.left_motor.run_timed(speed_sp=-350, time_sp=300)
time.sleep(milli_per_beat / 1000)
self.right_motor.run_timed(speed_sp=motor_speed, time_sp=150)
self.left_motor.run_timed(speed_sp=-motor_speed, time_sp=150)
time.sleep(milli_per_beat / 1000)
def _move(self, direction, duration: int, speed: int, is_blocking=False):
"""
Handles move commands from the directive.
Right and left movement can under or over turn depending on the surface type.
:param direction: the move direction
:param duration: the duration in seconds
:param speed: the speed percentage as an integer
:param is_blocking: if set, motor run until duration expired before accepting another command
"""
print("Move command: ({}, {}, {}, {})".format(direction, speed, duration, is_blocking))
if direction in Direction.FORWARD.value:
#self.drive.on_for_seconds(SpeedPercent(speed), SpeedPercent(speed), duration, block=is_blocking)
self.right_motor.run_timed(speed_sp=-750, time_sp=2500)
self.left_motor.run_timed(speed_sp=-750, time_sp=2500)
if direction in Direction.BACKWARD.value:
#self.drive.on_for_seconds(SpeedPercent(-speed), SpeedPercent(-speed), duration, block=is_blocking)
self.right_motor.run_timed(speed_sp=750, time_sp=2500)
self.left_motor.run_timed(speed_sp=750, time_sp=2500)
if direction in (Direction.RIGHT.value + Direction.LEFT.value):
self._turn(direction, speed)
#self.drive.on_for_seconds(SpeedPercent(speed), SpeedPercent(speed), duration, block=is_blocking)
self.right_motor.run_timed(speed_sp=750, time_sp=2500)
self.left_motor.run_timed(speed_sp=-750, time_sp=2500)
if direction in Direction.STOP.value:
#self.drive.off()
self.right_motor.stop
self.left_motor.stop
self.sentry_mode = False
self.patrol_mode = False
def _activate(self, command, speed=50):
"""
Handles preset commands.
:param command: the preset command
:param speed: the speed if applicable
"""
print("Activate command: ({}, {})".format(command, speed))
if command in Command.MOVE_CIRCLE.value:
#self.drive.on_for_seconds(SpeedPercent(int(speed)), SpeedPercent(5), 12)
self.right_motor.run_timed(speed_sp=750, time_sp=2500)
self.left_motor.run_timed(speed_sp=50, time_sp=100)
if command in Command.MOVE_SQUARE.value:
for i in range(4):
self._move("right", 2, speed, is_blocking=True)
if command in Command.PATROL.value:
# Set patrol mode to resume patrol thread processing
self.patrol_mode = True
self._send_event(EventName.SPEECH, {'speechOut': "PATROL_MODE_ACTIVATED_MSG"})
if command in Command.FIRE_ONE.value:
self.head.on_for_rotations(SpeedPercent(100), 3)
if command in Command.FIRE_ALL.value:
self.head.on_for_rotations(SpeedPercent(100), 10)
if command in Command.SING.value:
threading.Thread(target=self._marchaimp).start()
if command in Command.SECOND_SONG.value:
threading.Thread(target=self._smallSong).start()
if command in Command.SENTRY.value:
self.sentry_mode = True
self._send_event(EventName.SPEECH, {'speechOut': "SENTRY_MODE_ACTIVATED_MSG"})
def _turn(self, direction, speed):
"""
Turns based on the specified direction and speed.
Calibrated for hard smooth surface.
:param direction: the turn direction
:param speed: the turn speed
"""
if direction in Direction.LEFT.value:
#self.drive.on_for_seconds(SpeedPercent(0), SpeedPercent(speed), 2)
self.right_motor.run_timed(speed_sp=0, time_sp=100)
self.left_motor.run_timed(speed_sp=750, time_sp=100)
if direction in Direction.RIGHT.value:
#self.drive.on_for_seconds(SpeedPercent(speed), SpeedPercent(0), 2)
self.right_motor.run_timed(speed_sp=750, time_sp=100)
self.left_motor.run_timed(speed_sp=0, time_sp=100)
def _send_event(self, name: EventName, payload):
"""
Sends a custom event to trigger a sentry action.
:param name: the name of the custom event
:param payload: the sentry JSON payload
"""
self.send_custom_event('Custom.Mindstorms.Gadget', name.value, payload)
def _proximity_thread(self):
"""
Monitors the distance between the robot and an obstacle when sentry mode is activated.
If the minimum distance is breached, send a custom event to trigger action on
the Alexa skill.
"""
count = 0
while True:
while self.sentry_mode:
distance = self.ir.proximity
print("Proximity: {}".format(distance))
count = count + 1 if distance < 10 else 0
if count > 3:
print("Proximity breached. Sending event to skill")
self.leds.set_color("LEFT", "RED", 1)
self.leds.set_color("RIGHT", "RED", 1)
self._send_event(EventName.PROXIMITY, {'distance': distance})
self.sentry_mode = False
time.sleep(0.2)
time.sleep(1)
def _touchsensor_thread(self):
print("Touch sensor activated")
while True:
if self.ts.is_pressed:
self._send_event(EventName.SPEECH, {'speechOut': "SENSOR_TOUCH_ACTIVATED_MSG"})
self.leds.set_color("LEFT", "RED")
self.leds.set_color("RIGHT", "RED")
else:
self.leds.set_color("LEFT", "GREEN")
self.leds.set_color("RIGHT", "GREEN")
def _shakehead(self):
# turn robot head left and right
self.head.on_for_rotations(SpeedPercent(30), 0.3)
self.head.on_for_rotations(SpeedPercent(30), -0.3)
def _patrol_thread(self):
"""
Performs random movement when patrol mode is activated.
"""
while True:
while self.patrol_mode:
print("Patrol mode activated randomly picks a path")
direction = random.choice(list(Direction))
duration = random.randint(1, 5)
speed = random.randint(1, 4) * 25
while direction == Direction.STOP:
direction = random.choice(list(Direction))
# direction: all except stop, duration: 1-5s, speed: 25, 50, 75, 100
self._move(direction.value[0], duration, speed)
time.sleep(duration)
time.sleep(1)
def _cabezaderecha(self):
self.head.run_forever(speed=450)
def _cabezaizquierda(self):
self.head.run_forever(speed=-450)
def _marchaimp(self):
self.sound.tone([
(392, 350, 100), (392, 350, 100), (392, 350, 100), (311.1, 250, 100),
(466.2, 25, 100), (392, 350, 100), (311.1, 250, 100), (466.2, 25, 100),
(392, 700, 100), (587.32, 350, 100), (587.32, 350, 100),
(587.32, 350, 100), (622.26, 250, 100), (466.2, 25, 100),
(369.99, 350, 100), (311.1, 250, 100), (466.2, 25, 100), (392, 700, 100),
(784, 350, 100), (392, 250, 100), (392, 25, 100), (784, 350, 100),
(739.98, 250, 100), (698.46, 25, 100), (659.26, 25, 100),
(622.26, 25, 100), (659.26, 50, 400), (415.3, 25, 200), (554.36, 350, 100),
(523.25, 250, 100), (493.88, 25, 100), (466.16, 25, 100), (440, 25, 100),
(466.16, 50, 400), (311.13, 25, 200), (369.99, 350, 100),
(311.13, 250, 100), (392, 25, 100), (466.16, 350, 100), (392, 250, 100),
(466.16, 25, 100), (587.32, 700, 100), (784, 350, 100), (392, 250, 100),
(392, 25, 100), (784, 350, 100), (739.98, 250, 100), (698.46, 25, 100),
(659.26, 25, 100), (622.26, 25, 100), (659.26, 50, 400), (415.3, 25, 200),
(554.36, 350, 100), (523.25, 250, 100), (493.88, 25, 100),
(466.16, 25, 100), (440, 25, 100), (466.16, 50, 400), (311.13, 25, 200),
(392, 350, 100), (311.13, 250, 100), (466.16, 25, 100),
(392.00, 300, 150), (311.13, 250, 100), (466.16, 25, 100), (392, 700)
])
def _smallSong(self):
self.sound.play_song((
('D4', 'e3'), # A long time ago in a galaxy far,
('D4', 'e3'), # far away...
('D4', 'e3'),
('G4', 'h'),
('D5', 'h'),
('C5', 'e3'),
('B4', 'e3'),
('A4', 'e3'),
('G5', 'h'),
('D5', 'q'),
('C5', 'e3'),
('B4', 'e3'),
('A4', 'e3'),
('G5', 'h'),
('D5', 'q'),
('C5', 'e3'),
('B4', 'e3'),
('C5', 'e3'),
('A4', 'h.'),
))
if __name__ == '__main__':
# Startup sequence
gadget = MindstormsGadget()
#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")
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# You may not use this file except in compliance with the terms and conditions
# set forth in the accompanying LICENSE.TXT file.
#
# THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH
# RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
# THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
[GadgetSettings]
amazonId = AMAZON_ID
alexaGadgetSecret = ALEXA_SECRET
[GadgetCapabilities]
Custom.Mindstorms.Gadget = 1.0
Alexa.Gadget.MusicData = 1.0 - tempo
Alexa.Gadget.SpeechData = 1.0 - viseme
Alexa.Gadget.StateListener = 1.0 - timeinfo, wakeword
module.exports = {
en: {
translation: {
COMMAND_TEXT: `command`,
ACTIVATED_TEXT: `activated`,
NO_EV3_FOUND_MSG: `<say-as interpret-as="interjection">oh boy, </say-as> I couldn't find LEGO Artoo-Detoo connected to this Echo device. Please check your LEGO Artoo-Detoo is connected, and try again.`,
AWAIT_COMMANDS_MSG: `<voice name="Matthew"> Awaiting your commands </voice>`,
WELCOME_GREETING_1_MSG: `<voice name="Matthew"> Weclome, I am Artoo-Detoo. I am very good in dancing, singing, and marchal arts. Just say Artoo-Detoo dance, or Artoo-Detoo sing. /voice>`,
WELCOME_GREETING_2_MSG: `<voice name="Matthew">Hi, I am Artoo-Detoo. I am not a human but I am very good in dancing, singing. Just say Alexa, let's dance, or please sing. </voice>`,
WELCOME_GREETING_3_MSG: `<say-as interpret-as="interjection">aloha, </say-as><voice name="Matthew"> Artoo-Detoo, your best friend in the whole galaxy. Say dance or let's sing.</voice>`,
WELCOME_GREETING_4_MSG: `<voice name="Matthew"> Artoo-Detoo welcomes you. </voice> <amazon:effect name="whispered">Or just Eitoo.</amazon:effect> I am good in dancing and singing. Just tell Alexa let's dance or sing a song.`,
WELCOME_BACK_GREETING_1_MSG: `<voice name="Matthew"> Weclome back! What should we do now.<break time="2s"/> Say, Alexa let's dance.</voice>`,
WELCOME_BACK_GREETING_2_MSG: `<voice name="Matthew"> howdy, Artoo-Detoo is happy to play with you again. <s>Shoud we dance ?</s> Just say dance.</voice>`,
WELCOME_BACK_GREETING_3_MSG: `<voice name="Matthew"> Artoo-Detoo can dance and sing. Say dance.</voice>`,
WELCOME_BACK_GREETING_4_MSG: `<voice name="Matthew"> Hello there. You can ask me to tell you about Emperor Palpatine</voice> `,
REPEAT_COMMANDS_MSG: `<voice name="Matthew">Sorry, I could not understand your command. Can you repeat that? </voice>`,
ERROR_COMMANDS_MSG: `<voice name="Matthew"> Sorry, I had trouble doing what you asked. Please try again.</voice>`,
VOICE_INTERFACE_ACTIV_MSG:`Voice interface activated.`,
PATROL_MODE_ACTIVATED_MSG : `<voice name="Matthew"> Patrol mode activated </voice>`,
SENTRY_MODE_ACTIVATED_MSG: `<voice name="Matthew"> Sentry mode is now activated </voice>`,
BRAKE_MSG: `<voice name="Matthew">Applying brake </voice>`,
OBJECT_DETECTED_MSG: `<voice name="Matthew"> Object detected </voice>`,
OBJECT_ELIMINATED_MSG: `<voice name="Matthew">Threat eliminated </voice>`,
UNKNOWN_EVENT_MSG: `<voice name="Matthew"> Event not recognized. Awaiting new command.</voice>`,
GOODBYE_MSG: `<voice name="Matthew"><emphasis level="strong">Goodbye</emphasis> Artoo-Detoo goes sleeping. To wake me up, say Alexa start lego robot</voice>`,
COMMAND_REMIND_MSG: `<voice name="Matthew">If you want me to sing, say sing a song. or you want me to dance, then say lets dance. If you want a story, say tell me story.</voice>`,
HELP_COMMAND_MSG: `<voice name="Matthew">you can say, turn left or go forward. to change my speed, say set speed 60 percent.</voice>`,
SENSOR_TOUCH_ACTIVATED_MSG:`<voice name="Matthew"><say-as interpret-as="interjection">ha ha</say-as> i can feel that you touched me</voice>`,
PALPATINE: `<voice name="Matthew">Let me tell you something about Emperor Palpatine. Sheev Palpatine was the sole engineer of his rise to power.
Being a former apprentice to Darth Plagueis the Wise, a Sith Lord who was a master of arcane and unnatural knowledge, he could plan events far in the future and use the Force to foresee the results.
He began as a Naboo Senator in the Galactic Republic and used several conflicts he had constructed to gain more power.</voice>`,
VADER: `<voice name="Matthew"> Ok, I will tell you something about Darth Vader. Darth Vader was the Chosen One, a Jedi legend who brings balance to the Force.
Vader was born as Anakin Skywalker on Tatooine. He was first slave, then became a Jedi and eventually fell to the Dark Side.
Along the way, he earned a great name for himself by saving the Galactic Republic more than a few times. He liked his Jedi Master, Obi-Wan Kenobi and he loved Padme Amidala.
Darth Vader turned his back on the Jedi and sweared his allegiance to the Emperor.</voice>`,
MAUL:`<voice name="Matthew"> <say-as interpret-as="interjection">oh boy, </say-as> Darth Maul was an Iridonian, born on Iridonia. At an early age he was trained as a Jedi, but was kidnapped by Darth Sidious, who conditioned him to forget everything he had learned from the Jedi.
He then began to teach him the ways of the Dark Side. Maul had absolutely no memories of his homeworld of Iridonia and was incapable of feeling emotions outside of bloodlust and rage.
Sidious turned him into a brutal killing machine and a weapon of pure hatred, severely punishing any show of fear or mercy.
Maul is described as the ultimate tool of the dark side, with Sith tattoos covering his entire body.
The reason that Maul was Sidious' apprentice is because of the martial powers of the Zabraks and how they'd hire themselves to the Sith.</voice>`
}
},
de: {
translation: {
COMMAND_TEXT: `Befehl`,
ACTIVATED_TEXT: `aktiviert`,
NO_EV3_FOUND_MSG: ` <say-as interpret-as="interjection">oh mann </say-as> LEGO r zwo d zwo ist mit deinem Echo Gert nicht verbunden. berprfe auf deinem LEGO r zwo d zwo die Bluetooth Verbindung und probiere es nochmal.`,
AWAIT_COMMANDS_MSG: `<voice name="Hans"> Warte auf deine Befehle </voice>`,
WELCOME_GREETING_1_MSG: `<voice name="Hans"> Hallo und Willkommen zu r zwo d zwo.</voice>`,
WELCOME_GREETING_2_MSG: `<voice name="Hans"> hallihallo. Ich bin r zwo d zwo. Ich bin kein Mensch aber auch nicht einfach Maschine.</voice>`,
WELCOME_GREETING_3_MSG: `<voice name="Hans"> r zwo d zwo - dein bester Freund.</voice>`,
WELCOME_GREETING_4_MSG: `<voice name="Hans"> Gr Gott, ich bn rr zwoo du zwoo.</voice>`,
WELCOME_BACK_GREETING_1_MSG: `<voice name="Hans"> Ich freue mich dass du wieder da bist. </voice>`,
WELCOME_BACK_GREETING_2_MSG: `<voice name="Hans"> Hallo, lass uns zusammen was unternehmen. Ich habe auf dich gewartet.</voice>`,
WELCOME_BACK_GREETING_3_MSG: `<voice name="Hans"> LEGO r zwo d zwo </voice><amazon:effect name="whispered">Wusstes du dass ich eigentlich LEGO r zwo hie? </amazon:effect>`,
WELCOME_BACK_GREETING_4_MSG: `<voice name="Hans"> Cool, du bist wieder da. Lass uns singen, tanzen, oder Geschichten erzhlen.</voice> `,
REPEAT_COMMANDS_MSG: `<voice name="Hans"> Es tut mir leid. Ich kenne dieses Kommando noch nicht, kannst du nochmal wiederholen ? </voice>`,
VOICE_INTERFACE_ACTIV_MSG: `<voice name="Hans">Sprach-Modus aktiviert </voice>`,
PATROL_MODE_ACTIVATED_MSG : `<voice name="Hans"> Wache Modus aktiviert </voice>`,
SENTRY_MODE_ACTIVATED_MSG: `<voice name="Hans"> berwachung aktiviert </voice>`,
BRAKE_MSG: `<voice name="Hans"> Bremsen aktiviert </voice>`,
OBJECT_DETECTED_MSG: `<audio src="soundbank://soundlibrary/scifi/amzn_sfx_scifi_alarm_02"/> Sprachen-Modus aktiviert`,
OBJECT_ELIMINATED_MSG: `<voice name="Matthew">Gefahr eliminiert </voice>`,
UNKNOWN_EVENT_MSG: `<voice name="Hans"> Was ist passiert, ich kenne dieses Kommando nicht. Warte auf neue Befehle.</voice>`,
GOODBYE_MSG: `<voice name="Hans"> <emphasis level="strong">Tschss </emphasis> Meine Zeit ist aus. Mich wieder zu starten, sage: Alexa, starte lego robot.</voice>`,
DURATION_REMIND_MSG: `<voice name="Hans"><say-as interpret-as="interjection">oh boy, lets play</say-as> Otherwise Artoo-Detoo goes sleeping.</voice>`,
COMMAND_REMIND_MSG: `<voice name="Hans"> Soll ich singen, sag singe. Falls du mich tanzen siehen willst, sag tanze. Falls du Geschichten magst, sag erzhle Geschichte.</voice>`,
HELP_COMMAND_MSG: `<voice name="Hans"> Willst du dass ich mich bewege, dann sag fahre rechts oder links. Du kannst meine Geschwindigket ndern indem du mir sagst, ndere Geschwindigket auf 60 Prozent.</voice>`,
SENSOR_TOUCH_ACTIVATED_MSG:`<voice name="Hans"><say-as interpret-as="interjection">au weia</say-as> Du hast mich gepickst</voice>`,
PALPATINE: `<voice name="Hans">Kaiser Sheev Palpatine, auch bekannt als Darth Sidious, wurde von Darth Plageuis trainiert.
Nachdem er alles gelernt hatte, was er wusste, ttete er ihn im Schlaf und begann, Darth Maul als Lehrling aufzunehmen.
Palpatine schien zunchst ein liebenswrdiger Politiker und ein harmloser, aber wohlmeinender Mensch zu sein. Dies war ein Vorwand, um die Mitglieder des Galaktischen Senats zu tuschen, dass er die besten Absichten fr die Galaxis hatte.
In Wahrheit war Palpatine jedoch ein arroganter, ehrgeiziger, machtgieriger und machiavellistischer Intrigant.
Er wnschte sich absolute Macht und Ausschluss aus dem trgerischen Glauben, ber allem anderen zu stehen. Trotz seiner Arroganz war er uerst intelligent, geduldig, gerissen und manipulativ.</voice>`,
VADER: `<voice name="Hans"> Ok, Ich erzhle dir was ber Darth Vader. Darth Vader war zunchst ein Sklave, geboren in Tatooine.
Damals hie er Anakin Skywalker. Er wurde Jedi-Ritter Anakin Skywalker aber spter wechselte er an die dunkle Seite.
Vader war kalt, brutal und unbarmherzig gegenber seinen Feinden, da er durchaus bereit war, sie kaltbltig zu terrorisieren, zu foltern und sogar zu ermorden.
Als Auserwhlter war Vader immens mchtig und hatte eine erstaunlich starke Verbindung zur Macht. Strker als jeder Force-Benutzer, der jemals existierte, verfgte er auch ber das Potenzial, der mchtigste Force-Benutzer in der Geschichte der Galaxis zu werden.
Laut Obi-Wan Kenobi, Vaders Krfte bertrafen die von Yoda und Palpatin.Nur sein Sohn Luke Skywalker hat ihn bertroffen. </voice>`,
MAUL: `<voice name="Hans"> Maul war ein Lehrling von Palpatine.
Maul lebte in den letzten Tagen der Galaktischen Republik und am Vorabend der Regierungszeit des Galaktischen Reiches .
Maul war Sohn von Talzin und auf Dathomir geboren. Er wurde von Darth Sidious als Sith-Lehrling aufgenommen und erhielt den Namen Darth Maul.
Die Trainingsmethoden von Sidious waren oft unvershnlich und hart. Mauls Leben und Beweggrnde beruhten auf Rache.
Als Sith-Lord suchte Maul Rache an den Jedi fr ihren Triumph ber die Sith und wollte den Sith-Orden wieder an die Macht ber die Galaxis bringen.
Nach seinem Exil und der Wiederherstellung seines Geistes wandte Maul seine Gedanken an Rache der Galaxis zu.
Manchmal war Maul animalisch, was sich in seiner Fhigkeit uerte, wie ein wildes Tier zu knurren. Dies knnte ihm gelegentlich erlauben, seine Gegner psychisch zu verunsichern.</voice>`
}
}
}
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* You may not use this file except in compliance with the terms and conditions
* set forth in the accompanying LICENSE.TXT file.
*
* THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH
* RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
* THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
*/
'use strict'
const Alexa = require('ask-sdk-core');
const HelpIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
const speakOutput = 'Ok';
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
const CancelAndStopIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent'
|| Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent');
},
handle(handlerInput) {
const speakOutput = 'Ciao!';
return handlerInput.responseBuilder
.speak(speakOutput)
.getResponse();
}
};
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest';
},
handle(handlerInput) {
// Any cleanup logic goes here.
return handlerInput.responseBuilder.getResponse();
}
};
// The intent reflector is used for interaction model testing and debugging.
// It will simply repeat the intent the user said. You can create custom handlers
// for your intents by defining them above, then also adding them to the request
// handler chain below.
const IntentReflectorHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest';
},
handle(handlerInput) {
const intentName = Alexa.getIntentName(handlerInput.requestEnvelope);
const speakOutput = `You just triggered ${intentName}`;
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(handlerInput.t('REPEAT_COMMANDS_MSG'))
.getResponse();
}
};
// Generic error handling to capture any syntax or routing errors. If you receive an error
// stating the request handler chain is not found, you have not implemented a handler for
// the intent being invoked or included it in the skill builder below.
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
console.log(`~~~~ Error handled: ${error.stack}`);
const speakOutput = handlerInput.t('ERROR_COMMANDS_MSG');
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
// The request interceptor is used for request handling testing and debugging.
// It will simply log the request in raw json format before any processing is performed.
const RequestInterceptor = {
process(handlerInput) {
let { attributesManager, requestEnvelope } = handlerInput;
let sessionAttributes = attributesManager.getSessionAttributes();
// Log the request for debug purposes.
console.log(`=====Request==${JSON.stringify(requestEnvelope)}`);
console.log(`=========SessionAttributes==${JSON.stringify(sessionAttributes, null, 2)}`);
}
};
module.exports = {
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
IntentReflectorHandler,
ErrorHandler,
RequestInterceptor
};
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* You may not use this file except in compliance with the terms and conditions
* set forth in the accompanying LICENSE.TXT file.
*
* THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH
* RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
* THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
*/
// This skill uses source code provided in https://www.hackster.io/alexagadgets/
const Alexa = require('ask-sdk-core');
const Util = require('./util');
const Common = require('./common');
// Import language strings containing all skill voice messages
// e.g. handlerInput.t('WELCOME_MSG')
const i18n = require('i18next');
const languageStrings = require('./localisation');
// The audio tag to include background music
const BG_MUSIC = '<audio src="soundbank://soundlibrary/ui/gameshow/amzn_ui_sfx_gameshow_waiting_loop_30s_01"/>';
const EUREKA_AUDIO= '<audio src="https://www.jovo.tech/audio/MzFl4xyr-eureka-r2d2.mp3"/>';
const CONFIRMATION_AUDIO = '<audio src="https://www.jovo.tech/audio/xUKox0Df-happy-confirmation.mp3"/>';
const LAUGH_AUDIO = '<audio src="https://www.jovo.tech/audio/wna3ztb3-laughing-r2d2.mp3"/>';
const PROCESSING_AUDIO = '<audio src="https://www.jovo.tech/audio/huqkWkdP-processing-r2d2.mp3"/>';
const BEEPING_AUDIO = '<audio src="https://www.jovo.tech/audio/WZaiiPHa-r2-beeping-5.mp3"/>';
const PUTTING_TOGETHER_AUDIO = '<audio src="https://www.jovo.tech/audio/wFIPR2pX-putting-it-together.mp3"/>';
const SAD_AUDIO = '<audio src="https://www.jovo.tech/audio/os8CFK0M-sad-r2d2.mp3"/>';
const GRUMBLING_AUDIO = '<audio src="https://www.jovo.tech/audio/NrdaEx4K-unconvined-grumbling.mp3"/>';
const AUDIO = [EUREKA_AUDIO, LAUGH_AUDIO, PROCESSING_AUDIO, PUTTING_TOGETHER_AUDIO, GRUMBLING_AUDIO];
const COMMANDS_LIST = ['COMMAND_REMIND_MSG', 'HELP_COMMAND_MSG'];
// Array of welcome greetings
const welcomeGreetings = ['WELCOME_GREETING_1_MSG','WELCOME_GREETING_2_MSG','WELCOME_GREETING_3_MSG', 'WELCOME_GREETING_4_MSG'];
const welcomeAgainGreetings = ['WELCOME_BACK_GREETING_1_MSG','WELCOME_BACK_GREETING_2_MSG','WELCOME_BACK_GREETING_3_MSG', 'WELCOME_BACK_GREETING_4_MSG'];
// The namespace of the custom directive to be sent by this skill
const NAMESPACE = 'Custom.Mindstorms.Gadget';
// The name of the custom directive to be sent this skill
const NAME_CONTROL = 'control';
const LaunchRequestHandler = {
canHandle(handlerInput) {
console.log("Inside LaunchRequest");
const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
const launchCount = sessionAttributes['launchCount'] || 0;
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
},
handle: async function(handlerInput) {
const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
const request = handlerInput.requestEnvelope;
const { apiEndpoint, apiAccessToken } = request.context.System;
const apiResponse = await Util.getConnectedEndpoints(apiEndpoint, apiAccessToken);
console.log("apiResponse: " + apiResponse);
let speakOutput = handlerInput.t('NO_EV3_FOUND_MSG');
if ((apiResponse.endpoints || []).length === 0) {
return handlerInput.responseBuilder
.speak(speakOutput)
.getResponse();
}
// Store the gadget endpointId to be used in this skill session
const endpointId = apiResponse.endpoints[0].endpointId || [];
Util.putSessionAttribute(handlerInput, 'endpointId', endpointId);
// Set skill duration to 5 minutes (ten 30-seconds interval)
Util.putSessionAttribute(handlerInput, 'duration', 10);
// Set the token to track the event handler
const token = handlerInput.requestEnvelope.request.requestId;
Util.putSessionAttribute(handlerInput, 'token', token);
const launchCount = sessionAttributes['launchCount'];
let speechOutput = '';
if (launchCount === 1) {
speechOutput = handlerInput.t('VOICE_INTERFACE_ACTIV_MSG') + handlerInput.t(randomChoice(welcomeGreetings));
} else {
speechOutput = handlerInput.t('VOICE_INTERFACE_ACTIV_MSG') + handlerInput.t(randomChoice(welcomeAgainGreetings));
}
// starting point
return handlerInput.responseBuilder
.speak(randomChoice(AUDIO) + speechOutput)
.addDirective(Util.buildStartEventHandler(token,60000, {}))
.getResponse();
}
};
// Add the speed value to the session attribute.
// This allows other intent handler to use the specified speed value
// without asking the user for input.
const SetSpeedIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'SetSpeedIntent';
},
handle: function (handlerInput) {
// Bound speed to (1-100)
let speed = Alexa.getSlotValue(handlerInput.requestEnvelope, 'Speed');
speed = Math.max(1, Math.min(100, parseInt(speed)));
Util.putSessionAttribute(handlerInput, 'speed', speed);
let speechOutput = `speed set to ${speed} percent.`;
return handlerInput.responseBuilder
.speak(PROCESSING_AUDIO + speechOutput + CONFIRMATION_AUDIO)
.getResponse();
}
};
// Construct and send a custom directive to the connected gadget with
// data from the MoveIntent.
const MoveIntentHandler = {
canHandle(handlerInput) {
console.log("Inside MoveIntentHandler");
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'MoveIntent';
},
handle: function (handlerInput) {
const request = handlerInput.requestEnvelope;
const direction = Alexa.getSlotValue(request, 'Direction');
console.log("MoveIntent request: " + JSON.stringify(request));
// Duration is optional, use default if not available
const duration = Alexa.getSlotValue(request, 'Duration') || "2";
// Get data from session attribute
const attributesManager = handlerInput.attributesManager;
const speed = attributesManager.getSessionAttributes().speed || "50";
const endpointId = attributesManager.getSessionAttributes().endpointId || [];
// Construct the directive with the payload containing the move parameters
let directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
{
type: 'move',
direction: direction,
duration: duration,
speed: speed
});
const speechOutput = (direction === "brake")
? handlerInput.t('BRAKE_MSG')
: `${direction} ${duration} seconds at ${speed} percent speed`;
return handlerInput.responseBuilder
.speak(speechOutput + BG_MUSIC)
.addDirective(directive)
.getResponse();
}
};
const TellStoryIntentHandler = {
canHandle(handlerInput) {
console.log("Inside TellStoryIntentHandler");
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'TellStoryIntent';
},
handle: function (handlerInput) {
const story = ['PALPATINE','VADER','MAUL'];
const request = handlerInput.requestEnvelope;
console.log(`Telling a story about ${story}`);
// Get data from session attribute
let speechOutput = handlerInput.t(randomChoice(story));
return handlerInput.responseBuilder
.speak(speechOutput)
.withShouldEndSession(false)
.getResponse();
}
};
// Construct and send a custom directive to the connected gadget with data from
// the SetCommandIntent.
const SetCommandIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'SetCommandIntent';
},
handle: function (handlerInput) {
let command = Alexa.getSlotValue(handlerInput.requestEnvelope, 'Command');
if (!command) {
return handlerInput.responseBuilder
.speak(handlerInput.t('REPEAT_COMMANDS_MSG'))
.withShouldEndSession(false)
.getResponse();
}
const attributesManager = handlerInput.attributesManager;
let endpointId = attributesManager.getSessionAttributes().endpointId || [];
let speed = attributesManager.getSessionAttributes().speed || "50";
// Construct the directive with the payload containing the move parameters
let directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
{
type: 'command',
command: command,
speed: speed
});
let speechOutput = handlerInput.t('COMMAND_TEXT') + `${command}` + handlerInput.t('ACTIVATED_TEXT');
return handlerInput.responseBuilder
.speak(speechOutput + randomChoice(AUDIO))
.addDirective(directive)
.getResponse();
}
};
const EventsReceivedRequestHandler = {
// Checks for a valid token and endpoint.
canHandle(handlerInput) {
let { request } = handlerInput.requestEnvelope;
console.log("Inside EventsReceivedRequestHandler");
console.log('Request type: ' + Alexa.getRequestType(handlerInput.requestEnvelope));
if (request.type !== 'CustomInterfaceController.EventsReceived') return false;
const attributesManager = handlerInput.attributesManager;
let sessionAttributes = attributesManager.getSessionAttributes();
let customEvent = request.events[0];
// Validate event token
if (sessionAttributes.token !== request.token) {
console.log("Event token doesn't match. Ignoring this event");
return false;
}
// Validate endpoint
let requestEndpoint = customEvent.endpoint.endpointId;
if (requestEndpoint !== sessionAttributes.endpointId) {
console.log("Event endpoint id doesn't match. Ignoring this event");
return false;
}
return true;
},
handle(handlerInput) {
console.log("== Received Custom Event ==");
let customEvent = handlerInput.requestEnvelope.request.events[0];
let payload = customEvent.payload;
console.log(JSON.stringify(payload));
let name = customEvent.header.name;
let speechOutput;
if (name === 'Proximity') {
let distance = parseInt(payload.distance);
if (distance < 10) {
let speechOutput = handlerInput.t('OBJECT_DETECTED_MSG');
return handlerInput.responseBuilder
.speak(speechOutput, "REPLACE_ALL")
.withShouldEndSession(false)
.getResponse();
}
} else if (name === 'Sentry') {
if ('fire' in payload) {
speechOutput = handlerInput.t('OBJECT_ELIMINATED_MSG');
}
} else if (name === 'Speech') {
speechOutput = payload.speechOut;
} else {
speechOutput = handlerInput.t('UNKNOWN_EVENT_MSG');
}
return handlerInput.responseBuilder
.speak(LAUGH_AUDIO + handlerInput.t(speechOutput), "REPLACE_ALL")
.getResponse();
}
};
const ExpiredRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'CustomInterfaceController.Expired'
},
handle(handlerInput) {
console.log("== Custom Event Expiration Input ==");
// Set the token to track the event handler
const token = handlerInput.requestEnvelope.request.requestId;
Util.putSessionAttribute(handlerInput, 'token', token);
const attributesManager = handlerInput.attributesManager;
let duration = attributesManager.getSessionAttributes().duration || 0;
if (duration > 0) {
Util.putSessionAttribute(handlerInput, 'duration', --duration);
const speechOutput = handlerInput.t(randomChoice(COMMANDS_LIST));
// Extends skill session
return handlerInput.responseBuilder
.addDirective(Util.buildStartEventHandler(token, 60000, {}))
.speak(randomChoice(AUDIO) + speechOutput + randomChoice(AUDIO))
.getResponse();
}
else {
// End skill session
return handlerInput.responseBuilder
.speak(handlerInput.t('GOODBYE_MSG'))
.withShouldEndSession(true)
.getResponse();
}
}
};
// 2. Helper Functions ============================================================================
function randomChoice(array) {
// the argument is an array [] of words or phrases
const i = Math.floor(Math.random() * array.length);
return (array[i]);
}
const LocalisationRequestInterceptor = {
process(handlerInput) {
i18n.init({
lng: handlerInput.requestEnvelope.request.locale,
resources: languageStrings
}).then((t) => {
handlerInput.t = (...args) => t(...args);
});
}
};
// The SkillBuilder acts as the entry point for your skill, routing all request and response
// payloads to the handlers above. Make sure any new handlers or interceptors you've
// defined are included below. The order matters - they're processed top to bottom.
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
SetSpeedIntentHandler,
SetCommandIntentHandler,
TellStoryIntentHandler,
MoveIntentHandler,
EventsReceivedRequestHandler,
ExpiredRequestHandler,
Common.HelpIntentHandler,
Common.CancelAndStopIntentHandler,
Common.SessionEndedRequestHandler,
Common.IntentReflectorHandler, // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers
)
.addRequestInterceptors(
LocalisationRequestInterceptor,
Common.RequestInterceptor,
)
.addErrorHandlers(
Common.ErrorHandler,
)
.lambda();
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* You may not use this file except in compliance with the terms and conditions
* set forth in the accompanying LICENSE.TXT file.
*
* THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH
* RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
* THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
*/
'use strict';
const Https = require('https');
/**
* Build a custom directive payload to the gadget with the specified endpointId
* @param {string} endpointId - the gadget endpoint Id
* @param {string} namespace - the namespace of the skill
* @param {string} name - the name of the skill within the scope of this namespace
* @param {object} payload - the payload data
* @see {@link https://developer.amazon.com/docs/alexa-gadgets-toolkit/send-gadget-custom-directive-from-skill.html#respond}
*/
exports.build = function (endpointId, namespace, name, payload) {
// Construct the custom directive that needs to be sent
// Gadget should declare the capabilities in the discovery response to
// receive the directives under the following namespace.
return {
type: 'CustomInterfaceController.SendDirective',
header: {
name: name,
namespace: namespace
},
endpoint: {
endpointId: endpointId
},
payload
};
};
/**
* A convenience routine to add the a key-value pair to the session attribute.
* @param handlerInput - the handlerInput from Alexa Service
* @param key - the key to be added
* @param value - the value be added
*/
exports.putSessionAttribute = function(handlerInput, key, value) {
const attributesManager = handlerInput.attributesManager;
let sessionAttributes = attributesManager.getSessionAttributes();
sessionAttributes[key] = value;
attributesManager.setSessionAttributes(sessionAttributes);
};
/**
* To get a list of all the gadgets that meet these conditions,
* Call the Endpoint Enumeration API with the apiEndpoint and apiAccessToken to
* retrieve the list of all connected gadgets.
*
* @param {string} apiEndpoint - the Endpoint API url
* @param {string} apiAccessToken - the token from the session object in the Alexa request
* @see {@link https://developer.amazon.com/docs/alexa-gadgets-toolkit/send-gadget-custom-directive-from-skill.html#call-endpoint-enumeration-api}
*/
exports.getConnectedEndpoints = function(apiEndpoint, apiAccessToken) {
// The preceding https:// need to be stripped off before making the call
apiEndpoint = (apiEndpoint || '').replace('https://', '');
return new Promise(((resolve, reject) => {
const options = {
host: apiEndpoint,
path: '/v1/endpoints',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiAccessToken
}
};
const request = Https.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
};
{
"name": "agt-mindstorms",
"version": "1.1.0",
"description": "A sample skill demonstrating how to use AGT with Lego Mindstorms",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Amazon Alexa",
"license": "ISC",
"dependencies": {
"ask-sdk-core": "^2.6.0",
"ask-sdk-model": "^1.18.0",
"aws-sdk": "^2.326.0",
"request": "^2.81.0",
"lodash": "^4.17.11",
"i18next": "^15.0.5"
}
}
Comments