Skip to content

Instantly share code, notes, and snippets.

@ma2shita
Last active August 1, 2020 01:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ma2shita/76c563550448a08b92f0614f8d772921 to your computer and use it in GitHub Desktop.
Save ma2shita/76c563550448a08b92f0614f8d772921 to your computer and use it in GitHub Desktop.
#include <M5Stack.h>
#include <HTTPClient.h> /* Why? see https://qiita.com/ma2shita/items/97bf1a0c3158b848019a */
#define console Serial
#define TEXT_SIZE 2
//https://www.switch-science.com/catalog/5219/
#define ToF_ADDR 0x29 // the iic address of tof
#include <VL53L0X.h> // from Lib. manager: https://github.com/pololu/vl53l0x-arduino/blob/master/examples/Continuous/Continuous.ino
VL53L0X tof;
#define SerialAT Serial2 // `Serial2` is 3G Extension board for M5Stack Basic/Gray
#define TINY_GSM_MODEM_UBLOX
#include <TinyGsmClient.h>
TinyGsm modem(SerialAT);
TinyGsmClient ctx(modem);
void connect_check_and_reconnect() {
console.println((modem.isGprsConnected()) ? "isGprsConnected(): true" : "isGprsConnected(): false");
long s = millis();
if (!modem.isGprsConnected()) {
console.print("modem.restart(): ");
SerialAT.begin(115200, SERIAL_8N1, 16, 17);
modem.restart();
console.println("done");
console.print("getModemInfo(): ");
console.println(modem.getModemInfo());
console.print("waitForNetwork(): ");
while (!modem.waitForNetwork()) console.print(".");
console.println("Ok");
console.print("gprsConnect(soracom.io): ");
modem.gprsConnect("soracom.io", "sora", "sora");
console.println("done");
console.print("isNetworkConnected(): ");
while (!modem.isNetworkConnected()) console.print(".");
console.println("Ok");
console.print("localIP(): ");
console.println(modem.localIP());
}
long e = millis();
console.print("Modem bootup elapsed(ms): "); console.println(e - s);
}
#include <ArduinoJson.h>
/* Dynamic config by SORACOM Air metadata */
// for loop()
long DETECT_RANGE_LOW_MM;
long DETECT_RANGE_HIGH_MM;
// for reset_countdown()
long NOTIFICATION_INTERVAL_SEC;
// for setup()
long _COUNT_DOWN_INTERVAL_SEC;
bool LCD_TURN_ON_AT_BOOT;
// for sampling_measurement()
int _SAMPLING_COUNT;
int _SAMPLING_INTERVAL_MS;
int _CUT_RANGE_LOW_MM;
int _CUT_RANGE_HIGH_MM;
// for send_to_cloud()
bool SEND_TO_CLOUD;
volatile long countdown = 0;
void tick_countdown() {
countdown--;
}
void reset_countdown() {
countdown = NOTIFICATION_INTERVAL_SEC;
}
#include <ArduinoHttpClient.h>
HttpClient http1 = HttpClient(ctx, "metadata.soracom.io", 80);
HttpClient http2 = HttpClient(ctx, "uni.soracom.io", 80);
void send_to_cloud(float avg) {
const size_t capacity = JSON_OBJECT_SIZE(1); // Code generate by https://arduinojson.org/v6/assistant/
DynamicJsonDocument doc(capacity);
doc["avg_mm"] = avg;
char buf[1024];
serializeJson(doc, buf);
console.println(buf);
connect_check_and_reconnect();
http2.post("/", "application/json", buf);
console.print("responseStatusCode(): "); console.println(http2.responseStatusCode());
http2.stop();
}
/* internal use */
bool lcd_status = true;
void setup() {
console.begin(115200);
M5.begin();
M5.Power.begin();
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setTextSize(TEXT_SIZE);
M5.Lcd.setCursor(0, 0);
M5.Lcd.println("Boot...");
bool trying_fetch_config_from_cloud = true;
M5.update();
if (M5.BtnA.isPressed()) { // TODO
console.println("Skip fetching config from Cloud");
M5.Lcd.println("Skip fetching config from Cloud");
delay(2000);
trying_fetch_config_from_cloud = false;
}
String json = "";
bool is_successful_fetching_config = false;
if (trying_fetch_config_from_cloud) {
console.println("Trying fetch config from Cloud");
M5.Lcd.println("Trying fetch config from Cloud (Wait about 40 seconds...");
connect_check_and_reconnect();
http1.get("/v1/subscriber.tags.config_json");
int rc = http1.responseStatusCode();
String rb = http1.responseBody();
http1.stop();
console.print("responseStatusCode(): "); console.println(rc);
console.print("responseBody(): "); console.println(rb);
if (rc == 200) {
is_successful_fetching_config = true;
json = rb;
}
}
console.println(json);
M5.Lcd.fillScreen(TFT_BLACK); // for clear
M5.Lcd.fillRect(0, M5.Lcd.fontHeight() * 0, M5.Lcd.width(), M5.Lcd.fontHeight() * 1, TFT_DARKGREY); // 0means 0row
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextDatum(TL_DATUM);
M5.Lcd.drawString("Config", 0, 0);
if (trying_fetch_config_from_cloud) {
if (is_successful_fetching_config) {
M5.Lcd.drawString("(by Cloud)", M5.Lcd.textWidth("Config "), 0);
} else {
M5.Lcd.drawString("(by Default)", M5.Lcd.textWidth("Config "), 0);
}
} else {
M5.Lcd.drawString("(by Local)", M5.Lcd.textWidth("Config "), 0);
}
const size_t capacity = JSON_OBJECT_SIZE(10) + 230; // Code generate by https://arduinojson.org/v6/assistant/
DynamicJsonDocument doc(capacity);
deserializeJson(doc, json); // NOTE: Need error handling
SEND_TO_CLOUD = doc["SEND_TO_CLOUD"] | trying_fetch_config_from_cloud;
DETECT_RANGE_LOW_MM = doc["DETECT_RANGE_LOW_MM"] | 20;
DETECT_RANGE_HIGH_MM = doc["DETECT_RANGE_HIGH_MM"] | 55;
NOTIFICATION_INTERVAL_SEC = doc["NOTIFICATION_INTERVAL_SEC"] | 300;
LCD_TURN_ON_AT_BOOT = doc["LCD_TURN_ON_AT_BOOT"] | lcd_status;
_COUNT_DOWN_INTERVAL_SEC = doc["_COUNT_DOWN_INTERVAL_SEC"] | 1;
_SAMPLING_COUNT = doc["_SAMPLING_COUNT"] | 5;
_SAMPLING_INTERVAL_MS = doc["_SAMPLING_INTERVAL_MS"] | 50;
_CUT_RANGE_LOW_MM = doc["_CUT_RANGE_LOW_MM"] | 5;
_CUT_RANGE_HIGH_MM = doc["_CUT_RANGE_HIGH_MM"] | 700;
if (LCD_TURN_ON_AT_BOOT) {
M5.Lcd.wakeup();
M5.Lcd.setBrightness(255);
} else {
M5.Lcd.sleep();
M5.Lcd.setBrightness(0);
}
lcd_status = LCD_TURN_ON_AT_BOOT;
M5.Lcd.setCursor(0, M5.Lcd.fontHeight() * 1); // 1means 1row
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.print("Send to cloud: "); M5.Lcd.println((SEND_TO_CLOUD) ? "true" : "false");
M5.Lcd.printf("Detect Range(mm): %3u..%3u\r\n", DETECT_RANGE_LOW_MM, DETECT_RANGE_HIGH_MM);
M5.Lcd.printf("Notification Int.(s): %3u\r\n", NOTIFICATION_INTERVAL_SEC);
M5.Lcd.print("Trun ON LCD at boot: "); M5.Lcd.println((LCD_TURN_ON_AT_BOOT) ? "true" : "false");
M5.Lcd.fillRect(0, M5.Lcd.fontHeight() * 6, M5.Lcd.width(), M5.Lcd.fontHeight() * 1, TFT_DARKGREEN); // 6means 6row
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextDatum(TL_DATUM);
M5.Lcd.drawString("Current Status", 0, M5.Lcd.fontHeight() * 6); // 6means 6row
Wire.begin();
tof.setAddress(ToF_ADDR);
tof.setTimeout(500);
tof.init();
tof.startContinuous();
reset_countdown();
}
#include <vector>
std::vector<int> v;
#include <algorithm>
float sampling_measurement() {
v.clear();
for (int i = 0 ; i < _SAMPLING_COUNT ; i++) {
v.push_back(tof.readRangeContinuousMillimeters());
delay(_SAMPLING_INTERVAL_MS);
}
console.print("All records: ");
for (const auto &x : v) {
console.print(x); console.print(", ");
} console.println();
for (auto it = v.begin(); it != v.end();) { // instead of #erase_if(), C++11 not impl.
if ( !(_CUT_RANGE_LOW_MM <= *it && *it <= _CUT_RANGE_HIGH_MM) ) { // cut higher and lower for noise cancel
it = v.erase(it);
} else {
++it;
}
}
console.print("Actual records: ");
for (const auto &x : v) {
console.print(x); console.print(", ");
} console.println();
const auto avg = std::accumulate(v.begin(), v.end(), 0.0) / v.size();
console.print("Avg: "); console.println(avg);
return avg;
}
bool object_exists_state = false;
#include <Ticker.h>
Ticker ticker1;
bool ticker1_active = false; /*Ticker::active() does not implement in esp32 1.0.4 */
void loop() {
M5.update();
if (M5.BtnC.wasReleased()) {
if (lcd_status) {
M5.Lcd.sleep();
M5.Lcd.setBrightness(0);
} else {
M5.Lcd.wakeup();
M5.Lcd.setBrightness(255);
}
lcd_status = !lcd_status;
}
float mm = sampling_measurement();
console.print("mm: "); console.println(mm);
M5.Lcd.fillRect(0, M5.Lcd.fontHeight() * 7, M5.Lcd.textWidth("Distance avg.: 999mm"), M5.Lcd.fontHeight() * 1, TFT_BLACK); // 7means 7row
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextDatum(TL_DATUM);
M5.Lcd.setCursor(0, M5.Lcd.fontHeight() * 7); // 7means 7row
M5.Lcd.printf("Distance avg.: %3.0f mm\r\n", mm);
if (DETECT_RANGE_LOW_MM <= (long) mm && (long) mm <= DETECT_RANGE_HIGH_MM) {
object_exists_state = true;
if (!ticker1_active) {
ticker1_active = true;
ticker1.attach(_COUNT_DOWN_INTERVAL_SEC, tick_countdown);
}
} else {
object_exists_state = false;
ticker1_active = false;
ticker1.detach();
reset_countdown();
}
console.print("object_exists_state: "); console.println(object_exists_state);
M5.Lcd.fillRect(0, M5.Lcd.fontHeight() * 8, M5.Lcd.textWidth("Object: NOT Found"), M5.Lcd.fontHeight() * 1, TFT_BLACK); // 8means 8row
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextDatum(TL_DATUM);
M5.Lcd.setCursor(0, M5.Lcd.fontHeight() * 8); // 8means 8row
M5.Lcd.printf("Object: %s\r\n", ((object_exists_state) ? "Found!" : "NOT Found"));
console.print("countdown: "); console.println(countdown);
M5.Lcd.fillRect(0, M5.Lcd.fontHeight() * 9, M5.Lcd.textWidth("Notification Left: 9999s"), M5.Lcd.fontHeight() * 1, TFT_BLACK); // 9means 9row
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextDatum(TL_DATUM);
M5.Lcd.setCursor(0, M5.Lcd.fontHeight() * 9); // 9means 9row
if (countdown < NOTIFICATION_INTERVAL_SEC) {
M5.Lcd.printf("Notification Left: %4u s\r\n", countdown);
} else {
M5.Lcd.print("Notification Left: ---- s\r\n");
}
if (countdown < 1) {
if (SEND_TO_CLOUD) {
M5.Lcd.fillRect(0, M5.Lcd.fontHeight() * 10, M5.Lcd.textWidth("Send to cloud..."), M5.Lcd.fontHeight() * 1, TFT_BLACK); // 10means 10row
M5.Lcd.setTextColor(TFT_MAROON);
M5.Lcd.setTextDatum(TL_DATUM);
M5.Lcd.drawString("Send to cloud...", 0, M5.Lcd.fontHeight() * 10); // 10means 10row
console.println("send_to_cloud()");
send_to_cloud(mm);
M5.Lcd.fillRect(0, M5.Lcd.fontHeight() * 10, M5.Lcd.textWidth("Send to cloud..."), M5.Lcd.fontHeight() * 1, TFT_BLACK); // 10means 10row
}
reset_countdown();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment