Skip to content

Instantly share code, notes, and snippets.

@TakuroFukamizu
Created April 3, 2020 00:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TakuroFukamizu/019682fbda50414500e63454e69301de to your computer and use it in GitHub Desktop.
Save TakuroFukamizu/019682fbda50414500e63454e69301de to your computer and use it in GitHub Desktop.
Sesame smartlock controller application run on M5Atom Matrix.
#include "M5Atom.h"
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#define WIFI_SSID "YOUR WIFI SSID"
#define WIFI_PASS "YOUR WIFI PASS"
#define SESAME_TOKEN "YOUR API KEY"
#define SESAME_DEVICE_ID "YOUR SESAME ID"
// ----------------
uint8_t counter = 0;
const CRGB COLOR[4] = {
0xf08b18,
0x00f000,
0x0000f0,
0x707070
};
// ----------------
enum SESAME_COMMAND
{
LOCK,
UNLOCK,
};
typedef struct {
bool locked;
uint8_t battery;
bool responsive;
} SESAME_STATUS;
typedef struct {
const char* status;
bool successful;
} ACTION_STATUS;
// ----------------
void display_all_clear() {
M5.dis.clear();
}
void display_progress_clear() {
M5.dis.clear();
counter = 0;
}
void display_progress() {
counter++;
if (NUM_LEDS <= counter) {
counter = 0;
M5.dis.clear();
}
for (int i=0; i<counter+1; i++) {
M5.dis.drawpix(i, 0xf08b18);
}
}
void display_all_green(bool stop = false) {
M5.dis.clear();
delay(50);
for (int i=0; i<NUM_LEDS; i++) {
M5.dis.drawpix(i, 0xff0000); // GRB
}
delay(1000);
if (stop) {
M5.dis.clear();
}
}
void display_all_red(bool stop = false) {
M5.dis.clear();
delay(50);
for (int i=0; i<NUM_LEDS; i++) {
M5.dis.drawpix(i, 0x00ff00); // GRB
}
delay(1000);
if (stop) {
M5.dis.clear();
}
}
void display_blink_green() {
CRGB color = 0xff0000;
for (int i=0; i<NUM_LEDS; i++) {
M5.dis.drawpix(i, color); // GRB
}
delay(200);
M5.dis.clear();
delay(200);
for (int i=0; i<NUM_LEDS; i++) {
M5.dis.drawpix(i, color); // GRB
}
delay(200);
M5.dis.clear();
}
void display_blink_red(bool stop = false) {
CRGB color = 0x00ff00;
for (int i=0; i<NUM_LEDS; i++) {
M5.dis.drawpix(i, color); // GRB
}
delay(200);
M5.dis.clear();
delay(200);
for (int i=0; i<NUM_LEDS; i++) {
M5.dis.drawpix(i, color); // GRB
}
delay(200);
M5.dis.clear();
}
// ----------------
void wifi_connect() {
const char* ssid = WIFI_SSID;
const char* pass = WIFI_PASS;
// M5.Lcd.print("Connect to ");
// M5.Lcd.println(ssid);
WiFi.disconnect(true);
display_progress();
delay(1000);
display_progress();
WiFiMulti wifiMulti;
wifiMulti.addAP(ssid, pass);
while (wifiMulti.run() != WL_CONNECTED) {
delay(500);
display_progress();
}
display_all_green();
}
SESAME_STATUS getStatus() {
String url = "https://api.candyhouse.co/public/sesame/" + String(SESAME_DEVICE_ID);
Serial.println(url);
HTTPClient http;
http.begin(url);
http.addHeader("Authorization", String(SESAME_TOKEN));
int httpResponseCode = http.GET();
Serial.println("http status code: "+String(httpResponseCode));
if (httpResponseCode < 0) {
Serial.println(http.errorToString(httpResponseCode));
throw http.errorToString(httpResponseCode);
} else if (httpResponseCode != 200) {
throw "other errors: " + String(httpResponseCode);
} else if (http.getSize() < 0) {
throw "size is invalid";
}
SESAME_STATUS res;
Stream* resp = http.getStreamPtr();
StaticJsonDocument<255> resDoc;
deserializeJson(resDoc, *resp);
JsonObject object = resDoc.as<JsonObject>();
bool locked = object["locked"];
uint8_t battery = object["battery"];
bool responsive = object["responsive"];
Serial.print("locked:" + String(locked));
Serial.print("battery:" + String(battery));
Serial.println("responsive:" + String(responsive));
res = { locked, battery, responsive };
http.end();
return res;
}
String sendCommand(SESAME_COMMAND command) {
StaticJsonDocument<200> doc;
switch(command) {
case LOCK : doc["command"] = "lock"; break;
case UNLOCK: doc["command"] = "unlock"; break;
}
String jsonString;
serializeJson(doc, jsonString);
const char* taskId;
HTTPClient http;
http.begin("https://api.candyhouse.co/public/sesame/" + String(SESAME_DEVICE_ID));
http.addHeader("Authorization", String(SESAME_TOKEN));
int httpResponseCode = http.POST(jsonString);
if (httpResponseCode < 0) {
Serial.println(http.errorToString(httpResponseCode));
throw http.errorToString(httpResponseCode);
} else if (httpResponseCode != 200) {
throw "other errors: " + String(httpResponseCode);
} else if (http.getSize() < 0) {
throw "size is invalid";
}
Stream* resp = http.getStreamPtr();
StaticJsonDocument<255> resDoc;
deserializeJson(resDoc, *resp);
JsonObject object = resDoc.as<JsonObject>();
taskId = object["task_id"];
Serial.println("taskId:" + String(taskId));
http.end();
return taskId;
}
ACTION_STATUS getActionResult(String taskId) {
String url = "https://api.candyhouse.co/public/action-result?task_id=" + String(taskId);
Serial.println(url);
HTTPClient http;
http.begin(url);
http.addHeader("Authorization", String(SESAME_TOKEN));
int httpResponseCode = http.GET();
Serial.println("http status code: "+String(httpResponseCode));
if (httpResponseCode < 0) {
Serial.println(http.errorToString(httpResponseCode));
throw http.errorToString(httpResponseCode);
} else if (httpResponseCode != 200) {
throw "other errors: " + String(httpResponseCode);
} else if (http.getSize() < 0) {
throw "size is invalid";
}
ACTION_STATUS res;
Stream* resp = http.getStreamPtr();
StaticJsonDocument<255> resDoc;
deserializeJson(resDoc, *resp);
JsonObject object = resDoc.as<JsonObject>();
const char* status = object["status"];
bool successful = object["successful"];
Serial.println("status:" + String(status) + ", successful:" + String(successful));
res = { status, successful };
http.end();
return res;
}
// ----------------
void setup() {
M5.begin(true, false, true);
delay(50);
M5.dis.clear();
wifi_connect();
}
bool isOpenMode = true;
void loop() {
M5.update();
if (!M5.Btn.wasPressed()) {
display_all_clear();
delay(100);
return;
}
try {
display_progress_clear();
SESAME_COMMAND mode;
if (isOpenMode) {
mode = UNLOCK;
} else {
mode = LOCK;
}
Serial.println("M5.BtnA.wasPressed()");
String taskId = sendCommand(mode);
while(true) {
ACTION_STATUS res = getActionResult(taskId);
if (res.successful) {
Serial.println(" complete");
break;
}
display_progress();
Serial.print(".");
delay(300);
}
if (isOpenMode) {
display_blink_green();
} else {
display_blink_red();
}
delay(1000);
display_progress_clear();
isOpenMode = !isOpenMode;
} catch (char *e) {
display_all_red(true);
Serial.println(e);
}
delay(500);
// try {
// if (M5.Btn.wasPressed()) {
// display_progress_clear();
//
// SESAME_STATUS status = getStatus();
// if (status.locked) {
// display_all_red();
// //M5.Lcd.print("LOCK");
// } else {
// display_all_green();
// //M5.Lcd.print("OPEN");
// }
// //M5.Lcd.print(", battery:" + String(status.battery));
// //M5.Lcd.println(", responsive:" + String(status.responsive));
// }
// } catch (char *e) {
// display_all_red(true);
// Serial.println(e);
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment