mirror of
https://github.com/airgradienthq/arduino.git
synced 2025-06-27 16:50:58 +02:00
Compare commits
93 Commits
Author | SHA1 | Date | |
---|---|---|---|
f46c66a77f | |||
9c8ae315a0 | |||
3ef438412f | |||
ce1373141a | |||
aceecde7b6 | |||
6926abd6f7 | |||
15dec40dfc | |||
4a36cf0c13 | |||
ecc92a6824 | |||
3d243cb8ca | |||
471448a0f1 | |||
ea3e976232 | |||
87f2463233 | |||
49c7877ec3 | |||
be1a9778e6 | |||
ed1d45cea1 | |||
db31b39ce2 | |||
d92d312b0c | |||
6837529096 | |||
b94ae9eff0 | |||
1810c0f355 | |||
eb0f45750d | |||
9ae8fb2355 | |||
512509c2e2 | |||
66815f590c | |||
f60e9bbe3e | |||
f361e3c9a9 | |||
e76dcf07c8 | |||
e6fe489be7 | |||
9ddb606a00 | |||
cd5ee2da18 | |||
4c42a9ddc8 | |||
78b1b0975c | |||
d99881aa46 | |||
df937fe65f | |||
dc742d3c92 | |||
a7b2ad526f | |||
bb804b9f6a | |||
1a00073cf6 | |||
469d07a2d6 | |||
6cf5e31843 | |||
3f1da6387b | |||
99b4858f1d | |||
4374c980ec | |||
ded7637b06 | |||
6a79ab6b5b | |||
7baff75524 | |||
d421c94647 | |||
d78205aa20 | |||
c1228bbd06 | |||
1eb43f684b | |||
4798e44cb7 | |||
a867e9af38 | |||
8fcf257726 | |||
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 |
58
.github/workflows/check.yml
vendored
Normal file
58
.github/workflows/check.yml
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
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"
|
||||||
|
fqbn: "esp32:esp32:esp32c3"
|
||||||
|
- example: "ONE"
|
||||||
|
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
|
||||||
|
# In some cases, actions/checkout@v4 will check out a detached HEAD; for
|
||||||
|
# example, this happens on pull request events, where an hypothetical
|
||||||
|
# PR merge commit is checked out. This tends to confuse
|
||||||
|
# `arduino-cli lib install --git-url`, making it fail with errors such as:
|
||||||
|
# Error installing Git Library: Library install failed: object not found
|
||||||
|
# Create and check out a dummy branch to work around this issue.
|
||||||
|
- run: git checkout -b check
|
||||||
|
- 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
|
*.DS_Store
|
||||||
|
build
|
||||||
|
.vscode
|
||||||
|
@ -35,7 +35,6 @@ If you have any questions or problems, check out [our forum](https://forum.airgr
|
|||||||
- [Sensirion Core](https://github.com/Sensirion/arduino-core/)
|
- [Sensirion Core](https://github.com/Sensirion/arduino-core/)
|
||||||
- [Sensirion I2C SGP41](https://github.com/Sensirion/arduino-i2c-sgp41)
|
- [Sensirion I2C SGP41](https://github.com/Sensirion/arduino-i2c-sgp41)
|
||||||
- [Sensirion I2C SHT](https://github.com/Sensirion/arduino-sht)
|
- [Sensirion I2C SHT](https://github.com/Sensirion/arduino-sht)
|
||||||
- [PMS](https://github.com/fu-hsi/pms)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
@ -50,7 +50,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
|||||||
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
|
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
|
||||||
#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */
|
#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */
|
||||||
#define SENSOR_PM_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 DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
|
||||||
#define WIFI_HOTSPOT_PASSWORD_DEFAULT \
|
#define WIFI_HOTSPOT_PASSWORD_DEFAULT \
|
||||||
"cleanair" /** default WiFi AP password \
|
"cleanair" /** default WiFi AP password \
|
||||||
@ -115,7 +115,7 @@ public:
|
|||||||
* @return true Success
|
* @return true Success
|
||||||
* @return false Failure
|
* @return false Failure
|
||||||
*/
|
*/
|
||||||
bool pollServerConfig(String id) {
|
bool fetchServerConfiguration(String id) {
|
||||||
String uri =
|
String uri =
|
||||||
"http://hw.airgradient.com/sensors/airgradient:" + id + "/one/config";
|
"http://hw.airgradient.com/sensors/airgradient:" + id + "/one/config";
|
||||||
|
|
||||||
@ -249,6 +249,8 @@ public:
|
|||||||
if ((retCode == 200) || (retCode == 429)) {
|
if ((retCode == 200) || (retCode == 429)) {
|
||||||
serverFailed = false;
|
serverFailed = false;
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
Serial.printf("Post response failed code: %d\r\n", retCode);
|
||||||
}
|
}
|
||||||
serverFailed = true;
|
serverFailed = true;
|
||||||
return false;
|
return false;
|
||||||
@ -368,10 +370,10 @@ static bool wifiHasConfig = false; /** */
|
|||||||
static void boardInit(void);
|
static void boardInit(void);
|
||||||
static void failedHandler(String msg);
|
static void failedHandler(String msg);
|
||||||
static void co2Calibration(void);
|
static void co2Calibration(void);
|
||||||
static void serverConfigPoll(void);
|
static void updateServerConfiguration(void);
|
||||||
static void co2Poll(void);
|
static void co2Update(void);
|
||||||
static void pmPoll(void);
|
static void pmUpdate(void);
|
||||||
static void tempHumPoll(void);
|
static void tempHumUpdate(void);
|
||||||
static void sendDataToServer(void);
|
static void sendDataToServer(void);
|
||||||
static void dispHandler(void);
|
static void dispHandler(void);
|
||||||
static String getDevId(void);
|
static String getDevId(void);
|
||||||
@ -382,12 +384,14 @@ bool hasSensorS8 = true;
|
|||||||
bool hasSensorPMS = true;
|
bool hasSensorPMS = true;
|
||||||
bool hasSensorSHT = true;
|
bool hasSensorSHT = true;
|
||||||
int pmFailCount = 0;
|
int pmFailCount = 0;
|
||||||
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll);
|
int getCO2FailCount = 0;
|
||||||
|
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL,
|
||||||
|
updateServerConfiguration);
|
||||||
AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
|
AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
|
||||||
AgSchedule dispSchedule(DISP_UPDATE_INTERVAL, dispHandler);
|
AgSchedule dispSchedule(DISP_UPDATE_INTERVAL, dispHandler);
|
||||||
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Poll);
|
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update);
|
||||||
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmPoll);
|
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmUpdate);
|
||||||
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumPoll);
|
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate);
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
@ -413,7 +417,7 @@ void setup() {
|
|||||||
wifiHasConfig = true;
|
wifiHasConfig = true;
|
||||||
sendPing();
|
sendPing();
|
||||||
|
|
||||||
agServer.pollServerConfig(getDevId());
|
agServer.fetchServerConfiguration(getDevId());
|
||||||
if (agServer.isCo2Calib()) {
|
if (agServer.isCo2Calib()) {
|
||||||
co2Calibration();
|
co2Calibration();
|
||||||
}
|
}
|
||||||
@ -453,6 +457,9 @@ void loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateWiFiConnect();
|
updateWiFiConnect();
|
||||||
|
|
||||||
|
/** Read PMS on loop */
|
||||||
|
ag.pms5003.handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sendPing() {
|
static void sendPing() {
|
||||||
@ -576,8 +583,8 @@ static void co2Calibration(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serverConfigPoll(void) {
|
static void updateServerConfiguration(void) {
|
||||||
if (agServer.pollServerConfig(getDevId())) {
|
if (agServer.fetchServerConfiguration(getDevId())) {
|
||||||
if (agServer.isCo2Calib()) {
|
if (agServer.isCo2Calib()) {
|
||||||
if (hasSensorS8) {
|
if (hasSensorS8) {
|
||||||
co2Calibration();
|
co2Calibration();
|
||||||
@ -591,7 +598,7 @@ static void serverConfigPoll(void) {
|
|||||||
Serial.printf("abcDays config: %d days(%d hours)\r\n",
|
Serial.printf("abcDays config: %d days(%d hours)\r\n",
|
||||||
agServer.getCo2AbcDaysConfig(), newHour);
|
agServer.getCo2AbcDaysConfig(), newHour);
|
||||||
int curHour = ag.s8.getAbcPeriod();
|
int curHour = ag.s8.getAbcPeriod();
|
||||||
Serial.printf("Current config: %d (hours)\r\n", ag.s8.getAbcPeriod());
|
Serial.printf("Current config: %d (hours)\r\n", curHour);
|
||||||
if (curHour == newHour) {
|
if (curHour == newHour) {
|
||||||
Serial.println("set 'abcDays' ignored");
|
Serial.println("set 'abcDays' ignored");
|
||||||
} else {
|
} else {
|
||||||
@ -609,13 +616,23 @@ static void serverConfigPoll(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void co2Poll() {
|
static void co2Update() {
|
||||||
co2Ppm = ag.s8.getCo2();
|
int value = ag.s8.getCo2();
|
||||||
Serial.printf("CO2 index: %d\r\n", co2Ppm);
|
if (value >= 0) {
|
||||||
|
co2Ppm = value;
|
||||||
|
getCO2FailCount = 0;
|
||||||
|
Serial.printf("CO2 index: %d\r\n", co2Ppm);
|
||||||
|
} else {
|
||||||
|
getCO2FailCount++;
|
||||||
|
Serial.printf("Get CO2 failed: %d\r\n", getCO2FailCount);
|
||||||
|
if (getCO2FailCount >= 3) {
|
||||||
|
co2Ppm = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pmPoll() {
|
void pmUpdate() {
|
||||||
if (ag.pms5003.readData()) {
|
if (ag.pms5003.isFailed() == false) {
|
||||||
pm25 = ag.pms5003.getPm25Ae();
|
pm25 = ag.pms5003.getPm25Ae();
|
||||||
Serial.printf("PMS2.5: %d\r\n", pm25);
|
Serial.printf("PMS2.5: %d\r\n", pm25);
|
||||||
pmFailCount = 0;
|
pmFailCount = 0;
|
||||||
@ -628,7 +645,7 @@ void pmPoll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tempHumPoll() {
|
static void tempHumUpdate() {
|
||||||
if (ag.sht.measure()) {
|
if (ag.sht.measure()) {
|
||||||
temp = ag.sht.getTemperature();
|
temp = ag.sht.getTemperature();
|
||||||
hum = ag.sht.getRelativeHumidity();
|
hum = ag.sht.getRelativeHumidity();
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@ void setup()
|
|||||||
if (ag.s8.begin(&Serial) == false)
|
if (ag.s8.begin(&Serial) == false)
|
||||||
{
|
{
|
||||||
#else
|
#else
|
||||||
if (ag.s8.begin(Serial1) == false)
|
if (ag.s8.begin(Serial0) == false)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
failedHandler("SenseAir S8 init failed");
|
failedHandler("SenseAir S8 init failed");
|
||||||
|
@ -10,8 +10,8 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
|||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
AirGradient ag = AirGradient(DIY_BASIC);
|
AirGradient ag = AirGradient(DIY_BASIC);
|
||||||
#else
|
#else
|
||||||
// AirGradient ag = AirGradient(ONE_INDOOR);
|
AirGradient ag = AirGradient(ONE_INDOOR);
|
||||||
AirGradient ag = AirGradient(OPEN_AIR_OUTDOOR);
|
// AirGradient ag = AirGradient(OPEN_AIR_OUTDOOR);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void failedHandler(String msg);
|
void failedHandler(String msg);
|
||||||
@ -35,42 +35,56 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t lastRead = 0;
|
||||||
void loop() {
|
void loop() {
|
||||||
int PM2;
|
int PM2;
|
||||||
bool readResul = false;
|
bool readResul = false;
|
||||||
#ifdef ESP8266
|
|
||||||
if (ag.pms5003.readData()) {
|
|
||||||
PM2 = ag.pms5003.getPm25Ae();
|
|
||||||
Serial.printf("PM2.5 in ug/m3: %d\r\n", PM2);
|
|
||||||
Serial.printf("PM2.5 in US AQI: %d\r\n",
|
|
||||||
ag.pms5003.convertPm25ToUsAqi(PM2));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (ag.getBoardType() == OPEN_AIR_OUTDOOR) {
|
|
||||||
if (ag.pms5003t_1.readData()) {
|
|
||||||
PM2 = ag.pms5003t_1.getPm25Ae();
|
|
||||||
readResul = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ag.pms5003.readData()) {
|
|
||||||
PM2 = ag.pms5003.getPm25Ae();
|
|
||||||
readResul = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readResul) {
|
uint32_t ms = (uint32_t)(millis() - lastRead);
|
||||||
Serial.printf("PM2.5 in ug/m3: %d\r\n", PM2);
|
if (ms >= 5000) {
|
||||||
if (ag.getBoardType() == OPEN_AIR_OUTDOOR) {
|
lastRead = millis();
|
||||||
Serial.printf("PM2.5 in US AQI: %d\r\n",
|
#ifdef ESP8266
|
||||||
ag.pms5003t_1.convertPm25ToUsAqi(PM2));
|
if (ag.pms5003.isFailed() == false) {
|
||||||
} else {
|
PM2 = ag.pms5003.getPm25Ae();
|
||||||
|
Serial.printf("PM2.5 in ug/m3: %d\r\n", PM2);
|
||||||
Serial.printf("PM2.5 in US AQI: %d\r\n",
|
Serial.printf("PM2.5 in US AQI: %d\r\n",
|
||||||
ag.pms5003.convertPm25ToUsAqi(PM2));
|
ag.pms5003.convertPm25ToUsAqi(PM2));
|
||||||
|
} else {
|
||||||
|
Serial.println("PMS sensor failed");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (ag.getBoardType() == OPEN_AIR_OUTDOOR) {
|
||||||
|
if (ag.pms5003t_1.isFailed() == false) {
|
||||||
|
PM2 = ag.pms5003t_1.getPm25Ae();
|
||||||
|
readResul = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ag.pms5003.isFailed() == false) {
|
||||||
|
PM2 = ag.pms5003.getPm25Ae();
|
||||||
|
readResul = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
delay(5000);
|
if (readResul) {
|
||||||
|
Serial.printf("PM2.5 in ug/m3: %d\r\n", PM2);
|
||||||
|
if (ag.getBoardType() == OPEN_AIR_OUTDOOR) {
|
||||||
|
Serial.printf("PM2.5 in US AQI: %d\r\n",
|
||||||
|
ag.pms5003t_1.convertPm25ToUsAqi(PM2));
|
||||||
|
} else {
|
||||||
|
Serial.printf("PM2.5 in US AQI: %d\r\n",
|
||||||
|
ag.pms5003.convertPm25ToUsAqi(PM2));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.println("PMS sensor failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ag.getBoardType() == OPEN_AIR_OUTDOOR) {
|
||||||
|
ag.pms5003t_1.handle();
|
||||||
|
} else {
|
||||||
|
ag.pms5003.handle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void failedHandler(String msg) {
|
void failedHandler(String msg) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=AirGradient Air Quality Sensor
|
name=AirGradient Air Quality Sensor
|
||||||
version=3.0.4
|
version=3.0.8
|
||||||
author=AirGradient <support@airgradient.com>
|
author=AirGradient <support@airgradient.com>
|
||||||
maintainer=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.
|
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"
|
#include "AirGradient.h"
|
||||||
|
|
||||||
#define AG_LIB_VER "3.0.4"
|
#define AG_LIB_VER "3.0.8"
|
||||||
|
|
||||||
AirGradient::AirGradient(BoardType type)
|
AirGradient::AirGradient(BoardType type)
|
||||||
: pms5003(type), pms5003t_1(type), pms5003t_2(type), s8(type), sgp41(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) {
|
double AirGradient::round2(double value) {
|
||||||
return (int)(value * 100 + 0.5) / 100.0;
|
return (int)(value * 100 + 0.5) / 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String AirGradient::getBoardName(void) {
|
||||||
|
return String(getBoardDefName(boardType));
|
||||||
|
}
|
||||||
|
@ -107,6 +107,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
String getVersion(void);
|
String getVersion(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Board Name object
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
String getBoardName(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Round double value with for 2 decimal
|
* @brief Round double value with for 2 decimal
|
||||||
*
|
*
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef _AIR_GRADIENT_OLED_H_
|
#ifndef _AIR_GRADIENT_OLED_H_
|
||||||
#define _AIR_GRADIENT_OLED_H_
|
#define _AIR_GRADIENT_OLED_H_
|
||||||
|
|
||||||
#include "../main/BoardDef.h"
|
#include "../Main/BoardDef.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
|
|
||||||
|
@ -335,6 +335,19 @@ const BoardDef *getBoardDef(BoardType def) {
|
|||||||
return &bsps[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)
|
#if defined(ESP8266)
|
||||||
#define bspPrintf(c, ...) \
|
#define bspPrintf(c, ...) \
|
||||||
if (_debug != nullptr) { \
|
if (_debug != nullptr) { \
|
||||||
|
@ -76,13 +76,14 @@ struct BoardDef {
|
|||||||
|
|
||||||
/** Watchdog */
|
/** Watchdog */
|
||||||
struct {
|
struct {
|
||||||
const uint8_t resetPin;
|
const int resetPin;
|
||||||
const bool supported;
|
const bool supported;
|
||||||
} WDG;
|
} WDG;
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BoardDef *getBoardDef(BoardType def);
|
const BoardDef *getBoardDef(BoardType def);
|
||||||
|
const char *getBoardDefName(BoardType type);
|
||||||
void printBoardDef(Stream *_debug);
|
void printBoardDef(Stream *_debug);
|
||||||
|
|
||||||
#endif /** _AIR_GRADIENT_BOARD_DEF_H_ */
|
#endif /** _AIR_GRADIENT_BOARD_DEF_H_ */
|
||||||
|
@ -35,6 +35,7 @@ void LedBar::begin(void) {
|
|||||||
this->_bsp->LED.rgbNum, this->_bsp->LED.pin, NEO_GRB + NEO_KHZ800);
|
this->_bsp->LED.rgbNum, this->_bsp->LED.pin, NEO_GRB + NEO_KHZ800);
|
||||||
pixel()->begin();
|
pixel()->begin();
|
||||||
pixel()->clear();
|
pixel()->clear();
|
||||||
|
pixel()->show();
|
||||||
|
|
||||||
this->_isBegin = true;
|
this->_isBegin = true;
|
||||||
|
|
||||||
@ -114,6 +115,10 @@ void LedBar::setColor(uint8_t red, uint8_t green, uint8_t blue) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void LedBar::show(void) {
|
void LedBar::show(void) {
|
||||||
|
// Ignore update the LED if LED bar disabled
|
||||||
|
if (enabled == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (pixel()->canShow()) {
|
if (pixel()->canShow()) {
|
||||||
pixel()->show();
|
pixel()->show();
|
||||||
}
|
}
|
||||||
@ -124,3 +129,15 @@ void LedBar::show(void) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void LedBar::clear(void) { pixel()->clear(); }
|
void LedBar::clear(void) { pixel()->clear(); }
|
||||||
|
|
||||||
|
void LedBar::setEnable(bool enable) {
|
||||||
|
if (this->enabled != enable) {
|
||||||
|
if (enable == false) {
|
||||||
|
pixel()->clear();
|
||||||
|
pixel()->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LedBar::isEnabled(void) { return enabled; }
|
||||||
|
@ -23,8 +23,11 @@ public:
|
|||||||
int getNumberOfLeds(void);
|
int getNumberOfLeds(void);
|
||||||
void show(void);
|
void show(void);
|
||||||
void clear(void);
|
void clear(void);
|
||||||
|
void setEnable(bool enable);
|
||||||
|
bool isEnabled(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool enabled = true;
|
||||||
const BoardDef *_bsp;
|
const BoardDef *_bsp;
|
||||||
bool _isBegin = false;
|
bool _isBegin = false;
|
||||||
uint8_t _ledState = 0;
|
uint8_t _ledState = 0;
|
||||||
|
426
src/PMS/PMS.cpp
426
src/PMS/PMS.cpp
@ -1,164 +1,300 @@
|
|||||||
#include "PMS.h"
|
#include "PMS.h"
|
||||||
|
#include "../Main/BoardDef.h"
|
||||||
|
|
||||||
bool PMS::begin(Stream *stream) {
|
/**
|
||||||
_stream = stream;
|
* @brief Init and check that sensor has connected
|
||||||
|
*
|
||||||
|
* @param stream UART stream
|
||||||
|
* @return true Sucecss
|
||||||
|
* @return false Failure
|
||||||
|
*/
|
||||||
|
bool PMSBase::begin(Stream *stream) {
|
||||||
|
this->stream = stream;
|
||||||
|
|
||||||
DATA data;
|
failed = true;
|
||||||
if (readUntil(data, 5000)) {
|
lastRead = 0; // To read buffer on handle without wait after 1.5sec
|
||||||
return true;
|
|
||||||
|
this->stream->flush();
|
||||||
|
|
||||||
|
// Run and check sensor data for 4sec
|
||||||
|
while (1) {
|
||||||
|
handle();
|
||||||
|
if (failed == false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1);
|
||||||
|
uint32_t ms = (uint32_t)(millis() - lastRead);
|
||||||
|
if (ms >= 4000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standby mode. For low power consumption and prolong the life of the sensor.
|
/**
|
||||||
void PMS::sleep() {
|
* @brief Check and read sensor data then update variable.
|
||||||
uint8_t command[] = {0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73};
|
* Check result from method @isFailed before get value
|
||||||
_stream->write(command, sizeof(command));
|
*/
|
||||||
}
|
void PMSBase::handle() {
|
||||||
|
uint32_t ms;
|
||||||
// Operating mode. Stable data should be got at least 30 seconds after the
|
if (lastRead == 0) {
|
||||||
// sensor wakeup from the sleep mode because of the fan's performance.
|
lastRead = millis();
|
||||||
void PMS::wakeUp() {
|
if (lastRead == 0) {
|
||||||
uint8_t command[] = {0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74};
|
lastRead = 1;
|
||||||
_stream->write(command, sizeof(command));
|
}
|
||||||
}
|
} else {
|
||||||
|
ms = (uint32_t)(millis() - lastRead);
|
||||||
// Active mode. Default mode after power up. In this mode sensor would send
|
/**
|
||||||
// serial data to the host automatically.
|
* The PMS in Active mode sends an update data every 1 second. If we read
|
||||||
void PMS::activeMode() {
|
* exactly every 1 sec then we may or may not get an update (depending on
|
||||||
uint8_t command[] = {0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71};
|
* timing tolerances). Hence we read every 2.5 seconds and expect 2 ..3
|
||||||
_stream->write(command, sizeof(command));
|
* updates,
|
||||||
_mode = MODE_ACTIVE;
|
*/
|
||||||
}
|
if (ms < 2500) {
|
||||||
|
return;
|
||||||
// Passive mode. In this mode sensor would send serial data to the host only for
|
}
|
||||||
// request.
|
|
||||||
void PMS::passiveMode() {
|
|
||||||
uint8_t command[] = {0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70};
|
|
||||||
_stream->write(command, sizeof(command));
|
|
||||||
_mode = MODE_PASSIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request read in Passive Mode.
|
|
||||||
void PMS::requestRead() {
|
|
||||||
if (_mode == MODE_PASSIVE) {
|
|
||||||
uint8_t command[] = {0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71};
|
|
||||||
_stream->write(command, sizeof(command));
|
|
||||||
}
|
}
|
||||||
}
|
bool result = false;
|
||||||
|
char buf[32];
|
||||||
|
int bufIndex;
|
||||||
|
int step = 0;
|
||||||
|
int len = 0;
|
||||||
|
int bcount = 0;
|
||||||
|
|
||||||
// Non-blocking function for parse response.
|
while (stream->available()) {
|
||||||
bool PMS::read(DATA &data) {
|
char value = stream->read();
|
||||||
_data = &data;
|
switch (step) {
|
||||||
loop();
|
case 0: {
|
||||||
|
if (value == 0x42) {
|
||||||
return _status == STATUS_OK;
|
step = 1;
|
||||||
}
|
bufIndex = 0;
|
||||||
|
buf[bufIndex++] = value;
|
||||||
// Blocking function for parse response. Default timeout is 1s.
|
}
|
||||||
bool PMS::readUntil(DATA &data, uint16_t timeout) {
|
|
||||||
_data = &data;
|
|
||||||
uint32_t start = millis();
|
|
||||||
do {
|
|
||||||
loop();
|
|
||||||
if (_status == STATUS_OK) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 1: {
|
||||||
/** Relax task to avoid watchdog reset */
|
if (value == 0x4d) {
|
||||||
delay(1);
|
step = 2;
|
||||||
} while (millis() - start < timeout);
|
buf[bufIndex++] = value;
|
||||||
|
// Serial.println("Got 0x4d");
|
||||||
return _status == STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PMS::loop() {
|
|
||||||
_status = STATUS_WAITING;
|
|
||||||
if (_stream->available()) {
|
|
||||||
uint8_t ch = _stream->read();
|
|
||||||
|
|
||||||
switch (_index) {
|
|
||||||
case 0:
|
|
||||||
if (ch != 0x42) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_calculatedChecksum = ch;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
if (ch != 0x4D) {
|
|
||||||
_index = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_calculatedChecksum += ch;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
_calculatedChecksum += ch;
|
|
||||||
_frameLen = ch << 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
_frameLen |= ch;
|
|
||||||
// Unsupported sensor, different frame length, transmission error e.t.c.
|
|
||||||
if (_frameLen != 2 * 9 + 2 && _frameLen != 2 * 13 + 2) {
|
|
||||||
_index = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_calculatedChecksum += ch;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (_index == _frameLen + 2) {
|
|
||||||
_checksum = ch << 8;
|
|
||||||
} else if (_index == _frameLen + 2 + 1) {
|
|
||||||
_checksum |= ch;
|
|
||||||
|
|
||||||
if (_calculatedChecksum == _checksum) {
|
|
||||||
_status = STATUS_OK;
|
|
||||||
|
|
||||||
// Standard Particles, CF=1.
|
|
||||||
_data->PM_SP_UG_1_0 = makeWord(_payload[0], _payload[1]);
|
|
||||||
_data->PM_SP_UG_2_5 = makeWord(_payload[2], _payload[3]);
|
|
||||||
_data->PM_SP_UG_10_0 = makeWord(_payload[4], _payload[5]);
|
|
||||||
|
|
||||||
// Atmospheric Environment.
|
|
||||||
_data->PM_AE_UG_1_0 = makeWord(_payload[6], _payload[7]);
|
|
||||||
_data->PM_AE_UG_2_5 = makeWord(_payload[8], _payload[9]);
|
|
||||||
_data->PM_AE_UG_10_0 = makeWord(_payload[10], _payload[11]);
|
|
||||||
|
|
||||||
// Total particles count per 100ml air
|
|
||||||
_data->PM_RAW_0_3 = makeWord(_payload[12], _payload[13]);
|
|
||||||
_data->PM_RAW_0_5 = makeWord(_payload[14], _payload[15]);
|
|
||||||
_data->PM_RAW_1_0 = makeWord(_payload[16], _payload[17]);
|
|
||||||
_data->PM_RAW_2_5 = makeWord(_payload[18], _payload[19]);
|
|
||||||
_data->PM_RAW_5_0 = makeWord(_payload[20], _payload[21]);
|
|
||||||
_data->PM_RAW_10_0 = makeWord(_payload[22], _payload[23]);
|
|
||||||
|
|
||||||
// Formaldehyde concentration (PMSxxxxST units only)
|
|
||||||
_data->AMB_HCHO = makeWord(_payload[24], _payload[25]) / 1000;
|
|
||||||
|
|
||||||
// Temperature & humidity (PMSxxxxST units only)
|
|
||||||
_data->AMB_TMP = makeWord(_payload[20], _payload[21]);
|
|
||||||
_data->AMB_HUM = makeWord(_payload[22], _payload[23]);
|
|
||||||
}
|
|
||||||
|
|
||||||
_index = 0;
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
_calculatedChecksum += ch;
|
step = 0;
|
||||||
uint8_t payloadIndex = _index - 4;
|
}
|
||||||
|
break;
|
||||||
// Payload is common to all sensors (first 2x6 bytes).
|
}
|
||||||
if (payloadIndex < sizeof(_payload)) {
|
case 2: {
|
||||||
_payload[payloadIndex] = ch;
|
buf[bufIndex++] = value;
|
||||||
|
if (bufIndex >= 4) {
|
||||||
|
len = toValue(&buf[2]);
|
||||||
|
if (len != 28) {
|
||||||
|
// Serial.printf("Got good bad len %d\r\n", len);
|
||||||
|
len += 4;
|
||||||
|
step = 3;
|
||||||
|
} else {
|
||||||
|
// Serial.println("Got good len");
|
||||||
|
step = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
bufIndex++;
|
||||||
|
if (bufIndex >= len) {
|
||||||
|
step = 0;
|
||||||
|
// Serial.println("Bad lengh read all buffer");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
buf[bufIndex++] = value;
|
||||||
|
if (bufIndex >= 32) {
|
||||||
|
result |= validate(buf);
|
||||||
|
step = 0;
|
||||||
|
// Serial.println("Got data");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_index++;
|
// Reduce core panic: delay 1 ms each 32bytes data
|
||||||
|
bcount++;
|
||||||
|
if ((bcount % 32) == 0) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
lastRead = millis();
|
||||||
|
if (lastRead == 0) {
|
||||||
|
lastRead = 1;
|
||||||
|
}
|
||||||
|
failed = false;
|
||||||
|
} else {
|
||||||
|
if (ms > 5000) {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check that PMS send is failed or disconnected
|
||||||
|
*
|
||||||
|
* @return true Failed
|
||||||
|
* @return false No problem
|
||||||
|
*/
|
||||||
|
bool PMSBase::isFailed(void) { return failed; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read PMS 0.1 ug/m3 with CF = 1 PM estimates
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getRaw0_1(void) { return toValue(&package[4]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read PMS 2.5 ug/m3 with CF = 1 PM estimates
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getRaw2_5(void) { return toValue(&package[6]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read PMS 10 ug/m3 with CF = 1 PM estimates
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getRaw10(void) { return toValue(&package[8]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read PMS 0.1 ug/m3
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getPM0_1(void) { return toValue(&package[10]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read PMS 2.5 ug/m3
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getPM2_5(void) { return toValue(&package[12]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read PMS 10 ug/m3
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getPM10(void) { return toValue(&package[14]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get numnber concentrations over 0.3 um/0.1L
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getCount0_3(void) { return toValue(&package[16]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get numnber concentrations over 0.5 um/0.1L
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getCount0_5(void) { return toValue(&package[18]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get numnber concentrations over 1.0 um/0.1L
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getCount1_0(void) { return toValue(&package[20]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get numnber concentrations over 2.5 um/0.1L
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getCount2_5(void) { return toValue(&package[22]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get numnber concentrations over 5.0 um/0.1L (only PMS5003)
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getCount5_0(void) { return toValue(&package[24]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get numnber concentrations over 10.0 um/0.1L (only PMS5003)
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getCount10(void) { return toValue(&package[26]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get temperature (only PMS5003T)
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getTemp(void) { return toValue(&package[24]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get humidity (only PMS5003T)
|
||||||
|
*
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::getHum(void) { return toValue(&package[26]); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert PMS2.5 to US AQI unit
|
||||||
|
*
|
||||||
|
* @param pm02
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int PMSBase::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 Convert two byte value to uint16_t value
|
||||||
|
*
|
||||||
|
* @param buf bytes array (must be >= 2)
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
uint16_t PMSBase::toValue(char *buf) { return (buf[0] << 8) | buf[1]; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validate package data
|
||||||
|
*
|
||||||
|
* @param buf Package buffer
|
||||||
|
* @return true Success
|
||||||
|
* @return false Failed
|
||||||
|
*/
|
||||||
|
bool PMSBase::validate(char *buf) {
|
||||||
|
uint16_t sum = 0;
|
||||||
|
for (int i = 0; i < 30; i++) {
|
||||||
|
sum += buf[i];
|
||||||
|
}
|
||||||
|
if (sum == toValue(&buf[30])) {
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
package[i] = buf[i];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -1,75 +1,43 @@
|
|||||||
#ifndef _PMS_BASE_H_
|
#ifndef _PMS5003_BASE_H_
|
||||||
#define _PMS_BASE_H_
|
#define _PMS5003_BASE_H_
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
/**
|
class PMSBase {
|
||||||
* @brief Class define how to handle plantower PMS sensor it's upport for
|
|
||||||
* PMS5003 and PMS5003T series. The data @ref AMB_TMP and @ref AMB_HUM only
|
|
||||||
* valid on PMS5003T
|
|
||||||
*/
|
|
||||||
class PMS {
|
|
||||||
public:
|
public:
|
||||||
static const uint16_t SINGLE_RESPONSE_TIME = 1000;
|
|
||||||
static const uint16_t TOTAL_RESPONSE_TIME = 1000 * 10;
|
|
||||||
static const uint16_t STEADY_RESPONSE_TIME = 1000 * 30;
|
|
||||||
|
|
||||||
// static const uint16_t BAUD_RATE = 9600;
|
|
||||||
|
|
||||||
struct DATA {
|
|
||||||
// Standard Particles, CF=1
|
|
||||||
uint16_t PM_SP_UG_1_0;
|
|
||||||
uint16_t PM_SP_UG_2_5;
|
|
||||||
uint16_t PM_SP_UG_10_0;
|
|
||||||
|
|
||||||
// Atmospheric environment
|
|
||||||
uint16_t PM_AE_UG_1_0;
|
|
||||||
uint16_t PM_AE_UG_2_5;
|
|
||||||
uint16_t PM_AE_UG_10_0;
|
|
||||||
|
|
||||||
// Raw particles count (number of particles in 0.1l of air
|
|
||||||
uint16_t PM_RAW_0_3;
|
|
||||||
uint16_t PM_RAW_0_5;
|
|
||||||
uint16_t PM_RAW_1_0;
|
|
||||||
uint16_t PM_RAW_2_5;
|
|
||||||
uint16_t PM_RAW_5_0;
|
|
||||||
uint16_t PM_RAW_10_0;
|
|
||||||
|
|
||||||
// Formaldehyde (HCHO) concentration in mg/m^3 - PMSxxxxST units only
|
|
||||||
uint16_t AMB_HCHO;
|
|
||||||
|
|
||||||
// Temperature & humidity - PMSxxxxST units only
|
|
||||||
int16_t AMB_TMP;
|
|
||||||
uint16_t AMB_HUM;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool begin(Stream *stream);
|
bool begin(Stream *stream);
|
||||||
void sleep();
|
void handle();
|
||||||
void wakeUp();
|
bool isFailed(void);
|
||||||
void activeMode();
|
uint16_t getRaw0_1(void);
|
||||||
void passiveMode();
|
uint16_t getRaw2_5(void);
|
||||||
|
uint16_t getRaw10(void);
|
||||||
|
uint16_t getPM0_1(void);
|
||||||
|
uint16_t getPM2_5(void);
|
||||||
|
uint16_t getPM10(void);
|
||||||
|
uint16_t getCount0_3(void);
|
||||||
|
uint16_t getCount0_5(void);
|
||||||
|
uint16_t getCount1_0(void);
|
||||||
|
uint16_t getCount2_5(void);
|
||||||
|
|
||||||
void requestRead();
|
/** For PMS5003 */
|
||||||
bool read(DATA &data);
|
uint16_t getCount5_0(void);
|
||||||
bool readUntil(DATA &data, uint16_t timeout = SINGLE_RESPONSE_TIME);
|
uint16_t getCount10(void);
|
||||||
|
|
||||||
|
/** For PMS5003T*/
|
||||||
|
uint16_t getTemp(void);
|
||||||
|
uint16_t getHum(void);
|
||||||
|
|
||||||
|
int pm25ToAQI(int pm02);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum STATUS { STATUS_WAITING, STATUS_OK };
|
Stream *stream;
|
||||||
enum MODE { MODE_ACTIVE, MODE_PASSIVE };
|
char package[32];
|
||||||
|
int packageIndex;
|
||||||
|
bool failed = false;
|
||||||
|
uint32_t lastRead;
|
||||||
|
|
||||||
uint8_t _payload[50];
|
uint16_t toValue(char *buf);
|
||||||
Stream *_stream;
|
bool validate(char *buf);
|
||||||
DATA *_data;
|
|
||||||
STATUS _status;
|
|
||||||
MODE _mode = MODE_ACTIVE;
|
|
||||||
|
|
||||||
uint8_t _index = 0;
|
|
||||||
uint16_t _frameLen;
|
|
||||||
uint16_t _checksum;
|
|
||||||
uint16_t _calculatedChecksum;
|
|
||||||
|
|
||||||
void loop();
|
|
||||||
char Char_PM2[10];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif /** _PMS5003_BASE_H_ */
|
||||||
|
@ -63,7 +63,8 @@ bool PMS5003::begin(void) {
|
|||||||
|
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
bsp->Pms5003.uart_tx_pin;
|
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);
|
uart->begin(9600);
|
||||||
if (pms.begin(uart) == false) {
|
if (pms.begin(uart) == false) {
|
||||||
AgLog("PMS failed");
|
AgLog("PMS failed");
|
||||||
@ -81,73 +82,33 @@ bool PMS5003::begin(void) {
|
|||||||
return true;
|
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
|
|
||||||
*
|
|
||||||
* @return true Success
|
|
||||||
* @return false Failure
|
|
||||||
*/
|
|
||||||
bool PMS5003::readData(void) {
|
|
||||||
if (this->isBegin() == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pms.readUntil(pmsData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read PM1.0 must call this function after @ref readData success
|
* @brief Read PM1.0 must call this function after @ref readData success
|
||||||
*
|
*
|
||||||
* @return int PM1.0 index
|
* @return int PM1.0 index
|
||||||
*/
|
*/
|
||||||
int PMS5003::getPm01Ae(void) { return pmsData.PM_AE_UG_1_0; }
|
int PMS5003::getPm01Ae(void) { return pms.getPM0_1(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read PM2.5 must call this function after @ref readData success
|
* @brief Read PM2.5 must call this function after @ref readData success
|
||||||
*
|
*
|
||||||
* @return int PM2.5 index
|
* @return int PM2.5 index
|
||||||
*/
|
*/
|
||||||
int PMS5003::getPm25Ae(void) { return pmsData.PM_AE_UG_2_5; }
|
int PMS5003::getPm25Ae(void) { return pms.getPM2_5(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read PM10.0 must call this function after @ref readData success
|
* @brief Read PM10.0 must call this function after @ref readData success
|
||||||
*
|
*
|
||||||
* @return int PM10.0 index
|
* @return int PM10.0 index
|
||||||
*/
|
*/
|
||||||
int PMS5003::getPm10Ae(void) { return pmsData.PM_AE_UG_10_0; }
|
int PMS5003::getPm10Ae(void) { return pms.getPM10(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read PM3.0 must call this function after @ref readData success
|
* @brief Read PM0.3 must call this function after @ref readData success
|
||||||
*
|
*
|
||||||
* @return int PM3.0 index
|
* @return int PM0.3 index
|
||||||
*/
|
*/
|
||||||
int PMS5003::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; }
|
int PMS5003::getPm03ParticleCount(void) { return pms.getCount0_3(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert PM2.5 to US AQI
|
* @brief Convert PM2.5 to US AQI
|
||||||
@ -155,7 +116,7 @@ int PMS5003::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; }
|
|||||||
* @param pm25 PM2.5 index
|
* @param pm25 PM2.5 index
|
||||||
* @return int PM2.5 US AQI
|
* @return int PM2.5 US AQI
|
||||||
*/
|
*/
|
||||||
int PMS5003::convertPm25ToUsAqi(int pm25) { return this->pm25ToAQI(pm25); }
|
int PMS5003::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check device initialized or not
|
* @brief Check device initialized or not
|
||||||
@ -186,3 +147,17 @@ void PMS5003::end(void) {
|
|||||||
#endif
|
#endif
|
||||||
AgLog("De-initialize");
|
AgLog("De-initialize");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check and read PMS sensor data. This method should be callack from
|
||||||
|
* loop process to continoue check sensor data if it's available
|
||||||
|
*/
|
||||||
|
void PMS5003::handle(void) { pms.handle(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get sensor status
|
||||||
|
*
|
||||||
|
* @return true No problem
|
||||||
|
* @return false Communication timeout or sensor has removed
|
||||||
|
*/
|
||||||
|
bool PMS5003::isFailed(void) { return pms.isFailed(); }
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#define _AIR_GRADIENT_PMS5003_H_
|
#define _AIR_GRADIENT_PMS5003_H_
|
||||||
|
|
||||||
#include "../Main/BoardDef.h"
|
#include "../Main/BoardDef.h"
|
||||||
#include "Stream.h"
|
|
||||||
#include "PMS.h"
|
#include "PMS.h"
|
||||||
|
#include "Stream.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The class define how to handle PMS5003 sensor bas on @ref PMS class
|
* @brief The class define how to handle PMS5003 sensor bas on @ref PMS class
|
||||||
@ -17,8 +17,8 @@ public:
|
|||||||
bool begin(HardwareSerial &serial);
|
bool begin(HardwareSerial &serial);
|
||||||
#endif
|
#endif
|
||||||
void end(void);
|
void end(void);
|
||||||
|
void handle(void);
|
||||||
bool readData(void);
|
bool isFailed(void);
|
||||||
int getPm01Ae(void);
|
int getPm01Ae(void);
|
||||||
int getPm25Ae(void);
|
int getPm25Ae(void);
|
||||||
int getPm10Ae(void);
|
int getPm10Ae(void);
|
||||||
@ -28,7 +28,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool _isBegin = false;
|
bool _isBegin = false;
|
||||||
BoardType _boardDef;
|
BoardType _boardDef;
|
||||||
PMS pms;
|
PMSBase pms;
|
||||||
const BoardDef *bsp;
|
const BoardDef *bsp;
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
Stream *_debugStream;
|
Stream *_debugStream;
|
||||||
@ -36,11 +36,7 @@ private:
|
|||||||
#else
|
#else
|
||||||
HardwareSerial *_serial;
|
HardwareSerial *_serial;
|
||||||
#endif
|
#endif
|
||||||
// Conplug_PMS5003T *pms;
|
|
||||||
PMS::DATA pmsData;
|
|
||||||
|
|
||||||
bool begin(void);
|
bool begin(void);
|
||||||
bool isBegin(void);
|
bool isBegin(void);
|
||||||
int pm25ToAQI(int pm02);
|
|
||||||
};
|
};
|
||||||
#endif /** _AIR_GRADIENT_PMS5003_H_ */
|
#endif /** _AIR_GRADIENT_PMS5003_H_ */
|
||||||
|
@ -78,19 +78,21 @@ bool PMS5003T::begin(void) {
|
|||||||
|
|
||||||
#if ARDUINO_USB_CDC_ON_BOOT // Serial used for USB CDC
|
#if ARDUINO_USB_CDC_ON_BOOT // Serial used for USB CDC
|
||||||
if (this->_serial == &Serial0) {
|
if (this->_serial == &Serial0) {
|
||||||
|
AgLog("Init Serial0");
|
||||||
|
_serial->begin(9600, SERIAL_8N1);
|
||||||
#else
|
#else
|
||||||
if (this->_serial == &Serial) {
|
if (this->_serial == &Serial) {
|
||||||
#endif
|
|
||||||
AgLog("Init Serial");
|
AgLog("Init Serial");
|
||||||
this->_serial->begin(9600, SERIAL_8N1, bsp->Pms5003.uart_rx_pin,
|
this->_serial->begin(9600, SERIAL_8N1, bsp->Pms5003.uart_rx_pin,
|
||||||
bsp->Pms5003.uart_tx_pin);
|
bsp->Pms5003.uart_tx_pin);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
|
/** Share with sensor air s8*/
|
||||||
if (bsp->SenseAirS8.supported == false) {
|
if (bsp->SenseAirS8.supported == false) {
|
||||||
AgLog("Board [%d] PMS5003T_2 not supported", this->_boardDef);
|
AgLog("Board [%d] PMS5003T_2 not supported", this->_boardDef);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Share with sensor air s8*/
|
|
||||||
AgLog("Init Serialx");
|
AgLog("Init Serialx");
|
||||||
this->_serial->begin(9600, SERIAL_8N1, bsp->SenseAirS8.uart_rx_pin,
|
this->_serial->begin(9600, SERIAL_8N1, bsp->SenseAirS8.uart_rx_pin,
|
||||||
bsp->SenseAirS8.uart_tx_pin);
|
bsp->SenseAirS8.uart_tx_pin);
|
||||||
@ -105,73 +107,33 @@ bool PMS5003T::begin(void) {
|
|||||||
return true;
|
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
|
|
||||||
*
|
|
||||||
* @return true Success
|
|
||||||
* @return false Failure
|
|
||||||
*/
|
|
||||||
bool PMS5003T::readData(void) {
|
|
||||||
if (this->isBegin() == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pms.readUntil(pmsData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read PM1.0 must call this function after @ref readData success
|
* @brief Read PM1.0 must call this function after @ref readData success
|
||||||
*
|
*
|
||||||
* @return int PM1.0 index
|
* @return int PM1.0 index
|
||||||
*/
|
*/
|
||||||
int PMS5003T::getPm01Ae(void) { return pmsData.PM_AE_UG_1_0; }
|
int PMS5003T::getPm01Ae(void) { return pms.getPM0_1(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read PM2.5 must call this function after @ref readData success
|
* @brief Read PM2.5 must call this function after @ref readData success
|
||||||
*
|
*
|
||||||
* @return int PM2.5 index
|
* @return int PM2.5 index
|
||||||
*/
|
*/
|
||||||
int PMS5003T::getPm25Ae(void) { return pmsData.PM_AE_UG_2_5; }
|
int PMS5003T::getPm25Ae(void) { return pms.getPM2_5(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read PM10.0 must call this function after @ref readData success
|
* @brief Read PM10.0 must call this function after @ref readData success
|
||||||
*
|
*
|
||||||
* @return int PM10.0 index
|
* @return int PM10.0 index
|
||||||
*/
|
*/
|
||||||
int PMS5003T::getPm10Ae(void) { return pmsData.PM_AE_UG_10_0; }
|
int PMS5003T::getPm10Ae(void) { return pms.getPM10(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read PM3.0 must call this function after @ref readData success
|
* @brief Read PM 0.3 Count must call this function after @ref readData success
|
||||||
*
|
*
|
||||||
* @return int PM3.0 index
|
* @return int PM 0.3 Count index
|
||||||
*/
|
*/
|
||||||
int PMS5003T::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; }
|
int PMS5003T::getPm03ParticleCount(void) { return pms.getCount0_3(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert PM2.5 to US AQI
|
* @brief Convert PM2.5 to US AQI
|
||||||
@ -179,7 +141,7 @@ int PMS5003T::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; }
|
|||||||
* @param pm25 PM2.5 index
|
* @param pm25 PM2.5 index
|
||||||
* @return int PM2.5 US AQI
|
* @return int PM2.5 US AQI
|
||||||
*/
|
*/
|
||||||
int PMS5003T::convertPm25ToUsAqi(int pm25) { return this->pm25ToAQI(pm25); }
|
int PMS5003T::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get temperature, Must call this method after @ref readData() success
|
* @brief Get temperature, Must call this method after @ref readData() success
|
||||||
@ -187,7 +149,7 @@ int PMS5003T::convertPm25ToUsAqi(int pm25) { return this->pm25ToAQI(pm25); }
|
|||||||
* @return float Degree Celcius
|
* @return float Degree Celcius
|
||||||
*/
|
*/
|
||||||
float PMS5003T::getTemperature(void) {
|
float PMS5003T::getTemperature(void) {
|
||||||
float temp = pmsData.AMB_TMP;
|
float temp = pms.getTemp();
|
||||||
return correctionTemperature(temp / 10.0f);
|
return correctionTemperature(temp / 10.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,8 +159,8 @@ float PMS5003T::getTemperature(void) {
|
|||||||
* @return float Percent (%)
|
* @return float Percent (%)
|
||||||
*/
|
*/
|
||||||
float PMS5003T::getRelativeHumidity(void) {
|
float PMS5003T::getRelativeHumidity(void) {
|
||||||
float temp = pmsData.AMB_HUM;
|
float hum = pms.getHum();
|
||||||
return temp / 10.0f;
|
return correctionRelativeHumidity(hum / 10.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -234,3 +196,31 @@ void PMS5003T::end(void) {
|
|||||||
#endif
|
#endif
|
||||||
AgLog("De-initialize");
|
AgLog("De-initialize");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check and read PMS sensor data. This method should be callack from
|
||||||
|
* loop process to continoue check sensor data if it's available
|
||||||
|
*/
|
||||||
|
void PMS5003T::handle(void) { pms.handle(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get sensor status
|
||||||
|
*
|
||||||
|
* @return true No problem
|
||||||
|
* @return false Communication timeout or sensor has removed
|
||||||
|
*/
|
||||||
|
bool PMS5003T::isFailed(void) { return pms.isFailed(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Correct the PMS5003T relactive humidity
|
||||||
|
*
|
||||||
|
* @param inHum Input humidity
|
||||||
|
* @return float Corrected humidity
|
||||||
|
*/
|
||||||
|
float PMS5003T::correctionRelativeHumidity(float inHum) {
|
||||||
|
float hum = inHum * 1.259 + 7.34;
|
||||||
|
if (hum > 100.0f) {
|
||||||
|
hum = 100.0f;
|
||||||
|
}
|
||||||
|
return hum;
|
||||||
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#ifndef _PMS5003T_H_
|
#ifndef _PMS5003T_H_
|
||||||
#define _PMS5003T_H_
|
#define _PMS5003T_H_
|
||||||
|
|
||||||
#include <HardwareSerial.h>
|
|
||||||
#include "../Main/BoardDef.h"
|
#include "../Main/BoardDef.h"
|
||||||
#include "PMS.h"
|
#include "PMS.h"
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
|
#include <HardwareSerial.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The class define how to handle PMS5003T sensor bas on @ref PMS class
|
* @brief The class define how to handle PMS5003T sensor bas on @ref PMS class
|
||||||
@ -19,7 +19,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
void end(void);
|
void end(void);
|
||||||
|
|
||||||
bool readData(void);
|
void handle(void);
|
||||||
|
bool isFailed(void);
|
||||||
int getPm01Ae(void);
|
int getPm01Ae(void);
|
||||||
int getPm25Ae(void);
|
int getPm25Ae(void);
|
||||||
int getPm10Ae(void);
|
int getPm10Ae(void);
|
||||||
@ -40,13 +41,11 @@ private:
|
|||||||
#else
|
#else
|
||||||
HardwareSerial *_serial;
|
HardwareSerial *_serial;
|
||||||
#endif
|
#endif
|
||||||
|
PMSBase pms;
|
||||||
bool begin(void);
|
bool begin(void);
|
||||||
int pm25ToAQI(int pm02);
|
|
||||||
PMS pms;
|
|
||||||
PMS::DATA pmsData;
|
|
||||||
bool isBegin(void);
|
bool isBegin(void);
|
||||||
float correctionTemperature(float inTemp);
|
float correctionTemperature(float inTemp);
|
||||||
|
float correctionRelativeHumidity(float inHum);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /** _PMS5003T_H_ */
|
#endif /** _PMS5003T_H_ */
|
||||||
|
@ -228,7 +228,7 @@ int16_t S8::getCo2(void) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t co2 = 0;
|
int16_t co2 = -1;
|
||||||
|
|
||||||
// Ask CO2 value
|
// Ask CO2 value
|
||||||
sendCommand(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR4, 0x0001);
|
sendCommand(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR4, 0x0001);
|
||||||
@ -649,11 +649,25 @@ bool S8::init(int txPin, int rxPin, uint32_t baud) {
|
|||||||
uart->begin(baud);
|
uart->begin(baud);
|
||||||
this->_uartStream = uart;
|
this->_uartStream = uart;
|
||||||
#else
|
#else
|
||||||
|
#if ARDUINO_USB_CDC_ON_BOOT
|
||||||
|
/** The 'Serial0' can ont configure tx, rx pin, only use as default */
|
||||||
|
if (_serial == &Serial0) {
|
||||||
|
AgLog("Init on 'Serial0'");
|
||||||
|
_serial->begin(baud, SERIAL_8N1);
|
||||||
|
} else {
|
||||||
|
AgLog("Init on 'Serialx'");
|
||||||
|
this->_serial->begin(baud, SERIAL_8N1, rxPin, txPin);
|
||||||
|
}
|
||||||
|
this->_uartStream = this->_serial;
|
||||||
|
#else
|
||||||
|
AgLog("Init on 'Serialx'");
|
||||||
this->_serial->begin(baud, SERIAL_8N1, rxPin, txPin);
|
this->_serial->begin(baud, SERIAL_8N1, rxPin, txPin);
|
||||||
this->_uartStream = this->_serial;
|
this->_uartStream = this->_serial;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Check communication by get firmware version */
|
/** Check communication by get firmware version */
|
||||||
|
delay(100);
|
||||||
char fwVers[11];
|
char fwVers[11];
|
||||||
this->_isBegin = true;
|
this->_isBegin = true;
|
||||||
this->getFirmwareVersion(fwVers);
|
this->getFirmwareVersion(fwVers);
|
||||||
@ -712,7 +726,7 @@ uint8_t S8::uartReadBytes(uint8_t max_bytes, uint32_t timeout_ms) {
|
|||||||
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
// Relax 5ms to avoid watchdog reset
|
// Relax 5ms to avoid watchdog reset
|
||||||
vTaskDelay(pdMS_TO_TICKS(5));
|
vTaskDelay(pdMS_TO_TICKS(1));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return nb;
|
return nb;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef _S8_H_
|
#ifndef _S8_H_
|
||||||
#define _S8_H_
|
#define _S8_H_
|
||||||
|
|
||||||
#include "../main/BoardDef.h"
|
#include "../Main/BoardDef.h"
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,7 +91,7 @@ void Sgp41::handle(void) {
|
|||||||
if (getRawSignal(srawVoc, srawNox)) {
|
if (getRawSignal(srawVoc, srawNox)) {
|
||||||
nox = noxAlgorithm()->process(srawNox);
|
nox = noxAlgorithm()->process(srawNox);
|
||||||
tvoc = vocAlgorithm()->process(srawVoc);
|
tvoc = vocAlgorithm()->process(srawVoc);
|
||||||
AgLog("Polling SGP41 success: tvoc: %d, nox: %d", tvoc, nox);
|
// AgLog("Polling SGP41 success: tvoc: %d, nox: %d", tvoc, nox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,9 +121,10 @@ void Sgp41::_handle(void) {
|
|||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
if (getRawSignal(srawVoc, srawNox)) {
|
if (getRawSignal(srawVoc, srawNox)) {
|
||||||
tvocRaw = srawVoc;
|
tvocRaw = srawVoc;
|
||||||
|
noxRaw = srawNox;
|
||||||
nox = noxAlgorithm()->process(srawNox);
|
nox = noxAlgorithm()->process(srawNox);
|
||||||
tvoc = vocAlgorithm()->process(srawVoc);
|
tvoc = vocAlgorithm()->process(srawVoc);
|
||||||
AgLog("Polling SGP41 success: tvoc: %d, nox: %d", tvoc, nox);
|
// AgLog("Polling SGP41 success: tvoc: %d, nox: %d", tvoc, nox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,3 +250,23 @@ bool Sgp41::_noxConditioning(void) {
|
|||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int Sgp41::getTvocRaw(void) { return tvocRaw; }
|
int Sgp41::getTvocRaw(void) { return tvocRaw; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get NOX raw value
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int Sgp41::getNoxRaw(void) { return noxRaw; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set compasation temperature and humidity to calculate TVOC and NOx
|
||||||
|
* index
|
||||||
|
*
|
||||||
|
* @param temp Temperature
|
||||||
|
* @param hum Humidity
|
||||||
|
*/
|
||||||
|
void Sgp41::setCompensationTemperatureHumidity(float temp, float hum) {
|
||||||
|
defaultT = static_cast<uint16_t>((temp + 45) * 65535 / 175);
|
||||||
|
defaultRh = static_cast<uint16_t>(hum * 65535 / 100);
|
||||||
|
AgLog("Update: defaultT: %d, defaultRh: %d", defaultT, defaultRh);
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef _AIR_GRADIENT_SGP4X_H_
|
#ifndef _AIR_GRADIENT_SGP4X_H_
|
||||||
#define _AIR_GRADIENT_SGP4X_H_
|
#define _AIR_GRADIENT_SGP4X_H_
|
||||||
|
|
||||||
#include "../main/BoardDef.h"
|
#include "../Main/BoardDef.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
|
|
||||||
@ -24,6 +24,8 @@ public:
|
|||||||
int getTvocIndex(void);
|
int getTvocIndex(void);
|
||||||
int getNoxIndex(void);
|
int getNoxIndex(void);
|
||||||
int getTvocRaw(void);
|
int getTvocRaw(void);
|
||||||
|
int getNoxRaw(void);
|
||||||
|
void setCompensationTemperatureHumidity(float temp, float hum);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool onConditioning = true;
|
bool onConditioning = true;
|
||||||
@ -39,6 +41,7 @@ private:
|
|||||||
int tvoc = 0;
|
int tvoc = 0;
|
||||||
int tvocRaw;
|
int tvocRaw;
|
||||||
int nox = 0;
|
int nox = 0;
|
||||||
|
int noxRaw;
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
uint32_t conditioningPeriod;
|
uint32_t conditioningPeriod;
|
||||||
uint8_t conditioningCount;
|
uint8_t conditioningCount;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef _SHT_H_
|
#ifndef _SHT_H_
|
||||||
#define _SHT_H_
|
#define _SHT_H_
|
||||||
|
|
||||||
#include "../main/BoardDef.h"
|
#include "../Main/BoardDef.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user