mirror of
https://github.com/airgradienthq/arduino.git
synced 2025-06-26 08:11:33 +02:00
Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
d78205aa20 | |||
c1228bbd06 | |||
1eb43f684b | |||
4798e44cb7 | |||
a867e9af38 | |||
a59d5a1bb8 | |||
b4d6006678 | |||
236c5bab84 | |||
852fdc4360 | |||
f7e85a92e8 | |||
e99fc2ecdc | |||
67785ed99b | |||
45ac4f116b | |||
173e3caf2f | |||
351af57591 | |||
0bda7a1c4b | |||
9a31c107fa | |||
5449fa15ea | |||
3e4e2affa8 | |||
d3a242a0b7 | |||
e5e2887c4d | |||
4eda2e4cb5 | |||
fcee721d58 | |||
7d12e63e34 | |||
8ff8b7929e | |||
66c53daed6 | |||
5de3a34dd0 | |||
b94112e22a | |||
99e925e7bd | |||
d8cba0d346 | |||
39de897621 | |||
9f1a793848 | |||
be9ba88d52 | |||
0084b6fb91 | |||
75b579bafa | |||
cf5ff99d8a | |||
ea204d90b1 | |||
13f6c2c747 | |||
760f827d0d | |||
8c8e0d4dea | |||
b749495bf4 | |||
7e3eabf09f | |||
e636876c9b | |||
68953d7390 |
51
.github/workflows/check.yml
vendored
Normal file
51
.github/workflows/check.yml
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
compile:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
example:
|
||||
- "BASIC"
|
||||
- "ONE"
|
||||
- "Open_Air"
|
||||
- "TestCO2"
|
||||
- "TestPM"
|
||||
- "TestSht"
|
||||
fqbn:
|
||||
- "esp8266:esp8266:d1_mini"
|
||||
- "esp32:esp32:esp32c3"
|
||||
include:
|
||||
- fqbn: "esp8266:esp8266:d1_mini"
|
||||
core: "esp8266:esp8266@3.1.2"
|
||||
core_url: "https://arduino.esp8266.com/stable/package_esp8266com_index.json"
|
||||
- fqbn: "esp32:esp32:esp32c3"
|
||||
board_options: "JTAGAdapter=default,CDCOnBoot=cdc,PartitionScheme=default,CPUFreq=160,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=verbose,EraseFlash=none"
|
||||
core: "esp32:esp32@2.0.11"
|
||||
exclude:
|
||||
- example: "BASIC_v4"
|
||||
fqbn: "esp32:esp32:esp32c3"
|
||||
- example: "ONE_I-9PSL"
|
||||
fqbn: "esp8266:esp8266:d1_mini"
|
||||
- example: "Open_Air"
|
||||
fqbn: "esp8266:esp8266:d1_mini"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run:
|
||||
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh |
|
||||
sh -s 0.35.3
|
||||
- run: bin/arduino-cli --verbose core install '${{ matrix.core }}'
|
||||
--additional-urls '${{ matrix.core_url }}'
|
||||
- run: bin/arduino-cli --verbose lib install
|
||||
WiFiManager@2.0.16-rc.2
|
||||
Arduino_JSON@0.2.0
|
||||
U8g2@2.34.22
|
||||
- run: bin/arduino-cli --verbose lib install --git-url .
|
||||
env:
|
||||
ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL: "true"
|
||||
- run: bin/arduino-cli --verbose compile 'examples/${{ matrix.example }}'
|
||||
--fqbn '${{ matrix.fqbn }}' --board-options '${{ matrix.board_options }}'
|
||||
# TODO: at this point it would be a good idea to run some smoke tests on
|
||||
# the resulting image (e.g. that it boots successfully and sends metrics)
|
||||
# but that would either require a high fidelity device emulator, or a
|
||||
# "hardware lab" runner that is directly connected to a relevant device.
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
.vscode
|
||||
*.DS_Store
|
||||
build
|
||||
.vscode
|
||||
|
@ -50,7 +50,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
|
||||
#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SENSOR_PM_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 2000 /** ms */
|
||||
#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
|
||||
#define WIFI_HOTSPOT_PASSWORD_DEFAULT \
|
||||
"cleanair" /** default WiFi AP password \
|
||||
@ -115,7 +115,7 @@ public:
|
||||
* @return true Success
|
||||
* @return false Failure
|
||||
*/
|
||||
bool pollServerConfig(String id) {
|
||||
bool fetchServerConfiguration(String id) {
|
||||
String uri =
|
||||
"http://hw.airgradient.com/sensors/airgradient:" + id + "/one/config";
|
||||
|
||||
@ -368,10 +368,10 @@ static bool wifiHasConfig = false; /** */
|
||||
static void boardInit(void);
|
||||
static void failedHandler(String msg);
|
||||
static void co2Calibration(void);
|
||||
static void serverConfigPoll(void);
|
||||
static void co2Poll(void);
|
||||
static void pmPoll(void);
|
||||
static void tempHumPoll(void);
|
||||
static void updateServerConfiguration(void);
|
||||
static void co2Update(void);
|
||||
static void pmUpdate(void);
|
||||
static void tempHumUpdate(void);
|
||||
static void sendDataToServer(void);
|
||||
static void dispHandler(void);
|
||||
static String getDevId(void);
|
||||
@ -382,12 +382,12 @@ bool hasSensorS8 = true;
|
||||
bool hasSensorPMS = true;
|
||||
bool hasSensorSHT = true;
|
||||
int pmFailCount = 0;
|
||||
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll);
|
||||
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, updateServerConfiguration);
|
||||
AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
|
||||
AgSchedule dispSchedule(DISP_UPDATE_INTERVAL, dispHandler);
|
||||
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Poll);
|
||||
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmPoll);
|
||||
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumPoll);
|
||||
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update);
|
||||
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmUpdate);
|
||||
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
@ -413,7 +413,7 @@ void setup() {
|
||||
wifiHasConfig = true;
|
||||
sendPing();
|
||||
|
||||
agServer.pollServerConfig(getDevId());
|
||||
agServer.fetchServerConfiguration(getDevId());
|
||||
if (agServer.isCo2Calib()) {
|
||||
co2Calibration();
|
||||
}
|
||||
@ -576,8 +576,8 @@ static void co2Calibration(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void serverConfigPoll(void) {
|
||||
if (agServer.pollServerConfig(getDevId())) {
|
||||
static void updateServerConfiguration(void) {
|
||||
if (agServer.fetchServerConfiguration(getDevId())) {
|
||||
if (agServer.isCo2Calib()) {
|
||||
if (hasSensorS8) {
|
||||
co2Calibration();
|
||||
@ -609,12 +609,12 @@ static void serverConfigPoll(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void co2Poll() {
|
||||
static void co2Update() {
|
||||
co2Ppm = ag.s8.getCo2();
|
||||
Serial.printf("CO2 index: %d\r\n", co2Ppm);
|
||||
}
|
||||
|
||||
void pmPoll() {
|
||||
void pmUpdate() {
|
||||
if (ag.pms5003.readData()) {
|
||||
pm25 = ag.pms5003.getPm25Ae();
|
||||
Serial.printf("PMS2.5: %d\r\n", pm25);
|
||||
@ -628,7 +628,7 @@ void pmPoll() {
|
||||
}
|
||||
}
|
||||
|
||||
static void tempHumPoll() {
|
||||
static void tempHumUpdate() {
|
||||
if (ag.sht.measure()) {
|
||||
temp = ag.sht.getTemperature();
|
||||
hum = ag.sht.getRelativeHumidity();
|
@ -90,14 +90,15 @@ enum {
|
||||
#define WIFI_CONNECT_RETRY_MS 10000 /** ms */
|
||||
#define LED_BAR_COUNT_INIT_VALUE (-1) /** */
|
||||
#define LED_BAR_ANIMATION_PERIOD 100 /** ms */
|
||||
#define DISP_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */
|
||||
#define DISP_UPDATE_INTERVAL 2500 /** ms */
|
||||
#define SERVER_CONFIG_UPDATE_INTERVAL 15000 /** ms */
|
||||
#define SERVER_SYNC_INTERVAL 60000 /** ms */
|
||||
#define MQTT_SYNC_INTERVAL 60000 /** ms */
|
||||
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
|
||||
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
|
||||
#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SENSOR_PM_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SENSOR_CO2_UPDATE_INTERVAL 4000 /** ms */
|
||||
#define SENSOR_PM_UPDATE_INTERVAL 2000 /** ms */
|
||||
#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 2000 /** ms */
|
||||
#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
|
||||
#define WIFI_HOTSPOT_PASSWORD_DEFAULT \
|
||||
"cleanair" /** default WiFi AP password \
|
||||
@ -153,13 +154,27 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get server configuration
|
||||
* @brief Reset local config into default value.
|
||||
*
|
||||
*/
|
||||
void defaultReset(void) {
|
||||
config.inF = false;
|
||||
config.inUSAQI = false;
|
||||
memset(config.models, 0, sizeof(config.models));
|
||||
memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers));
|
||||
config.useRGBLedBar = UseLedBarOff;
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetch server configuration, if get sucessed and configuratrion
|
||||
* parameter has changed store into local storage
|
||||
*
|
||||
* @param id Device ID
|
||||
* @return true Success
|
||||
* @return false Failure
|
||||
*/
|
||||
bool pollServerConfig(String id) {
|
||||
bool fetchServerConfiguration(String id) {
|
||||
String uri =
|
||||
"http://hw.airgradient.com/sensors/airgradient:" + id + "/one/config";
|
||||
|
||||
@ -631,6 +646,7 @@ public:
|
||||
int connectionFailedCount(void) { return connectFailedCount; }
|
||||
};
|
||||
AgMqtt agMqtt;
|
||||
static TaskHandle_t mqttTask = NULL;
|
||||
|
||||
/** Create airgradient instance for 'ONE_INDOOR' board */
|
||||
AirGradient ag(ONE_INDOOR);
|
||||
@ -665,7 +681,7 @@ static String wifiSSID = "";
|
||||
|
||||
static void boardInit(void);
|
||||
static void failedHandler(String msg);
|
||||
static void serverConfigPoll(void);
|
||||
static void updateServerConfiguration(void);
|
||||
static void co2Calibration(void);
|
||||
static void setRGBledPMcolor(int pm25Value);
|
||||
static void ledSmHandler(int sm);
|
||||
@ -675,15 +691,17 @@ static void sensorLedColorHandler(void);
|
||||
static void appLedHandler(void);
|
||||
static void appDispHandler(void);
|
||||
static void updateWiFiConnect(void);
|
||||
static void updateDispLedBar(void);
|
||||
static void tvocPoll(void);
|
||||
static void pmPoll(void);
|
||||
static void displayAndLedBarUpdate(void);
|
||||
static void tvocUpdate(void);
|
||||
static void pmUpdate(void);
|
||||
static void sendDataToServer(void);
|
||||
static void tempHumPoll(void);
|
||||
static void co2Poll(void);
|
||||
static void tempHumUpdate(void);
|
||||
static void co2Update(void);
|
||||
static void showNr(void);
|
||||
static void webServerInit(void);
|
||||
static String getServerSyncData(bool localServer);
|
||||
static void createMqttTask(void);
|
||||
static void factoryConfigReset(void);
|
||||
|
||||
/** Init schedule */
|
||||
bool hasSensorS8 = true;
|
||||
@ -691,13 +709,16 @@ bool hasSensorPMS = true;
|
||||
bool hasSensorSGP = true;
|
||||
bool hasSensorSHT = true;
|
||||
int pmFailCount = 0;
|
||||
AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, updateDispLedBar);
|
||||
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll);
|
||||
uint32_t factoryBtnPressTime = 0;
|
||||
String mdnsModelName = "";
|
||||
AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, displayAndLedBarUpdate);
|
||||
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL,
|
||||
updateServerConfiguration);
|
||||
AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
|
||||
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Poll);
|
||||
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmPoll);
|
||||
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumPoll);
|
||||
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocPoll);
|
||||
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update);
|
||||
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmUpdate);
|
||||
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate);
|
||||
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocUpdate);
|
||||
|
||||
void setup() {
|
||||
EEPROM.begin(512);
|
||||
@ -715,7 +736,8 @@ void setup() {
|
||||
u8g2.begin();
|
||||
|
||||
/** Show boot display */
|
||||
displayShowText("One V9", "Lib Ver: " + ag.getVersion(), "");
|
||||
Serial.println("Firmware Version: "+ag.getVersion());
|
||||
displayShowText("One V9", "FW Ver: " + ag.getVersion(), "");
|
||||
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
|
||||
|
||||
/** Init sensor */
|
||||
@ -725,7 +747,7 @@ void setup() {
|
||||
agServer.begin();
|
||||
|
||||
/** Run LED test on start up */
|
||||
displayShowText("Press now for", "LED test", "");
|
||||
displayShowText("Press now for", "LED test &", "offline mode");
|
||||
bool test = false;
|
||||
uint32_t stime = millis();
|
||||
while (1) {
|
||||
@ -741,9 +763,9 @@ void setup() {
|
||||
}
|
||||
if (test) {
|
||||
ledTest();
|
||||
}
|
||||
/** WIFI connect */
|
||||
} else {
|
||||
connectToWifi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send first data to ping server and get server configuration
|
||||
@ -754,6 +776,7 @@ void setup() {
|
||||
/** MQTT init */
|
||||
if (agServer.getMqttBroker().isEmpty() == false) {
|
||||
if (agMqtt.begin(agServer.getMqttBroker())) {
|
||||
createMqttTask();
|
||||
Serial.println("MQTT client init success");
|
||||
} else {
|
||||
Serial.println("MQTT client init failure");
|
||||
@ -766,7 +789,7 @@ void setup() {
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
/** Get first connected to wifi */
|
||||
agServer.pollServerConfig(getDevId());
|
||||
agServer.fetchServerConfiguration(getDevId());
|
||||
if (agServer.isConfigFailed()) {
|
||||
dispSmHandler(APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED);
|
||||
ledSmHandler(APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED);
|
||||
@ -797,6 +820,7 @@ void loop() {
|
||||
}
|
||||
|
||||
if (hasSensorSHT) {
|
||||
delay(100);
|
||||
tempHumSchedule.run();
|
||||
}
|
||||
|
||||
@ -806,6 +830,9 @@ void loop() {
|
||||
|
||||
/** Check for handle WiFi reconnect */
|
||||
updateWiFiConnect();
|
||||
|
||||
/** factory reset handle */
|
||||
factoryConfigReset();
|
||||
}
|
||||
|
||||
static void setTestColor(char color) {
|
||||
@ -881,7 +908,7 @@ static void ledTest2Min(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void co2Poll(void) {
|
||||
static void co2Update(void) {
|
||||
co2Ppm = ag.s8.getCo2();
|
||||
Serial.printf("CO2 index: %d\r\n", co2Ppm);
|
||||
}
|
||||
@ -892,6 +919,141 @@ void webServerMeasureCurrentGet(void) {
|
||||
webServer.send(200, "application/json", getServerSyncData(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends metrics in Prometheus/OpenMetrics format to the currently connected
|
||||
* webServer client.
|
||||
*
|
||||
* For background, see:
|
||||
* https://prometheus.io/docs/instrumenting/exposition_formats/
|
||||
*/
|
||||
void webServerMetricsGet(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=\"" + getDevId() +
|
||||
"\",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("", agServer.isConfigFailed() ? "0" : "1");
|
||||
|
||||
add_metric(
|
||||
"post_ok",
|
||||
"1 if the AirGradient device was able to successfully send to the server",
|
||||
"gauge");
|
||||
add_metric_point("", agServer.isServerFailed() ? "0" : "1");
|
||||
|
||||
add_metric(
|
||||
"wifi_rssi",
|
||||
"WiFi signal strength from the AirGradient device perspective, in dBm",
|
||||
"gauge", "dbm");
|
||||
add_metric_point("", String(WiFi.RSSI()));
|
||||
|
||||
if (hasSensorS8 && co2Ppm >= 0) {
|
||||
add_metric("co2",
|
||||
"Carbon dioxide concentration as measured by the AirGradient S8 "
|
||||
"sensor, in parts per million",
|
||||
"gauge", "ppm");
|
||||
add_metric_point("", String(co2Ppm));
|
||||
}
|
||||
|
||||
if (hasSensorPMS) {
|
||||
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 (hasSensorSGP) {
|
||||
if (tvocIndex >= 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(tvocIndex));
|
||||
}
|
||||
if (tvocRawIndex >= 0) {
|
||||
add_metric("tvoc_raw_index",
|
||||
"The raw input value to the Total Volatile Organic Compounds "
|
||||
"(TVOC) index as measured by the AirGradient SGP sensor",
|
||||
"gauge");
|
||||
add_metric_point("", String(tvocRawIndex));
|
||||
}
|
||||
if (noxIndex >= 0) {
|
||||
add_metric("nox_index",
|
||||
"The processed Nitrous Oxide (NOx) index as measured by the "
|
||||
"AirGradient SGP sensor",
|
||||
"gauge");
|
||||
add_metric_point("", String(noxIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSensorSHT) {
|
||||
if (temp > -1001) {
|
||||
add_metric("temperature",
|
||||
"The ambient temperature as measured by the AirGradient SHT "
|
||||
"sensor, in degrees Celsius",
|
||||
"gauge", "degc");
|
||||
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";
|
||||
webServer.send(200,
|
||||
"application/openmetrics-text; version=1.0.0; charset=utf-8",
|
||||
response);
|
||||
}
|
||||
|
||||
void webServerHandler(void *param) {
|
||||
for (;;) {
|
||||
webServer.handleClient();
|
||||
@ -906,8 +1068,16 @@ static void webServerInit(void) {
|
||||
}
|
||||
|
||||
webServer.on("/measures/current", HTTP_GET, webServerMeasureCurrentGet);
|
||||
// Make it possible to query this device from Prometheus/OpenMetrics.
|
||||
webServer.on("/metrics", HTTP_GET, webServerMetricsGet);
|
||||
webServer.begin();
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
if (agServer.getModelName().isEmpty() != true) {
|
||||
MDNS.addServiceTxt("http", "_tcp", "model", agServer.getModelName());
|
||||
mdnsModelName = agServer.getModelName();
|
||||
}
|
||||
MDNS.addServiceTxt("http", "_tcp", "serialno", getDevId());
|
||||
MDNS.addServiceTxt("http", "_tcp", "fw_ver", ag.getVersion());
|
||||
|
||||
if (xTaskCreate(webServerHandler, "webserver", 1024 * 4, NULL, 5, NULL) !=
|
||||
pdTRUE) {
|
||||
@ -949,7 +1119,7 @@ static String getServerSyncData(bool localServer) {
|
||||
root["tvoc_raw"] = tvocRawIndex;
|
||||
}
|
||||
if (noxIndex >= 0) {
|
||||
root["noxIndex"] = noxIndex;
|
||||
root["nox_index"] = noxIndex;
|
||||
}
|
||||
}
|
||||
if (hasSensorSHT) {
|
||||
@ -965,6 +1135,89 @@ static String getServerSyncData(bool localServer) {
|
||||
return JSON.stringify(root);
|
||||
}
|
||||
|
||||
static void createMqttTask(void) {
|
||||
if (mqttTask) {
|
||||
vTaskDelete(mqttTask);
|
||||
mqttTask = NULL;
|
||||
}
|
||||
|
||||
xTaskCreate(
|
||||
[](void *param) {
|
||||
for (;;) {
|
||||
delay(MQTT_SYNC_INTERVAL);
|
||||
|
||||
/** Send data */
|
||||
if (agMqtt.isConnected()) {
|
||||
String syncData = getServerSyncData(false);
|
||||
String topic = "airgradient/readings/" + getDevId();
|
||||
if (agMqtt.publish(topic.c_str(), syncData.c_str(),
|
||||
syncData.length())) {
|
||||
Serial.println("Mqtt sync success");
|
||||
} else {
|
||||
Serial.println("Mqtt sync failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mqtt-task", 1024 * 3, NULL, 6, &mqttTask);
|
||||
|
||||
if (mqttTask == NULL) {
|
||||
Serial.println("Creat mqttTask failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void factoryConfigReset(void) {
|
||||
if (ag.button.getState() == ag.button.BUTTON_PRESSED) {
|
||||
if (factoryBtnPressTime == 0) {
|
||||
factoryBtnPressTime = millis();
|
||||
} else {
|
||||
uint32_t ms = (uint32_t)(millis() - factoryBtnPressTime);
|
||||
if (ms >= 2000) {
|
||||
// Show display message: For factory keep for x seconds
|
||||
// Count display.
|
||||
displayShowText("Factory reset", "keep pressed", "for 8 sec");
|
||||
|
||||
int count = 7;
|
||||
while (ag.button.getState() == ag.button.BUTTON_PRESSED) {
|
||||
delay(1000);
|
||||
displayShowText("Factory reset", "keep pressed",
|
||||
"for " + String(count) + " sec");
|
||||
count--;
|
||||
// ms = (uint32_t)(millis() - factoryBtnPressTime);
|
||||
if (count == 0) {
|
||||
/** Stop MQTT task first */
|
||||
if (mqttTask) {
|
||||
vTaskDelete(mqttTask);
|
||||
mqttTask = NULL;
|
||||
}
|
||||
|
||||
/** Disconnect WIFI */
|
||||
WiFi.disconnect();
|
||||
wifiManager.resetSettings();
|
||||
|
||||
/** Reset local config */
|
||||
agServer.defaultReset();
|
||||
|
||||
displayShowText("Factory reset", "successful", "");
|
||||
delay(3000);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
/** Show current content cause reset ignore */
|
||||
factoryBtnPressTime = 0;
|
||||
appDispHandler();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (factoryBtnPressTime != 0) {
|
||||
/** Restore last display content */
|
||||
appDispHandler();
|
||||
}
|
||||
factoryBtnPressTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void sendPing() {
|
||||
JSONVar root;
|
||||
root["wifi"] = WiFi.RSSI();
|
||||
@ -1287,20 +1540,80 @@ static String getNormalizedMac() {
|
||||
}
|
||||
|
||||
static void setRGBledCO2color(int co2Value) {
|
||||
if (co2Value >= 300 && co2Value < 800) {
|
||||
setRGBledColor('g');
|
||||
} else if (co2Value >= 800 && co2Value < 1000) {
|
||||
setRGBledColor('y');
|
||||
} else if (co2Value >= 1000 && co2Value < 1500) {
|
||||
setRGBledColor('o');
|
||||
} else if (co2Value >= 1500 && co2Value < 2000) {
|
||||
setRGBledColor('r');
|
||||
} else if (co2Value >= 2000 && co2Value < 3000) {
|
||||
setRGBledColor('p');
|
||||
} else if (co2Value >= 3000 && co2Value < 10000) {
|
||||
setRGBledColor('z');
|
||||
} else {
|
||||
setRGBledColor('n');
|
||||
if (co2Value <= 400) {
|
||||
/** G; 1 */
|
||||
ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
} else if (co2Value <= 700) {
|
||||
/** GG; 2 */
|
||||
ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
} else if (co2Value <= 1000) {
|
||||
/** YYY; 3 */
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
} else if (co2Value <= 1333) {
|
||||
/** YYYY; 4 */
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
} else if (co2Value <= 1666) {
|
||||
/** YYYYY; 5 */
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
} else if (co2Value <= 2000) {
|
||||
/** RRRRRR; 6 */
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
} else if (co2Value <= 2666) {
|
||||
/** RRRRRRR; 7 */
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
|
||||
} else if (co2Value <= 3333) {
|
||||
/** RRRRRRRR; 8 */
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
|
||||
} else if (co2Value <= 4000) {
|
||||
/** RRRRRRRRR; 9 */
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 9);
|
||||
} else { /** > 4000 */
|
||||
/* PRPRPRPRP; 9 */
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 7);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 9);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1415,8 +1728,8 @@ static void failedHandler(String msg) {
|
||||
/**
|
||||
* @brief Send data to server
|
||||
*/
|
||||
static void serverConfigPoll(void) {
|
||||
if (agServer.pollServerConfig(getDevId())) {
|
||||
static void updateServerConfiguration(void) {
|
||||
if (agServer.fetchServerConfiguration(getDevId())) {
|
||||
if (agServer.isCo2Calib()) {
|
||||
if (hasSensorS8) {
|
||||
co2Calibration();
|
||||
@ -1458,12 +1771,23 @@ static void serverConfigPoll(void) {
|
||||
String mqttUri = agServer.getMqttBroker();
|
||||
if (mqttUri != agMqtt.getUri()) {
|
||||
agMqtt.end();
|
||||
|
||||
if (mqttTask != NULL) {
|
||||
vTaskDelete(mqttTask);
|
||||
mqttTask = NULL;
|
||||
}
|
||||
if (agMqtt.begin(mqttUri)) {
|
||||
Serial.println("Connect to new mqtt broker success");
|
||||
createMqttTask();
|
||||
} else {
|
||||
Serial.println("Connect to new mqtt broker failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (mdnsModelName != agServer.getModelName()) {
|
||||
MDNS.addServiceTxt("http", "_tcp", "model", agServer.getModelName());
|
||||
mdnsModelName = agServer.getModelName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1506,18 +1830,81 @@ static void co2Calibration(void) {
|
||||
* @param pm25Value PMS2.5 value
|
||||
*/
|
||||
static void setRGBledPMcolor(int pm25Value) {
|
||||
if (pm25Value >= 0 && pm25Value < 10)
|
||||
setRGBledColor('g');
|
||||
if (pm25Value >= 10 && pm25Value < 35)
|
||||
setRGBledColor('y');
|
||||
if (pm25Value >= 35 && pm25Value < 55)
|
||||
setRGBledColor('o');
|
||||
if (pm25Value >= 55 && pm25Value < 150)
|
||||
setRGBledColor('r');
|
||||
if (pm25Value >= 150 && pm25Value < 250)
|
||||
setRGBledColor('p');
|
||||
if (pm25Value >= 250 && pm25Value < 1000)
|
||||
setRGBledColor('p');
|
||||
if (pm25Value <= 5) {
|
||||
/** G; 1 */
|
||||
ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
} else if (pm25Value <= 10) {
|
||||
/** GG; 2 */
|
||||
ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
} else if (pm25Value <= 20) {
|
||||
/** YYY; 3 */
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
} else if (pm25Value <= 35) {
|
||||
/** YYYY; 4 */
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
} else if (pm25Value <= 45) {
|
||||
/** YYYYY; 5 */
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
} else if (pm25Value <= 55) {
|
||||
/** RRRRRR; 6 */
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
} else if (pm25Value <= 65) {
|
||||
/** RRRRRRR; 7 */
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
|
||||
} else if (pm25Value <= 150) {
|
||||
/** RRRRRRRR; 8 */
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
|
||||
} else if (pm25Value <= 250) {
|
||||
/** RRRRRRRRR; 9 */
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 9);
|
||||
} else { /** > 250 */
|
||||
/* PRPRPRPRP; 9 */
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 1);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 3);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 5);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 7);
|
||||
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
|
||||
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 9);
|
||||
}
|
||||
}
|
||||
|
||||
static void singleLedAnimation(uint8_t r, uint8_t g, uint8_t b) {
|
||||
@ -1785,8 +2172,10 @@ static void updateWiFiConnect(void) {
|
||||
* @brief APP display and LED handler
|
||||
*
|
||||
*/
|
||||
static void updateDispLedBar(void) {
|
||||
static void displayAndLedBarUpdate(void) {
|
||||
if (factoryBtnPressTime == 0) {
|
||||
appDispHandler();
|
||||
}
|
||||
appLedHandler();
|
||||
}
|
||||
|
||||
@ -1794,7 +2183,7 @@ static void updateDispLedBar(void) {
|
||||
* @brief Update tvocIndexindex
|
||||
*
|
||||
*/
|
||||
static void tvocPoll(void) {
|
||||
static void tvocUpdate(void) {
|
||||
tvocIndex = ag.sgp41.getTvocIndex();
|
||||
tvocRawIndex = ag.sgp41.getTvocRaw();
|
||||
noxIndex = ag.sgp41.getNoxIndex();
|
||||
@ -1809,7 +2198,7 @@ static void tvocPoll(void) {
|
||||
* @brief Update PMS data
|
||||
*
|
||||
*/
|
||||
static void pmPoll(void) {
|
||||
static void pmUpdate(void) {
|
||||
if (ag.pms5003.readData()) {
|
||||
pm01 = ag.pms5003.getPm01Ae();
|
||||
pm25 = ag.pms5003.getPm25Ae();
|
||||
@ -1844,21 +2233,13 @@ static void sendDataToServer(void) {
|
||||
resetWatchdog();
|
||||
}
|
||||
|
||||
if (agMqtt.isConnected()) {
|
||||
String topic = "airgradient/readings/" + getDevId();
|
||||
if (agMqtt.publish(topic.c_str(), syncData.c_str(), syncData.length())) {
|
||||
Serial.println("Mqtt sync success");
|
||||
} else {
|
||||
Serial.println("Mqtt sync failure");
|
||||
}
|
||||
}
|
||||
bootCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update temperature and humidity value
|
||||
*/
|
||||
static void tempHumPoll(void) {
|
||||
static void tempHumUpdate(void) {
|
||||
if (ag.sht.measure()) {
|
||||
|
||||
temp = ag.sht.getTemperature();
|
||||
@ -1873,10 +2254,6 @@ static void tempHumPoll(void) {
|
||||
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data) {
|
||||
|
||||
ESP_LOGD(TAG,
|
||||
"Event dispatched from event loop base=%s, event_id=%" PRIi32 "",
|
||||
base, event_id);
|
||||
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
@ -77,7 +77,7 @@ enum {
|
||||
APP_SM_SERVER_LOST, /** Connected to WiFi network but the server cannot be
|
||||
reached through the internet, e.g. blocked by firewall
|
||||
*/
|
||||
APP_SM_SENSOR_CONFIG_FAILED, /** Server is reachable but there is some
|
||||
APP_SM_SENSOR_CONFIG_FAILED, /** Server is reachabFirmware nodele but there is some
|
||||
configuration issue to be fixed on the server
|
||||
side */
|
||||
APP_SM_NORMAL,
|
||||
@ -85,17 +85,20 @@ enum {
|
||||
|
||||
#define LED_FAST_BLINK_DELAY 250 /** ms */
|
||||
#define LED_SLOW_BLINK_DELAY 1000 /** ms */
|
||||
#define LED_SHORT_BLINK_DELAY 500 /** ms */
|
||||
#define LED_LONG_BLINK_DELAY 2000 /** ms */
|
||||
#define WIFI_CONNECT_COUNTDOWN_MAX 180 /** sec */
|
||||
#define WIFI_CONNECT_RETRY_MS 10000 /** ms */
|
||||
#define LED_BAR_COUNT_INIT_VALUE (-1) /** */
|
||||
#define LED_BAR_ANIMATION_PERIOD 100 /** ms */
|
||||
#define DISP_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */
|
||||
#define SERVER_CONFIG_UPDATE_INTERVAL 15000 /** ms */
|
||||
#define SERVER_SYNC_INTERVAL 60000 /** ms */
|
||||
#define MQTT_SYNC_INTERVAL 60000 /** ms */
|
||||
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
|
||||
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
|
||||
#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SENSOR_PM_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define SENSOR_CO2_UPDATE_INTERVAL 4000 /** ms */
|
||||
#define SENSOR_PM_UPDATE_INTERVAL 2000 /** ms */
|
||||
#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 5000 /** ms */
|
||||
#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
|
||||
#define WIFI_HOTSPOT_PASSWORD_DEFAULT \
|
||||
@ -152,6 +155,19 @@ public:
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset local config into default value.
|
||||
*
|
||||
*/
|
||||
void defaultReset(void) {
|
||||
config.inF = false;
|
||||
config.inUSAQI = false;
|
||||
memset(config.models, 0, sizeof(config.models));
|
||||
memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers));
|
||||
config.useRGBLedBar = UseLedBarOff;
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get server configuration
|
||||
*
|
||||
@ -159,7 +175,7 @@ public:
|
||||
* @return true Success
|
||||
* @return false Failure
|
||||
*/
|
||||
bool pollServerConfig(String id) {
|
||||
bool fetchServerConfiguration(String id) {
|
||||
String uri =
|
||||
"http://hw.airgradient.com/sensors/airgradient:" + id + "/one/config";
|
||||
|
||||
@ -631,6 +647,7 @@ public:
|
||||
int connectionFailedCount(void) { return connectFailedCount; }
|
||||
};
|
||||
AgMqtt agMqtt;
|
||||
static TaskHandle_t mqttTask = NULL;
|
||||
|
||||
/** Create airgradient instance for 'OPEN_AIR_OUTDOOR' board */
|
||||
AirGradient ag(OPEN_AIR_OUTDOOR);
|
||||
@ -692,25 +709,30 @@ void failedHandler(String msg);
|
||||
void co2Calibration(void);
|
||||
static String getDevId(void);
|
||||
static void updateWiFiConnect(void);
|
||||
static void tvocPoll(void);
|
||||
static void pmPoll(void);
|
||||
static void tvocUpdate(void);
|
||||
static void pmUpdate(void);
|
||||
static void sendDataToServer(void);
|
||||
static void co2Poll(void);
|
||||
static void serverConfigPoll(void);
|
||||
static void co2Update(void);
|
||||
static void updateServerConfiguration(void);
|
||||
static const char *getFwMode(int mode);
|
||||
static void showNr(void);
|
||||
static void webServerInit(void);
|
||||
static String getServerSyncData(bool localServer);
|
||||
static void createMqttTask(void);
|
||||
static void factoryConfigReset(void);
|
||||
|
||||
bool hasSensorS8 = true;
|
||||
bool hasSensorPMS1 = true;
|
||||
bool hasSensorPMS2 = true;
|
||||
bool hasSensorSGP = true;
|
||||
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll);
|
||||
uint32_t factoryBtnPressTime = 0;
|
||||
String mdnsModelName = "";
|
||||
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL,
|
||||
updateServerConfiguration);
|
||||
AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
|
||||
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Poll);
|
||||
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmPoll);
|
||||
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocPoll);
|
||||
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update);
|
||||
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmUpdate);
|
||||
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocUpdate);
|
||||
|
||||
void setup() {
|
||||
EEPROM.begin(512);
|
||||
@ -734,6 +756,7 @@ void setup() {
|
||||
/** MQTT init */
|
||||
if (agServer.getMqttBroker().isEmpty() == false) {
|
||||
if (agMqtt.begin(agServer.getMqttBroker())) {
|
||||
createMqttTask();
|
||||
Serial.println("MQTT client init success");
|
||||
} else {
|
||||
Serial.println("MQTT client init failure");
|
||||
@ -743,7 +766,7 @@ void setup() {
|
||||
wifiHasConfig = true;
|
||||
sendPing();
|
||||
|
||||
agServer.pollServerConfig(getDevId());
|
||||
agServer.fetchServerConfiguration(getDevId());
|
||||
if (agServer.isConfigFailed()) {
|
||||
ledSmHandler(APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED);
|
||||
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
|
||||
@ -773,6 +796,8 @@ void loop() {
|
||||
}
|
||||
}
|
||||
updateWiFiConnect();
|
||||
|
||||
factoryConfigReset();
|
||||
}
|
||||
|
||||
void sendPing() {
|
||||
@ -793,14 +818,6 @@ static void sendDataToServer(void) {
|
||||
resetWatchdog();
|
||||
}
|
||||
|
||||
if (agMqtt.isConnected()) {
|
||||
String topic = "airgradient/readings/" + getDevId();
|
||||
if (agMqtt.publish(topic.c_str(), syncData.c_str(), syncData.length())) {
|
||||
Serial.println("Mqtt sync success");
|
||||
} else {
|
||||
Serial.println("Mqtt sync failure");
|
||||
}
|
||||
}
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
@ -889,6 +906,8 @@ void boardInit(void) {
|
||||
failedHandler("Init I2C failed");
|
||||
}
|
||||
|
||||
Serial.println("Firmware Version: "+ag.getVersion());
|
||||
|
||||
ag.watchdog.begin();
|
||||
ag.button.begin();
|
||||
ag.statusLed.begin();
|
||||
@ -936,7 +955,7 @@ void boardInit(void) {
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("Firmware node: %s\r\n", getFwMode(fw_mode));
|
||||
Serial.printf("Firmware Mode: %s\r\n", getFwMode(fw_mode));
|
||||
}
|
||||
|
||||
void failedHandler(String msg) {
|
||||
@ -996,7 +1015,7 @@ static void updateWiFiConnect(void) {
|
||||
* @brief Update tvocIndexindex
|
||||
*
|
||||
*/
|
||||
static void tvocPoll(void) {
|
||||
static void tvocUpdate(void) {
|
||||
tvocIndex = ag.sgp41.getTvocIndex();
|
||||
tvocRawIndex = ag.sgp41.getTvocRaw();
|
||||
noxIndex = ag.sgp41.getNoxIndex();
|
||||
@ -1011,7 +1030,7 @@ static void tvocPoll(void) {
|
||||
* @brief Update PMS data
|
||||
*
|
||||
*/
|
||||
static void pmPoll(void) {
|
||||
static void pmUpdate(void) {
|
||||
bool pmsResult_1 = false;
|
||||
bool pmsResult_2 = false;
|
||||
if (hasSensorPMS1 && ag.pms5003t_1.readData()) {
|
||||
@ -1119,13 +1138,13 @@ static void pmPoll(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void co2Poll(void) {
|
||||
static void co2Update(void) {
|
||||
co2Ppm = ag.s8.getCo2();
|
||||
Serial.printf("CO2 index: %d\r\n", co2Ppm);
|
||||
}
|
||||
|
||||
static void serverConfigPoll(void) {
|
||||
if (agServer.pollServerConfig(getDevId())) {
|
||||
static void updateServerConfiguration(void) {
|
||||
if (agServer.fetchServerConfiguration(getDevId())) {
|
||||
/** Only support CO2 S8 sensor on FW_MODE_PST */
|
||||
if (fw_mode == FW_MODE_PST) {
|
||||
if (agServer.isCo2Calib()) {
|
||||
@ -1162,12 +1181,22 @@ static void serverConfigPoll(void) {
|
||||
String mqttUri = agServer.getMqttBroker();
|
||||
if (mqttUri != agMqtt.getUri()) {
|
||||
agMqtt.end();
|
||||
if (mqttTask != NULL) {
|
||||
vTaskDelete(mqttTask);
|
||||
mqttTask = NULL;
|
||||
}
|
||||
if (agMqtt.begin(mqttUri)) {
|
||||
Serial.println("Connect to new mqtt broker success");
|
||||
createMqttTask();
|
||||
} else {
|
||||
Serial.println("Connect to new mqtt broker failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (mdnsModelName != agServer.getModelName()) {
|
||||
MDNS.addServiceTxt("http", "_tcp", "model", agServer.getModelName());
|
||||
mdnsModelName = agServer.getModelName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1310,6 +1339,12 @@ static void webServerInit(void) {
|
||||
webServer.on("/measures/current", HTTP_GET, webServerMeasureCurrentGet);
|
||||
webServer.begin();
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
if (mdnsModelName != agServer.getModelName()) {
|
||||
MDNS.addServiceTxt("http", "_tcp", "model", agServer.getModelName());
|
||||
mdnsModelName = agServer.getModelName();
|
||||
}
|
||||
MDNS.addServiceTxt("http", "_tcp", "serialno", getDevId());
|
||||
MDNS.addServiceTxt("http", "_tcp", "fw_ver", ag.getVersion());
|
||||
|
||||
if (xTaskCreate(webServerHandler, "webserver", 1024 * 4, NULL, 5, NULL) !=
|
||||
pdTRUE) {
|
||||
@ -1376,13 +1411,13 @@ static String getServerSyncData(bool localServer) {
|
||||
|
||||
if ((fw_mode == FW_MODE_PPT) || (fw_mode == FW_MODE_PST)) {
|
||||
if (hasSensorSGP) {
|
||||
if (tvocIndex > 0) {
|
||||
if (tvocIndex >= 0) {
|
||||
root["tvoc_index"] = tvocIndex;
|
||||
}
|
||||
if (tvocRawIndex >= 0) {
|
||||
root["tvoc_raw"] = tvocRawIndex;
|
||||
}
|
||||
if (noxIndex > 0) {
|
||||
if (noxIndex >= 0) {
|
||||
root["nox_index"] = noxIndex;
|
||||
}
|
||||
}
|
||||
@ -1418,12 +1453,96 @@ static String getServerSyncData(bool localServer) {
|
||||
return JSON.stringify(root);
|
||||
}
|
||||
|
||||
static void createMqttTask(void) {
|
||||
if (mqttTask) {
|
||||
vTaskDelete(mqttTask);
|
||||
mqttTask = NULL;
|
||||
}
|
||||
|
||||
xTaskCreate(
|
||||
[](void *param) {
|
||||
for (;;) {
|
||||
delay(MQTT_SYNC_INTERVAL);
|
||||
|
||||
/** Send data */
|
||||
if (agMqtt.isConnected()) {
|
||||
String syncData = getServerSyncData(false);
|
||||
String topic = "airgradient/readings/" + getDevId();
|
||||
if (agMqtt.publish(topic.c_str(), syncData.c_str(),
|
||||
syncData.length())) {
|
||||
Serial.println("Mqtt sync success");
|
||||
} else {
|
||||
Serial.println("Mqtt sync failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mqtt-task", 1024 * 3, NULL, 6, &mqttTask);
|
||||
|
||||
if (mqttTask == NULL) {
|
||||
Serial.println("Creat mqttTask failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void factoryConfigReset(void) {
|
||||
if (ag.button.getState() == ag.button.BUTTON_PRESSED) {
|
||||
if (factoryBtnPressTime == 0) {
|
||||
factoryBtnPressTime = millis();
|
||||
} else {
|
||||
uint32_t ms = (uint32_t)(millis() - factoryBtnPressTime);
|
||||
if (ms >= 2000) {
|
||||
Serial.println("Factory reset keep presssed for 8 sec");
|
||||
|
||||
uint32_t ledTime = millis();
|
||||
bool ledOn = true;
|
||||
ag.statusLed.setOn();
|
||||
while (ag.button.getState() == ag.button.BUTTON_PRESSED) {
|
||||
ms = (uint32_t)(millis() - ledTime);
|
||||
if (ms >= LED_SHORT_BLINK_DELAY) {
|
||||
ledTime = millis();
|
||||
ag.statusLed.setToggle();
|
||||
}
|
||||
|
||||
ms = (uint32_t)(millis() - factoryBtnPressTime);
|
||||
if (ms > 10000) {
|
||||
ag.statusLed.setOff();
|
||||
|
||||
/** Stop MQTT task first */
|
||||
if (mqttTask) {
|
||||
vTaskDelete(mqttTask);
|
||||
mqttTask = NULL;
|
||||
}
|
||||
|
||||
/** Disconnect WIFI */
|
||||
WiFi.disconnect();
|
||||
wifiManager.resetSettings();
|
||||
|
||||
/** Reset local config */
|
||||
agServer.defaultReset();
|
||||
|
||||
Serial.println("Factory successful");
|
||||
ledBlinkDelay(LED_LONG_BLINK_DELAY);
|
||||
ledBlinkDelay(LED_LONG_BLINK_DELAY);
|
||||
ledBlinkDelay(LED_LONG_BLINK_DELAY);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
/** Show current content cause reset ignore */
|
||||
factoryBtnPressTime = 0;
|
||||
ag.statusLed.setOff();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (factoryBtnPressTime != 0) {
|
||||
ag.statusLed.setOff();
|
||||
}
|
||||
factoryBtnPressTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data) {
|
||||
|
||||
ESP_LOGD(TAG,
|
||||
"Event dispatched from event loop base=%s, event_id=%" PRIi32 "",
|
||||
base, event_id);
|
||||
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=AirGradient Air Quality Sensor
|
||||
version=3.0.4
|
||||
version=3.0.6
|
||||
author=AirGradient <support@airgradient.com>
|
||||
maintainer=AirGradient <support@airgradient.com>
|
||||
sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display.
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "AirGradient.h"
|
||||
|
||||
#define AG_LIB_VER "3.0.4"
|
||||
#define AG_LIB_VER "3.0.6"
|
||||
|
||||
AirGradient::AirGradient(BoardType type)
|
||||
: pms5003(type), pms5003t_1(type), pms5003t_2(type), s8(type), sgp41(type),
|
||||
@ -40,3 +40,7 @@ BoardType AirGradient::getBoardType(void) { return boardType; }
|
||||
double AirGradient::round2(double value) {
|
||||
return (int)(value * 100 + 0.5) / 100.0;
|
||||
}
|
||||
|
||||
String AirGradient::getBoardName(void) {
|
||||
return String(getBoardDefName(boardType));
|
||||
}
|
||||
|
@ -107,6 +107,13 @@ public:
|
||||
*/
|
||||
String getVersion(void);
|
||||
|
||||
/**
|
||||
* @brief Get the Board Name object
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String getBoardName(void);
|
||||
|
||||
/**
|
||||
* @brief Round double value with for 2 decimal
|
||||
*
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _AIR_GRADIENT_OLED_H_
|
||||
#define _AIR_GRADIENT_OLED_H_
|
||||
|
||||
#include "../main/BoardDef.h"
|
||||
#include "../Main/BoardDef.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
|
@ -335,6 +335,19 @@ const BoardDef *getBoardDef(BoardType def) {
|
||||
return &bsps[def];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the Board Name
|
||||
*
|
||||
* @param type BoarType
|
||||
* @return const char*
|
||||
*/
|
||||
const char *getBoardDefName(BoardType type) {
|
||||
if (type >= _BOARD_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
return bsps[type].name;
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
#define bspPrintf(c, ...) \
|
||||
if (_debug != nullptr) { \
|
||||
|
@ -76,13 +76,14 @@ struct BoardDef {
|
||||
|
||||
/** Watchdog */
|
||||
struct {
|
||||
const uint8_t resetPin;
|
||||
const int resetPin;
|
||||
const bool supported;
|
||||
} WDG;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
const BoardDef *getBoardDef(BoardType def);
|
||||
const char *getBoardDefName(BoardType type);
|
||||
void printBoardDef(Stream *_debug);
|
||||
|
||||
#endif /** _AIR_GRADIENT_BOARD_DEF_H_ */
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "PMS5003.h"
|
||||
#include "Arduino.h"
|
||||
#include "PMSUtils.h"
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <SoftwareSerial.h>
|
||||
@ -63,7 +64,8 @@ bool PMS5003::begin(void) {
|
||||
|
||||
#if defined(ESP8266)
|
||||
bsp->Pms5003.uart_tx_pin;
|
||||
SoftwareSerial *uart = new SoftwareSerial(bsp->Pms5003.uart_tx_pin, bsp->Pms5003.uart_rx_pin);
|
||||
SoftwareSerial *uart =
|
||||
new SoftwareSerial(bsp->Pms5003.uart_tx_pin, bsp->Pms5003.uart_rx_pin);
|
||||
uart->begin(9600);
|
||||
if (pms.begin(uart) == false) {
|
||||
AgLog("PMS failed");
|
||||
@ -81,31 +83,6 @@ bool PMS5003::begin(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert PM2.5 to US AQI
|
||||
*
|
||||
* @param pm02
|
||||
* @return int
|
||||
*/
|
||||
int PMS5003::pm25ToAQI(int pm02) {
|
||||
if (pm02 <= 12.0)
|
||||
return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0);
|
||||
else if (pm02 <= 35.4)
|
||||
return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50);
|
||||
else if (pm02 <= 55.4)
|
||||
return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100);
|
||||
else if (pm02 <= 150.4)
|
||||
return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150);
|
||||
else if (pm02 <= 250.4)
|
||||
return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200);
|
||||
else if (pm02 <= 350.4)
|
||||
return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300);
|
||||
else if (pm02 <= 500.4)
|
||||
return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400);
|
||||
else
|
||||
return 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read all package data then call to @ref getPMxxx to get the target
|
||||
* data
|
||||
@ -155,7 +132,7 @@ int PMS5003::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; }
|
||||
* @param pm25 PM2.5 index
|
||||
* @return int PM2.5 US AQI
|
||||
*/
|
||||
int PMS5003::convertPm25ToUsAqi(int pm25) { return this->pm25ToAQI(pm25); }
|
||||
int PMS5003::convertPm25ToUsAqi(int pm25) { return pm25ToAQI(pm25); }
|
||||
|
||||
/**
|
||||
* @brief Check device initialized or not
|
||||
|
@ -2,8 +2,8 @@
|
||||
#define _AIR_GRADIENT_PMS5003_H_
|
||||
|
||||
#include "../Main/BoardDef.h"
|
||||
#include "Stream.h"
|
||||
#include "PMS.h"
|
||||
#include "Stream.h"
|
||||
|
||||
/**
|
||||
* @brief The class define how to handle PMS5003 sensor bas on @ref PMS class
|
||||
@ -41,6 +41,5 @@ private:
|
||||
|
||||
bool begin(void);
|
||||
bool isBegin(void);
|
||||
int pm25ToAQI(int pm02);
|
||||
};
|
||||
#endif /** _AIR_GRADIENT_PMS5003_H_ */
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "PMS5003T.h"
|
||||
#include "Arduino.h"
|
||||
#include "PMSUtils.h"
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <SoftwareSerial.h>
|
||||
@ -105,31 +106,6 @@ bool PMS5003T::begin(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert PM2.5 to US AQI
|
||||
*
|
||||
* @param pm02
|
||||
* @return int
|
||||
*/
|
||||
int PMS5003T::pm25ToAQI(int pm02) {
|
||||
if (pm02 <= 12.0)
|
||||
return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0);
|
||||
else if (pm02 <= 35.4)
|
||||
return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50);
|
||||
else if (pm02 <= 55.4)
|
||||
return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100);
|
||||
else if (pm02 <= 150.4)
|
||||
return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150);
|
||||
else if (pm02 <= 250.4)
|
||||
return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200);
|
||||
else if (pm02 <= 350.4)
|
||||
return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300);
|
||||
else if (pm02 <= 500.4)
|
||||
return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400);
|
||||
else
|
||||
return 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read all package data then call to @ref getPMxxx to get the target
|
||||
* data
|
||||
@ -179,7 +155,7 @@ int PMS5003T::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; }
|
||||
* @param pm25 PM2.5 index
|
||||
* @return int PM2.5 US AQI
|
||||
*/
|
||||
int PMS5003T::convertPm25ToUsAqi(int pm25) { return this->pm25ToAQI(pm25); }
|
||||
int PMS5003T::convertPm25ToUsAqi(int pm25) { return pm25ToAQI(pm25); }
|
||||
|
||||
/**
|
||||
* @brief Get temperature, Must call this method after @ref readData() success
|
||||
@ -197,8 +173,8 @@ float PMS5003T::getTemperature(void) {
|
||||
* @return float Percent (%)
|
||||
*/
|
||||
float PMS5003T::getRelativeHumidity(void) {
|
||||
float temp = pmsData.AMB_HUM;
|
||||
return temp / 10.0f;
|
||||
float hum = pmsData.AMB_HUM;
|
||||
return correctionRelativeHumidity(hum / 10.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,3 +210,7 @@ void PMS5003T::end(void) {
|
||||
#endif
|
||||
AgLog("De-initialize");
|
||||
}
|
||||
|
||||
float PMS5003T::correctionRelativeHumidity(float inHum) {
|
||||
return inHum * 1.259 + 7.34;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
#ifndef _PMS5003T_H_
|
||||
#define _PMS5003T_H_
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include "../Main/BoardDef.h"
|
||||
#include "PMS.h"
|
||||
#include "Stream.h"
|
||||
#include <HardwareSerial.h>
|
||||
|
||||
/**
|
||||
* @brief The class define how to handle PMS5003T sensor bas on @ref PMS class
|
||||
@ -42,11 +42,11 @@ private:
|
||||
#endif
|
||||
|
||||
bool begin(void);
|
||||
int pm25ToAQI(int pm02);
|
||||
PMS pms;
|
||||
PMS::DATA pmsData;
|
||||
bool isBegin(void);
|
||||
float correctionTemperature(float inTemp);
|
||||
float correctionRelativeHumidity(float inHum);
|
||||
};
|
||||
|
||||
#endif /** _PMS5003T_H_ */
|
||||
|
26
src/PMS/PMSUtils.cpp
Normal file
26
src/PMS/PMSUtils.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "PMSUtils.h"
|
||||
|
||||
/**
|
||||
* @brief Convert PM2.5 to US AQI
|
||||
*
|
||||
* @param pm02
|
||||
* @return int
|
||||
*/
|
||||
int pm25ToAQI(int pm02) {
|
||||
if (pm02 <= 12.0)
|
||||
return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0);
|
||||
else if (pm02 <= 35.4)
|
||||
return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50);
|
||||
else if (pm02 <= 55.4)
|
||||
return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100);
|
||||
else if (pm02 <= 150.4)
|
||||
return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150);
|
||||
else if (pm02 <= 250.4)
|
||||
return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200);
|
||||
else if (pm02 <= 350.4)
|
||||
return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300);
|
||||
else if (pm02 <= 500.4)
|
||||
return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400);
|
||||
else
|
||||
return 500;
|
||||
}
|
6
src/PMS/PMSUtils.h
Normal file
6
src/PMS/PMSUtils.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _PMS_UTILS_H_
|
||||
#define _PMS_UTILS_H_
|
||||
|
||||
int pm25ToAQI(int pm02);
|
||||
|
||||
#endif /** _PMS_UTILS_H_ */
|
@ -1,7 +1,7 @@
|
||||
#ifndef _S8_H_
|
||||
#define _S8_H_
|
||||
|
||||
#include "../main/BoardDef.h"
|
||||
#include "../Main/BoardDef.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _AIR_GRADIENT_SGP4X_H_
|
||||
#define _AIR_GRADIENT_SGP4X_H_
|
||||
|
||||
#include "../main/BoardDef.h"
|
||||
#include "../Main/BoardDef.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _SHT_H_
|
||||
#define _SHT_H_
|
||||
|
||||
#include "../main/BoardDef.h"
|
||||
#include "../Main/BoardDef.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
|
Reference in New Issue
Block a user