claude garrett
Published

Dash Lid

The Dash Lid is an easy to use, low friction replenishment device. You just use it like a lid.

IntermediateFull instructions provided6 hours4,036
Dash Lid

Things used in this project

Hardware components

Arduino MKR1000
Arduino MKR1000
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
Adafruit 3.7V LiPo Battery
×1

Software apps and online services

Visual Studio 2015
Microsoft Visual Studio 2015
Arduino IDE
Arduino IDE

Story

Read more

Schematics

DashLid Schematic

Dashlid schematic eoy6akpqfl

Code

Visual Studio DashLid Client Solution

C#
This code is run to setup the DashLid Device.
No preview (download only).

Visual Studio DashLid Client Code

C#
Used to set up the Dash Lid
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using RestSharp;
using System.IO.Ports;

//Watin problems?
//Add reference to Interop.SHDocVw
//Set CopyLocal to true, or copy the dll into the Release/Debug folders

namespace DRS
{
    public partial class SetupForm : Form
    {
        SerialPort serialPort;
        string returnURL;
        string code;
        Tokens tokens;
        string wifiPassword;
        string wifiSsid;

        //Enter your client info here.
        //Go to https://developer.amazon.com/iba-sp/overview.html -> APPS & SERVICES -> Security Profile (in sub-header) and choose your security profile.
        const string client_id = "";
        const string client_secret = "";
        const string slot_id = ""; //APPS & SERVICES -> Dash Replenishment Service  (sub-header)

        DeviceData deviceData;
        DeviceSpecifications deviceSpecifications;
        string URL;
        byte replenishHour;

        public SetupForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //Save the settings from the form
            replenishHour = (Byte) cbRefreshHour.SelectedIndex;
            wifiSsid = tbSSID.Text;
            wifiPassword = tbPassword.Text;

            GetDRSDeviceInfo();
            BuildURL();
            UseWatinBrowser();
            ExtractCodeFromReturnURL();
            ObtainDRSTokens();
            SendDeviceInfo();
            ReadDeviceDebuggingInfo();
        }

        private void GetDRSDeviceInfo()
        {
            while (SerialPort.GetPortNames().Count() == 0); //Wait for a COM port to appear - when MKR1000 is connected
            string[] ports = SerialPort.GetPortNames();
            string port = ports[0];
            
            Console.WriteLine("Opening port " + port);

            serialPort = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
            serialPort.Open();
            string deviceInfo = serialPort.ReadLine();
            System.Diagnostics.Debug.WriteLine(deviceInfo);
            deviceSpecifications = Json.JsonParser.Deserialize<DeviceSpecifications>(deviceInfo);
        }

        private void BuildURL()
        {
            string scopeData = "{\"dash:replenish\":{\"device_model\":\"" + deviceSpecifications.model + "\",\"serial\":\"" + deviceSpecifications.serial + "\",\"is_test_device\":\"true\"}}";
            string urlEncodedScopeData = WebUtility.UrlEncode(scopeData); 
            URL = "https://www.amazon.com/ap/oa?client_id=" + client_id + "&scope=dash%3Areplenish&scope_data=" + urlEncodedScopeData + "&response_type=code&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback";   
        }

        private void UseWatinBrowser()
        {
            //Check url until the code is returned
            WatiN.Core.IE ie = new WatiN.Core.IE(URL);
            bool OkToContinue = true;
            while (OkToContinue)
            {
                string currentURL = ie.Url;
                System.Diagnostics.Debug.WriteLine(currentURL);
                if (currentURL.Contains("code="))
                {
                    returnURL = currentURL;
                    OkToContinue = false;
                    ie.ForceClose();
                }
                else
                    System.Threading.Thread.Sleep(1000);
            }
        }

