Amazon Dash button is an incredible piece of hardware and another example of “applied engineering” in Amazon, just like Kindle.
The inspiration for this project isn’t directly derived from amazon dash, I wasn’t aware of it until I started digging the internet but at end, I had to set the performance goal to Amazon dash, because no other piece of hardware was up to mark. A detailed teardown of dash button can be found here.
So, Since “decades” I wanted to build some piece of hardware which I could dynamically program for any functionality like playing next youtube video, unlocking door, rebooting a machine, minimizing all open tabs or whatever with a push of a button. The button should be portable and independent of device for operation.
To meet my requirements I had to remove BLE or any other radio-based technology which needed a receiver or additional unit to operate. ESP-12F is power intensive and somewhat large if compared to esp-01. The end prototype looked like this and worked as expected.
Below is list of components I used.
- 1x LiPo Battery – 150mAh
- 1x ESP8266-01
- 1x 1k Register
- 1x Tactile Switch Button
You might require a soldering iron with fine tip, basic desoldering skills, access to 3d printer, FTDI board or similar setup.
The schematics of setup would look like below:
The functioning would be like – We turn on ESP using push button, but it would take time to log in to wifi, authenticate – so we need to keep it on for pretty long time – which could be done by using programming output pins, As soon as ESP turn on GPIO2 can be set to HIGH, Once operation is finished it can be set to low. Few challenges which I found on way (with fixes):
- Power is very limited – So we need to remove LED’s from the esp, this would save a lot of power and would increase battery life by almost a fold!
- You should use diode and transistor to limit current, since I am not an electronic nerd I would not comment on it.
- You should set a timeout period, in case you are writing custom logic else battery will drain and you will never come to know why!
After soldering – You have to upload following code which need to be tweaked according to need, but it has basic logic code –
The code can set in hotspot mode if couldn’t connect to wifi and if could connect it would make a connection to mqtt server and make an announcement then shutdown.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
#define DEVICE_ID "YOUR_USERNAME" #define DEVICE_NAME "iot-" DEVICE_ID #define WIFI_SSID "mad-" DEVICE_ID #define WIFI_PASSWORD DEVICE_ID #define MQTT_SERVER "YOUR_SERVER" #define MQTT_USERNAME DEVICE_ID #define MQTT_PASSWORD "YOUR_PASSWORD" #define MQTT_SEND_CHANNEL "pushbutton" #define MQTT_RECV_CHANNEL DEVICE_NAME #define BUTTON_MODE 1 #define USE_SSL 1 #define GPIO2 2 #define BUTTON_TIMEOUT 30000 #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <ESP8266mDNS.h> #include <PubSubClient.h> #include <DNSServer.h> #include <WiFiManager.h> #include <ArduinoJson.h> #include <stdarg.h> #if USE_SSL # include <WiFiClientSecure.h> // WiFiClientSecure client; # define PORT 443 #else // WiFiClient client; # define PORT 80 #endif void reconnect(); void sendMessage(String action, String data, char* num = "", ...); char* stringToChar(String str); WiFiClient espClient; PubSubClient client(espClient); WiFiManager wifiManager; long lastMsg = 0; char msg[50]; int value = 0; String DEVICE_FEATURES = ""; void setup() { DEVICE_FEATURES += "pushbutton;"; pinMode(GPIO2, OUTPUT); digitalWrite(GPIO2, HIGH); //Serial.begin(9600); // wifiManager.resetSettings(); if (!wifiManager.autoConnect(WIFI_SSID, WIFI_PASSWORD)) { //Serial.println("failed to connect, we should reset as see if it connects"); delay(1000); ESP.reset(); delay(1000); } client.setServer(MQTT_SERVER, 1883); } void loop() { //if button mode, & time since start is greater than TIMEOUT close the time. if (millis() > BUTTON_TIMEOUT) digitalWrite(GPIO2, LOW); //if MQTT Client not connect connect it back. if (!client.connected()) reconnect(); client.loop(); } /** Send message to server example: sendMessage("hello", DEVICE_NAME,"ksks","mac",getMacAddress(),"localIP",WiFi.localIP().toString()); k for key d : double, f : float, s : string, l : long, No char type */ void sendMessage(String action, String data, char *types, ...) { StaticJsonBuffer<200> jsonBuffer; JsonObject& root = jsonBuffer.createObject(); root["action"] = action; root["data"] = data; //find length int count = 0; while (types[count++] != '\0'); --count; //if not even args if (count % 2 != 0) return; //for argument parsing. va_list arguments; va_start ( arguments, types ); String key; //even length validated already for (int i = 0; types[i] != '\0'; i += 2) { //this is intentionally done, default key as type k can be used, but developer might mistake, causing lot of debugging if (types[i] != 'k') continue; key = va_arg ( arguments, char * ); switch (types[i + 1]) { case 'd': root[key] = (va_arg(arguments, int)); break; case 'l': root[key] = (va_arg(arguments, long)); break; case 'f': root[key] = (va_arg(arguments, double)); break; case 's': root[key] = (va_arg(arguments, char *)); break; default: ; }; } va_end ( arguments ); // Cleans up the list char tmp[root.measureLength() + 2]; root.printTo(tmp, sizeof(tmp)); client.publish(MQTT_SEND_CHANNEL, tmp); } void reconnect() { // Loop until we're reconnected while (!client.connected()) { //Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect(DEVICE_NAME, MQTT_USERNAME, MQTT_PASSWORD)) { //Serial.println("connected"); // Once connected, publish an announcement... sendMessage("hello", DEVICE_NAME, "ksks", "features", (DEVICE_FEATURES).c_str() , "localIP", (WiFi.localIP().toString().c_str())); digitalWrite(GPIO2, LOW); } else { //Serial.print("failed, rc="); //Serial.print(client.state()); //Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(2000); } } } |
I hope you enjoyed the article, it wasn’t a detailed writeup and I dropped many details – but if you have any questions you can comment or drop mail – I will surely help.