diff --git a/.github/workflows/platformio.yml b/.github/workflows/platformio.yml index 30b43fe0..83b683e7 100644 --- a/.github/workflows/platformio.yml +++ b/.github/workflows/platformio.yml @@ -1,7 +1,7 @@ name: PlatformIO on: - push: + pull_request: branches: - master paths-ignore: @@ -9,23 +9,28 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: max-parallel: 1 matrix: - python-version: [3.7] + os: [ubuntu-latest] steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + - uses: actions/checkout@v4 + - uses: actions/cache@v3 with: - python-version: ${{ matrix.python-version }} + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -U platformio - platformio update - - name: Build test + pio pkg update + - name: PlatformIO Build Test run: | - pio run -e TTGO_T7 -e ESP32DEVKIT -e TTGO_TDISPLAY -e M5STICKCPLUS -e ESP32C3LOLIN - + pio run -e TTGO_T7 -e TTGO_TDISPLAY -e ESP32C3LOLIN diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 02e3a20c..752351db 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -1,7 +1,7 @@ name: PlatformIO on: - push: + pull_request: branches: - devel paths-ignore: @@ -9,23 +9,29 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: max-parallel: 1 matrix: - python-version: [3.7] + os: [ubuntu-latest] steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + - uses: actions/checkout@v4 + - uses: actions/cache@v3 with: - python-version: ${{ matrix.python-version }} + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -U platformio - platformio update - - name: Build test + pio pkg update + - name: Devel Build Test run: | - pio run -e TTGO_T7 -e TTGO_TDISPLAY -e M5STICKCPLUS -e ESP32C3LOLIN - \ No newline at end of file + pio run -e TTGO_T7 -e TTGO_TDISPLAY -e ESP32C3LOLIN + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 88bc1481..9f4dee8d 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,7 @@ esptool.py md5output.txt releases/manifest releases/installer/rev* - +lib/easy-preferences # IDE .travis.yml extensions.json diff --git a/build b/build index dbf88c82..db90bdb6 100755 --- a/build +++ b/build @@ -26,7 +26,8 @@ OWNER="kike-canaries" REPO="canairio_firmware" INSDIR=$RELDIR/installer/${NAME}_installer -flavors="TTGO_T7 WEMOSOLED HELTEC TTGO_TQ ESP32DEVKIT TTGO_TDISPLAY ESP32PICOD4 M5STICKCPLUS M5ATOM M5PICOD4 ESP32C3 ESP32C3OIPLUS ESP32C3LOLIN ESP32C3SEEDX ESP32S3 TTGO_T7S3 LORADEVKIT" +flavors="TTGO_T7 WEMOSOLED HELTEC TTGO_TQ ESP32DEVKIT TTGO_TDISPLAY ESP32PICOD4 M5ATOM M5PICOD4 ESP32C3 ESP32C3OIPLUS ESP32C3LOLIN ESP32C3SEEDX ESP32S3 TTGO_T7S3 LORADEVKIT AG_OPENAIR" +#flavors="TTGO_T7 WEMOSOLED HELTEC TTGO_TQ ESP32DEVKIT TTGO_TDISPLAY ESP32PICOD4 M5STICKCPLUS M5ATOM M5PICOD4 ESP32C3 ESP32C3OIPLUS ESP32C3LOLIN ESP32C3SEEDX ESP32S3 TTGO_T7S3 LORADEVKIT AG_OPENAIR" #flavors="TTGO_T7 WEMOSOLED ESP32DEVKIT TTGO_TDISPLAY M5STICKCPLUS M5ATOM ESP32C3 ESP32C3OIPLUS ESP32C3LOLIN ESP32C3SEEDX" #flavors="TTGO_T7 ESP32C3 ESP32C3OIPLUS ESP32C3LOLIN ESP32C3SEEDX" diff --git a/include/wifi.hpp b/include/wifi.hpp deleted file mode 100644 index b94349e9..00000000 --- a/include/wifi.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef DISABLE_CLI -#include -#endif - -//#define IFX_RETRY_CONNECTION 5 // influxdb publish retry - -#define PUBLISH_INTERVAL 30 // publish to cloud each 30 seconds -#define WIFI_RETRY_CONNECTION 30 // 30 seconds wait for wifi connection -#define MQTT_RETRY_CONNECTION 1 // mqtt publish retry -#define MQTT_DELAYED_TIME 30 // mqtt retry connection delayed time -#define MQTT_BUFFER_SIZE 512 // mqtt buffer size - -void otaLoop(); -void wifiInit(); -void wifiStop(); -void wifiRestart(); -void wifiLoop(); - -int getWifiRSSI(); -void printWifiRSSI(); -String getDeviceInfo(); -String getHostId(); diff --git a/lib/batterylib/Batterylib.hpp b/lib/batterylib/Batterylib.hpp index 8adbe1f3..c25e130c 100644 --- a/lib/batterylib/Batterylib.hpp +++ b/lib/batterylib/Batterylib.hpp @@ -1,3 +1,4 @@ +#ifndef DISABLE_BATT #ifndef Batterylib_hpp #define Batterylib_hpp @@ -16,3 +17,4 @@ #endif #endif +#endif \ No newline at end of file diff --git a/lib/batterylib/battery.hpp b/lib/batterylib/battery.hpp index e262cd05..347f7c8e 100644 --- a/lib/batterylib/battery.hpp +++ b/lib/batterylib/battery.hpp @@ -143,4 +143,4 @@ class Battery { } return (int)percentage; } -}; +}; \ No newline at end of file diff --git a/lib/batterylib/battery_m5stack.cpp b/lib/batterylib/battery_m5stack.cpp index 76fdb9e7..d327d1b2 100644 --- a/lib/batterylib/battery_m5stack.cpp +++ b/lib/batterylib/battery_m5stack.cpp @@ -4,7 +4,7 @@ void Battery_M5STACK::init(bool debug) { this->debug = debug; - M5.Axp.EnableCoulombcounter(); // Enable Coulomb counter. + // M5.Axp.EnableCoulombcounter(); // Enable Coulomb counter. setLimits(BATTERY_MIN_V, BATTERY_MAX_V, BATTCHARG_MIN_V, BATTCHARG_MAX_V); } @@ -13,12 +13,12 @@ float Battery_M5STACK::getVoltage() { } void Battery_M5STACK::update() { - curv = M5.Axp.GetBatVoltage(); - vusb = M5.Axp.GetVBusVoltage(); + curv = M5.Power.getBatteryVoltage(); + // vusb = M5.Power.getUsbOutput(); } bool Battery_M5STACK::isCharging() { - return M5.axp.GetVBusVoltage() > btCharVMax; + return M5.Power.getUsbOutput(); } int Battery_M5STACK::getCharge() { @@ -31,15 +31,16 @@ int Battery_M5STACK::getCharge() { void Battery_M5STACK::printValues() { if (!debug) return; - Serial.printf("-->[BATT] AXP Temp \t: %.1fC \tC: %03d\r\n", M5.Axp.GetTempInAXP192(), getCharge()); //Get the temperature of AXP192 - Serial.printf("-->[BATT] AXP Bat Volts \t: %.3fv \tI: %.3fma\r\n", curv, M5.Axp.GetBatCurrent()); //Output voltage and current of Bat - Serial.printf("-->[BATT] AXP USB Volts \t: %.3fv \tI: %.3fma\r\n", M5.Axp.GetVBusVoltage(), M5.Axp.GetVBusCurrent()); //Output current and voltage of USB - Serial.printf("-->[BATT] AXP 5V Volts \t: %.3fv \tI: %.3fma\r\n", M5.Axp.GetVinVoltage(), M5.Axp.GetVinCurrent()); - Serial.printf("-->[BATT] AXP Bat power \t: %.3fmw\r\n", M5.Axp.GetBatPower()); + // Serial.printf("-->[BATT] AXP Temp \t: %.1fC \tC: %03d\r\n", M5.Power.GetTempInAXP192(), getCharge()); //Get the temperature of AXP192 + Serial.printf("-->[BATT] AXP Bat Volts \t: %.3fv \tI: %.3fma\r\n", curv, M5.Power.getBatteryVoltage()); //Output voltage and current of Bat + // Serial.printf("-->[BATT] AXP USB Volts \t: %.3fv \tI: %.3fma\r\n", M5.Axp.GetVBusVoltage(), M5.Axp.GetVBusCurrent()); //Output current and voltage of USB + Serial.printf("-->[BATT] AXP Bat Level \t: %.3fv \tI: %.3fma\r\n", M5.Power.getBatteryLevel(), M5.Power.getBatteryCurrent()); + // Serial.printf("-->[BATT] AXP 5V Volts \t: %.3fv \tI: %.3fma\r\n", M5.Axp.GetVinVoltage(), M5.Axp.GetVinCurrent()); + // Serial.printf("-->[BATT] AXP Bat power \t: %.3fmw\r\n", M5.Axp.GetBatPower()); } #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_M5STACKBATTERY) Battery_M5STACK battery; #endif -#endif \ No newline at end of file +#endif diff --git a/lib/batterylib/battery_m5stack.hpp b/lib/batterylib/battery_m5stack.hpp index 9eac1cb3..8e8adf9e 100644 --- a/lib/batterylib/battery_m5stack.hpp +++ b/lib/batterylib/battery_m5stack.hpp @@ -3,7 +3,7 @@ #include #ifdef M5STICKCPLUS -#include +#include #endif #define BATTERY_MIN_V 3.4 @@ -13,7 +13,7 @@ class Battery_M5STACK : public Battery { public: - float vusb = 0.0; + // float vusb = 0.0; void init(bool debug = false); float getVoltage(); float getCurrent(); diff --git a/lib/batterylib/battery_oled.cpp b/lib/batterylib/battery_oled.cpp index 747d2237..a32c7b6a 100644 --- a/lib/batterylib/battery_oled.cpp +++ b/lib/batterylib/battery_oled.cpp @@ -9,6 +9,9 @@ #elif TTGO_T7S3 #define ADC_PIN 2 int channel_atten = ADC1_CHANNEL_1; +#elif ESP32C3_AIRGRADIENT + #define ADC_PIN 4 + int channel_atten = ADC1_CHANNEL_1; #else #define ADC_PIN 34 int channel_atten = 0; diff --git a/src/bluetooth.cpp b/lib/ble/bluetooth.cpp similarity index 80% rename from src/bluetooth.cpp rename to lib/ble/bluetooth.cpp index 7123fc84..bc199518 100644 --- a/src/bluetooth.cpp +++ b/lib/ble/bluetooth.cpp @@ -1,4 +1,6 @@ +#ifndef DISABLE_BLE #include +#include "ConfigApp.hpp" BLEServer* pServer = NULL; BLECharacteristic* pCharactData = NULL; @@ -12,7 +14,7 @@ bool oldDeviceConnected = false; *************************************************************************/ String getNotificationData() { - StaticJsonDocument<40> doc; // notification capacity is reduced, only main value + JsonDocument doc; // notification capacity is reduced, only main value int deviceType = sensors.getUARTDeviceTypeSelected(); if (deviceType <= 3) { doc["P25"] = sensors.getPM25(); @@ -25,7 +27,7 @@ String getNotificationData() { } String getSensorData() { - StaticJsonDocument<512> doc; + JsonDocument doc; doc["P1"] = sensors.getPM1(); doc["P25"] = sensors.getPM25(); @@ -40,8 +42,10 @@ String getSensorData() { doc["pre"] = sensors.getPressure(); doc["nh3"] = sensors.getNH3(); doc["co"] = sensors.getCO(); + #ifndef DISABLE_BATT doc["bat"] = battery.getCharge(); doc["vol"] = battery.getVoltage(); + #endif doc["PAX"] = getPaxCount(); doc["dsl"] = sensors.getSensorName((SENSORS) sensors.getUARTDeviceTypeSelected()); String json; @@ -58,39 +62,39 @@ void bleServerDataRefresh(){ } void bleServerConfigRefresh(){ - if (FAMILY == "ESP32-C3") return; - cfg.setWifiConnected(WiFi.isConnected()); // for notify on each write - pCharactConfig->setValue(cfg.getCurrentConfig().c_str()); + // if (FAMILY == "ESP32-C3") return; + setWifiConnected(WiFi.isConnected()); // for notify on each write + pCharactConfig->setValue(getCurrentConfig().c_str()); } // Config BLE callbacks class MyConfigCallbacks : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic* pCharacteristic) { - if (FAMILY == "ESP32-C3") return; + // if (FAMILY == "ESP32-C3") return; std::string value = pCharacteristic->getValue(); if (value.length() > 0) { - if (cfg.save(value.c_str())) { - cfg.reload(); + if (save(value.c_str())) { + reload(); gui.displayPreferenceSaveIcon(); - gui.setWifiMode(cfg.isWifiEnable()); - if (!cfg.isWifiEnable()) wifiStop(); + gui.setWifiMode(isWifiEnable()); + if (!isWifiEnable()) wifiStop(); - if(sensors.sample_time != cfg.stime) { - sensors.setSampleTime(cfg.stime); - gui.setSampleTime(cfg.stime); + if(sensors.sample_time != stime) { + sensors.setSampleTime(stime); + gui.setSampleTime(stime); } - if(sensors.toffset != cfg.toffset) sensors.setTempOffset(cfg.toffset); - if(sensors.devmode != cfg.devmode) sensors.setDebugMode(cfg.devmode); + if(sensors.toffset != toffset) sensors.setTempOffset(toffset); + if(sensors.devmode != devmode) sensors.setDebugMode(devmode); } else{ - Serial.println("[E][BTLE][CONFIG] saving error!"); + log_w("[W][BTLE][CONFIG] save return false with %s",value.c_str()); } } }; void onRead(BLECharacteristic* pCharacteristic) { - if (FAMILY == "ESP32-C3") return; + // if (FAMILY == "ESP32-C3") return; bleServerConfigRefresh(); } }; @@ -98,12 +102,12 @@ class MyConfigCallbacks : public BLECharacteristicCallbacks { // Status BLE callbacks class MyStatusCallbacks : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic* pCharacteristic) { - if (FAMILY == "ESP32-C3") return; + // if (FAMILY == "ESP32-C3") return; std::string value = pCharacteristic->getValue(); - if (value.length() > 0 && cfg.getTrackStatusValues(value.c_str())) { + if (value.length() > 0 && getTrackStatusValues(value.c_str())) { log_v("[E][BTLE][STATUS] "+String(value.c_str())); - gui.setTrackValues(cfg.track.spd,cfg.track.kms); - gui.setTrackTime(cfg.track.hrs,cfg.track.min,cfg.track.seg); + gui.setTrackValues(track.spd,track.kms); + gui.setTrackTime(track.hrs,track.min,track.seg); } else { Serial.println("[E][BTLE][STATUS] write error!"); @@ -164,7 +168,7 @@ void bleServerInit() { void bleLoop() { static uint_fast64_t bleTimeStamp = 0; // notify changed value - if (deviceConnected && (millis() - bleTimeStamp > cfg.stime * 1000)) { // each 5 secs + if (deviceConnected && (millis() - bleTimeStamp > stime * 1000)) { // each 5 secs log_i("[BTLE] sending notification.."); log_d("[BTLE] %s",getNotificationData().c_str()); bleTimeStamp = millis(); @@ -189,3 +193,4 @@ void bleLoop() { bool bleIsConnected(){ return deviceConnected; } +#endif \ No newline at end of file diff --git a/include/bluetooth.hpp b/lib/ble/bluetooth.hpp similarity index 72% rename from include/bluetooth.hpp rename to lib/ble/bluetooth.hpp index ca593a09..589ccf49 100644 --- a/include/bluetooth.hpp +++ b/lib/ble/bluetooth.hpp @@ -1,15 +1,14 @@ +#ifndef DISABLE_BLE + #include -#include #include #include #include #include -#include -#include -#include -#include -#include - +#include "GUILib.hpp" +#include "Sensors.hpp" +#include "sniffer.hpp" +#include "Batterylib.hpp" #define SERVICE_UUID "c8d1d262-861f-4082-947e-f383a259aaf3" #define CHARAC_DATA_UUID "b0f332a8-a5aa-4f3f-bb43-f99e7791ae01" @@ -19,4 +18,5 @@ void bleLoop(); void bleServerInit(); bool bleIsConnected(); -void bleServerConfigRefresh(); \ No newline at end of file +void bleServerConfigRefresh(); +#endif \ No newline at end of file diff --git a/lib/cli/cli.cpp b/lib/cli/cli.cpp new file mode 100644 index 00000000..183cd60c --- /dev/null +++ b/lib/cli/cli.cpp @@ -0,0 +1,338 @@ +#ifndef DISABLE_CLI +#include "cli.hpp" +#include +#include "cloud_influxdb.hpp" +#include "ConfigApp.hpp" + +bool setup_mode = false; +int setup_time = 10000; +bool first_run = true; + +TaskHandle_t xCliHandle; + + +void wcli_debug(char *args, Stream *response) { + Pair operands = wcli.parseCommand(args); + String param = operands.first(); + param.toUpperCase(); + bool dbgmode = param.equals("ON") || param.equals("1"); + debugEnable(dbgmode); + devmode = dbgmode; + sensors.setDebugMode(dbgmode); + #ifndef DISABLE_BATT + battery.debug = dbgmode; + #endif +} + +void wcli_klist(char *args, Stream *response) { + Pair operands = wcli.parseCommand(args); + String opt = operands.first(); + int key_count = PKEYS::KCOUNT; // Show all keys to configure + if (opt.equals("basic")) key_count = PKEYS::KBASIC; // Only show the basic keys to configure + response->printf("\n%11s \t%s \t%s \r\n", "KEYNAME", "DEFINED", "VALUE"); + response->printf("\n%11s \t%s \t%s \r\n", "=======", "=======", "====="); + + for (int i = 0; i < key_count; i++) { + if (i == PKEYS::KBASIC) continue; + if (i == PKEYS::KPASS) continue; + String key = cfg.getKey((CONFKEYS)i); + bool isDefined = cfg.isKey(key); + String defined = isDefined ? "custom " : "default"; + String value = ""; + if (isDefined) value = cfg.getValue(key); + response->printf("%11s \t%s \t%s \r\n", key, defined.c_str(), value.c_str()); + } + + response->printf("\r\nMore info: https://canair.io/docs/cli\r\n"); +} + +void wcli_kset(char *args, Stream *response) { + Pair operands = wcli.parseCommand(args); + String key = operands.first(); + String v = operands.second(); + if(cfg.saveAuto(key,v)){ + response->printf("saved key %s\t: %s\r\n", key, v); + } +} + +void wcli_uartpins(char *args, Stream *response) { + Pair operands = wcli.parseCommand(args); + if (operands.first().isEmpty() || operands.second().isEmpty()) { + response->printf("current TX/RX configured: %i/%i\r\n", sTX, sRX); + return; + } + int sTX = operands.first().toInt(); + int sRX = operands.second().toInt(); + if (sTX >= 0 && sRX >= 0) { + saveSensorPins(sTX, sRX); + } + else + response->println("invalid pins values"); +} + +bool validBattLimits(float min, float max){ + return (min >= 3.0 && min <= 5.0 && max <=5.0 && max >= 3.0); +} + +void wcli_battvLimits(char *args, Stream *response) { + #ifndef DISABLE_BATT + Pair operands = wcli.parseCommand(args); + float battMin = operands.first().toFloat(); + float battMax = operands.second().toFloat(); + if (validBattLimits(battMin, battMax)) { + response->printf("Battery limits: Vmin: %2.2f Vmax: %2.2f\r\n", battMin, battMax); + battery.setBattLimits(battMin, battMax); + cfg.saveFloat(CONFKEYS::KBATVMI,battMin); + cfg.saveFloat(CONFKEYS::KBATVMX,battMax); + } + else { + response->println("-->[BATT] !invalid battery value! Current values:"); + battery.printLimits(); + } + #endif +} + +void wcli_chargLimits(char *args, Stream *response) { + #ifndef DISABLE_BATT + Pair operands = wcli.parseCommand(args); + float battMin = operands.first().toFloat(); + float battMax = operands.second().toFloat(); + if (validBattLimits(battMin, battMax)) { + response->printf("Battery charging limits: Vmin: %2.2f Vmax: %2.2f\r\n", battMin, battMax); + battery.setChargLimits(battMin, battMax); + cfg.saveFloat(CONFKEYS::KCHRVMI,battMin); + cfg.saveFloat(CONFKEYS::KCHRVMX,battMax); + } + else { + response->println("-->[BATT] !invalid battery value! Current values:"); + battery.printLimits(); + } + #endif +} + +void wcli_stime(char *args, Stream *response) { + Pair operands = wcli.parseCommand(args); + int stime = operands.first().toInt(); + if (stime >= 5) { + saveSampleTime(stime); + sensors.setSampleTime(stime); + } + else + response->println("invalid sample time"); +} + +void wcli_stype_error(Stream *response) { + // SENSORS::SSCD30-1 is the seperator (see Sensors.hpp) + response->printf("invalid UART sensor type! Choose one into 0-%i:\r\n",SENSORS::SSCD30-1); + for (int i = 0; i <= SENSORS::SSCD30-1; i++) response->printf("%i\t%s\r\n", i, sensors.getSensorName((SENSORS)i)); +} + +void wcli_stype(char *args, Stream *response) { + Pair operands = wcli.parseCommand(args); + String stype = operands.first(); + if(stype.length()==0){ + wcli_stype_error(response); + return; + } + int type = stype.toInt(); + if (type > SENSORS::SSCD30-1 || type < 0) wcli_stype_error(response); // SENSORS::SSCD30-1 is the seperator (see Sensors.hpp) + else { + saveSensorType(type); + response->printf("\nselected UART sensor model\t: %s\r\n", sensors.getSensorName((SENSORS)type)); + response->println("Please reboot to changes apply"); + } +} + +void wcli_sgeoh (char *args, Stream *response) { + Pair operands = wcli.parseCommand(args); + String geoh = operands.first(); + if (geoh.length() > 5) { + geoh.toLowerCase(); + if (saveGeo(geoh)) ifxdbEnable(true); + } else { + response->println("\nInvalid localization. (Precision should be > to 5 chars).\r\n"); + response->println("Please visit:\033[0;33m http://bit.ly/geohashe\033[0m and please"); + response->println("\nchoose a geohash code of your fixed station position."); + } +} + +void wcli_sensors(Stream *response) { + response->printf("\r\nCanAirIO Sensorslib\t: %s\r\n",sensors.getLibraryVersion().c_str()); + int i = 0; + int count = sensors.getSensorsRegisteredCount(); + response->printf("Sensors count \t\t: %i (", count); + if (count > 0 && sensors.getSensorsRegistered()[0] == SENSORS::Auto) { + response->printf("%s,", sensors.getSensorName((SENSORS)sensors.getSensorsRegistered()[0])); + i = 1; + } + while (sensors.getSensorsRegistered()[i++] != 0) { + response->printf("%s,", sensors.getSensorName((SENSORS)sensors.getSensorsRegistered()[i-1])); + } + response->println(")"); +} + +void wcli_sensors_values(Stream *response) { + response->println("\r\nCurrent sensors values:"); + UNIT unit = sensors.getNextUnit(); + while(unit != UNIT::NUNIT) { + String uName = sensors.getUnitName(unit); + float uValue = sensors.getUnitValue(unit); + String uSymb = sensors.getUnitSymbol(unit); + response->printf(" %s:\t%02.1f\t%s\r\n", uName.c_str(), uValue, uSymb.c_str()); + unit = sensors.getNextUnit(); + } +} + +void wcli_info(char *args, Stream *response) { + response->println(); + response->print(getDeviceInfo()); + wcli.status(response); + wcli_sensors(response); + wcli_sensors_values(response); +} + +void wcli_exit(char *args, Stream *response) { + setup_time = 0; + setup_mode = false; +} + +void wcli_setup(char *args, Stream *response) { + setup_mode = true; + response->println("\r\nMain presets:\r\n"); + String canAirIOname = "Please first set your position (using \"sgeoh\" command)"; + if(geo.length()>5)canAirIOname = getStationName(); + response->printf("CanAirIO device id\t: %s\r\n", canAirIOname.c_str()); + response->printf("Device factory id\t: %s\r\n", getAnaireDeviceId().c_str()); + response->printf("Sensor geohash id\t: %s\r\n", geo.length() == 0 ? "undefined" : geo.c_str()); + response->printf("WiFi current status\t: %s\r\n", WiFi.status() == WL_CONNECTED ? "connected" : "disconnected"); + response->printf("Sensor sample time \t: %d\r\n", stime); + response->printf("UART sensor model \t: %s\r\n", sensors.getSensorName((SENSORS)stype)); + response->printf("UART sensor TX pin\t: %d\r\n", sTX == -1 ? PMS_TX : sTX); + response->printf("UART sensor RX pin\t: %d\r\n", sRX == -1 ? PMS_RX : sRX); + response->printf("Current debug mode\t: %s\r\n", devmode == true ? "enabled" : "disabled"); + + wcli_klist((char *)"basic",response); + + response->printf("\r\nType \"klist\" for advanced settings\r\n"); + response->printf("Type \"help\" for available commands details\r\n"); + response->printf("Type \"info\" for sytem and sensors details\r\n"); +} + +void wcli_reboot(char *args, Stream *response) { + wd.execute(); +} + +void wcli_swipe(char *args, Stream *response) { + Pair operands = wcli.parseCommand(args); + String deviceId = operands.first(); + if (deviceId.equals(getAnaireDeviceId())) { + response->println("Clearing device to defaults.."); + wcli.clearSettings(); + cfg.clear(); + } + else { + response->println("\nPlease type \"swipe\" and the factory device id to confirm. (it showed in setup command)"); + } +} + +void wcli_clear(char *args, Stream *response){ + wcli.shell->clear(); +} + +void cliTask(void *param) { + for ( ; ; ) { + wcli.loop(); + vTaskDelay(60 / portTICK_PERIOD_MS); + } + vTaskDelete( NULL ); +} + +void cliTaskInit() { +#ifndef DISABLE_CLI + xTaskCreatePinnedToCore(cliTask, "cliTask ", 4000, NULL, 1, &xCliHandle, 1); +#endif +} + +int32_t cliTaskStackFree(){ + return uxTaskGetStackHighWaterMark(xCliHandle); +} + +const char logo[] = +" \r\n" +" .d8888b. d8888 d8b 8888888 .d88888b. \r\n" +"d88P Y88b d88888 Y8P 888 d88P\" \"Y88b \r\n" +"888 888 d88P888 888 888 888 \r\n" +"888 8888b. 88888b. d88P 888 888 888d888 888 888 888 \r\n" +"888 \"88b 888 \"88b d88P 888 888 888P\" 888 888 888 \r\n" +"888 888 .d888888 888 888 d88P 888 888 888 888 888 888 \r\n" +"Y88b d88P 888 888 888 888 d8888888888 888 888 888 Y88b. .d88P \r\n" +" \"Y8888P\" \"Y888888 888 888 d88P 888 888 888 8888888 \"Y88888P\" \r\n" +" \r\n" +"\r\n" +"" +; + +void initRemoteShell(){ +#ifndef DISABLE_CLI_TELNET + if (wcli.isTelnetRunning()) wcli.shellTelnet->attachLogo(logo); +#endif +} + +class mESP32WifiCLICallbacks : public ESP32WifiCLICallbacks { + void onWifiStatus(bool isConnected) {} + + void onHelpShow() {} + + void onNewWifi(String ssid, String passw) { saveWifi(ssid, passw); } +}; + +void initShell(){ + wcli.shell->attachLogo(logo); + wcli.setCallback(new mESP32WifiCLICallbacks()); + wcli.setSilentMode(true); + // wcli.disableAutoConnect(); + // Main Commands: + wcli.add("reboot",&wcli_reboot, "\tperform an ESP32 reboot"); + wcli.add("swipe", &wcli_swipe, "\t\tfactory settings reset. (needs confirmation)"); + wcli.add("debug", &wcli_debug, "\t\tenable debug mode"); + wcli.add("stime", &wcli_stime, "\t\tset the sample time (seconds)"); + wcli.add("stype", &wcli_stype, "\t\tset the sensor type (UART)"); + wcli.add("sgeoh", &wcli_sgeoh, "\t\tset geohash. Type help for more details."); + wcli.add("spins", &wcli_uartpins, "\t\tset the UART pins TX RX"); + wcli.add("battv", &wcli_battvLimits, "\t\tset battery min/max voltage"); + wcli.add("charg", &wcli_chargLimits, "\t\tset battery charging min/max voltage"); + wcli.add("kset", &wcli_kset, "\t\tset preference key (e.g on/off or 1/0 or text)"); + wcli.add("klist", &wcli_klist, "\t\tlist valid preference keys"); + wcli.add("info", &wcli_info, "\t\tget device information"); + wcli.add("exit", &wcli_exit, "\t\texit of the setup mode. AUTO EXIT in 10 seg! :)"); + wcli.add("clear", &wcli_clear, "\t\tclear shell"); + wcli.add("setup", &wcli_setup, "\t\tTYPE THIS WORD to enter to SAFE MODE setup"); + + wcli.begin("CanAirIO"); +} + +/** + * @brief WiFi CLI init and CanAirIO custom commands + **/ +void cliInit() { + initShell(); // shell config and launched via Serial + initRemoteShell(); // if it is enable, launched via Telnet + + // Configuration loop: + // 10 seconds for reconfiguration or first use case. + // for reconfiguration type disconnect and switch the "output" mode + uint32_t start = millis(); + if (cfg.getBool(CONFKEYS::KFAILSAFE, true)) + { + wcli.shell->setBannerText("setup"); + while (setup_mode || (millis() - start < setup_time)) wcli.loop(); + wcli.shell->setBannerText("CanAirIO"); + Serial.println(); + if (setup_time == 0) + Serial.println("==>[INFO] Settings saved. Booting..\r\n"); + else + Serial.println("==>[INFO] Time for initial setup over. Booting..\r\n"); + } + Serial.println(); +} +#endif \ No newline at end of file diff --git a/src/cli.hpp b/lib/cli/cli.hpp similarity index 56% rename from src/cli.hpp rename to lib/cli/cli.hpp index d5cce491..c999dd1f 100644 --- a/src/cli.hpp +++ b/lib/cli/cli.hpp @@ -1,8 +1,10 @@ #ifndef DISABLE_CLI #include -#include -#include +#include +#include "Batterylib.hpp" +#include "logmem.hpp" +#include "Watchdog.hpp" void cliInit(); void cliTaskInit(); diff --git a/lib/configlib/ConfigApp.cpp b/lib/configlib/ConfigApp.cpp index ca77b928..9c3ad8e8 100644 --- a/lib/configlib/ConfigApp.cpp +++ b/lib/configlib/ConfigApp.cpp @@ -1,16 +1,51 @@ #include "ConfigApp.hpp" -#define X(kname, kreal, ktype) kreal, -char const *keys[] = { CONFIG_KEYS_LIST }; -#undef X - -#define X(kname, kreal, ktype) ktype, -int keys_type[] = { CONFIG_KEYS_LIST }; -#undef X - -void ConfigApp::init(const char app_name[]) { +uint64_t chipid; +String deviceId; +String dname; + +trackStatus track; +ifxdbValues ifx; + +int stime; +int stype; +int sTX; +int sRX; +double lat; +double lon; +String geo; + +String ssid; +String pass; + +String hassip; +String hassusr; +String hasspsw; +int16_t hasspt; + +bool isNewWifi; +bool devmode; +bool i2conly; +bool pax_enable; +bool solarmode; +uint32_t deepSleep; +float toffset; +float altoffset; +float sealevel; + +char* _app_name; +bool wifi_enable; +bool ifxdb_enable; +bool wifi_connected; + +Geohash geohash; + +RemoteConfigCallbacks* mRemoteConfigCallBacks = nullptr; + +void init(const char app_name[]) { _app_name = new char[strlen(app_name) + 1]; strcpy(_app_name, app_name); + cfg.init(_app_name); chipid = ESP.getEfuseMac(); deviceId = getDeviceId(); reload(); @@ -21,81 +56,54 @@ void ConfigApp::init(const char app_name[]) { if (devmode) Serial.println("-->[CONF] debug is enable."); } -void ConfigApp::reload() { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RO_MODE); - // device name or station name - dname = preferences.getString("dname", ""); +void reload() { // wifi settings - wifi_enable = preferences.getBool(getKey(CONFKEYS::KBWIFIEN).c_str(), false); - ssid = preferences.getString("ssid", ""); - pass = preferences.getString("pass", ""); + wifi_enable = cfg.getBool(CONFKEYS::KWIFIEN, false); + ssid = cfg.getString(CONFKEYS::KSSID, ""); + pass = cfg.getString(CONFKEYS::KPASS, ""); // influx db optional settings - ifxdb_enable = preferences.getBool(getKey(CONFKEYS::KBIFXENB).c_str(), false); - ifx.db = preferences.getString("ifxdb", ifx.db); - ifx.ip = preferences.getString("ifxip", ifx.ip); - ifx.pt = preferences.getInt("ifxpt", ifx.pt); + ifxdb_enable = cfg.getBool(CONFKEYS::KIFXENB, false); + ifx.db = cfg.getString(CONFKEYS::KIFXDB, ifx.db); + ifx.ip = cfg.getString(CONFKEYS::KIFXIP, ifx.ip); + ifx.pt = cfg.getInt(CONFKEYS::KIFXPT, ifx.pt); // station and sensor settings - lat = preferences.getDouble("lat", 0); - lon = preferences.getDouble("lon", 0); - geo = preferences.getString("geo", ""); - stime = preferences.getInt("stime", 5); - stype = preferences.getInt("stype", 0); - sTX = preferences.getInt("sTX", -1); - sRX = preferences.getInt("sRX", -1); - toffset = preferences.getFloat("toffset", 0.0); - altoffset = preferences.getFloat("altoffset", 0.0); - sealevel = preferences.getFloat("sealevel", 1013.25); - devmode = preferences.getBool("debugEnable", false); - pax_enable = preferences.getBool(getKey(CONFKEYS::KBPAXENB).c_str(), true); - i2conly = preferences.getBool("i2conly", false); - solarmode = preferences.getBool("solarEnable", false); - deepSleep = preferences.getInt("deepSleep", 0); - hassip = preferences.getString("hassip", ""); - hasspt = preferences.getInt("hasspt", 1883); - hassusr = preferences.getString("hassusr", ""); - hasspsw = preferences.getString("hasspsw", ""); - - preferences.end(); -} - -String ConfigApp::getCurrentConfig() { - StaticJsonDocument<1000> doc; - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RO_MODE); - doc["dname"] = preferences.getString("dname", ""); // device or station name - doc["stime"] = preferences.getInt("stime", 5); // sensor measure time - doc["stype"] = preferences.getInt("stype", 0); // sensor UART type; - doc["sRX"] = preferences.getInt("sRX", -1); // sensor UART type; - doc["sTX"] = preferences.getInt("sTX", -1); // sensor UART type; - doc["wenb"] = preferences.getBool(getKey(CONFKEYS::KBWIFIEN).c_str(), false); // wifi on/off - doc["ssid"] = preferences.getString("ssid", ""); // influxdb database name - doc["ienb"] = preferences.getBool(getKey(CONFKEYS::KBIFXENB).c_str(), false); // ifxdb on/off - doc["ifxdb"] = preferences.getString("ifxdb", ifx.db); // influxdb database name - doc["ifxip"] = preferences.getString("ifxip", ifx.ip); // influxdb database ip - doc["ifxpt"] = preferences.getInt("ifxpt", ifx.pt); // influxdb sensor tags - doc["geo"] = preferences.getString("geo", ""); // influxdb GeoHash tag - doc["denb"] = preferences.getBool("debugEnable", false); // debug mode enable - doc["penb"] = preferences.getBool(getKey(CONFKEYS::KBPAXENB).c_str(), true); // PaxCounter enable - doc["i2conly"] = preferences.getBool("i2conly", false); // force only i2c sensors - doc["sse"] = preferences.getBool("solarEnable", false); // Enable solar station - doc["deepSleep"] = preferences.getInt("deepSleep", 0); // deep sleep time in seconds - doc["toffset"] = preferences.getFloat("toffset", 0.0); // temperature offset - doc["altoffset"] = preferences.getFloat("altoffset",0.0);// altitude offset - doc["sealevel"] = preferences.getFloat("sealevel",1013.25);// altitude offset - doc["hassip"] = preferences.getString("hassip", ""); // Home Assistant MQTT server ip - doc["hasspt"] = preferences.getInt("hasspt", 1883); // Home Assistant MQTT server port - doc["hassusr"] = preferences.getString("hassusr", ""); // Home Assistant MQTT user - // doc["hasspsw"] = preferences.getString("hasspsw", "");// Home Assistant MQTT password - doc["lskey"] = lastKeySaved; // last key saved - doc["wmac"] = (uint16_t)(chipid >> 32); // chipid calculated in init - doc["anaireid"] = getStationName(); // deviceId for Anaire cloud - doc["wsta"] = wifi_connected; // current wifi state + lat = cfg.getDouble("lat", 0); + lon = cfg.getDouble("lon", 0); + geo = cfg.getString("geo", ""); + stime = cfg.getInt("stime", 5); + stype = cfg.getInt("stype", 0); + sTX = cfg.getInt("sTX", -1); + sRX = cfg.getInt("sRX", -1); + toffset = cfg.getFloat(CONFKEYS::KTOFFST, 0.0); + altoffset = cfg.getFloat(CONFKEYS::KALTOFST, 0.0); + sealevel = cfg.getFloat(CONFKEYS::KSEALVL, 1013.25); + devmode = cfg.getBool(CONFKEYS::KDEBUG, false); + pax_enable = cfg.getBool(CONFKEYS::KPAXENB, false); + i2conly = cfg.getBool(CONFKEYS::KI2CONLY, false); + solarmode = cfg.getBool(CONFKEYS::KSOLAREN, false); + deepSleep = cfg.getInt(CONFKEYS::KDEEPSLP, 0); + hassip = cfg.getString(CONFKEYS::KHASSIP, ""); + hasspt = cfg.getInt(CONFKEYS::KHASSPT, 1883); + hassusr = cfg.getString(CONFKEYS::KHASSUSR, ""); + hasspsw = cfg.getString(CONFKEYS::KHASSPW, ""); +} + +String getCurrentConfig() { + JsonDocument doc; + doc["wmac"] = (uint16_t)(chipid >> 32); // chipid calculated in init + doc["anaireid"] = getStationName(); // deviceId for Anaire cloud + doc["wsta"] = wifi_connected; // current wifi state doc["vrev"] = REVISION; doc["vflv"] = FLAVOR; doc["vtag"] = TARGET; doc["vmac"] = getDeviceId(); - preferences.end(); + doc["wenb"] = cfg.getBool(CONFKEYS::KWIFIEN, false); // wifi on/off + doc["ienb"] = cfg.getBool(CONFKEYS::KIFXENB, false); // ifxdb on/off + doc["denb"] = cfg.getBool(CONFKEYS::KDEBUG, false); // debug mode enable + doc["sse"] = cfg.getBool(CONFKEYS::KSOLAREN, false); // Enable solar station + doc["geo"] = cfg.getString("geo", ""); // influxdb GeoHash tag + doc["i2conly"] = cfg.getBool(CONFKEYS::KI2CONLY, false); // force only i2c sensors + doc["toffset"] = cfg.getFloat(CONFKEYS::KTOFFST, 0.0); // temperature offset String output; serializeJson(doc, output); #if CORE_DEBUG_LEVEL >= 3 @@ -105,415 +113,275 @@ String ConfigApp::getCurrentConfig() { Serial.println(""); #endif return output; -} - -void ConfigApp::setLastKeySaved(String key){ - lastKeySaved = key; -} - -void ConfigApp::saveString(String key, String value){ - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putString(key.c_str(), value.c_str()); - preferences.end(); - setLastKeySaved(key); -} - -void ConfigApp::saveString(CONFKEYS key, String value){ - saveString(getKey(key),value); -} - -String ConfigApp::getString(String key, String defaultValue){ - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RO_MODE); - String out = preferences.getString(key.c_str(), defaultValue); - preferences.end(); - return out; -} - -String ConfigApp::getString(CONFKEYS key, String defaultValue){ - return getString(getKey(key),defaultValue); -} - -void ConfigApp::saveInt(String key, int value){ - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putInt(key.c_str(), value); - preferences.end(); - setLastKeySaved(key); -} - -void ConfigApp::saveInt(CONFKEYS key, int value){ - saveInt(getKey(key),value); -} - -int32_t ConfigApp::getInt(String key, int defaultValue){ - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RO_MODE); - int32_t out = preferences.getInt(key.c_str(), defaultValue); - preferences.end(); - return out; -} - -int32_t ConfigApp::getInt(CONFKEYS key, int defaultValue){ - return getInt(getKey(key),defaultValue); -} - -void ConfigApp::saveBool(String key, bool value){ - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putBool(key.c_str(), value); - preferences.end(); - setLastKeySaved(key); -} - -void ConfigApp::saveBool(CONFKEYS key, bool value){ - saveBool(getKey(key),value); -} - -bool ConfigApp::getBool(String key, bool defaultValue){ - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RO_MODE); - bool out = preferences.getBool(key.c_str(), defaultValue); - preferences.end(); - return out; -} - -bool ConfigApp::getBool(CONFKEYS key, bool defaultValue){ - return getBool(getKey(key),defaultValue); -} - -void ConfigApp::saveFloat(String key, float value){ - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putFloat(key.c_str(), value); - preferences.end(); - setLastKeySaved(key); -} - -void ConfigApp::saveFloat(CONFKEYS key, float value){ - saveFloat(getKey(key),value); -} - -float ConfigApp::getFloat(String key, float defaultValue){ - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RO_MODE); - float out = preferences.getFloat(key.c_str(), defaultValue); - preferences.end(); - return out; -} - -float ConfigApp::getFloat(CONFKEYS key, float defaultValue){ - return getFloat(getKey(key),defaultValue); -} - -PreferenceType ConfigApp::keyType(String key) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RO_MODE); - PreferenceType type = preferences.getType(key.c_str()); - preferences.end(); - return type; -} - - - -bool ConfigApp::isKey(String key) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RO_MODE); - bool iskey = preferences.isKey(key.c_str()); - preferences.end(); - return iskey; -} - -bool ConfigApp::isKey(CONFKEYS key) { - return isKey(getKey(key)); -} - -String ConfigApp::getKey(CONFKEYS key) { - if (key < 0 || key > CONFKEYS::KCOUNT) return ""; - return String(keys[key]); -} - -ConfKeyType ConfigApp::getKeyType(CONFKEYS key) { - if (key < 0 || key > CONFKEYS::KCOUNT) return ConfKeyType::UNKNOWN; - return (ConfKeyType)keys_type[key]; -} - -ConfKeyType ConfigApp::getKeyType(String key) { - for (int i = 0; i < KCOUNT; i++) { - if (key.equals(keys[i])) return (ConfKeyType)keys_type[i]; - } - return ConfKeyType::UNKNOWN; -} -/** - * @brief DEPRECATED - */ -bool ConfigApp::saveDeviceName(String name) { - if (name.length() > 0) { - saveString("dname",name); - Serial.println("-->[CONF] set device name to: " + name); - return true; - } - DEBUG("[E][CONF] device name is empty!"); - return false; -} - -bool ConfigApp::saveSampleTime(int time) { +// StaticJsonDocument<1000> doc; +// doc["dname"] = preferences.getString("dname", ""); // device or station name +// doc["stime"] = preferences.getInt("stime", 5); // sensor measure time +// doc["stype"] = preferences.getInt("stype", 0); // sensor UART type; +// doc["sRX"] = preferences.getInt("sRX", -1); // sensor UART type; +// doc["sTX"] = preferences.getInt("sTX", -1); // sensor UART type; +// doc["ssid"] = preferences.getString("ssid", ""); // influxdb database name +// doc["ifxdb"] = preferences.getString("ifxdb", ifx.db); // influxdb database name +// doc["ifxip"] = preferences.getString("ifxip", ifx.ip); // influxdb database ip +// doc["ifxpt"] = preferences.getInt("ifxpt", ifx.pt); // influxdb sensor tags +// doc["penb"] = preferences.getBool(getKey(CONFKEYS::KBPAXENB).c_str(), true); // PaxCounter enable +// doc["deepSleep"] = preferences.getInt("deepSleep", 0); // deep sleep time in seconds +// doc["altoffset"] = preferences.getFloat("altoffset",0.0);// altitude offset +// doc["sealevel"] = preferences.getFloat("sealevel",1013.25);// altitude offset +// doc["hassip"] = preferences.getString("hassip", ""); // Home Assistant MQTT server ip +// doc["hasspt"] = preferences.getInt("hasspt", 1883); // Home Assistant MQTT server port +// doc["hassusr"] = preferences.getString("hassusr", ""); // Home Assistant MQTT user +// // doc["hasspsw"] = preferences.getString("hasspsw", "");// Home Assistant MQTT password +// doc["lskey"] = lastKeySaved; // last key saved +// doc["anaireid"] = getStationName(); // deviceId for Anaire cloud +// preferences.end(); +// String output; +// serializeJson(doc, output); +// #if CORE_DEBUG_LEVEL >= 3 +// char buf[1000]; +// serializeJsonPretty(doc, buf, 1000); +// Serial.printf("-->[CONF] response: %s", buf); +// Serial.println(""); +// #endif +// return output; +} + +bool saveSampleTime(int time) { if (time >= 5) { - saveInt("stime", time); + cfg.saveInt("stime", time); stime=time; Serial.printf("-->[CONF] set sample time to\t: %d\r\n", time); return true; } - DEBUG("[W][CONF] warning: sample time is too low!"); + // DEBUG("[W][CONF] warning: sample time is too low!"); return false; } /** - * @brief ConfigApp::saveSensorType + * @brief saveSensorType * @param type UART sensor type. Sync it with Android app * @return true (compatibility) */ -bool ConfigApp::saveSensorType(int type) { - saveInt("stype", type); +bool saveSensorType(int type) { + cfg.saveInt("stype", type); Serial.printf("-->[CONF] sensor device type\t: %d\r\n", type); return true; } /** - * @brief ConfigApp::saveSensorPins + * @brief saveSensorPins * @param tx UART sensor TX * @param rx UART sensor RX * @return true (compatibility) */ -bool ConfigApp::saveSensorPins(int tx, int rx) { - saveInt("sTX", tx); - saveInt("sRX", rx); +bool saveSensorPins(int tx, int rx) { + cfg.saveInt("sTX", tx); + cfg.saveInt("sRX", rx); Serial.printf("-->[CONF] sensor UART TX/RX\t: %d/%d\r\n", tx, rx); return true; } -int ConfigApp::getSensorType(){ +int getSensorType(){ return stype; } /** - * @brief ConfigApp::saveWifiEnable + * @brief saveWifiEnable * @param unit save the sensor UNIT selected * @return */ -bool ConfigApp::saveUnitSelected(int unit){ - saveInt("unit", unit); +bool saveUnitSelected(int unit){ + cfg.saveInt("unit", unit); Serial.printf("-->[CONF] default unit to \t: %d\r\n", unit); return true; } /** - * @brief ConfigApp::getUnitSelected + * @brief getUnitSelected * @return unit selected and saved by user (default PM2.5) */ -int ConfigApp::getUnitSelected(){ - return getInt("unit", 2); +int getUnitSelected(){ + return cfg.getInt("unit", 2); } -bool ConfigApp::saveTempOffset(float offset) { - saveFloat("toffset", offset); +bool saveTempOffset(float offset) { + cfg.saveFloat("toffset", offset); Serial.printf("-->[CONF] sensor temp offset\t: %0.2f\r\n", offset); return true; } -bool ConfigApp::saveAltitudeOffset(float offset) { - saveFloat("altoffset", offset); +bool saveAltitudeOffset(float offset) { + cfg.saveFloat("altoffset", offset); Serial.printf("-->[CONF] sensor altitude offset\t: %0.2f\r\n", offset); - if(mRemoteConfigCallBacks!=nullptr) this->mRemoteConfigCallBacks->onAltitudeOffset(offset); + if(mRemoteConfigCallBacks!=nullptr) mRemoteConfigCallBacks->onAltitudeOffset(offset); return true; } -bool ConfigApp::saveSeaLevel(float hpa) { - saveFloat("sealevel", hpa); +bool saveSeaLevel(float hpa) { + cfg.saveFloat("sealevel", hpa); Serial.printf("-->[CONF] sea level pressure\t: %0.2f\r\n", hpa); - if(mRemoteConfigCallBacks!=nullptr) this->mRemoteConfigCallBacks->onSeaLevelPressure(hpa); + if(mRemoteConfigCallBacks!=nullptr) mRemoteConfigCallBacks->onSeaLevelPressure(hpa); return true; } -bool ConfigApp::saveSSID(String ssid){ +// @deprecated +bool saveSSID(String ssid){ if (ssid.length() > 0) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putString("ssid", ssid); - preferences.end(); - setLastKeySaved("ssid"); - Serial.println("-->[CONF] WiFi SSID saved!"); + cfg.saveString(CONFKEYS::KSSID, ssid); return true; } - DEBUG("[W][CONF] empty Wifi SSID"); return false; } -bool ConfigApp::saveWifi(String ssid, String pass){ - if (ssid.length() > 0) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putString("ssid", ssid); - preferences.putString("pass", pass); - preferences.putBool(getKey(CONFKEYS::KBWIFIEN).c_str(), true); - preferences.end(); - setLastKeySaved("ssid"); - wifi_enable = true; - isNewWifi = true; // for execute wifi reconnect - Serial.println("-->[CONF] WiFi credentials saved!"); - log_i("[CONF] ssid:%s pass:%s",ssid,pass); - return true; +bool saveWifi(String ssid, String pass) { + if (ssid.length() > 0) { + cfg.saveBool(CONFKEYS::KWIFIEN, true); + wifi_enable = true; + bool new_wifi = !wcli.isSSIDSaved(ssid); + if (new_wifi) { + wcli.setSSID(ssid); + wcli.setPASW(pass); + wcli.wifiAPConnect(true); } - DEBUG("[W][CONF] empty Wifi SSID"); - return false; + else + wcli.wifiAPConnect(false); + delay(2000); + + if (!wcli.wifiValidation()) { + if (new_wifi) wcli.loadAP(wcli.getDefaultAP()); + if (!new_wifi) wcli.loadAP(ssid); + ssid = wcli.getCurrentSSID(); + pass = wcli.getCurrentPASW(); + log_w("[CONF] restored ssid:%s pass:%s", ssid, pass); + } + log_i("[CONF] ssid:%s pass:%s", ssid, pass); + cfg.saveString(CONFKEYS::KSSID, ssid); + cfg.saveString(CONFKEYS::KPASS, pass); + return true; // backward compatibility with the Android app + } + log_w("[W][CONF] empty Wifi SSID"); + return false; } -bool ConfigApp::saveInfluxDb(String db, String ip, int pt) { +bool saveInfluxDb(String db, String ip, int pt) { if (db.length() > 0 && ip.length() > 0) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putString("ifxdb", db); - preferences.putString("ifxip", ip); - if (pt > 0) preferences.putInt("ifxpt", pt); - preferences.putBool(getKey(CONFKEYS::KBIFXENB).c_str(), true); - preferences.end(); - setLastKeySaved("ifxdb"); + cfg.saveString("ifxdb", db); + cfg.saveString("ifxip", ip); + if (pt > 0) cfg.saveInt("ifxpt", pt); + cfg.saveBool(CONFKEYS::KIFXENB, true); ifxdb_enable = true; Serial.printf("-->[CONF] influxdb: %s@%s:%i\r\n",db.c_str(),ip.c_str(),pt); Serial.println("-->[CONF] influxdb config saved."); return true; } - DEBUG("[W][CONF] wrong InfluxDb params!"); + log_w("[W][CONF] wrong InfluxDb params!"); return false; } -bool ConfigApp::saveGeo(double lat, double lon, String geo){ - if (lat != 0 && lon != 0) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putDouble("lat", lat); - preferences.putDouble("lon", lon); - preferences.putString("geo", geo); - preferences.end(); - this->lat = lat; - this->lon = lon; - this->geo = geo; - setLastKeySaved("geo"); - Serial.printf("-->[CONF] New Geohash: %s \t: (%.4f,%.4f)\r\n",geo,lat,lon); +bool saveGeo(double latitude, double longitude, String geohash){ + if (latitude != 0 && longitude != 0) { + cfg.saveDouble("lat", latitude); + cfg.saveDouble("lon", longitude); + cfg.saveString("geo", geohash); + lat = latitude; + lon = longitude; + geo = geohash; + Serial.printf("-->[CONF] New Geohash: %s \t: (%.4f,%.4f)\r\n", geo, lat, lon); return true; } - DEBUG("[W][CONF] wrong GEO params!"); + log_w("[W][CONF] wrong GEO params!"); return false; } -bool ConfigApp::saveGeo(String geo){ - if (geo.length() > 5) { - float lat; - float lon; - geohash.decode(geo.c_str(),geo.length(),&lon,&lat); - log_i("[CONF] Geohash decoder: %s (%.4f,%.4f)\r\n",geo,lat,lon); - cfg.saveGeo(lat,lon, geo); - setLastKeySaved("geo"); +bool saveGeo(String geoh){ + if (geoh.length() > 5) { + float latitude; + float longitude; + geohash.decode(geoh.c_str(),geoh.length(),&longitude,&latitude); + log_i("[CONF] Geohash decoder: %s (%.4f,%.4f)\r\n", geoh, latitude, longitude); + saveGeo(latitude,longitude, geoh); return true; } - DEBUG("[W][CONF] wrong GEO params!"); + log_w("[W][CONF] wrong GEO params!"); return false; } -bool ConfigApp::wifiEnable(bool enable) { - saveBool(CONFKEYS::KBWIFIEN, enable); +bool wifiEnable(bool enable) { + cfg.saveBool(CONFKEYS::KWIFIEN, enable); wifi_enable = enable; Serial.println("-->[CONF] updating WiFi state\t: " + String(enable)); return true; } -bool ConfigApp::ifxdbEnable(bool enable) { - saveBool(CONFKEYS::KBIFXENB, enable); +bool ifxdbEnable(bool enable) { + cfg.saveBool(CONFKEYS::KIFXENB, enable); ifxdb_enable = enable; Serial.println("-->[CONF] updating InfluxDB state\t: " + String(enable)); return true; } -bool ConfigApp::debugEnable(bool enable) { - saveBool(CONFKEYS::KDEBUG, enable); +bool debugEnable(bool enable) { + cfg.saveBool(CONFKEYS::KDEBUG, enable); devmode = enable; Serial.println("-->[CONF] new debug mode\t: " + String(enable)); return true; } -bool ConfigApp::paxEnable(bool enable) { - saveBool(CONFKEYS::KBPAXENB, enable); +bool paxEnable(bool enable) { + cfg.saveBool(CONFKEYS::KPAXENB, enable); pax_enable = enable; Serial.println("-->[CONF] new PaxCounter mode\t: " + String(enable)); return true; } -bool ConfigApp::solarEnable(bool enable) { - saveBool(CONFKEYS::KBSOLARE, enable); +bool solarEnable(bool enable) { + cfg.saveBool(CONFKEYS::KSOLAREN, enable); solarmode = enable; Serial.println("-->[CONF] Solar Station mode\t: " + String(enable)); return true; } -bool ConfigApp::saveDeepSleep(int seconds){ - saveInt(CONFKEYS::KIDEEPSL, seconds); +bool saveDeepSleep(int seconds){ + cfg.saveInt(CONFKEYS::KDEEPSLP, seconds); deepSleep = seconds; Serial.printf("-->[CONF] deep sleep time to\t: %d\r\n", seconds); return true; } -bool ConfigApp::saveI2COnly(bool enable) { - saveBool(CONFKEYS::KBI2COLY, enable); +bool saveI2COnly(bool enable) { + cfg.saveBool(CONFKEYS::KI2CONLY, enable); i2conly = enable; Serial.println("-->[CONF] forced only i2c sensors\t: " + String(enable)); return true; } -bool ConfigApp::saveHassIP(String ip) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putString("hassip", ip); - preferences.end(); - setLastKeySaved("hassip"); +bool saveHassIP(String ip) { + cfg.saveString("hassip", ip); Serial.printf("-->[CONF] Hass local IP \t: %s saved.\r\n",ip.c_str()); return true; } -bool ConfigApp::saveHassPort(int port) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putInt("hasspt", port); - preferences.end(); - setLastKeySaved("hasspt"); +bool saveHassPort(int port) { + cfg.saveInt("hasspt", port); Serial.printf("-->[CONF] Hass Port \t: %i saved.\r\n", port); return true; } -bool ConfigApp::saveHassUser(String user) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putString("hassusr", user); - preferences.end(); - setLastKeySaved("hassusr"); +bool saveHassUser(String user) { + cfg.saveString("hassusr", user); Serial.printf("-->[CONF] Hass User \t: %s saved.\r\n", user.c_str()); return true; } -bool ConfigApp::saveHassPassword(String passw) { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.putString("hasspsw", passw); - preferences.end(); - setLastKeySaved("hasspsw"); +bool saveHassPassword(String passw) { + cfg.saveString("hasspsw", passw); if (devmode) Serial.printf("-->[CONF] Hass password %s saved.\r\n", passw.c_str()); else Serial.println("-->[CONF] Hass password saved."); return true; } -bool ConfigApp::save(const char *json) { - StaticJsonDocument<1000> doc; +bool save(const char *json) { + JsonDocument doc; auto error = deserializeJson(doc, json); if (error) { Serial.print(F("[E][CONF] deserialize Json failed with code ")); @@ -531,21 +399,21 @@ bool ConfigApp::save(const char *json) { uint16_t cmd = doc["cmd"].as(); String act = doc["act"] | ""; - if (doc.containsKey("dname")) return saveDeviceName(doc["dname"] | ""); - if (doc.containsKey("stime")) return saveSampleTime(doc["stime"] | 0); - if (doc.containsKey("stype")) return saveSensorType(doc["stype"] | 0); - if (doc.containsKey("ifxdb")) return saveInfluxDb(doc["ifxdb"] | "", doc["ifxip"] | "", doc["ifxpt"] | 0); - if (doc.containsKey("pass") && doc.containsKey("ssid")) return saveWifi(doc["ssid"] | "", doc["pass"] | ""); - if (doc.containsKey("ssid")) return saveSSID(doc["ssid"] | ""); - if (doc.containsKey("lat")) return saveGeo(doc["lat"].as(), doc["lon"].as(), doc["geo"] | ""); - if (doc.containsKey("toffset")) return saveTempOffset(doc["toffset"].as()); - if (doc.containsKey("altoffset")) return saveAltitudeOffset(doc["altoffset"].as()); - if (doc.containsKey("sealevel")) return saveSeaLevel(doc["sealevel"].as()); - if (doc.containsKey("hassip")) return saveHassIP(doc["hassip"] | ""); - if (doc.containsKey("hasspt")) return saveHassPort(doc["hasspt"] | 1883); - if (doc.containsKey("hassusr")) return saveHassUser(doc["hassusr"] | ""); - if (doc.containsKey("hasspsw")) return saveHassPassword(doc["hasspsw"] | ""); - if (doc.containsKey("deepSleep")) return saveDeepSleep(doc["deepSleep"] | 0); + // if (doc.containsKey("dname")) return saveDeviceName(doc["dname"] | ""); + if (doc["stime"].is()) return saveSampleTime(doc["stime"] | 0); + if (doc["stype"].is()) return saveSensorType(doc["stype"] | 0); + if (doc["ifxdb"].is()) return saveInfluxDb(doc["ifxdb"] | "", doc["ifxip"] | "", doc["ifxpt"] | 0); + if (doc["pass"].is() && doc["ssid"].is()) return saveWifi(doc["ssid"] | "", doc["pass"] | ""); + if (doc["ssid"].is()) return saveSSID(doc["ssid"] | ""); + if (doc["lat"].is()) return saveGeo(doc["lat"].as(), doc["lon"].as(), doc["geo"] | ""); + if (doc["toffset"].is()) return saveTempOffset(doc["toffset"].as()); + if (doc["altoffset"].is()) return saveAltitudeOffset(doc["altoffset"].as()); + if (doc["sealevel"].is()) return saveSeaLevel(doc["sealevel"].as()); + if (doc["hassip"].is()) return saveHassIP(doc["hassip"] | ""); + if (doc["hasspt"].is()) return saveHassPort(doc["hasspt"] | 1883); + if (doc["hassusr"].is()) return saveHassUser(doc["hassusr"] | ""); + if (doc["hasspsw"].is()) return saveHassPassword(doc["hasspsw"] | ""); + if (doc["deepSleep"].is()) return saveDeepSleep(doc["deepSleep"] | 0); // some actions with chopid validation (for security reasons) if (cmd == ((uint16_t)(chipid >> 32)) && act.length() > 0) { @@ -556,7 +424,7 @@ bool ConfigApp::save(const char *json) { if (act.equals("pst")) return paxEnable(doc["penb"].as()); if (act.equals("sse")) return solarEnable(doc["sse"].as()); if (act.equals("cls")) clear(); - if (act.equals("rbt")) reboot(); + // if (act.equals("rbt")) reboot(); if (act.equals("clb")) performCO2Calibration(); return true; } else { @@ -565,25 +433,25 @@ bool ConfigApp::save(const char *json) { } } -bool ConfigApp::getTrackStatusValues(const char *json) { - StaticJsonDocument<200> doc; +bool getTrackStatusValues(const char *json) { + JsonDocument doc; auto error = deserializeJson(doc, json); if (error) { Serial.print(F("[E][CONF] deserialize Json failed with code ")); Serial.println(error.c_str()); return false; } - if (doc.containsKey("spd")) track.spd = doc["spd"] | 0.0; - if (doc.containsKey("kms")) track.kms = doc["kms"] | 0.0; - if (doc.containsKey("hrs")) track.hrs = doc["hrs"] | 0; - if (doc.containsKey("min")) track.min = doc["min"] | 0; - if (doc.containsKey("seg")) track.seg = doc["seg"] | 0; + if (doc["spd"].is()) track.spd = doc["spd"] | 0.0; + if (doc["kms"].is()) track.kms = doc["kms"] | 0.0; + if (doc["hrs"].is()) track.hrs = doc["hrs"] | 0; + if (doc["min"].is()) track.min = doc["min"] | 0; + if (doc["seg"].is()) track.seg = doc["seg"] | 0; return true; } -String ConfigApp::getDeviceId() { +String getDeviceId() { uint8_t baseMac[6]; // Get MAC address for WiFi station esp_read_mac(baseMac, ESP_MAC_WIFI_STA); @@ -592,20 +460,20 @@ String ConfigApp::getDeviceId() { return String(baseMacChr); } -String ConfigApp::getAnaireDeviceId() { +String getAnaireDeviceId() { uint32_t chipId = 0; for (int i = 0; i < 17; i = i + 8) chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; return String(chipId, HEX); } -String ConfigApp::getDeviceIdShort() { +String getDeviceIdShort() { String devId = getDeviceId(); devId = devId.substring(13); devId.replace(":",""); return devId; } -String ConfigApp::getStationName() { +String getStationName() { if (geo.isEmpty()) return getAnaireDeviceId(); String name = ""+geo.substring(0,3); // GeoHash ~70km https://en.wikipedia.org/wiki/Geohash String flavor = String(FLAVOR); @@ -618,77 +486,59 @@ String ConfigApp::getStationName() { return name; } -String ConfigApp::getVersion() { +String getVersion() { return "v"+String(VERSION)+"r"+String(REVISION)+String(TARGET); } -bool ConfigApp::isWifiEnable() { +bool isWifiEnable() { return wifi_enable; } -bool ConfigApp::isPaxEnable() { +bool isPaxEnable() { return pax_enable; } -bool ConfigApp::isIfxEnable() { +bool isIfxEnable() { return ifxdb_enable; } -void ConfigApp::setWifiConnected(bool connected){ +void setWifiConnected(bool connected){ wifi_connected = connected; } -bool ConfigApp::isWifiConnected() { +bool isWifiConnected() { return wifi_connected; } -void ConfigApp::clear() { - std::lock_guard lck(config_mtx); - preferences.begin(_app_name, RW_MODE); - preferences.clear(); - preferences.end(); +void clear() { + cfg.clear(); Serial.println("-->[CONF] clear settings!"); delay(200); reboot(); } -void ConfigApp::reboot() { +void reboot() { Serial.println("-->[CONF] reboot.."); delay(100); wd.execute(); // ESP and WiFi reboot } -void ConfigApp::performCO2Calibration() { - if(mRemoteConfigCallBacks!=nullptr) this->mRemoteConfigCallBacks->onCO2Calibration(); -} - -void ConfigApp::saveBrightness(int value){ - saveInt("bright",value); +void performCO2Calibration() { + if(mRemoteConfigCallBacks!=nullptr) mRemoteConfigCallBacks->onCO2Calibration(); } -int32_t ConfigApp::getBrightness(){ - return getInt("bright",30); +void saveBrightness(int value){ + cfg.saveInt("bright",value); } -void ConfigApp::colorsInvertedEnable(bool enable){ - saveBool("cinverted",enable); +int32_t getBrightness(){ + return cfg.getInt("bright",30); } -void ConfigApp::DEBUG(const char *text, const char *textb) { - if (devmode) { - _debugPort.print(text); - if (textb) { - _debugPort.print(" "); - _debugPort.print(textb); - } - _debugPort.println(); - } +void colorsInvertedEnable(bool enable){ + cfg.saveBool("cinverted",enable); } -void ConfigApp::setRemoteConfigCallbacks(RemoteConfigCallbacks* pCallbacks){ +void setRemoteConfigCallbacks(RemoteConfigCallbacks* pCallbacks){ mRemoteConfigCallBacks = pCallbacks; } - -#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_CFGHANDLER) -ConfigApp cfg; -#endif diff --git a/lib/configlib/ConfigApp.hpp b/lib/configlib/ConfigApp.hpp index 8b8e9047..317b7711 100644 --- a/lib/configlib/ConfigApp.hpp +++ b/lib/configlib/ConfigApp.hpp @@ -2,274 +2,114 @@ #define CanfigApp_hpp #include -#include -#include #include -#include - -#define RW_MODE false -#define RO_MODE true - -typedef enum { - INT, BOOL, FLOAT, STRING, UNKNOWN -} ConfKeyType; - -#define CONFIG_KEYS_LIST \ - X(KBWIFIEN, "wifiEnable", BOOL) \ - X(KBPAXENB, "paxEnable", BOOL) \ - X(KEMOTICO, "emoEnable", BOOL) \ - X(KBI2COLY, "i2conly", BOOL) \ - X(KFALTFST, "altoffset", FLOAT) \ - X(KFTOFFST, "toffset", FLOAT) \ - X(KTEMPUNT, "tunit", INT) \ - X(KBASIC, "-----", UNKNOWN) \ - X(KDEBUG, "debugEnable", BOOL) \ - X(KFLIPV, "flipVEnable", BOOL) \ - X(KBHOMEAS, "homeaEnable", BOOL) \ - X(KBANAIRE, "anaireEnable", BOOL) \ - X(KBIFXENB, "ifxEnable", BOOL) \ - X(KSIFXDB, "ifxdb", STRING) \ - X(KSIFXIP, "ifxip", STRING) \ - X(KIIFXPT, "ifxpt", INT) \ - X(KSHASSIP, "hassip", STRING) \ - X(KSHASSU, "hassusr", STRING) \ - X(KSHASSPW, "hasspsw", STRING) \ - X(KIHASSPT, "hasspt", INT) \ - X(KFSEALV, "sealevel", FLOAT) \ - X(KSTIME, "stime", INT) \ - X(KBATVMX, "battVmax", FLOAT) \ - X(KBATVMI, "battVmin", FLOAT) \ - X(KCHRVMX, "chrgVmin", FLOAT) \ - X(KCHRVMI, "chrgVmax", FLOAT) \ - X(KFAILSAFE, "fsafeEnable", BOOL) \ - X(KWKUPRST, "wkrstEnable", BOOL) \ - X(KBSOLARE, "solarEnable", BOOL) \ - X(KIDEEPSL, "deepSleep", INT) \ - X(KGEIGERP, "geigerPin", INT) \ - X(KCOUNT, "KCOUNT", UNKNOWN) - -#define X(kname, kreal, ktype) kname, -typedef enum CONFKEYS : size_t { CONFIG_KEYS_LIST } CONFKEYS; -#undef X +#include +#include +#include "Watchdog.hpp" class RemoteConfigCallbacks; -class ConfigApp { - public: - uint64_t chipid; - String deviceId; - String dname; - - int stime; - int stype; - int sTX; - int sRX; - double lat; - double lon; - String geo; - - String ssid; - String pass; - - String hassip; - String hassusr; - String hasspsw; - int16_t hasspt; - - struct ifxdbValues { - String db = "canairio"; - String ip = "influxdb.canair.io"; - uint16_t pt = 8086; - } ifx; - - bool isNewWifi; - - struct trackStatus { - float kms = 0.0; - float spd = 0.0; - int hrs = 0; - int min = 0; - int seg = 0; - } track; - - bool devmode; - - bool i2conly; - - bool pax_enable = true; - - bool solarmode = false; - - uint32_t deepSleep = 0; - - float toffset = 0.0; - - float altoffset = 0.0; - - float sealevel = 1013.25; - - void init(const char app_name[]); - - void reload(); - - bool save(const char* json); - - bool saveDeviceName(String name); - - bool saveSampleTime(int time); - - bool saveSensorType(int type); - - bool saveSensorPins(int tx, int rx); - - bool saveUnitSelected(int unit); - - int getUnitSelected(); - - bool saveSSID(String ssid); - - bool saveWifi(String ssid, String pass); - - bool saveInfluxDb(String db, String ip, int pt); - - bool saveGeo(String geo); - - bool saveGeo(double lat, double lon, String geo); - - bool wifiEnable(bool enable); - - bool ifxdbEnable(bool enable); - - bool debugEnable(bool enable); - - bool paxEnable(bool enable); - - bool solarEnable(bool enable); - - bool saveDeepSleep(int seconds); - - bool saveHassIP(String ip); - - bool saveHassPort(int port); - - bool saveHassPassword(String pass); - - bool saveHassUser(String user); - - void saveInt(String key, int value); - void saveInt(CONFKEYS key, int value); - - int32_t getInt(String key, int defaultValue); - int32_t getInt(CONFKEYS key, int defaultValue); - - bool getBool(String key, bool defaultValue); - bool getBool(CONFKEYS key, bool defaultValue); - void saveBool(String key, bool value); - void saveBool(CONFKEYS key, bool value); - - float getFloat(String key, float defaultValue = 0.0); - float getFloat(CONFKEYS key, float defaultValue = 0.0); - - void saveFloat(String key, float value); - void saveFloat(CONFKEYS key, float value); - - void saveString(String key, String value); - void saveString(CONFKEYS key, String value); - - String getString(String key, String defaultValue); - String getString(CONFKEYS key, String defaultValue); - - String getCurrentConfig(); - - bool isWifiEnable(); - - bool isPaxEnable(); - - bool isIfxEnable(); - - void setWifiConnected(bool connected); - - bool isWifiConnected(); - - String getDeviceId(); - - String getDeviceIdShort(); - - String getStationName(); - - String getAnaireDeviceId(); - - String getVersion(); - - int getSensorType(); - - void clear(); - - void reboot(); - - void saveBrightness(int value); - - int32_t getBrightness(); - - void colorsInvertedEnable(bool enable); - - bool getTrackStatusValues(const char *json); - - bool saveTempOffset(float offset); - - bool saveAltitudeOffset(float offset); - - bool saveSeaLevel(float hpa); - - void setRemoteConfigCallbacks(RemoteConfigCallbacks* pCallbacks); - - PreferenceType keyType(String key); - - bool isKey(String key); - - bool isKey(CONFKEYS key); - - String getKey(CONFKEYS key); - - ConfKeyType getKeyType(String key); - - ConfKeyType getKeyType(CONFKEYS key); - - private: - /// mutex for R/W actions - std::mutex config_mtx; - ///preferences main key - char* _app_name; - ///ESP32 preferences abstraction - Preferences preferences; - ///last key saved (for callback) - String lastKeySaved = ""; - ///device wifi on/off - bool wifi_enable; - ///InfluxDB cloud publication on/off - bool ifxdb_enable; - ///WiFi state - bool wifi_connected; - - Geohash geohash; - - RemoteConfigCallbacks* mRemoteConfigCallBacks = nullptr; - - void setLastKeySaved(String key); - - bool saveI2COnly(bool enable); - - void performCO2Calibration(); - - void DEBUG(const char* text, const char* textb = ""); - - // @todo use DEBUG_ESP_PORT ? -#ifdef WM_DEBUG_PORT - Stream& _debugPort = WM_DEBUG_PORT; -#else - Stream& _debugPort = Serial; // debug output stream ref -#endif -}; +typedef struct trackStatus { + float kms = 0.0; + float spd = 0.0; + int hrs = 0; + int min = 0; + int seg = 0; +} trackStatus; + +extern trackStatus track; + +typedef struct ifxdbValues { + String db = "canairio"; + String ip = "influxdb.canair.io"; + uint16_t pt = 8086; +} ifxdbValues; + +extern ifxdbValues ifx; + +extern uint64_t chipid; +extern String deviceId; +extern bool devmode; +extern char* _app_name; + +extern int stime; +extern int stype; +extern int sTX; +extern int sRX; +extern double lat; +extern double lon; +extern String geo; + +extern String ssid; +extern String pass; +extern bool isNewWifi; +extern bool wifi_enable; +extern bool wifi_connected; + +extern String hassip; +extern String hassusr; +extern String hasspsw; +extern int16_t hasspt; + +extern bool i2conly; +extern bool pax_enable; +extern bool solarmode; +extern uint32_t deepSleep; +extern float toffset; +extern float altoffset; +extern float sealevel; +extern bool ifxdb_enable; +extern Geohash geohash; + +extern RemoteConfigCallbacks* mRemoteConfigCallBacks; + +void init(const char app_name[]); +void reload(); +bool save(const char* json); +bool saveSampleTime(int time); +bool saveSensorType(int type); +bool saveSensorPins(int tx, int rx); +bool saveUnitSelected(int unit); +int getUnitSelected(); +bool saveSSID(String ssid); +bool saveWifi(String ssid, String pass); +bool saveInfluxDb(String db, String ip, int pt); +bool saveGeo(String geo); +bool saveGeo(double latitude, double longitude, String geohash); +bool wifiEnable(bool enable); +bool ifxdbEnable(bool enable); +bool debugEnable(bool enable); +bool paxEnable(bool enable); +bool solarEnable(bool enable); +bool saveDeepSleep(int seconds); +bool saveHassIP(String ip); +bool saveHassPort(int port); +bool saveHassPassword(String pass); +bool saveHassUser(String user); +String getCurrentConfig(); +bool isWifiEnable(); +bool isPaxEnable(); +bool isIfxEnable(); +void setWifiConnected(bool connected); +bool isWifiConnected(); +String getDeviceId(); +String getDeviceIdShort(); +String getStationName(); +String getAnaireDeviceId(); +String getVersion(); +int getSensorType(); +void clear(); +void reboot(); +void saveBrightness(int value); +int32_t getBrightness(); +void colorsInvertedEnable(bool enable); +bool getTrackStatusValues(const char* json); +bool saveTempOffset(float offset); +bool saveAltitudeOffset(float offset); +bool saveSeaLevel(float hpa); +void setRemoteConfigCallbacks(RemoteConfigCallbacks* pCallbacks); +bool saveI2COnly(bool enable); +void performCO2Calibration(); class RemoteConfigCallbacks { public: @@ -279,8 +119,4 @@ class RemoteConfigCallbacks { virtual void onSeaLevelPressure(float hpa); }; -#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_CFGHANDLER) -extern ConfigApp cfg; -#endif - #endif \ No newline at end of file diff --git a/lib/gui-utils-tft/src/TFTUtils.cpp b/lib/gui-utils-tft/src/TFTUtils.cpp index d4a576af..c1ee043e 100644 --- a/lib/gui-utils-tft/src/TFTUtils.cpp +++ b/lib/gui-utils-tft/src/TFTUtils.cpp @@ -31,8 +31,11 @@ void TFTUtils::displayInit() { pinMode(BUTTON_L, INPUT_PULLUP); pinMode(BUTTON_R, INPUT); #ifdef M5STICKCPLUS - M5.begin(true,true,false); // Initialize M5Stack without serial messages - M5.Beep.end(); + auto cfg = M5.config(); + M5.begin(cfg); + tft = M5.Display; + tft.setBrightness(80); + M5.update(); pinMode(36, INPUT); // UART port alternative for this board gpio_pulldown_dis(GPIO_NUM_25); // 36 and 25 pins share the same port gpio_pullup_dis(GPIO_NUM_25); // https://docs.m5stack.com/en/core/m5stickc_plus @@ -97,18 +100,19 @@ void TFTUtils::showStatus() { void TFTUtils::showMain() { showStatus(); - tft.setCursor(RCOLSTART, 204, 1); + tft.setTextFont(1); + tft.setCursor(RCOLSTART, 204); tft.println("BATT:"); updateBatteryValue(); - - tft.setCursor(RCOLSTART, 152, 2); + tft.setTextFont(2); + tft.setCursor(RCOLSTART, 152); tft.println("HEALTH:"); tft.setTextColor(TFT_WHITE, lightblue); - tft.setCursor(4, 152, 2); + tft.setCursor(4, 152); tft.println("TEMP:"); - tft.setCursor(4, 192, 2); + tft.setCursor(4, 192); tft.println("HUM: "); tft.fillRect(68, 152, 1, 74, TFT_GREY); @@ -131,18 +135,20 @@ void TFTUtils::showWindowBike(){ holdR = 0; delay(100); showStatus(); - tft.setCursor(80, 204, 1); + tft.setTextFont(1); + tft.setCursor(80, 204); tft.println("BATT:"); updateBatteryValue(); - tft.setCursor(80, 152, 2); + tft.setTextFont(2); + tft.setCursor(80, 152); tft.println("HEALTH:"); tft.setTextColor(TFT_WHITE, lightblue); - tft.setCursor(4, 152, 2); + tft.setCursor(4, 152); tft.println("KM:"); - tft.setCursor(4, 192, 2); + tft.setCursor(4, 192); tft.println("TIME: "); tft.fillRect(68, 152, 1, 74, TFT_GREY); @@ -174,7 +180,7 @@ void TFTUtils::refreshInfoWindow() { tft.setTextFont(2); tft.setTextPadding(5); tft.setTextDatum(CR_DATUM); - tft.setCursor(0, 50, 2); + tft.setCursor(0, 50); tft.println(_info); } @@ -189,26 +195,27 @@ void TFTUtils::showSetup() { tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.drawLine(18,44,117,44,TFT_GREY); + tft.setTextFont(2); tft.setTextColor(TFT_WHITE, lightblue); - tft.setCursor(MARGINL, SSTART, 2); + tft.setCursor(MARGINL, SSTART); tft.println("BRIGHT:"); - tft.setCursor(MARGINL, SSTART+PRESETH, 2); + tft.setCursor(MARGINL, SSTART+PRESETH); tft.println("COLORS:"); - tft.setCursor(MARGINL, SSTART+PRESETH*2, 2); + tft.setCursor(MARGINL, SSTART+PRESETH*2); tft.println("WiFi:"); - tft.setCursor(MARGINL, SSTART+PRESETH*3, 2); + tft.setCursor(MARGINL, SSTART+PRESETH*3); tft.println("STIME:"); - tft.setCursor(MARGINL, SSTART+PRESETH*4, 2); + tft.setCursor(MARGINL, SSTART+PRESETH*4); tft.println("CALIBRT:"); - tft.setCursor(MARGINL, SSTART+PRESETH*5, 2); + tft.setCursor(MARGINL, SSTART+PRESETH*5); tft.println("INFO:"); - tft.setCursor(MARVALL, SSTART+PRESETH*5, 2); + tft.setCursor(MARVALL, SSTART+PRESETH*5); tft.println(String(VERSION)); updateInvertValue(); @@ -258,7 +265,8 @@ void TFTUtils::invertScreen(){ void TFTUtils::updateInvertValue(){ tft.fillRect(MARVALL, SSTART+PRESETH, 54, 13, TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - tft.setCursor(MARVALL, SSTART+PRESETH, 2); + tft.setTextFont(2); + tft.setCursor(MARVALL, SSTART+PRESETH); if(inv) tft.println("normal"); else tft.println("inverted"); } @@ -302,7 +310,8 @@ void TFTUtils::updateWifiMode(){ if (state < 1) return; tft.fillRect(MARVALL, SSTART+PRESETH*2, 54, 13, TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - tft.setCursor(MARVALL, SSTART+PRESETH*2, 2); + tft.setTextFont(2); + tft.setCursor(MARVALL, SSTART+PRESETH*2); if(_wifi_enable) tft.println("On"); else if (_pax_enable) tft.println("PAX"); else tft.println("Off"); @@ -324,7 +333,8 @@ void TFTUtils::updateSampleTime() { if (state < 1) return; tft.fillRect(MARVALL, SSTART + PRESETH * 3, 54, 13, TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - tft.setCursor(MARVALL, SSTART + PRESETH * 3, 2); + tft.setTextFont(2); + tft.setCursor(MARVALL, SSTART + PRESETH * 3); tft.println("" + String(_sample_time) + "s"); } @@ -334,7 +344,8 @@ void TFTUtils::updateCalibrationField(){ calibretts = millis(); tft.fillRect(MARVALL, SSTART + PRESETH * 4, 54, 13, TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - tft.setCursor(MARVALL, SSTART + PRESETH * 4, 2); + tft.setTextFont(2); + tft.setCursor(MARVALL, SSTART + PRESETH * 4); if (_calibration_counter > 0){ log_i("[TGUI] coundown to calibration: %i",_calibration_counter); tft.println("" + String(_calibration_counter--) + "s"); @@ -453,7 +464,7 @@ void TFTUtils::suspend() { welcomeAddMessage("Suspending.."); delay(2000); #ifdef M5STICKCPLUS - M5.Axp.PowerOff(); + M5.Power.powerOff(); #else int r = digitalRead(TFT_BL); digitalWrite(TFT_BL, !r); @@ -483,7 +494,7 @@ void TFTUtils::displayMainUnit(String uName, String uSymbol) { void TFTUtils::displayBottomLine(String msg) { tft.setTextFont(1); tft.fillRect(1, 230, 99, 8, TFT_BLACK); - tft.setCursor(2, 232, 1); + tft.setCursor(2, 232); tft.println(msg.substring(0,16).c_str()); } @@ -862,7 +873,8 @@ void TFTUtils::setBrightness(uint32_t value) { void TFTUtils::notifyBrightness() { #ifdef M5STICKCPLUS - M5.Axp.ScreenBreath(brightness); + // M5.Axp.ScreenBreath(brightness); + M5.Display.setBrightness(brightness); #else ledcWrite(pwmLedChannelTFT, brightness); #endif diff --git a/lib/gui-utils-tft/src/TFTUtils.hpp b/lib/gui-utils-tft/src/TFTUtils.hpp index e37e668f..5137ee3d 100644 --- a/lib/gui-utils-tft/src/TFTUtils.hpp +++ b/lib/gui-utils-tft/src/TFTUtils.hpp @@ -3,7 +3,7 @@ #include #ifdef M5STICKCPLUS -#include +#include #else #include #endif @@ -50,9 +50,11 @@ class GUIUserPreferencesCallbacks; class TFTUtils { public: TFTUtils(void){}; - +#ifndef M5STICKCPLUS TFT_eSPI tft = TFT_eSPI(); // Invoke custom library - +#else + M5GFX tft; +#endif enum WIFI_MODE { WIFI_OFF, WIFI_ON }; void displayInit(); @@ -132,8 +134,7 @@ class TFTUtils { const int pwmLedChannelTFT = 0; #ifdef M5STICKCPLUS - int backlight[5] = {5, 20, 30, 50, 80}; - + int backlight[5] = {60, 65, 70, 90, 120}; #else int backlight[5] = {10, 30, 60, 120, 220}; #endif diff --git a/src/logmem.cpp b/lib/logmem/logmem.cpp similarity index 85% rename from src/logmem.cpp rename to lib/logmem/logmem.cpp index 1918ac79..04d544c4 100644 --- a/src/logmem.cpp +++ b/lib/logmem/logmem.cpp @@ -1,9 +1,10 @@ #include +#include "ConfigApp.hpp" uint32_t heap_size = 0; void logMemory(const char* msg) { - if (!cfg.devmode) return; + if (!devmode) return; if (heap_size == 0) heap_size = ESP.getFreeHeap(); heap_size = heap_size - ESP.getFreeHeap(); Serial.printf("-->[HEAP] %s bytes used\t: %05db/%03dKb\r\n", msg, heap_size, ESP.getFreeHeap() / 1024); @@ -12,7 +13,6 @@ void logMemory(const char* msg) { void logMemoryObjects(){ Serial.printf("-->[HEAP] sizeof sensors\t: %05ub\r\n", sizeof(sensors)); - Serial.printf("-->[HEAP] sizeof config \t: %05ub\r\n", sizeof(cfg)); Serial.printf("-->[HEAP] sizeof GUI \t: %05ub\r\n", sizeof(gui)); Serial.printf("-->[HEAP] free memory \t: %05ub\r\n", ESP.getFreeHeap()); } \ No newline at end of file diff --git a/include/logmem.hpp b/lib/logmem/logmem.hpp similarity index 79% rename from include/logmem.hpp rename to lib/logmem/logmem.hpp index b627b51a..5638b830 100644 --- a/include/logmem.hpp +++ b/lib/logmem/logmem.hpp @@ -1,6 +1,5 @@ -#include #include #include - + void logMemory(const char* msg); void logMemoryObjects(); \ No newline at end of file diff --git a/lib/lorawan/lorawan.cpp b/lib/lorawan/lorawan.cpp index 16f2ad06..6e7c9291 100644 --- a/lib/lorawan/lorawan.cpp +++ b/lib/lorawan/lorawan.cpp @@ -28,7 +28,7 @@ bool GO_DEEP_SLEEP = false; RTC_DATA_ATTR lmic_t RTC_LMIC; -DynamicJsonDocument jsonBuffer(4096); +JsonDocument jsonBuffer; CayenneLPP lpp(160); //JsonObject root = jsonBuffer.to(); JsonObject LORA_DATA = jsonBuffer.to(); diff --git a/src/power.cpp b/lib/power/power.cpp similarity index 87% rename from src/power.cpp rename to lib/power/power.cpp index 518b8c26..6df899a3 100644 --- a/src/power.cpp +++ b/lib/power/power.cpp @@ -4,7 +4,9 @@ void prepairShutdown() { #ifndef M5STICKCPLUS + #ifndef DISABLE_BATT digitalWrite(ADC_EN, LOW); + #endif delay(10); //rtc_gpio_init(GPIO_NUM_14); //rtc_gpio_set_direction(GPIO_NUM_14, RTC_GPIO_MODE_OUTPUT_ONLY); @@ -27,7 +29,7 @@ void powerCompleteShutdown(){ esp_deep_sleep_start(); #endif #ifdef M5STICKCPLUS - M5.Axp.PowerOff(); + M5.Power.powerOff(); #endif } @@ -46,7 +48,7 @@ void powerDeepSleepTimer(int seconds) { Serial.flush(); prepairShutdown(); #ifdef M5STICKCPLUS - M5.Axp.DeepSleep(seconds*1000000); + M5.Power.deepSleep(seconds*1000000); #endif esp_sleep_enable_timer_wakeup(seconds * 1000000ULL); #ifdef TTGO_TDISPLAY @@ -63,19 +65,19 @@ void powerLightSleepTimer(int seconds) { esp_light_sleep_start(); #endif #ifdef M5STICKCPLUS - M5.Axp.LightSleep(seconds*1000000); + M5.Power.lightSleep(seconds*1000000); #endif } void powerEnableSensors() { - if(cfg.devmode) Serial.println("-->[POWR] == enable sensors =="); + if(devmode) Serial.println("-->[POWR] == enable sensors =="); // init all sensors (step-up to 5V with enable pin) pinMode(MAIN_HW_EN_PIN, OUTPUT); digitalWrite(MAIN_HW_EN_PIN, HIGH); // step-up on } void powerDisableSensors() { - if(cfg.devmode) Serial.println("-->[POWR] == disable sensors =="); + if(devmode) Serial.println("-->[POWR] == disable sensors =="); digitalWrite(MAIN_HW_EN_PIN, LOW); // step-up off } @@ -106,20 +108,22 @@ float powerESP32TempRead(){ } void powerLoop() { + #ifndef DISABLE_BATT static uint32_t powerTimeStamp = 0; // timestamp for check low power if ((millis() - powerTimeStamp > 30 * 1000)) { // check it every 5 seconds powerTimeStamp = millis(); float vbat = battery.getVoltage(); if (vbat > 3.0 && vbat < BATTERY_MIN_V) { Serial.println("-->[POWR] Goto DeepSleep (VBat too low)"); - if (cfg.solarmode) - powerDeepSleepTimer(cfg.deepSleep); + if (solarmode) + powerDeepSleepTimer(deepSleep); else powerCompleteShutdown(); } #ifdef CONFIG_IDF_TARGET_ESP32S3 - if (cfg.devmode) Serial.printf("-->[POWR] CPU Temperature\t: %02.1f°C\r\n", powerESP32TempRead()); + if (devmode) Serial.printf("-->[POWR] CPU Temperature\t: %02.1f°C\r\n", powerESP32TempRead()); #endif log_i("[HEAP] Min:%d Max:%d\t: %d\r\n", ESP.getMinFreeHeap(), ESP.getMaxAllocHeap(), ESP.getFreeHeap()); } + #endif } diff --git a/include/power.hpp b/lib/power/power.hpp similarity index 100% rename from include/power.hpp rename to lib/power/power.hpp diff --git a/lib/preferences/preferences-keys.h b/lib/preferences/preferences-keys.h new file mode 100644 index 00000000..cbd7305a --- /dev/null +++ b/lib/preferences/preferences-keys.h @@ -0,0 +1,35 @@ +#define CONFIG_KEYS_LIST \ + X(KWIFIEN, "wifiEnable", BOOL) \ + X(KSSID, "ssid", STRING) \ + X(KPASS, "pass", STRING) \ + X(KPAXENB, "paxEnable", BOOL) \ + X(KEMOTICO, "emoEnable", BOOL) \ + X(KI2CONLY, "i2conly", BOOL) \ + X(KALTOFST, "altoffset", FLOAT) \ + X(KTOFFST, "toffset", FLOAT) \ + X(KTEMPUNT, "tunit", INT) \ + X(KBASIC, "-----", UNKNOWN) \ + X(KDEBUG, "debugEnable", BOOL) \ + X(KFLIPV, "flipVEnable", BOOL) \ + X(KHOMEAS, "homeaEnable", BOOL) \ + X(KANAIRE, "anaireEnable", BOOL) \ + X(KIFXENB, "ifxEnable", BOOL) \ + X(KIFXDB, "ifxdb", STRING) \ + X(KIFXIP, "ifxip", STRING) \ + X(KIFXPT, "ifxpt", INT) \ + X(KHASSIP, "hassip", STRING) \ + X(KHASSUSR, "hassusr", STRING) \ + X(KHASSPW, "hasspsw", STRING) \ + X(KHASSPT, "hasspt", INT) \ + X(KSEALVL, "sealevel", FLOAT) \ + X(KSTIME, "stime", INT) \ + X(KBATVMX, "battVmax", FLOAT) \ + X(KBATVMI, "battVmin", FLOAT) \ + X(KCHRVMX, "chrgVmin", FLOAT) \ + X(KCHRVMI, "chrgVmax", FLOAT) \ + X(KFAILSAFE, "fsafeEnable", BOOL) \ + X(KWKUPRST, "wkrstEnable", BOOL) \ + X(KSOLAREN, "solarEnable", BOOL) \ + X(KDEEPSLP, "deepSleep", INT) \ + X(KGEIGERP, "geigerPin", INT) \ + X(KCOUNT, "KCOUNT", UNKNOWN) diff --git a/src/MACPool.cpp b/lib/sniffer/MACPool.cpp similarity index 100% rename from src/MACPool.cpp rename to lib/sniffer/MACPool.cpp diff --git a/include/MACPool.hpp b/lib/sniffer/MACPool.hpp similarity index 100% rename from include/MACPool.hpp rename to lib/sniffer/MACPool.hpp diff --git a/src/sniffer.cpp b/lib/sniffer/sniffer.cpp similarity index 88% rename from src/sniffer.cpp rename to lib/sniffer/sniffer.cpp index 22952567..694f4f45 100644 --- a/src/sniffer.cpp +++ b/lib/sniffer/sniffer.cpp @@ -76,7 +76,7 @@ void sniffer(void* buf, wifi_promiscuous_pkt_type_t type) { pax_count = listOfMAC.size(); if (pax_count != last_pax_count) { - if(cfg.devmode) Serial.printf("-->[WIFI] new PAX count found\t: %d\r\n",pax_count); + if(devmode) Serial.printf("-->[WIFI] new PAX count found\t: %d\r\n",pax_count); last_pax_count = pax_count; } delay(10); @@ -121,11 +121,11 @@ void snifferStop () { void snifferLoop() { static uint32_t snifferTimeStamp = 0; // timestamp for sensor loop check data - if ((millis() - snifferTimeStamp > cfg.stime / 5 * (uint32_t)500)) { // sample time for each capture + if ((millis() - snifferTimeStamp > stime / 5 * (uint32_t)500)) { // sample time for each capture snifferTimeStamp = millis(); - if (!cfg.isWifiEnable() && cfg.isPaxEnable() && !sniffer_start) snifferInit(); - else if (!cfg.isWifiEnable() && cfg.isPaxEnable() && sniffer_start) wifiScanChannels(); - else if (!cfg.isWifiEnable() && !cfg.isPaxEnable() && sniffer_start) snifferStop(); + if (!isWifiEnable() && isPaxEnable() && !sniffer_start) snifferInit(); + else if (!isWifiEnable() && isPaxEnable() && sniffer_start) wifiScanChannels(); + else if (!isWifiEnable() && !isPaxEnable() && sniffer_start) snifferStop(); } } diff --git a/include/sniffer.hpp b/lib/sniffer/sniffer.hpp similarity index 88% rename from include/sniffer.hpp rename to lib/sniffer/sniffer.hpp index 0dc4db42..d91737c3 100644 --- a/include/sniffer.hpp +++ b/lib/sniffer/sniffer.hpp @@ -1,6 +1,6 @@ #include #include -#include +#include "ConfigApp.hpp" using namespace std; #include diff --git a/lib/watchdoglib/Watchdog.cpp b/lib/watchdoglib/Watchdog.cpp index b9a5f0bc..15d22604 100644 --- a/lib/watchdoglib/Watchdog.cpp +++ b/lib/watchdoglib/Watchdog.cpp @@ -1,62 +1,75 @@ #include +void Watchdog::feed() { + log_v("[WDOG] soft watchdog feeded."); + timerWrite(timer, 0); // reset timer (feed watchdog) +#ifdef ESP32C3_AIRGRADIENT + log_v("[WDOG] external watchdog feeded."); + digitalWrite(2, HIGH); + delay(25); + digitalWrite(2, LOW); +#endif +} + void Watchdog::loop() { - static uint_fast64_t timeStamp = 0; // timestamp for loop check - if ((millis() - timeStamp > 1000)) { - timeStamp = millis(); - timerWrite(timer, 0); //reset timer (feed watchdog) + static uint_fast64_t timeStamp = 0; // timestamp for loop check + if ((millis() - timeStamp > 10000)) { // feed each 10sec + timeStamp = millis(); + feed(); #ifdef FORCE_WATCHDOG - if (resetvar++ == FORCE_WATCHDOG_TIME * 60) { - resetvar = 0; - Serial.print("-->[WDOG] Watchdog running force reboot in "); - Serial.print(WATCHDOG_TIME); - Serial.println(" seconds."); - delay(WATCHDOG_TIME * 2 * 1000); // force to do watchdog - } -#endif + if (resetvar++ == FORCE_WATCHDOG_TIME * 60) { + resetvar = 0; + Serial.print("-->[WDOG] Watchdog running force reboot in "); + Serial.print(WATCHDOG_TIME); + Serial.println(" seconds."); + delay(WATCHDOG_TIME * 2 * 1000); // force to do watchdog } +#endif + } } void IRAM_ATTR resetModule() { - Serial.println("-->[WDOG] Watchdog reached, rebooting.."); - digitalWrite(MAIN_HW_EN_PIN, LOW); - esp_wifi_disconnect(); - delay(200); - esp_wifi_stop(); - delay(200); - esp_wifi_deinit(); - digitalWrite(MAIN_HW_EN_PIN, HIGH); - delay(200); - ESP.restart(); + Serial.println("-->[WDOG] Watchdog reached, rebooting.."); + digitalWrite(MAIN_HW_EN_PIN, LOW); + esp_wifi_disconnect(); + delay(200); + esp_wifi_stop(); + delay(200); + esp_wifi_deinit(); + digitalWrite(MAIN_HW_EN_PIN, HIGH); + delay(200); + ESP.restart(); } void Watchdog::init() { - timer = timerBegin(0, 80, true); // timer 0, div 80 - timerAttachInterrupt(timer, &resetModule, true); // setting callback - timerAlarmWrite(timer, WATCHDOG_TIME * 1000000, false); // set time in us - timerAlarmEnable(timer); // enable interrupt - - Serial.print("-->[WDOG] watchdog check each\t: "); - Serial.print(WATCHDOG_TIME); - Serial.println(" seconds."); + timer = timerBegin(0, 80, true); // timer 0, div 80 + timerAttachInterrupt(timer, &resetModule, true); // setting callback + timerAlarmWrite(timer, WATCHDOG_TIME * 1000000, false); // set time in us + timerAlarmEnable(timer); // enable interrupt + +#ifdef ESP32C3_AIRGRADIENT + pinMode(2, OUTPUT); + feed(); +#endif + Serial.print("-->[WDOG] watchdog check each\t: "); + Serial.print(WATCHDOG_TIME); + Serial.println(" seconds."); #ifdef FORCE_WATCHDOG - Serial.print("-->[WDOG] watchdog force reboot each "); - Serial.print(FORCE_WATCHDOG_TIME); - Serial.println(" minutes."); + Serial.print("-->[WDOG] watchdog force reboot each "); + Serial.print(FORCE_WATCHDOG_TIME); + Serial.println(" minutes."); #endif } void Watchdog::pause() { - timerAlarmDisable(timer); // disable interrupt + timerAlarmDisable(timer); // disable interrupt } void Watchdog::resume() { - timerAlarmEnable(timer); // enable interrupt + timerAlarmEnable(timer); // enable interrupt } -void Watchdog::execute() { - resetModule(); -} +void Watchdog::execute() { resetModule(); } #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_WATCHDOGHANDLER) Watchdog wd; diff --git a/lib/watchdoglib/Watchdog.hpp b/lib/watchdoglib/Watchdog.hpp index 113a1763..4e458039 100644 --- a/lib/watchdoglib/Watchdog.hpp +++ b/lib/watchdoglib/Watchdog.hpp @@ -29,6 +29,8 @@ class Watchdog void execute(); + void feed(); + void loop(); private: diff --git a/src/cloud_anaire.cpp b/lib/wifi/cloud_anaire.cpp similarity index 79% rename from src/cloud_anaire.cpp rename to lib/wifi/cloud_anaire.cpp index 8bc8df9e..2c14bf23 100644 --- a/src/cloud_anaire.cpp +++ b/lib/wifi/cloud_anaire.cpp @@ -1,6 +1,4 @@ #include -#include -#include /****************************************************************************** * A N A I R E M Q T T M E T H O D S @@ -11,9 +9,9 @@ MQTTClient client(MQTT_BUFFER_SIZE); void anairePublish() { static uint_fast64_t mqttTimeStamp = 0; - uint32_t ptime = cfg.stime; + uint32_t ptime = stime; if (ptime 0) ptime = cfg.deepSleep; + if(!solarmode && deepSleep > 0) ptime = deepSleep; if (millis() - mqttTimeStamp > ptime * 1000) { mqttTimeStamp = millis(); @@ -22,11 +20,11 @@ void anairePublish() { float temp = sensors.getTemperature(); if (temp == 0.0) temp = sensors.getCO2temp(); - StaticJsonDocument doc; + JsonDocument doc; char buffer[MQTT_BUFFER_SIZE]; - doc["id"] = cfg.getStationName(); - doc["ver"] = cfg.getVersion(); + doc["id"] = getStationName(); + doc["ver"] = getVersion(); doc["CO2"] = String(sensors.getCO2()); doc["humidity"] = String(humi); doc["temperature"] = String(temp); @@ -38,9 +36,11 @@ void anairePublish() { doc["pm10"] = sensors.getPM10(); doc["cpm"] = String(sensors.getGeigerCPM()); doc["usvh"] = String(sensors.getGeigerMicroSievertHour()); - doc["geo"] = cfg.geo; + doc["geo"] = geo; + #ifndef DISABLE_BATT doc["battery"] = String(battery.getCharge()); doc["VBat"] = String(battery.getVoltage()); + #endif doc["co"] = String(sensors.getCO()); doc["nh3"] = String(sensors.getNH3()); doc["no2"] = String(sensors.getNO2()); @@ -48,7 +48,7 @@ void anairePublish() { size_t n = serializeJson(doc, buffer); if (client.publish(ANAIRE_TOPIC, buffer, n)) { - if (cfg.devmode) Serial.printf("-->[MQTT] Anaire published\t: payload size: %d\t:)\r\n", n); + if (devmode) Serial.printf("-->[MQTT] Anaire published\t: payload size: %d\t:)\r\n", n); } else { if(client.lastError()!=0) Serial.printf("[E][MQTT] Anaire publish error \t: %d\r\n",client.lastError()); @@ -59,21 +59,21 @@ void anairePublish() { static uint_fast64_t mqttDelayedStamp = 0; void anaireConnect() { - if (!(cfg.isWifiEnable() && WiFi.isConnected())) return; + if (!(isWifiEnable() && WiFi.isConnected())) return; if (millis() - mqttDelayedStamp > MQTT_DELAYED_TIME * 1000) { - if (cfg.devmode) Serial.printf("-->[MQTT] %s\t: ", ANAIRE_HOST); + if (devmode) Serial.printf("-->[MQTT] %s\t: ", ANAIRE_HOST); int mqtt_try = 0; - while (mqtt_try++ < MQTT_RETRY_CONNECTION && !client.connect(cfg.getStationName().c_str())) { + while (mqtt_try++ < MQTT_RETRY_CONNECTION && !client.connect(getStationName().c_str())) { delay(100); } if (mqtt_try >= MQTT_RETRY_CONNECTION && !client.connected()) { mqttDelayedStamp = millis(); - if (cfg.devmode) Serial.println("connection failed!"); + if (devmode) Serial.println("connection failed!"); return; } mqttDelayedStamp = millis(); - if (cfg.devmode) Serial.println("connected!"); + if (devmode) Serial.println("connected!"); client.subscribe(ANAIRE_TOPIC); } } @@ -96,5 +96,6 @@ void anaireLoop () { } client.loop(); delay(10); + if (!client.connected()) anaireConnect(); anairePublish(); } \ No newline at end of file diff --git a/include/cloud_anaire.hpp b/lib/wifi/cloud_anaire.hpp similarity index 54% rename from include/cloud_anaire.hpp rename to lib/wifi/cloud_anaire.hpp index 93dae875..3745c5c5 100644 --- a/include/cloud_anaire.hpp +++ b/lib/wifi/cloud_anaire.hpp @@ -1,3 +1,10 @@ +#include +#include +#include +#include "Batterylib.hpp" +#include "mqtt_config.h" +#include "ConfigApp.hpp" + #define ANAIRE_HOST "mqtt.anaire.org" #define ANAIRE_TOPIC "measurement" #define ANAIRE_PORT 80 diff --git a/src/cloud_hass.cpp b/lib/wifi/cloud_hass.cpp similarity index 86% rename from src/cloud_hass.cpp rename to lib/wifi/cloud_hass.cpp index a8cd9ddd..9396b417 100644 --- a/src/cloud_hass.cpp +++ b/lib/wifi/cloud_hass.cpp @@ -1,6 +1,4 @@ #include -#include -#include /****************************************************************************** * H A S S M Q T T M E T H O D S @@ -36,7 +34,7 @@ void hassPubSensorPayload() { float temp = sensors.getTemperature(); if (temp == 0.0) temp = sensors.getCO2temp(); - StaticJsonDocument doc; + JsonDocument doc; char buffer[MQTT_BUFFER_SIZE]; doc["carbon_dioxide"] = String(sensors.getCO2()); @@ -50,8 +48,10 @@ void hassPubSensorPayload() { doc["pm4"] = String(sensors.getPM4()); doc["pm10"] = String(sensors.getPM10()); doc["signal_strength"] = String(getWifiRSSI()); + #ifndef DISABLE_BATT doc["battery"] = String(battery.getCharge()); doc["voltage"] = String(battery.getVoltage()); + #endif doc["cpm"] = String(sensors.getGeigerCPM()); doc["usvh"] = String(sensors.getGeigerMicroSievertHour()); doc["co"] = String(sensors.getCO()); @@ -61,21 +61,21 @@ void hassPubSensorPayload() { size_t n = serializeJson(doc, buffer); if (clientHass.publish(getStateTopic().c_str(), buffer, n)) { - if(cfg.devmode) Serial.printf ("-->[MQTT] HA local published\t: payload size: %d\r\n", n); + if(devmode) Serial.printf ("-->[MQTT] HA local published\t: payload size: %d\t:)\r\n", n); } else { Serial.printf("[E][MQTT] HA publish state error\t: %d\r\n",clientHass.lastError()); } } bool publishDiscoveryPayload(String name, String dclass, String unit) { - StaticJsonDocument doc; + JsonDocument doc; doc["name"] = getHostId()+name; // name of the entity - JsonObject device = doc.createNestedObject("device"); + JsonObject device = doc["device"].to(); device["manufacturer"] = "CanAirIO"; device["model"] = ""+String(FLAVOR); device["name"] = getHostId(); // name of the device device["sw_version"] = "v"+String(VERSION)+" rev"+String(REVISION); - JsonArray identifiers = device.createNestedArray("identifiers"); + JsonArray identifiers = device["identifiers"].to(); identifiers.add(getHostId()); // name of the device doc["state_topic"] = getStateTopic(); doc["state_class"] = "measurement", @@ -124,9 +124,9 @@ bool hassStatusSubscription() { void hassPublish() { if (!clientHass.connected()) return; static uint_fast64_t mqttTimeStamp = 0; - uint32_t ptime = cfg.stime; + uint32_t ptime = stime; if (ptime 0) ptime = cfg.deepSleep; + if(!solarmode && deepSleep > 0) ptime = deepSleep; if (millis() - mqttTimeStamp > ptime * 1000) { mqttTimeStamp = millis(); if (!hassConfigured) hassRegisterSensors(); @@ -136,15 +136,15 @@ void hassPublish() { } bool hassAuth() { - return clientHass.connect(cfg.getStationName().c_str(), cfg.hassusr.c_str(), cfg.hasspsw.c_str()); + return clientHass.connect(getStationName().c_str(), hassusr.c_str(), hasspsw.c_str()); } static uint_fast64_t mqttHassDelayedStamp = 0; void hassConnect() { - if (!(cfg.isWifiEnable() && WiFi.isConnected())) return; + if (!(isWifiEnable() && WiFi.isConnected())) return; if (millis() - mqttHassDelayedStamp > MQTT_DELAYED_TIME * 1000) { - Serial.printf("-->[MQTT] %s\t: ", cfg.hassip.c_str()); + if(devmode) Serial.printf("-->[MQTT] %s\t: ", hassip.c_str()); int mqtt_try = 0; while (mqtt_try++ < MQTT_RETRY_CONNECTION && !hassAuth()) { delay(100); @@ -153,17 +153,17 @@ void hassConnect() { mqttHassDelayedStamp = millis(); hassSubscribed = false; hassConfigured = false; - Serial.println("connection failed!"); - if (cfg.devmode) Serial.printf("-->[MQTT] %s\r\n",cfg.hassusr.c_str()); + if(devmode) Serial.println("connection failed!"); + if(devmode) Serial.printf("-->[MQTT] %s\r\n",hassusr.c_str()); return; } - Serial.println("connected!"); + if(devmode) Serial.println("connected!"); mqttHassDelayedStamp = millis(); } } bool isHassEnable() { - if (cfg.hassip.isEmpty()) { + if (hassip.isEmpty()) { hassInited = false; hassConfigured = false; hassSubscribed = false; @@ -179,7 +179,7 @@ bool hassIsConnected() { void hassInit() { if (!isHassEnable()) return; - clientHass.begin(cfg.hassip.c_str(), cfg.hasspt, netHass); + clientHass.begin(hassip.c_str(), hasspt, netHass); clientHass.onMessage(messageReceived); mqttHassDelayedStamp = millis() - MQTT_DELAYED_TIME * 1000; hassInited = true; @@ -190,7 +190,7 @@ void hassLoop () { if(!WiFi.isConnected()) return; if (!isHassEnable()) return; if (!clientHass.connected()) { - anaireInit(); + hassInit(); delay(10); } clientHass.loop(); diff --git a/include/cloud_hass.hpp b/lib/wifi/cloud_hass.hpp similarity index 61% rename from include/cloud_hass.hpp rename to lib/wifi/cloud_hass.hpp index ee917e5d..719a4282 100644 --- a/include/cloud_hass.hpp +++ b/lib/wifi/cloud_hass.hpp @@ -1,3 +1,10 @@ +#include +#include +#include +#include "Batterylib.hpp" +#include "ConfigApp.hpp" +#include "mqtt_config.h" +#include "wifi.hpp" #define HPREFIX "homeassistant/" #define HCOMP "sensor/" diff --git a/src/cloud_influxdb.cpp b/lib/wifi/cloud_influxdb.cpp similarity index 52% rename from src/cloud_influxdb.cpp rename to lib/wifi/cloud_influxdb.cpp index aafad3be..7064e532 100644 --- a/src/cloud_influxdb.cpp +++ b/lib/wifi/cloud_influxdb.cpp @@ -1,7 +1,6 @@ -#include -#include -#include -#include +#include +#include "cloud_influxdb.hpp" +#include "power.hpp" /****************************************************************************** * I N F L U X D B M E T H O D S @@ -14,17 +13,17 @@ bool enable_sensors; int ifx_error_count; bool influxDbIsConfigured() { - if(cfg.ifx.db.length() > 0 && cfg.ifx.ip.length() > 0 && cfg.geo.length()==0) { + if(ifx.db.length() > 0 && ifx.ip.length() > 0 && geo.length()==0) { Serial.println("[W][IFDB] ifxdb is configured but Location (GeoHash) is missing!"); } - return cfg.ifx.db.length() > 0 && cfg.ifx.ip.length() > 0 && cfg.geo.length() > 0; + return ifx.db.length() > 0 && ifx.ip.length() > 0 && geo.length() > 0; } void influxDbAddTags() { - sensor.addTag("mac",cfg.deviceId.c_str()); - sensor.addTag("geo3",cfg.geo.substring(0,3).c_str()); - sensor.addTag("name",cfg.getStationName().c_str()); - sensor.addTag("rev",cfg.getVersion()); + sensor.addTag("mac",deviceId.c_str()); + sensor.addTag("geo3",geo.substring(0,3).c_str()); + sensor.addTag("name",getStationName().c_str()); + sensor.addTag("rev",getVersion()); } void influxDbParseFields() { @@ -43,7 +42,7 @@ void influxDbParseFields() { sensor.addField("co2tmp",sensors.getCO2temp()); sensor.addField("tmp",temp); sensor.addField("hum",humi); - sensor.addField("geo",cfg.geo.c_str()); + sensor.addField("geo",geo.c_str()); sensor.addField("prs",sensors.getPressure()); sensor.addField("gas",sensors.getGas()); sensor.addField("nh3",sensors.getNH3()); @@ -52,11 +51,13 @@ void influxDbParseFields() { sensor.addField("alt",sensors.getAltitude()); sensor.addField("cpm",sensors.getGeigerCPM()); sensor.addField("usvh",sensors.getGeigerMicroSievertHour()); + #ifndef DISABLE_BATT sensor.addField("bat",battery.getCharge()); sensor.addField("vbat",battery.getVoltage()); + #endif sensor.addField("rssi",getWifiRSSI()); sensor.addField("heap",ESP.getFreeHeap()); - sensor.addField("name",cfg.getStationName().c_str()); + sensor.addField("name",getStationName().c_str()); } bool influxDbWrite() { @@ -71,63 +72,63 @@ bool influxDbWrite() { return true; } -void suspendDevice() { - if (!bleIsConnected()) { - if (cfg.solarmode && cfg.deepSleep > 0) { // sleep mode and ECO mode on - powerDeepSleepTimer(cfg.deepSleep); - } - else if (cfg.deepSleep > 0) { // sleep mode, ECO mode off - powerDisableSensors(); - enable_sensors = false; - } - } else { - if (!enable_sensors && !cfg.solarmode && cfg.deepSleep == 0) { // restore to normal mode - powerEnableSensors(); - enable_sensors = true; - sensors.setSampleTime(cfg.stime); - } - if (cfg.devmode) Serial.println(F("-->[IFDB] BLE client connected\t: skip shutdown")); - } -} +// void suspendDevice() { +// if (!bleIsConnected()) { +// if (solarmode && deepSleep > 0) { // sleep mode and ECO mode on +// powerDeepSleepTimer(deepSleep); +// } +// else if (deepSleep > 0) { // sleep mode, ECO mode off +// powerDisableSensors(); +// enable_sensors = false; +// } +// } else { +// if (!enable_sensors && !solarmode && deepSleep == 0) { // restore to normal mode +// powerEnableSensors(); +// enable_sensors = true; +// sensors.setSampleTime(stime); +// } +// if (devmode) Serial.println(F("-->[IFDB] BLE client connected\t: skip shutdown")); +// } +// } -void enableSensors() { - if (!enable_sensors) { - powerEnableSensors(); - sensors.setSampleTime(cfg.deepSleep); - sensors.init(); - enable_sensors = true; - Serial.printf("-->[HEAP] sizeof sensors\t: %04ub\r\n", sizeof(sensors)); - } -} +// void enableSensors() { +// if (!enable_sensors) { +// powerEnableSensors(); +// sensors.setSampleTime(deepSleep); +// sensors.init(); +// enable_sensors = true; +// Serial.printf("-->[HEAP] sizeof sensors\t: %04ub\r\n", sizeof(sensors)); +// } +// } void influxDbLoop() { static uint_fast64_t timeStamp = 0; - uint32_t ptime = cfg.stime; + uint32_t ptime = stime; if (ptime 0) { - ptime = cfg.deepSleep; - if (millis() - timeStamp > (ptime - WAIT_FOR_PM_SENSOR) * 1000) { - enableSensors(); // enable sensors before publish - } - } - if ((cfg.solarmode || cfg.deepSleep > 0 ) && millis() - timeStamp > (ptime - 2) * 1000) { - sensors.readAllSensors(); // read sensors after stabilization - delay(500); - } + // if (solarmode) ptime = MIN_PUBLISH_INTERVAL; + // if(!solarmode && deepSleep > 0) { + // ptime = deepSleep; + // if (millis() - timeStamp > (ptime - WAIT_FOR_PM_SENSOR) * 1000) { + // enableSensors(); // enable sensors before publish + // } + // } + // if ((solarmode || deepSleep > 0 ) && millis() - timeStamp > (ptime - 2) * 1000) { + // sensors.readAllSensors(); // read sensors after stabilization + // delay(500); + // } if (millis() - timeStamp > ptime * 1000) { timeStamp = millis(); - if (ifx_ready && sensors.isDataReady() && WiFi.isConnected() && cfg.isIfxEnable()) { + if (ifx_ready && sensors.isDataReady() && WiFi.isConnected() && isIfxEnable()) { if (influxDbWrite()){ - if(cfg.devmode) Serial.printf ("-->[IFDB] CanAirIO published \t: payload size: %d\t:)\r\n", sizeof(sensor)); + if(devmode) Serial.printf ("-->[IFDB] CanAirIO published \t: payload size: %d\t:)\r\n", sizeof(sensor)); gui.displayDataOnIcon(); - suspendDevice(); + // suspendDevice(); ifx_error_count = 0; } else { - Serial.printf("[E][IFDB] write error to %s@%s:%i \r\n",cfg.ifx.db.c_str(),cfg.ifx.ip.c_str(),cfg.ifx.pt); - if (cfg.solarmode && ifx_error_count++ > IFX_ERROR_COUNT_MAX) { - powerDeepSleepTimer(cfg.deepSleep); + Serial.printf("[E][IFDB] write error to %s@%s:%i \r\n",ifx.db.c_str(),ifx.ip.c_str(),ifx.pt); + if (solarmode && ifx_error_count++ > IFX_ERROR_COUNT_MAX) { + powerDeepSleepTimer(deepSleep); } } } @@ -135,13 +136,13 @@ void influxDbLoop() { } void influxDbInit() { - if (!ifx_ready && WiFi.isConnected() && cfg.isIfxEnable() && influxDbIsConfigured()) { - String url = "http://" + cfg.ifx.ip + ":" + String(cfg.ifx.pt); + if (!ifx_ready && WiFi.isConnected() && isIfxEnable() && influxDbIsConfigured()) { + String url = "http://" + ifx.ip + ":" + String(ifx.pt); influx.setInsecure(); - influx.setConnectionParamsV1(url.c_str(), cfg.ifx.db.c_str()); - if (cfg.devmode) Serial.printf("-->[IFDB] InfluxDB config \t: %s:%i\r\n", cfg.ifx.ip.c_str(), cfg.ifx.pt); + influx.setConnectionParamsV1(url.c_str(), ifx.db.c_str()); + if (devmode) Serial.printf("-->[IFDB] InfluxDB config \t: %s:%i\r\n", ifx.ip.c_str(), ifx.pt); influxDbAddTags(); - Serial.printf("-->[IFDB] %s\t: ", cfg.ifx.ip.c_str()); + Serial.printf("-->[IFDB] %s\t: ", ifx.ip.c_str()); int influx_retry = 0; while (influx_retry++ < IFX_RETRY_CONNECTION && !influx.validateConnection()) { delay(100); diff --git a/include/cloud_influxdb.hpp b/lib/wifi/cloud_influxdb.hpp similarity index 62% rename from include/cloud_influxdb.hpp rename to lib/wifi/cloud_influxdb.hpp index cf209ea6..50b9fd22 100644 --- a/include/cloud_influxdb.hpp +++ b/lib/wifi/cloud_influxdb.hpp @@ -1,3 +1,9 @@ +#include +#include +#include "Batterylib.hpp" +#include "wifi.hpp" +#include "ConfigApp.hpp" + #define IFX_RETRY_CONNECTION 5 // influxdb publish retry #define IFX_ERROR_COUNT_MAX 5 // max error count before full ESP restart diff --git a/lib/wifi/mqtt_config.h b/lib/wifi/mqtt_config.h new file mode 100644 index 00000000..f6b888c0 --- /dev/null +++ b/lib/wifi/mqtt_config.h @@ -0,0 +1,4 @@ +#define MQTT_RETRY_CONNECTION 1 // mqtt publish retry +#define MQTT_DELAYED_TIME 30 // mqtt retry connection delayed time +#define MQTT_BUFFER_SIZE 512 // mqtt buffer size + diff --git a/src/wifi.cpp b/lib/wifi/wifi.cpp similarity index 66% rename from src/wifi.cpp rename to lib/wifi/wifi.cpp index 4a3fe018..962bd4d6 100644 --- a/src/wifi.cpp +++ b/lib/wifi/wifi.cpp @@ -1,5 +1,14 @@ -#include #include +#include "OTAHandler.h" +#ifndef DISABLE_CLI +#include "cli.hpp" +#endif +#include "ConfigApp.hpp" +#include "cloud_influxdb.hpp" +#include "cloud_hass.hpp" +#include "cloud_anaire.hpp" +#include "Watchdog.hpp" +#include "power.hpp" /****************************************************************************** * W I F I M E T H O D S @@ -49,7 +58,7 @@ void onUpdateMessage(const char* msg) { } String getHostId() { - return "CanAirIO" + cfg.getDeviceIdShort(); + return "CanAirIO" + getDeviceIdShort(); } void otaInit() { @@ -64,44 +73,34 @@ void otaInit() { void wifiCloudsInit() { influxDbInit(); - if (cfg.getBool(CONFKEYS::KBANAIRE,false)) anaireInit(); - if (cfg.getBool(CONFKEYS::KBHOMEAS,false)) hassInit(); - else return; + if (cfg.getBool(CONFKEYS::KANAIRE,false)) anaireInit(); + if (cfg.getBool(CONFKEYS::KHOMEAS,false)) hassInit(); if (anaireIsConnected()) Serial.printf("-->[MQTT] %s\t: connected!\r\n", ANAIRE_HOST); + if (hassIsConnected()) Serial.printf("-->[MQTT] Home Assistant \t: connected!\r\n"); } -void wifiConnect(const char* ssid, const char* pass) { +void wifiConnect() { + if (!(wcli.getCurrentSSID().compareTo(ssid)==0)){ + saveWifi(ssid, pass); + return; + } Serial.print("-->[WIFI] connecting to wifi\t: "); Serial.print(ssid); - int wifi_retry = 0; - WiFi.begin(ssid, pass); - - if (FAMILY == "ESP32-C3") WiFi.setTxPower(WIFI_POWER_8_5dBm); + wcli.wifiAPConnect(false); - while (!WiFi.isConnected() && wifi_retry++ <= WIFI_RETRY_CONNECTION) { - Serial.print("."); - delay(500); // increment this delay on possible reconnect issues - } - delay(500); if (WiFi.isConnected()) { - cfg.isNewWifi = false; // flag for config via BLE - #ifndef DISABLE_CLI - if(!wcli.isSSIDSaved(ssid))wcli.saveNetwork(ssid, pass); - #endif Serial.println(" done."); - } else { - Serial.println("fail!\r\n[E][WIFI] disconnected!"); - } + } } void wifiInit() { - if (!WiFi.isConnected() && cfg.isWifiEnable() && cfg.ssid.length() > 0) { - wifiConnect(cfg.ssid.c_str(), cfg.pass.c_str()); + if (!WiFi.isConnected() && isWifiEnable() && ssid.length() > 0) { + wifiConnect(); } if(WiFi.isConnected()) { Serial.print("-->[WIFI] device network IP\t: "); Serial.println(WiFi.localIP()); - Serial.println("-->[WIFI] publish interval \t: " + String(cfg.stime * 2) + " sec."); + Serial.println("-->[WIFI] publish interval \t: " + String(stime * 2) + " sec."); otaInit(); wifiCloudsInit(); } @@ -122,18 +121,18 @@ void wifiRestart() { void wifiLoop() { static uint_least64_t wifiTimeStamp = 0; - if (millis() - wifiTimeStamp > 5000) { + if (millis() - wifiTimeStamp > 10000) { wifiTimeStamp = millis(); - if (cfg.isWifiEnable() && cfg.ssid.length() > 0 && !WiFi.isConnected()) { + setWifiConnected(WiFi.isConnected()); + if (isWifiEnable() && ssid.length() > 0 && !WiFi.isConnected()) { wifiInit(); } + if (!WiFi.isConnected()) return; influxDbInit(); - cfg.setWifiConnected(WiFi.isConnected()); + influxDbLoop(); // influxDB publication + if (cfg.getBool(CONFKEYS::KANAIRE, false)) anaireLoop(); + if (cfg.getBool(CONFKEYS::KHOMEAS, false)) hassLoop(); } - if (!WiFi.isConnected()) return; - influxDbLoop(); // influxDB publication - if (cfg.getBool(CONFKEYS::KBANAIRE,false)) anaireLoop(); - if (cfg.getBool(CONFKEYS::KBHOMEAS,false)) hassLoop(); } int getWifiRSSI() { @@ -142,25 +141,28 @@ int getWifiRSSI() { else return 0; } - +/** + * @brief get the general info on reduced width for TFT screens and CLI. +*/ String getDeviceInfo() { String info = getHostId() + "\r\n"; info = info + "Rev" + String(REVISION) + " v" + String(VERSION) + "\r\n"; - info = info + "" + cfg.getStationName() + "\r\n"; + info = info + "" + getStationName() + "\r\n"; info = info + String(FLAVOR) + "\r\n"; info = info + "IP: " + WiFi.localIP().toString() + "\r\n"; info = info + "OTA: " + String(TARGET) + " channel\r\n"; info = info + "==================\r\n"; info = info + "MEM: " + String(ESP.getFreeHeap() / 1024) + "Kb\r\n"; info = info + "GUI: " + String(gui.getStackFree() / 1024) + "Kb\r\n"; - info = info + "CLI: " + String(cliTaskStackFree() / 1024) + "Kb\r\n"; #ifdef CONFIG_IDF_TARGET_ESP32S3 info = info + "CPU: " + String(powerESP32TempRead()) + "°C\r\n"; #endif + #ifndef DISABLE_BATT info = info + "BAT: " + String(battery.getVoltage()) + "v "+String(battery.getCharge()) +"%\r\n"; + #endif return info; } void printWifiRSSI(){ - if (cfg.devmode) Serial.println("-->[WIFI] AP RSSI signal \t: " + String(getWifiRSSI()) + " dBm"); + if (devmode) Serial.println("-->[WIFI] AP RSSI signal \t: " + String(getWifiRSSI()) + " dBm"); } \ No newline at end of file diff --git a/lib/wifi/wifi.hpp b/lib/wifi/wifi.hpp new file mode 100644 index 00000000..5bc1c03f --- /dev/null +++ b/lib/wifi/wifi.hpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include "GUILib.hpp" +// #ifndef DISABLE_CLI +// #include "cli.hpp" +// #endif + +//#define IFX_RETRY_CONNECTION 5 // influxdb publish retry + +#define PUBLISH_INTERVAL 30 // publish to cloud each 30 seconds +#define WIFI_RETRY_CONNECTION 30 // 30 seconds wait for wifi connection + +void otaLoop(); +void wifiInit(); +void wifiStop(); +void wifiRestart(); +void wifiLoop(); + +int getWifiRSSI(); +void printWifiRSSI(); +String getDeviceInfo(); +String getHostId(); diff --git a/platformio.ini b/platformio.ini index fd248629..82242670 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ [platformio] default_envs = TTGO_TDISPLAY -;extra_configs = ../canairio_sensorlib/unified-lib-deps.ini ; only for local tests of sensorslib +extra_configs = ../canairio_sensorlib/unified-lib-deps.ini ; only for local tests of sensorslib [common] build_type = release @@ -18,10 +18,10 @@ platform = espressif32 @ 4.4.0 framework = arduino upload_speed = 1500000 monitor_speed = 115200 -version = 0.6.1 -revision = 979 +version = 0.7.0 +revision = 985 # OTA remote update target (change it to none, if you want prevent CanAirIO updates) -target = prod +target = dev monitor_filters = esp32_exception_decoder ; time @@ -32,34 +32,36 @@ build_flags = -D WAIT_FOR_PM_SENSOR=25 # time of stabilization of PM sensors in seconds -D ARDUINO_ESP32_DEV=1 # compatibilty for DFRobot NH3/CO library -D DISABLE_ALL_LIBRARY_WARNINGS=1 - ; -D DISABLE_CLI # uncomment to only have Bluetooth config via - ; -D ENABLE_OTA # disable for memory saving, we have FOTA enable + -D SHELLMINATOR_BUFF_LEN=70 + -D SHELLMINATOR_BUFF_DIM=70 + -D SHELLMINATOR_LOGO_COLOR=YELLOW + -D COMMANDER_MAX_COMMAND_SIZE=70 + -D WCLI_MAX_CMDS=16 + ; -D DISABLE_BLE=1 # removed Bluetooth module + ; -D DISABLE_BATT=1 # removed battery module + ; -D DISABLE_CLI_TELNET=1 # disable remote access via telnet. It needs CLI + ; -D DISABLE_CLI=1 # removed CLI module. Config via Bluetooth only + ; -D ENABLE_OTA # disable for memory saving. We have FOTA enable lib_deps = - bblanchon/ArduinoJson @ 6.21.2 - hpsaturn/ESP32 Wifi CLI @ 0.2.2 + bblanchon/ArduinoJson @ 7.3.0 + hpsaturn/EasyPreferences @ 0.1.3 + ; hpsaturn/ESP32 Wifi CLI @ 0.3.1 + https://github.com/hpsaturn/esp32-wifi-cli.git#devel https://github.com/chrisjoyce911/esp32FOTA.git#2bbc9cb https://github.com/rlogiacco/CircularBuffer.git#f29cf01 https://github.com/256dpi/arduino-mqtt.git#7afcfb1 https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino.git#8e5f051 - - hpsaturn/CanAirIO Air Quality Sensors Library @ 0.7.3 + hpsaturn/CanAirIO Air Quality Sensors Library @ 0.7.5 ; https://github.com/kike-canaries/canairio_sensorlib.git#devel ; ${commonlibs.lib_deps} ; only for local tests of sensorslib [esp32_common] -build_type = ${common.build_type} -platform = ${common.platform} +extends = common board = lolin32 -framework = ${common.framework} -upload_speed = ${common.upload_speed} -monitor_speed = ${common.monitor_speed} -lib_deps = ${common.lib_deps} -monitor_filters = ${common.monitor_filters} -extra_scripts = ${common.extra_scripts} board_build.partitions = min_spiffs.csv build_flags = ${common.build_flags} - -D MAIN_HW_EN_PIN=27 # enable the main hardware pin (main sensor) + -D MAIN_HW_EN_PIN=27 # enable pin (of the main sensor) [oled_common] extends = esp32_common @@ -113,29 +115,33 @@ lib_ignore = gui-utils-oled lorawan +[env:M5STICKCPLUS] +extends = tft_common +lib_deps = + ${common.lib_deps} + m5stack/M5Unified@0.2.2 + [env:TTGO_TDISPLAY] extends = tft_common lib_deps = ${common.lib_deps} - bodmer/TFT_eSPI @ 2.5.31 + bodmer/TFT_eSPI @ 2.5.43 build_flags = ${esp32_common.build_flags} -D USER_SETUP_LOADED=1 -include .pio/libdeps/${PIOENV}/TFT_eSPI/User_Setups/Setup25_TTGO_T_Display.h -[env:M5STICKCPLUS] -extends = tft_common -lib_deps = - ${common.lib_deps} - https://github.com/hpsaturn/M5StickC-Plus.git - [esp32c3_common] -platform = espressif32 @ 5.3.0 +platform = espressif32 @ 6.9.0 extends = oled_common +board = esp32-c3-devkitm-1 +build_flags = + ${oled_common.build_flags} + -D DISABLE_BLE=1 + -D DISABLE_BATT=1 [env:ESP32C3] extends = esp32c3_common -board = esp32-c3-devkitm-1 [env:ESP32C3OIPLUS] extends = esp32c3_common @@ -149,9 +155,16 @@ board = lolin_c3_mini extends = esp32c3_common board = seeed_xiao_esp32c3 +[env:AG_OPENAIR] +extends = esp32c3_common +build_flags = + ${esp32c3_common.build_flags} + -D ARDUINO_USB_CDC_ON_BOOT=1 + -D ARDUINO_USB_MODE=1 + [esp32s3_common] extends = oled_common -platform = espressif32 @ 6.5.0 +platform = espressif32 @ 6.9.0 board = esp32-s3-devkitc-1 board_build.mcu = esp32s3 board_build.f_cpu = 240000000L @@ -161,7 +174,6 @@ build_flags = -mfix-esp32-psram-cache-issue -D MAIN_HW_EN_PIN=3 # enable the main hardware pin (main sensor) -; ESP32S3 DEVKIT (Also ESP32S3 CAM) [env:ESP32S3] extends = esp32s3_common @@ -171,6 +183,7 @@ build_flags = ${esp32s3_common.build_flags} -D ARDUINO_USB_CDC_ON_BOOT=1 +; experimental LoRa version [env:LORADEVKIT] extends = esp32_common upload_speed = 921600 @@ -179,7 +192,7 @@ lib_ignore = gui-utils-tft lib_deps = ${oled_common.lib_deps} - mcci-catena/MCCI LoRaWAN LMIC library @ ^4.1.1 + mcci-catena/MCCI LoRaWAN LMIC library @ 5.0.1 lorawan ;nanopb/Nanopb@^0.4.7 ;sabas1080/CayenneLPP @ ^1.1.0 diff --git a/prebuild.py b/prebuild.py index db0e38ff..d4f95db3 100755 --- a/prebuild.py +++ b/prebuild.py @@ -32,7 +32,7 @@ chipFamily = "ESP32" -if flavor == "ESP32C3" or flavor == "ESP32C3OIPLUS" or flavor == "ESP32C3LOLIN" or flavor == "ESP32C3SEEDX": +if flavor == "ESP32C3" or flavor == "ESP32C3OIPLUS" or flavor == "ESP32C3LOLIN" or flavor == "ESP32C3SEEDX" or flavor == "AG_OPENAIR": chipFamily = "ESP32-C3" if flavor == "ESP32S3" or flavor == "TTGO_T7S3": diff --git a/src/cli.cpp b/src/cli.cpp deleted file mode 100644 index af82f542..00000000 --- a/src/cli.cpp +++ /dev/null @@ -1,365 +0,0 @@ -#ifndef DISABLE_CLI -#include -#include - -bool setup_mode = false; -int setup_time = 10000; -bool first_run = true; - -TaskHandle_t xCliHandle; - -void wcli_debug(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - String param = operands.first(); - param.toUpperCase(); - bool dbgmode = param.equals("ON") || param.equals("1"); - cfg.debugEnable(dbgmode); - cfg.devmode = dbgmode; - sensors.setDebugMode(dbgmode); - battery.debug = dbgmode; -} - -bool isValidKey(String key) { - for (int i = 0; i < KCOUNT; i++) { - if (key.equals(cfg.getKey((CONFKEYS)i))) return true; - } - return false; -} - -String getValue(String key) { - ConfKeyType type = cfg.getKeyType(key); - if (type == ConfKeyType::BOOL) return cfg.getBool(key, false) ? "true" : "false"; - if (type == ConfKeyType::FLOAT) return String(cfg.getFloat(key, false)); - if (type == ConfKeyType::INT) return String(cfg.getInt(key, false)); - if (type == ConfKeyType::STRING) return cfg.getString(key, ""); - return ""; -} - -void wcli_klist(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - String opt = operands.first(); - int key_count = KCOUNT; // Show all keys to configure - if (opt.equals("basic")) key_count = KBASIC; // Only show the basic keys to configure - Serial.printf("\n%11s \t%s \t%s \r\n", "KEYNAME", "DEFINED", "VALUE"); - Serial.printf("\n%11s \t%s \t%s \r\n", "=======", "=======", "====="); - - for (int i = 0; i < key_count; i++) { - if(i==KBASIC) continue; - String key = cfg.getKey((CONFKEYS)i); - bool isDefined = cfg.isKey(key); - String defined = isDefined ? "custom " : "default"; - String value = ""; - if (isDefined) value = getValue(key); - Serial.printf("%11s \t%s \t%s \r\n", key, defined.c_str(), value.c_str()); - } - - Serial.printf("\r\nMore info: https://canair.io/docs/cli\r\n"); -} - -void saveInteger(String key, String v) { - int32_t value = v.toInt(); - cfg.saveInt(key, value); - Serial.printf("saved: %s:%i\r\n",key.c_str(),value); -} - -void saveFloat(String key, String v) { - float value = v.toFloat(); - cfg.saveFloat(key, value); - Serial.printf("saved: %s:%.5f\r\n",key.c_str(),value); -} - -void saveBoolean(String key, String v) { - v.toLowerCase(); - cfg.saveBool(key, v.equals("on") || v.equals("1") || v.equals("enable") || v.equals("true")); - Serial.printf("saved: %s:%s\r\n", key.c_str(), cfg.getBool(key, false) ? "true" : "false"); -} - -void saveString(String key, String v) { - cfg.saveString(key, v); - Serial.printf("saved: %s:%s\r\n",key.c_str(),v.c_str()); -} - -void wcli_kset(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - String key = operands.first(); - String v = operands.second(); - if(isValidKey(key)){ - if(cfg.getKeyType(key) == ConfKeyType::BOOL) saveBoolean(key,v); - else if(cfg.getKeyType(key) == ConfKeyType::FLOAT) saveFloat(key,v); - else if(cfg.getKeyType(key) == ConfKeyType::INT) saveInteger(key,v); - else if(cfg.getKeyType(key) == ConfKeyType::STRING) saveString(key,v); - else Serial.println("Invalid key action for: " + key); - } - else { - Serial.printf("invalid key: %s\r\nPlease see the valid keys with klist command.\r\n",key.c_str()); - } -} - -void wcli_uartpins(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - int sTX = operands.first().toInt(); - int sRX = operands.second().toInt(); - if (sTX >= 0 && sRX >= 0) { - cfg.saveSensorPins(sTX, sRX); - } - else - Serial.println("invalid pins values"); -} - -bool validBattLimits(float min, float max){ - return (min >= 3.0 && min <= 5.0 && max <=5.0 && max >= 3.0); -} - -void wcli_battvLimits(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - float battMin = operands.first().toFloat(); - float battMax = operands.second().toFloat(); - if (validBattLimits(battMin, battMax)) { - Serial.printf("Battery limits: Vmin: %2.2f Vmax: %2.2f\r\n", battMin, battMax); - battery.setBattLimits(battMin, battMax); - cfg.saveFloat(CONFKEYS::KBATVMI,battMin); - cfg.saveFloat(CONFKEYS::KBATVMX,battMax); - } - else { - Serial.println("-->[BATT] !invalid battery value! Current values:"); - battery.printLimits(); - } -} - -void wcli_chargLimits(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - float battMin = operands.first().toFloat(); - float battMax = operands.second().toFloat(); - if (validBattLimits(battMin, battMax)) { - Serial.printf("Battery charging limits: Vmin: %2.2f Vmax: %2.2f\r\n", battMin, battMax); - battery.setChargLimits(battMin, battMax); - cfg.saveFloat(CONFKEYS::KCHRVMI,battMin); - cfg.saveFloat(CONFKEYS::KCHRVMX,battMax); - } - else { - Serial.println("-->[BATT] !invalid battery value! Current values:"); - battery.printLimits(); - } -} - -void wcli_stime(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - int stime = operands.first().toInt(); - if (stime >= 5) { - cfg.saveSampleTime(stime); - sensors.setSampleTime(stime); - } - else - Serial.println("invalid sample time"); -} - -void wcli_stype_error(){ - Serial.println("invalid UART sensor type! Choose one into 0-7:"); - for (int i=0; i<=7 ;i++)Serial.printf("%i\t%s\r\n",i,sensors.getSensorName((SENSORS)i)); -} - -void wcli_stype(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - String stype = operands.first(); - if(stype.length()==0){ - wcli_stype_error(); - return; - } - int type = stype.toInt(); - if (type > 7 || type < 0) wcli_stype_error(); - else { - cfg.saveSensorType(type); - Serial.printf("\nselected UART sensor model\t: %s\r\n", sensors.getSensorName((SENSORS)type)); - Serial.println("Please reboot to changes apply"); - } -} - -void wcli_sgeoh (String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - String geoh = operands.first(); - if (geoh.length() > 5) { - geoh.toLowerCase(); - cfg.saveGeo(geoh); - cfg.ifxdbEnable(true); - } else { - Serial.println("\nInvalid Geohash. (Precision should be > to 5).\r\n"); - Serial.println("Please visit: http://bit.ly/geohashe"); - Serial.println("\nand select one of your fixed station."); - } -} - -void wcli_sensors() { - Serial.printf("\r\nCanAirIO Sensorslib\t: %s\r\n",sensors.getLibraryVersion().c_str()); - int i = 0; - int count = sensors.getSensorsRegisteredCount(); - Serial.printf("Sensors count \t\t: %i (", count); - if (count > 0 && sensors.getSensorsRegistered()[0] == SENSORS::Auto) { - Serial.printf("%s,", sensors.getSensorName((SENSORS)sensors.getSensorsRegistered()[0])); - i = 1; - } - while (sensors.getSensorsRegistered()[i++] != 0) { - Serial.printf("%s,", sensors.getSensorName((SENSORS)sensors.getSensorsRegistered()[i-1])); - } - Serial.println(")"); -} - -void wcli_sensors_values() { - Serial.println("\r\nCurrent sensors values:"); - UNIT unit = sensors.getNextUnit(); - while(unit != UNIT::NUNIT) { - String uName = sensors.getUnitName(unit); - float uValue = sensors.getUnitValue(unit); - String uSymb = sensors.getUnitSymbol(unit); - Serial.printf(" %s:\t%02.1f\t%s\r\n", uName.c_str(), uValue, uSymb.c_str()); - unit = sensors.getNextUnit(); - } -} - -void wcli_info(String opts) { - Serial.println(); - Serial.print(getDeviceInfo()); - wcli_sensors(); - wcli_sensors_values(); -} - -void wcli_exit(String opts) { - setup_time = 0; - setup_mode = false; -} - -void wcli_setup(String opts) { - setup_mode = true; - Serial.println("\r\nSetup Mode. Main presets:\r\n"); - String canAirIOname = "Please set your geohash with \"sgeoh\" cmd"; - if(cfg.geo.length()>5)canAirIOname = cfg.getStationName(); - Serial.printf("CanAirIO device id\t: %s\r\n", canAirIOname.c_str()); - Serial.printf("Device factory id\t: %s\r\n", cfg.getAnaireDeviceId().c_str()); - Serial.printf("Sensor geohash id\t: %s\r\n", cfg.geo.length() == 0 ? "undefined" : cfg.geo.c_str()); - Serial.printf("WiFi current status\t: %s\r\n", WiFi.status() == WL_CONNECTED ? "connected" : "disconnected"); - Serial.printf("Sensor sample time \t: %d\r\n", cfg.stime); - Serial.printf("UART sensor model \t: %s\r\n", sensors.getSensorName((SENSORS)cfg.stype)); - Serial.printf("UART sensor TX pin\t: %d\r\n", cfg.sTX == -1 ? PMS_TX : cfg.sTX); - Serial.printf("UART sensor RX pin\t: %d\r\n", cfg.sRX == -1 ? PMS_RX : cfg.sRX); - Serial.printf("Current debug mode\t: %s\r\n", cfg.devmode == true ? "enabled" : "disabled"); - - wcli_klist("basic"); - - Serial.printf("\r\nType \"klist\" for advanced settings\r\n"); - Serial.printf("Type \"help\" for available commands details\r\n"); - Serial.printf("Type \"exit\" for leave the safe mode\r\n"); -} - -void wcli_reboot(String opts) { - wd.execute(); -} - -void wcli_clear(String opts) { - maschinendeck::Pair operands = maschinendeck::SerialTerminal::ParseCommand(opts); - String deviceId = operands.first(); - if (deviceId.equals(cfg.getAnaireDeviceId())) { - Serial.println("Clearing device to defaults.."); - wcli.clearSettings(); - cfg.clear(); - } - else { - Serial.println("\nPlease type clear and the factory device id to confirm."); - } -} - -class mESP32WifiCLICallbacks : public ESP32WifiCLICallbacks { - void onWifiStatus(bool isConnected) { - - } - - void onHelpShow() { - // Enter your custom help here: - Serial.println("\r\nCanAirIO Commands:\r\n"); - Serial.println("reboot\t\t\tperform a soft ESP32 reboot"); - Serial.println("clear\t\t\tfactory settings reset. (needs confirmation)"); - Serial.println("debug\t\tto enable debug mode"); - Serial.println("stime\t