        private void ExtractCodeFromReturnURL()
        {
            //returnURL example: "https://app.getpostman.com/oauth2/callback?code=cccccccooooooooodddddddeeeeee&scope=dash%3Areplenish";
            int startString = returnURL.IndexOf("?code") + 6;
            int endString = returnURL.IndexOf("&scope");
            code = returnURL.Substring(startString, endString - startString);
            //System.Diagnostics.Debug.WriteLine(code);
        }

        private void ObtainDRSTokens()
        {
            var client = new RestClient("https://api.amazon.com/auth/o2/token");
            var request = new RestRequest(Method.POST);
            request.AddHeader("cache-control", "no-cache");
            request.AddHeader("content-type", "application/x-www-form-urlencoded");
            request.AddParameter("application/x-www-form-urlencoded", "grant_type=authorization_code&code=" + code + "&client_id=" + client_id + "&client_secret=" + client_secret + "&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback", ParameterType.RequestBody);
            IRestResponse response = client.Execute(request);

            //System.Diagnostics.Debug.WriteLine(response.Content);
            tokens = Json.JsonParser.Deserialize<Tokens>(response.Content);
        }

        private void SendDeviceInfo()
        {
            deviceData = new DeviceData();
            deviceData.AccessToken = tokens.access_token;
            deviceData.RefreshToken = tokens.refresh_token;
            deviceData.WifiPassword = wifiPassword;
            deviceData.WifiSsid = wifiSsid;
            deviceData.ClientId = client_id;
            deviceData.ClientSecret = client_secret;
            deviceData.SlotId = slot_id;
            deviceData.ReplenishHour = replenishHour;

            DateTime dateTime = System.DateTime.Now;
            deviceData.Year = (byte)(dateTime.Year - 2000);
            deviceData.Month = (byte)dateTime.Month;
            deviceData.Day = (byte)dateTime.Day;
            deviceData.Hour = (byte)dateTime.Hour;
            deviceData.Minute = (byte)dateTime.Minute;
            deviceData.Second = (byte)dateTime.Second;
            string json = Json.JsonParser.Serialize<DeviceData>(deviceData);
            System.Diagnostics.Debug.WriteLine(json);
            serialPort.WriteLine(json);
        }


        private void ReadDeviceDebuggingInfo()
        {
            while (true)
            {
                if (serialPort.BytesToRead > 0)
                {
                    System.Diagnostics.Debug.WriteLine(serialPort.ReadLine());
                }
            }
        }


        // FIN
























        private void TestSendingDeviceInfo()
        {
            //SerialPort testPort = new SerialPort("COM5", 9600, Parity.None, 8, StopBits.One);
            //testPort.Open();
            //string line = testPort.ReadLine();
            //System.Diagnostics.Debug.WriteLine(line);

            deviceData = new DeviceData();
            deviceData.AccessToken = "Atza|testAccessToken";
            deviceData.RefreshToken = "Atzr|testRefreshToken";
            deviceData.WifiPassword = wifiPassword;
            deviceData.WifiSsid = wifiSsid;
            deviceData.ClientId = client_id;
            deviceData.ClientSecret = client_secret;
            deviceData.SlotId = slot_id;
            deviceData.ReplenishHour = 3;

            DateTime dateTime = System.DateTime.Now;
            deviceData.Year = (byte)(dateTime.Year - 2000);
            deviceData.Month = (byte)dateTime.Month;
            deviceData.Day = (byte)dateTime.Day;
            deviceData.Hour = (byte)dateTime.Hour;
            deviceData.Minute = (byte)dateTime.Minute;
            deviceData.Second = (byte)dateTime.Second;
            string json = Json.JsonParser.Serialize<DeviceData>(deviceData);
            //testPort.WriteLine(json);
        }




        private void ParseTokensTest()
        {
            string tokens = "{\"access_token\":\"Atza|testAccessToken\",\"refresh_token\":\"Atzr|testRefreshToken\",\"token_type\":\"bearer\",\"expires_in\":3585}";
            System.Diagnostics.Debug.WriteLine(tokens);
            Tokens t = Json.JsonParser.Deserialize<Tokens>(tokens);
        }

