Alexa, Turn on the ThingyStick...
BackgroundMore and more devices are powered by USB, many of these tend to be "dumb" devices without internet connectivity or home automation options (e.g. LED lights), how can we automate or control them remotely? Perhaps a USB supply plugged into a mains switch, that's a bit overkill, especially if we want 4 devices controlled individually!
This project allows you to control the power supply to USB powered devices via the internet, and by using the Tinamous SmartHome Skill for Alexa, you can enable voice control for your dumb USB devices.
Currently their are very few devices on the market to control USB power remotely, when I started this project I didn't find any (in the UK), but a couple have recently appeared as part of multi-gang outlets (yes, the idea started a long time ago, in a galaxy far away), these are not by well known home automation manufacturers, instead by unbranded manufacturers (i.e. ZLD-34UK) so we have the issue of whose device cloud they use, is the data going to China and back, what happens if that manufacturer no longer exists, how secure is it, how usable is the software, will it be in the recycling box next week, and many of the other normal concerns of Internet connected devices, not to mention not being hackable in the same way an open source Arduino powered device can be.
Use CasesExamples of USB powered devices we might wish to control:
- USB powered lights
- Kindle Fire / Chrome cast sticks (esp. in kids rooms to stop them watching TV)
- USB humidifiers
- Echo Dot (make Alexa shut itself down for the night? or just reboot the device)
- Development boards. Need to reboot that project because your codes gone into an infinite loop?
- Devices that are difficult to access but need to be rebooted occasionally (i.e. sensors in the loft).
- Devices installed at client premises where we want to ensure it is powered (by measuring the current consumption and the input voltage)
Simple power control: Internet enabled power switching, either via Alexa voice control or other commands through Tinamous. On and Off.
Smart power control: Many USB lamps have touch controls to switch the lamp on, which means we can't switch the light on remotely, but we can switch it off, and a lot of the time that's all we want (trying to sleep, left a lamp on? Going out, want all the lights switched off?).
However, once we've used Alexa to Turn Off the USB lamp, we then have to ask Alexa to Turn On the lamp before we can then switch it on, that's just silly. With smart power enabled, the off command will turn the lamp power off for a few seconds before restoring power to the device. Enough to turn the lamp off, but also allowing normal operation after.
Timer Automation: Have your devices automatically power down at set times. Kids watching Amazon TV on the fire stick to late? Have the USB supply shut down automatically at 8pm.
Power monitoring: If you're developing USB powered hardware you may well want to know how much current you device is taking, particularly when it is first switches on, or you may like to profile battery pack charging. With the on-board INA219 you can monitor current consumption (I managed about 1kHz sampling with little effort). Voltage drop on USB leads at high current can also be a problem, the INA219 monitors the power into the device so we can warn of low voltage. A terminal block is also provided to allow for higher currents and bigger cables to be used.
Power failure: By using the battery option on the MKR 1000 we can monitor the USB supply voltage and send notifications if the input power has failed. This might be useful for remote (off site) solutions that use USB power but need a bit of extra monitoring, or just as a simple mains power fail detection for your house.
HardwareThis project is fairly simple, an Arduino MKR1000 at the heart, USB power switching using two LM3526M's to provides high side switching and fault detection (low voltage, over current), along with power monitoring (voltage and current) using an INA219, and finally LEDs and switches for local control options.
I had a PCB made at DirtyPCBs.com, you could also send the .brd file off to OSHPark.com to have some made as well. The Arduino socket has pcb pads either side of each pin to allow for hacking. e.g. you could easily add some sensors for environmental conditions, or a small OLED display to show voltage and current.
In the github repository their is a 2 port and 4 port option. Be-careful with the 2 port PCB as I messed up and got the layout for the USB socket wrong (they are back to front - wrong polarity!).
Victory from the jaws of defeat:
As it turns out mounting the USB socked on the back of the board is actually a nice solution and meant the pin connections were correct (however for the 2 port board it also means the silk screen is on the wrong side!). The Arduino with headers in a socket was a bit pushed for space with the height required to get the USB sockets out of the enclosure so it actually worked out better, I decided to re-do the board with sockets, switches and LEDs on the reverse side and to add two extra ports, hence the four port version was created (also, I had the LEDs horribly aligned on the 2 porter, so that got fixed as well!).
Theirs very little stopping this being extended to a 6 or 8 port switcher, although the LEDs and switches might need to be dropped or improved on.
The schematic looks a lot more complex to build that it is. A lot of the resistors are optional. Resistors R23, 19, 27 and 26 are all pull-ups for the switches, likewise R20-22, R14 & R15 are pull-ups for the USB control and fault detection. These can all be done through the INPUT_PULLUP pin mode in the Arduino, however if you wanted to put the Arduino to low power sleep and use interrupts to wake it, you may wish to populate these so they don't float (and bounce around).
I also added optional resistors around the USB D+/D- lines. These can be fitted to tell the device how much power it can use, but for a lot of dumb devices these are ignored anyway. Below only R24 for the LED current limiting is actually needed. R2-5 and R28 are left empty.
The LEDs and switches are also completely optional. If you just want a standalone box that controls USB remotely don't add those parts.
Power Input
This controller can be powered via three options.
The first is the "Internal" option (JP6 pins 1 & 2 connected), USB power is taken from the Arduino's 5V pin (and hence from the Arduino USB connector). However this should only be used for low power loads.
The other options are for external power (JP6 pins 2 & 3 connected), you can then connect 5V via J2 (the onboard USB micro connector), or JP8 (a terminal block). You shouldn't use both options at the same time. The external power is also routed to the Arduino VIn pin so it won't need its own power option as well.
For bonus points, fitting 0R resistors to R10 and R11, as well as J2 gives USB pass through for USB 3 so we can reboot a USB connected device, very handy when developing hardware and you don't want to wear out your USB sockets on the PC!
A 3D printable enclosure is included with this project. It uses M3 heatfit inserts for PCB and lid connections, although the tolerances on the lid are good enough for a friction fit.
The Lid includes a few options.
- With or without battery compartment.
- With or without feet (aka mounting holes to allow the box to be secured to a surface).
Likewise the base box can be configured (using OpenSCAD) to include openings for each of the three power sources.
It took a few goes to get the enclosure right. How do you version your prints? My samples from the Rigid.Ink fan club came in very handy.
We're using the Arduino MKR1000 to control the outlets, so we have WiFi connectivity. If you're new to this board you'll need to add the board option to your Arduino IDE.
We're going to use the Tinamous MQTT server to connect to, mainly because it's awesome, but also, maybe because I'm the founder/developer/tea maker! We'll subscribe to the status post topic for messages sent to the device. (i.e. the "Status.To" topic).
Before starting coding we need to ensure the Arduino has the latest firmware as well as the required SSL certificates to get a secure connection to Tinamous. Obviously if you prefer you could adapt this to your own local MQTT server and not worry so much about security.
Step 1Open the Arduino IDE and load the FirmwareUpdater sketch from the WiFi101 examples menu. Upload this to your device.
Once uploaded select WiFi101 Firmware Updater from the Tools menu.
Test your connection then Update Firmware. Once that's done use the Add domain button and add tinamous.com to ensure the Arduino has the correct SSL certificates in place. Press the Upload Certificates to WiFi module button to upload the certificates.
Step 4Now we can write our own firmware. You'll find the files attached to this project and also in the GitHub repository (GitHub will have the latest version).
We'll use the WiFi101 and MQTT Client to your Arduino sketch.
Select the MQTT by Joel Gaehwiler option.
The file secrets.h needs to be populates with your WiFi and Tinamous MQTT settings, I've not included my copy for obvious reasons.
WiFi and MQTT Server Settings:
#define SECRET_SSID "Your SSID"
#define SECRET_PASS "Your SSIDs Password"
/************************* Tinamous MQTT Setup *********************************/
#define MQTT_SERVER "<tinanamous account name>.tinamous.com"
#define MQTT_SERVERPORT 8883
#define MQTT_USERNAME "UsbSwitch.<tinanamous account name>"
#define MQTT_PASSWORD "Your password goes in here."
#define MQTT_CLIENT_ID "UsbSwitch"
#define DEVICE_USERNAME "UsbSwitch"
If you've not already registered with Tinamous, you can create your own free account here. When you register you are asked for an Account/Organisation name, this becomes your own private area of Tinamous, you can invite other members to that area (including Alexa), and share your devices with your group.
Below I'm calling my account "AlexaExample", this is what I'll need to include in the MQTT setup, and my Tinamous account is at https://AlexaExample.Tinamous.com
Next up, we need to add our Device. On the Tinamous Devices page, click the Add button.
Hence the Tinamous MQTT settings for my device look something like this...
/************************* Tinamous MQTT Setup *********************************/
#define MQTT_SERVER "AlexaExample.tinamous.com"
#define MQTT_SERVERPORT 8883
#define MQTT_USERNAME "UsbSwitch.AlexaExample"
#define MQTT_PASSWORD "My super secret password that totally isn't Passw0rd...."
#define MQTT_CLIENT_ID "UsbSwitch"
#define DEVICE_USERNAME "UsbSwitch"
That's our Tinamous account and device enabled. You can add more devices here if you wish, just update the MQTT settings for the DEVICE_USERNAME and MQTT_USERNAME (MQTT doesn't send header information like http, so Tinamous has no idea which sub-domain you are using, hence we need to specify the account in the username).
Step 6Upload the attached code to your devices (with your updated secrets.h file). Take a moment to look at the TinamousMQTTClient.ino file, this handles our MQTT interactions, and with that the Alexa commands that are sent to our device.
We need to be using the WiFiSSLClient for SSL. If you wish to use a local MQTT server without SSL you can use the regular WiFi Client and drop down to port 1883, but for anything internet based, use the SSL Client.
We also need to reserve a little more than the default buffer for the MQTT client, here we're reserving 4096 bytes.
WiFiSSLClient networkClient;
MQTTClient mqttClient(4096);
We use the mqttClient.begin to set-up the client and specify a function handler in onMessage that is called when a message is received from the MQTT server.
mqttClient.begin(MQTT_SERVER, MQTT_SERVERPORT, networkClient);
// Handle received messages.
mqttClient.onMessage(messageReceived);
And then we can connect and subscribe to the topic's we are interested in. Here you see we've subscribed to "Tinamous/V1/Status.To/UsbSwitch", we'll receive messages send to @UsbSwitch from the Tinamous timeline. This is how we'll get messages from Alexa.
if (!mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
if (mqttClient.lastError() == LWMQTT_CONNECTION_DENIED) {
// This error is because your username or password is wrong
}
if (mqttClient.lastError() == -6) {
// This error is most likely because you didn't add the SSL certificate.
}
// Force a delay before re-trying the connection
delay (10000);
return false;
}
// Successful connection. Now subscribe to the topic
mqttClient.subscribe("/Tinamous/V1/Status.To/" DEVICE_USERNAME);
You can think of the Tinamous timeline like a private version of Twitter for you and your devices, they can use MQTT or the REST API (or one of the bots) to see the messages sent to them and act on them, as well as post messages back.
We've got a little bit more work to do in Tinamous to enable Alexa integration, but for now we can test our device and firmware by using the timeline and sending messages.
If you use the Tinamous SmartHome skill that's all the coding that is needed.
The Tinamous Smart Home Skill for AlexaThe Tinamous Smart Home Skill is currently pending approval to be published (at the time of writing, fingers crossed it's in the store now...). To make your own USB switcher you can just use this Skill when it's available.
The skill is actually very generic, it knows nothing about the devices or how to talk to it. We apply tags to the devices in Tinamous and the skill will create an appropriate device in the Alexa account, hence, you could use this skill and Tinamous to voice enable one of your own projects with just a few lines of code on the device.
However, you may wish to alter things, or write your own skill so I'll share the details of my development.
I wrote the skill in C# for .Net Core 2.0, it was actually developed for my BOFF smart fan project, but for this project I extended it to allow a device to have many outlets (ports) and for each one to be a first class citizen in Alexa Smart Home devices.
All the code (including some tests!) is in the Tinamous SmartHome repository, clone, download or just view as you like. I used Visual Studio 2017 with the AWS tools installed to help push the skill to Lambda.
The framework deserializes the incoming directive message from Alexa into objects that we can access through the code, appropriate actions are taken based on the headers namespace and directive name, and then an appropriate response is returned.
The main messages of interest are:
- Account Linking
This is handled by Alexa for us, after we add the skill to our account, Alexa will request authentication, we are taken to the Tinamous Authorize page to allow for the device to access our account. Here you need to enter your account name (AlexaExample in this case), username (Steve) and password (no, I'm not telling!)
Once your account is linked, Alexa prompts to perform discovery, the skill then queries Tinamous for devices that are tagged with "Alexa.SmartDevice". Devices without this are simply ignored.
These tags are applied by editing the device from the Devices page in Tinamous.
If the device is also tagged with "MultiPort" each port is enumerated and a device is also added for those. We also apply tags based on the Alexa directives our device supports, here it's just "Alexa.PowerController" and also a tag to indicate which category the device should be displayed under in the app, here I've used "SmartPlug".
Other interfaces are available, such as Alexa.BrightnessController, but that's not so useful here. See the repository readme for more details.
For our MultiPort device to expose individual ports to Alexa we need to set-up the State Variables, also on the edit device page.
PortCount indicates the number of ports the device has, then "Port-1".."Port-n" give the names that Alexa will use for the ports. Any port without a name will be ignored. You can easily change the name of the port here and re-run discovery to get Alexa updated.
During discovery, the skill will also look for a field tagged, named or labelled "powerState", or "powerState-port-n" as appropriate. If this field is found it is assigned as a supported capability for the device (more on this in State Report).
During the discover phase we told Alexa what capabilities our device has, the skill defaults to telling Alexa these can be requested, hence Alexa will send a StateReport request to get the values for these.
We have one last set of tags to be applied to support this, this time to the devices fields. Once your device is sending data (That's the senml message that is being pushed across MQTT in the Arduino code), Tinamous will create fields for the device. We can then use the Advanced option from the fields list to edit this. Using the tag option is the most versatile as it means we don't need to get the field name correct in the firmware or stuck if we want to rename it.
If the port specific fields are not found, Alexa will fall back to the non-port specific field (here named powerState).
Power ControlOur device isn't going to be any use in Alexa without this! Alexa will send two directives to our Skill "TurnOn" and "TurnOff". The main function entry point for the skill first looks for the namespace (Alexa.PowerController), then hands the job off to the approriate controller class (PowerController.cs).
The skill then simply publishes a Status Message onto the Tinamous timeline.
For Example:
@UsbSwitch Turn On
or
@UsbSwitch Turn On port-1
The other supported interfaces are handled in an almost identical way. It's then up to our device to watch for this status message and perform an action. Alexa can then read back the state using a StateReport.
That's how the skill works. Now we just need to push it to AWS Lambda and create a Skill entry on the Alexa console to actually give Alexa access to it.
Creating the AWS Lambda function:I used the AWS tools within Visual Studio to push the compiled skill to Lambda. But first we need to create the Lambda.
Pro-tip: Create the Lambda in the appropriate AWS area for the language you are supporting. English (UK) needs to target eu-west (Ireland).
Create a new lambda function from scratch. The existing blueprints are limited and out of date (only supporting V2 of the SmartHome interface which is very different and deprecated - we're using V3).
You'll need to create a new role to allow the Lambda to access the resources it needs. Here we select Simple Microservices as a default (it actually gives way more than we need). If you find you are not getting logs in Cloud Watch you may also need to go and give the role permissions for that though the IAM section.
Then we need to publish the binaries from Visual Studio. With the AWS tools installed, right click on the project and select "Publish to AWS Lambda..."
Then fill out the details for the Lambda expression and hit Upload...
Once uploaded we can run some tests on the Lambda to ensure it runs. Then we need to "Publish new version" from the Actions dropdown.
Once published we need to give our Skill permissions to access this,
Click on the "Alexa Smart Home" trigger and enter the skill id (we don't have that just yet though....)
With our Lambda almost ready to go we need to head on over to the skill developer console and actually create an entry for it. Open up https://developer.amazon.com, select Alexa Skills Kit and add a new Skill.
Select Smart Home Skill API, the language you wish to target (e.g. English (UK) for us in the UK) and select V3 (preferred) payload version.
On the Configuration page we get into the more interesting details. Enter the Lambda ARN from our versioned Lambda (top right of the screen). It should end something like :1 or :2 or :5246 (if you've had a few goes ;-) ).
Whilst in Lambda we can also paste in the "Application ID" or "Skill ID" or "ID" or whatever it's called today from the skill, it should look something like amzn1.ask.skill.2_______________50.
Be sure to click on Save once you've added the Application ID. In the old console you can find the id in the header under the skill name, in the new, erm, open a new window, go back to the console skill list, and click the appropriate link. (it's as if they never used the console to actually make a skill).
To enable account linking we need an OAuth application created at Tinamous, this is done using the Alexa Bot. Head on to your Tinamous account Bots page and add an Alexa Bot. Once you've created that the dialog box will give you all the details you need to configure account linking.
NB: If you're using the (soon to be...) published Tinamous SmartHome skill you don't need an Alexa Bot.
The application created by the bot will allow any other Tinamous account holders to use your skill and link their account. Naturally you don't have to publish your skill and you could keep it private, and they won't be able to see anything in your Tinamous account.
Likewise if you use a different device cloud (seriously, why would you do that ;-) ), then you'll need to enter their OAuth application details.
On the Test page, ensure your skill is set to "Yes" for "Show this skill in the Alexa App".
Save and head on over to alexa.amazon.co.uk (or the one appropriate for your region), or apparently theirs an app as well.....
Click on the "Skills", then top right, "Your Skills", and then "DEV SKILLS", you should see your skill listed with a green marker to indicate it is a development skill.
The "Alexa, turn off the usb light", and additional skill information when you select it is configured on the "Publishing Information" page, you can enter the info during development without having to go for full on publishing.
If you need to update the skill code, upload the new Lambda function, create a new version, re-add the SmartHome trigger and Skill Id, then paste the versioned Lambda function into the skill console (you might be able to use a non-versioned lambda, but it didn't work when I tried - although there were many other things I'd also got wrong at that time).
Success!With our skill code is running in Lambda and the Skill installed in our Alexa account, we can run discovery, and then start controlling the devices.
You can click over to the CloudWatch logs to see the log information written by your skill.
Skill Debugging & TipsAlexa provides next to no developer feedback when things go wrong, you can spend ages guessing why Alexa doesn't do as you hoped.
- Avoid most things other than alpha-numerics in your endpointID's (I used * at one stage and everything broke, but not in an obvious way, however # was fine. Go figure!).
- Log everything. Check for logs when you've invoked your skill. No log then it's probably authentication, or your skill isn't authorized for the Lambda expression.
- Use matching AWS and Alexa email accounts.
- Keep the Lambda in the same region as the skill (Ireland for UK skills).
- If your skill is invoked but Alexa isn't responding to it (i.e. not listing devices), your response format is probably wrong.
- If you don't want to use your day to day Alexa account you can use Amazon households to add a second adult account. Note however this appears to be limited to 2 adults, and you can't change it without an epic delay.
- You can ask "Alexa, Switch Profiles" to switch between your developer and regular profiles.
- I hope with the redesign of the Alexa Console some better debugging information will be available. However right now all I see is bigger boxes and a little better validation. Some logs are available but they are just success logs. aka management level feel good metrics, and delayed by 36 hours which isn't helpful for debugging!
With the Tinamous SmartHome skill, as long as your (Internet of Things) thing can connect to the Tinamous MQTT server (or is connected via a supported bot) adding Alexa SmartHome control to your thing is simply a few lines of code to handle messages like "Turn On", "Turn Off", "Set brightness 20". Just add the tags in Tinamous, and....
"Alexa, Discover Smart Home Devices".
Comments