Created
April 3, 2020 00:07
-
-
Save TakuroFukamizu/019682fbda50414500e63454e69301de to your computer and use it in GitHub Desktop.
Sesame smartlock controller application run on M5Atom Matrix.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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