        private void flowLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void label3_Click(object sender, EventArgs e)
        {

        }
    }
}

Arduino Code Files

Arduino
MKR1000 Code
No preview (download only).

Arduino Code for DashLid

Arduino
DashLid Code
#include <ArduinoJson.h>
#include <RTCZero.h>
#include "AmazonDRS.h"

//JSON Parsing -------------------------------------------------------------------------------
StaticJsonBuffer<2000> jsonBuffer;
String readString;
//--------------------------------------------------------------------------------------------

//DRS ----------------------------------------------------
//WiFi creds ----------------------------------------------------------------------------------
//char ssid[] = ""; //  your network SSID (name)
//char pass[] = ""; // your network password (use for WPA, or use as key for WEP)
//------------------------------------------------------------------------------------------------------

#define slotNumber 1 //This will vary for multi slot devices - dash buttons typically only serve one product/slot

const int dashButton = 5;     //DIO number of the pushbutton pin
static long buttonHigh = 0;    //millis of last button push for switch debouncing
static String slotStatus = ""; //boolean which depicts if slot is available for replenishment
static String slotId = "";     //unique slot id ex: 0a5038b7-7609-4b81-b87e-3e291f386324 
//Enter your device Info
  char jsonDeviceInfo[] ="{\"model\":\"Dry_Goods_Retro_Container\",\"serial\":\"dgrc01\"}";
  
AmazonDRS DRS = AmazonDRS();
  
//RTC ----------------------------------------------------
RTCZero rtc; //rtc RTCZero instance
bool awake = false; //true = running, false = sleep mode
//Values to set the current initial date and time 
byte seconds;
byte minutes;
byte hours;
byte day;
byte month;
byte year;
byte replenishhour;

//Ultrasonic ---------------------------------------------
#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 6 // Onboard LED

int maximumRange = 200; // Maximum range needed
int minimumRange = 5; // Minimum range needed
int replenishRange = 20; //20 cm. or greater => Replenish
long duration, distance; // Duration used to calculate distance

//Setup ---------------------------------------------------
void setup() {
 Serial.begin (9600);

 delay(10000); //delay to measure current draw. Also needed to be able to re-program MKR1000 when using sleep mode

//Exchange Data with Client ----------------------------------------------------------------
Serial.println(jsonDeviceInfo);

  while (!Serial.available()) {} //Wait for the serial port
  while (Serial.available()) {
    delay(3);  //delay to allow buffer to fill
    if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //append to readString
    }
  }

  //if (readString.length() >0) Serial.println(readString); //see what was received

  JsonObject& root = jsonBuffer.parseObject(readString);

  // Test if parsing failed
  if (!root.success()) {
    Serial.println("parseObject() failed");
    return; //We have a problem
  }

  
  String ssidString = root["wifissid"];
  char ssid[ssidString.length()]; 
  ssidString.toCharArray(ssid, ssidString.length()+1); 

  String passString = root["wifipassword"];
  char pass[passString.length()]; 
  passString.toCharArray(pass, passString.length()+1);

  String refreshToken = root["refreshtoken"];
  DRS.setRefreshToken(refreshToken);

  String accessToken = root["accesstoken"];
  DRS.setAccessToken(accessToken);

  

  Serial.print("==========> Refresh Token: ");
  Serial.println(refresh_token);

  Serial.print("==========> Access Token: ");
  Serial.println(access_token);

  


  seconds = root["second"];
  minutes = root["minute"];
  hours = root["hour"];
  year = root["year"];
  month = root["month"];
  day = root["day"];
  replenishhour = root["replenishhour"];

  Serial.print("SSID: ");
  Serial.println(ssid);
  //Serial.print("PASS: ");
  //Serial.println(pass);
      
