diff --git a/examples/BASIC_v4/BASIC_v4.ino b/examples/BASIC_v4/BASIC_v4.ino index 8fdedca..cc0dc1c 100644 --- a/examples/BASIC_v4/BASIC_v4.ino +++ b/examples/BASIC_v4/BASIC_v4.ino @@ -79,8 +79,8 @@ public: /** Call handler */ handler(); - Serial.printf("[AgSchedule] handle 0x%08x, period: %d(ms)\r\n", - (unsigned int)handler, period); + // Serial.printf("[AgSchedule] handle 0x%08x, period: %d(ms)\r\n", + // (unsigned int)handler, period); /** Update period time */ count = millis(); @@ -271,7 +271,7 @@ public: bool isPMSinUSAQI(void) { return inUSAQI; } /** - * @brief Get status of get server coniguration is failed + * @brief Get status of get server configuration is failed * * @return true Failed * @return false Success @@ -305,7 +305,7 @@ public: * * @return int days, -1 if invalid. */ - int getCo2Abccalib(void) { return co2AbcCalib; } + int getCo2AbcDaysConfig(void) { return co2AbcCalib; } /** * @brief Get device configuration model name @@ -359,7 +359,7 @@ AirGradient ag = AirGradient(DIY_BASIC); static int co2Ppm = -1; static int pm25 = -1; -static float temp = -1; +static float temp = -1001; static int hum = -1; static long val; static String wifiSSID = ""; @@ -376,7 +376,12 @@ static void sendDataToServer(void); static void dispHandler(void); static String getDevId(void); static void updateWiFiConnect(void); +static void showNr(void); +bool hasSensorS8 = true; +bool hasSensorPMS = true; +bool hasSensorSHT = true; +int pmFailCount = 0; AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll); AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); AgSchedule dispSchedule(DISP_UPDATE_INTERVAL, dispHandler); @@ -386,6 +391,7 @@ AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumPoll); void setup() { Serial.begin(115200); + showNr(); /** Init I2C */ Wire.begin(ag.getI2cSdaPin(), ag.getI2cSclPin()); @@ -436,9 +442,15 @@ void loop() { configSchedule.run(); serverSchedule.run(); dispSchedule.run(); - co2Schedule.run(); - pmsSchedule.run(); - tempHumSchedule.run(); + if (hasSensorS8) { + co2Schedule.run(); + } + if (hasSensorPMS) { + pmsSchedule.run(); + } + if (hasSensorSHT) { + tempHumSchedule.run(); + } updateWiFiConnect(); } @@ -469,6 +481,7 @@ void displayShowText(String ln1, String ln2, String ln3) { ag.display.setText(ln3); ag.display.show(); + delay(100); } // Wifi Manager @@ -507,22 +520,28 @@ void connectToWifi() { static void boardInit(void) { /** Init SHT sensor */ if (ag.sht.begin(Wire) == false) { - failedHandler("SHT init failed"); + hasSensorSHT = false; + Serial.println("SHT sensor not found"); } /** CO2 init */ if (ag.s8.begin(&Serial) == false) { - failedHandler("SenseAirS8 init failed"); + Serial.println("CO2 S8 snsor not found"); + hasSensorS8 = false; } /** PMS init */ if (ag.pms5003.begin(&Serial) == false) { - failedHandler("PMS5003 init failed"); + Serial.println("PMS sensor not found"); + hasSensorPMS = false; } /** Display init */ ag.display.begin(Wire); ag.display.setTextColor(1); + ag.display.clear(); + ag.display.show(); + delay(100); } static void failedHandler(String msg) { @@ -560,11 +579,31 @@ static void co2Calibration(void) { static void serverConfigPoll(void) { if (agServer.pollServerConfig(getDevId())) { if (agServer.isCo2Calib()) { - co2Calibration(); + if (hasSensorS8) { + co2Calibration(); + } else { + Serial.println("CO2 S8 not available, calib ignored"); + } } - if (agServer.getCo2Abccalib() > 0) { - if (ag.s8.setAutoCalib(agServer.getCo2Abccalib() * 24) == false) { - Serial.println("Set S8 auto calib failed"); + if (agServer.getCo2AbcDaysConfig() > 0) { + if (hasSensorS8) { + int newHour = agServer.getCo2AbcDaysConfig() * 24; + Serial.printf("abcDays config: %d days(%d hours)\r\n", + agServer.getCo2AbcDaysConfig(), newHour); + int curHour = ag.s8.getAbcPeriod(); + Serial.printf("Current config: %d (hours)\r\n", ag.s8.getAbcPeriod()); + if (curHour == newHour) { + Serial.println("set 'abcDays' ignored"); + } else { + if (ag.s8.setAbcPeriod(agServer.getCo2AbcDaysConfig() * 24) == + false) { + Serial.println("Set S8 abcDays period calib failed"); + } else { + Serial.println("Set S8 abcDays period calib success"); + } + } + } else { + Serial.println("CO2 S8 not available, set 'abcDays' ignored"); } } } @@ -579,8 +618,13 @@ void pmPoll() { if (ag.pms5003.readData()) { pm25 = ag.pms5003.getPm25Ae(); Serial.printf("PMS2.5: %d\r\n", pm25); + pmFailCount = 0; } else { - pm25 = -1; + Serial.printf("PM read failed, %d", pmFailCount); + pmFailCount++; + if (pmFailCount >= 3) { + pm25 = -1; + } } } @@ -604,8 +648,8 @@ static void sendDataToServer() { if (pm25 >= 0) { root["pm02"] = pm25; } - if (temp >= 0) { - root["atmp"] = temp; + if (temp > -1001) { + root["atmp"] = ag.round2(temp); } if (hum >= 0) { root["rhum"] = hum; @@ -622,16 +666,42 @@ static void dispHandler() { String ln3 = ""; if (agServer.isPMSinUSAQI()) { - ln1 = "AQI:" + String(ag.pms5003.convertPm25ToUsAqi(pm25)); + if (pm25 < 0) { + ln1 = "AQI: -"; + } else { + ln1 = "AQI:" + String(ag.pms5003.convertPm25ToUsAqi(pm25)); + } } else { - ln1 = "PM :" + String(pm25) + " ug"; + if (pm25 < 0) { + ln1 = "PM :- ug"; + + } else { + ln1 = "PM :" + String(pm25) + " ug"; + } } - ln2 = "CO2:" + String(co2Ppm); + if (co2Ppm > -1001) { + ln2 = "CO2:" + String(co2Ppm); + } else { + ln2 = "CO2: -"; + } + + String _hum = "-"; + if (hum > 0) { + _hum = String(hum); + } + + String _temp = "-"; if (agServer.isTemperatureUnitF()) { - ln3 = String((temp * 9 / 5) + 32).substring(0, 4) + " " + String(hum) + "%"; + if (temp > -1001) { + _temp = String((temp * 9 / 5) + 32).substring(0, 4); + } + ln3 = _temp + " " + _hum + "%"; } else { - ln3 = String(temp).substring(0, 4) + " " + String(hum) + "%"; + if (temp > -1001) { + _temp = String(temp).substring(0, 4); + } + ln3 = _temp + " " + _hum + "%"; } displayShowText(ln1, ln2, ln3); } @@ -659,6 +729,11 @@ static void updateWiFiConnect(void) { } } +static void showNr(void) { + Serial.println(); + Serial.println("Serial nr: " + getDevId()); +} + String getNormalizedMac() { String mac = WiFi.macAddress(); mac.replace(":", ""); diff --git a/examples/ONE_I-9PSL/ONE_I-9PSL.ino b/examples/ONE_I-9PSL/ONE_I-9PSL.ino index a2ba33c..10b10bd 100644 --- a/examples/ONE_I-9PSL/ONE_I-9PSL.ino +++ b/examples/ONE_I-9PSL/ONE_I-9PSL.ino @@ -38,13 +38,17 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License */ +#include "mqtt_client.h" #include #include #include +#include "EEPROM.h" #include #include +#include #include +#include /** * @brief Application state machine state @@ -52,7 +56,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License */ enum { APP_SM_WIFI_MANAGER_MODE, /** In WiFi Manger Mode */ - APP_SM_WIFI_MAMAGER_PORTAL_ACTIVE, /** WiFi Manager has connected to mobile + APP_SM_WIFI_MANAGER_PORTAL_ACTIVE, /** WiFi Manager has connected to mobile phone */ APP_SM_WIFI_MANAGER_STA_CONNECTING, /** After SSID and PW entered and OK clicked, connection to WiFI network is @@ -60,24 +64,24 @@ enum { APP_SM_WIFI_MANAGER_STA_CONNECTED, /** Connecting to WiFi worked */ APP_SM_WIFI_OK_SERVER_CONNECTING, /** Once connected to WiFi an attempt to reach the server is performed */ - APP_SM_WIFI_OK_SERVER_CONNNECTED, /** Server is reachable, all fine */ + APP_SM_WIFI_OK_SERVER_CONNECTED, /** Server is reachable, all fine */ /** Exceptions during WIFi Setup */ APP_SM_WIFI_MANAGER_CONNECT_FAILED, /** Cannot connect to WiFi (e.g. wrong password, WPA Enterprise etc.) */ APP_SM_WIFI_OK_SERVER_CONNECT_FAILED, /** Connected to WiFi but server not - reachable, e.g. firewall block/ + reachable, e.g. firewall block/ whitelisting needed etc. */ APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED, /** Server reachable but sensor - not configured correctly*/ + not configured correctly*/ /** During Normal Operation */ APP_SM_WIFI_LOST, /** Connection to WiFi network failed credentials incorrect encryption not supported etc. */ APP_SM_SERVER_LOST, /** Connected to WiFi network but the server cannot be - reached through the internet, e.g. blocked by firewall + reached through the internet, e.g. blocked by firewall */ APP_SM_SENSOR_CONFIG_FAILED, /** Server is reachable but there is some - configuration issue to be fixed on the server + configuration issue to be fixed on the server side */ APP_SM_NORMAL, }; @@ -122,8 +126,8 @@ public: /** Call handler */ handler(); - Serial.printf("[AgSchedule] handle 0x%08x, period: %d(ms)\r\n", - (unsigned int)handler, period); + // Serial.printf("[AgSchedule] handle 0x%08x, period: %d(ms)\r\n", + // (unsigned int)handler, period); /** Update period time */ count = millis(); @@ -143,12 +147,9 @@ private: class AgServer { public: void begin(void) { - inF = false; - inUSAQI = false; configFailed = false; serverFailed = false; - memset(models, 0, sizeof(models)); - memset(mqttBroker, 0, sizeof(mqttBroker)); + loadConfig(); } /** @@ -193,6 +194,7 @@ public: } /** Get "country" */ + bool inF = false; if (JSON.typeof_(root["country"]) == "string") { String _country = root["country"]; country = _country; @@ -205,6 +207,7 @@ public: } /** Get "pmsStandard" */ + bool inUSAQI = false; if (JSON.typeof_(root["pmStandard"]) == "string") { String standard = root["pmStandard"]; if (standard == "ugm3") { @@ -222,6 +225,7 @@ public: } /** Get "ledBarMode" */ + uint8_t ledBarMode = UseLedBarOff; if (JSON.typeof_(root["ledBarMode"]) == "string") { String mode = root["ledBarMode"]; if (mode == "co2") { @@ -236,13 +240,18 @@ public: } /** Get model */ + bool _saveConfig = false; if (JSON.typeof_(root["model"]) == "string") { String model = root["model"]; if (model.length()) { - int len = - model.length() < sizeof(models) ? model.length() : sizeof(models); - memset(models, 0, sizeof(models)); - memcpy(models, model.c_str(), len); + int len = model.length() < sizeof(config.models) + ? model.length() + : sizeof(config.models); + if (model != String(config.models)) { + memset(config.models, 0, sizeof(config.models)); + memcpy(config.models, model.c_str(), len); + _saveConfig = true; + } } } @@ -250,10 +259,14 @@ public: if (JSON.typeof_(root["mqttBrokerUrl"]) == "string") { String mqtt = root["mqttBrokerUrl"]; if (mqtt.length()) { - int len = mqtt.length() < sizeof(mqttBroker) ? mqtt.length() - : sizeof(mqttBroker); - memset(mqttBroker, 0, sizeof(mqttBroker)); - memcpy(mqttBroker, mqtt.c_str(), len); + int len = mqtt.length() < sizeof(config.mqttBrokers) + ? mqtt.length() + : sizeof(config.mqttBrokers); + if (mqtt != String(config.mqttBrokers)) { + memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers)); + memcpy(config.mqttBrokers, mqtt.c_str(), len); + _saveConfig = true; + } } } @@ -273,6 +286,14 @@ public: /** Show configuration */ showServerConfig(); + if (_saveConfig || (inF != config.inF) || (inUSAQI != config.inUSAQI) || + (ledBarMode != config.useRGBLedBar)) { + config.inF = inF; + config.inUSAQI = inUSAQI; + config.useRGBLedBar = ledBarMode; + + saveConfig(); + } return true; } @@ -313,7 +334,7 @@ public: * @return true F unit * @return false C Unit */ - bool isTemperatureUnitF(void) { return inF; } + bool isTemperatureUnitF(void) { return config.inF; } /** * @brief Get PMS standard unit @@ -321,10 +342,10 @@ public: * @return true USAQI * @return false ugm3 */ - bool isPMSinUSAQI(void) { return inUSAQI; } + bool isPMSinUSAQI(void) { return config.inUSAQI; } /** - * @brief Get status of get server coniguration is failed + * @brief Get status of get server configuration is failed * * @return true Failed * @return false Success @@ -372,32 +393,33 @@ public: * * @return int days, -1 if invalid. */ - int getCo2Abccalib(void) { return co2AbcCalib; } + int getCo2AbcDaysConfig(void) { return co2AbcCalib; } /** * @brief Get device configuration model name * * @return String Model name, empty string if server failed */ - String getModelName(void) { return String(models); } + String getModelName(void) { return String(config.models); } /** * @brief Get mqttBroker url * * @return String Broker url, empty if server failed */ - String getMqttBroker(void) { return String(mqttBroker); } + String getMqttBroker(void) { return String(config.mqttBrokers); } /** * @brief Show server configuration parameter */ void showServerConfig(void) { Serial.println("Server configuration: "); - Serial.printf(" inF: %s\r\n", inF ? "true" : "false"); - Serial.printf(" inUSAQI: %s\r\n", inUSAQI ? "true" : "false"); - Serial.printf(" useRGBLedBar: %d\r\n", (int)ledBarMode); - Serial.printf(" Model: %s\r\n", models); - Serial.printf(" Mqtt Broker: %s\r\n", mqttBroker); + Serial.printf(" inF: %s\r\n", config.inF ? "true" : "false"); + Serial.printf(" inUSAQI: %s\r\n", + config.inUSAQI ? "true" : "false"); + Serial.printf(" useRGBLedBar: %d\r\n", (int)config.useRGBLedBar); + Serial.printf(" Model: %s\r\n", config.models); + Serial.printf(" Mqtt Broker: %s\r\n", config.mqttBrokers); Serial.printf(" S8 calib period: %d\r\n", co2AbcCalib); } @@ -406,7 +428,7 @@ public: * * @return UseLedBar */ - UseLedBar getLedBarMode(void) { return ledBarMode; } + UseLedBar getLedBarMode(void) { return (UseLedBar)config.useRGBLedBar; } /** * @brief Get the Country @@ -416,20 +438,200 @@ public: String getCountry(void) { return country; } private: - bool inF; /** Temperature unit, true: F, false: C */ - bool inUSAQI; /** PMS unit, true: USAQI, false: ugm3 */ bool configFailed; /** Flag indicate get server configuration failed */ bool serverFailed; /** Flag indicate post data to server failed */ bool co2Calib; /** Is co2Ppmcalibration requset */ bool ledBarTestRequested; /** */ int co2AbcCalib = -1; /** update auto calibration number of day */ - UseLedBar ledBarMode = UseLedBarCO2; /** */ - char models[20]; /** */ - char mqttBroker[256]; /** */ - String country; /***/ + String country; /***/ + + struct config_s { + bool inF; + bool inUSAQI; + uint8_t useRGBLedBar; + char models[20]; + char mqttBrokers[256]; + uint32_t checksum; + }; + struct config_s config; + + void defaultConfig(void) { + config.inF = false; + config.inUSAQI = false; + memset(config.models, 0, sizeof(config.models)); + memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers)); + + Serial.println("Load config default"); + saveConfig(); + } + + void loadConfig(void) { + if (EEPROM.readBytes(0, &config, sizeof(config)) != sizeof(config)) { + config.inF = false; + config.inUSAQI = false; + memset(config.models, 0, sizeof(config.models)); + memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers)); + + Serial.println("Load configure failed"); + } else { + uint32_t sum = 0; + uint8_t *data = (uint8_t *)&config; + for (int i = 0; i < sizeof(config) - 4; i++) { + sum += data[i]; + } + if (sum != config.checksum) { + Serial.println("config checksum failed"); + defaultConfig(); + } + } + + showServerConfig(); + } + + void saveConfig(void) { + config.checksum = 0; + uint8_t *data = (uint8_t *)&config; + for (int i = 0; i < sizeof(config) - 4; i++) { + config.checksum += data[i]; + } + + EEPROM.writeBytes(0, &config, sizeof(config)); + EEPROM.commit(); + Serial.println("Save config"); + } }; AgServer agServer; +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, + int32_t event_id, void *event_data); + +class AgMqtt { +private: + bool _isBegin = false; + String uri; + String hostname; + String user; + String pass; + int port; + esp_mqtt_client_handle_t client; + bool clientConnected = false; + int connectFailedCount = 0; + +public: + AgMqtt() {} + ~AgMqtt() {} + + /** + * @brief Initialize mqtt + * + * @param uri Complete mqtt uri, ex: + * mqtts://username:password@my.broker.com:4711 + * @return true Success + * @return false Failure + */ + bool begin(String uri) { + if (_isBegin) { + Serial.println("Mqtt already begin, call 'end' and try again"); + return true; + } + + if (uri.isEmpty()) { + Serial.println("Mqtt uri is empty"); + return false; + } + + this->uri = uri; + Serial.printf("mqtt init '%s'\r\n", uri.c_str()); + + /** config esp_mqtt client */ + esp_mqtt_client_config_t config = { + .uri = this->uri.c_str(), + }; + + /** init client */ + client = esp_mqtt_client_init(&config); + if (client == NULL) { + Serial.println("mqtt client init failed"); + return false; + } + + /** Register event */ + if (esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, + mqtt_event_handler, NULL) != ESP_OK) { + Serial.println("mqtt client register event failed"); + return false; + } + + if (esp_mqtt_client_start(client) != ESP_OK) { + Serial.println("mqtt client start failed"); + return false; + } + + _isBegin = true; + return true; + } + + /** + * @brief Deinitialize mqtt + * + */ + void end(void) { + if (_isBegin == false) { + return; + } + + esp_mqtt_client_disconnect(client); + esp_mqtt_client_stop(client); + esp_mqtt_client_destroy(client); + _isBegin = false; + + Serial.println("mqtt de-init"); + } + + bool publish(const char *topic, const char *payload, int len) { + if ((_isBegin == false) || (clientConnected == false)) { + return false; + } + + if (esp_mqtt_client_publish(client, topic, payload, len, 0, 0) == ESP_OK) { + return true; + } + return false; + } + + /** + * @brief Get current complete mqtt uri + * + * @return String + */ + String getUri(void) { return uri; } + + void _connectionHandler(bool connected) { + clientConnected = connected; + if (clientConnected == false) { + connectFailedCount++; + } else { + connectFailedCount = 0; + } + } + + /** + * @brief Mqtt client connect status + * + * @return true Connected + * @return false Disconnected or Not initialize + */ + bool isConnected(void) { return (_isBegin && clientConnected); } + + /** + * @brief Get number of times connection failed + * + * @return int + */ + int connectionFailedCount(void) { return connectFailedCount; } +}; +AgMqtt agMqtt; + /** Create airgradient instance for 'ONE_INDOOR' board */ AirGradient ag(ONE_INDOOR); @@ -439,6 +641,9 @@ U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE); /** wifi manager instance */ WiFiManager wifiManager; +/** Web server instance */ +WebServer webServer; + static bool wifiHasConfig = false; /** */ static int connectCountDown; /** wifi configuration countdown */ static int ledCount; /** For LED animation */ @@ -446,13 +651,14 @@ static int ledSmState = APP_SM_NORMAL; /** Save display SM */ static int dispSmState = APP_SM_NORMAL; /** Save LED SM */ static int tvocIndex = -1; +static int tvocRawIndex = -1; static int noxIndex = -1; static int co2Ppm = -1; static int pm25 = -1; static int pm01 = -1; static int pm10 = -1; static int pm03PCount = -1; -static float temp = -1; +static float temp = -1001; static int hum = -1; static int bootCount; static String wifiSSID = ""; @@ -475,8 +681,16 @@ static void pmPoll(void); static void sendDataToServer(void); static void tempHumPoll(void); static void co2Poll(void); +static void showNr(void); +static void webServerInit(void); +static String getServerSyncData(bool localServer); /** Init schedule */ +bool hasSensorS8 = true; +bool hasSensorPMS = true; +bool hasSensorSGP = true; +bool hasSensorSHT = true; +int pmFailCount = 0; AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, updateDispLedBar); AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll); AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); @@ -486,8 +700,12 @@ AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumPoll); AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocPoll); void setup() { - /** Serial fore print debug message */ + EEPROM.begin(512); + + /** Serial for print debug message */ Serial.begin(115200); + delay(100); /** For bester show log */ + showNr(); /** Init I2C */ Wire.begin(ag.getI2cSdaPin(), ag.getI2cSclPin()); @@ -523,15 +741,25 @@ void setup() { } if (test) { ledTest(); - } else { - /** WIFI connect */ - connectToWifi(); } + /** WIFI connect */ + connectToWifi(); /** * Send first data to ping server and get server configuration */ if (WiFi.status() == WL_CONNECTED) { + webServerInit(); + + /** MQTT init */ + if (agServer.getMqttBroker().isEmpty() == false) { + if (agMqtt.begin(agServer.getMqttBroker())) { + Serial.println("MQTT client init success"); + } else { + Serial.println("MQTT client init failure"); + } + } + sendPing(); Serial.println(F("WiFi connected!")); Serial.println("IP address: "); @@ -559,10 +787,22 @@ void loop() { dispLedSchedule.run(); configSchedule.run(); serverSchedule.run(); - co2Schedule.run(); - pmsSchedule.run(); - tempHumSchedule.run(); - tvocSchedule.run(); + + if (hasSensorS8) { + co2Schedule.run(); + } + + if (hasSensorPMS) { + pmsSchedule.run(); + } + + if (hasSensorSHT) { + tempHumSchedule.run(); + } + + if (hasSensorSGP) { + tvocSchedule.run(); + } /** Check for handle WiFi reconnect */ updateWiFiConnect(); @@ -646,6 +886,85 @@ static void co2Poll(void) { Serial.printf("CO2 index: %d\r\n", co2Ppm); } +static void showNr(void) { Serial.println("Serial nr: " + getDevId()); } + +void webServerMeasureCurrentGet(void) { + webServer.send(200, "application/json", getServerSyncData(true)); +} + +void webServerHandler(void *param) { + for (;;) { + webServer.handleClient(); + } +} + +static void webServerInit(void) { + String host = "airgradient_" + getDevId(); + if (!MDNS.begin(host)) { + Serial.println("Init MDNS failed"); + return; + } + + webServer.on("/measures/current", HTTP_GET, webServerMeasureCurrentGet); + webServer.begin(); + MDNS.addService("http", "tcp", 80); + + if (xTaskCreate(webServerHandler, "webserver", 1024 * 4, NULL, 5, NULL) != + pdTRUE) { + Serial.println("Create task handle webserver failed"); + } + Serial.printf("Webserver init: %s.local\r\n", host.c_str()); +} + +static String getServerSyncData(bool localServer) { + JSONVar root; + root["wifi"] = WiFi.RSSI(); + if (localServer) { + root["serialno"] = getDevId(); + } + if (hasSensorS8) { + if (co2Ppm >= 0) { + root["rco2"] = co2Ppm; + } + } + if (hasSensorPMS) { + if (pm01 >= 0) { + root["pm01"] = pm01; + } + if (pm25 >= 0) { + root["pm02"] = pm25; + } + if (pm10 >= 0) { + root["pm10"] = pm10; + } + if (pm03PCount >= 0) { + root["pm003_count"] = pm03PCount; + } + } + if (hasSensorSGP) { + if (tvocIndex >= 0) { + root["tvoc_index"] = tvocIndex; + } + if (tvocRawIndex >= 0) { + root["tvoc_raw"] = tvocRawIndex; + } + if (noxIndex >= 0) { + root["noxIndex"] = noxIndex; + } + } + if (hasSensorSHT) { + if (temp > -1001) { + root["atmp"] = ag.round2(temp); + } + if (hum >= 0) { + root["rhum"] = hum; + } + } + root["boot"] = bootCount; + + return JSON.stringify(root); +} + static void sendPing() { JSONVar root; root["wifi"] = WiFi.RSSI(); @@ -671,8 +990,8 @@ static void sendPing() { delay(1500); if (agServer.postToServer(getDevId(), JSON.stringify(root))) { - dispSmHandler(APP_SM_WIFI_OK_SERVER_CONNNECTED); - ledSmHandler(APP_SM_WIFI_OK_SERVER_CONNNECTED); + dispSmHandler(APP_SM_WIFI_OK_SERVER_CONNECTED); + ledSmHandler(APP_SM_WIFI_OK_SERVER_CONNECTED); } else { dispSmHandler(APP_SM_WIFI_OK_SERVER_CONNECT_FAILED); ledSmHandler(APP_SM_WIFI_OK_SERVER_CONNECT_FAILED); @@ -717,7 +1036,7 @@ static void displayShowDashboard(String err) { /** Show temperature */ if (agServer.isTemperatureUnitF()) { - if (temp > -10001) { + if (temp > -1001) { float tempF = (temp * 9 / 5) + 32; sprintf(strBuf, "%.1f°F", tempF); } else { @@ -725,7 +1044,7 @@ static void displayShowDashboard(String err) { } u8g2.drawUTF8(1, 10, strBuf); } else { - if (temp > -10001) { + if (temp > -1001) { sprintf(strBuf, "%.1f°C", temp); } else { sprintf(strBuf, "-°C"); @@ -752,7 +1071,7 @@ static void displayShowDashboard(String err) { if (err == "WiFi N/A") { u8g2.setFont(u8g2_font_t0_12_tf); if (agServer.isTemperatureUnitF()) { - if (temp > -10001) { + if (temp > -1001) { float tempF = (temp * 9 / 5) + 32; sprintf(strBuf, "%.1f", tempF); } else { @@ -760,7 +1079,7 @@ static void displayShowDashboard(String err) { } u8g2.drawUTF8(1, 10, strBuf); } else { - if (temp > -10001) { + if (temp > -1001) { sprintf(strBuf, "%.1f", temp); } else { sprintf(strBuf, "-"); @@ -935,7 +1254,7 @@ static void connectToWifi() { if (clientConnected != clientConnectChanged) { clientConnectChanged = clientConnected; if (clientConnectChanged) { - ledSmHandler(APP_SM_WIFI_MAMAGER_PORTAL_ACTIVE); + ledSmHandler(APP_SM_WIFI_MANAGER_PORTAL_ACTIVE); } else { ledCount = LED_BAR_COUNT_INIT_VALUE; ledSmHandler(APP_SM_WIFI_MANAGER_MODE); @@ -1032,6 +1351,11 @@ static void setRGBledColor(char color) { ag.ledBar.setColor(r, g, b, ledNum); } +void dispSensorNotFound(String ss) { + displayShowText("Sensor init", "Error:", ss + " not found"); + delay(2000); +} + /** * @brief Initialize board */ @@ -1044,12 +1368,16 @@ static void boardInit(void) { /** Init sensor SGP41 */ if (ag.sgp41.begin(Wire) == false) { - failedHandler("Init SGP41 failed"); + Serial.println("SGP41 sensor not found"); + hasSensorSGP = false; + dispSensorNotFound("SGP41"); } /** INit SHT */ if (ag.sht.begin(Wire) == false) { - failedHandler("Init SHT failed"); + Serial.println("SHTx sensor not found"); + hasSensorSHT = false; + dispSensorNotFound("SHT"); } /** Init watchdog */ @@ -1057,12 +1385,18 @@ static void boardInit(void) { /** Init S8 CO2 sensor */ if (ag.s8.begin(Serial1) == false) { - failedHandler("Init SenseAirS8 failed"); + // failedHandler("Init SenseAirS8 failed"); + Serial.println("CO2 S8 sensor not found"); + hasSensorS8 = false; + dispSensorNotFound("S8"); } /** Init PMS5003 */ if (ag.pms5003.begin(Serial0) == false) { - failedHandler("Init PMS5003 failed"); + Serial.println("PMS sensor not found"); + hasSensorPMS = false; + + dispSensorNotFound("PMS"); } } @@ -1084,13 +1418,35 @@ static void failedHandler(String msg) { static void serverConfigPoll(void) { if (agServer.pollServerConfig(getDevId())) { if (agServer.isCo2Calib()) { - co2Calibration(); - } - if (agServer.getCo2Abccalib() > 0) { - if (ag.s8.setAutoCalib(agServer.getCo2Abccalib() * 24) == false) { - Serial.println("Set S8 auto calib failed"); + if (hasSensorS8) { + co2Calibration(); + } else { + Serial.println("CO2 S8 not available, calib ignored"); } } + + if (agServer.getCo2AbcDaysConfig() > 0) { + if (hasSensorS8) { + int newHour = agServer.getCo2AbcDaysConfig() * 24; + Serial.printf("abcDays config: %d days(%d hours)\r\n", + agServer.getCo2AbcDaysConfig(), newHour); + int curHour = ag.s8.getAbcPeriod(); + Serial.printf("Current config: %d (hours)\r\n", ag.s8.getAbcPeriod()); + if (curHour == newHour) { + Serial.println("set 'abcDays' ignored"); + } else { + if (ag.s8.setAbcPeriod(agServer.getCo2AbcDaysConfig() * 24) == + false) { + Serial.println("Set S8 abcDays period calib failed"); + } else { + Serial.println("Set S8 abcDays period calib success"); + } + } + } else { + Serial.println("CO2 S8 not available, set 'abcDays' ignored"); + } + } + if (agServer.isLedBarTestRequested()) { if (agServer.getCountry() == "TH") { ledTest2Min(); @@ -1098,6 +1454,16 @@ static void serverConfigPoll(void) { ledTest(); } } + + String mqttUri = agServer.getMqttBroker(); + if (mqttUri != agMqtt.getUri()) { + agMqtt.end(); + if (agMqtt.begin(mqttUri)) { + Serial.println("Connect to new mqtt broker success"); + } else { + Serial.println("Connect to new mqtt broker failed"); + } + } } } @@ -1187,7 +1553,7 @@ static void ledSmHandler(int sm) { ag.ledBar.setColor(0, 0, 255, ag.ledBar.getNumberOfLeds() / 2); break; } - case APP_SM_WIFI_MAMAGER_PORTAL_ACTIVE: { + case APP_SM_WIFI_MANAGER_PORTAL_ACTIVE: { /** WiFi Manager has connected to mobile phone */ ag.ledBar.setColor(0, 0, 255); break; @@ -1208,7 +1574,7 @@ static void ledSmHandler(int sm) { singleLedAnimation(0, 255, 0); break; } - case APP_SM_WIFI_OK_SERVER_CONNNECTED: { + case APP_SM_WIFI_OK_SERVER_CONNECTED: { /** Server is reachable, all fine */ ag.ledBar.setColor(0, 255, 0); break; @@ -1219,13 +1585,13 @@ static void ledSmHandler(int sm) { break; } case APP_SM_WIFI_OK_SERVER_CONNECT_FAILED: { - /** Connected to WiFi but server not reachable, e.g. firewall block/ + /** Connected to WiFi but server not reachable, e.g. firewall block/ * whitelisting needed etc. */ ag.ledBar.setColor(233, 183, 54); /** orange */ break; } case APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED: { - /** Server reachable but sensor not configured correctly */ + /** Server reachable but sensor not configured correctly */ ag.ledBar.setColor(139, 24, 248); /** violet */ break; } @@ -1241,7 +1607,7 @@ static void ledSmHandler(int sm) { } case APP_SM_SERVER_LOST: { /** Connected to WiFi network but the server cannot be reached through the - * internet, e.g. blocked by firewall */ + * internet, e.g. blocked by firewall */ ag.ledBar.setColor(233, 183, 54, 0); @@ -1250,7 +1616,7 @@ static void ledSmHandler(int sm) { break; } case APP_SM_SENSOR_CONFIG_FAILED: { - /** Server is reachable but there is some configuration issue to be fixed on + /** Server is reachable but there is some configuration issue to be fixed on * the server side */ ag.ledBar.setColor(139, 24, 248, 0); @@ -1289,7 +1655,7 @@ static void dispSmHandler(int sm) { switch (sm) { case APP_SM_WIFI_MANAGER_MODE: - case APP_SM_WIFI_MAMAGER_PORTAL_ACTIVE: { + case APP_SM_WIFI_MANAGER_PORTAL_ACTIVE: { if (connectCountDown >= 0) { displayShowWifiText(String(connectCountDown) + "s to connect", "to WiFi hotspot:", "\"airgradient-", @@ -1310,7 +1676,7 @@ static void dispSmHandler(int sm) { displayShowText("Connecting to", "Server", "..."); break; } - case APP_SM_WIFI_OK_SERVER_CONNNECTED: { + case APP_SM_WIFI_OK_SERVER_CONNECTED: { displayShowText("Server", "connection", "successful"); break; } @@ -1341,7 +1707,7 @@ static void dispSmHandler(int sm) { case APP_SM_NORMAL: { displayShowDashboard(""); } - detault: + default: break; } } @@ -1430,10 +1796,13 @@ static void updateDispLedBar(void) { */ static void tvocPoll(void) { tvocIndex = ag.sgp41.getTvocIndex(); + tvocRawIndex = ag.sgp41.getTvocRaw(); noxIndex = ag.sgp41.getNoxIndex(); - Serial.printf("tvocIndexindex: %d\r\n", tvocIndex); - Serial.printf(" NOx index: %d\r\n", noxIndex); + Serial.println(); + Serial.printf(" TVOC index: %d\r\n", tvocIndex); + Serial.printf("TVOC raw index: %d\r\n", tvocRawIndex); + Serial.printf(" NOx index: %d\r\n", noxIndex); } /** @@ -1447,15 +1816,21 @@ static void pmPoll(void) { pm10 = ag.pms5003.getPm10Ae(); pm03PCount = ag.pms5003.getPm03ParticleCount(); + Serial.println(); Serial.printf(" PMS0.1: %d\r\n", pm01); Serial.printf(" PMS2.5: %d\r\n", pm25); Serial.printf(" PMS10.0: %d\r\n", pm10); Serial.printf("PMS3.0 Count: %d\r\n", pm03PCount); + pmFailCount = 0; } else { - pm01 = -1; - pm25 = -1; - pm10 = -1; - pm03PCount = -1; + pmFailCount++; + Serial.printf("PM read failed: %d\r\n", pmFailCount); + if (pmFailCount >= 3) { + pm01 = -1; + pm25 = -1; + pm10 = -1; + pm03PCount = -1; + } } } @@ -1464,41 +1839,19 @@ static void pmPoll(void) { * */ static void sendDataToServer(void) { - JSONVar root; - root["wifi"] = WiFi.RSSI(); - if (co2Ppm >= 0) { - root["rco2"] = co2Ppm; - } - if (pm01 >= 0) { - root["pm01"] = pm01; - } - if (pm25 >= 0) { - root["pm02"] = pm25; - } - if (pm10 >= 0) { - root["pm10"] = pm10; - } - if (pm03PCount >= 0) { - root["pm003_count"] = pm03PCount; - } - if (tvocIndex >= 0) { - root["tvoc_index"] = tvocIndex; - } - if (noxIndex >= 0) { - root["noxIndex"] = noxIndex; - } - if (temp >= 0) { - root["atmp"] = temp; - } - if (hum >= 0) { - root["rhum"] = hum; - } - root["boot"] = bootCount; - - // NOTE Need determine offline mode to reset watchdog timer - if (agServer.postToServer(getDevId(), JSON.stringify(root))) { + String syncData = getServerSyncData(false); + if (agServer.postToServer(getDevId(), syncData)) { resetWatchdog(); } + + if (agMqtt.isConnected()) { + String topic = "airgradient/readings/" + getDevId(); + if (agMqtt.publish(topic.c_str(), syncData.c_str(), syncData.length())) { + Serial.println("Mqtt sync success"); + } else { + Serial.println("Mqtt sync failure"); + } + } bootCount++; } @@ -1517,3 +1870,54 @@ static void tempHumPoll(void) { Serial.println("Measure SHT failed"); } } + +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, + int32_t event_id, void *event_data) { + + ESP_LOGD(TAG, + "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", + base, event_id); + esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data; + esp_mqtt_client_handle_t client = event->client; + int msg_id; + switch ((esp_mqtt_event_id_t)event_id) { + case MQTT_EVENT_CONNECTED: + Serial.println("MQTT_EVENT_CONNECTED"); + // msg_id = esp_mqtt_client_subscribe(client, "helloworld", 0); + // Serial.printf("sent subscribe successful, msg_id=%d\r\n", msg_id); + agMqtt._connectionHandler(true); + break; + case MQTT_EVENT_DISCONNECTED: + Serial.println("MQTT_EVENT_DISCONNECTED"); + agMqtt._connectionHandler(false); + break; + case MQTT_EVENT_SUBSCRIBED: + break; + case MQTT_EVENT_UNSUBSCRIBED: + Serial.printf("MQTT_EVENT_UNSUBSCRIBED, msg_id=%d\r\n", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + Serial.printf("MQTT_EVENT_PUBLISHED, msg_id=%d\r\n", event->msg_id); + break; + case MQTT_EVENT_DATA: + Serial.println("MQTT_EVENT_DATA"); + // add null terminal to data + // event->data[event->data_len] = 0; + // rpc_attritbutes_handler(event->data, event->data_len); + break; + case MQTT_EVENT_ERROR: + Serial.println("MQTT_EVENT_ERROR"); + if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { + Serial.printf("reported from esp-tls: %d", + event->error_handle->esp_tls_last_esp_err); + Serial.printf("reported from tls stack: %d", + event->error_handle->esp_tls_stack_err); + Serial.printf("captured as transport's socket errno: %d", + event->error_handle->esp_transport_sock_errno); + } + break; + default: + Serial.printf("Other event id:%d\r\n", event->event_id); + break; + } +} diff --git a/examples/Open_Air/Open_Air.ino b/examples/Open_Air/Open_Air.ino new file mode 100644 index 0000000..6838aa7 --- /dev/null +++ b/examples/Open_Air/Open_Air.ino @@ -0,0 +1,1470 @@ +/* +This is the code for the AirGradient Open Air open-source hardware outdoor Air +Quality Monitor with an ESP32-C3 Microcontroller. + +It is an air quality monitor for PM2.5, CO2, TVOCs, NOx, Temperature and +Humidity and can send data over Wifi. + +Open source air quality monitors and kits are available: +Indoor Monitor: https://www.airgradient.com/indoor/ +Outdoor Monitor: https://www.airgradient.com/outdoor/ + +Build Instructions: +https://www.airgradient.com/documentation/open-air-pst-kit-1-3/ + +The codes needs the following libraries installed: +“WifiManager by tzapu, tablatronix” tested with version 2.0.16-rc.2 +"Arduino_JSON" by Arduino Version 0.2.0 + +Please make sure you have esp32 board manager installed. Tested with +version 2.0.11. + +Important flashing settings: +- Set board to "ESP32C3 Dev Module" +- Enable "USB CDC On Boot" +- Flash frequency "80Mhz" +- Flash mode "QIO" +- Flash size "4MB" +- Partition scheme "Default 4MB with spiffs (1.2MB APP/1,5MB SPIFFS)" +- JTAG adapter "Disabled" + +If you have any questions please visit our forum at +https://forum.airgradient.com/ + +CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License + +*/ + +#include "EEPROM.h" +#include "mqtt_client.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * + * @brief Application state machine state + * + */ +enum { + APP_SM_WIFI_MANAGER_MODE, /** In WiFi Manger Mode */ + APP_SM_WIFI_MANAGER_PORTAL_ACTIVE, /** WiFi Manager has connected to mobile + phone */ + APP_SM_WIFI_MANAGER_STA_CONNECTING, /** After SSID and PW entered and OK + clicked, connection to WiFI network is + attempted*/ + APP_SM_WIFI_MANAGER_STA_CONNECTED, /** Connecting to WiFi worked */ + APP_SM_WIFI_OK_SERVER_CONNECTING, /** Once connected to WiFi an attempt to + reach the server is performed */ + APP_SM_WIFI_OK_SERVER_CONNECTED, /** Server is reachable, all fine */ + /** Exceptions during WIFi Setup */ + APP_SM_WIFI_MANAGER_CONNECT_FAILED, /** Cannot connect to WiFi (e.g. wrong + password, WPA Enterprise etc.) */ + APP_SM_WIFI_OK_SERVER_CONNECT_FAILED, /** Connected to WiFi but server not + reachable, e.g. firewall block/ + whitelisting needed etc. */ + APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED, /** Server reachable but sensor + not configured correctly*/ + + /** During Normal Operation */ + APP_SM_WIFI_LOST, /** Connection to WiFi network failed credentials incorrect + encryption not supported etc. */ + APP_SM_SERVER_LOST, /** Connected to WiFi network but the server cannot be + reached through the internet, e.g. blocked by firewall + */ + APP_SM_SENSOR_CONFIG_FAILED, /** Server is reachable but there is some + configuration issue to be fixed on the server + side */ + APP_SM_NORMAL, +}; + +#define LED_FAST_BLINK_DELAY 250 /** ms */ +#define LED_SLOW_BLINK_DELAY 1000 /** ms */ +#define WIFI_CONNECT_COUNTDOWN_MAX 180 /** sec */ +#define WIFI_CONNECT_RETRY_MS 10000 /** ms */ +#define LED_BAR_COUNT_INIT_VALUE (-1) /** */ +#define LED_BAR_ANIMATION_PERIOD 100 /** ms */ +#define DISP_UPDATE_INTERVAL 5000 /** ms */ +#define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */ +#define SERVER_SYNC_INTERVAL 60000 /** ms */ +#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */ +#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */ +#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */ +#define SENSOR_PM_UPDATE_INTERVAL 5000 /** ms */ +#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 5000 /** ms */ +#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */ +#define WIFI_HOTSPOT_PASSWORD_DEFAULT \ + "cleanair" /** default WiFi AP password \ + */ + +/** + * @brief Use use LED bar state + */ +typedef enum { + UseLedBarOff, /** Don't use LED bar */ + UseLedBarPM, /** Use LED bar for PMS */ + UseLedBarCO2, /** Use LED bar for CO2 */ +} UseLedBar; + +/** + * @brief Schedule handle with timing period + * + */ +class AgSchedule { +public: + AgSchedule(int period, void (*handler)(void)) + : period(period), handler(handler) {} + void run(void) { + uint32_t ms = (uint32_t)(millis() - count); + if (ms >= period) { + /** Call handler */ + handler(); + + // Serial.printf("[AgSchedule] handle 0x%08x, period: %d(ms)\r\n", + // (unsigned int)handler, period); + + /** Update period time */ + count = millis(); + } + } + void setPeriod(int period) { this->period = period; } + +private: + void (*handler)(void); + int period; + int count; +}; + +/** + * @brief AirGradient server configuration and sync data + * + */ +class AgServer { +public: + void begin(void) { + configFailed = false; + serverFailed = false; + loadConfig(); + } + + /** + * @brief Get server configuration + * + * @param id Device ID + * @return true Success + * @return false Failure + */ + bool pollServerConfig(String id) { + String uri = + "http://hw.airgradient.com/sensors/airgradient:" + id + "/one/config"; + + /** Init http client */ + HTTPClient client; + if (client.begin(uri) == false) { + configFailed = true; + return false; + } + + /** Get */ + int retCode = client.GET(); + if (retCode != 200) { + client.end(); + configFailed = true; + return false; + } + + /** clear failed */ + configFailed = false; + + /** Get response string */ + String respContent = client.getString(); + client.end(); + Serial.println("Get server config: " + respContent); + + /** Parse JSON */ + JSONVar root = JSON.parse(respContent); + if (JSON.typeof(root) == "undefined") { + /** JSON invalid */ + return false; + } + + /** Get "country" */ + bool inF = false; + if (JSON.typeof_(root["country"]) == "string") { + String _country = root["country"]; + country = _country; + + if (country == "US") { + inF = true; + } else { + inF = false; + } + } + + /** Get "pmsStandard" */ + bool inUSAQI = false; + if (JSON.typeof_(root["pmStandard"]) == "string") { + String standard = root["pmStandard"]; + if (standard == "ugm3") { + inUSAQI = false; + } else { + inUSAQI = true; + } + } + + /** Get "co2CalibrationRequested" */ + if (JSON.typeof_(root["co2CalibrationRequested"]) == "boolean") { + co2Calib = root["co2CalibrationRequested"]; + } else { + co2Calib = false; + } + + /** Get "ledBarMode" */ + uint8_t ledBarMode = UseLedBarOff; + if (JSON.typeof_(root["ledBarMode"]) == "string") { + String mode = root["ledBarMode"]; + if (mode == "co2") { + ledBarMode = UseLedBarCO2; + } else if (mode == "pm") { + ledBarMode = UseLedBarPM; + } else if (mode == "off") { + ledBarMode = UseLedBarOff; + } else { + ledBarMode = UseLedBarOff; + } + } + + /** Get model */ + bool _saveConfig = false; + if (JSON.typeof_(root["model"]) == "string") { + String model = root["model"]; + if (model.length()) { + int len = model.length() < sizeof(config.models) + ? model.length() + : sizeof(config.models); + if (model != String(config.models)) { + memset(config.models, 0, sizeof(config.models)); + memcpy(config.models, model.c_str(), len); + _saveConfig = true; + } + } + } + + /** Get "mqttBrokerUrl" */ + if (JSON.typeof_(root["mqttBrokerUrl"]) == "string") { + String mqtt = root["mqttBrokerUrl"]; + if (mqtt.length()) { + int len = mqtt.length() < sizeof(config.mqttBrokers) + ? mqtt.length() + : sizeof(config.mqttBrokers); + if (mqtt != String(config.mqttBrokers)) { + memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers)); + memcpy(config.mqttBrokers, mqtt.c_str(), len); + _saveConfig = true; + } + } + } + + /** Get 'abcDays' */ + if (JSON.typeof_(root["abcDays"]) == "number") { + co2AbcCalib = root["abcDays"]; + } else { + co2AbcCalib = -1; + } + + /** Get "ledBarTestRequested" */ + if (JSON.typeof_(root["ledBarTestRequested"]) == "boolean") { + ledBarTestRequested = root["ledBarTestRequested"]; + } else { + ledBarTestRequested = false; + } + + /** Show configuration */ + showServerConfig(); + if (_saveConfig || (inF != config.inF) || (inUSAQI != config.inUSAQI) || + (ledBarMode != config.useRGBLedBar)) { + config.inF = inF; + config.inUSAQI = inUSAQI; + config.useRGBLedBar = ledBarMode; + + saveConfig(); + } + + return true; + } + + bool postToServer(String id, String payload) { + /** + * @brief Only post data if WiFi is connected + */ + if (WiFi.isConnected() == false) { + return false; + } + + Serial.printf("Post payload: %s\r\n", payload.c_str()); + + String uri = + "http://hw.airgradient.com/sensors/airgradient:" + id + "/measures"; + + WiFiClient wifiClient; + HTTPClient client; + if (client.begin(wifiClient, uri.c_str()) == false) { + return false; + } + client.addHeader("content-type", "application/json"); + int retCode = client.POST(payload); + client.end(); + + if ((retCode == 200) || (retCode == 429)) { + serverFailed = false; + return true; + } + serverFailed = true; + return false; + } + + /** + * @brief Get temperature configuration unit + * + * @return true F unit + * @return false C Unit + */ + bool isTemperatureUnitF(void) { return config.inF; } + + /** + * @brief Get PMS standard unit + * + * @return true USAQI + * @return false ugm3 + */ + bool isPMSinUSAQI(void) { return config.inUSAQI; } + + /** + * @brief Get status of get server configuration is failed + * + * @return true Failed + * @return false Success + */ + bool isConfigFailed(void) { return configFailed; } + + /** + * @brief Get status of post server configuration is failed + * + * @return true Failed + * @return false Success + */ + bool isServerFailed(void) { return serverFailed; } + + /** + * @brief Get request calibration CO2 + * + * @return true Requested. If result = true, it's clear after function call + * @return false Not-requested + */ + bool isCo2Calib(void) { + bool ret = co2Calib; + if (ret) { + co2Calib = false; + } + return ret; + } + + /** + * @brief Get request LedBar test + * + * @return true Requested. If result = true, it's clear after function call + * @return false Not-requested + */ + bool isLedBarTestRequested(void) { + bool ret = ledBarTestRequested; + if (ret) { + ledBarTestRequested = false; + } + return ret; + } + + /** + * @brief Get the Co2 auto calib period + * + * @return int days, -1 if invalid. + */ + int getCo2AbcDaysConfig(void) { return co2AbcCalib; } + + /** + * @brief Get device configuration model name + * + * @return String Model name, empty string if server failed + */ + String getModelName(void) { return String(config.models); } + + /** + * @brief Get mqttBroker url + * + * @return String Broker url, empty if server failed + */ + String getMqttBroker(void) { return String(config.mqttBrokers); } + + /** + * @brief Show server configuration parameter + */ + void showServerConfig(void) { + Serial.println("Server configuration: "); + Serial.printf(" inF: %s\r\n", config.inF ? "true" : "false"); + Serial.printf(" inUSAQI: %s\r\n", + config.inUSAQI ? "true" : "false"); + Serial.printf(" useRGBLedBar: %d\r\n", (int)config.useRGBLedBar); + Serial.printf(" Model: %s\r\n", config.models); + Serial.printf(" Mqtt Broker: %s\r\n", config.mqttBrokers); + Serial.printf(" S8 calib period: %d\r\n", co2AbcCalib); + } + + /** + * @brief Get server config led bar mode + * + * @return UseLedBar + */ + UseLedBar getLedBarMode(void) { return (UseLedBar)config.useRGBLedBar; } + + /** + * @brief Get the Country + * + * @return String + */ + String getCountry(void) { return country; } + +private: + bool configFailed; /** Flag indicate get server configuration failed */ + bool serverFailed; /** Flag indicate post data to server failed */ + bool co2Calib; /** Is co2Ppmcalibration requset */ + bool ledBarTestRequested; /** */ + int co2AbcCalib = -1; /** update auto calibration number of day */ + String country; /***/ + + struct config_s { + bool inF; + bool inUSAQI; + uint8_t useRGBLedBar; + char models[20]; + char mqttBrokers[256]; + uint32_t checksum; + }; + struct config_s config; + + void defaultConfig(void) { + config.inF = false; + config.inUSAQI = false; + memset(config.models, 0, sizeof(config.models)); + memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers)); + + Serial.println("Load config default"); + saveConfig(); + } + + void loadConfig(void) { + if (EEPROM.readBytes(0, &config, sizeof(config)) != sizeof(config)) { + config.inF = false; + config.inUSAQI = false; + memset(config.models, 0, sizeof(config.models)); + memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers)); + + Serial.println("Load configure failed"); + } else { + uint32_t sum = 0; + uint8_t *data = (uint8_t *)&config; + for (int i = 0; i < sizeof(config) - 4; i++) { + sum += data[i]; + } + if (sum != config.checksum) { + Serial.println("config checksum failed"); + defaultConfig(); + } + } + + showServerConfig(); + } + + void saveConfig(void) { + config.checksum = 0; + uint8_t *data = (uint8_t *)&config; + for (int i = 0; i < sizeof(config) - 4; i++) { + config.checksum += data[i]; + } + + EEPROM.writeBytes(0, &config, sizeof(config)); + EEPROM.commit(); + Serial.println("Save config"); + } +}; +AgServer agServer; + +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, + int32_t event_id, void *event_data); + +class AgMqtt { +private: + bool _isBegin = false; + String uri; + String hostname; + String user; + String pass; + int port; + esp_mqtt_client_handle_t client; + bool clientConnected = false; + int connectFailedCount = 0; + +public: + AgMqtt() {} + ~AgMqtt() {} + + /** + * @brief Initialize mqtt + * + * @param uri Complete mqtt uri, ex: + * mqtts://username:password@my.broker.com:4711 + * @return true Success + * @return false Failure + */ + bool begin(String uri) { + if (_isBegin) { + Serial.println("Mqtt already begin, call 'end' and try again"); + return true; + } + + if (uri.isEmpty()) { + Serial.println("Mqtt uri is empty"); + return false; + } + + this->uri = uri; + Serial.printf("mqtt init '%s'\r\n", uri.c_str()); + + /** config esp_mqtt client */ + esp_mqtt_client_config_t config = { + .uri = this->uri.c_str(), + }; + + /** init client */ + client = esp_mqtt_client_init(&config); + if (client == NULL) { + Serial.println("mqtt client init failed"); + return false; + } + + /** Register event */ + if (esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, + mqtt_event_handler, NULL) != ESP_OK) { + Serial.println("mqtt client register event failed"); + return false; + } + + if (esp_mqtt_client_start(client) != ESP_OK) { + Serial.println("mqtt client start failed"); + return false; + } + + _isBegin = true; + return true; + } + + /** + * @brief Deinitialize mqtt + * + */ + void end(void) { + if (_isBegin == false) { + return; + } + + esp_mqtt_client_disconnect(client); + esp_mqtt_client_stop(client); + esp_mqtt_client_destroy(client); + _isBegin = false; + + Serial.println("mqtt de-init"); + } + + bool publish(const char *topic, const char *payload, int len) { + if ((_isBegin == false) || (clientConnected == false)) { + return false; + } + + if (esp_mqtt_client_publish(client, topic, payload, len, 0, 0) == ESP_OK) { + return true; + } + return false; + } + + /** + * @brief Get current complete mqtt uri + * + * @return String + */ + String getUri(void) { return uri; } + + void _connectionHandler(bool connected) { + clientConnected = connected; + if (clientConnected == false) { + connectFailedCount++; + } else { + connectFailedCount = 0; + } + } + + /** + * @brief Mqtt client connect status + * + * @return true Connected + * @return false Disconnected or Not initialize + */ + bool isConnected(void) { return (_isBegin && clientConnected); } + + /** + * @brief Get number of times connection failed + * + * @return int + */ + int connectionFailedCount(void) { return connectFailedCount; } +}; +AgMqtt agMqtt; + +/** Create airgradient instance for 'OPEN_AIR_OUTDOOR' board */ +AirGradient ag(OPEN_AIR_OUTDOOR); + +static int ledSmState = APP_SM_NORMAL; + +int loopCount = 0; + +WiFiManager wifiManager; /** wifi manager instance */ +static bool wifiHasConfig = false; +static String wifiSSID = ""; + +/** Web server instance */ +WebServer webServer; + +int tvocIndex = -1; +int tvocRawIndex = -1; +int noxIndex = -1; +int co2Ppm = 0; + +int pm25_1 = -1; +int pm01_1 = -1; +int pm10_1 = -1; +int pm03PCount_1 = -1; +float temp_1 = -1001; +int hum_1 = -1; + +int pm25_2 = -1; +int pm01_2 = -1; +int pm10_2 = -1; +int pm03PCount_2 = -1; +float temp_2 = -1001; +int hum_2 = -1; + +int pm1Value01; +int pm1Value25; +int pm1Value10; +int pm1PCount; +int pm1temp; +int pm1hum; +int pm2Value01; +int pm2Value25; +int pm2Value10; +int pm2PCount; +int pm2temp; +int pm2hum; +int countPosition; +const int targetCount = 20; + +enum { + FW_MODE_PST, /** PMS5003T, S8 and SGP41 */ + FW_MODE_PPT, /** PMS5003T_1, PMS5003T_2, SGP41 */ + FW_MODE_PP /** PMS5003T_1, PMS5003T_2 */ +}; +int fw_mode = FW_MODE_PST; + +void boardInit(void); +void failedHandler(String msg); +void co2Calibration(void); +static String getDevId(void); +static void updateWiFiConnect(void); +static void tvocPoll(void); +static void pmPoll(void); +static void sendDataToServer(void); +static void co2Poll(void); +static void serverConfigPoll(void); +static const char *getFwMode(int mode); +static void showNr(void); +static void webServerInit(void); +static String getServerSyncData(bool localServer); + +bool hasSensorS8 = true; +bool hasSensorPMS1 = true; +bool hasSensorPMS2 = true; +bool hasSensorSGP = true; +AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll); +AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); +AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Poll); +AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmPoll); +AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocPoll); + +void setup() { + EEPROM.begin(512); + + Serial.begin(115200); + delay(100); /** For bester show log */ + showNr(); + + /** Board init */ + boardInit(); + + /** Server init */ + agServer.begin(); + + /** WiFi connect */ + connectToWifi(); + + if (WiFi.isConnected()) { + webServerInit(); + + /** MQTT init */ + if (agServer.getMqttBroker().isEmpty() == false) { + if (agMqtt.begin(agServer.getMqttBroker())) { + Serial.println("MQTT client init success"); + } else { + Serial.println("MQTT client init failure"); + } + } + + wifiHasConfig = true; + sendPing(); + + agServer.pollServerConfig(getDevId()); + if (agServer.isConfigFailed()) { + ledSmHandler(APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED); + delay(DISPLAY_DELAY_SHOW_CONTENT_MS); + } + } + + ledSmHandler(APP_SM_NORMAL); +} + +void loop() { + configSchedule.run(); + serverSchedule.run(); + + if (fw_mode == FW_MODE_PST) { + if (hasSensorS8) { + co2Schedule.run(); + } + } + + if (hasSensorPMS1 || hasSensorPMS2) { + pmsSchedule.run(); + } + + if (fw_mode == FW_MODE_PST || fw_mode == FW_MODE_PPT) { + if (hasSensorSGP) { + tvocSchedule.run(); + } + } + updateWiFiConnect(); +} + +void sendPing() { + JSONVar root; + root["wifi"] = WiFi.RSSI(); + root["boot"] = loopCount; + if (agServer.postToServer(getDevId(), JSON.stringify(root))) { + ledSmHandler(APP_SM_WIFI_OK_SERVER_CONNECTED); + } else { + ledSmHandler(APP_SM_WIFI_OK_SERVER_CONNECT_FAILED); + } + delay(DISPLAY_DELAY_SHOW_CONTENT_MS); +} + +static void sendDataToServer(void) { + String syncData = getServerSyncData(false); + if (agServer.postToServer(getDevId(), syncData)) { + resetWatchdog(); + } + + if (agMqtt.isConnected()) { + String topic = "airgradient/readings/" + getDevId(); + if (agMqtt.publish(topic.c_str(), syncData.c_str(), syncData.length())) { + Serial.println("Mqtt sync success"); + } else { + Serial.println("Mqtt sync failure"); + } + } + loopCount++; +} + +void resetWatchdog() { + Serial.println("Watchdog reset"); + ag.watchdog.reset(); +} + +bool wifiMangerClientConnected(void) { + return WiFi.softAPgetStationNum() ? true : false; +} + +// Wifi Manager +void connectToWifi() { + wifiSSID = "airgradient-" + String(getNormalizedMac()); + + wifiManager.setConfigPortalBlocking(false); + wifiManager.setTimeout(WIFI_CONNECT_COUNTDOWN_MAX); + + wifiManager.setAPCallback([](WiFiManager *obj) { + /** This callback if wifi connnected failed and try to start configuration + * portal */ + ledSmState = APP_SM_WIFI_MANAGER_MODE; + }); + wifiManager.setSaveConfigCallback([]() { + /** Wifi connected save the configuration */ + ledSmHandler(APP_SM_WIFI_MANAGER_STA_CONNECTED); + }); + wifiManager.setSaveParamsCallback([]() { + /** Wifi set connect: ssid, password */ + ledSmHandler(APP_SM_WIFI_MANAGER_STA_CONNECTING); + }); + wifiManager.autoConnect(wifiSSID.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT); + + xTaskCreate( + [](void *obj) { + while (wifiManager.getConfigPortalActive()) { + wifiManager.process(); + } + vTaskDelete(NULL); + }, + "wifi_cfg", 4096, NULL, 10, NULL); + + uint32_t stimer = millis(); + bool clientConnectChanged = false; + while (wifiManager.getConfigPortalActive()) { + if (WiFi.isConnected() == false) { + if (ledSmState == APP_SM_WIFI_MANAGER_MODE) { + uint32_t ms = (uint32_t)(millis() - stimer); + if (ms >= 100) { + stimer = millis(); + ledSmHandler(ledSmState); + } + } + + /** Check for client connect to change led color */ + bool clientConnected = wifiMangerClientConnected(); + if (clientConnected != clientConnectChanged) { + clientConnectChanged = clientConnected; + if (clientConnectChanged) { + ledSmHandler(APP_SM_WIFI_MANAGER_PORTAL_ACTIVE); + } else { + ledSmHandler(APP_SM_WIFI_MANAGER_MODE); + } + } + } + } + + /** Show display wifi connect result failed */ + ag.statusLed.setOff(); + delay(2000); + if (WiFi.isConnected() == false) { + ledSmHandler(APP_SM_WIFI_MANAGER_CONNECT_FAILED); + } +} + +String getNormalizedMac() { + String mac = WiFi.macAddress(); + mac.replace(":", ""); + mac.toLowerCase(); + return mac; +} + +void boardInit(void) { + if (Wire.begin(ag.getI2cSdaPin(), ag.getI2cSclPin()) == false) { + failedHandler("Init I2C failed"); + } + + ag.watchdog.begin(); + ag.button.begin(); + ag.statusLed.begin(); + + /** detect sensor: PMS5003, PMS5003T, SGP41 and S8 */ + if (ag.s8.begin(Serial1) == false) { + hasSensorS8 = false; + + Serial.println("CO2 S8 sensor not found"); + Serial.println("Can not detect S8 run mode 'PPT'"); + fw_mode = FW_MODE_PPT; + + /** De-initialize Serial1 */ + Serial1.end(); + } + if (ag.sgp41.begin(Wire) == false) { + hasSensorSGP = false; + Serial.println("SGP sensor not found"); + + Serial.println("Can not detect SGP run mode 'PP'"); + fw_mode = FW_MODE_PP; + } + + if (ag.pms5003t_1.begin(Serial0) == false) { + hasSensorPMS1 = false; + Serial.println("PMS1 sensor not found"); + + if (ag.pms5003t_2.begin(Serial1) == false) { + hasSensorPMS2 = false; + Serial.println("PMS2 sensor not found"); + } + } + + if (fw_mode != FW_MODE_PST) { + if (ag.pms5003t_2.begin(Serial1) == false) { + hasSensorPMS2 = false; + Serial.println("PMS2 sensor not found"); + } + } + + /** update the PMS poll period base on fw mode and sensor available */ + if (fw_mode != FW_MODE_PST) { + if (hasSensorPMS1 && hasSensorPMS2) { + pmsSchedule.setPeriod(2000); + } + } + + Serial.printf("Firmware node: %s\r\n", getFwMode(fw_mode)); +} + +void failedHandler(String msg) { + while (true) { + Serial.println(msg); + vTaskDelay(1000); + } +} + +void co2Calibration(void) { + /** Count down for co2CalibCountdown secs */ + for (int i = 0; i < SENSOR_CO2_CALIB_COUNTDOWN_MAX; i++) { + Serial.printf("Start CO2 calib after %d sec\r\n", + SENSOR_CO2_CALIB_COUNTDOWN_MAX - i); + delay(1000); + } + + if (ag.s8.setBaselineCalibration()) { + Serial.println("Calibration success"); + delay(1000); + Serial.println("Wait for calib finish..."); + int count = 0; + while (ag.s8.isBaseLineCalibrationDone() == false) { + delay(1000); + count++; + } + Serial.printf("Calib finish after %d sec\r\n", count); + delay(2000); + } else { + Serial.println("Calibration failure!!!"); + delay(2000); + } +} + +/** + * @brief WiFi reconnect handler + */ +static void updateWiFiConnect(void) { + static uint32_t lastRetry; + if (wifiHasConfig == false) { + return; + } + if (WiFi.isConnected()) { + lastRetry = millis(); + return; + } + uint32_t ms = (uint32_t)(millis() - lastRetry); + if (ms >= WIFI_CONNECT_RETRY_MS) { + lastRetry = millis(); + WiFi.reconnect(); + + Serial.printf("Re-Connect WiFi\r\n"); + } +} + +/** + * @brief Update tvocIndexindex + * + */ +static void tvocPoll(void) { + tvocIndex = ag.sgp41.getTvocIndex(); + tvocRawIndex = ag.sgp41.getTvocRaw(); + noxIndex = ag.sgp41.getNoxIndex(); + + Serial.println(); + Serial.printf(" TVOC index: %d\r\n", tvocIndex); + Serial.printf("TVOC raw index: %d\r\n", tvocRawIndex); + Serial.printf(" NOx index: %d\r\n", noxIndex); +} + +/** + * @brief Update PMS data + * + */ +static void pmPoll(void) { + bool pmsResult_1 = false; + bool pmsResult_2 = false; + if (hasSensorPMS1 && ag.pms5003t_1.readData()) { + pm01_1 = ag.pms5003t_1.getPm01Ae(); + pm25_1 = ag.pms5003t_1.getPm25Ae(); + pm10_1 = ag.pms5003t_1.getPm10Ae(); + pm03PCount_1 = ag.pms5003t_1.getPm03ParticleCount(); + temp_1 = ag.pms5003t_1.getTemperature(); + hum_1 = ag.pms5003t_1.getRelativeHumidity(); + + pmsResult_1 = true; + + Serial.println(); + Serial.printf("[1] PMS0.1: %d\r\n", pm01_1); + Serial.printf("[1] PMS2.5: %d\r\n", pm25_1); + Serial.printf("[1] PMS10.0: %d\r\n", pm10_1); + Serial.printf("[1]PMS3.0 Count: %d\r\n", pm03PCount_1); + Serial.printf("[1] Temperature: %0.2f\r\n", temp_1); + Serial.printf("[1] Humidity: %d\r\n", hum_1); + } else { + pm01_1 = -1; + pm25_1 = -1; + pm10_1 = -1; + pm03PCount_1 = -1; + temp_1 = -1001; + hum_1 = -1; + } + + if (hasSensorPMS2 && ag.pms5003t_2.readData()) { + pm01_2 = ag.pms5003t_2.getPm01Ae(); + pm25_2 = ag.pms5003t_2.getPm25Ae(); + pm10_2 = ag.pms5003t_2.getPm10Ae(); + pm03PCount_2 = ag.pms5003t_2.getPm03ParticleCount(); + temp_2 = ag.pms5003t_2.getTemperature(); + hum_2 = ag.pms5003t_2.getRelativeHumidity(); + + pmsResult_2 = true; + + Serial.println(); + Serial.printf("[2] PMS0.1: %d\r\n", pm01_2); + Serial.printf("[2] PMS2.5: %d\r\n", pm25_2); + Serial.printf("[2] PMS10.0: %d\r\n", pm10_2); + Serial.printf("[2]PMS3.0 Count: %d\r\n", pm03PCount_2); + Serial.printf("[2] Temperature: %0.2f\r\n", temp_2); + Serial.printf("[2] Humidity: %d\r\n", hum_2); + } else { + pm01_2 = -1; + pm25_2 = -1; + pm10_2 = -1; + pm03PCount_2 = -1; + temp_2 = -1001; + hum_2 = -1; + } + + if (hasSensorPMS1 && hasSensorPMS2 && pmsResult_1 && pmsResult_2) { + /** Get total of PMS1*/ + pm1Value01 = pm1Value01 + pm01_1; + pm1Value25 = pm1Value25 + pm25_1; + pm1Value10 = pm1Value10 + pm10_1; + pm1PCount = pm1PCount + pm03PCount_1; + pm1temp = pm1temp + temp_1; + pm1hum = pm1hum + hum_1; + + /** Get total of PMS2 */ + pm2Value01 = pm2Value01 + pm01_2; + pm2Value25 = pm2Value25 + pm25_2; + pm2Value10 = pm2Value10 + pm10_2; + pm2PCount = pm2PCount + pm03PCount_2; + pm2temp = pm2temp + temp_2; + pm2hum = pm2hum + hum_2; + + countPosition++; + + /** Get average */ + if (countPosition == targetCount) { + pm01_1 = pm1Value01 / targetCount; + pm25_1 = pm1Value25 / targetCount; + pm10_1 = pm1Value10 / targetCount; + pm03PCount_1 = pm1PCount / targetCount; + temp_1 = pm1temp / targetCount; + hum_1 = pm1hum / targetCount; + + pm01_2 = pm2Value01 / targetCount; + pm25_2 = pm2Value25 / targetCount; + pm10_2 = pm2Value10 / targetCount; + pm03PCount_2 = pm2PCount / targetCount; + temp_2 = pm2temp / targetCount; + hum_2 = pm2hum / targetCount; + + countPosition = 0; + + pm1Value01 = 0; + pm1Value25 = 0; + pm1Value10 = 0; + pm1PCount = 0; + pm1temp = 0; + pm1hum = 0; + pm2Value01 = 0; + pm2Value25 = 0; + pm2Value10 = 0; + pm2PCount = 0; + pm2temp = 0; + pm2hum = 0; + } + } +} + +static void co2Poll(void) { + co2Ppm = ag.s8.getCo2(); + Serial.printf("CO2 index: %d\r\n", co2Ppm); +} + +static void serverConfigPoll(void) { + if (agServer.pollServerConfig(getDevId())) { + /** Only support CO2 S8 sensor on FW_MODE_PST */ + if (fw_mode == FW_MODE_PST) { + if (agServer.isCo2Calib()) { + if (hasSensorS8) { + co2Calibration(); + } else { + Serial.println("CO2 S8 not available, calib ignored"); + } + } + + if (agServer.getCo2AbcDaysConfig() > 0) { + if (hasSensorS8) { + int newHour = agServer.getCo2AbcDaysConfig() * 24; + Serial.printf("abcDays config: %d days(%d hours)\r\n", + agServer.getCo2AbcDaysConfig(), newHour); + int curHour = ag.s8.getAbcPeriod(); + Serial.printf("Current config: %d (hours)\r\n", ag.s8.getAbcPeriod()); + if (curHour == newHour) { + Serial.println("set 'abcDays' ignored"); + } else { + if (ag.s8.setAbcPeriod(agServer.getCo2AbcDaysConfig() * 24) == + false) { + Serial.println("Set S8 abcDays period calib failed"); + } else { + Serial.println("Set S8 abcDays period calib success"); + } + } + } + } else { + Serial.println("CO2 S8 not available, set 'abcDays' ignored"); + } + } + + String mqttUri = agServer.getMqttBroker(); + if (mqttUri != agMqtt.getUri()) { + agMqtt.end(); + if (agMqtt.begin(mqttUri)) { + Serial.println("Connect to new mqtt broker success"); + } else { + Serial.println("Connect to new mqtt broker failed"); + } + } + } +} + +static String getDevId(void) { return getNormalizedMac(); } + +void ledBlinkDelay(uint32_t tdelay) { + ag.statusLed.setOn(); + delay(tdelay); + ag.statusLed.setOff(); + delay(tdelay); +} + +void ledSmHandler(int sm) { + if (sm > APP_SM_NORMAL) { + return; + } + + ledSmState = sm; + switch (sm) { + case APP_SM_WIFI_MANAGER_MODE: { + ag.statusLed.setToggle(); + break; + } + case APP_SM_WIFI_MANAGER_PORTAL_ACTIVE: { + ag.statusLed.setOn(); + break; + } + case APP_SM_WIFI_MANAGER_STA_CONNECTING: { + ag.statusLed.setOff(); + break; + } + case APP_SM_WIFI_MANAGER_STA_CONNECTED: { + ag.statusLed.setOff(); + break; + } + case APP_SM_WIFI_OK_SERVER_CONNECTING: { + ag.statusLed.setOff(); + break; + } + case APP_SM_WIFI_OK_SERVER_CONNECTED: { + ag.statusLed.setOff(); + + /** two time slow blink, then off */ + for (int i = 0; i < 2; i++) { + ledBlinkDelay(LED_SLOW_BLINK_DELAY); + } + + ag.statusLed.setOff(); + break; + } + case APP_SM_WIFI_MANAGER_CONNECT_FAILED: { + /** Three time fast blink then 2 sec pause. Repeat 3 times */ + ag.statusLed.setOff(); + + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 3; i++) { + ledBlinkDelay(LED_FAST_BLINK_DELAY); + } + delay(2000); + } + ag.statusLed.setOff(); + break; + } + case APP_SM_WIFI_OK_SERVER_CONNECT_FAILED: { + ag.statusLed.setOff(); + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 4; i++) { + ledBlinkDelay(LED_FAST_BLINK_DELAY); + } + delay(2000); + } + ag.statusLed.setOff(); + break; + } + case APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED: { + ag.statusLed.setOff(); + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 5; i++) { + ledBlinkDelay(LED_FAST_BLINK_DELAY); + } + delay(2000); + } + ag.statusLed.setOff(); + break; + } + case APP_SM_WIFI_LOST: { + ag.statusLed.setOff(); + break; + } + case APP_SM_SERVER_LOST: { + ag.statusLed.setOff(); + break; + } + case APP_SM_SENSOR_CONFIG_FAILED: { + ag.statusLed.setOff(); + break; + } + case APP_SM_NORMAL: { + ag.statusLed.setOff(); + break; + } + default: + break; + } +} + +static const char *getFwMode(int mode) { + switch (mode) { + case FW_MODE_PST: + return "FW_MODE_PST"; + case FW_MODE_PPT: + return "FW_MODE_PPT"; + case FW_MODE_PP: + return "FW_MODE_PP"; + default: + break; + } + return "FW_MODE_UNKNOW"; +} + +static void showNr(void) { Serial.println("Serial nr: " + getDevId()); } + +void webServerMeasureCurrentGet(void) { + webServer.send(200, "application/json", getServerSyncData(true)); +} + +void webServerHandler(void *param) { + for (;;) { + webServer.handleClient(); + } +} + +static void webServerInit(void) { + String host = "airgradient_" + getDevId(); + if (!MDNS.begin(host)) { + Serial.println("Init MDNS failed"); + return; + } + + webServer.on("/measures/current", HTTP_GET, webServerMeasureCurrentGet); + webServer.begin(); + MDNS.addService("http", "tcp", 80); + + if (xTaskCreate(webServerHandler, "webserver", 1024 * 4, NULL, 5, NULL) != + pdTRUE) { + Serial.println("Create task handle webserver failed"); + } + Serial.printf("Webserver init: %s.local\r\n", host.c_str()); +} + +static String getServerSyncData(bool localServer) { + JSONVar root; + root["wifi"] = WiFi.RSSI(); + root["boot"] = loopCount; + if (localServer) { + root["serialno"] = getDevId(); + } + + if (fw_mode == FW_MODE_PST) { + if (hasSensorS8) { + if (co2Ppm >= 0) { + root["rco2"] = co2Ppm; + } + } + + if (hasSensorPMS1) { + if (pm01_1 >= 0) { + root["pm01"] = pm01_1; + } + if (pm25_1 >= 0) { + root["pm02"] = pm25_1; + } + if (pm10_1 >= 0) { + root["pm10"] = pm10_1; + } + if (pm03PCount_1 >= 0) { + root["pm003_count"] = pm03PCount_1; + } + if (temp_1 > -1001) { + root["atmp"] = ag.round2(temp_1); + } + if (hum_1 >= 0) { + root["rhum"] = hum_1; + } + } else if (hasSensorPMS2) { + if (pm01_2 >= 0) { + root["pm01"] = pm01_2; + } + if (pm25_2 >= 0) { + root["pm02"] = pm25_2; + } + if (pm10_2 >= 0) { + root["pm10"] = pm10_2; + } + if (pm03PCount_2 >= 0) { + root["pm003_count"] = pm03PCount_2; + } + if (temp_2 > -1001) { + root["atmp"] = ag.round2(temp_2); + } + if (hum_2 >= 0) { + root["rhum"] = hum_2; + } + } + } + + if ((fw_mode == FW_MODE_PPT) || (fw_mode == FW_MODE_PST)) { + if (hasSensorSGP) { + if (tvocIndex > 0) { + root["tvoc_index"] = tvocIndex; + } + if (tvocRawIndex >= 0) { + root["tvoc_raw"] = tvocRawIndex; + } + if (noxIndex > 0) { + root["nox_index"] = noxIndex; + } + } + } + + if ((fw_mode == FW_MODE_PP) || (fw_mode == FW_MODE_PPT)) { + if (hasSensorPMS1 && hasSensorPMS2) { + root["pm01"] = ag.round2((pm01_1 + pm01_2) / 2.0); + root["pm02"] = ag.round2((pm25_1 + pm25_2) / 2.0); + root["pm10"] = ag.round2((pm10_1 + pm10_2) / 2.0); + root["pm003_count"] = ag.round2((pm03PCount_1 + pm03PCount_2) / 2.0); + root["atmp"] = ag.round2((temp_1 + temp_2) / 2.0); + root["rhum"] = ag.round2((hum_1 + hum_2) / 2.0); + } + if (hasSensorPMS1) { + root["channels"]["1"]["pm01"] = pm01_1; + root["channels"]["1"]["pm02"] = pm25_1; + root["channels"]["1"]["pm10"] = pm10_1; + root["channels"]["1"]["pm003_count"] = pm03PCount_1; + root["channels"]["1"]["atmp"] = ag.round2(temp_1); + root["channels"]["1"]["rhum"] = hum_1; + } + if (hasSensorPMS2) { + root["channels"]["2"]["pm01"] = pm01_2; + root["channels"]["2"]["pm02"] = pm25_2; + root["channels"]["2"]["pm10"] = pm10_2; + root["channels"]["2"]["pm003_count"] = pm03PCount_2; + root["channels"]["2"]["atmp"] = ag.round2(temp_2); + root["channels"]["2"]["rhum"] = hum_2; + } + } + + return JSON.stringify(root); +} + +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, + int32_t event_id, void *event_data) { + + ESP_LOGD(TAG, + "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", + base, event_id); + esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data; + esp_mqtt_client_handle_t client = event->client; + int msg_id; + switch ((esp_mqtt_event_id_t)event_id) { + case MQTT_EVENT_CONNECTED: + Serial.println("MQTT_EVENT_CONNECTED"); + // msg_id = esp_mqtt_client_subscribe(client, "helloworld", 0); + // Serial.printf("sent subscribe successful, msg_id=%d\r\n", msg_id); + agMqtt._connectionHandler(true); + break; + case MQTT_EVENT_DISCONNECTED: + Serial.println("MQTT_EVENT_DISCONNECTED"); + agMqtt._connectionHandler(false); + break; + case MQTT_EVENT_SUBSCRIBED: + break; + case MQTT_EVENT_UNSUBSCRIBED: + Serial.printf("MQTT_EVENT_UNSUBSCRIBED, msg_id=%d\r\n", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + Serial.printf("MQTT_EVENT_PUBLISHED, msg_id=%d\r\n", event->msg_id); + break; + case MQTT_EVENT_DATA: + Serial.println("MQTT_EVENT_DATA"); + // add null terminal to data + // event->data[event->data_len] = 0; + // rpc_attritbutes_handler(event->data, event->data_len); + break; + case MQTT_EVENT_ERROR: + Serial.println("MQTT_EVENT_ERROR"); + if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { + Serial.printf("reported from esp-tls: %d", + event->error_handle->esp_tls_last_esp_err); + Serial.printf("reported from tls stack: %d", + event->error_handle->esp_tls_stack_err); + Serial.printf("captured as transport's socket errno: %d", + event->error_handle->esp_transport_sock_errno); + } + break; + default: + Serial.printf("Other event id:%d\r\n", event->event_id); + break; + } +} diff --git a/examples/Open_Air_O/Open_Air_O.ino b/examples/Open_Air_O/Open_Air_O.ino deleted file mode 100644 index 9bfeac2..0000000 --- a/examples/Open_Air_O/Open_Air_O.ino +++ /dev/null @@ -1,974 +0,0 @@ -/* -This is the code for the AirGradient Open Air open-source hardware outdoor Air -Quality Monitor with an ESP32-C3 Microcontroller. - -It is an air quality monitor for PM2.5, CO2, TVOCs, NOx, Temperature and -Humidity and can send data over Wifi. - -Open source air quality monitors and kits are available: -Indoor Monitor: https://www.airgradient.com/indoor/ -Outdoor Monitor: https://www.airgradient.com/outdoor/ - -Build Instructions: -https://www.airgradient.com/documentation/open-air-pst-kit-1-3/ - -The codes needs the following libraries installed: -“WifiManager by tzapu, tablatronix” tested with version 2.0.16-rc.2 -"Arduino_JSON" by Arduino Version 0.2.0 - -Please make sure you have esp32 board manager installed. Tested with -version 2.0.11. - -Important flashing settings: -- Set board to "ESP32C3 Dev Module" -- Enable "USB CDC On Boot" -- Flash frequency "80Mhz" -- Flash mode "QIO" -- Flash size "4MB" -- Partition scheme "Default 4MB with spiffs (1.2MB APP/1,5MB SPIFFS)" -- JTAG adapter "Disabled" - -If you have any questions please visit our forum at -https://forum.airgradient.com/ - -CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License - -*/ - -#include -#include -#include -#include -#include -#include - -/** - * - * @brief Application state machine state - * - */ -enum { - APP_SM_WIFI_MANAGER_MODE, /** In WiFi Manger Mode */ - APP_SM_WIFI_MAMAGER_PORTAL_ACTIVE, /** WiFi Manager has connected to mobile - phone */ - APP_SM_WIFI_MANAGER_STA_CONNECTING, /** After SSID and PW entered and OK - clicked, connection to WiFI network is - attempted*/ - APP_SM_WIFI_MANAGER_STA_CONNECTED, /** Connecting to WiFi worked */ - APP_SM_WIFI_OK_SERVER_CONNECTING, /** Once connected to WiFi an attempt to - reach the server is performed */ - APP_SM_WIFI_OK_SERVER_CONNNECTED, /** Server is reachable, all fine */ - /** Exceptions during WIFi Setup */ - APP_SM_WIFI_MANAGER_CONNECT_FAILED, /** Cannot connect to WiFi (e.g. wrong - password, WPA Enterprise etc.) */ - APP_SM_WIFI_OK_SERVER_CONNECT_FAILED, /** Connected to WiFi but server not - reachable, e.g. firewall block/ - whitelisting needed etc. */ - APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED, /** Server reachable but sensor - not configured correctly*/ - - /** During Normal Operation */ - APP_SM_WIFI_LOST, /** Connection to WiFi network failed credentials incorrect - encryption not supported etc. */ - APP_SM_SERVER_LOST, /** Connected to WiFi network but the server cannot be - reached through the internet, e.g. blocked by firewall - */ - APP_SM_SENSOR_CONFIG_FAILED, /** Server is reachable but there is some - configuration issue to be fixed on the server - side */ - APP_SM_NORMAL, -}; - -#define LED_FAST_BLINK_DELAY 250 /** ms */ -#define LED_SLOW_BLINK_DELAY 1000 /** ms */ -#define WIFI_CONNECT_COUNTDOWN_MAX 180 /** sec */ -#define WIFI_CONNECT_RETRY_MS 10000 /** ms */ -#define LED_BAR_COUNT_INIT_VALUE (-1) /** */ -#define LED_BAR_ANIMATION_PERIOD 100 /** ms */ -#define DISP_UPDATE_INTERVAL 5000 /** ms */ -#define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */ -#define SERVER_SYNC_INTERVAL 60000 /** ms */ -#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */ -#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */ -#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */ -#define SENSOR_PM_UPDATE_INTERVAL 5000 /** ms */ -#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 5000 /** ms */ -#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */ -#define WIFI_HOTSPOT_PASSWORD_DEFAULT \ - "cleanair" /** default WiFi AP password \ - */ - -/** - * @brief Use use LED bar state - */ -typedef enum { - UseLedBarOff, /** Don't use LED bar */ - UseLedBarPM, /** Use LED bar for PMS */ - UseLedBarCO2, /** Use LED bar for CO2 */ -} UseLedBar; - -/** - * @brief Schedule handle with timing period - * - */ -class AgSchedule { -public: - AgSchedule(int period, void (*handler)(void)) - : period(period), handler(handler) {} - void run(void) { - uint32_t ms = (uint32_t)(millis() - count); - if (ms >= period) { - /** Call handler */ - handler(); - - Serial.printf("[AgSchedule] handle 0x%08x, period: %d(ms)\r\n", - (unsigned int)handler, period); - - /** Update period time */ - count = millis(); - } - } - void setPeriod(int period) { this->period = period; } - -private: - void (*handler)(void); - int period; - int count; -}; - -/** - * @brief AirGradient server configuration and sync data - * - */ -class AgServer { -public: - void begin(void) { - inF = false; - inUSAQI = false; - configFailed = false; - serverFailed = false; - memset(models, 0, sizeof(models)); - memset(mqttBroker, 0, sizeof(mqttBroker)); - } - - /** - * @brief Get server configuration - * - * @param id Device ID - * @return true Success - * @return false Failure - */ - bool pollServerConfig(String id) { - String uri = - "http://hw.airgradient.com/sensors/airgradient:" + id + "/one/config"; - - /** Init http client */ - HTTPClient client; - if (client.begin(uri) == false) { - configFailed = true; - return false; - } - - /** Get */ - int retCode = client.GET(); - if (retCode != 200) { - client.end(); - configFailed = true; - return false; - } - - /** clear failed */ - configFailed = false; - - /** Get response string */ - String respContent = client.getString(); - client.end(); - Serial.println("Get server config: " + respContent); - - /** Parse JSON */ - JSONVar root = JSON.parse(respContent); - if (JSON.typeof(root) == "undefined") { - /** JSON invalid */ - return false; - } - - /** Get "country" */ - if (JSON.typeof_(root["country"]) == "string") { - String country = root["country"]; - if (country == "US") { - inF = true; - } else { - inF = false; - } - } - - /** Get "pmStandard" */ - if (JSON.typeof_(root["pmStandard"]) == "string") { - String standard = root["pmStandard"]; - if (standard == "ugm3") { - inUSAQI = false; - } else { - inUSAQI = true; - } - } - - /** Get "co2CalibrationRequested" */ - if (JSON.typeof_(root["co2CalibrationRequested"]) == "boolean") { - co2Calib = root["co2CalibrationRequested"]; - } - - /** Get "ledBarMode" */ - if (JSON.typeof_(root["ledBarMode"]) == "string") { - String mode = root["ledBarMode"]; - if (mode == "co2") { - ledBarMode = UseLedBarCO2; - } else if (mode == "pm") { - ledBarMode = UseLedBarPM; - } else if (mode == "off") { - ledBarMode = UseLedBarOff; - } else { - ledBarMode = UseLedBarOff; - } - } - - /** Get model */ - if (JSON.typeof_(root["model"]) == "string") { - String model = root["model"]; - if (model.length()) { - int len = - model.length() < sizeof(models) ? model.length() : sizeof(models); - memset(models, 0, sizeof(models)); - memcpy(models, model.c_str(), len); - } - } - - /** Get "mqttBrokerUrl" */ - if (JSON.typeof_(root["mqttBrokerUrl"]) == "string") { - String mqtt = root["mqttBrokerUrl"]; - if (mqtt.length()) { - int len = mqtt.length() < sizeof(mqttBroker) ? mqtt.length() - : sizeof(mqttBroker); - memset(mqttBroker, 0, sizeof(mqttBroker)); - memcpy(mqttBroker, mqtt.c_str(), len); - } - } - - /** Get 'abcDays' */ - if (JSON.typeof_(root["abcDays"]) == "number") { - co2AbcCalib = root["abcDays"]; - } else { - co2AbcCalib = -1; - } - - /** Show configuration */ - showServerConfig(); - - return true; - } - - bool postToServer(String id, String payload) { - /** - * @brief Only post data if WiFi is connected - */ - if (WiFi.isConnected() == false) { - return false; - } - - Serial.printf("Post payload: %s\r\n", payload.c_str()); - - String uri = - "http://hw.airgradient.com/sensors/airgradient:" + id + "/measures"; - - WiFiClient wifiClient; - HTTPClient client; - if (client.begin(wifiClient, uri.c_str()) == false) { - return false; - } - client.addHeader("content-type", "application/json"); - int retCode = client.POST(payload); - client.end(); - - if ((retCode == 200) || (retCode == 429)) { - serverFailed = false; - return true; - } - serverFailed = true; - return false; - } - - /** - * @brief Get temperature configuration unit - * - * @return true F unit - * @return false C Unit - */ - bool isTemperatureUnitF(void) { return inF; } - - /** - * @brief Get PMS standard unit - * - * @return true USAQI - * @return false ugm3 - */ - bool isPMSinUSAQI(void) { return inUSAQI; } - - /** - * @brief Get status of get server coniguration is failed - * - * @return true Failed - * @return false Success - */ - bool isConfigFailed(void) { return configFailed; } - - /** - * @brief Get status of post server configuration is failed - * - * @return true Failed - * @return false Success - */ - bool isServerFailed(void) { return serverFailed; } - - /** - * @brief Get request calibration CO2 - * - * @return true Requested. If result = true, it's clear after function call - * @return false Not-requested - */ - bool isCo2Calib(void) { - bool ret = co2Calib; - if (ret) { - co2Calib = false; - } - return ret; - } - - /** - * @brief Get the Co2 auto calib period - * - * @return int days, -1 if invalid. - */ - int getCo2Abccalib(void) { return co2AbcCalib; } - - /** - * @brief Get device configuration model name - * - * @return String Model name, empty string if server failed - */ - String getModelName(void) { return String(models); } - - /** - * @brief Get mqttBroker url - * - * @return String Broker url, empty if server failed - */ - String getMqttBroker(void) { return String(mqttBroker); } - - /** - * @brief Show server configuration parameter - */ - void showServerConfig(void) { - Serial.println("Server configuration: "); - Serial.printf(" inF: %s\r\n", inF ? "true" : "false"); - Serial.printf(" inUSAQI: %s\r\n", inUSAQI ? "true" : "false"); - Serial.printf(" useRGBLedBar: %d\r\n", (int)ledBarMode); - Serial.printf(" Model: %s\r\n", models); - Serial.printf(" Mqtt Broker: %s\r\n", mqttBroker); - Serial.printf(" S8 calib period: %d\r\n", co2AbcCalib); - } - - /** - * @brief Get server config led bar mode - * - * @return UseLedBar - */ - UseLedBar getLedBarMode(void) { return ledBarMode; } - -private: - bool inF; /** Temperature unit, true: F, false: C */ - bool inUSAQI; /** PMS unit, true: USAQI, false: ugm3 */ - bool configFailed; /** Flag indicate get server configuration failed */ - bool serverFailed; /** Flag indicate post data to server failed */ - bool co2Calib; /** Is co2Ppmcalibration requset */ - int co2AbcCalib = -1; /** update auto calibration number of day */ - UseLedBar ledBarMode = UseLedBarCO2; /** */ - char models[20]; /** */ - char mqttBroker[256]; /** */ -}; -AgServer agServer; - -/** Create airgradient instance for 'OPEN_AIR_OUTDOOR' board */ -AirGradient ag(OPEN_AIR_OUTDOOR); - -static int ledSmState = APP_SM_NORMAL; - -int loopCount = 0; - -WiFiManager wifiManager; /** wifi manager instance */ -static bool wifiHasConfig = false; -static String wifiSSID = ""; - -int tvocIndex = -1; -int noxIndex = -1; -int co2Ppm = 0; - -int pm25_1 = -1; -int pm01_1 = -1; -int pm10_1 = -1; -int pm03PCount_1 = -1; -float temp_1; -int hum_1; - -int pm25_2 = -1; -int pm01_2 = -1; -int pm10_2 = -1; -int pm03PCount_2 = -1; -float temp_2; -int hum_2; - -int pm1Value01; -int pm1Value25; -int pm1Value10; -int pm1PCount; -int pm1temp; -int pm1hum; -int pm2Value01; -int pm2Value25; -int pm2Value10; -int pm2PCount; -int pm2temp; -int pm2hum; -int countPosition; -const int targetCount = 20; - -enum { - FW_MODE_PST, /** PMS5003T, S8 and SGP41 */ - FW_MODE_PPT, /** PMS5003T_1, PMS5003T_2, SGP41 */ - FW_MODE_PP /** PMS5003T_1, PMS5003T_2 */ -}; -int fw_mode = FW_MODE_PST; - -void boardInit(void); -void failedHandler(String msg); -void co2Calibration(void); -static String getDevId(void); -static void updateWiFiConnect(void); -static void tvocPoll(void); -static void pmPoll(void); -static void sendDataToServer(void); -static void co2Poll(void); -static void serverConfigPoll(void); -static const char *getFwMode(int mode); - -AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll); -AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); -AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Poll); -AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmPoll); -AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocPoll); - -void setup() { - Serial.begin(115200); - - /** Board init */ - boardInit(); - - /** Server init */ - agServer.begin(); - - /** WiFi connect */ - connectToWifi(); - - if (WiFi.isConnected()) { - wifiHasConfig = true; - sendPing(); - - agServer.pollServerConfig(getDevId()); - if (agServer.isConfigFailed()) { - ledSmHandler(APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED); - delay(DISPLAY_DELAY_SHOW_CONTENT_MS); - } - } - - ledSmHandler(APP_SM_NORMAL); -} - -void loop() { - configSchedule.run(); - serverSchedule.run(); - if (fw_mode == FW_MODE_PST) { - co2Schedule.run(); - } - pmsSchedule.run(); - if (fw_mode == FW_MODE_PST || fw_mode == FW_MODE_PPT) { - tvocSchedule.run(); - } - updateWiFiConnect(); -} - -void sendPing() { - JSONVar root; - root["wifi"] = WiFi.RSSI(); - root["boot"] = loopCount; - if (agServer.postToServer(getDevId(), JSON.stringify(root))) { - ledSmHandler(APP_SM_WIFI_OK_SERVER_CONNNECTED); - } else { - ledSmHandler(APP_SM_WIFI_OK_SERVER_CONNECT_FAILED); - } - delay(DISPLAY_DELAY_SHOW_CONTENT_MS); -} - -static void sendDataToServer(void) { - JSONVar root; - root["wifi"] = WiFi.RSSI(); - root["boot"] = loopCount; - if (fw_mode == FW_MODE_PST) { - if (co2Ppm >= 0) { - root["rco2"] = co2Ppm; - } - if (pm01_1 >= 0) { - root["pm01"] = pm01_1; - } - if (pm25_1 >= 0) { - root["pm02"] = pm25_1; - } - if (pm10_1 >= 0) { - root["pm10"] = pm10_1; - } - if (pm03PCount_1 >= 0) { - root["pm003_count"] = pm03PCount_1; - } - if (tvocIndex >= 0) { - root["tvoc_index"] = tvocIndex; - } - if (noxIndex >= 0) { - root["noxIndex"] = noxIndex; - } - if (temp_1 >= 0) { - root["atmp"] = temp_1; - } - if (hum_1 >= 0) { - root["rhum"] = hum_1; - } - } else if (fw_mode == FW_MODE_PPT) { - if (tvocIndex > 0) { - root["tvoc_index"] = loopCount; - } - if (noxIndex > 0) { - root["nox_index"] = loopCount; - } - } - - if (fw_mode == FW_MODE_PP || FW_MODE_PPT) { - root["pm01"] = (int)((pm01_1 + pm01_2) / 2); - root["pm02"] = (int)((pm25_1 + pm25_2) / 2); - root["pm003_count"] = (int)((pm03PCount_1 + pm03PCount_2) / 2); - root["atmp"] = (int)((temp_1 + temp_2) / 2); - root["rhum"] = (int)((hum_1 + hum_2) / 2); - root["channels"]["1"]["pm01"] = pm01_1; - root["channels"]["1"]["pm02"] = pm25_1; - root["channels"]["1"]["pm10"] = pm10_1; - root["channels"]["1"]["pm003_count"] = pm03PCount_1; - root["channels"]["1"]["atmp"] = temp_1; - root["channels"]["1"]["rhum"] = hum_1; - root["channels"]["2"]["pm01"] = pm01_2; - root["channels"]["2"]["pm02"] = pm25_2; - root["channels"]["2"]["pm10"] = pm10_2; - root["channels"]["2"]["pm003_count"] = pm03PCount_2; - root["channels"]["2"]["atmp"] = temp_2; - root["channels"]["2"]["rhum"] = hum_2; - } - - /** Send data to sensor */ - if (agServer.postToServer(getDevId(), JSON.stringify(root))) { - resetWatchdog(); - } - loopCount++; -} - -void resetWatchdog() { - Serial.println("Watchdog reset"); - ag.watchdog.reset(); -} - -bool wifiMangerClientConnected(void) { - return WiFi.softAPgetStationNum() ? true : false; -} - -// Wifi Manager -void connectToWifi() { - wifiSSID = "airgradient-" + String(getNormalizedMac()); - - wifiManager.setConfigPortalBlocking(false); - wifiManager.setTimeout(WIFI_CONNECT_COUNTDOWN_MAX); - - wifiManager.setAPCallback([](WiFiManager *obj) { - /** This callback if wifi connnected failed and try to start configuration - * portal */ - ledSmState = APP_SM_WIFI_MANAGER_MODE; - }); - wifiManager.setSaveConfigCallback([]() { - /** Wifi connected save the configuration */ - ledSmHandler(APP_SM_WIFI_MANAGER_STA_CONNECTED); - }); - wifiManager.setSaveParamsCallback([]() { - /** Wifi set connect: ssid, password */ - ledSmHandler(APP_SM_WIFI_MANAGER_STA_CONNECTING); - }); - wifiManager.autoConnect(wifiSSID.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT); - - xTaskCreate( - [](void *obj) { - while (wifiManager.getConfigPortalActive()) { - wifiManager.process(); - } - vTaskDelete(NULL); - }, - "wifi_cfg", 4096, NULL, 10, NULL); - - uint32_t stimer = millis(); - bool clientConnectChanged = false; - while (wifiManager.getConfigPortalActive()) { - if (WiFi.isConnected() == false) { - if (ledSmState == APP_SM_WIFI_MANAGER_MODE) { - uint32_t ms = (uint32_t)(millis() - stimer); - if (ms >= 100) { - stimer = millis(); - ledSmHandler(ledSmState); - } - } - - /** Check for client connect to change led color */ - bool clientConnected = wifiMangerClientConnected(); - if (clientConnected != clientConnectChanged) { - clientConnectChanged = clientConnected; - if (clientConnectChanged) { - ledSmHandler(APP_SM_WIFI_MAMAGER_PORTAL_ACTIVE); - } else { - ledSmHandler(APP_SM_WIFI_MANAGER_MODE); - } - } - } - } - - /** Show display wifi connect result failed */ - ag.statusLed.setOff(); - delay(2000); - if (WiFi.isConnected() == false) { - ledSmHandler(APP_SM_WIFI_MANAGER_CONNECT_FAILED); - } -} - -String getNormalizedMac() { - String mac = WiFi.macAddress(); - mac.replace(":", ""); - mac.toLowerCase(); - return mac; -} - -void boardInit(void) { - if (Wire.begin(ag.getI2cSdaPin(), ag.getI2cSclPin()) == false) { - failedHandler("Init I2C failed"); - } - - ag.watchdog.begin(); - - ag.button.begin(); - - ag.statusLed.begin(); - - /** detect sensor: PMS5003, PMS5003T, SGP41 and S8 */ - if (ag.s8.begin(Serial1) == false) { - Serial.println("S8 not detect run mode 'PPT'"); - fw_mode = FW_MODE_PPT; - - /** De-initialize Serial1 */ - Serial1.end(); - } - if (ag.sgp41.begin(Wire) == false) { - if (fw_mode == FW_MODE_PST) { - failedHandler("Init SGP41 failed"); - } else { - Serial.println("SGP41 not detect run mode 'PP'"); - fw_mode = FW_MODE_PP; - } - } - - if (ag.pms5003t_1.begin(Serial0) == false) { - failedHandler("Init PMS5003T_1 failed"); - } - if (fw_mode != FW_MODE_PST) { - if (ag.pms5003t_2.begin(Serial1) == false) { - failedHandler("Init PMS5003T_2 failed"); - } - } - - if (fw_mode != FW_MODE_PST) { - pmsSchedule.setPeriod(2000); - } - - Serial.printf("Firmware node: %s\r\n", getFwMode(fw_mode)); -} - -void failedHandler(String msg) { - while (true) { - Serial.println(msg); - vTaskDelay(1000); - } -} - -void co2Calibration(void) { - /** Count down for co2CalibCountdown secs */ - for (int i = 0; i < SENSOR_CO2_CALIB_COUNTDOWN_MAX; i++) { - Serial.printf("Start CO2 calib after %d sec\r\n", - SENSOR_CO2_CALIB_COUNTDOWN_MAX - i); - delay(1000); - } - - if (ag.s8.setBaselineCalibration()) { - Serial.println("Calibration success"); - delay(1000); - Serial.println("Wait for calib finish..."); - int count = 0; - while (ag.s8.isBaseLineCalibrationDone() == false) { - delay(1000); - count++; - } - Serial.printf("Calib finish after %d sec\r\n", count); - delay(2000); - } else { - Serial.println("Calibration failure!!!"); - delay(2000); - } -} - -/** - * @brief WiFi reconnect handler - */ -static void updateWiFiConnect(void) { - static uint32_t lastRetry; - if (wifiHasConfig == false) { - return; - } - if (WiFi.isConnected()) { - lastRetry = millis(); - return; - } - uint32_t ms = (uint32_t)(millis() - lastRetry); - if (ms >= WIFI_CONNECT_RETRY_MS) { - lastRetry = millis(); - WiFi.reconnect(); - - Serial.printf("Re-Connect WiFi\r\n"); - } -} - -/** - * @brief Update tvocIndexindex - * - */ -static void tvocPoll(void) { - tvocIndex = ag.sgp41.getTvocIndex(); - noxIndex = ag.sgp41.getNoxIndex(); - - Serial.printf("tvocIndexindex: %d\r\n", tvocIndex); - Serial.printf(" NOx index: %d\r\n", noxIndex); -} - -/** - * @brief Update PMS data - * - */ -static void pmPoll(void) { - if (fw_mode == FW_MODE_PST) { - if (ag.pms5003t_1.readData()) { - pm01_1 = ag.pms5003t_1.getPm01Ae(); - pm25_1 = ag.pms5003t_1.getPm25Ae(); - pm25_1 = ag.pms5003t_1.getPm10Ae(); - pm03PCount_1 = ag.pms5003t_1.getPm03ParticleCount(); - temp_1 = ag.pms5003t_1.getTemperature(); - hum_1 = ag.pms5003t_1.getRelativeHumidity(); - } - } else { - if (ag.pms5003t_1.readData() && ag.pms5003t_2.readData()) { - pm1Value01 = pm1Value01 + ag.pms5003t_1.getPm01Ae(); - pm1Value25 = pm1Value25 + ag.pms5003t_1.getPm25Ae(); - pm1Value10 = pm1Value10 + ag.pms5003t_1.getPm10Ae(); - pm1PCount = pm1PCount + ag.pms5003t_1.getPm03ParticleCount(); - pm1temp = pm1temp + ag.pms5003t_1.getTemperature(); - pm1hum = pm1hum + ag.pms5003t_1.getRelativeHumidity(); - pm2Value01 = pm2Value01 + ag.pms5003t_2.getPm01Ae(); - pm2Value25 = pm2Value25 + ag.pms5003t_2.getPm25Ae(); - pm2Value10 = pm2Value10 + ag.pms5003t_2.getPm10Ae(); - pm2PCount = pm2PCount + ag.pms5003t_2.getPm03ParticleCount(); - pm2temp = pm2temp + ag.pms5003t_2.getTemperature(); - pm2hum = pm2hum + ag.pms5003t_2.getRelativeHumidity(); - countPosition++; - if (countPosition == targetCount) { - pm01_1 = pm1Value01 / targetCount; - pm25_1 = pm1Value25 / targetCount; - pm10_1 = pm1Value10 / targetCount; - pm03PCount_1 = pm1PCount / targetCount; - temp_1 = pm1temp / targetCount; - hum_1 = pm1hum / targetCount; - pm01_2 = pm2Value01 / targetCount; - pm25_2 = pm2Value25 / targetCount; - pm10_2 = pm2Value10 / targetCount; - pm03PCount_2 = pm2PCount / targetCount; - temp_2 = pm2temp / targetCount; - hum_2 = pm2hum / targetCount; - - countPosition = 0; - - pm1Value01 = 0; - pm1Value25 = 0; - pm1Value10 = 0; - pm1PCount = 0; - pm1temp = 0; - pm1hum = 0; - pm2Value01 = 0; - pm2Value25 = 0; - pm2Value10 = 0; - pm2PCount = 0; - pm2temp = 0; - pm2hum = 0; - } - } - } -} - -static void co2Poll(void) { - co2Ppm = ag.s8.getCo2(); - Serial.printf("CO2 index: %d\r\n", co2Ppm); -} - -static void serverConfigPoll(void) { - if (agServer.pollServerConfig(getDevId())) { - /** Only support CO2 S8 sensor on FW_MODE_PST */ - if (fw_mode == FW_MODE_PST) { - if (agServer.isCo2Calib()) { - co2Calibration(); - } - if (agServer.getCo2Abccalib() > 0) { - if (ag.s8.setAutoCalib(agServer.getCo2Abccalib() * 24) == false) { - Serial.println("Set S8 auto calib failed"); - } - } - } - } -} - -static String getDevId(void) { return getNormalizedMac(); } - -void ledBlinkDelay(uint32_t tdelay) { - ag.statusLed.setOn(); - delay(tdelay); - ag.statusLed.setOff(); - delay(tdelay); -} - -void ledSmHandler(int sm) { - if (sm > APP_SM_NORMAL) { - return; - } - - ledSmState = sm; - switch (sm) { - case APP_SM_WIFI_MANAGER_MODE: { - ag.statusLed.setToggle(); - break; - } - case APP_SM_WIFI_MAMAGER_PORTAL_ACTIVE: { - ag.statusLed.setOn(); - break; - } - case APP_SM_WIFI_MANAGER_STA_CONNECTING: { - ag.statusLed.setOff(); - break; - } - case APP_SM_WIFI_MANAGER_STA_CONNECTED: { - ag.statusLed.setOff(); - break; - } - case APP_SM_WIFI_OK_SERVER_CONNECTING: { - ag.statusLed.setOff(); - break; - } - case APP_SM_WIFI_OK_SERVER_CONNNECTED: { - ag.statusLed.setOff(); - - /** two time slow blink, then off */ - for (int i = 0; i < 2; i++) { - ledBlinkDelay(LED_SLOW_BLINK_DELAY); - } - - ag.statusLed.setOff(); - break; - } - case APP_SM_WIFI_MANAGER_CONNECT_FAILED: { - /** Three time fast blink then 2 sec pause. Repeat 3 times */ - ag.statusLed.setOff(); - - for (int j = 0; j < 3; j++) { - for (int i = 0; i < 3; i++) { - ledBlinkDelay(LED_FAST_BLINK_DELAY); - } - delay(2000); - } - ag.statusLed.setOff(); - break; - } - case APP_SM_WIFI_OK_SERVER_CONNECT_FAILED: { - ag.statusLed.setOff(); - for (int j = 0; j < 3; j++) { - for (int i = 0; i < 4; i++) { - ledBlinkDelay(LED_FAST_BLINK_DELAY); - } - delay(2000); - } - ag.statusLed.setOff(); - break; - } - case APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED: { - ag.statusLed.setOff(); - for (int j = 0; j < 3; j++) { - for (int i = 0; i < 5; i++) { - ledBlinkDelay(LED_FAST_BLINK_DELAY); - } - delay(2000); - } - ag.statusLed.setOff(); - break; - } - case APP_SM_WIFI_LOST: { - ag.statusLed.setOff(); - break; - } - case APP_SM_SERVER_LOST: { - ag.statusLed.setOff(); - break; - } - case APP_SM_SENSOR_CONFIG_FAILED: { - ag.statusLed.setOff(); - break; - } - case APP_SM_NORMAL: { - ag.statusLed.setOff(); - break; - } - default: - break; - } -} - -static const char *getFwMode(int mode) { - switch (mode) { - case FW_MODE_PST: - return "FW_MODE_PST"; - case FW_MODE_PPT: - return "FW_MODE_PPT"; - case FW_MODE_PP: - return "FW_MODE_PP"; - default: - break; - } - return "FW_MODE_UNKNOW"; -} diff --git a/library.properties b/library.properties index 5de192c..2941f5b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AirGradient Air Quality Sensor -version=3.0.3 +version=3.0.4 author=AirGradient maintainer=AirGradient sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display. diff --git a/src/AirGradient.cpp b/src/AirGradient.cpp index 8246876..44d7305 100644 --- a/src/AirGradient.cpp +++ b/src/AirGradient.cpp @@ -1,6 +1,6 @@ #include "AirGradient.h" -#define AG_LIB_VER "3.0.3" +#define AG_LIB_VER "3.0.4" AirGradient::AirGradient(BoardType type) : pms5003(type), pms5003t_1(type), pms5003t_2(type), s8(type), sgp41(type), @@ -36,3 +36,7 @@ int AirGradient::getI2cSclPin(void) { String AirGradient::getVersion(void) { return AG_LIB_VER; } BoardType AirGradient::getBoardType(void) { return boardType; } + +double AirGradient::round2(double value) { + return (int)(value * 100 + 0.5) / 100.0; +} diff --git a/src/AirGradient.h b/src/AirGradient.h index 2a1c102..376f43d 100644 --- a/src/AirGradient.h +++ b/src/AirGradient.h @@ -1,17 +1,17 @@ #ifndef _AIR_GRADIENT_H_ #define _AIR_GRADIENT_H_ -#include "display/oled.h" -#include "main/BoardDef.h" -#include "main/HardwareWatchdog.h" -#include "main/LedBar.h" -#include "main/PushButton.h" -#include "main/StatusLed.h" -#include "pms/pms5003.h" -#include "pms/pms5003t.h" -#include "s8/s8.h" -#include "sgp41/sgp41.h" -#include "sht/sht.h" +#include "Display/Display.h" +#include "Main/BoardDef.h" +#include "Main/HardwareWatchdog.h" +#include "Main/LedBar.h" +#include "Main/PushButton.h" +#include "Main/StatusLed.h" +#include "PMS/PMS5003.h" +#include "PMS/PMS5003T.h" +#include "S8/S8.h" +#include "Sgp41/Sgp41.h" +#include "Sht/Sht.h" /** * @brief Class with define all the sensor has supported by Airgradient. Each @@ -107,6 +107,14 @@ public: */ String getVersion(void); + /** + * @brief Round double value with for 2 decimal + * + * @param valuem Round value + * @return double + */ + double round2(double value); + private: BoardType boardType; }; diff --git a/src/display/oled.cpp b/src/Display/Display.cpp similarity index 97% rename from src/display/oled.cpp rename to src/Display/Display.cpp index 24d1a44..3bc433e 100644 --- a/src/display/oled.cpp +++ b/src/Display/Display.cpp @@ -1,6 +1,6 @@ -#include "oled.h" -#include "../library/Adafruit_SH110x/Adafruit_SH110X.h" -#include "../library/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.h" +#include "Display.h" +#include "../Libraries/Adafruit_SH110x/Adafruit_SH110X.h" +#include "../Libraries/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.h" #define disp(func) \ if (this->_boardType == DIY_BASIC) { \ diff --git a/src/display/oled.h b/src/Display/Display.h similarity index 100% rename from src/display/oled.h rename to src/Display/Display.h diff --git a/src/library/Adafruit-GFX-Library/.github/ISSUE_TEMPLATE.md b/src/Libraries/Adafruit-GFX-Library/.github/ISSUE_TEMPLATE.md similarity index 100% rename from src/library/Adafruit-GFX-Library/.github/ISSUE_TEMPLATE.md rename to src/Libraries/Adafruit-GFX-Library/.github/ISSUE_TEMPLATE.md diff --git a/src/library/Adafruit-GFX-Library/.github/PULL_REQUEST_TEMPLATE.md b/src/Libraries/Adafruit-GFX-Library/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from src/library/Adafruit-GFX-Library/.github/PULL_REQUEST_TEMPLATE.md rename to src/Libraries/Adafruit-GFX-Library/.github/PULL_REQUEST_TEMPLATE.md diff --git a/src/library/Adafruit-GFX-Library/.github/workflows/githubci.yml b/src/Libraries/Adafruit-GFX-Library/.github/workflows/githubci.yml similarity index 100% rename from src/library/Adafruit-GFX-Library/.github/workflows/githubci.yml rename to src/Libraries/Adafruit-GFX-Library/.github/workflows/githubci.yml diff --git a/src/library/Adafruit-GFX-Library/.gitignore b/src/Libraries/Adafruit-GFX-Library/.gitignore similarity index 100% rename from src/library/Adafruit-GFX-Library/.gitignore rename to src/Libraries/Adafruit-GFX-Library/.gitignore diff --git a/src/library/Adafruit-GFX-Library/Adafruit_GFX.cpp b/src/Libraries/Adafruit-GFX-Library/Adafruit_GFX.cpp similarity index 100% rename from src/library/Adafruit-GFX-Library/Adafruit_GFX.cpp rename to src/Libraries/Adafruit-GFX-Library/Adafruit_GFX.cpp diff --git a/src/library/Adafruit-GFX-Library/Adafruit_GFX.h b/src/Libraries/Adafruit-GFX-Library/Adafruit_GFX.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Adafruit_GFX.h rename to src/Libraries/Adafruit-GFX-Library/Adafruit_GFX.h diff --git a/src/library/Adafruit-GFX-Library/Adafruit_GrayOLED.cpp b/src/Libraries/Adafruit-GFX-Library/Adafruit_GrayOLED.cpp similarity index 100% rename from src/library/Adafruit-GFX-Library/Adafruit_GrayOLED.cpp rename to src/Libraries/Adafruit-GFX-Library/Adafruit_GrayOLED.cpp diff --git a/src/library/Adafruit-GFX-Library/Adafruit_GrayOLED.h b/src/Libraries/Adafruit-GFX-Library/Adafruit_GrayOLED.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Adafruit_GrayOLED.h rename to src/Libraries/Adafruit-GFX-Library/Adafruit_GrayOLED.h diff --git a/src/library/Adafruit-GFX-Library/Adafruit_SPITFT.cpp b/src/Libraries/Adafruit-GFX-Library/Adafruit_SPITFT.cpp similarity index 100% rename from src/library/Adafruit-GFX-Library/Adafruit_SPITFT.cpp rename to src/Libraries/Adafruit-GFX-Library/Adafruit_SPITFT.cpp diff --git a/src/library/Adafruit-GFX-Library/Adafruit_SPITFT.h b/src/Libraries/Adafruit-GFX-Library/Adafruit_SPITFT.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Adafruit_SPITFT.h rename to src/Libraries/Adafruit-GFX-Library/Adafruit_SPITFT.h diff --git a/src/library/Adafruit-GFX-Library/Adafruit_SPITFT_Macros.h b/src/Libraries/Adafruit-GFX-Library/Adafruit_SPITFT_Macros.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Adafruit_SPITFT_Macros.h rename to src/Libraries/Adafruit-GFX-Library/Adafruit_SPITFT_Macros.h diff --git a/src/library/Adafruit-GFX-Library/CMakeLists.txt b/src/Libraries/Adafruit-GFX-Library/CMakeLists.txt similarity index 100% rename from src/library/Adafruit-GFX-Library/CMakeLists.txt rename to src/Libraries/Adafruit-GFX-Library/CMakeLists.txt diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMono12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMono12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMono12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMono12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMono18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMono18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMono18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMono18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMono24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMono24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMono24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMono24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMono9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMono9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMono9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMono9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoBold12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBold12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoBold12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBold12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoBold18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBold18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoBold18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBold18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoBold24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBold24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoBold24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBold24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoBold9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBold9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoBold9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBold9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoOblique12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoOblique12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoOblique12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoOblique12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoOblique18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoOblique18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoOblique18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoOblique18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoOblique24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoOblique24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoOblique24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoOblique24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeMonoOblique9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoOblique9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeMonoOblique9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeMonoOblique9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSans12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSans12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSans12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSans12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSans18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSans18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSans18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSans18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSans24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSans24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSans24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSans24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSans9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSans9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSans9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSans9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansBold12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBold12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansBold12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBold12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansBold18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBold18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansBold18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBold18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansBold24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBold24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansBold24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBold24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansBold9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBold9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansBold9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBold9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansOblique12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansOblique12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansOblique12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansOblique12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansOblique18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansOblique18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansOblique18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansOblique18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansOblique24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansOblique24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansOblique24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansOblique24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSansOblique9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansOblique9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSansOblique9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSansOblique9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerif12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerif12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerif12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerif12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerif18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerif18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerif18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerif18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerif24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerif24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerif24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerif24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerif9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerif9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerif9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerif9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifBold12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBold12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifBold12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBold12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifBold18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBold18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifBold18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBold18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifBold24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBold24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifBold24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBold24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifBold9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBold9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifBold9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBold9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifItalic12pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifItalic12pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifItalic12pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifItalic12pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifItalic18pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifItalic18pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifItalic18pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifItalic18pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifItalic24pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifItalic24pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifItalic24pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifItalic24pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/FreeSerifItalic9pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifItalic9pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/FreeSerifItalic9pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/FreeSerifItalic9pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/Org_01.h b/src/Libraries/Adafruit-GFX-Library/Fonts/Org_01.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/Org_01.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/Org_01.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/Picopixel.h b/src/Libraries/Adafruit-GFX-Library/Fonts/Picopixel.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/Picopixel.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/Picopixel.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/Tiny3x3a2pt7b.h b/src/Libraries/Adafruit-GFX-Library/Fonts/Tiny3x3a2pt7b.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/Tiny3x3a2pt7b.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/Tiny3x3a2pt7b.h diff --git a/src/library/Adafruit-GFX-Library/Fonts/TomThumb.h b/src/Libraries/Adafruit-GFX-Library/Fonts/TomThumb.h similarity index 100% rename from src/library/Adafruit-GFX-Library/Fonts/TomThumb.h rename to src/Libraries/Adafruit-GFX-Library/Fonts/TomThumb.h diff --git a/src/library/Adafruit-GFX-Library/README.md b/src/Libraries/Adafruit-GFX-Library/README.md similarity index 100% rename from src/library/Adafruit-GFX-Library/README.md rename to src/Libraries/Adafruit-GFX-Library/README.md diff --git a/src/library/Adafruit-GFX-Library/component.mk b/src/Libraries/Adafruit-GFX-Library/component.mk similarity index 100% rename from src/library/Adafruit-GFX-Library/component.mk rename to src/Libraries/Adafruit-GFX-Library/component.mk diff --git a/src/library/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvas.ino b/src/Libraries/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvas.ino similarity index 100% rename from src/library/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvas.ino rename to src/Libraries/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvas.ino diff --git a/src/library/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.cpp b/src/Libraries/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.cpp similarity index 100% rename from src/library/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.cpp rename to src/Libraries/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.cpp diff --git a/src/library/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.h b/src/Libraries/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.h similarity index 100% rename from src/library/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.h rename to src/Libraries/Adafruit-GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.h diff --git a/src/library/Adafruit-GFX-Library/examples/mock_ili9341/mock_ili9341.ino b/src/Libraries/Adafruit-GFX-Library/examples/mock_ili9341/mock_ili9341.ino similarity index 100% rename from src/library/Adafruit-GFX-Library/examples/mock_ili9341/mock_ili9341.ino rename to src/Libraries/Adafruit-GFX-Library/examples/mock_ili9341/mock_ili9341.ino diff --git a/src/library/Adafruit-GFX-Library/fontconvert/Makefile b/src/Libraries/Adafruit-GFX-Library/fontconvert/Makefile similarity index 100% rename from src/library/Adafruit-GFX-Library/fontconvert/Makefile rename to src/Libraries/Adafruit-GFX-Library/fontconvert/Makefile diff --git a/src/library/Adafruit-GFX-Library/fontconvert/bdf2adafruit.py b/src/Libraries/Adafruit-GFX-Library/fontconvert/bdf2adafruit.py similarity index 100% rename from src/library/Adafruit-GFX-Library/fontconvert/bdf2adafruit.py rename to src/Libraries/Adafruit-GFX-Library/fontconvert/bdf2adafruit.py diff --git a/src/library/Adafruit-GFX-Library/fontconvert/fontconvert.c b/src/Libraries/Adafruit-GFX-Library/fontconvert/fontconvert.c similarity index 100% rename from src/library/Adafruit-GFX-Library/fontconvert/fontconvert.c rename to src/Libraries/Adafruit-GFX-Library/fontconvert/fontconvert.c diff --git a/src/library/Adafruit-GFX-Library/fontconvert/fontconvert_win.md b/src/Libraries/Adafruit-GFX-Library/fontconvert/fontconvert_win.md similarity index 100% rename from src/library/Adafruit-GFX-Library/fontconvert/fontconvert_win.md rename to src/Libraries/Adafruit-GFX-Library/fontconvert/fontconvert_win.md diff --git a/src/library/Adafruit-GFX-Library/fontconvert/makefonts.sh b/src/Libraries/Adafruit-GFX-Library/fontconvert/makefonts.sh similarity index 100% rename from src/library/Adafruit-GFX-Library/fontconvert/makefonts.sh rename to src/Libraries/Adafruit-GFX-Library/fontconvert/makefonts.sh diff --git a/src/library/Adafruit-GFX-Library/gfxfont.h b/src/Libraries/Adafruit-GFX-Library/gfxfont.h similarity index 100% rename from src/library/Adafruit-GFX-Library/gfxfont.h rename to src/Libraries/Adafruit-GFX-Library/gfxfont.h diff --git a/src/library/Adafruit-GFX-Library/glcdfont.c b/src/Libraries/Adafruit-GFX-Library/glcdfont.c similarity index 100% rename from src/library/Adafruit-GFX-Library/glcdfont.c rename to src/Libraries/Adafruit-GFX-Library/glcdfont.c diff --git a/src/library/Adafruit-GFX-Library/library.properties b/src/Libraries/Adafruit-GFX-Library/library.properties similarity index 100% rename from src/library/Adafruit-GFX-Library/library.properties rename to src/Libraries/Adafruit-GFX-Library/library.properties diff --git a/src/library/Adafruit-GFX-Library/license.txt b/src/Libraries/Adafruit-GFX-Library/license.txt similarity index 100% rename from src/library/Adafruit-GFX-Library/license.txt rename to src/Libraries/Adafruit-GFX-Library/license.txt diff --git a/src/library/Adafruit_BusIO/.github/ISSUE_TEMPLATE.md b/src/Libraries/Adafruit_BusIO/.github/ISSUE_TEMPLATE.md similarity index 100% rename from src/library/Adafruit_BusIO/.github/ISSUE_TEMPLATE.md rename to src/Libraries/Adafruit_BusIO/.github/ISSUE_TEMPLATE.md diff --git a/src/library/Adafruit_BusIO/.github/PULL_REQUEST_TEMPLATE.md b/src/Libraries/Adafruit_BusIO/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from src/library/Adafruit_BusIO/.github/PULL_REQUEST_TEMPLATE.md rename to src/Libraries/Adafruit_BusIO/.github/PULL_REQUEST_TEMPLATE.md diff --git a/src/library/Adafruit_BusIO/.github/workflows/githubci.yml b/src/Libraries/Adafruit_BusIO/.github/workflows/githubci.yml similarity index 100% rename from src/library/Adafruit_BusIO/.github/workflows/githubci.yml rename to src/Libraries/Adafruit_BusIO/.github/workflows/githubci.yml diff --git a/src/library/Adafruit_BusIO/Adafruit_BusIO_Register.cpp b/src/Libraries/Adafruit_BusIO/Adafruit_BusIO_Register.cpp similarity index 100% rename from src/library/Adafruit_BusIO/Adafruit_BusIO_Register.cpp rename to src/Libraries/Adafruit_BusIO/Adafruit_BusIO_Register.cpp diff --git a/src/library/Adafruit_BusIO/Adafruit_BusIO_Register.h b/src/Libraries/Adafruit_BusIO/Adafruit_BusIO_Register.h similarity index 100% rename from src/library/Adafruit_BusIO/Adafruit_BusIO_Register.h rename to src/Libraries/Adafruit_BusIO/Adafruit_BusIO_Register.h diff --git a/src/library/Adafruit_BusIO/Adafruit_I2CDevice.cpp b/src/Libraries/Adafruit_BusIO/Adafruit_I2CDevice.cpp similarity index 100% rename from src/library/Adafruit_BusIO/Adafruit_I2CDevice.cpp rename to src/Libraries/Adafruit_BusIO/Adafruit_I2CDevice.cpp diff --git a/src/library/Adafruit_BusIO/Adafruit_I2CDevice.h b/src/Libraries/Adafruit_BusIO/Adafruit_I2CDevice.h similarity index 100% rename from src/library/Adafruit_BusIO/Adafruit_I2CDevice.h rename to src/Libraries/Adafruit_BusIO/Adafruit_I2CDevice.h diff --git a/src/library/Adafruit_BusIO/Adafruit_I2CRegister.h b/src/Libraries/Adafruit_BusIO/Adafruit_I2CRegister.h similarity index 100% rename from src/library/Adafruit_BusIO/Adafruit_I2CRegister.h rename to src/Libraries/Adafruit_BusIO/Adafruit_I2CRegister.h diff --git a/src/library/Adafruit_BusIO/Adafruit_SPIDevice.cpp b/src/Libraries/Adafruit_BusIO/Adafruit_SPIDevice.cpp similarity index 100% rename from src/library/Adafruit_BusIO/Adafruit_SPIDevice.cpp rename to src/Libraries/Adafruit_BusIO/Adafruit_SPIDevice.cpp diff --git a/src/library/Adafruit_BusIO/Adafruit_SPIDevice.h b/src/Libraries/Adafruit_BusIO/Adafruit_SPIDevice.h similarity index 100% rename from src/library/Adafruit_BusIO/Adafruit_SPIDevice.h rename to src/Libraries/Adafruit_BusIO/Adafruit_SPIDevice.h diff --git a/src/library/Adafruit_BusIO/CMakeLists.txt b/src/Libraries/Adafruit_BusIO/CMakeLists.txt similarity index 100% rename from src/library/Adafruit_BusIO/CMakeLists.txt rename to src/Libraries/Adafruit_BusIO/CMakeLists.txt diff --git a/src/library/Adafruit_BusIO/LICENSE b/src/Libraries/Adafruit_BusIO/LICENSE similarity index 100% rename from src/library/Adafruit_BusIO/LICENSE rename to src/Libraries/Adafruit_BusIO/LICENSE diff --git a/src/library/Adafruit_BusIO/README.md b/src/Libraries/Adafruit_BusIO/README.md similarity index 100% rename from src/library/Adafruit_BusIO/README.md rename to src/Libraries/Adafruit_BusIO/README.md diff --git a/src/library/Adafruit_BusIO/component.mk b/src/Libraries/Adafruit_BusIO/component.mk similarity index 100% rename from src/library/Adafruit_BusIO/component.mk rename to src/Libraries/Adafruit_BusIO/component.mk diff --git a/src/library/Adafruit_BusIO/examples/i2c_address_detect/i2c_address_detect.ino b/src/Libraries/Adafruit_BusIO/examples/i2c_address_detect/i2c_address_detect.ino similarity index 100% rename from src/library/Adafruit_BusIO/examples/i2c_address_detect/i2c_address_detect.ino rename to src/Libraries/Adafruit_BusIO/examples/i2c_address_detect/i2c_address_detect.ino diff --git a/src/library/Adafruit_BusIO/examples/i2c_readwrite/i2c_readwrite.ino b/src/Libraries/Adafruit_BusIO/examples/i2c_readwrite/i2c_readwrite.ino similarity index 100% rename from src/library/Adafruit_BusIO/examples/i2c_readwrite/i2c_readwrite.ino rename to src/Libraries/Adafruit_BusIO/examples/i2c_readwrite/i2c_readwrite.ino diff --git a/src/library/Adafruit_BusIO/examples/i2c_registers/i2c_registers.ino b/src/Libraries/Adafruit_BusIO/examples/i2c_registers/i2c_registers.ino similarity index 100% rename from src/library/Adafruit_BusIO/examples/i2c_registers/i2c_registers.ino rename to src/Libraries/Adafruit_BusIO/examples/i2c_registers/i2c_registers.ino diff --git a/src/library/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino b/src/Libraries/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino similarity index 100% rename from src/library/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino rename to src/Libraries/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino diff --git a/src/library/Adafruit_BusIO/examples/spi_modetest/spi_modetest.ino b/src/Libraries/Adafruit_BusIO/examples/spi_modetest/spi_modetest.ino similarity index 100% rename from src/library/Adafruit_BusIO/examples/spi_modetest/spi_modetest.ino rename to src/Libraries/Adafruit_BusIO/examples/spi_modetest/spi_modetest.ino diff --git a/src/library/Adafruit_BusIO/examples/spi_readwrite/spi_readwrite.ino b/src/Libraries/Adafruit_BusIO/examples/spi_readwrite/spi_readwrite.ino similarity index 100% rename from src/library/Adafruit_BusIO/examples/spi_readwrite/spi_readwrite.ino rename to src/Libraries/Adafruit_BusIO/examples/spi_readwrite/spi_readwrite.ino diff --git a/src/library/Adafruit_BusIO/examples/spi_register_bits/spi_register_bits.ino b/src/Libraries/Adafruit_BusIO/examples/spi_register_bits/spi_register_bits.ino similarity index 100% rename from src/library/Adafruit_BusIO/examples/spi_register_bits/spi_register_bits.ino rename to src/Libraries/Adafruit_BusIO/examples/spi_register_bits/spi_register_bits.ino diff --git a/src/library/Adafruit_BusIO/examples/spi_registers/spi_registers.ino b/src/Libraries/Adafruit_BusIO/examples/spi_registers/spi_registers.ino similarity index 100% rename from src/library/Adafruit_BusIO/examples/spi_registers/spi_registers.ino rename to src/Libraries/Adafruit_BusIO/examples/spi_registers/spi_registers.ino diff --git a/src/library/Adafruit_BusIO/library.properties b/src/Libraries/Adafruit_BusIO/library.properties similarity index 100% rename from src/library/Adafruit_BusIO/library.properties rename to src/Libraries/Adafruit_BusIO/library.properties diff --git a/src/library/Adafruit_NeoPixel/.github/ISSUE_TEMPLATE.md b/src/Libraries/Adafruit_NeoPixel/.github/ISSUE_TEMPLATE.md similarity index 100% rename from src/library/Adafruit_NeoPixel/.github/ISSUE_TEMPLATE.md rename to src/Libraries/Adafruit_NeoPixel/.github/ISSUE_TEMPLATE.md diff --git a/src/library/Adafruit_NeoPixel/.github/PULL_REQUEST_TEMPLATE.md b/src/Libraries/Adafruit_NeoPixel/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from src/library/Adafruit_NeoPixel/.github/PULL_REQUEST_TEMPLATE.md rename to src/Libraries/Adafruit_NeoPixel/.github/PULL_REQUEST_TEMPLATE.md diff --git a/src/library/Adafruit_NeoPixel/.github/workflows/githubci.yml b/src/Libraries/Adafruit_NeoPixel/.github/workflows/githubci.yml similarity index 100% rename from src/library/Adafruit_NeoPixel/.github/workflows/githubci.yml rename to src/Libraries/Adafruit_NeoPixel/.github/workflows/githubci.yml diff --git a/src/library/Adafruit_NeoPixel/.gitignore b/src/Libraries/Adafruit_NeoPixel/.gitignore similarity index 100% rename from src/library/Adafruit_NeoPixel/.gitignore rename to src/Libraries/Adafruit_NeoPixel/.gitignore diff --git a/src/library/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp b/src/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp similarity index 100% rename from src/library/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp rename to src/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp diff --git a/src/library/Adafruit_NeoPixel/Adafruit_NeoPixel.h b/src/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h similarity index 100% rename from src/library/Adafruit_NeoPixel/Adafruit_NeoPixel.h rename to src/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h diff --git a/src/library/Adafruit_NeoPixel/CONTRIBUTING.md b/src/Libraries/Adafruit_NeoPixel/CONTRIBUTING.md similarity index 100% rename from src/library/Adafruit_NeoPixel/CONTRIBUTING.md rename to src/Libraries/Adafruit_NeoPixel/CONTRIBUTING.md diff --git a/src/library/Adafruit_NeoPixel/COPYING b/src/Libraries/Adafruit_NeoPixel/COPYING similarity index 100% rename from src/library/Adafruit_NeoPixel/COPYING rename to src/Libraries/Adafruit_NeoPixel/COPYING diff --git a/src/library/Adafruit_NeoPixel/README.md b/src/Libraries/Adafruit_NeoPixel/README.md similarity index 100% rename from src/library/Adafruit_NeoPixel/README.md rename to src/Libraries/Adafruit_NeoPixel/README.md diff --git a/src/library/Adafruit_NeoPixel/esp.c b/src/Libraries/Adafruit_NeoPixel/esp.c similarity index 100% rename from src/library/Adafruit_NeoPixel/esp.c rename to src/Libraries/Adafruit_NeoPixel/esp.c diff --git a/src/library/Adafruit_NeoPixel/esp8266.c b/src/Libraries/Adafruit_NeoPixel/esp8266.c similarity index 100% rename from src/library/Adafruit_NeoPixel/esp8266.c rename to src/Libraries/Adafruit_NeoPixel/esp8266.c diff --git a/src/library/Adafruit_NeoPixel/kendyte_k210.c b/src/Libraries/Adafruit_NeoPixel/kendyte_k210.c similarity index 100% rename from src/library/Adafruit_NeoPixel/kendyte_k210.c rename to src/Libraries/Adafruit_NeoPixel/kendyte_k210.c diff --git a/src/library/Adafruit_NeoPixel/keywords.txt b/src/Libraries/Adafruit_NeoPixel/keywords.txt similarity index 100% rename from src/library/Adafruit_NeoPixel/keywords.txt rename to src/Libraries/Adafruit_NeoPixel/keywords.txt diff --git a/src/library/Adafruit_NeoPixel/library.properties b/src/Libraries/Adafruit_NeoPixel/library.properties similarity index 100% rename from src/library/Adafruit_NeoPixel/library.properties rename to src/Libraries/Adafruit_NeoPixel/library.properties diff --git a/src/library/Adafruit_NeoPixel/rp2040_pio.h b/src/Libraries/Adafruit_NeoPixel/rp2040_pio.h similarity index 100% rename from src/library/Adafruit_NeoPixel/rp2040_pio.h rename to src/Libraries/Adafruit_NeoPixel/rp2040_pio.h diff --git a/src/library/Adafruit_SH110x/.github/ISSUE_TEMPLATE.md b/src/Libraries/Adafruit_SH110x/.github/ISSUE_TEMPLATE.md similarity index 100% rename from src/library/Adafruit_SH110x/.github/ISSUE_TEMPLATE.md rename to src/Libraries/Adafruit_SH110x/.github/ISSUE_TEMPLATE.md diff --git a/src/library/Adafruit_SH110x/.github/PULL_REQUEST_TEMPLATE.md b/src/Libraries/Adafruit_SH110x/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from src/library/Adafruit_SH110x/.github/PULL_REQUEST_TEMPLATE.md rename to src/Libraries/Adafruit_SH110x/.github/PULL_REQUEST_TEMPLATE.md diff --git a/src/library/Adafruit_SH110x/.github/workflows/githubci.yml b/src/Libraries/Adafruit_SH110x/.github/workflows/githubci.yml similarity index 100% rename from src/library/Adafruit_SH110x/.github/workflows/githubci.yml rename to src/Libraries/Adafruit_SH110x/.github/workflows/githubci.yml diff --git a/src/library/Adafruit_SH110x/.gitignore b/src/Libraries/Adafruit_SH110x/.gitignore similarity index 100% rename from src/library/Adafruit_SH110x/.gitignore rename to src/Libraries/Adafruit_SH110x/.gitignore diff --git a/src/library/Adafruit_SH110x/Adafruit_SH1106G.cpp b/src/Libraries/Adafruit_SH110x/Adafruit_SH1106G.cpp similarity index 100% rename from src/library/Adafruit_SH110x/Adafruit_SH1106G.cpp rename to src/Libraries/Adafruit_SH110x/Adafruit_SH1106G.cpp diff --git a/src/library/Adafruit_SH110x/Adafruit_SH1107.cpp b/src/Libraries/Adafruit_SH110x/Adafruit_SH1107.cpp similarity index 100% rename from src/library/Adafruit_SH110x/Adafruit_SH1107.cpp rename to src/Libraries/Adafruit_SH110x/Adafruit_SH1107.cpp diff --git a/src/library/Adafruit_SH110x/Adafruit_SH110X.cpp b/src/Libraries/Adafruit_SH110x/Adafruit_SH110X.cpp similarity index 100% rename from src/library/Adafruit_SH110x/Adafruit_SH110X.cpp rename to src/Libraries/Adafruit_SH110x/Adafruit_SH110X.cpp diff --git a/src/library/Adafruit_SH110x/Adafruit_SH110X.h b/src/Libraries/Adafruit_SH110x/Adafruit_SH110X.h similarity index 100% rename from src/library/Adafruit_SH110x/Adafruit_SH110X.h rename to src/Libraries/Adafruit_SH110x/Adafruit_SH110X.h diff --git a/src/library/Adafruit_SH110x/README.md b/src/Libraries/Adafruit_SH110x/README.md similarity index 100% rename from src/library/Adafruit_SH110x/README.md rename to src/Libraries/Adafruit_SH110x/README.md diff --git a/src/library/Adafruit_SH110x/examples/OLED_QTPY_SH1106/SH1106_128x64_SPi_QTPY/SH1106_128x64_SPi_QTPY.ino b/src/Libraries/Adafruit_SH110x/examples/OLED_QTPY_SH1106/SH1106_128x64_SPi_QTPY/SH1106_128x64_SPi_QTPY.ino similarity index 100% rename from src/library/Adafruit_SH110x/examples/OLED_QTPY_SH1106/SH1106_128x64_SPi_QTPY/SH1106_128x64_SPi_QTPY.ino rename to src/Libraries/Adafruit_SH110x/examples/OLED_QTPY_SH1106/SH1106_128x64_SPi_QTPY/SH1106_128x64_SPi_QTPY.ino diff --git a/src/library/Adafruit_SH110x/examples/OLED_QTPY_SH1106/SH1106_128x64_i2c_QTPY/SH1106_128x64_i2c_QTPY.ino b/src/Libraries/Adafruit_SH110x/examples/OLED_QTPY_SH1106/SH1106_128x64_i2c_QTPY/SH1106_128x64_i2c_QTPY.ino similarity index 100% rename from src/library/Adafruit_SH110x/examples/OLED_QTPY_SH1106/SH1106_128x64_i2c_QTPY/SH1106_128x64_i2c_QTPY.ino rename to src/Libraries/Adafruit_SH110x/examples/OLED_QTPY_SH1106/SH1106_128x64_i2c_QTPY/SH1106_128x64_i2c_QTPY.ino diff --git a/src/library/Adafruit_SH110x/examples/OLED_featherwing/OLED_featherwing.ino b/src/Libraries/Adafruit_SH110x/examples/OLED_featherwing/OLED_featherwing.ino similarity index 100% rename from src/library/Adafruit_SH110x/examples/OLED_featherwing/OLED_featherwing.ino rename to src/Libraries/Adafruit_SH110x/examples/OLED_featherwing/OLED_featherwing.ino diff --git a/src/library/Adafruit_SH110x/examples/SH1107_128x128/SH1107_128x128.ino b/src/Libraries/Adafruit_SH110x/examples/SH1107_128x128/SH1107_128x128.ino similarity index 100% rename from src/library/Adafruit_SH110x/examples/SH1107_128x128/SH1107_128x128.ino rename to src/Libraries/Adafruit_SH110x/examples/SH1107_128x128/SH1107_128x128.ino diff --git a/src/library/Adafruit_SH110x/library.properties b/src/Libraries/Adafruit_SH110x/library.properties similarity index 100% rename from src/library/Adafruit_SH110x/library.properties rename to src/Libraries/Adafruit_SH110x/library.properties diff --git a/src/library/Adafruit_SH110x/license.txt b/src/Libraries/Adafruit_SH110x/license.txt similarity index 100% rename from src/library/Adafruit_SH110x/license.txt rename to src/Libraries/Adafruit_SH110x/license.txt diff --git a/src/library/Adafruit_SH110x/splash.h b/src/Libraries/Adafruit_SH110x/splash.h similarity index 100% rename from src/library/Adafruit_SH110x/splash.h rename to src/Libraries/Adafruit_SH110x/splash.h diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/.github/ISSUE_TEMPLATE.md b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/.github/ISSUE_TEMPLATE.md similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/.github/ISSUE_TEMPLATE.md rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/.github/ISSUE_TEMPLATE.md diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/.github/PULL_REQUEST_TEMPLATE.md b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/.github/PULL_REQUEST_TEMPLATE.md rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/.github/PULL_REQUEST_TEMPLATE.md diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.cpp b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.cpp similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.cpp rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.cpp diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.h b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.h similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.h rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/Adafruit_SSD1306.h diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/README.md b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/README.md similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/README.md rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/README.md diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/README.txt b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/README.txt similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/README.txt rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/README.txt diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x32_spi/ssd1306_128x32_spi.ino b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x32_spi/ssd1306_128x32_spi.ino similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x32_spi/ssd1306_128x32_spi.ino rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x32_spi/ssd1306_128x32_spi.ino diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x64_spi/ssd1306_128x64_spi.ino b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x64_spi/ssd1306_128x64_spi.ino similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x64_spi/ssd1306_128x64_spi.ino rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_128x64_spi/ssd1306_128x64_spi.ino diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_64x48_i2c/ssd1306_64x48_i2c.ino b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_64x48_i2c/ssd1306_64x48_i2c.ino similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_64x48_i2c/ssd1306_64x48_i2c.ino rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/examples/ssd1306_64x48_i2c/ssd1306_64x48_i2c.ino diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/library.properties b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/library.properties similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/library.properties rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/library.properties diff --git a/src/library/Adafruit_SSD1306_Wemos_OLED/license.txt b/src/Libraries/Adafruit_SSD1306_Wemos_OLED/license.txt similarity index 100% rename from src/library/Adafruit_SSD1306_Wemos_OLED/license.txt rename to src/Libraries/Adafruit_SSD1306_Wemos_OLED/license.txt diff --git a/src/library/SensirionCore/.clang-format b/src/Libraries/SensirionCore/.clang-format similarity index 100% rename from src/library/SensirionCore/.clang-format rename to src/Libraries/SensirionCore/.clang-format diff --git a/src/library/SensirionCore/.editorconfig b/src/Libraries/SensirionCore/.editorconfig similarity index 100% rename from src/library/SensirionCore/.editorconfig rename to src/Libraries/SensirionCore/.editorconfig diff --git a/src/library/SensirionCore/.gitignore b/src/Libraries/SensirionCore/.gitignore similarity index 100% rename from src/library/SensirionCore/.gitignore rename to src/Libraries/SensirionCore/.gitignore diff --git a/src/library/SensirionCore/.gitlab-ci.yml b/src/Libraries/SensirionCore/.gitlab-ci.yml similarity index 100% rename from src/library/SensirionCore/.gitlab-ci.yml rename to src/Libraries/SensirionCore/.gitlab-ci.yml diff --git a/src/library/SensirionCore/CHANGELOG.rst b/src/Libraries/SensirionCore/CHANGELOG.rst similarity index 100% rename from src/library/SensirionCore/CHANGELOG.rst rename to src/Libraries/SensirionCore/CHANGELOG.rst diff --git a/src/library/SensirionCore/LICENSE b/src/Libraries/SensirionCore/LICENSE similarity index 100% rename from src/library/SensirionCore/LICENSE rename to src/Libraries/SensirionCore/LICENSE diff --git a/src/library/SensirionCore/README.md b/src/Libraries/SensirionCore/README.md similarity index 100% rename from src/library/SensirionCore/README.md rename to src/Libraries/SensirionCore/README.md diff --git a/src/library/SensirionCore/examples/AllCommandsI2c/AllCommandsI2c.ino b/src/Libraries/SensirionCore/examples/AllCommandsI2c/AllCommandsI2c.ino similarity index 100% rename from src/library/SensirionCore/examples/AllCommandsI2c/AllCommandsI2c.ino rename to src/Libraries/SensirionCore/examples/AllCommandsI2c/AllCommandsI2c.ino diff --git a/src/library/SensirionCore/examples/AllCommandsShdlc/AllCommandsShdlc.ino b/src/Libraries/SensirionCore/examples/AllCommandsShdlc/AllCommandsShdlc.ino similarity index 100% rename from src/library/SensirionCore/examples/AllCommandsShdlc/AllCommandsShdlc.ino rename to src/Libraries/SensirionCore/examples/AllCommandsShdlc/AllCommandsShdlc.ino diff --git a/src/library/SensirionCore/keywords.txt b/src/Libraries/SensirionCore/keywords.txt similarity index 100% rename from src/library/SensirionCore/keywords.txt rename to src/Libraries/SensirionCore/keywords.txt diff --git a/src/library/SensirionCore/library.properties b/src/Libraries/SensirionCore/library.properties similarity index 100% rename from src/library/SensirionCore/library.properties rename to src/Libraries/SensirionCore/library.properties diff --git a/src/library/SensirionCore/src/SensirionCore.h b/src/Libraries/SensirionCore/src/SensirionCore.h similarity index 100% rename from src/library/SensirionCore/src/SensirionCore.h rename to src/Libraries/SensirionCore/src/SensirionCore.h diff --git a/src/library/SensirionCore/src/SensirionCoreArduinoLibrary.h b/src/Libraries/SensirionCore/src/SensirionCoreArduinoLibrary.h similarity index 100% rename from src/library/SensirionCore/src/SensirionCoreArduinoLibrary.h rename to src/Libraries/SensirionCore/src/SensirionCoreArduinoLibrary.h diff --git a/src/library/SensirionCore/src/SensirionCrc.cpp b/src/Libraries/SensirionCore/src/SensirionCrc.cpp similarity index 100% rename from src/library/SensirionCore/src/SensirionCrc.cpp rename to src/Libraries/SensirionCore/src/SensirionCrc.cpp diff --git a/src/library/SensirionCore/src/SensirionCrc.h b/src/Libraries/SensirionCore/src/SensirionCrc.h similarity index 100% rename from src/library/SensirionCore/src/SensirionCrc.h rename to src/Libraries/SensirionCore/src/SensirionCrc.h diff --git a/src/library/SensirionCore/src/SensirionErrors.cpp b/src/Libraries/SensirionCore/src/SensirionErrors.cpp similarity index 100% rename from src/library/SensirionCore/src/SensirionErrors.cpp rename to src/Libraries/SensirionCore/src/SensirionErrors.cpp diff --git a/src/library/SensirionCore/src/SensirionErrors.h b/src/Libraries/SensirionCore/src/SensirionErrors.h similarity index 100% rename from src/library/SensirionCore/src/SensirionErrors.h rename to src/Libraries/SensirionCore/src/SensirionErrors.h diff --git a/src/library/SensirionCore/src/SensirionI2CCommunication.cpp b/src/Libraries/SensirionCore/src/SensirionI2CCommunication.cpp similarity index 100% rename from src/library/SensirionCore/src/SensirionI2CCommunication.cpp rename to src/Libraries/SensirionCore/src/SensirionI2CCommunication.cpp diff --git a/src/library/SensirionCore/src/SensirionI2CCommunication.h b/src/Libraries/SensirionCore/src/SensirionI2CCommunication.h similarity index 100% rename from src/library/SensirionCore/src/SensirionI2CCommunication.h rename to src/Libraries/SensirionCore/src/SensirionI2CCommunication.h diff --git a/src/library/SensirionCore/src/SensirionI2CRxFrame.h b/src/Libraries/SensirionCore/src/SensirionI2CRxFrame.h similarity index 100% rename from src/library/SensirionCore/src/SensirionI2CRxFrame.h rename to src/Libraries/SensirionCore/src/SensirionI2CRxFrame.h diff --git a/src/library/SensirionCore/src/SensirionI2CTxFrame.cpp b/src/Libraries/SensirionCore/src/SensirionI2CTxFrame.cpp similarity index 100% rename from src/library/SensirionCore/src/SensirionI2CTxFrame.cpp rename to src/Libraries/SensirionCore/src/SensirionI2CTxFrame.cpp diff --git a/src/library/SensirionCore/src/SensirionI2CTxFrame.h b/src/Libraries/SensirionCore/src/SensirionI2CTxFrame.h similarity index 100% rename from src/library/SensirionCore/src/SensirionI2CTxFrame.h rename to src/Libraries/SensirionCore/src/SensirionI2CTxFrame.h diff --git a/src/library/SensirionCore/src/SensirionRxFrame.cpp b/src/Libraries/SensirionCore/src/SensirionRxFrame.cpp similarity index 100% rename from src/library/SensirionCore/src/SensirionRxFrame.cpp rename to src/Libraries/SensirionCore/src/SensirionRxFrame.cpp diff --git a/src/library/SensirionCore/src/SensirionRxFrame.h b/src/Libraries/SensirionCore/src/SensirionRxFrame.h similarity index 100% rename from src/library/SensirionCore/src/SensirionRxFrame.h rename to src/Libraries/SensirionCore/src/SensirionRxFrame.h diff --git a/src/library/SensirionCore/src/SensirionShdlcCommunication.cpp b/src/Libraries/SensirionCore/src/SensirionShdlcCommunication.cpp similarity index 100% rename from src/library/SensirionCore/src/SensirionShdlcCommunication.cpp rename to src/Libraries/SensirionCore/src/SensirionShdlcCommunication.cpp diff --git a/src/library/SensirionCore/src/SensirionShdlcCommunication.h b/src/Libraries/SensirionCore/src/SensirionShdlcCommunication.h similarity index 100% rename from src/library/SensirionCore/src/SensirionShdlcCommunication.h rename to src/Libraries/SensirionCore/src/SensirionShdlcCommunication.h diff --git a/src/library/SensirionCore/src/SensirionShdlcRxFrame.h b/src/Libraries/SensirionCore/src/SensirionShdlcRxFrame.h similarity index 100% rename from src/library/SensirionCore/src/SensirionShdlcRxFrame.h rename to src/Libraries/SensirionCore/src/SensirionShdlcRxFrame.h diff --git a/src/library/SensirionCore/src/SensirionShdlcTxFrame.cpp b/src/Libraries/SensirionCore/src/SensirionShdlcTxFrame.cpp similarity index 100% rename from src/library/SensirionCore/src/SensirionShdlcTxFrame.cpp rename to src/Libraries/SensirionCore/src/SensirionShdlcTxFrame.cpp diff --git a/src/library/SensirionCore/src/SensirionShdlcTxFrame.h b/src/Libraries/SensirionCore/src/SensirionShdlcTxFrame.h similarity index 100% rename from src/library/SensirionCore/src/SensirionShdlcTxFrame.h rename to src/Libraries/SensirionCore/src/SensirionShdlcTxFrame.h diff --git a/src/library/SensirionCore/tests/compile_test.py b/src/Libraries/SensirionCore/tests/compile_test.py similarity index 100% rename from src/library/SensirionCore/tests/compile_test.py rename to src/Libraries/SensirionCore/tests/compile_test.py diff --git a/src/library/SensirionCore/tests/run_cppcheck.sh b/src/Libraries/SensirionCore/tests/run_cppcheck.sh similarity index 100% rename from src/library/SensirionCore/tests/run_cppcheck.sh rename to src/Libraries/SensirionCore/tests/run_cppcheck.sh diff --git a/src/library/SensirionCore/tests/syntax_check.sh b/src/Libraries/SensirionCore/tests/syntax_check.sh similarity index 100% rename from src/library/SensirionCore/tests/syntax_check.sh rename to src/Libraries/SensirionCore/tests/syntax_check.sh diff --git a/src/library/SensirionSGP41/.clang-format b/src/Libraries/SensirionSGP41/.clang-format similarity index 100% rename from src/library/SensirionSGP41/.clang-format rename to src/Libraries/SensirionSGP41/.clang-format diff --git a/src/library/SensirionSGP41/.gitlab-ci.yml b/src/Libraries/SensirionSGP41/.gitlab-ci.yml similarity index 100% rename from src/library/SensirionSGP41/.gitlab-ci.yml rename to src/Libraries/SensirionSGP41/.gitlab-ci.yml diff --git a/src/library/SensirionSGP41/CHANGELOG.md b/src/Libraries/SensirionSGP41/CHANGELOG.md similarity index 100% rename from src/library/SensirionSGP41/CHANGELOG.md rename to src/Libraries/SensirionSGP41/CHANGELOG.md diff --git a/src/library/SensirionSGP41/LICENSE b/src/Libraries/SensirionSGP41/LICENSE similarity index 100% rename from src/library/SensirionSGP41/LICENSE rename to src/Libraries/SensirionSGP41/LICENSE diff --git a/src/library/SensirionSGP41/README.md b/src/Libraries/SensirionSGP41/README.md similarity index 100% rename from src/library/SensirionSGP41/README.md rename to src/Libraries/SensirionSGP41/README.md diff --git a/src/library/SensirionSGP41/examples/exampleUsage/exampleUsage.ino b/src/Libraries/SensirionSGP41/examples/exampleUsage/exampleUsage.ino similarity index 100% rename from src/library/SensirionSGP41/examples/exampleUsage/exampleUsage.ino rename to src/Libraries/SensirionSGP41/examples/exampleUsage/exampleUsage.ino diff --git a/src/library/SensirionSGP41/images/SGP41.png b/src/Libraries/SensirionSGP41/images/SGP41.png similarity index 100% rename from src/library/SensirionSGP41/images/SGP41.png rename to src/Libraries/SensirionSGP41/images/SGP41.png diff --git a/src/library/SensirionSGP41/keywords.txt b/src/Libraries/SensirionSGP41/keywords.txt similarity index 100% rename from src/library/SensirionSGP41/keywords.txt rename to src/Libraries/SensirionSGP41/keywords.txt diff --git a/src/library/SensirionSGP41/library.properties b/src/Libraries/SensirionSGP41/library.properties similarity index 100% rename from src/library/SensirionSGP41/library.properties rename to src/Libraries/SensirionSGP41/library.properties diff --git a/src/library/SensirionSGP41/src/SensirionI2CSgp41.cpp b/src/Libraries/SensirionSGP41/src/SensirionI2CSgp41.cpp similarity index 100% rename from src/library/SensirionSGP41/src/SensirionI2CSgp41.cpp rename to src/Libraries/SensirionSGP41/src/SensirionI2CSgp41.cpp diff --git a/src/library/SensirionSGP41/src/SensirionI2CSgp41.h b/src/Libraries/SensirionSGP41/src/SensirionI2CSgp41.h similarity index 100% rename from src/library/SensirionSGP41/src/SensirionI2CSgp41.h rename to src/Libraries/SensirionSGP41/src/SensirionI2CSgp41.h diff --git a/src/library/Sensirion_Gas_Index_Algorithm/CHANGELOG.md b/src/Libraries/Sensirion_Gas_Index_Algorithm/CHANGELOG.md similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/CHANGELOG.md rename to src/Libraries/Sensirion_Gas_Index_Algorithm/CHANGELOG.md diff --git a/src/library/Sensirion_Gas_Index_Algorithm/LICENSE b/src/Libraries/Sensirion_Gas_Index_Algorithm/LICENSE similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/LICENSE rename to src/Libraries/Sensirion_Gas_Index_Algorithm/LICENSE diff --git a/src/library/Sensirion_Gas_Index_Algorithm/README.md b/src/Libraries/Sensirion_Gas_Index_Algorithm/README.md similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/README.md rename to src/Libraries/Sensirion_Gas_Index_Algorithm/README.md diff --git a/src/library/Sensirion_Gas_Index_Algorithm/examples/exampleLowPowerUsage/exampleLowPowerUsage.ino b/src/Libraries/Sensirion_Gas_Index_Algorithm/examples/exampleLowPowerUsage/exampleLowPowerUsage.ino similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/examples/exampleLowPowerUsage/exampleLowPowerUsage.ino rename to src/Libraries/Sensirion_Gas_Index_Algorithm/examples/exampleLowPowerUsage/exampleLowPowerUsage.ino diff --git a/src/library/Sensirion_Gas_Index_Algorithm/examples/exampleUsage/exampleUsage.ino b/src/Libraries/Sensirion_Gas_Index_Algorithm/examples/exampleUsage/exampleUsage.ino similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/examples/exampleUsage/exampleUsage.ino rename to src/Libraries/Sensirion_Gas_Index_Algorithm/examples/exampleUsage/exampleUsage.ino diff --git a/src/library/Sensirion_Gas_Index_Algorithm/keywords.txt b/src/Libraries/Sensirion_Gas_Index_Algorithm/keywords.txt similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/keywords.txt rename to src/Libraries/Sensirion_Gas_Index_Algorithm/keywords.txt diff --git a/src/library/Sensirion_Gas_Index_Algorithm/library.json b/src/Libraries/Sensirion_Gas_Index_Algorithm/library.json similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/library.json rename to src/Libraries/Sensirion_Gas_Index_Algorithm/library.json diff --git a/src/library/Sensirion_Gas_Index_Algorithm/library.properties b/src/Libraries/Sensirion_Gas_Index_Algorithm/library.properties similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/library.properties rename to src/Libraries/Sensirion_Gas_Index_Algorithm/library.properties diff --git a/src/library/Sensirion_Gas_Index_Algorithm/src/NOxGasIndexAlgorithm.h b/src/Libraries/Sensirion_Gas_Index_Algorithm/src/NOxGasIndexAlgorithm.h similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/src/NOxGasIndexAlgorithm.h rename to src/Libraries/Sensirion_Gas_Index_Algorithm/src/NOxGasIndexAlgorithm.h diff --git a/src/library/Sensirion_Gas_Index_Algorithm/src/SensirionGasIndexAlgorithm.cpp b/src/Libraries/Sensirion_Gas_Index_Algorithm/src/SensirionGasIndexAlgorithm.cpp similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/src/SensirionGasIndexAlgorithm.cpp rename to src/Libraries/Sensirion_Gas_Index_Algorithm/src/SensirionGasIndexAlgorithm.cpp diff --git a/src/library/Sensirion_Gas_Index_Algorithm/src/SensirionGasIndexAlgorithm.h b/src/Libraries/Sensirion_Gas_Index_Algorithm/src/SensirionGasIndexAlgorithm.h similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/src/SensirionGasIndexAlgorithm.h rename to src/Libraries/Sensirion_Gas_Index_Algorithm/src/SensirionGasIndexAlgorithm.h diff --git a/src/library/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.cpp b/src/Libraries/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.cpp similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.cpp rename to src/Libraries/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.cpp diff --git a/src/library/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.h b/src/Libraries/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.h similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.h rename to src/Libraries/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.h diff --git a/src/library/Sensirion_Gas_Index_Algorithm/src/algorithm/sensirion_gas_index_algorithm.c b/src/Libraries/Sensirion_Gas_Index_Algorithm/src/algorithm/sensirion_gas_index_algorithm.c similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/src/algorithm/sensirion_gas_index_algorithm.c rename to src/Libraries/Sensirion_Gas_Index_Algorithm/src/algorithm/sensirion_gas_index_algorithm.c diff --git a/src/library/Sensirion_Gas_Index_Algorithm/src/algorithm/sensirion_gas_index_algorithm.h b/src/Libraries/Sensirion_Gas_Index_Algorithm/src/algorithm/sensirion_gas_index_algorithm.h similarity index 100% rename from src/library/Sensirion_Gas_Index_Algorithm/src/algorithm/sensirion_gas_index_algorithm.h rename to src/Libraries/Sensirion_Gas_Index_Algorithm/src/algorithm/sensirion_gas_index_algorithm.h diff --git a/src/library/arduino-sht/LICENSE b/src/Libraries/arduino-sht/LICENSE similarity index 100% rename from src/library/arduino-sht/LICENSE rename to src/Libraries/arduino-sht/LICENSE diff --git a/src/library/arduino-sht/README.md b/src/Libraries/arduino-sht/README.md similarity index 100% rename from src/library/arduino-sht/README.md rename to src/Libraries/arduino-sht/README.md diff --git a/src/library/arduino-sht/SHTSensor.cpp b/src/Libraries/arduino-sht/SHTSensor.cpp similarity index 100% rename from src/library/arduino-sht/SHTSensor.cpp rename to src/Libraries/arduino-sht/SHTSensor.cpp diff --git a/src/library/arduino-sht/SHTSensor.h b/src/Libraries/arduino-sht/SHTSensor.h similarity index 100% rename from src/library/arduino-sht/SHTSensor.h rename to src/Libraries/arduino-sht/SHTSensor.h diff --git a/src/library/arduino-sht/arduino-sht.h b/src/Libraries/arduino-sht/arduino-sht.h similarity index 100% rename from src/library/arduino-sht/arduino-sht.h rename to src/Libraries/arduino-sht/arduino-sht.h diff --git a/src/library/arduino-sht/examples/multiple-sht-sensors/multiple-sht-sensors.ino b/src/Libraries/arduino-sht/examples/multiple-sht-sensors/multiple-sht-sensors.ino similarity index 100% rename from src/library/arduino-sht/examples/multiple-sht-sensors/multiple-sht-sensors.ino rename to src/Libraries/arduino-sht/examples/multiple-sht-sensors/multiple-sht-sensors.ino diff --git a/src/library/arduino-sht/examples/sht-autodetect/sht-autodetect.ino b/src/Libraries/arduino-sht/examples/sht-autodetect/sht-autodetect.ino similarity index 100% rename from src/library/arduino-sht/examples/sht-autodetect/sht-autodetect.ino rename to src/Libraries/arduino-sht/examples/sht-autodetect/sht-autodetect.ino diff --git a/src/library/arduino-sht/examples/sht3xanalog/sht3xanalog.ino b/src/Libraries/arduino-sht/examples/sht3xanalog/sht3xanalog.ino similarity index 100% rename from src/library/arduino-sht/examples/sht3xanalog/sht3xanalog.ino rename to src/Libraries/arduino-sht/examples/sht3xanalog/sht3xanalog.ino diff --git a/src/library/arduino-sht/keywords.txt b/src/Libraries/arduino-sht/keywords.txt similarity index 100% rename from src/library/arduino-sht/keywords.txt rename to src/Libraries/arduino-sht/keywords.txt diff --git a/src/library/arduino-sht/library.properties b/src/Libraries/arduino-sht/library.properties similarity index 100% rename from src/library/arduino-sht/library.properties rename to src/Libraries/arduino-sht/library.properties diff --git a/src/main/BoardDef.cpp b/src/Main/BoardDef.cpp similarity index 100% rename from src/main/BoardDef.cpp rename to src/Main/BoardDef.cpp diff --git a/src/main/BoardDef.h b/src/Main/BoardDef.h similarity index 100% rename from src/main/BoardDef.h rename to src/Main/BoardDef.h diff --git a/src/main/HardwareWatchdog.cpp b/src/Main/HardwareWatchdog.cpp similarity index 100% rename from src/main/HardwareWatchdog.cpp rename to src/Main/HardwareWatchdog.cpp diff --git a/src/main/HardwareWatchdog.h b/src/Main/HardwareWatchdog.h similarity index 100% rename from src/main/HardwareWatchdog.h rename to src/Main/HardwareWatchdog.h diff --git a/src/main/LedBar.cpp b/src/Main/LedBar.cpp similarity index 97% rename from src/main/LedBar.cpp rename to src/Main/LedBar.cpp index 1b1f5ef..c6cca1e 100644 --- a/src/main/LedBar.cpp +++ b/src/Main/LedBar.cpp @@ -1,6 +1,6 @@ #include "LedBar.h" -#include "../library/Adafruit_NeoPixel/Adafruit_NeoPixel.h" +#include "../Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h" #define pixel() ((Adafruit_NeoPixel *)this->pixels) diff --git a/src/main/LedBar.h b/src/Main/LedBar.h similarity index 100% rename from src/main/LedBar.h rename to src/Main/LedBar.h diff --git a/src/main/PushButton.cpp b/src/Main/PushButton.cpp similarity index 100% rename from src/main/PushButton.cpp rename to src/Main/PushButton.cpp diff --git a/src/main/PushButton.h b/src/Main/PushButton.h similarity index 100% rename from src/main/PushButton.h rename to src/Main/PushButton.h diff --git a/src/main/StatusLed.cpp b/src/Main/StatusLed.cpp similarity index 100% rename from src/main/StatusLed.cpp rename to src/Main/StatusLed.cpp diff --git a/src/main/StatusLed.h b/src/Main/StatusLed.h similarity index 100% rename from src/main/StatusLed.h rename to src/Main/StatusLed.h diff --git a/src/pms/PMS.cpp b/src/PMS/PMS.cpp similarity index 100% rename from src/pms/PMS.cpp rename to src/PMS/PMS.cpp diff --git a/src/pms/PMS.h b/src/PMS/PMS.h similarity index 100% rename from src/pms/PMS.h rename to src/PMS/PMS.h diff --git a/src/pms/pms5003.cpp b/src/PMS/PMS5003.cpp similarity index 99% rename from src/pms/pms5003.cpp rename to src/PMS/PMS5003.cpp index 9f4fe81..128d1b1 100644 --- a/src/pms/pms5003.cpp +++ b/src/PMS/PMS5003.cpp @@ -1,4 +1,4 @@ -#include "pms5003.h" +#include "PMS5003.h" #include "Arduino.h" #if defined(ESP8266) diff --git a/src/pms/pms5003.h b/src/PMS/PMS5003.h similarity index 96% rename from src/pms/pms5003.h rename to src/PMS/PMS5003.h index 3ba47aa..69e6de4 100644 --- a/src/pms/pms5003.h +++ b/src/PMS/PMS5003.h @@ -1,7 +1,7 @@ #ifndef _AIR_GRADIENT_PMS5003_H_ #define _AIR_GRADIENT_PMS5003_H_ -#include "../main/BoardDef.h" +#include "../Main/BoardDef.h" #include "Stream.h" #include "PMS.h" diff --git a/src/pms/pms5003t.cpp b/src/PMS/PMS5003T.cpp similarity index 99% rename from src/pms/pms5003t.cpp rename to src/PMS/PMS5003T.cpp index a229229..ee0c709 100644 --- a/src/pms/pms5003t.cpp +++ b/src/PMS/PMS5003T.cpp @@ -1,4 +1,4 @@ -#include "pms5003t.h" +#include "PMS5003T.h" #include "Arduino.h" #if defined(ESP8266) diff --git a/src/pms/pms5003t.h b/src/PMS/PMS5003T.h similarity index 97% rename from src/pms/pms5003t.h rename to src/PMS/PMS5003T.h index f5a19f5..e1394ef 100644 --- a/src/pms/pms5003t.h +++ b/src/PMS/PMS5003T.h @@ -2,7 +2,7 @@ #define _PMS5003T_H_ #include -#include "../main/BoardDef.h" +#include "../Main/BoardDef.h" #include "PMS.h" #include "Stream.h" diff --git a/src/s8/s8.cpp b/src/S8/S8.cpp similarity index 99% rename from src/s8/s8.cpp rename to src/S8/S8.cpp index 628cc5b..dc22155 100644 --- a/src/s8/s8.cpp +++ b/src/S8/S8.cpp @@ -1,4 +1,4 @@ -#include "s8.h" +#include "S8.h" #include "mb_crc.h" #if defined(ESP8266) #include @@ -801,7 +801,7 @@ void S8::sendCommand(uint8_t func, uint16_t reg, uint16_t value) { * @return true Success * @return false Failure */ -bool S8::setAutoCalib(int hours) { +bool S8::setAbcPeriod(int hours) { if (isBegin() == false) { return false; } @@ -813,3 +813,10 @@ bool S8::setAutoCalib(int hours) { return setCalibPeriodABC(hours); } + +/** + * @brief Get current 'ABC' calib period + * + * @return int Hour + */ +int S8::getAbcPeriod(void) { return getCalibPeriodABC(); } diff --git a/src/s8/s8.h b/src/S8/S8.h similarity index 98% rename from src/s8/s8.h rename to src/S8/S8.h index b967a9e..5d18952 100644 --- a/src/s8/s8.h +++ b/src/S8/S8.h @@ -78,7 +78,8 @@ public: int16_t getCo2(void); bool setBaselineCalibration(void); bool isBaseLineCalibrationDone(void); - bool setAutoCalib(int hours); + bool setAbcPeriod(int hours); + int getAbcPeriod(void); private: /** Variables */ diff --git a/src/s8/mb_crc.cpp b/src/S8/mb_crc.cpp similarity index 100% rename from src/s8/mb_crc.cpp rename to src/S8/mb_crc.cpp diff --git a/src/s8/mb_crc.h b/src/S8/mb_crc.h similarity index 100% rename from src/s8/mb_crc.h rename to src/S8/mb_crc.h diff --git a/src/sgp41/sgp41.cpp b/src/Sgp41/Sgp41.cpp similarity index 93% rename from src/sgp41/sgp41.cpp rename to src/Sgp41/Sgp41.cpp index b6ae3aa..ea3d4ae 100644 --- a/src/sgp41/sgp41.cpp +++ b/src/Sgp41/Sgp41.cpp @@ -1,7 +1,7 @@ -#include "sgp41.h" -#include "../library/SensirionSGP41/src/SensirionI2CSgp41.h" -#include "../library/Sensirion_Gas_Index_Algorithm/src/NOxGasIndexAlgorithm.h" -#include "../library/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.h" +#include "Sgp41.h" +#include "../Libraries/SensirionSGP41/src/SensirionI2CSgp41.h" +#include "../Libraries/Sensirion_Gas_Index_Algorithm/src/NOxGasIndexAlgorithm.h" +#include "../Libraries/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.h" #define sgpSensor() ((SensirionI2CSgp41 *)(this->_sensor)) #define vocAlgorithm() ((VOCGasIndexAlgorithm *)(this->_vocAlgorithm)) @@ -120,6 +120,7 @@ void Sgp41::_handle(void) { for (;;) { vTaskDelay(pdMS_TO_TICKS(1000)); if (getRawSignal(srawVoc, srawNox)) { + tvocRaw = srawVoc; nox = noxAlgorithm()->process(srawNox); tvoc = vocAlgorithm()->process(srawVoc); AgLog("Polling SGP41 success: tvoc: %d, nox: %d", tvoc, nox); @@ -241,3 +242,10 @@ bool Sgp41::_noxConditioning(void) { err = sgpSensor()->executeConditioning(defaultRh, defaultT, srawVoc); return (err == 0); } + +/** + * @brief Get TVOC raw value + * + * @return int + */ +int Sgp41::getTvocRaw(void) { return tvocRaw; } diff --git a/src/sgp41/sgp41.h b/src/Sgp41/Sgp41.h similarity index 96% rename from src/sgp41/sgp41.h rename to src/Sgp41/Sgp41.h index f26b343..5c58de1 100644 --- a/src/sgp41/sgp41.h +++ b/src/Sgp41/Sgp41.h @@ -23,6 +23,7 @@ public: void end(void); int getTvocIndex(void); int getNoxIndex(void); + int getTvocRaw(void); private: bool onConditioning = true; @@ -36,6 +37,7 @@ private: uint16_t defaultRh = 0x8000; uint16_t defaultT = 0x6666; int tvoc = 0; + int tvocRaw; int nox = 0; #if defined(ESP8266) uint32_t conditioningPeriod; diff --git a/src/sht/sht.cpp b/src/Sht/Sht.cpp similarity index 97% rename from src/sht/sht.cpp rename to src/Sht/Sht.cpp index 7e5f9e6..aaba59d 100644 --- a/src/sht/sht.cpp +++ b/src/Sht/Sht.cpp @@ -1,6 +1,6 @@ -#include "sht.h" +#include "Sht.h" -#include "../library/arduino-sht/SHTSensor.h" +#include "../Libraries/arduino-sht/SHTSensor.h" /** Cast _sensor to SHTSensor */ #define shtSensor() ((SHTSensor *)(this->_sensor)) diff --git a/src/sht/sht.h b/src/Sht/Sht.h similarity index 100% rename from src/sht/sht.h rename to src/Sht/Sht.h