clarifying method/variable/class names

This commit is contained in:
Phat Nguyen
2024-04-07 16:39:01 +07:00
parent 9a03fb2bd7
commit 4577082731
21 changed files with 1372 additions and 1279 deletions

View File

@ -15,7 +15,6 @@ https://www.airgradient.com/documentation/diy-v4/
Following libraries need to be installed: Following libraries need to be installed:
“WifiManager by tzapu, tablatronix” tested with version 2.0.16-rc.2 “WifiManager by tzapu, tablatronix” tested with version 2.0.16-rc.2
"Arduino_JSON" by Arduino version 0.2.0 "Arduino_JSON" by Arduino version 0.2.0
"U8g2" by oliver version 2.34.22
Please make sure you have esp8266 board manager installed. Tested with Please make sure you have esp8266 board manager installed. Tested with
version 3.1.2. version 3.1.2.
@ -32,15 +31,15 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
*/ */
#include <AirGradient.h>
#include "AgSchedule.h"
#include "AgConfigure.h"
#include "AgApiClient.h" #include "AgApiClient.h"
#include "AgConfigure.h"
#include "AgSchedule.h"
#include "AgWiFiConnector.h"
#include <AirGradient.h>
#include <Arduino_JSON.h> #include <Arduino_JSON.h>
#include <ESP8266HTTPClient.h> #include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <WiFiManager.h>
#define WIFI_CONNECT_COUNTDOWN_MAX 180 /** sec */ #define WIFI_CONNECT_COUNTDOWN_MAX 180 /** sec */
#define WIFI_CONNECT_RETRY_MS 10000 /** ms */ #define WIFI_CONNECT_RETRY_MS 10000 /** ms */
@ -61,20 +60,19 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
/** Create airgradient instance for 'DIY_BASIC' board */ /** Create airgradient instance for 'DIY_BASIC' board */
static AirGradient ag = AirGradient(DIY_BASIC); static AirGradient ag = AirGradient(DIY_BASIC);
static AgConfigure localConfig(Serial); static Configuration configuration(Serial);
static AgApiClient apiClient(Serial, localConfig); static AgApiClient apiClient(Serial, configuration);
static WifiConnector wifiConnector(Serial);
static int co2Ppm = -1; static int co2Ppm = -1;
static int pm25 = -1; static int pm25 = -1;
static float temp = -1001; static float temp = -1001;
static int hum = -1; static int hum = -1;
static long val; static long val;
static String wifiSSID = "";
static bool wifiHasConfig = false; /** */
static void boardInit(void); static void boardInit(void);
static void failedHandler(String msg); static void failedHandler(String msg);
static void co2Calibration(void); static void executeCo2Calibration(void);
static void updateServerConfiguration(void); static void updateServerConfiguration(void);
static void co2Update(void); static void co2Update(void);
static void pmUpdate(void); static void pmUpdate(void);
@ -82,7 +80,6 @@ static void tempHumUpdate(void);
static void sendDataToServer(void); static void sendDataToServer(void);
static void dispHandler(void); static void dispHandler(void);
static String getDevId(void); static String getDevId(void);
static void updateWiFiConnect(void);
static void showNr(void); static void showNr(void);
bool hasSensorS8 = true; bool hasSensorS8 = true;
@ -112,23 +109,24 @@ void setup() {
/** Init AirGradient server */ /** Init AirGradient server */
apiClient.begin(); apiClient.begin();
apiClient.setAirGradient(&ag); apiClient.setAirGradient(&ag);
wifiConnector.setAirGradient(&ag);
/** Show boot display */ /** Show boot display */
displayShowText("DIY basic", "Lib:" + ag.getVersion(), ""); displayShowText("DIY basic", "Lib:" + ag.getVersion(), "");
delay(2000); delay(2000);
/** WiFi connect */ /** WiFi connect */
connectToWifi(); // connectToWifi();
if (wifiConnector.connect()) {
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
wifiHasConfig = true; sendDataToAg();
sendPing();
apiClient.fetchServerConfiguration(); apiClient.fetchServerConfiguration();
if (localConfig.isCo2CalibrationRequested()) { if (configuration.isCo2CalibrationRequested()) {
co2Calibration(); executeCo2Calibration();
}
} }
} }
/** Show serial number display */ /** Show serial number display */
ag.display.clear(); ag.display.clear();
ag.display.setCursor(1, 1); ag.display.setCursor(1, 1);
@ -162,13 +160,13 @@ void loop() {
tempHumSchedule.run(); tempHumSchedule.run();
} }
updateWiFiConnect(); wifiConnector.handle();
/** Read PMS on loop */ /** Read PMS on loop */
ag.pms5003.handle(); ag.pms5003.handle();
} }
static void sendPing() { static void sendDataToAg() {
JSONVar root; JSONVar root;
root["wifi"] = WiFi.RSSI(); root["wifi"] = WiFi.RSSI();
root["boot"] = 0; root["boot"] = 0;
@ -197,39 +195,6 @@ void displayShowText(String ln1, String ln2, String ln3) {
delay(100); delay(100);
} }
// Wifi Manager
void connectToWifi() {
WiFiManager wifiManager;
wifiSSID = "AG-" + String(ESP.getChipId(), HEX);
wifiManager.setConfigPortalBlocking(false);
wifiManager.setConfigPortalTimeout(WIFI_CONNECT_COUNTDOWN_MAX);
wifiManager.autoConnect(wifiSSID.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT);
uint32_t lastTime = millis();
int count = WIFI_CONNECT_COUNTDOWN_MAX;
displayShowText(String(WIFI_CONNECT_COUNTDOWN_MAX) + " sec",
"SSID:", wifiSSID);
while (wifiManager.getConfigPortalActive()) {
wifiManager.process();
uint32_t ms = (uint32_t)(millis() - lastTime);
if (ms >= 1000) {
lastTime = millis();
displayShowText(String(count) + " sec", "SSID:", wifiSSID);
count--;
// Timeout
if (count == 0) {
break;
}
}
}
if (!WiFi.isConnected()) {
displayShowText("Booting", "offline", "mode");
Serial.println("failed to connect and hit timeout");
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
}
}
static void boardInit(void) { static void boardInit(void) {
/** Init SHT sensor */ /** Init SHT sensor */
if (ag.sht.begin(Wire) == false) { if (ag.sht.begin(Wire) == false) {
@ -264,7 +229,7 @@ static void failedHandler(String msg) {
} }
} }
static void co2Calibration(void) { static void executeCo2Calibration(void) {
/** Count down for co2CalibCountdown secs */ /** Count down for co2CalibCountdown secs */
for (int i = 0; i < SENSOR_CO2_CALIB_COUNTDOWN_MAX; i++) { for (int i = 0; i < SENSOR_CO2_CALIB_COUNTDOWN_MAX; i++) {
displayShowText("CO2 calib", "after", displayShowText("CO2 calib", "after",
@ -291,25 +256,25 @@ static void co2Calibration(void) {
static void updateServerConfiguration(void) { static void updateServerConfiguration(void) {
if (apiClient.fetchServerConfiguration()) { if (apiClient.fetchServerConfiguration()) {
if (localConfig.isCo2CalibrationRequested()) { if (configuration.isCo2CalibrationRequested()) {
if (hasSensorS8) { if (hasSensorS8) {
co2Calibration(); executeCo2Calibration();
} else { } else {
Serial.println("CO2 S8 not available, calib ignored"); Serial.println("CO2 S8 not available, calib ignored");
} }
} }
if (localConfig.getCO2CalirationAbcDays() > 0) { if (configuration.getCO2CalibrationAbcDays() > 0) {
if (hasSensorS8) { if (hasSensorS8) {
int newHour = localConfig.getCO2CalirationAbcDays() * 24; int newHour = configuration.getCO2CalibrationAbcDays() * 24;
Serial.printf("abcDays config: %d days(%d hours)\r\n", Serial.printf("abcDays config: %d days(%d hours)\r\n",
localConfig.getCO2CalirationAbcDays(), newHour); configuration.getCO2CalibrationAbcDays(), newHour);
int curHour = ag.s8.getAbcPeriod(); int curHour = ag.s8.getAbcPeriod();
Serial.printf("Current config: %d (hours)\r\n", curHour); Serial.printf("Current config: %d (hours)\r\n", curHour);
if (curHour == newHour) { if (curHour == newHour) {
Serial.println("set 'abcDays' ignored"); Serial.println("set 'abcDays' ignored");
} else { } else {
if (ag.s8.setAbcPeriod(localConfig.getCO2CalirationAbcDays() * 24) == if (ag.s8.setAbcPeriod(configuration.getCO2CalibrationAbcDays() *
false) { 24) == false) {
Serial.println("Set S8 abcDays period calib failed"); Serial.println("Set S8 abcDays period calib failed");
} else { } else {
Serial.println("Set S8 abcDays period calib success"); Serial.println("Set S8 abcDays period calib success");
@ -388,7 +353,7 @@ static void dispHandler() {
String ln2 = ""; String ln2 = "";
String ln3 = ""; String ln3 = "";
if (localConfig.isPmStandardInUSAQI()) { if (configuration.isPmStandardInUSAQI()) {
if (pm25 < 0) { if (pm25 < 0) {
ln1 = "AQI: -"; ln1 = "AQI: -";
} else { } else {
@ -415,7 +380,7 @@ static void dispHandler() {
String _temp = "-"; String _temp = "-";
if (localConfig.isTemperatureUnitInF()) { if (configuration.isTemperatureUnitInF()) {
if (temp > -1001) { if (temp > -1001) {
_temp = String((temp * 9 / 5) + 32).substring(0, 4); _temp = String((temp * 9 / 5) + 32).substring(0, 4);
} }
@ -431,27 +396,6 @@ static void dispHandler() {
static String getDevId(void) { return getNormalizedMac(); } static String getDevId(void) { return getNormalizedMac(); }
/**
* @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");
}
}
static void showNr(void) { static void showNr(void) {
Serial.println(); Serial.println();
Serial.println("Serial nr: " + getDevId()); Serial.println("Serial nr: " + getDevId());

View File

@ -0,0 +1,68 @@
#include "LocalServer.h"
LocalServer::LocalServer(Stream &log, OpenMetrics &openMetrics,
Measurements &measure, Configuration &config,
WifiConnector &wifiConnector)
: PrintLog(log, "LocalServer"), openMetrics(openMetrics), measure(measure),
config(config), wifiConnector(wifiConnector) {}
LocalServer::~LocalServer() {}
bool LocalServer::begin(void) {
server.on("/measures/current", HTTP_GET, [this]() { _GET_measure(); });
server.on(openMetrics.getApi(), HTTP_GET, [this]() { _GET_metrics(); });
server.on("/config", HTTP_GET, [this]() { _GET_config(); });
server.on("/config", HTTP_PUT, [this]() { _PUT_config(); });
server.begin();
if (xTaskCreate(
[](void *param) {
LocalServer *localServer = (LocalServer *)param;
for (;;) {
localServer->_handle();
}
},
"webserver", 1024 * 4, this, 5, NULL) != pdTRUE) {
Serial.println("Create task handle webserver failed");
}
logInfo("Init: " + getHostname() + ".local");
return true;
}
void LocalServer::setAirGraident(AirGradient *ag) { this->ag = ag; }
String LocalServer::getHostname(void) {
return "airgradient_" + ag->deviceId();
}
void LocalServer::_handle(void) { server.handleClient(); }
void LocalServer::_GET_config(void) {
server.send(200, "application/json", config.toString());
}
void LocalServer::_PUT_config(void) {
String data = server.arg(0);
String response = "";
int statusCode = 400; // Status code for data invalid
if (config.parse(data, true)) {
statusCode = 200;
response = "Success";
} else {
response = "Set for cloud configuration. Local configuration ignored";
}
server.send(statusCode, "text/plain", response);
}
void LocalServer::_GET_metrics(void) {
server.send(200, openMetrics.getApiContentType(), openMetrics.getPayload());
}
void LocalServer::_GET_measure(void) {
server.send(
200, "application/json",
measure.toString(true, fwMode, wifiConnector.RSSI(), ag, &config));
}
void LocalServer::setFwMode(AgFirmwareMode fwMode) { this->fwMode = fwMode; }

View File

@ -0,0 +1,38 @@
#ifndef _LOCAL_SERVER_H_
#define _LOCAL_SERVER_H_
#include "AgConfigure.h"
#include "AgValue.h"
#include "AirGradient.h"
#include "OpenMetrics.h"
#include "AgWiFiConnector.h"
#include <Arduino.h>
#include <WebServer.h>
class LocalServer : public PrintLog {
private:
AirGradient *ag;
OpenMetrics &openMetrics;
Measurements &measure;
Configuration &config;
WifiConnector &wifiConnector;
WebServer server;
AgFirmwareMode fwMode;
public:
LocalServer(Stream &log, OpenMetrics &openMetrics, Measurements &measure,
Configuration &config, WifiConnector& wifiConnector);
~LocalServer();
bool begin(void);
void setAirGraident(AirGradient *ag);
String getHostname(void);
void setFwMode(AgFirmwareMode fwMode);
void _handle(void);
void _GET_config(void);
void _PUT_config(void);
void _GET_metrics(void);
void _GET_measure(void);
};
#endif /** _LOCAL_SERVER_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,186 @@
#include "OpenMetrics.h"
OpenMetrics::OpenMetrics(Measurements &measure, Configuration &config,
WifiConnector &wifiConnector, AgApiClient &apiClient)
: measure(measure), config(config), wifiConnector(wifiConnector),
apiClient(apiClient) {}
OpenMetrics::~OpenMetrics() {}
void OpenMetrics::setAirGradient(AirGradient *ag) { this->ag = ag; }
const char *OpenMetrics::getApiContentType(void) {
return "application/openmetrics-text; version=1.0.0; charset=utf-8";
}
const char *OpenMetrics::getApi(void) { return "/metrics"; }
String OpenMetrics::getPayload(void) {
String response;
String current_metric_name;
const auto add_metric = [&](const String &name, const String &help,
const String &type, const String &unit = "") {
current_metric_name = "airgradient_" + name;
if (!unit.isEmpty())
current_metric_name += "_" + unit;
response += "# HELP " + current_metric_name + " " + help + "\n";
response += "# TYPE " + current_metric_name + " " + type + "\n";
if (!unit.isEmpty())
response += "# UNIT " + current_metric_name + " " + unit + "\n";
};
const auto add_metric_point = [&](const String &labels, const String &value) {
response += current_metric_name + "{" + labels + "} " + value + "\n";
};
add_metric("info", "AirGradient device information", "info");
add_metric_point("airgradient_serial_number=\"" + ag->deviceId() +
"\",airgradient_device_type=\"" + ag->getBoardName() +
"\",airgradient_library_version=\"" + ag->getVersion() +
"\"",
"1");
add_metric("config_ok",
"1 if the AirGradient device was able to successfully fetch its "
"configuration from the server",
"gauge");
add_metric_point("", apiClient.isFetchConfigureFailed() ? "0" : "1");
add_metric(
"post_ok",
"1 if the AirGradient device was able to successfully send to the server",
"gauge");
add_metric_point("", apiClient.isPostToServerFailed() ? "0" : "1");
add_metric(
"wifi_rssi",
"WiFi signal strength from the AirGradient device perspective, in dBm",
"gauge", "dbm");
add_metric_point("", String(wifiConnector.RSSI()));
if (config.hasSensorS8 && measure.CO2 >= 0) {
add_metric("co2",
"Carbon dioxide concentration as measured by the AirGradient S8 "
"sensor, in parts per million",
"gauge", "ppm");
add_metric_point("", String(measure.CO2));
}
float _temp = -1001;
float _hum = -1;
int pm01 = -1;
int pm25 = -1;
int pm10 = -1;
int pm03PCount = -1;
if (config.hasSensorPMS1 && config.hasSensorPMS2) {
_temp = (measure.temp_1 + measure.temp_2) / 2.0f;
_hum = (measure.hum_1 + measure.hum_2) / 2.0f;
pm01 = (measure.pm01_1 + measure.pm01_2) / 2;
pm25 = (measure.pm25_1 + measure.pm25_2) / 2;
pm10 = (measure.pm10_1 + measure.pm10_2) / 2;
pm03PCount = (measure.pm03PCount_1 + measure.pm03PCount_2) / 2;
} else {
if (ag->isOne()) {
if (config.hasSensorSHT) {
_temp = measure.Temperature;
_hum = measure.Humidity;
}
} else {
if (config.hasSensorPMS1) {
_temp = measure.temp_1;
_hum = measure.hum_1;
pm01 = measure.pm01_1;
pm25 = measure.pm25_1;
pm10 = measure.pm10_1;
pm03PCount = measure.pm03PCount_1;
}
if (config.hasSensorPMS2) {
_temp = measure.temp_2;
_hum = measure.hum_2;
pm01 = measure.pm01_2;
pm25 = measure.pm25_2;
pm10 = measure.pm10_2;
pm03PCount = measure.pm03PCount_2;
}
}
}
if (config.hasSensorPMS1 || config.hasSensorPMS2) {
if (pm01 >= 0) {
add_metric("pm1",
"PM1.0 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm01));
}
if (pm25 >= 0) {
add_metric("pm2d5",
"PM2.5 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm25));
}
if (pm10 >= 0) {
add_metric("pm10",
"PM10 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm10));
}
if (pm03PCount >= 0) {
add_metric("pm0d3",
"PM0.3 concentration as measured by the AirGradient PMS "
"sensor, in number of particules per 100 milliliters",
"gauge", "p100ml");
add_metric_point("", String(pm03PCount));
}
}
if (config.hasSensorSGP) {
if (measure.TVOC >= 0) {
add_metric("tvoc_index",
"The processed Total Volatile Organic Compounds (TVOC) index "
"as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOC));
}
if (measure.TVOCRaw >= 0) {
add_metric("tvoc_raw",
"The raw input value to the Total Volatile Organic Compounds "
"(TVOC) index as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOCRaw));
}
if (measure.NOx >= 0) {
add_metric("nox_index",
"The processed Nitrous Oxide (NOx) index as measured by the "
"AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.NOx));
}
if (measure.NOxRaw >= 0) {
add_metric("nox_raw",
"The raw input value to the Nitrous Oxide (NOx) index as "
"measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.NOxRaw));
}
}
if (_temp > -1001) {
add_metric("temperature",
"The ambient temperature as measured by the AirGradient SHT "
"sensor, in degrees Celsius",
"gauge", "celsius");
add_metric_point("", String(_temp));
}
if (_hum >= 0) {
add_metric(
"humidity",
"The relative humidity as measured by the AirGradient SHT sensor",
"gauge", "percent");
add_metric_point("", String(_hum));
}
response += "# EOF\n";
return response;
}

View File

@ -0,0 +1,28 @@
#ifndef _OPEN_METRICS_H_
#define _OPEN_METRICS_H_
#include "AgConfigure.h"
#include "AgValue.h"
#include "AgWiFiConnector.h"
#include "AirGradient.h"
#include "AgApiClient.h"
class OpenMetrics{
private:
AirGradient *ag;
Measurements &measure;
Configuration &config;
WifiConnector &wifiConnector;
AgApiClient &apiClient;
public:
OpenMetrics(Measurements &measure, Configuration &conig,
WifiConnector &wifiConnector, AgApiClient& apiClient);
~OpenMetrics();
void setAirGradient(AirGradient *ag);
const char *getApiContentType(void);
const char* getApi(void);
String getPayload(void);
};
#endif /** _OPEN_METRICS_H_ */

View File

@ -9,7 +9,7 @@
#include <HTTPClient.h> #include <HTTPClient.h>
#endif #endif
AgApiClient::AgApiClient(Stream &debug, AgConfigure &config) AgApiClient::AgApiClient(Stream &debug, Configuration &config)
: PrintLog(debug, "ApiClient"), config(config) {} : PrintLog(debug, "ApiClient"), config(config) {}
AgApiClient::~AgApiClient() {} AgApiClient::~AgApiClient() {}

View File

@ -18,14 +18,14 @@
class AgApiClient : public PrintLog { class AgApiClient : public PrintLog {
private: private:
AgConfigure &config; Configuration &config;
AirGradient *ag; AirGradient *ag;
bool getConfigFailed; bool getConfigFailed;
bool postToServerFailed; bool postToServerFailed;
public: public:
AgApiClient(Stream &stream, AgConfigure &config); AgApiClient(Stream &stream, Configuration &config);
~AgApiClient(); ~AgApiClient();
void begin(void); void begin(void);

View File

@ -18,7 +18,7 @@ const char *LED_BAR_MODE_NAMES[] = {
* @param mode LedBarMode value * @param mode LedBarMode value
* @return String * @return String
*/ */
String AgConfigure::getLedBarModeName(LedBarMode mode) { String Configuration::getLedBarModeName(LedBarMode mode) {
if (mode == LedBarModeOff) { if (mode == LedBarModeOff) {
return String(LED_BAR_MODE_NAMES[LedBarModeOff]); return String(LED_BAR_MODE_NAMES[LedBarModeOff]);
} else if (mode == LedBarModePm) { } else if (mode == LedBarModePm) {
@ -33,7 +33,7 @@ String AgConfigure::getLedBarModeName(LedBarMode mode) {
* @brief Save configure to device storage (EEPROM) * @brief Save configure to device storage (EEPROM)
* *
*/ */
void AgConfigure::saveConfig(void) { void Configuration::saveConfig(void) {
config._check = 0; config._check = 0;
int len = sizeof(config) - sizeof(config._check); int len = sizeof(config) - sizeof(config._check);
uint8_t *data = (uint8_t *)&config; uint8_t *data = (uint8_t *)&config;
@ -51,7 +51,7 @@ void AgConfigure::saveConfig(void) {
logInfo("Save Config"); logInfo("Save Config");
} }
void AgConfigure::loadConfig(void) { void Configuration::loadConfig(void) {
bool readSuccess = false; bool readSuccess = false;
#ifdef ESP8266 #ifdef ESP8266
uint8_t *data = (uint8_t *)&config; uint8_t *data = (uint8_t *)&config;
@ -87,7 +87,7 @@ void AgConfigure::loadConfig(void) {
* @brief Set configuration default * @brief Set configuration default
* *
*/ */
void AgConfigure::defaultConfig(void) { void Configuration::defaultConfig(void) {
// Default country is null // Default country is null
memset(config.country, 0, sizeof(config.country)); memset(config.country, 0, sizeof(config.country));
// Default MQTT broker is null. // Default MQTT broker is null.
@ -111,20 +111,21 @@ void AgConfigure::defaultConfig(void) {
* @brief Show configuration as JSON string message over log * @brief Show configuration as JSON string message over log
* *
*/ */
void AgConfigure::printConfig(void) { logInfo(toString().c_str()); } void Configuration::printConfig(void) { logInfo(toString().c_str()); }
/** /**
* @brief Construct a new Ag Configure:: Ag Configure object * @brief Construct a new Ag Configure:: Ag Configure object
* *
* @param debugLog Serial Stream * @param debugLog Serial Stream
*/ */
AgConfigure::AgConfigure(Stream &debugLog) : PrintLog(debugLog, "Configure") {} Configuration::Configuration(Stream &debugLog)
: PrintLog(debugLog, "Configure") {}
/** /**
* @brief Destroy the Ag Configure:: Ag Configure object * @brief Destroy the Ag Configure:: Ag Configure object
* *
*/ */
AgConfigure::~AgConfigure() {} Configuration::~Configuration() {}
/** /**
* @brief Initialize configuration * @brief Initialize configuration
@ -132,7 +133,7 @@ AgConfigure::~AgConfigure() {}
* @return true Success * @return true Success
* @return false Failure * @return false Failure
*/ */
bool AgConfigure::begin(void) { bool Configuration::begin(void) {
EEPROM.begin(512); EEPROM.begin(512);
loadConfig(); loadConfig();
printConfig(); printConfig();
@ -149,7 +150,7 @@ bool AgConfigure::begin(void) {
* @return true Success * @return true Success
* @return false Failure * @return false Failure
*/ */
bool AgConfigure::parse(String data, bool isLocal) { bool Configuration::parse(String data, bool isLocal) {
JSONVar root = JSON.parse(data); JSONVar root = JSON.parse(data);
if (JSON.typeof_(root) == "undefined") { if (JSON.typeof_(root) == "undefined") {
logError("Configuration JSON invalid"); logError("Configuration JSON invalid");
@ -392,6 +393,7 @@ bool AgConfigure::parse(String data, bool isLocal) {
} }
printConfig(); printConfig();
udpated = true;
return true; return true;
} }
@ -400,7 +402,7 @@ bool AgConfigure::parse(String data, bool isLocal) {
* *
* @return String * @return String
*/ */
String AgConfigure::toString(void) { String Configuration::toString(void) {
JSONVar root; JSONVar root;
/** "country" */ /** "country" */
@ -453,7 +455,7 @@ String AgConfigure::toString(void) {
* @return true F * @return true F
* @return false C * @return false C
*/ */
bool AgConfigure::isTemperatureUnitInF(void) { bool Configuration::isTemperatureUnitInF(void) {
return (config.temperatureUnit == 'f'); return (config.temperatureUnit == 'f');
} }
@ -462,7 +464,7 @@ bool AgConfigure::isTemperatureUnitInF(void) {
* *
* @return String * @return String
*/ */
String AgConfigure::getCountry(void) { return String(config.country); } String Configuration::getCountry(void) { return String(config.country); }
/** /**
* @brief PM unit standard (USAQI, ugm3) * @brief PM unit standard (USAQI, ugm3)
@ -470,21 +472,21 @@ String AgConfigure::getCountry(void) { return String(config.country); }
* @return true USAQI * @return true USAQI
* @return false ugm3 * @return false ugm3
*/ */
bool AgConfigure::isPmStandardInUSAQI(void) { return config.inUSAQI; } bool Configuration::isPmStandardInUSAQI(void) { return config.inUSAQI; }
/** /**
* @brief Get CO2 calibration ABC time * @brief Get CO2 calibration ABC time
* *
* @return int Number of day * @return int Number of day
*/ */
int AgConfigure::getCO2CalirationAbcDays(void) { return config.abcDays; } int Configuration::getCO2CalibrationAbcDays(void) { return config.abcDays; }
/** /**
* @brief Get Led Bar Mode * @brief Get Led Bar Mode
* *
* @return LedBarMode * @return LedBarMode
*/ */
LedBarMode AgConfigure::getLedBarMode(void) { LedBarMode Configuration::getLedBarMode(void) {
return (LedBarMode)config.useRGBLedBar; return (LedBarMode)config.useRGBLedBar;
} }
@ -493,7 +495,7 @@ LedBarMode AgConfigure::getLedBarMode(void) {
* *
* @return String * @return String
*/ */
String AgConfigure::getLedBarModeName(void) { String Configuration::getLedBarModeName(void) {
return getLedBarModeName((LedBarMode)config.useRGBLedBar); return getLedBarModeName((LedBarMode)config.useRGBLedBar);
} }
@ -503,14 +505,16 @@ String AgConfigure::getLedBarModeName(void) {
* @return true On * @return true On
* @return false Off * @return false Off
*/ */
bool AgConfigure::getDisplayMode(void) { return config.displayMode; } bool Configuration::getDisplayMode(void) { return config.displayMode; }
/** /**
* @brief Get MQTT uri * @brief Get MQTT uri
* *
* @return String * @return String
*/ */
String AgConfigure::getMqttBrokerUri(void) { return String(config.mqttBroker); } String Configuration::getMqttBrokerUri(void) {
return String(config.mqttBroker);
}
/** /**
* @brief Get configuratoin post data to AirGradient cloud * @brief Get configuratoin post data to AirGradient cloud
@ -518,7 +522,7 @@ String AgConfigure::getMqttBrokerUri(void) { return String(config.mqttBroker); }
* @return true Post * @return true Post
* @return false No-Post * @return false No-Post
*/ */
bool AgConfigure::isPostDataToAirGradient(void) { bool Configuration::isPostDataToAirGradient(void) {
return config.postDataToAirGradient; return config.postDataToAirGradient;
} }
@ -527,7 +531,7 @@ bool AgConfigure::isPostDataToAirGradient(void) {
* *
* @return ConfigurationControl * @return ConfigurationControl
*/ */
ConfigurationControl AgConfigure::getConfigurationControl(void) { ConfigurationControl Configuration::getConfigurationControl(void) {
return (ConfigurationControl)config.configurationControl; return (ConfigurationControl)config.configurationControl;
} }
@ -538,7 +542,7 @@ ConfigurationControl AgConfigure::getConfigurationControl(void) {
* @return true Requested * @return true Requested
* @return false Not requested * @return false Not requested
*/ */
bool AgConfigure::isCo2CalibrationRequested(void) { bool Configuration::isCo2CalibrationRequested(void) {
bool requested = co2CalibrationRequested; bool requested = co2CalibrationRequested;
co2CalibrationRequested = false; // clear requested co2CalibrationRequested = false; // clear requested
return requested; return requested;
@ -551,7 +555,7 @@ bool AgConfigure::isCo2CalibrationRequested(void) {
* @return true Requested * @return true Requested
* @return false Not requested * @return false Not requested
*/ */
bool AgConfigure::isLedBarTestRequested(void) { bool Configuration::isLedBarTestRequested(void) {
bool requested = ledBarTestRequested; bool requested = ledBarTestRequested;
ledBarTestRequested = false; ledBarTestRequested = false;
return requested; return requested;
@ -560,7 +564,7 @@ bool AgConfigure::isLedBarTestRequested(void) {
/** /**
* @brief Reset default configure * @brief Reset default configure
*/ */
void AgConfigure::reset(void) { void Configuration::reset(void) {
defaultConfig(); defaultConfig();
logInfo("Reset to default configure"); logInfo("Reset to default configure");
printConfig(); printConfig();
@ -571,4 +575,10 @@ void AgConfigure::reset(void) {
* *
* @return String * @return String
*/ */
String AgConfigure::getModel(void) { return String(config.model); } String Configuration::getModel(void) { return String(config.model); }
bool Configuration::isUpdated(void) {
bool updated = this->udpated;
this->udpated = false;
return updated;
}

View File

@ -6,7 +6,7 @@
#include <Arduino.h> #include <Arduino.h>
#include <Arduino_JSON.h> #include <Arduino_JSON.h>
class AgConfigure : public PrintLog { class Configuration : public PrintLog {
private: private:
struct Config { struct Config {
char model[20]; char model[20];
@ -32,6 +32,7 @@ private:
struct Config config; struct Config config;
bool co2CalibrationRequested; bool co2CalibrationRequested;
bool ledBarTestRequested; bool ledBarTestRequested;
bool udpated;
String getLedBarModeName(LedBarMode mode); String getLedBarModeName(LedBarMode mode);
void saveConfig(void); void saveConfig(void);
@ -40,8 +41,14 @@ private:
void printConfig(void); void printConfig(void);
public: public:
AgConfigure(Stream &debugLog); Configuration(Stream &debugLog);
~AgConfigure(); ~Configuration();
bool hasSensorS8 = true;
bool hasSensorPMS1 = true;
bool hasSensorPMS2 = true;
bool hasSensorSGP = true;
bool hasSensorSHT = true;
bool begin(void); bool begin(void);
bool parse(String data, bool isLocal); bool parse(String data, bool isLocal);
@ -49,7 +56,7 @@ public:
bool isTemperatureUnitInF(void); bool isTemperatureUnitInF(void);
String getCountry(void); String getCountry(void);
bool isPmStandardInUSAQI(void); bool isPmStandardInUSAQI(void);
int getCO2CalirationAbcDays(void); int getCO2CalibrationAbcDays(void);
LedBarMode getLedBarMode(void); LedBarMode getLedBarMode(void);
String getLedBarModeName(void); String getLedBarModeName(void);
bool getDisplayMode(void); bool getDisplayMode(void);
@ -60,6 +67,7 @@ public:
bool isLedBarTestRequested(void); bool isLedBarTestRequested(void);
void reset(void); void reset(void);
String getModel(void); String getModel(void);
bool isUpdated(void);
}; };
#endif /** _AG_CONFIG_H_ */ #endif /** _AG_CONFIG_H_ */

View File

@ -9,7 +9,7 @@
* *
* @param hasStatus * @param hasStatus
*/ */
void AgOledDisplay::showTempHum(bool hasStatus) { void OledDisplay::showTempHum(bool hasStatus) {
char buf[10]; char buf[10];
if (value.Temperature > -1001) { if (value.Temperature > -1001) {
if (config.isTemperatureUnitInF()) { if (config.isTemperatureUnitInF()) {
@ -53,20 +53,20 @@ void AgOledDisplay::showTempHum(bool hasStatus) {
* @brief Construct a new Ag Oled Display:: Ag Oled Display object * @brief Construct a new Ag Oled Display:: Ag Oled Display object
* *
* @param config AgConfiguration * @param config AgConfiguration
* @param value AgValue * @param value Measurements
* @param log Serial Stream * @param log Serial Stream
*/ */
AgOledDisplay::AgOledDisplay(AgConfigure &config, AgValue &value, Stream &log) OledDisplay::OledDisplay(Configuration &config, Measurements &value, Stream &log)
: PrintLog(log, "AgOledDisplay"), config(config), value(value) {} : PrintLog(log, "OledDisplay"), config(config), value(value) {}
/** /**
* @brief Set AirGradient instance * @brief Set AirGradient instance
* *
* @param ag Point to AirGradient instance * @param ag Point to AirGradient instance
*/ */
void AgOledDisplay::setAirGradient(AirGradient *ag) { this->ag = ag; } void OledDisplay::setAirGradient(AirGradient *ag) { this->ag = ag; }
AgOledDisplay::~AgOledDisplay() {} OledDisplay::~OledDisplay() {}
/** /**
* @brief Initialize display * @brief Initialize display
@ -74,7 +74,7 @@ AgOledDisplay::~AgOledDisplay() {}
* @return true Success * @return true Success
* @return false Failure * @return false Failure
*/ */
bool AgOledDisplay::begin(void) { bool OledDisplay::begin(void) {
if (isBegin) { if (isBegin) {
logWarning("Already begin, call 'end' and try again"); logWarning("Already begin, call 'end' and try again");
return true; return true;
@ -102,14 +102,14 @@ bool AgOledDisplay::begin(void) {
* @brief De-Initialize display * @brief De-Initialize display
* *
*/ */
void AgOledDisplay::end(void) { void OledDisplay::end(void) {
if (!isBegin) { if (!isBegin) {
logWarning("Already end, call 'begin' and try again"); logWarning("Already end, call 'begin' and try again");
return; return;
} }
/** Free u8g2 */ /** Free u8g2 */
delete u8g2; delete DISP();
u8g2 = NULL; u8g2 = NULL;
isBegin = false; isBegin = false;
@ -123,7 +123,7 @@ void AgOledDisplay::end(void) {
* @param line2 * @param line2
* @param line3 * @param line3
*/ */
void AgOledDisplay::setText(String &line1, String &line2, String &line3) { void OledDisplay::setText(String &line1, String &line2, String &line3) {
setText(line1.c_str(), line2.c_str(), line3.c_str()); setText(line1.c_str(), line2.c_str(), line3.c_str());
} }
@ -134,7 +134,7 @@ void AgOledDisplay::setText(String &line1, String &line2, String &line3) {
* @param line2 * @param line2
* @param line3 * @param line3
*/ */
void AgOledDisplay::setText(const char *line1, const char *line2, void OledDisplay::setText(const char *line1, const char *line2,
const char *line3) { const char *line3) {
DISP()->firstPage(); DISP()->firstPage();
do { do {
@ -153,7 +153,7 @@ void AgOledDisplay::setText(const char *line1, const char *line2,
* @param line3 * @param line3
* @param line4 * @param line4
*/ */
void AgOledDisplay::setText(String &line1, String &line2, String &line3, void OledDisplay::setText(String &line1, String &line2, String &line3,
String &line4) { String &line4) {
setText(line1.c_str(), line2.c_str(), line3.c_str(), line4.c_str()); setText(line1.c_str(), line2.c_str(), line3.c_str(), line4.c_str());
} }
@ -166,7 +166,7 @@ void AgOledDisplay::setText(String &line1, String &line2, String &line3,
* @param line3 * @param line3
* @param line4 * @param line4
*/ */
void AgOledDisplay::setText(const char *line1, const char *line2, void OledDisplay::setText(const char *line1, const char *line2,
const char *line3, const char *line4) { const char *line3, const char *line4) {
DISP()->firstPage(); DISP()->firstPage();
do { do {
@ -182,13 +182,13 @@ void AgOledDisplay::setText(const char *line1, const char *line2,
* @brief Update dashboard content * @brief Update dashboard content
* *
*/ */
void AgOledDisplay::showDashboard(void) { showDashboard(NULL); } void OledDisplay::showDashboard(void) { showDashboard(NULL); }
/** /**
* @brief Update dashboard content and error status * @brief Update dashboard content and error status
* *
*/ */
void AgOledDisplay::showDashboard(const char *status) { void OledDisplay::showDashboard(const char *status) {
char strBuf[10]; char strBuf[10];
DISP()->firstPage(); DISP()->firstPage();
@ -244,8 +244,8 @@ void AgOledDisplay::showDashboard(const char *status) {
/** Draw PM2.5 value */ /** Draw PM2.5 value */
DISP()->setFont(u8g2_font_t0_22b_tf); DISP()->setFont(u8g2_font_t0_22b_tf);
if (config.isPmStandardInUSAQI()) { if (config.isPmStandardInUSAQI()) {
if (value.PM25 >= 0) { if (value.pm25_1 >= 0) {
sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(value.PM25)); sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(value.pm25_1));
} else { } else {
sprintf(strBuf, "%s", "-"); sprintf(strBuf, "%s", "-");
} }
@ -253,8 +253,8 @@ void AgOledDisplay::showDashboard(const char *status) {
DISP()->setFont(u8g2_font_t0_12_tf); DISP()->setFont(u8g2_font_t0_12_tf);
DISP()->drawUTF8(48, 61, "AQI"); DISP()->drawUTF8(48, 61, "AQI");
} else { } else {
if (value.PM25 >= 0) { if (value.pm25_1 >= 0) {
sprintf(strBuf, "%d", value.PM25); sprintf(strBuf, "%d", value.pm25_1);
} else { } else {
sprintf(strBuf, "%s", "-"); sprintf(strBuf, "%s", "-");
} }

View File

@ -7,19 +7,19 @@
#include "Main/PrintLog.h" #include "Main/PrintLog.h"
#include <Arduino.h> #include <Arduino.h>
class AgOledDisplay : public PrintLog { class OledDisplay : public PrintLog {
private: private:
AgConfigure &config; Configuration &config;
AirGradient *ag; AirGradient *ag;
bool isBegin = false; bool isBegin = false;
void *u8g2 = NULL; void *u8g2 = NULL;
AgValue &value; Measurements &value;
void showTempHum(bool hasStatus); void showTempHum(bool hasStatus);
public: public:
AgOledDisplay(AgConfigure &config, AgValue &value, OledDisplay(Configuration &config, Measurements &value,
Stream &log); Stream &log);
~AgOledDisplay(); ~OledDisplay();
void setAirGradient(AirGradient *ag); void setAirGradient(AirGradient *ag);
bool begin(void); bool begin(void);

View File

@ -5,6 +5,8 @@
#define LED_SHORT_BLINK_DELAY 500 /** ms */ #define LED_SHORT_BLINK_DELAY 500 /** ms */
#define LED_LONG_BLINK_DELAY 2000 /** ms */ #define LED_LONG_BLINK_DELAY 2000 /** ms */
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
/** /**
* @brief Animation LED bar with color * @brief Animation LED bar with color
* *
@ -12,7 +14,7 @@
* @param g * @param g
* @param b * @param b
*/ */
void AgStateMachine::ledBarSingleLedAnimation(uint8_t r, uint8_t g, uint8_t b) { void StateMachine::ledBarSingleLedAnimation(uint8_t r, uint8_t g, uint8_t b) {
if (ledBarAnimationCount < 0) { if (ledBarAnimationCount < 0) {
ledBarAnimationCount = 0; ledBarAnimationCount = 0;
ag->ledBar.setColor(r, g, b, ledBarAnimationCount); ag->ledBar.setColor(r, g, b, ledBarAnimationCount);
@ -30,7 +32,7 @@ void AgStateMachine::ledBarSingleLedAnimation(uint8_t r, uint8_t g, uint8_t b) {
* *
* @param ms Miliseconds * @param ms Miliseconds
*/ */
void AgStateMachine::ledStatusBlinkDelay(uint32_t ms) { void StateMachine::ledStatusBlinkDelay(uint32_t ms) {
ag->statusLed.setOn(); ag->statusLed.setOn();
delay(ms); delay(ms);
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -41,13 +43,13 @@ void AgStateMachine::ledStatusBlinkDelay(uint32_t ms) {
* @brief Led bar show led color status * @brief Led bar show led color status
* *
*/ */
void AgStateMachine::sensorLedHandle(void) { void StateMachine::sensorhandleLeds(void) {
switch (config.getLedBarMode()) { switch (config.getLedBarMode()) {
case LedBarMode::LedBarModeCO2: case LedBarMode::LedBarModeCO2:
co2LedHandle(); co2handleLeds();
break; break;
case LedBarMode::LedBarModePm: case LedBarMode::LedBarModePm:
pm25LedHandle(); pm25handleLeds();
break; break;
default: default:
ag->ledBar.clear(); ag->ledBar.clear();
@ -59,7 +61,7 @@ void AgStateMachine::sensorLedHandle(void) {
* @brief Show CO2 LED status * @brief Show CO2 LED status
* *
*/ */
void AgStateMachine::co2LedHandle(void) { void StateMachine::co2handleLeds(void) {
int co2Value = value.CO2; int co2Value = value.CO2;
if (co2Value <= 400) { if (co2Value <= 400) {
/** G; 1 */ /** G; 1 */
@ -142,8 +144,8 @@ void AgStateMachine::co2LedHandle(void) {
* @brief Show PM2.5 LED status * @brief Show PM2.5 LED status
* *
*/ */
void AgStateMachine::pm25LedHandle(void) { void StateMachine::pm25handleLeds(void) {
int pm25Value = value.PM25; int pm25Value = value.pm25_1;
if (pm25Value <= 5) { if (pm25Value <= 5) {
/** G; 1 */ /** G; 1 */
ag->ledBar.setColor(0, 255, 0, ag->ledBar.getNumberOfLeds() - 1); ag->ledBar.setColor(0, 255, 0, ag->ledBar.getNumberOfLeds() - 1);
@ -221,29 +223,182 @@ void AgStateMachine::pm25LedHandle(void) {
} }
} }
void StateMachine::co2Calibration(void) {
if (config.isCo2CalibrationRequested() && config.hasSensorS8) {
logInfo("CO2 Calibration");
/** Count down to 0 then start */
for (int i = 0; i < SENSOR_CO2_CALIB_COUNTDOWN_MAX; i++) {
if (ag->isOne()) {
String str =
"after " + String(SENSOR_CO2_CALIB_COUNTDOWN_MAX - i) + " sec";
disp.setText("Start CO2 calib", str.c_str(), "");
} else {
logInfo("Start CO2 calib after " +
String(SENSOR_CO2_CALIB_COUNTDOWN_MAX - i) + " sec");
}
delay(1000);
}
if (ag->s8.setBaselineCalibration()) {
if (ag->isOne()) {
disp.setText("Calibration", "success", "");
} else {
logInfo("CO2 Calibration: success");
}
delay(1000);
if (ag->isOne()) {
disp.setText("Wait for", "calib finish", "...");
} else {
logInfo("CO2 Calibration: Wait for calibration finish...");
}
/** Count down wait for finish */
int count = 0;
while (ag->s8.isBaseLineCalibrationDone() == false) {
delay(1000);
count++;
}
if (ag->isOne()) {
String str = "after " + String(count);
disp.setText("Calib finish", str.c_str(), "sec");
} else {
logInfo("CO2 Calibration: finish after " + String(count) + " sec");
}
delay(2000);
} else {
if (ag->isOne()) {
disp.setText("Calibration", "failure!!!", "");
} else {
logInfo("CO2 Calibration: failure!!!");
}
delay(2000);
}
}
if (config.getCO2CalibrationAbcDays() > 0 && config.hasSensorS8) {
int newHour = config.getCO2CalibrationAbcDays() * 24;
logInfo("Requested abcDays setting: " +
String(config.getCO2CalibrationAbcDays()) + "days (" +
String(newHour) + "hours)");
int curHour = ag->s8.getAbcPeriod();
logInfo("Current S8 abcDays setting: " + String(curHour) + "(hours)");
if (curHour == newHour) {
logInfo("'abcDays' unchanged");
} else {
if (ag->s8.setAbcPeriod(config.getCO2CalibrationAbcDays() * 24) ==
false) {
logError("Set S8 abcDays period failed");
} else {
logInfo("Set S8 abcDays period success");
}
}
} else {
logWarning("CO2 S8 not available, set 'abcDays' ignored");
}
}
void StateMachine::ledBarTest(void) {
if (config.isLedBarTestRequested()) {
if (config.getCountry() == "TH") {
uint32_t tstart = millis();
logInfo("Start run LED test for 2 min");
while (1) {
ledBarRunTest();
uint32_t ms = (uint32_t)(millis() - tstart);
if (ms >= (60 * 1000 * 2)) {
logInfo("LED test after 2 min finish");
break;
}
}
} else {
ledBarRunTest();
}
}
}
void StateMachine::ledBarRunTest(void) {
disp.setText("LED Test", "running", ".....");
runLedTest('r');
ag->ledBar.show();
delay(1000);
runLedTest('g');
ag->ledBar.show();
delay(1000);
runLedTest('b');
ag->ledBar.show();
delay(1000);
runLedTest('w');
ag->ledBar.show();
delay(1000);
runLedTest('n');
ag->ledBar.show();
delay(1000);
}
void StateMachine::runLedTest(char color) {
int r = 0;
int g = 0;
int b = 0;
switch (color) {
case 'g':
g = 255;
break;
case 'y':
r = 255;
g = 255;
break;
case 'o':
r = 255;
g = 128;
break;
case 'r':
r = 255;
break;
case 'b':
b = 255;
break;
case 'w':
r = 255;
g = 255;
b = 255;
break;
case 'p':
r = 153;
b = 153;
break;
case 'z':
r = 102;
break;
case 'n':
default:
break;
}
ag->ledBar.setColor(r, g, b);
}
/** /**
* @brief Construct a new Ag State Machine:: Ag State Machine object * @brief Construct a new Ag State Machine:: Ag State Machine object
* *
* @param disp AgOledDisplay * @param disp OledDisplay
* @param log Serial Stream * @param log Serial Stream
* @param value AgValue * @param value Measurements
* @param config AgConfigure * @param config Configuration
*/ */
AgStateMachine::AgStateMachine(AgOledDisplay &disp, Stream &log, AgValue &value, StateMachine::StateMachine(OledDisplay &disp, Stream &log, Measurements &value,
AgConfigure &config) Configuration &config)
: PrintLog(log, "AgStateMachine"), disp(disp), value(value), : PrintLog(log, "StateMachine"), disp(disp), value(value), config(config) {}
config(config) {}
AgStateMachine::~AgStateMachine() {} StateMachine::~StateMachine() {}
/** /**
* @brief OLED display show content from state value * @brief OLED display show content from state value
* *
* @param state * @param state
*/ */
void AgStateMachine::displayHandle(AgStateMachineState state) { void StateMachine::displayHandle(AgStateMachineState state) {
// Ignore handle if not ONE_INDOOR board // Ignore handle if not ONE_INDOOR board
if (!ag->isOneIndoor()) { if (!ag->isOne()) {
return; return;
} }
@ -320,6 +475,9 @@ void AgStateMachine::displayHandle(AgStateMachineState state) {
disp.showDashboard(); disp.showDashboard();
break; break;
} }
case AgStateMachineCo2Calibration:
co2Calibration();
break;
default: default:
break; break;
} }
@ -329,27 +487,25 @@ void AgStateMachine::displayHandle(AgStateMachineState state) {
* @brief OLED display show content as previous state updated * @brief OLED display show content as previous state updated
* *
*/ */
void AgStateMachine::displayHandle(void) { displayHandle(dispState); } void StateMachine::displayHandle(void) { displayHandle(dispState); }
/** /**
* @brief Update status add to dashboard * @brief Update status add to dashboard
* *
*/ */
void AgStateMachine::displaySetAddToDashBoard(void) { void StateMachine::displaySetAddToDashBoard(void) {
addToDashBoard = true; addToDashBoard = true;
addToDashboardTime = millis(); addToDashboardTime = millis();
} }
void AgStateMachine::displayClearAddToDashBoard(void) { void StateMachine::displayClearAddToDashBoard(void) { addToDashBoard = false; }
addToDashBoard = false;
}
/** /**
* @brief Set WiFi connection coundown on dashboard * @brief Set WiFi connection coundown on dashboard
* *
* @param count Seconds * @param count Seconds
*/ */
void AgStateMachine::displayWiFiConnectCountDown(int count) { void StateMachine::displayWiFiConnectCountDown(int count) {
wifiConnectCountDown = count; wifiConnectCountDown = count;
} }
@ -357,21 +513,21 @@ void AgStateMachine::displayWiFiConnectCountDown(int count) {
* @brief Init before start LED bar animation * @brief Init before start LED bar animation
* *
*/ */
void AgStateMachine::ledAnimationInit(void) { ledBarAnimationCount = -1; } void StateMachine::ledAnimationInit(void) { ledBarAnimationCount = -1; }
/** /**
* @brief Handle LED from state * @brief Handle LED from state
* *
* @param state * @param state
*/ */
void AgStateMachine::ledHandle(AgStateMachineState state) { void StateMachine::handleLeds(AgStateMachineState state) {
if (state > AgStateMachineNormal) { if (state > AgStateMachineNormal) {
logError("ledHandle: state invalid"); logError("ledHandle: state invalid");
return; return;
} }
ledState = state; ledState = state;
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.clear(); // Set all LED OFF ag->ledBar.clear(); // Set all LED OFF
} }
switch (state) { switch (state) {
@ -379,7 +535,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
/** In WiFi Manager Mode */ /** In WiFi Manager Mode */
/** Turn LED OFF */ /** Turn LED OFF */
/** Turn midle LED Color */ /** Turn midle LED Color */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(0, 0, 255, ag->ledBar.getNumberOfLeds() / 2); ag->ledBar.setColor(0, 0, 255, ag->ledBar.getNumberOfLeds() / 2);
} else { } else {
ag->statusLed.setToggle(); ag->statusLed.setToggle();
@ -388,7 +544,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
} }
case AgStateMachineWiFiManagerPortalActive: { case AgStateMachineWiFiManagerPortalActive: {
/** WiFi Manager has connected to mobile phone */ /** WiFi Manager has connected to mobile phone */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(0, 0, 255); ag->ledBar.setColor(0, 0, 255);
} else { } else {
ag->statusLed.setOn(); ag->statusLed.setOn();
@ -398,7 +554,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineWiFiManagerStaConnecting: { case AgStateMachineWiFiManagerStaConnecting: {
/** after SSID and PW entered and OK clicked, connection to WiFI network is /** after SSID and PW entered and OK clicked, connection to WiFI network is
* attempted */ * attempted */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ledBarSingleLedAnimation(255, 255, 255); ledBarSingleLedAnimation(255, 255, 255);
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -407,7 +563,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
} }
case AgStateMachineWiFiManagerStaConnected: { case AgStateMachineWiFiManagerStaConnected: {
/** Connecting to WiFi worked */ /** Connecting to WiFi worked */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(255, 255, 255); ag->ledBar.setColor(255, 255, 255);
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -416,7 +572,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
} }
case AgStateMachineWiFiOkServerConnecting: { case AgStateMachineWiFiOkServerConnecting: {
/** once connected to WiFi an attempt to reach the server is performed */ /** once connected to WiFi an attempt to reach the server is performed */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ledBarSingleLedAnimation(0, 255, 0); ledBarSingleLedAnimation(0, 255, 0);
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -425,7 +581,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
} }
case AgStateMachineWiFiOkServerConnected: { case AgStateMachineWiFiOkServerConnected: {
/** Server is reachable, all fine */ /** Server is reachable, all fine */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(0, 255, 0); ag->ledBar.setColor(0, 255, 0);
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -441,7 +597,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
} }
case AgStateMachineWiFiManagerConnectFailed: { case AgStateMachineWiFiManagerConnectFailed: {
/** Cannot connect to WiFi (e.g. wrong password, WPA Enterprise etc.) */ /** Cannot connect to WiFi (e.g. wrong password, WPA Enterprise etc.) */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(255, 0, 0); ag->ledBar.setColor(255, 0, 0);
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -459,7 +615,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineWiFiOkServerConnectFailed: { case AgStateMachineWiFiOkServerConnectFailed: {
/** 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. */ * whitelisting needed etc. */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(233, 183, 54); /** orange */ ag->ledBar.setColor(233, 183, 54); /** orange */
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -475,7 +631,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
} }
case AgStateMachineWiFiOkServerOkSensorConfigFailed: { case AgStateMachineWiFiOkServerOkSensorConfigFailed: {
/** Server reachable but sensor not configured correctly */ /** Server reachable but sensor not configured correctly */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(139, 24, 248); /** violet */ ag->ledBar.setColor(139, 24, 248); /** violet */
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -492,12 +648,12 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineWiFiLost: { case AgStateMachineWiFiLost: {
/** Connection to WiFi network failed credentials incorrect encryption not /** Connection to WiFi network failed credentials incorrect encryption not
* supported etc. */ * supported etc. */
if (ag->isOneIndoor()) { if (ag->isOne()) {
/** WIFI failed status LED color */ /** WIFI failed status LED color */
ag->ledBar.setColor(255, 0, 0, 0); ag->ledBar.setColor(255, 0, 0, 0);
/** Show CO2 or PM color status */ /** Show CO2 or PM color status */
// sensorLedColorHandler(); // sensorLedColorHandler();
sensorLedHandle(); sensorhandleLeds();
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
} }
@ -506,11 +662,11 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineServerLost: { case AgStateMachineServerLost: {
/** Connected to WiFi network but the server cannot be reached through the /** Connected to WiFi network but the server cannot be reached through the
* internet, e.g. blocked by firewall */ * internet, e.g. blocked by firewall */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(233, 183, 54, 0); ag->ledBar.setColor(233, 183, 54, 0);
/** Show CO2 or PM color status */ /** Show CO2 or PM color status */
sensorLedHandle(); sensorhandleLeds();
// sensorLedColorHandler(); // sensorLedColorHandler();
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
@ -520,30 +676,33 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineSensorConfigFailed: { case AgStateMachineSensorConfigFailed: {
/** 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 */ * the server side */
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.setColor(139, 24, 248, 0); ag->ledBar.setColor(139, 24, 248, 0);
/** Show CO2 or PM color status */ /** Show CO2 or PM color status */
sensorLedHandle(); sensorhandleLeds();
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
} }
break; break;
} }
case AgStateMachineNormal: { case AgStateMachineNormal: {
if (ag->isOneIndoor()) { if (ag->isOne()) {
sensorLedHandle(); sensorhandleLeds();
} else { } else {
ag->statusLed.setOff(); ag->statusLed.setOff();
} }
break; break;
} }
case AgStateMachineLedBarTest:
ledBarTest();
break;
default: default:
break; break;
} }
// Show LED bar color // Show LED bar color
if (ag->isOneIndoor()) { if (ag->isOne()) {
ag->ledBar.show(); ag->ledBar.show();
} }
} }
@ -552,14 +711,14 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
* @brief Handle LED as previous state updated * @brief Handle LED as previous state updated
* *
*/ */
void AgStateMachine::ledHandle(void) { ledHandle(ledState); } void StateMachine::handleLeds(void) { handleLeds(ledState); }
/** /**
* @brief Set display state * @brief Set display state
* *
* @param state * @param state
*/ */
void AgStateMachine::setDisplayState(AgStateMachineState state) { void StateMachine::setDisplayState(AgStateMachineState state) {
dispState = state; dispState = state;
} }
@ -568,18 +727,26 @@ void AgStateMachine::setDisplayState(AgStateMachineState state) {
* *
* @return AgStateMachineState * @return AgStateMachineState
*/ */
AgStateMachineState AgStateMachine::getDisplayState(void) { return dispState; } AgStateMachineState StateMachine::getDisplayState(void) { return dispState; }
/** /**
* @brief Set AirGradient instance * @brief Set AirGradient instance
* *
* @param ag Point to AirGradient instance * @param ag Point to AirGradient instance
*/ */
void AgStateMachine::setAirGradient(AirGradient *ag) { this->ag = ag; } void StateMachine::setAirGradient(AirGradient *ag) { this->ag = ag; }
/** /**
* @brief Get current LED state * @brief Get current LED state
* *
* @return AgStateMachineState * @return AgStateMachineState
*/ */
AgStateMachineState AgStateMachine::getLedState(void) { return ledState; } AgStateMachineState StateMachine::getLedState(void) { return ledState; }
void StateMachine::executeCo2Calibration(void) {
displayHandle(AgStateMachineCo2Calibration);
}
void StateMachine::executeLedBarTest(void) {
handleLeds(AgStateMachineLedBarTest);
}

View File

@ -7,15 +7,15 @@
#include "Main/PrintLog.h" #include "Main/PrintLog.h"
#include "App/AppDef.h" #include "App/AppDef.h"
class AgStateMachine : public PrintLog { class StateMachine : public PrintLog {
private: private:
// AgStateMachineState state; // AgStateMachineState state;
AgStateMachineState ledState; AgStateMachineState ledState;
AgStateMachineState dispState; AgStateMachineState dispState;
AirGradient *ag; AirGradient *ag;
AgOledDisplay &disp; OledDisplay &disp;
AgValue &value; Measurements &value;
AgConfigure &config; Configuration &config;
bool addToDashBoard = false; bool addToDashBoard = false;
uint32_t addToDashboardTime; uint32_t addToDashboardTime;
@ -24,14 +24,18 @@ private:
void ledBarSingleLedAnimation(uint8_t r, uint8_t g, uint8_t b); void ledBarSingleLedAnimation(uint8_t r, uint8_t g, uint8_t b);
void ledStatusBlinkDelay(uint32_t delay); void ledStatusBlinkDelay(uint32_t delay);
void sensorLedHandle(void); void sensorhandleLeds(void);
void co2LedHandle(void); void co2handleLeds(void);
void pm25LedHandle(void); void pm25handleLeds(void);
void co2Calibration(void);
void ledBarTest(void);
void ledBarRunTest(void);
void runLedTest(char color);
public: public:
AgStateMachine(AgOledDisplay &disp, Stream &log, StateMachine(OledDisplay &disp, Stream &log,
AgValue &value, AgConfigure& config); Measurements &value, Configuration& config);
~AgStateMachine(); ~StateMachine();
void setAirGradient(AirGradient* ag); void setAirGradient(AirGradient* ag);
void displayHandle(AgStateMachineState state); void displayHandle(AgStateMachineState state);
void displayHandle(void); void displayHandle(void);
@ -39,11 +43,13 @@ public:
void displayClearAddToDashBoard(void); void displayClearAddToDashBoard(void);
void displayWiFiConnectCountDown(int count); void displayWiFiConnectCountDown(int count);
void ledAnimationInit(void); void ledAnimationInit(void);
void ledHandle(AgStateMachineState state); void handleLeds(AgStateMachineState state);
void ledHandle(void); void handleLeds(void);
void setDisplayState(AgStateMachineState state); void setDisplayState(AgStateMachineState state);
AgStateMachineState getDisplayState(void); AgStateMachineState getDisplayState(void);
AgStateMachineState getLedState(void); AgStateMachineState getLedState(void);
void executeCo2Calibration(void);
void executeLedBarTest(void);
}; };
#endif /** _AG_STATE_MACHINE_H_ */ #endif /** _AG_STATE_MACHINE_H_ */

151
src/AgValue.cpp Normal file
View File

@ -0,0 +1,151 @@
#include "AgValue.h"
#include "AgConfigure.h"
#include "AirGradient.h"
#include <Arduino_JSON.h>
String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
void *_ag, void *_config) {
AirGradient *ag = (AirGradient *)_ag;
Configuration *config = (Configuration *)_config;
JSONVar root;
root["wifi"] = rssi;
if (localServer) {
root["serialno"] = ag->deviceId();
}
if (config->hasSensorS8) {
if (this->CO2 >= 0) {
root["rco2"] = this->CO2;
}
}
if (ag->isOne()) {
if (config->hasSensorPMS1) {
if (this->pm01_1 >= 0) {
root["pm01"] = this->pm01_1;
}
if (this->pm25_1 >= 0) {
root["pm02"] = this->pm25_1;
}
if (this->pm10_1 >= 0) {
root["pm10"] = this->pm10_1;
}
if (this->pm03PCount_1 >= 0) {
if (localServer) {
root["pm003Count"] = this->pm03PCount_1;
} else {
root["pm003_count"] = this->pm03PCount_1;
}
}
}
if (config->hasSensorSHT) {
if (this->Temperature > -1001) {
root["atmp"] = ag->round2(this->Temperature);
}
if (this->Humidity >= 0) {
root["rhum"] = this->Humidity;
}
}
} else {
if (config->hasSensorPMS1 && config->hasSensorPMS2) {
root["pm01"] = ag->round2((this->pm01_1 + this->pm01_2) / 2.0);
root["pm02"] = ag->round2((this->pm25_1 + this->pm25_2) / 2.0);
root["pm10"] = ag->round2((this->pm10_1 + this->pm10_2) / 2.0);
if (localServer) {
root["pm003Count"] =
ag->round2((this->pm03PCount_1 + this->pm03PCount_2) / 2.0);
} else {
root["pm003_count"] =
ag->round2((this->pm03PCount_1 + this->pm03PCount_2) / 2.0);
}
root["atmp"] = ag->round2((this->temp_1 + this->temp_2) / 2.0);
root["rhum"] = ag->round2((this->hum_1 + this->hum_2) / 2.0);
}
if (fwMode == FW_MDOE_O_1PS || fwMode == FW_MODE_O_1PST) {
if (config->hasSensorPMS1) {
root["pm01"] = this->pm01_1;
root["pm02"] = this->pm25_1;
root["pm10"] = this->pm10_1;
if (localServer) {
root["pm003Count"] = this->pm03PCount_1;
} else {
root["pm003_count"] = this->pm03PCount_1;
}
root["atmp"] = ag->round2(this->temp_1);
root["rhum"] = this->hum_1;
}
if (config->hasSensorPMS2) {
root["pm01"] = this->pm01_2;
root["pm02"] = this->pm25_2;
root["pm10"] = this->pm10_2;
if (localServer) {
root["pm003Count"] = this->pm03PCount_2;
} else {
root["pm003_count"] = this->pm03PCount_2;
}
root["atmp"] = ag->round2(this->temp_2);
root["rhum"] = this->hum_2;
}
} else {
if (config->hasSensorPMS1) {
root["channels"]["1"]["pm01"] = this->pm01_1;
root["channels"]["1"]["pm02"] = this->pm25_1;
root["channels"]["1"]["pm10"] = this->pm10_1;
if (localServer) {
root["channels"]["1"]["pm003Count"] = this->pm03PCount_1;
} else {
root["channels"]["1"]["pm003_count"] = this->pm03PCount_1;
}
root["channels"]["1"]["atmp"] = ag->round2(this->temp_1);
root["channels"]["1"]["rhum"] = this->hum_1;
}
if (config->hasSensorPMS2) {
root["channels"]["2"]["pm01"] = this->pm01_2;
root["channels"]["2"]["pm02"] = this->pm25_2;
root["channels"]["2"]["pm10"] = this->pm10_2;
if (localServer) {
root["channels"]["2"]["pm003Count"] = this->pm03PCount_2;
} else {
root["channels"]["2"]["pm003_count"] = this->pm03PCount_2;
}
root["channels"]["2"]["atmp"] = ag->round2(this->temp_2);
root["channels"]["2"]["rhum"] = this->hum_2;
}
}
}
if (config->hasSensorSGP) {
if (this->TVOC >= 0) {
if (localServer) {
root["tvocIndex"] = this->TVOC;
} else {
root["tvoc_index"] = this->TVOC;
}
}
if (this->TVOCRaw >= 0) {
root["tvoc_raw"] = this->TVOCRaw;
}
if (this->NOx >= 0) {
if (localServer) {
root["noxIndex"] = this->NOx;
} else {
root["nox_index"] = this->NOx;
}
}
if (this->NOxRaw >= 0) {
root["nox_raw"] = this->NOxRaw;
}
}
root["boot"] = bootCount;
if (localServer) {
root["ledMode"] = config->getLedBarModeName();
root["firmwareVersion"] = ag->getVersion();
root["fwMode"] = AgFirmwareModeName(fwMode);
}
return JSON.stringify(root);
}

View File

@ -1,20 +1,76 @@
#ifndef _AG_VALUE_H_ #ifndef _AG_VALUE_H_
#define _AG_VALUE_H_ #define _AG_VALUE_H_
class AgValue { #include <Arduino.h>
#include "App/AppDef.h"
class Measurements {
private: private:
public: public:
AgValue() {} Measurements() {
~AgValue() {} pm25_1 = -1;
pm01_1 = -1;
pm10_1 = -1;
pm03PCount_1 = -1;
temp_1 = -1001;
hum_1 = -1;
float Temperature = -1001; pm25_2 = -1;
int Humidity = -1; pm01_2 = -1;
int CO2 = -1; pm10_2 = -1;
int PM25 = -1; pm03PCount_2 = -1;
int TVOC = -1; temp_2 = -1001;
int TVOCRaw = -1; hum_2 = -1;
int NOx = -1;
int NOxRaw = -1; Temperature = -1001;
Humidity = -1;
CO2 = -1;
TVOC = -1;
TVOCRaw = -1;
NOx = -1;
NOxRaw = -1;
}
~Measurements() {}
float Temperature;
int Humidity;
int CO2;
int TVOC;
int TVOCRaw;
int NOx;
int NOxRaw;
int pm25_1;
int pm01_1;
int pm10_1;
int pm03PCount_1;
float temp_1;
int hum_1;
int pm25_2;
int pm01_2;
int pm10_2;
int pm03PCount_2;
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;
int bootCount;
String toString(bool isLocal, AgFirmwareMode fwMode, int rssi, void* _ag, void* _config);
}; };
#endif /** _AG_VALUE_H_ */ #endif /** _AG_VALUE_H_ */

View File

@ -1,5 +1,3 @@
#ifdef ESP32
#include "AgWiFiConnector.h" #include "AgWiFiConnector.h"
#include "Libraries/WiFiManager/WiFiManager.h" #include "Libraries/WiFiManager/WiFiManager.h"
@ -8,25 +6,28 @@
#define WIFI() ((WiFiManager *)(this->wifi)) #define WIFI() ((WiFiManager *)(this->wifi))
/**
* @brief Construct a new Ag Wi Fi Connector:: Ag Wi Fi Connector object
*
* @param disp AgOledDisplay
* @param log Stream
* @param sm AgStateMachine
*/
AgWiFiConnector::AgWiFiConnector(AgOledDisplay &disp, Stream &log,
AgStateMachine &sm)
: PrintLog(log, "AgWiFiConnector"), disp(disp), sm(sm) {}
AgWiFiConnector::~AgWiFiConnector() {}
/** /**
* @brief Set reference AirGradient instance * @brief Set reference AirGradient instance
* *
* @param ag Point to AirGradient instance * @param ag Point to AirGradient instance
*/ */
void AgWiFiConnector::setAirGradient(AirGradient *ag) { this->ag = ag; } void WifiConnector::setAirGradient(AirGradient *ag) { this->ag = ag; }
#ifdef ESP32
/**
* @brief Construct a new Ag Wi Fi Connector:: Ag Wi Fi Connector object
*
* @param disp OledDisplay
* @param log Stream
* @param sm StateMachine
*/
WifiConnector::WifiConnector(OledDisplay &disp, Stream &log, StateMachine &sm)
: PrintLog(log, "WifiConnector"), disp(disp), sm(sm) {}
#else
WifiConnector::WifiConnector(Stream &log) : PrintLog(log, "WiFiConnector") {}
#endif
WifiConnector::~WifiConnector() {}
/** /**
* @brief Connection to WIFI AP process. Just call one times * @brief Connection to WIFI AP process. Just call one times
@ -34,7 +35,7 @@ void AgWiFiConnector::setAirGradient(AirGradient *ag) { this->ag = ag; }
* @return true Success * @return true Success
* @return false Failure * @return false Failure
*/ */
bool AgWiFiConnector::connect(void) { bool WifiConnector::connect(void) {
if (wifi == NULL) { if (wifi == NULL) {
wifi = new WiFiManager(); wifi = new WiFiManager();
if (wifi == NULL) { if (wifi == NULL) {
@ -46,23 +47,27 @@ bool AgWiFiConnector::connect(void) {
WIFI()->setConfigPortalBlocking(false); WIFI()->setConfigPortalBlocking(false);
WIFI()->setTimeout(WIFI_CONNECT_COUNTDOWN_MAX); WIFI()->setTimeout(WIFI_CONNECT_COUNTDOWN_MAX);
#ifdef ESP32
WIFI()->setAPCallback([this](WiFiManager *obj) { _wifiApCallback(); }); WIFI()->setAPCallback([this](WiFiManager *obj) { _wifiApCallback(); });
WIFI()->setSaveConfigCallback([this]() { _wifiSaveConfig(); }); WIFI()->setSaveConfigCallback([this]() { _wifiSaveConfig(); });
WIFI()->setSaveParamsCallback([this]() { _wifiSaveParamCallback(); }); WIFI()->setSaveParamsCallback([this]() { _wifiSaveParamCallback(); });
if (ag->isOne()) {
if (ag->isOneIndoor()) {
disp.setText("Connecting to", "WiFi", "..."); disp.setText("Connecting to", "WiFi", "...");
} else { } else {
logInfo("Connecting to WiFi..."); logInfo("Connecting to WiFi...");
} }
ssid = "airgradient-" + ag->deviceId(); ssid = "airgradient-" + ag->deviceId();
#else
ssid = "AG-" + String(ESP.getChipId(), HEX);
#endif
WIFI()->setConfigPortalTimeout(WIFI_CONNECT_COUNTDOWN_MAX);
WIFI()->autoConnect(ssid.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT); WIFI()->autoConnect(ssid.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT);
#ifdef ESP32
// Task handle WiFi connection. // Task handle WiFi connection.
xTaskCreate( xTaskCreate(
[](void *obj) { [](void *obj) {
AgWiFiConnector *connector = (AgWiFiConnector *)obj; WifiConnector *connector = (WifiConnector *)obj;
while (connector->_wifiConfigPortalActive()) { while (connector->_wifiConfigPortalActive()) {
connector->_wifiProcess(); connector->_wifiProcess();
} }
@ -81,7 +86,7 @@ bool AgWiFiConnector::connect(void) {
if (WiFi.isConnected() == false) { if (WiFi.isConnected() == false) {
/** Display countdown */ /** Display countdown */
uint32_t ms; uint32_t ms;
if (ag->isOneIndoor()) { if (ag->isOne()) {
ms = (uint32_t)(millis() - dispPeriod); ms = (uint32_t)(millis() - dispPeriod);
if (ms >= 1000) { if (ms >= 1000) {
dispPeriod = millis(); dispPeriod = millis();
@ -98,7 +103,7 @@ bool AgWiFiConnector::connect(void) {
ms = (uint32_t)(millis() - ledPeriod); ms = (uint32_t)(millis() - ledPeriod);
if (ms >= 100) { if (ms >= 100) {
ledPeriod = millis(); ledPeriod = millis();
sm.ledHandle(); sm.handleLeds();
} }
/** Check for client connect to change led color */ /** Check for client connect to change led color */
@ -106,11 +111,11 @@ bool AgWiFiConnector::connect(void) {
if (clientConnected != clientConnectChanged) { if (clientConnected != clientConnectChanged) {
clientConnectChanged = clientConnected; clientConnectChanged = clientConnected;
if (clientConnectChanged) { if (clientConnectChanged) {
sm.ledHandle(AgStateMachineWiFiManagerPortalActive); sm.handleLeds(AgStateMachineWiFiManagerPortalActive);
} else { } else {
sm.ledAnimationInit(); sm.ledAnimationInit();
sm.ledHandle(AgStateMachineWiFiManagerMode); sm.handleLeds(AgStateMachineWiFiManagerMode);
if (ag->isOneIndoor()) { if (ag->isOne()) {
sm.displayHandle(AgStateMachineWiFiManagerMode); sm.displayHandle(AgStateMachineWiFiManagerMode);
} }
} }
@ -121,15 +126,18 @@ bool AgWiFiConnector::connect(void) {
} }
/** Show display wifi connect result failed */ /** Show display wifi connect result failed */
if (WiFi.isConnected() == false) { if (WiFi.isConnected() == false) {
sm.ledHandle(AgStateMachineWiFiManagerConnectFailed); sm.handleLeds(AgStateMachineWiFiManagerConnectFailed);
if (ag->isOneIndoor()) { if (ag->isOne()) {
sm.displayHandle(AgStateMachineWiFiManagerConnectFailed); sm.displayHandle(AgStateMachineWiFiManagerConnectFailed);
} }
delay(6000); delay(6000);
} else { } else {
hasConfig = true; hasConfig = true;
logInfo("WiFi Connected: " + WiFi.SSID() + " IP: " + localIpStr());
} }
#else
_wifiProcess();
#endif
return true; return true;
} }
@ -137,50 +145,69 @@ bool AgWiFiConnector::connect(void) {
* @brief Disconnect to current connected WiFi AP * @brief Disconnect to current connected WiFi AP
* *
*/ */
void AgWiFiConnector::disconnect(void) { void WifiConnector::disconnect(void) {
if (WiFi.isConnected()) { if (WiFi.isConnected()) {
logInfo("Disconnect"); logInfo("Disconnect");
WiFi.disconnect(); WiFi.disconnect();
} }
} }
#ifdef ESP32
#else
void WifiConnector::displayShowText(String ln1, String ln2, String ln3) {
char buf[9];
ag->display.clear();
ag->display.setCursor(1, 1);
ag->display.setText(ln1);
ag->display.setCursor(1, 19);
ag->display.setText(ln2);
ag->display.setCursor(1, 37);
ag->display.setText(ln3);
ag->display.show();
delay(100);
}
#endif
/** /**
* @brief Has wifi STA connected to WIFI softAP (this device) * @brief Has wifi STA connected to WIFI softAP (this device)
* *
* @return true Connected * @return true Connected
* @return false Not connected * @return false Not connected
*/ */
bool AgWiFiConnector::wifiClientConnected(void) { bool WifiConnector::wifiClientConnected(void) {
return WiFi.softAPgetStationNum() ? true : false; return WiFi.softAPgetStationNum() ? true : false;
} }
#ifdef ESP32
/** /**
* @brief Handle WiFiManage softAP setup completed callback * @brief Handle WiFiManage softAP setup completed callback
* *
*/ */
void AgWiFiConnector::_wifiApCallback(void) { void WifiConnector::_wifiApCallback(void) {
sm.displayWiFiConnectCountDown(WIFI_CONNECT_COUNTDOWN_MAX); sm.displayWiFiConnectCountDown(WIFI_CONNECT_COUNTDOWN_MAX);
sm.setDisplayState(AgStateMachineWiFiManagerMode); sm.setDisplayState(AgStateMachineWiFiManagerMode);
sm.ledAnimationInit(); sm.ledAnimationInit();
sm.ledHandle(AgStateMachineWiFiManagerMode); sm.handleLeds(AgStateMachineWiFiManagerMode);
} }
/** /**
* @brief Handle WiFiManager save configuration callback * @brief Handle WiFiManager save configuration callback
* *
*/ */
void AgWiFiConnector::_wifiSaveConfig(void) { void WifiConnector::_wifiSaveConfig(void) {
sm.setDisplayState(AgStateMachineWiFiManagerStaConnected); sm.setDisplayState(AgStateMachineWiFiManagerStaConnected);
sm.ledHandle(AgStateMachineWiFiManagerStaConnected); sm.handleLeds(AgStateMachineWiFiManagerStaConnected);
} }
/** /**
* @brief Handle WiFiManager save parameter callback * @brief Handle WiFiManager save parameter callback
* *
*/ */
void AgWiFiConnector::_wifiSaveParamCallback(void) { void WifiConnector::_wifiSaveParamCallback(void) {
sm.ledAnimationInit(); sm.ledAnimationInit();
sm.ledHandle(AgStateMachineWiFiManagerStaConnecting); sm.handleLeds(AgStateMachineWiFiManagerStaConnecting);
sm.setDisplayState(AgStateMachineWiFiManagerStaConnecting); sm.setDisplayState(AgStateMachineWiFiManagerStaConnecting);
} }
@ -190,21 +217,52 @@ void AgWiFiConnector::_wifiSaveParamCallback(void) {
* @return true Active * @return true Active
* @return false Not-Active * @return false Not-Active
*/ */
bool AgWiFiConnector::_wifiConfigPortalActive(void) { bool WifiConnector::_wifiConfigPortalActive(void) {
return WIFI()->getConfigPortalActive(); return WIFI()->getConfigPortalActive();
} }
#endif
/** /**
* @brief Process WiFiManager connection * @brief Process WiFiManager connection
* *
*/ */
void AgWiFiConnector::_wifiProcess() { WIFI()->process(); } void WifiConnector::_wifiProcess() {
#ifdef ESP32
WIFI()->process();
#else
int count = WIFI_CONNECT_COUNTDOWN_MAX;
displayShowText(String(WIFI_CONNECT_COUNTDOWN_MAX) + " sec", "SSID:", ssid);
while (WIFI()->getConfigPortalActive()) {
WIFI()->process();
uint32_t lastTime = millis();
uint32_t ms = (uint32_t)(millis() - lastTime);
if (ms >= 1000) {
lastTime = millis();
displayShowText(String(count) + " sec", "SSID:", ssid);
count--;
// Timeout
if (count == 0) {
break;
}
}
}
if (!WiFi.isConnected()) {
displayShowText("Booting", "offline", "mode");
Serial.println("failed to connect and hit timeout");
delay(2500);
}
#endif
}
/** /**
* @brief Handle and reconnect WiFi * @brief Handle and reconnect WiFi
* *
*/ */
void AgWiFiConnector::handle(void) { void WifiConnector::handle(void) {
// Ignore if WiFi is not configured // Ignore if WiFi is not configured
if (hasConfig == false) { if (hasConfig == false) {
return; return;
@ -232,27 +290,25 @@ void AgWiFiConnector::handle(void) {
* @return true Connected * @return true Connected
* @return false Disconnected * @return false Disconnected
*/ */
bool AgWiFiConnector::isConnected(void) { return WiFi.isConnected(); } bool WifiConnector::isConnected(void) { return WiFi.isConnected(); }
/** /**
* @brief Reset WiFi configuretion and connection, disconnect wifi before call * @brief Reset WiFi configuretion and connection, disconnect wifi before call
* this method * this method
* *
*/ */
void AgWiFiConnector::reset(void) { WIFI()->resetSettings(); } void WifiConnector::reset(void) { WIFI()->resetSettings(); }
/** /**
* @brief Get wifi RSSI * @brief Get wifi RSSI
* *
* @return int * @return int
*/ */
int AgWiFiConnector::RSSI(void) { return WiFi.RSSI(); } int WifiConnector::RSSI(void) { return WiFi.RSSI(); }
/** /**
* @brief Get WIFI IP as string format ex: 192.168.1.1 * @brief Get WIFI IP as string format ex: 192.168.1.1
* *
* @return String * @return String
*/ */
String AgWiFiConnector::localIpStr(void) { return WiFi.localIP().toString(); } String WifiConnector::localIpStr(void) { return WiFi.localIP().toString(); }
#endif

View File

@ -1,5 +1,3 @@
#ifdef ESP32
#ifndef _AG_WIFI_CONNECTOR_H_ #ifndef _AG_WIFI_CONNECTOR_H_
#define _AG_WIFI_CONNECTOR_H_ #define _AG_WIFI_CONNECTOR_H_
@ -10,11 +8,15 @@
#include <Arduino.h> #include <Arduino.h>
class AgWiFiConnector : public PrintLog { class WifiConnector : public PrintLog {
private: private:
AirGradient *ag; AirGradient *ag;
AgOledDisplay &disp; #ifdef ESP32
AgStateMachine &sm; OledDisplay &disp;
StateMachine &sm;
#else
void displayShowText(String ln1, String ln2, String ln3);
#endif
String ssid; String ssid;
void *wifi = NULL; void *wifi = NULL;
bool hasConfig; bool hasConfig;
@ -23,17 +25,23 @@ private:
bool wifiClientConnected(void); bool wifiClientConnected(void);
public: public:
AgWiFiConnector(AgOledDisplay &disp, Stream &log, AgStateMachine &sm);
~AgWiFiConnector();
void setAirGradient(AirGradient *ag); void setAirGradient(AirGradient *ag);
#ifdef ESP32
WifiConnector(OledDisplay &disp, Stream &log, StateMachine &sm);
#else
WifiConnector(Stream &log);
#endif
~WifiConnector();
bool connect(void); bool connect(void);
void disconnect(void); void disconnect(void);
void handle(void); void handle(void);
#ifdef ESP32
void _wifiApCallback(void); void _wifiApCallback(void);
void _wifiSaveConfig(void); void _wifiSaveConfig(void);
void _wifiSaveParamCallback(void); void _wifiSaveParamCallback(void);
bool _wifiConfigPortalActive(void); bool _wifiConfigPortalActive(void);
#endif
void _wifiProcess(); void _wifiProcess();
bool isConnected(void); bool isConnected(void);
void reset(void); void reset(void);
@ -42,6 +50,3 @@ public:
}; };
#endif /** _AG_WIFI_CONNECTOR_H_ */ #endif /** _AG_WIFI_CONNECTOR_H_ */
#endif

View File

@ -50,7 +50,13 @@ String AirGradient::getBoardName(void) {
return String(getBoardDefName(boardType)); return String(getBoardDefName(boardType));
} }
bool AirGradient::isOneIndoor(void) { /**
* @brief Board Type is ONE_INDOOR
*
* @return true ONE_INDOOR
* @return false Other
*/
bool AirGradient::isOne(void) {
return boardType == BoardType::ONE_INDOOR; return boardType == BoardType::ONE_INDOOR;
} }

View File

@ -128,7 +128,7 @@ public:
* @return true Yes * @return true Yes
* @return false No * @return false No
*/ */
bool isOneIndoor(void); bool isOne(void);
/** /**
* @brief Get device Id * @brief Get device Id

View File

@ -54,6 +54,14 @@ enum AgStateMachineState {
the server side */ the server side */
AgStateMachineSensorConfigFailed, AgStateMachineSensorConfigFailed,
/** CO2 calibration */
AgStateMachineCo2Calibration,
/* LED bar testing */
AgStateMachineLedBarTest,
/** LED: Show working state.
* Display: Show dashboard */
AgStateMachineNormal, AgStateMachineNormal,
}; };