Last active
August 1, 2020 01:49
-
-
Save ma2shita/76c563550448a08b92f0614f8d772921 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 <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