It has been about a year since I got certified on Android. But since I don't do much android at work I was looking for a project that I could try all kinds of stuff. I mean crazy stuff. A project to get dirty, fail, fail more, and learn from those failures.
It was about 6 months ago that I saw the smart mirror from Max Braun and caught my attention. After that I started researching more about smart mirrors and found other projects like the one from Evan Cohen. But it wasn't until I saw A Day Made In Glass that I felt so inspired that decided to try mu luck creating one. Not building, creating from nothing and it has been 6 months and here is the second iteration of that inspiration.
Here is my Another Smart Mirror project version 2.
Step 1: AWS Security ProfileFirst we login to the developer console located at https://developer.amazon.com/iba-sp/overview.html.
We click on the Create a New Security Profile button and fill out the information. When finished click Save.
Once this security profile has been created, write down the Client ID and Client Secret, because we will need it later.
Also under the Android/Kindle Settings tab, we click the Add an API Key. Follow the instructions but for Package the value would be com.vaporwarecorp.mirror. If you are also using the debug keystore included in the project then the signature value would be B1:36:DC:D5:55:BB:11:20:48:5C:A5:FA:60:BB:C0:D5.
After that click the link under Key that says Show and a pop up will display.
Save this key inside a file named api_key.txt
under the app/src/main/assets
directory
Now login to create an IOT thing at https://console.aws.amazon.com/iot/home.
From the home page, click the Create a thing button and enter a name for your thing.
After that click the Create a certificate button and click the 1-Click certificate create button too.
Then we proceed to click on the Create a policy button and fill out values.
Now we will attach the policy to the certificate. Select the checkbox on the certificate that we just created and click on the Actions dropdown. You will get a list of actions where you will click on Attach a policy.
A popup will display were we enter the name of the policy that we just created and click Attach.
With this we finished setting up the IOT side of the project. Now time to create our Lambda.
Step 3: AWS CognitoLet's login into AWS cognito at https://console.aws.amazon.com/cognito and click on Manage Federated Identities.
Then we click the Create new identity pool button.
We'll get the getting started wizard. Enter a name for your pool, select Enable access to unauthenticated identities and click the Create Pool button.
Here Cognito will ask you permission to create a new IAM role. Click the Allow button to continue.
And you will get this confirmation screen. Please write down the identity pool ID, because it's going to be need in Step 6.
Let's login into the Alexa developer console at https://developer.amazon.com/edw/home.html and click on the Get Started button for Alexa Skill kit.
Then click on the Add a New Skill button.
Enter a name for you skill, select Smart Home Skill API for skill type and click the Next button.
Then the next screen nothing needs to be done, so we click the Next button.
Here we are going to pause, continue with step 4 to be able to get the Lambda ARN and fill it out in this form. The Client ID and Client Secret are those that can be found back at step 1 figure 3.
After filling the required information in configuration, click the Next button and this will be displayed. Since we want to use this skill we just click Next again.
The following 2 screens you just need to fill out in case you want to publish your skill.
And that's it for the Alexa Home Skill Creation. Now we create the Lambda.
Step 5: AWS LambdaLet's login on the Lambda console at https://console.aws.amazon.com/lambda/home and click on the Create a Lambda function button.
The Select blueprint screen gets displayed. On the search box we enter alexa-smart and select the alexa-smart-home-skill-adapter.
Here we are going to enter the application ID for our Alexa Smart Home Skill that can be found at step 3 by going back to Skill Information (Figure 19) and then we click the Next button.
Here we start to configure the Lambda. We enter a name for the Lambda and select Node js 4.3 as the Runtime.
In the Lambda function code, we paste the code found at https://github.com/jreyes/mirrror-aws-lambda. Remember to replace your IOT_ENDPOINT and IOT_TOPIC with the values that we got from Step 2.
const IOT_ENDPOINT = 'YOUR_IOT_ENDPOINT';
const IOT_TOPIC = 'YOUR_IOT_TOPIC';
const IOT_COMMANDS = [
createCommand('e219f5e9-2d58-4fde-807b-cefec4dc4900', 'home'),
createCommand('e219f5e9-2d58-4fde-807b-cefec4dc4901', 'c. b. s.'),
createCommand('e219f5e9-2d58-4fde-807b-cefec4dc4902', 'connect to the internet'),
createCommand('e219f5e9-2d58-4fde-807b-cefec4dc4903', 'x. k. c. d.'),
createCommand('e219f5e9-2d58-4fde-807b-cefec4dc4904', 'display my flickr stream'),
createCommand('e219f5e9-2d58-4fde-807b-cefec4dc4905', 'miku time'),
createCommand('e219f5e9-2d58-4fde-807b-cefec4dc4906', 'new music releases')
];
var AWS = require('aws-sdk');
var iotdata = new AWS.IotData({endpoint: IOT_ENDPOINT});
/** * Main entry point. */
exports.handler = function (event, context) {
switch (event.header.namespace) {
/** * The namespace of "Discovery" indicates a request is being made to the lambda for * discovering all appliances associated with the customer's appliance cloud account. * can use the accessToken that is made available as part of the payload to determine * the customer. */
case 'Alexa.ConnectedHome.Discovery':
handleDiscovery(event, context);
break;
/** * The namespace of "Control" indicates a request is being made to us to turn a * given device on, off or brighten. This message comes with the "appliance" * parameter which indicates the appliance that needs to be acted on. */
case 'Alexa.ConnectedHome.Control':
handleControl(event, context);
break;
/** * We received an unexpected message */
default:
log('Err', 'No supported namespace: ' + event.header.namespace);
context.fail('Something went wrong');
break;
}
};
/** * This method is invoked when we receive a "Discovery" message from Alexa Smart Home Skill. * We are expected to respond back with a list of appliances that we have discovered for a given * customer. */function handleDiscovery(event, context) {
var messageId = event.header.messageId;
if (event.header.name != 'DiscoverAppliancesRequest') {
context.fail(generateControlError('DiscoverAppliancesRequest', messageId, 'UNSUPPORTED_OPERATION', 'Unrecognized operation'));
return;
}
var headers = {
namespace: 'Alexa.ConnectedHome.Discovery',
name: 'DiscoverAppliancesResponse',
payloadVersion: '2'
};
var payloads = {
discoveredAppliances: IOT_COMMANDS
};
var result = {
header: headers,
payload: payloads
};
log('Discovery', result);
context.succeed(result);
}
/** * Control events are processed here. * This is called when Alexa requests an action (IE turn off appliance). */function handleControl(event, context) {
var messageId = event.header.messageId;
if (event.header.name !== 'TurnOnRequest') {
context.fail(generateControlError('TurnOnRequest', messageId, 'UNSUPPORTED_OPERATION', 'Unrecognized operation'));
} else {
api(event.payload.appliance.applianceId, messageId, context);
}
}
function createCommand(applianceId, command) {
return {
applianceId: applianceId,
manufacturerName: 'VaporwareCorp',
modelName: 'ST01',
version: 'VER01',
friendlyName: command,
friendlyDescription: command + " command",
isReachable: true,
actions: ['turnOn']
};
}
function api(applianceId, messageId, context) {
var command = null;
for (var i in IOT_COMMANDS) {
if (IOT_COMMANDS[i].applianceId === applianceId) {
command = IOT_COMMANDS[i].friendlyName;
}
}
var payload = {
command: command,
state: {}
};
var params = {
topic: IOT_TOPIC,
payload: JSON.stringify(payload),
qos: 0
};
log("api", params);
iotdata.publish(params, function (err, data) {
if (err) { // an error occurred
log("Publish Error", err.stack);
context.fail(generateControlError('TurnOnRequest', messageId, 'DEPENDENT_SERVICE_UNAVAILABLE', 'Unable to connect to server'));
} else { // successful response
log("Publish Success", data);
context.succeed(generateControlSuccess(messageId));
}
});
}
function log(title, msg) {
console.log('*** ' + title + ' : ' + JSON.stringify(msg));
}
function generateControlSuccess(messageId) {
var headers = {
namespace: 'Alexa.ConnectedHome.Control',
name: 'TurnOnConfirmation',
payloadVersion: '2',
messageId: messageId
};
var payloads = {
success: true
};
return {
header: headers,
payload: payloads
};
}
function generateControlError(name, messageId, code, description) {
var headers = {
namespace: 'Alexa.ConnectedHome.Control',
name: name,
payloadVersion: '2',
messageId: messageId
};
var payload = {
exception: {
code: code,
description: description
}
};
return {
header: headers,
payload: payload
};
}
The rest of the page can be left as it is. Click the Next button to continue.
The page displayed now is the Review page for the Lambda. If everything looks good then click the Create function button.
And that's it for Amazon! Now let's build and configure the application.
Step 6: Another Smart Mirror appThe following steps starts with the assumption that you have android tools, java, and git installed in your machine and your device is connected to your machine in development mode.
We start by checking out the code from github:
git clone https://github.com/jreyes/mirror.git
After that we go into the directory where the code is found and we build the code. Before building don't forget to add your api_key.txt
file to app/src/main/assets
that you got from Step 1 figure 5.
gradlew build
After it has finished building, now we are going to deploy it to Android.
adb install app/build/outputs/apk/app-debug.apk
After it has finished installing and loading, in your local browser go to http://your-droid-ip:8080/
This address would load the configuration screen for the application. Select Alexa Configuration.
In this screen you would enter your Cognito Pool ID, Your IOT endpoint and your IOT topic. After filling these values click the Next button.
After that, you can start asking the smart mirror by speaking the keyword "Alexa".
The frame would be left up to you guys, since in my case the display was really big and wanted to keep it next to me for development, I just send it to be framed with a simple "L" shaped frame. This is so the frame can grab the IR frame and the TV together.
And of course thanks to the people, projects, and ideas that inspired me to create this.
Errata- On Step 5 there was an instruction referring to Figure 14 instead of 19. Thanks to Ajay Menon for spotting this error.
Comments