The Amazon Echo and the Alexa assistant are amazing innovations that enable many daily life interactions. Already incorporated in my morning routine, one of the first things I do when I wake up is ask Alexa about the current weather. Now that winter is coming, I usually do it from under my blankets. Before getting out of bed I also want to know what is the temperature in my apartment so I know how to face it.
I live in an older apartment building where smart thermostats are out of the question. My main baseboard heaters are controlled by old-school thermostats but I have an additional radiator connected to a smart plug (TP-Link) that I can turn on and off using Alexa. I still needed to know how cold is it before deciding whether I want to turn it on and stay a little longer in bed.
SolutionThe solution to my problem was to plug a USB thermometer (TEMPer) to an extra Raspberry Pi I had lying around and have it talk to Alexa. I couldn't find any general purpose projects so I decided to attempt mine. The idea is quite simple, an API receives messages (such as current temperature as recorded by the Raspberry Pi) and stores them. Then Alexa can access the stored messages and read them aloud. When I first heard about the daily briefing API I was really excited about being able to incorporate these as part of the daily briefing but currently that is not yet possible.
The API is already publicly available and I plan on extending it soon. Here is a demo console that can be used to interact with the API or to send yourself reminders and other personal messages:
https://s3.amazonaws.com/aws-website-textconsole-a3cnv/messages.html
You can enable the skill here:
Temperature MonitorTo replicate my setup:
- Enable the skill and navigate to the Alexa app at http://alexa.amazon.com to get your user identifier and secret. Setup your Raspberry Pi and get your USB thermometer working. In my case I am using this library: https://github.com/padelt/temper-python
- Check the code repository for two examples in Python and Bash for scripts that poll the current temperature and post it to the API (both tested in the current Raspbian).
- Replace the user identifier and secret in either script and add your scripts to crontab.
Someone asked me if it would be possible to integrate this with Slack. There are definitely multiple ways of doing so. I opted for an easy approach, all server side. To integrate with Slack, I choose to allow users in a team to add their Alexa accounts to the team (it could be in a per-channel basis as well, just not there yet). Then, anybody can post to all the registered message boards using a slack command from any channel in a team. To enable Slack integration:
- First create two slash commands in Slack (this is needed only once per team). Click in the dropdown next to your team name and select "Apps & integrations", then the "Manage" tab in the top, then "Custom Integrations" tab in the left, then "Slash Commands".
- Click "Add Configuration". In the configuration screen, set the Command to
/postmb
, set the URL tohttps://l7kjk6dx49.execute-api.us-east-1.amazonaws.com/prod/postedmessage/slack
and set the Method toPOST
. The rest of the settings are optional. Click "Save Integration".
- Click "Add Configuration" again. Use the same URL and Method but change the command to
/setupmb
. Click "Save Integration".
- The integration is complete. At this point, any user in the team that has an Alexa message board, can go to their direct messages (with themselves) and proceed to authenticate their account. Just use
/setupmb userId:secret
(copy and paste from the Alexa app at http://alexa.amazon.com).
- Now, any user in any channel can use
/postmb message
to post a message to all other users message boards (use this to add a reminder to everyone in the team!). If you have further ideas or requests, don't hesitate to contact me!
If you want to add the posted messages to your flash briefing, currently you need to host your own code (see linked repository) add your own skill so you can generate your own feed. I am hoping this will change in future revisions of the API.
- From messages_v1.py, replace the user identifier with your user identifier
- Create a new AWS Lambda and paste the code.
- When asked for triggers, select API Gateway
- In the API Gateway, make sure that your action and resource is available without authentication
- Remember to deploy your API and check that the URL given returns a JSON without errors
- In the Alexa Skils Kit, create a new flash briefing skill and use the URL from the API gateway
- In the Alexa app, Skills/Your skills section, enable the new skill
- In the Alexa app, Settings/My account/Flash briefing, enable your skill and set it's order
- Note that you don't need to submit your skill for certification for it to work with your own account
The posting, Slack and feed endpoints use Amazon's API Gateway as triggers to the Lambda code.
All the logic is handled by around 700 lines of Python code available in the linked repository (specifically https://github.com/josepvalls/ask.py/blob/master/messages_v1.py).
Voice User Interface (VUI)The voice interface for the skill is rather simple. The following diagram describes the interaction:
Internally, the skill uses my single file template for Alexa skills (available in the linked repository and here). The template facilitates the implementation of a simple finite state machine that I use for some of my more complex skills. This is an excerpt of the finite state machine used to manage the purge and reset interactions:
This FSM can be defined with a few lines of code:
[
['reading', 'do_purge', 'do_purge_confirm', 'purge'],
['reading', 'do_reset', 'do_reset_confirm', 'reset'],
['reset', 'do_yes', 'do_reset', 'extra_help'],
['reset', 'do_no', 'do_ok', 'reading'],
['purge', 'do_yes', 'do_purge', 'reading'],
['purge', 'do_no', 'do_ok', 'reading'],
['extra_help', 'do_yes', 'do_help', 'reading'],
['extra_help', 'do_no', 'do_ok', 'reading'],
]
In each of the lists, the first element is the state, the second is the input/trigger, the third is the action/output that will be executed and the fourth is the new state. Intents are mapped to input/triggers in a simple dictionary:
return {
'IntentRequest.ReadIntent': 'do_read',
'IntentRequest.ResetIntent': 'do_reset',
'IntentRequest.PurgeIntent': 'do_purge',
'IntentRequest.AMAZON.YesIntent': 'do_yes',
'IntentRequest.AMAZON.NoIntent': 'do_no',
}
And actions/output defined as simple functions:
def do_reset(self, args=None):
# will be executed when ResetIntent is followed by
# reset the secret here...
return self.response("Reset", "Secret was reset, do you need help?")
def do_reset_confirm(self, args=None):
return self.response("Reset", "Are you sure you want to reset your secret?")
def do_ok(self, args=None):
self.finish_session()
return self.response("Ok", "Ok.")
Comments