//------------------------------------------------------------------------------------------


  DRS.begin(ssid,pass); //Startup DRS
  
  pinMode(LEDPin, OUTPUT); //set LED pin to output
  digitalWrite(LEDPin, LOW); //turn LED off

  rtc.begin(); //Start RTC, this is where the clock source is initialized

  rtc.setTime(hours, minutes, seconds); //set time
  rtc.setDate(day, month, year); //set date
  rtc.setAlarmTime(replenishhour, 0, 0); 

  Serial.print("================> Replenish Hour: ");
  Serial.println(replenishhour);
  Serial.print("RTC Date/Time: ");
  PrintDateTime();

  
  //rtc.enableAlarm(rtc.MATCH_SS);//set alarm time to go off on matching seconds
  rtc.enableAlarm(rtc.MATCH_HHMMSS); //set alarm to go off at a specific time
  rtc.attachInterrupt(ISR); //creates an interrupt that wakes the SAMD21 which is triggered by a FTC alarm

  
  //Replenish(); //Replenish immediately for testing
  rtc.standbyMode(); //Puts the SAMD chip in standby (low power) mode. USB Serial port will not work (disconnects from USB). Comment out for testing.
}

//Loop -----------------------------------------------
void loop() {
 if (awake)
 { 
  Serial.println("awake in loop");
  ping();
  awake = false;
 }
}

void ISR()
{
  //Serial.println("awake in ISR");
  awake = true;
  PrintDateTime();
}

void ping()
{
  Serial.println("awake in ping");
 //Setup Ultrasonic Sensor
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);

 //Ping Ultrasonic Sensor and show distance
 /* The following trigPin/echoPin cycle is used to determine the distance of the nearest object by bouncing soundwaves off of it. */ 
 //digitalWrite(trigPin, LOW); 
 delayMicroseconds(2); 

 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10); 
 
 digitalWrite(trigPin, LOW);
 duration = pulseIn(echoPin, HIGH);
 
 //Calculate the distance (in cm) based on the speed of sound.
 float distance = duration/58.2;
 
 if (distance >= maximumRange || distance <= minimumRange)
 {
  //Ignore
  //Serial.println("out of range");
 }
 else {
  //We have a valid distance reading, see if we need to replenish
   digitalWrite(LEDPin, HIGH);
   delay(1000);
   digitalWrite(LEDPin, LOW);
   delay(1000);
  if (distance >= replenishRange)
    Replenish();
    
 /* Send the distance to the computer using Serial protocol, and turn LED OFF to indicate successful reading. */
 Serial.print("Distance: ");
 Serial.print(distance,3);
 Serial.print(" cm Duration: ");
 Serial.println(duration);
 }
}

void Replenish()
{
  Serial.println("Requesting replenishment");
    DRS.retrieveSubscriptionInfo();  //check slot statuses

  slotStatus = DRS.getSlotStatus(slotNumber);
  slotId = DRS.getSlotId(slotNumber);

        //Replenish          
        if(slotStatus == "true")   //if the product in slot are available 
        {
            //we have a match! replenish the products associated with that slot!    
            Serial.println("Trying to replenish!!!");        
            DRS.requestReplenishmentForSlot(slotId);
        }
        else
        {
          Serial.print("Sorry, slot ");
          Serial.print(slotId);
          Serial.println(" is not available at this time");
        }
}

void print2digits(int number) 
{
  if (number < 10) {
    Serial.print("0"); // print a 0 before if the number is < than 10
  }
  Serial.print(number);
}

void PrintDateTime()
{
    // Print date...
  print2digits(rtc.getMonth());
  Serial.print("/");
  print2digits(rtc.getDay());
  Serial.print("/");
  print2digits(rtc.getYear());
  Serial.print(" ");

  // ...and time
  print2digits(rtc.getHours());
  Serial.print(":");
  print2digits(rtc.getMinutes());
  Serial.print(":");
  print2digits(rtc.getSeconds());

  Serial.println();
}

An Arduino library for WiFi101 connected devices implementing the Amazon Dash Replenishment API

RTCZero

Credits

claude garrett

claude garrett

3 projects • 8 followers
Contact

Comments

Add projectSign up / Login