Buy some stuff on Amazon by clicking a pushbutton connected to your WiFi101 enabled Arduino. It's like a Dash button, but cooler!
MotivationBack in the Spring of 2015 Amazon released the Dash Button to help facilitate frictionless product purchases with just the click of a button! For example this dash button ensures my pups insatiable appetite for Greenies dog treats is always well served and my pantry never runs low! You register the button to your amazon account and when you're about to run out you press the button, a couple days later voilá treats at your doorstep! Cool.
Then for the developer community Amazon released the AWS IoT button!
It's possibilities are endless! Amazon describes the AWS IoT Button as...
"...a programmable button based on the Amazon Dash Button hardware. This simple Wi-Fi device is easy to configure and designed for developers to get started with AWS IoT, AWS Lambda, Amazon DynamoDB, Amazon SNS, and many other Amazon Web Services without writing device-specific code."
This is great if you're a web savvy developer comfortable with AWS or are looking to learn more about the IoT services Amazon is now supporting. Unfortunately this boxes out us hardware hackers! Where's my I/O? What if mildly "device-specific code" is sort of your thing? Sure you could hack open a Dash Button and dive headfirst into some "bare metal" dash embedded dev like the talented folks at Adafruit have documented for you. But if you're still building your chops on Arduino and aren't quite ready to dive into hardware abstraction layers and shift registers you're still out of luck. Until now!
Amazon has released the Dash Replenishment API for device manufacturers and developers!
The good news... now we can create hardware devices that can initiate frictionless purchases all on their own! This means our coffee makers can purchase filters for us before we run out, or our laundry machines can order detergent based off of usage statistics. It's now up to us to build these creative frictionless purchasing devices.
The bad news... communicating directly between the Arduino and the Dash API involves OAuth2.0 handshakes, building POST requests, parsing JSON responses and other non-trivial tasks to be handled in a single Arduino sketch.
So to lower the barrier to entry for Arduino DRS hackers I've abstracted these boring details out and into the AmazonDRS Arduino Library. This way you can continue to focus on creating unique purchasing actuators(buttons are boring) and spend less time concatenating strings and exchanging tokens! With this amazonDashButton example sketch you can start purchasing items on Amazon after editing only a handful of lines of code.
requestReplenishmentForSlot(slotId); //It's that easy
Let's walk through getting all set up and get you ordering all your favorite vices on Amazon automatically!
Getting StartedHardwareI've decided to use the Arduino MKR1000 as the hardware platform for this project, for a few reasons...
- Similarly sized form factor to dash button.
- 100% Arduino IDE compatible.
- Utilizes the Atmel ATWINC1500 WiFi Module(TLS capable w/ onboard SHA-256 encryption).
- ARM SAMD21 Cortex-M0 (256KB of Flash : ) ).
- LiPo Battery JST plug for portability.
That being said this library should work well with any ATWINC1500 WiFi enabled Arduino that uses the WiFi 101 library. Other options could include an Arduino Zero or Due sporting the WiFi101 shield, an Adafruit MO WiFi Feather, or really any Arduino with sufficient space, and Atmel's ATWINC1500 WiFi module.
Here's what you'll need...
The battery is of course optional and the resistor can be of any value really. We're just using it to pull down one of the push button pins to ground. The small push button will have 4 pins that are organized into two pairs. You'll want to bridge the gap in the breadboard by placing the button so that the longer gap between pins is utilized to span the space between the two sides of the breadboard. Then wire up the breadboard like so...
Any digital I/O pin will do for the pushbutton. Just remember to set
const int dashButton = 14; //DIO number of the pushbutton pin
to whichever pin you end up choosing. I've used jumper cables and a smaller breadboard so my final configuration looks like this...
If you feel like making this a bit more portable you can grab a prototype board, and a header plug to create a sort of push button shield for the MKR1000.
The initial setup procedure and configuration does involve a good amount of steps but once you are set up and configured the development process becomes that much easier. I've written a full fledged getting started guide in the readme/wiki pages located at the AmazonDRS GitHub repo which I'll paraphrase in this section. If you haven't set up "Login with Amazon", AWS SNS, your dash device, or stepped through the authCodeGrant example sketch head over to the repo wiki and follow along. By the time you come back you should have...
- Imported the AmazonDRS library into your Arduino IDE, as well as the Arduino Wifi101 and ArduinoJson libraries.
- Created your LWA Security Profile, created a Dash Replenishment Device, and your Amazon Web Services Simple Notification Service configuration.
- Completed the LWA Authorization Code Grant process and exchanged your auth_code for your refresh token by running the authCodeGrant example sketch.
- Updated the AmazonTokens.h header file in your AmazonDRS library 'src' directory with values for...client id, client secret, refresh token, and redirect uri.
If you've made it this far you're ready to test your new Arduino dash button! Let's take a look at the sketch in detail.
amazonDashButton#include "AmazonDRS.h"
AmazonDRS DRS = AmazonDRS();
//WiFi creds -----------------------------------------------------------------
char ssid[] = ""; // your network SSID (name)
char pass[] = ""; // your network password
//----------------------------------------------------------------------------
#define slotNumber 1 //dash buttons typically only serve one product/slot
const int dashButton = 14; //DIO number of the pushbutton pin
static long buttonHigh = 0; //millis of last button push for switch debounce
static String slotStatus = "";//boolean if slot is available for replenishment
static String slotId = ""; //unique slot id
void setup() {
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
pinMode(dashButton, INPUT);
//Start up DRS
DRS.begin(ssid,pass);
//initialize slots
DRS.retrieveSubscriptionInfo(); //check slot statuses
slotStatus = DRS.getSlotStatus(slotNumber);
slotId = DRS.getSlotId(slotNumber);
}
void loop() {
//Check for button push on the arduino dash button
//if the slot status is true proceed to request replenishment for the associated slot
if (buttonPushed())
{
//Check if slot is available, if so replenish
if(slotStatus == "true") //if the product in slot are available
{
//we have a match! replenish the products associated with that slot!
DRS.requestReplenishmentForSlot(slotId);
}
else
{
Serial.print("Sorry, slot ");
Serial.print(slotId);
Serial.println(" is not available at this time");
}
}
}
bool buttonPushed(void)
{
int buttonState = digitalRead(dashButton);
if(buttonState && ((millis() - buttonHigh) > 5000))
{
buttonHigh = millis();
Serial.println("Button pressed!!");
return true;
}
else
{
return false;
}
}
The sketch starts out by including our libraries header file and instantiating our DRS object which we'll use to access the DRS API endpoints exposed by the library. The first lines you'll need to edit are the WiFi SSID and password.
//WiFi creds -----------------------------------------------------------------
char ssid[] = "yourSSIDhere"; // your network SSID (name)
char pass[] = "yourPasswordHere"; // your network password
//----------------------------------------------------------------------------
Fill in these values so we can initialize DRS and connect our button to WiFi. Next we'll want to take note of some constants and global variables.
#define slotNumber 1 //dash buttons typically only serve one product/slot
SlotNumber refers to the number representing the slot in your Dash Replenishment Device that you created earlier on. You may have created multiple slots for the device, currently this sketch is only configured to purchase one item from one slot. (Just like a dash button).
const int dashButton = 14; //DIO number of the pushbutton pin
static long buttonHigh = 0; //millis of last button push for switch debounce
These variables are used to handle details around the button push. Be sure to set dashButton = to whichever digital I/O pin you've decided to connect to your push button.
ButtonHigh is a sort of flag thats sole purpose is to prevent you from overloading the sketch/API with a burst of subsequent purchase requests. Switches can send some mixed signals when switching from pressed to released and vice versa. This just prevents those fluctuations from being processed as additional requests to purchase. You'll notice once the button press is registered it takes about 5 seconds for the switch to respond again. That magic happens here in the buttonPushed() function.
if(buttonState && ((millis() - buttonHigh) > 5000))
Check out this great article on switch debounce if for some reason this topic really gets your juices flowing. The author does a great job of explaining this topic in detail and suggests a much more elegant software debounce solution that would come in handy for applications that require more frequent button pushes.
static String slotStatus = "";//boolean if slot is available for replenishment
static String slotId = ""; //unique slot id
SlotStatus and SlotId will store the information contained in the response of...
DRS.retrieveSubscriptionInfo(); //check slot statuses
This method is responsible for carrying out the /subscriptionInfo API endpoint. It'll return to us and store the slotId and slotStatus for the slotNumber we requested.
slotStatus = DRS.getSlotStatus(slotNumber);
slotId = DRS.getSlotId(slotNumber);
If for whatever reason that product isn't available our sketch will now be able to let us know. We also now possess the slotId which we'll need to pass to...
DRS.requestReplenishmentForSlot(slotId);
in order to place your order. If all goes well you'll receive an OrderPlacedNotification and an e-mail alerting your to the purchase. Any subsequent requests for replenishment will return an OrderInProgress response.
Ok, so burn this sketch on over to your Arduino and open up a serial terminal! Don't forget to set the baud rate to 115200. Give it a moment to connect to the network and update the status of your devices slots. Then go ahed... push the button... do it!
Don't worry about actually purchasing something and having to cancel the order. Back when you created the "Login with Amazon" consent request we tagged the device as a test device. So we'll still receive purchase notifications as if the product was bought, but that's it. If you get a shipment notification you might want to back track!(and expect a surprise gift in a ~2days)
Yay!You've done it! You've just initiated a purchase of a product on Amazon by pressing a pushbutton connected to an Arduino! This is great! But if you're like me this will start to get your mind racing on how else you can creatively "Push" the button and order things on Amazon.
Need some more inspiration? There are a bunch of great ideas bouncing around the Amazon DRS Developer Challenge. Also stay tuned for another project write up I'm working on which incorporates NFC! You can take a sneak peak by checking out the amazonDashNfc example sketch.
If you have any questions feel free to drop a line in the comments and I'll do my best to help out!
Enjoy!
Comments