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:
“WifiManager by tzapu, tablatronix” tested with version 2.0.16-rc.2
"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
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 "AgConfigure.h"
#include "AgSchedule.h"
#include "AgWiFiConnector.h"
#include <AirGradient.h>
#include <Arduino_JSON.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiManager.h>
#define WIFI_CONNECT_COUNTDOWN_MAX 180 /** sec */
#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 */
static AirGradient ag = AirGradient(DIY_BASIC);
static AgConfigure localConfig(Serial);
static AgApiClient apiClient(Serial, localConfig);
static Configuration configuration(Serial);
static AgApiClient apiClient(Serial, configuration);
static WifiConnector wifiConnector(Serial);
static int co2Ppm = -1;
static int pm25 = -1;
static float temp = -1001;
static int hum = -1;
static long val;
static String wifiSSID = "";
static bool wifiHasConfig = false; /** */
static void boardInit(void);
static void failedHandler(String msg);
static void co2Calibration(void);
static void executeCo2Calibration(void);
static void updateServerConfiguration(void);
static void co2Update(void);
static void pmUpdate(void);
@ -82,7 +80,6 @@ static void tempHumUpdate(void);
static void sendDataToServer(void);
static void dispHandler(void);
static String getDevId(void);
static void updateWiFiConnect(void);
static void showNr(void);
bool hasSensorS8 = true;
@ -112,23 +109,24 @@ void setup() {
/** Init AirGradient server */
apiClient.begin();
apiClient.setAirGradient(&ag);
wifiConnector.setAirGradient(&ag);
/** Show boot display */
displayShowText("DIY basic", "Lib:" + ag.getVersion(), "");
delay(2000);
/** WiFi connect */
connectToWifi();
// connectToWifi();
if (wifiConnector.connect()) {
if (WiFi.status() == WL_CONNECTED) {
wifiHasConfig = true;
sendPing();
sendDataToAg();
apiClient.fetchServerConfiguration();
if (localConfig.isCo2CalibrationRequested()) {
co2Calibration();
if (configuration.isCo2CalibrationRequested()) {
executeCo2Calibration();
}
}
}
/** Show serial number display */
ag.display.clear();
ag.display.setCursor(1, 1);
@ -162,13 +160,13 @@ void loop() {
tempHumSchedule.run();
}
updateWiFiConnect();
wifiConnector.handle();
/** Read PMS on loop */
ag.pms5003.handle();
}
static void sendPing() {
static void sendDataToAg() {
JSONVar root;
root["wifi"] = WiFi.RSSI();
root["boot"] = 0;
@ -197,39 +195,6 @@ void displayShowText(String ln1, String ln2, String ln3) {
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) {
/** Init SHT sensor */
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 */
for (int i = 0; i < SENSOR_CO2_CALIB_COUNTDOWN_MAX; i++) {
displayShowText("CO2 calib", "after",
@ -291,25 +256,25 @@ static void co2Calibration(void) {
static void updateServerConfiguration(void) {
if (apiClient.fetchServerConfiguration()) {
if (localConfig.isCo2CalibrationRequested()) {
if (configuration.isCo2CalibrationRequested()) {
if (hasSensorS8) {
co2Calibration();
executeCo2Calibration();
} else {
Serial.println("CO2 S8 not available, calib ignored");
}
}
if (localConfig.getCO2CalirationAbcDays() > 0) {
if (configuration.getCO2CalibrationAbcDays() > 0) {
if (hasSensorS8) {
int newHour = localConfig.getCO2CalirationAbcDays() * 24;
int newHour = configuration.getCO2CalibrationAbcDays() * 24;
Serial.printf("abcDays config: %d days(%d hours)\r\n",
localConfig.getCO2CalirationAbcDays(), newHour);
configuration.getCO2CalibrationAbcDays(), newHour);
int curHour = ag.s8.getAbcPeriod();
Serial.printf("Current config: %d (hours)\r\n", curHour);
if (curHour == newHour) {
Serial.println("set 'abcDays' ignored");
} else {
if (ag.s8.setAbcPeriod(localConfig.getCO2CalirationAbcDays() * 24) ==
false) {
if (ag.s8.setAbcPeriod(configuration.getCO2CalibrationAbcDays() *
24) == false) {
Serial.println("Set S8 abcDays period calib failed");
} else {
Serial.println("Set S8 abcDays period calib success");
@ -388,7 +353,7 @@ static void dispHandler() {
String ln2 = "";
String ln3 = "";
if (localConfig.isPmStandardInUSAQI()) {
if (configuration.isPmStandardInUSAQI()) {
if (pm25 < 0) {
ln1 = "AQI: -";
} else {
@ -415,7 +380,7 @@ static void dispHandler() {
String _temp = "-";
if (localConfig.isTemperatureUnitInF()) {
if (configuration.isTemperatureUnitInF()) {
if (temp > -1001) {
_temp = String((temp * 9 / 5) + 32).substring(0, 4);
}
@ -431,27 +396,6 @@ static void dispHandler() {
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) {
Serial.println();
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>
#endif
AgApiClient::AgApiClient(Stream &debug, AgConfigure &config)
AgApiClient::AgApiClient(Stream &debug, Configuration &config)
: PrintLog(debug, "ApiClient"), config(config) {}
AgApiClient::~AgApiClient() {}

View File

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

View File

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

View File

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

View File

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

View File

@ -5,6 +5,8 @@
#define LED_SHORT_BLINK_DELAY 500 /** ms */
#define LED_LONG_BLINK_DELAY 2000 /** ms */
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
/**
* @brief Animation LED bar with color
*
@ -12,7 +14,7 @@
* @param g
* @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) {
ledBarAnimationCount = 0;
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
*/
void AgStateMachine::ledStatusBlinkDelay(uint32_t ms) {
void StateMachine::ledStatusBlinkDelay(uint32_t ms) {
ag->statusLed.setOn();
delay(ms);
ag->statusLed.setOff();
@ -41,13 +43,13 @@ void AgStateMachine::ledStatusBlinkDelay(uint32_t ms) {
* @brief Led bar show led color status
*
*/
void AgStateMachine::sensorLedHandle(void) {
void StateMachine::sensorhandleLeds(void) {
switch (config.getLedBarMode()) {
case LedBarMode::LedBarModeCO2:
co2LedHandle();
co2handleLeds();
break;
case LedBarMode::LedBarModePm:
pm25LedHandle();
pm25handleLeds();
break;
default:
ag->ledBar.clear();
@ -59,7 +61,7 @@ void AgStateMachine::sensorLedHandle(void) {
* @brief Show CO2 LED status
*
*/
void AgStateMachine::co2LedHandle(void) {
void StateMachine::co2handleLeds(void) {
int co2Value = value.CO2;
if (co2Value <= 400) {
/** G; 1 */
@ -142,8 +144,8 @@ void AgStateMachine::co2LedHandle(void) {
* @brief Show PM2.5 LED status
*
*/
void AgStateMachine::pm25LedHandle(void) {
int pm25Value = value.PM25;
void StateMachine::pm25handleLeds(void) {
int pm25Value = value.pm25_1;
if (pm25Value <= 5) {
/** G; 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
*
* @param disp AgOledDisplay
* @param disp OledDisplay
* @param log Serial Stream
* @param value AgValue
* @param config AgConfigure
* @param value Measurements
* @param config Configuration
*/
AgStateMachine::AgStateMachine(AgOledDisplay &disp, Stream &log, AgValue &value,
AgConfigure &config)
: PrintLog(log, "AgStateMachine"), disp(disp), value(value),
config(config) {}
StateMachine::StateMachine(OledDisplay &disp, Stream &log, Measurements &value,
Configuration &config)
: PrintLog(log, "StateMachine"), disp(disp), value(value), config(config) {}
AgStateMachine::~AgStateMachine() {}
StateMachine::~StateMachine() {}
/**
* @brief OLED display show content from state value
*
* @param state
*/
void AgStateMachine::displayHandle(AgStateMachineState state) {
void StateMachine::displayHandle(AgStateMachineState state) {
// Ignore handle if not ONE_INDOOR board
if (!ag->isOneIndoor()) {
if (!ag->isOne()) {
return;
}
@ -320,6 +475,9 @@ void AgStateMachine::displayHandle(AgStateMachineState state) {
disp.showDashboard();
break;
}
case AgStateMachineCo2Calibration:
co2Calibration();
break;
default:
break;
}
@ -329,27 +487,25 @@ void AgStateMachine::displayHandle(AgStateMachineState state) {
* @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
*
*/
void AgStateMachine::displaySetAddToDashBoard(void) {
void StateMachine::displaySetAddToDashBoard(void) {
addToDashBoard = true;
addToDashboardTime = millis();
}
void AgStateMachine::displayClearAddToDashBoard(void) {
addToDashBoard = false;
}
void StateMachine::displayClearAddToDashBoard(void) { addToDashBoard = false; }
/**
* @brief Set WiFi connection coundown on dashboard
*
* @param count Seconds
*/
void AgStateMachine::displayWiFiConnectCountDown(int count) {
void StateMachine::displayWiFiConnectCountDown(int count) {
wifiConnectCountDown = count;
}
@ -357,21 +513,21 @@ void AgStateMachine::displayWiFiConnectCountDown(int count) {
* @brief Init before start LED bar animation
*
*/
void AgStateMachine::ledAnimationInit(void) { ledBarAnimationCount = -1; }
void StateMachine::ledAnimationInit(void) { ledBarAnimationCount = -1; }
/**
* @brief Handle LED from state
*
* @param state
*/
void AgStateMachine::ledHandle(AgStateMachineState state) {
void StateMachine::handleLeds(AgStateMachineState state) {
if (state > AgStateMachineNormal) {
logError("ledHandle: state invalid");
return;
}
ledState = state;
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.clear(); // Set all LED OFF
}
switch (state) {
@ -379,7 +535,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
/** In WiFi Manager Mode */
/** Turn LED OFF */
/** Turn midle LED Color */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(0, 0, 255, ag->ledBar.getNumberOfLeds() / 2);
} else {
ag->statusLed.setToggle();
@ -388,7 +544,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
}
case AgStateMachineWiFiManagerPortalActive: {
/** WiFi Manager has connected to mobile phone */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(0, 0, 255);
} else {
ag->statusLed.setOn();
@ -398,7 +554,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineWiFiManagerStaConnecting: {
/** after SSID and PW entered and OK clicked, connection to WiFI network is
* attempted */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ledBarSingleLedAnimation(255, 255, 255);
} else {
ag->statusLed.setOff();
@ -407,7 +563,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
}
case AgStateMachineWiFiManagerStaConnected: {
/** Connecting to WiFi worked */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(255, 255, 255);
} else {
ag->statusLed.setOff();
@ -416,7 +572,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
}
case AgStateMachineWiFiOkServerConnecting: {
/** once connected to WiFi an attempt to reach the server is performed */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ledBarSingleLedAnimation(0, 255, 0);
} else {
ag->statusLed.setOff();
@ -425,7 +581,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
}
case AgStateMachineWiFiOkServerConnected: {
/** Server is reachable, all fine */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(0, 255, 0);
} else {
ag->statusLed.setOff();
@ -441,7 +597,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
}
case AgStateMachineWiFiManagerConnectFailed: {
/** Cannot connect to WiFi (e.g. wrong password, WPA Enterprise etc.) */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(255, 0, 0);
} else {
ag->statusLed.setOff();
@ -459,7 +615,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineWiFiOkServerConnectFailed: {
/** Connected to WiFi but server not reachable, e.g. firewall block/
* whitelisting needed etc. */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(233, 183, 54); /** orange */
} else {
ag->statusLed.setOff();
@ -475,7 +631,7 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
}
case AgStateMachineWiFiOkServerOkSensorConfigFailed: {
/** Server reachable but sensor not configured correctly */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(139, 24, 248); /** violet */
} else {
ag->statusLed.setOff();
@ -492,12 +648,12 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineWiFiLost: {
/** Connection to WiFi network failed credentials incorrect encryption not
* supported etc. */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
/** WIFI failed status LED color */
ag->ledBar.setColor(255, 0, 0, 0);
/** Show CO2 or PM color status */
// sensorLedColorHandler();
sensorLedHandle();
sensorhandleLeds();
} else {
ag->statusLed.setOff();
}
@ -506,11 +662,11 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineServerLost: {
/** Connected to WiFi network but the server cannot be reached through the
* internet, e.g. blocked by firewall */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(233, 183, 54, 0);
/** Show CO2 or PM color status */
sensorLedHandle();
sensorhandleLeds();
// sensorLedColorHandler();
} else {
ag->statusLed.setOff();
@ -520,30 +676,33 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
case AgStateMachineSensorConfigFailed: {
/** Server is reachable but there is some configuration issue to be fixed on
* the server side */
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.setColor(139, 24, 248, 0);
/** Show CO2 or PM color status */
sensorLedHandle();
sensorhandleLeds();
} else {
ag->statusLed.setOff();
}
break;
}
case AgStateMachineNormal: {
if (ag->isOneIndoor()) {
sensorLedHandle();
if (ag->isOne()) {
sensorhandleLeds();
} else {
ag->statusLed.setOff();
}
break;
}
case AgStateMachineLedBarTest:
ledBarTest();
break;
default:
break;
}
// Show LED bar color
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ag->ledBar.show();
}
}
@ -552,14 +711,14 @@ void AgStateMachine::ledHandle(AgStateMachineState state) {
* @brief Handle LED as previous state updated
*
*/
void AgStateMachine::ledHandle(void) { ledHandle(ledState); }
void StateMachine::handleLeds(void) { handleLeds(ledState); }
/**
* @brief Set display state
*
* @param state
*/
void AgStateMachine::setDisplayState(AgStateMachineState state) {
void StateMachine::setDisplayState(AgStateMachineState state) {
dispState = state;
}
@ -568,18 +727,26 @@ void AgStateMachine::setDisplayState(AgStateMachineState state) {
*
* @return AgStateMachineState
*/
AgStateMachineState AgStateMachine::getDisplayState(void) { return dispState; }
AgStateMachineState StateMachine::getDisplayState(void) { return dispState; }
/**
* @brief Set 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
*
* @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 "App/AppDef.h"
class AgStateMachine : public PrintLog {
class StateMachine : public PrintLog {
private:
// AgStateMachineState state;
AgStateMachineState ledState;
AgStateMachineState dispState;
AirGradient *ag;
AgOledDisplay &disp;
AgValue &value;
AgConfigure &config;
OledDisplay &disp;
Measurements &value;
Configuration &config;
bool addToDashBoard = false;
uint32_t addToDashboardTime;
@ -24,14 +24,18 @@ private:
void ledBarSingleLedAnimation(uint8_t r, uint8_t g, uint8_t b);
void ledStatusBlinkDelay(uint32_t delay);
void sensorLedHandle(void);
void co2LedHandle(void);
void pm25LedHandle(void);
void sensorhandleLeds(void);
void co2handleLeds(void);
void pm25handleLeds(void);
void co2Calibration(void);
void ledBarTest(void);
void ledBarRunTest(void);
void runLedTest(char color);
public:
AgStateMachine(AgOledDisplay &disp, Stream &log,
AgValue &value, AgConfigure& config);
~AgStateMachine();
StateMachine(OledDisplay &disp, Stream &log,
Measurements &value, Configuration& config);
~StateMachine();
void setAirGradient(AirGradient* ag);
void displayHandle(AgStateMachineState state);
void displayHandle(void);
@ -39,11 +43,13 @@ public:
void displayClearAddToDashBoard(void);
void displayWiFiConnectCountDown(int count);
void ledAnimationInit(void);
void ledHandle(AgStateMachineState state);
void ledHandle(void);
void handleLeds(AgStateMachineState state);
void handleLeds(void);
void setDisplayState(AgStateMachineState state);
AgStateMachineState getDisplayState(void);
AgStateMachineState getLedState(void);
void executeCo2Calibration(void);
void executeLedBarTest(void);
};
#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_
#define _AG_VALUE_H_
class AgValue {
#include <Arduino.h>
#include "App/AppDef.h"
class Measurements {
private:
public:
AgValue() {}
~AgValue() {}
Measurements() {
pm25_1 = -1;
pm01_1 = -1;
pm10_1 = -1;
pm03PCount_1 = -1;
temp_1 = -1001;
hum_1 = -1;
float Temperature = -1001;
int Humidity = -1;
int CO2 = -1;
int PM25 = -1;
int TVOC = -1;
int TVOCRaw = -1;
int NOx = -1;
int NOxRaw = -1;
pm25_2 = -1;
pm01_2 = -1;
pm10_2 = -1;
pm03PCount_2 = -1;
temp_2 = -1001;
hum_2 = -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_ */

View File

@ -1,5 +1,3 @@
#ifdef ESP32
#include "AgWiFiConnector.h"
#include "Libraries/WiFiManager/WiFiManager.h"
@ -8,25 +6,28 @@
#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
*
* @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
@ -34,7 +35,7 @@ void AgWiFiConnector::setAirGradient(AirGradient *ag) { this->ag = ag; }
* @return true Success
* @return false Failure
*/
bool AgWiFiConnector::connect(void) {
bool WifiConnector::connect(void) {
if (wifi == NULL) {
wifi = new WiFiManager();
if (wifi == NULL) {
@ -46,23 +47,27 @@ bool AgWiFiConnector::connect(void) {
WIFI()->setConfigPortalBlocking(false);
WIFI()->setTimeout(WIFI_CONNECT_COUNTDOWN_MAX);
#ifdef ESP32
WIFI()->setAPCallback([this](WiFiManager *obj) { _wifiApCallback(); });
WIFI()->setSaveConfigCallback([this]() { _wifiSaveConfig(); });
WIFI()->setSaveParamsCallback([this]() { _wifiSaveParamCallback(); });
if (ag->isOneIndoor()) {
if (ag->isOne()) {
disp.setText("Connecting to", "WiFi", "...");
} else {
logInfo("Connecting to WiFi...");
}
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);
#ifdef ESP32
// Task handle WiFi connection.
xTaskCreate(
[](void *obj) {
AgWiFiConnector *connector = (AgWiFiConnector *)obj;
WifiConnector *connector = (WifiConnector *)obj;
while (connector->_wifiConfigPortalActive()) {
connector->_wifiProcess();
}
@ -81,7 +86,7 @@ bool AgWiFiConnector::connect(void) {
if (WiFi.isConnected() == false) {
/** Display countdown */
uint32_t ms;
if (ag->isOneIndoor()) {
if (ag->isOne()) {
ms = (uint32_t)(millis() - dispPeriod);
if (ms >= 1000) {
dispPeriod = millis();
@ -98,7 +103,7 @@ bool AgWiFiConnector::connect(void) {
ms = (uint32_t)(millis() - ledPeriod);
if (ms >= 100) {
ledPeriod = millis();
sm.ledHandle();
sm.handleLeds();
}
/** Check for client connect to change led color */
@ -106,11 +111,11 @@ bool AgWiFiConnector::connect(void) {
if (clientConnected != clientConnectChanged) {
clientConnectChanged = clientConnected;
if (clientConnectChanged) {
sm.ledHandle(AgStateMachineWiFiManagerPortalActive);
sm.handleLeds(AgStateMachineWiFiManagerPortalActive);
} else {
sm.ledAnimationInit();
sm.ledHandle(AgStateMachineWiFiManagerMode);
if (ag->isOneIndoor()) {
sm.handleLeds(AgStateMachineWiFiManagerMode);
if (ag->isOne()) {
sm.displayHandle(AgStateMachineWiFiManagerMode);
}
}
@ -121,15 +126,18 @@ bool AgWiFiConnector::connect(void) {
}
/** Show display wifi connect result failed */
if (WiFi.isConnected() == false) {
sm.ledHandle(AgStateMachineWiFiManagerConnectFailed);
if (ag->isOneIndoor()) {
sm.handleLeds(AgStateMachineWiFiManagerConnectFailed);
if (ag->isOne()) {
sm.displayHandle(AgStateMachineWiFiManagerConnectFailed);
}
delay(6000);
} else {
hasConfig = true;
logInfo("WiFi Connected: " + WiFi.SSID() + " IP: " + localIpStr());
}
#else
_wifiProcess();
#endif
return true;
}
@ -137,50 +145,69 @@ bool AgWiFiConnector::connect(void) {
* @brief Disconnect to current connected WiFi AP
*
*/
void AgWiFiConnector::disconnect(void) {
void WifiConnector::disconnect(void) {
if (WiFi.isConnected()) {
logInfo("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)
*
* @return true Connected
* @return false Not connected
*/
bool AgWiFiConnector::wifiClientConnected(void) {
bool WifiConnector::wifiClientConnected(void) {
return WiFi.softAPgetStationNum() ? true : false;
}
#ifdef ESP32
/**
* @brief Handle WiFiManage softAP setup completed callback
*
*/
void AgWiFiConnector::_wifiApCallback(void) {
void WifiConnector::_wifiApCallback(void) {
sm.displayWiFiConnectCountDown(WIFI_CONNECT_COUNTDOWN_MAX);
sm.setDisplayState(AgStateMachineWiFiManagerMode);
sm.ledAnimationInit();
sm.ledHandle(AgStateMachineWiFiManagerMode);
sm.handleLeds(AgStateMachineWiFiManagerMode);
}
/**
* @brief Handle WiFiManager save configuration callback
*
*/
void AgWiFiConnector::_wifiSaveConfig(void) {
void WifiConnector::_wifiSaveConfig(void) {
sm.setDisplayState(AgStateMachineWiFiManagerStaConnected);
sm.ledHandle(AgStateMachineWiFiManagerStaConnected);
sm.handleLeds(AgStateMachineWiFiManagerStaConnected);
}
/**
* @brief Handle WiFiManager save parameter callback
*
*/
void AgWiFiConnector::_wifiSaveParamCallback(void) {
void WifiConnector::_wifiSaveParamCallback(void) {
sm.ledAnimationInit();
sm.ledHandle(AgStateMachineWiFiManagerStaConnecting);
sm.handleLeds(AgStateMachineWiFiManagerStaConnecting);
sm.setDisplayState(AgStateMachineWiFiManagerStaConnecting);
}
@ -190,21 +217,52 @@ void AgWiFiConnector::_wifiSaveParamCallback(void) {
* @return true Active
* @return false Not-Active
*/
bool AgWiFiConnector::_wifiConfigPortalActive(void) {
bool WifiConnector::_wifiConfigPortalActive(void) {
return WIFI()->getConfigPortalActive();
}
#endif
/**
* @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
*
*/
void AgWiFiConnector::handle(void) {
void WifiConnector::handle(void) {
// Ignore if WiFi is not configured
if (hasConfig == false) {
return;
@ -232,27 +290,25 @@ void AgWiFiConnector::handle(void) {
* @return true Connected
* @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
* this method
*
*/
void AgWiFiConnector::reset(void) { WIFI()->resetSettings(); }
void WifiConnector::reset(void) { WIFI()->resetSettings(); }
/**
* @brief Get wifi RSSI
*
* @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
*
* @return String
*/
String AgWiFiConnector::localIpStr(void) { return WiFi.localIP().toString(); }
#endif
String WifiConnector::localIpStr(void) { return WiFi.localIP().toString(); }

View File

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

View File

@ -50,7 +50,13 @@ String AirGradient::getBoardName(void) {
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;
}

View File

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

View File

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