#undef ARDUINO_M5STACK_FIRE #define ARDUINO_M5STACK_Paper #define YAML_DISABLE_CJSON #include #include #include #include #include #include "settings.hpp" #include "mqtt.hpp" #include "keypad.hpp" static WiFiUDP ntpUDP; static NTPClient timeClient(ntpUDP); static MQTT *mqtt; static Keypad *keypad; static bool is_disarmed = false; static const int WIFI_CONNECT_RETRY_MAX = 30; void mqtt_callback(char *topic, byte *payload, unsigned int length) { payload[length] = '\0'; String state((const char *)payload); is_disarmed = state == "disarmed"; if (state == "armed_away") { keypad->draw(); } Serial.println(state); keypad->write(state); } void lock() { if (is_disarmed) { mqtt->send("ARM_AWAY"); } } void unlock() { mqtt->send("DISARM"); } bool isConnecting = false; void initWifi(Settings *settings) { if (!settings) { keypad->write("no settings"); return; } if (isConnecting) { keypad->write("already connecting"); return; } isConnecting = true; keypad->write("connecting"); WiFi.begin(settings->gettext("wifi:ssid"), settings->gettext("wifi:password")); if (WiFi.isConnected()) { WiFi.disconnect(); } Serial.print("Connecting to Wi-Fi network"); for (int cnt_retry = 0; cnt_retry < WIFI_CONNECT_RETRY_MAX && !WiFi.isConnected(); cnt_retry++) { delay(500); Serial.print("."); } Serial.println(""); if (WiFi.isConnected()) { Serial.print("Local IP: "); Serial.println(WiFi.localIP()); isConnecting = false; keypad->write("connected"); } else { keypad->write("failed to connect"); isConnecting = false; return; } } void initTOTP(Settings *settings) { uint8_t *base32_key = new uint8_t[20]; const char *hmac = ((String)settings->gettext("totp:hmac")).c_str(); for (int i = 0; i < 20; i++) { base32_key[i] = (uint8_t)hmac[i]; } TOTP(base32_key, 20, 30); } void setup() { M5.begin(); keypad = new Keypad(); keypad->write("loading"); auto settings = new Settings(); if (!settings) { keypad->write("unable to load settings"); return; } mqtt = new MQTT(settings, mqtt_callback); initWifi(settings); mqtt->connect(); timeClient.begin(); initTOTP(settings); } void submit(String code) { uint32_t newCode = getCodeFromTimestamp(timeClient.getEpochTime()); uint32_t input = code.toInt(); if (newCode == input) { unlock(); return; } lock(); } void loop() { timeClient.update(); mqtt->loop(); auto value = keypad->get_input(); if (value.has_value()) submit(value.value()); }