Merge pull request #342 from mtlynch/no-trailing-spaces

Eliminate trailing whitespace
This commit is contained in:
Samuel Siburian
2025-09-25 13:45:11 +07:00
committed by GitHub
25 changed files with 148 additions and 117 deletions

View File

@@ -1,5 +1,36 @@
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
trailing-whitespace:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- name: Check for trailing whitespace
run: |
set -u
# Don't enforce checks on vendored libraries.
readonly EXCLUDED_DIR='src/Libraries'
has_trailing_whitespace=false
while read -r line; do
if grep \
"\s$" \
--line-number \
--with-filename \
--binary-files=without-match \
"${line}"; then
has_trailing_whitespace=true
fi
done < <(git ls-files | grep --invert-match "^${EXCLUDED_DIR}/")
if [ "$has_trailing_whitespace" = true ]; then
echo "ERROR: Found trailing whitespace"
exit 1
fi
compile: compile:
strategy: strategy:
fail-fast: false fail-fast: false

View File

@@ -32,7 +32,7 @@ Each GitHub release note will also include the planned rollout date for wider av
## Help & Support ## Help & Support
If you have any questions or problems, check out [our forum](https://forum.airgradient.com/). If you have any questions or problems, check out [our forum](https://forum.airgradient.com/).
## Development ## Development

View File

@@ -16,15 +16,15 @@ Arduino IDE version 2.x ([download](https://www.arduino.cc/en/software))
#### Version < 3.2.0 #### Version < 3.2.0
Using library manager install the latest version (Tools ➝ Manage Libraries... ➝ search for `"airgradient"`) Using library manager install the latest version (Tools ➝ Manage Libraries... ➝ search for `"airgradient"`)
![Aigradient Library](images/ag-lib.png) ![Aigradient Library](images/ag-lib.png)
#### Version >= 3.3.0 #### Version >= 3.3.0
- From your terminal, go to Arduino libraries folder (windows and mac: `Documents/Arduino/libraries` or linux: `~/Arduino/Libraries`). - From your terminal, go to Arduino libraries folder (windows and mac: `Documents/Arduino/libraries` or linux: `~/Arduino/Libraries`).
- With **git** cli, execute this command `git clone --recursive https://github.com/airgradienthq/arduino.git AirGradient_Air_Quality_Sensor` - With **git** cli, execute this command `git clone --recursive https://github.com/airgradienthq/arduino.git AirGradient_Air_Quality_Sensor`
- Restart Arduino IDE - Restart Arduino IDE
3. On tools tab, follow settings below 3. On tools tab, follow settings below
@@ -57,7 +57,7 @@ Upload Speed ➝ 921600
![board manager](images/esp8266-board.png) ![board manager](images/esp8266-board.png)
3. Install AirGradient library on library manager using the latest version (Tools ➝ Manage Libraries... ➝ search for `"airgradient"`) 3. Install AirGradient library on library manager using the latest version (Tools ➝ Manage Libraries... ➝ search for `"airgradient"`)
![Aigradient Library](images/ag-lib.png) ![Aigradient Library](images/ag-lib.png)
@@ -65,7 +65,7 @@ Upload Speed ➝ 921600
![settings esp8266](images/settings-esp8266.png) ![settings esp8266](images/settings-esp8266.png)
5. Open sketch to compile (File ➝ Examples ➝ AirGradient Air Quality Sensor ➝ `<Model Option>`). Depends on the DIY model, either `BASIC`, `DiyProIndoorV3_3` and `DiyProIndoorV4_2` 5. Open sketch to compile (File ➝ Examples ➝ AirGradient Air Quality Sensor ➝ `<Model Option>`). Depends on the DIY model, either `BASIC`, `DiyProIndoorV3_3` and `DiyProIndoorV4_2`
6. Compile 6. Compile
![compiled esp8266](images/compiled-esp8266.png) ![compiled esp8266](images/compiled-esp8266.png)
@@ -78,13 +78,13 @@ ModuleNotFoundError: No module named serial
![Linux Failed](images/linux-failed.png) ![Linux Failed](images/linux-failed.png)
Make sure python pyserial module installed globally in the environment by executing: Make sure python pyserial module installed globally in the environment by executing:
`$ sudo apt install -y python3-pyserial` `$ sudo apt install -y python3-pyserial`
or or
`$ pip install pyserial` `$ pip install pyserial`
Choose based on how python installed on your machine. But most user, using `apt` is better. Choose based on how python installed on your machine. But most user, using `apt` is better.

View File

@@ -1,6 +1,6 @@
## Local Server API ## Local Server API
From [firmware version 3.0.10](firmwares) onwards, the AirGradient ONE and Open Air monitors have below API available. From [firmware version 3.0.10](firmwares) onwards, the AirGradient ONE and Open Air monitors have below API available.
### Discovery ### Discovery
@@ -20,7 +20,7 @@ http://airgradient_ecda3b1eaaaf.local/measures/current
“ecda3b1eaaaf” being the serial number of your monitor. “ecda3b1eaaaf” being the serial number of your monitor.
You get the following response: You get the following response:
```json ```json
{ {
"wifi": -46, "wifi": -46,
"serialno": "ecda3b1eaaaf", "serialno": "ecda3b1eaaaf",
@@ -84,7 +84,7 @@ Compensated values apply correction algorithms to make the sensor values more ac
"/config" path returns the current configuration of the monitor. "/config" path returns the current configuration of the monitor.
```json ```json
{ {
"country": "TH", "country": "TH",
"pmStandard": "ugm3", "pmStandard": "ugm3",
@@ -118,22 +118,22 @@ Configuration parameters can be changed with a PUT request to the monitor, e.g.
Example to force CO2 calibration Example to force CO2 calibration
```bash ```bash
curl -X PUT -H "Content-Type: application/json" -d '{"co2CalibrationRequested":true}' http://airgradient_84fce612eff4.local/config curl -X PUT -H "Content-Type: application/json" -d '{"co2CalibrationRequested":true}' http://airgradient_84fce612eff4.local/config
``` ```
Example to set monitor to Celsius Example to set monitor to Celsius
```bash ```bash
curl -X PUT -H "Content-Type: application/json" -d '{"temperatureUnit":"c"}' http://airgradient_84fce612eff4.local/config curl -X PUT -H "Content-Type: application/json" -d '{"temperatureUnit":"c"}' http://airgradient_84fce612eff4.local/config
``` ```
If you use command prompt on Windows, you need to escape the quotes: If you use command prompt on Windows, you need to escape the quotes:
``` -d "{\"param\":\"value\"}" ``` ``` -d "{\"param\":\"value\"}" ```
### Avoiding Conflicts with Configuration on AirGradient Server ### Avoiding Conflicts with Configuration on AirGradient Server
If the monitor is set up on the AirGradient dashboard, it will also receive the configuration parameters from there. In case you do not want this, please set `configurationControl` to `local`. In case you set it to `cloud` and want to change it to `local`, you need to make a factory reset. If the monitor is set up on the AirGradient dashboard, it will also receive the configuration parameters from there. In case you do not want this, please set `configurationControl` to `local`. In case you set it to `cloud` and want to change it to `local`, you need to make a factory reset.
### Configuration Parameters (GET/PUT) ### Configuration Parameters (GET/PUT)
@@ -204,34 +204,34 @@ Example correction configuration:
Field Name: `pm02` Field Name: `pm02`
| Algorithm | Value | Description | SLR required | | Algorithm | Value | Description | SLR required |
|------------|-------------|------|---------| |------------|-------------|------|---------|
| Raw | `"none"` | No correction (default) | No | | Raw | `"none"` | No correction (default) | No |
| EPA 2021 | `"epa_2021"` | Use EPA 2021 correction factors on top of raw value | No | | EPA 2021 | `"epa_2021"` | Use EPA 2021 correction factors on top of raw value | No |
| PMS5003_20240104 | `"slr_PMS5003_20240104"` | Correction for PMS5003 sensor batch 20240104| Yes | | PMS5003_20240104 | `"slr_PMS5003_20240104"` | Correction for PMS5003 sensor batch 20240104| Yes |
| PMS5003_20231218 | `"slr_PMS5003_20231218"` | Correction for PMS5003 sensor batch 20231218| Yes | | PMS5003_20231218 | `"slr_PMS5003_20231218"` | Correction for PMS5003 sensor batch 20231218| Yes |
| PMS5003_20231030 | `"slr_PMS5003_20231030"` | Correction for PMS5003 sensor batch 20231030| Yes | | PMS5003_20231030 | `"slr_PMS5003_20231030"` | Correction for PMS5003 sensor batch 20231030| Yes |
**NOTES**: **NOTES**:
- Set `useEpa2021` to `true` if want to apply EPA 2021 correction factors on top of SLR correction value, otherwise `false` - Set `useEpa2021` to `true` if want to apply EPA 2021 correction factors on top of SLR correction value, otherwise `false`
- `intercept` and `scalingFactor` values can be obtained from [this article](https://www.airgradient.com/blog/low-readings-from-pms5003/) - `intercept` and `scalingFactor` values can be obtained from [this article](https://www.airgradient.com/blog/low-readings-from-pms5003/)
- If `configurationControl` is set to `local` (eg. when using Home Assistant), correction need to be set manually, see examples below - If `configurationControl` is set to `local` (eg. when using Home Assistant), correction need to be set manually, see examples below
**Examples**: **Examples**:
- PMS5003_20231030 - PMS5003_20231030
```bash ```bash
curl --location -X PUT 'http://airgradient_84fce612eff4.local/config' --header 'Content-Type: application/json' --data '{"corrections":{"pm02":{"correctionAlgorithm":"slr_PMS5003_20231030","slr":{"intercept":0,"scalingFactor":0.02838,"useEpa2021":true}}}}' curl --location -X PUT 'http://airgradient_84fce612eff4.local/config' --header 'Content-Type: application/json' --data '{"corrections":{"pm02":{"correctionAlgorithm":"slr_PMS5003_20231030","slr":{"intercept":0,"scalingFactor":0.02838,"useEpa2021":true}}}}'
``` ```
- PMS5003_20231218 - PMS5003_20231218
```bash ```bash
curl --location -X PUT 'http://airgradient_84fce612eff4.local/config' --header 'Content-Type: application/json' --data '{"corrections":{"pm02":{"correctionAlgorithm":"slr_PMS5003_20231218","slr":{"intercept":0,"scalingFactor":0.03525,"useEpa2021":true}}}}' curl --location -X PUT 'http://airgradient_84fce612eff4.local/config' --header 'Content-Type: application/json' --data '{"corrections":{"pm02":{"correctionAlgorithm":"slr_PMS5003_20231218","slr":{"intercept":0,"scalingFactor":0.03525,"useEpa2021":true}}}}'
``` ```
- PMS5003_20240104 - PMS5003_20240104
```bash ```bash
curl --location -X PUT 'http://airgradient_84fce612eff4.local/config' --header 'Content-Type: application/json' --data '{"corrections":{"pm02":{"correctionAlgorithm":"slr_PMS5003_20240104","slr":{"intercept":0,"scalingFactor":0.02896,"useEpa2021":true}}}}' curl --location -X PUT 'http://airgradient_84fce612eff4.local/config' --header 'Content-Type: application/json' --data '{"corrections":{"pm02":{"correctionAlgorithm":"slr_PMS5003_20240104","slr":{"intercept":0,"scalingFactor":0.02896,"useEpa2021":true}}}}'
@@ -244,10 +244,10 @@ Field Name:
- Humidity: `rhum` - Humidity: `rhum`
| Algorithm | Value | Description | SLR required | | Algorithm | Value | Description | SLR required |
|------------|-------------|------|---------| |------------|-------------|------|---------|
| Raw | `"none"` | No correction (default) | No | | Raw | `"none"` | No correction (default) | No |
| AirGradient Standard Correction | `"ag_pms5003t_2024"` | Using standard airgradient correction (for outdoor monitor)| No | | AirGradient Standard Correction | `"ag_pms5003t_2024"` | Using standard airgradient correction (for outdoor monitor)| No |
| Custom | `"custom"` | custom corrections constant, set `intercept` and `scalingFactor` manually | Yes | | Custom | `"custom"` | custom corrections constant, set `intercept` and `scalingFactor` manually | Yes |
*Table above apply for both Temperature and Humidity* *Table above apply for both Temperature and Humidity*

View File

@@ -1,6 +1,6 @@
## OTA Updates ## OTA Updates
From [firmware version 3.1.1](https://github.com/airgradienthq/arduino/tree/3.1.1) onwards, the AirGradient ONE and Open Air monitors support over the air (OTA) updates. From [firmware version 3.1.1](https://github.com/airgradienthq/arduino/tree/3.1.1) onwards, the AirGradient ONE and Open Air monitors support over the air (OTA) updates.
#### Mechanism #### Mechanism
@@ -10,7 +10,7 @@ The device attempts to update to the latest version on startup and in regular in
http://hw.airgradient.com/sensors/{deviceId}/generic/os/firmware.bin?current_firmware={GIT_VERSION} http://hw.airgradient.com/sensors/{deviceId}/generic/os/firmware.bin?current_firmware={GIT_VERSION}
If does pass the version it is currently running on along to the server through URL parameter 'current_firmware'. If does pass the version it is currently running on along to the server through URL parameter 'current_firmware'.
This allows the server to identify if the device is already running on the latest version or should update. This allows the server to identify if the device is already running on the latest version or should update.
The following scenarios are possible The following scenarios are possible

View File

@@ -249,7 +249,7 @@ void loop() {
configUpdateHandle(); configUpdateHandle();
localServer._handle(); localServer._handle();
if (configuration.hasSensorSGP) { if (configuration.hasSensorSGP) {
ag.sgp41.handle(); ag.sgp41.handle();
} }

View File

@@ -75,8 +75,8 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 6000 /** ms */ #define SENSOR_TEMP_HUM_UPDATE_INTERVAL 6000 /** ms */
#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */ #define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
#define FIRMWARE_CHECK_FOR_UPDATE_MS (60 * 60 * 1000) /** ms */ #define FIRMWARE_CHECK_FOR_UPDATE_MS (60 * 60 * 1000) /** ms */
#define TIME_TO_START_POWER_CYCLE_CELLULAR_MODULE (1 * 60) /** minutes */ #define TIME_TO_START_POWER_CYCLE_CELLULAR_MODULE (1 * 60) /** minutes */
#define TIMEOUT_WAIT_FOR_CELLULAR_MODULE_READY (2 * 60) /** minutes */ #define TIMEOUT_WAIT_FOR_CELLULAR_MODULE_READY (2 * 60) /** minutes */
#define MEASUREMENT_TRANSMIT_CYCLE 3 #define MEASUREMENT_TRANSMIT_CYCLE 3
#define MAXIMUM_MEASUREMENT_CYCLE_QUEUE 80 #define MAXIMUM_MEASUREMENT_CYCLE_QUEUE 80
@@ -123,7 +123,7 @@ static uint32_t factoryBtnPressTime = 0;
static AgFirmwareMode fwMode = FW_MODE_I_9PSL; static AgFirmwareMode fwMode = FW_MODE_I_9PSL;
static bool ledBarButtonTest = false; static bool ledBarButtonTest = false;
static String fwNewVersion; static String fwNewVersion;
static int lastCellSignalQuality = 99; // CSQ static int lastCellSignalQuality = 99; // CSQ
// Default value is 0, indicate its not started yet // Default value is 0, indicate its not started yet
// In minutes // In minutes
@@ -136,7 +136,7 @@ static void boardInit(void);
static void initializeNetwork(); static void initializeNetwork();
static void failedHandler(String msg); static void failedHandler(String msg);
static void configurationUpdateSchedule(void); static void configurationUpdateSchedule(void);
static void configUpdateHandle(void); static void configUpdateHandle(void);
static void updateDisplayAndLedBar(void); static void updateDisplayAndLedBar(void);
static void updateTvoc(void); static void updateTvoc(void);
static void updatePm(void); static void updatePm(void);
@@ -157,7 +157,7 @@ static void displayExecuteOta(AirgradientOTA::OtaResult result, String msg, int
static int calculateMaxPeriod(int updateInterval); static int calculateMaxPeriod(int updateInterval);
static void setMeasurementMaxPeriod(); static void setMeasurementMaxPeriod();
static void newMeasurementCycle(); static void newMeasurementCycle();
static void restartIfCeClientIssueOverTwoHours(); static void restartIfCeClientIssueOverTwoHours();
static void networkSignalCheck(); static void networkSignalCheck();
static void networkingTask(void *args); static void networkingTask(void *args);
@@ -180,7 +180,7 @@ void setup() {
Serial.begin(115200); Serial.begin(115200);
delay(100); /** For bester show log */ delay(100); /** For bester show log */
// Enable cullular module power board // Enable cullular module power board
pinMode(GPIO_EXPANSION_CARD_POWER, OUTPUT); pinMode(GPIO_EXPANSION_CARD_POWER, OUTPUT);
digitalWrite(GPIO_EXPANSION_CARD_POWER, HIGH); digitalWrite(GPIO_EXPANSION_CARD_POWER, HIGH);
@@ -284,7 +284,7 @@ void setup() {
// Queue now only applied for cellular // Queue now only applied for cellular
// Allocate queue memory to avoid always reallocation // Allocate queue memory to avoid always reallocation
measurementCycleQueue.reserve(RESERVED_MEASUREMENT_CYCLE_CAPACITY); measurementCycleQueue.reserve(RESERVED_MEASUREMENT_CYCLE_CAPACITY);
// Initialize mutex to access mesurementCycleQueue // Initialize mutex to access mesurementCycleQueue
mutexMeasurementCycleQueue = xSemaphoreCreateMutex(); mutexMeasurementCycleQueue = xSemaphoreCreateMutex();
} }
@@ -312,7 +312,7 @@ void setup() {
void loop() { void loop() {
if (networkOption == UseCellular) { if (networkOption == UseCellular) {
// Check if cellular client not ready until certain time // Check if cellular client not ready until certain time
// Redundant check in both task to make sure its executed // Redundant check in both task to make sure its executed
restartIfCeClientIssueOverTwoHours(); restartIfCeClientIssueOverTwoHours();
} }
@@ -725,7 +725,7 @@ static void sendDataToAg() {
"task_led", 2048, NULL, 5, NULL); "task_led", 2048, NULL, 5, NULL);
delay(1500); delay(1500);
// Build payload to check connection to airgradient server // Build payload to check connection to airgradient server
JSONVar root; JSONVar root;
root["wifi"] = wifiConnector.RSSI(); root["wifi"] = wifiConnector.RSSI();
@@ -970,7 +970,7 @@ void initializeNetwork() {
agSerial->init(GPIO_IIC_RESET); agSerial->init(GPIO_IIC_RESET);
if (agSerial->open()) { if (agSerial->open()) {
Serial.println("Cellular module found"); Serial.println("Cellular module found");
// Initialize cellular module and use cellular as agClient // Initialize cellular module and use cellular as agClient
cellularCard = new CellularModuleA7672XX(agSerial, GPIO_POWER_MODULE_PIN); cellularCard = new CellularModuleA7672XX(agSerial, GPIO_POWER_MODULE_PIN);
agClient = new AirgradientCellularClient(cellularCard); agClient = new AirgradientCellularClient(cellularCard);
networkOption = UseCellular; networkOption = UseCellular;
@@ -984,7 +984,7 @@ void initializeNetwork() {
} }
if (networkOption == UseCellular) { if (networkOption == UseCellular) {
// Enable serial stream debugging to check the AT command when doing registration // Enable serial stream debugging to check the AT command when doing registration
agSerial->setDebug(true); agSerial->setDebug(true);
} }
@@ -1005,7 +1005,7 @@ void initializeNetwork() {
ESP.restart(); ESP.restart();
} }
// Provide openmetrics to have access to last transmission result // Provide openmetrics to have access to last transmission result
openMetrics.setAirgradientClient(agClient); openMetrics.setAirgradientClient(agClient);
if (networkOption == UseCellular) { if (networkOption == UseCellular) {
@@ -1018,7 +1018,7 @@ void initializeNetwork() {
Serial.println("Cannot initiate wifi connection"); Serial.println("Cannot initiate wifi connection");
return; return;
} }
if (!wifiConnector.isConnected()) { if (!wifiConnector.isConnected()) {
Serial.println("Failed connect to WiFi"); Serial.println("Failed connect to WiFi");
if (wifiConnector.isConfigurePorttalTimeout()) { if (wifiConnector.isConfigurePorttalTimeout()) {
@@ -1027,17 +1027,17 @@ void initializeNetwork() {
oledDisplay.setText("", "", ""); oledDisplay.setText("", "", "");
ESP.restart(); ESP.restart();
} }
// Directly return because the rest of the function applied if wifi is connect only // Directly return because the rest of the function applied if wifi is connect only
return; return;
} }
// Initiate local network configuration // Initiate local network configuration
mdnsInit(); mdnsInit();
localServer.begin(); localServer.begin();
// Apply mqtt connection if configured // Apply mqtt connection if configured
initMqtt(); initMqtt();
// Ignore the rest if cloud connection to AirGradient is disabled // Ignore the rest if cloud connection to AirGradient is disabled
if (configuration.isCloudConnectionDisabled()) { if (configuration.isCloudConnectionDisabled()) {
return; return;
@@ -1202,7 +1202,7 @@ static void updateDisplayAndLedBar(void) {
} }
if (configuration.isCloudConnectionDisabled()) { if (configuration.isCloudConnectionDisabled()) {
// Ignore API related check since cloud is disabled // Ignore API related check since cloud is disabled
stateMachine.displayHandle(AgStateMachineNormal); stateMachine.displayHandle(AgStateMachineNormal);
stateMachine.handleLeds(AgStateMachineNormal); stateMachine.handleLeds(AgStateMachineNormal);
return; return;
@@ -1395,7 +1395,7 @@ void postUsingWifi() {
void postUsingCellular(bool forcePost) { void postUsingCellular(bool forcePost) {
// Aquire queue mutex to get queue size // Aquire queue mutex to get queue size
xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY); xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY);
// Make sure measurement cycle available // Make sure measurement cycle available
int queueSize = measurementCycleQueue.size(); int queueSize = measurementCycleQueue.size();
if (queueSize == 0) { if (queueSize == 0) {
@@ -1405,7 +1405,7 @@ void postUsingCellular(bool forcePost) {
} }
// Check queue size if its ready to transmit // Check queue size if its ready to transmit
// It is ready if size is divisible by 3 // It is ready if size is divisible by 3
if (!forcePost && (queueSize % MEASUREMENT_TRANSMIT_CYCLE) > 0) { if (!forcePost && (queueSize % MEASUREMENT_TRANSMIT_CYCLE) > 0) {
Serial.printf("Not ready to transmit, queue size are %d\n", queueSize); Serial.printf("Not ready to transmit, queue size are %d\n", queueSize);
xSemaphoreGive(mutexMeasurementCycleQueue); xSemaphoreGive(mutexMeasurementCycleQueue);
@@ -1426,7 +1426,7 @@ void postUsingCellular(bool forcePost) {
// Attempt to send // Attempt to send
if (agClient->httpPostMeasures(payload) == false) { if (agClient->httpPostMeasures(payload) == false) {
// Consider network has a problem, retry in next schedule // Consider network has a problem, retry in next schedule
Serial.println("Post measures failed, retry in next schedule"); Serial.println("Post measures failed, retry in next schedule");
return; return;
} }
@@ -1527,7 +1527,7 @@ void setMeasurementMaxPeriod() {
int calculateMaxPeriod(int updateInterval) { int calculateMaxPeriod(int updateInterval) {
// 0.8 is 80% reduced interval for max period // 0.8 is 80% reduced interval for max period
// NOTE: Both network option use the same measurement interval // NOTE: Both network option use the same measurement interval
return (WIFI_MEASUREMENT_INTERVAL - (WIFI_MEASUREMENT_INTERVAL * 0.8)) / updateInterval; return (WIFI_MEASUREMENT_INTERVAL - (WIFI_MEASUREMENT_INTERVAL * 0.8)) / updateInterval;
} }
@@ -1544,7 +1544,7 @@ void networkSignalCheck() {
} }
// Save last signal quality // Save last signal quality
lastCellSignalQuality = result.data; lastCellSignalQuality = result.data;
if (result.data == 99) { if (result.data == 99) {
// 99 indicate cellular not attached to network // 99 indicate cellular not attached to network
@@ -1557,7 +1557,7 @@ void networkSignalCheck() {
} }
/** /**
* If in 2 hours cellular client still not ready, then restart system * If in 2 hours cellular client still not ready, then restart system
*/ */
void restartIfCeClientIssueOverTwoHours() { void restartIfCeClientIssueOverTwoHours() {
if (agCeClientProblemDetectedTime > 0 && if (agCeClientProblemDetectedTime > 0 &&
@@ -1622,10 +1622,10 @@ void networkingTask(void *args) {
} }
// Enable at command debug // Enable at command debug
agSerial->setDebug(true); agSerial->setDebug(true);
// Check if cellular client not ready until certain time // Check if cellular client not ready until certain time
// Redundant check in both task to make sure its executed // Redundant check in both task to make sure its executed
restartIfCeClientIssueOverTwoHours(); restartIfCeClientIssueOverTwoHours();
// Power cycling cellular module due to network issues for more than 1 hour // Power cycling cellular module due to network issues for more than 1 hour
@@ -1676,14 +1676,14 @@ void networkingTask(void *args) {
void newMeasurementCycle() { void newMeasurementCycle() {
if (xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY) == pdTRUE) { if (xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY) == pdTRUE) {
// Make sure queue not overflow // Make sure queue not overflow
if (measurementCycleQueue.size() >= MAXIMUM_MEASUREMENT_CYCLE_QUEUE) { if (measurementCycleQueue.size() >= MAXIMUM_MEASUREMENT_CYCLE_QUEUE) {
// Remove the oldest data from queue if queue reach max // Remove the oldest data from queue if queue reach max
measurementCycleQueue.erase(measurementCycleQueue.begin()); measurementCycleQueue.erase(measurementCycleQueue.begin());
} }
// Get current measures // Get current measures
auto mc = measurements.getMeasures(); auto mc = measurements.getMeasures();
mc.signal = cellularCard->csqToDbm(lastCellSignalQuality); // convert to RSSI mc.signal = cellularCard->csqToDbm(lastCellSignalQuality); // convert to RSSI
measurementCycleQueue.push_back(mc); measurementCycleQueue.push_back(mc);

View File

@@ -6,8 +6,8 @@ OpenMetrics::OpenMetrics(Measurements &measure, Configuration &config,
OpenMetrics::~OpenMetrics() {} OpenMetrics::~OpenMetrics() {}
void OpenMetrics::setAirGradient(AirGradient *ag) { void OpenMetrics::setAirGradient(AirGradient *ag) {
this->ag = ag; this->ag = ag;
} }
void OpenMetrics::setAirgradientClient(AirgradientClient *client) { void OpenMetrics::setAirgradientClient(AirgradientClient *client) {

View File

@@ -15,7 +15,7 @@ framework = arduino
build_flags = !echo '-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 -D AG_LOG_LEVEL=AG_LOG_LEVEL_INFO -D GIT_VERSION=\\"'$(git describe --tags --always --dirty)'\\"' build_flags = !echo '-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 -D AG_LOG_LEVEL=AG_LOG_LEVEL_INFO -D GIT_VERSION=\\"'$(git describe --tags --always --dirty)'\\"'
board_build.partitions = partitions.csv board_build.partitions = partitions.csv
monitor_speed = 115200 monitor_speed = 115200
lib_deps = lib_deps =
aglib=symlink://../arduino aglib=symlink://../arduino
EEPROM EEPROM
WebServer WebServer
@@ -32,7 +32,7 @@ platform = espressif8266
board = d1_mini board = d1_mini
framework = arduino framework = arduino
monitor_speed = 115200 monitor_speed = 115200
lib_deps = lib_deps =
aglib=symlink://../arduino aglib=symlink://../arduino
EEPROM EEPROM
ESP8266HTTPClient ESP8266HTTPClient

View File

@@ -47,7 +47,7 @@ bool AgApiClient::fetchServerConfiguration(void) {
} }
#else #else
HTTPClient client; HTTPClient client;
client.setConnectTimeout(timeoutMs); // Set timeout when establishing connection to server client.setConnectTimeout(timeoutMs); // Set timeout when establishing connection to server
client.setTimeout(timeoutMs); // Timeout when waiting for response from AG server client.setTimeout(timeoutMs); // Timeout when waiting for response from AG server
if (apiRootChanged) { if (apiRootChanged) {
// If apiRoot is changed, assume not using https // If apiRoot is changed, assume not using https
@@ -114,7 +114,7 @@ bool AgApiClient::postToServer(String data) {
} }
#else #else
HTTPClient client; HTTPClient client;
client.setConnectTimeout(timeoutMs); // Set timeout when establishing connection to server client.setConnectTimeout(timeoutMs); // Set timeout when establishing connection to server
client.setTimeout(timeoutMs); // Timeout when waiting for response from AG server client.setTimeout(timeoutMs); // Timeout when waiting for response from AG server
if (apiRootChanged) { if (apiRootChanged) {
// If apiRoot is changed, assume not using https // If apiRoot is changed, assume not using https
@@ -185,13 +185,13 @@ void AgApiClient::setAirGradient(AirGradient *ag) { this->ag = ag; }
/** /**
* @brief Send the package to check the connection with cloud * @brief Send the package to check the connection with cloud
* *
* @param rssi WiFi RSSI * @param rssi WiFi RSSI
* @param bootCount Boot count * @param bootCount Boot count
* @return true Success * @return true Success
* @return false Failure * @return false Failure
*/ */
bool AgApiClient::sendPing(int rssi, int bootCount) { bool AgApiClient::sendPing(int rssi, int bootCount) {
JSONVar root; JSONVar root;
root["wifi"] = rssi; root["wifi"] = rssi;
root["boot"] = bootCount; root["boot"] = bootCount;

View File

@@ -114,7 +114,7 @@ PMCorrectionAlgorithm Configuration::matchPmAlgorithm(String algorithm) {
const size_t enumSize = COR_ALGO_PM_SLR_CUSTOM + 1; // Get the actual size of the enum const size_t enumSize = COR_ALGO_PM_SLR_CUSTOM + 1; // Get the actual size of the enum
PMCorrectionAlgorithm result = COR_ALGO_PM_UNKNOWN;; PMCorrectionAlgorithm result = COR_ALGO_PM_UNKNOWN;;
// Loop through enum values // Loop through enum values
for (size_t enumVal = 0; enumVal < enumSize; enumVal++) { for (size_t enumVal = 0; enumVal < enumSize; enumVal++) {
if (algorithm == PM_CORRECTION_ALGORITHM_NAMES[enumVal]) { if (algorithm == PM_CORRECTION_ALGORITHM_NAMES[enumVal]) {
@@ -122,7 +122,7 @@ PMCorrectionAlgorithm Configuration::matchPmAlgorithm(String algorithm) {
} }
} }
// If string not match from enum, check if correctionAlgorithm is one of the PM batch corrections // If string not match from enum, check if correctionAlgorithm is one of the PM batch corrections
if (result == COR_ALGO_PM_UNKNOWN) { if (result == COR_ALGO_PM_UNKNOWN) {
// Check the substring "slr_PMS5003_xxxxxxxx" // Check the substring "slr_PMS5003_xxxxxxxx"
if (algorithm.substring(0, 11) == "slr_PMS5003") { if (algorithm.substring(0, 11) == "slr_PMS5003") {
@@ -749,7 +749,7 @@ bool Configuration::parse(String data, bool isLocal) {
} }
else if (JSON.typeof_(root[jprop_mqttBrokerUrl]) == "null" and !isLocal) { else if (JSON.typeof_(root[jprop_mqttBrokerUrl]) == "null" and !isLocal) {
// So if its not available on the json and json comes from aigradient server // So if its not available on the json and json comes from aigradient server
// then set its value to default (empty) // then set its value to default (empty)
jconfig[jprop_mqttBrokerUrl] = jprop_mqttBrokerUrl_default; jconfig[jprop_mqttBrokerUrl] = jprop_mqttBrokerUrl_default;
} }
else { else {
@@ -1073,7 +1073,7 @@ String Configuration::getMqttBrokerUri(void) {
} }
/** /**
* @brief Get HTTP domain for post measures and get configuration * @brief Get HTTP domain for post measures and get configuration
* *
* @return String http domain, might be empty string * @return String http domain, might be empty string
*/ */
@@ -1562,13 +1562,13 @@ void Configuration::setDisableCloudConnection(bool disable) {
saveConfig(); saveConfig();
} }
bool Configuration::isLedBarModeChanged(void) { bool Configuration::isLedBarModeChanged(void) {
bool changed = _ledBarModeChanged; bool changed = _ledBarModeChanged;
_ledBarModeChanged = false; _ledBarModeChanged = false;
return changed; return changed;
} }
bool Configuration::isMonitorDisplayCompensatedValues(void) { bool Configuration::isMonitorDisplayCompensatedValues(void) {
return jconfig[jprop_monitorDisplayCompensatedValues]; return jconfig[jprop_monitorDisplayCompensatedValues];
} }
@@ -1591,8 +1591,8 @@ bool Configuration::isPMCorrectionChanged(void) {
} }
/** /**
* @brief Check if PM correction is enabled * @brief Check if PM correction is enabled
* *
* @return true if PM correction algorithm is not None, otherwise false * @return true if PM correction algorithm is not None, otherwise false
*/ */
bool Configuration::isPMCorrectionEnabled(void) { bool Configuration::isPMCorrectionEnabled(void) {

View File

@@ -568,7 +568,7 @@ float Measurements::getAverage(MeasurementType type, int ch) {
assert(0); assert(0);
} }
return measurementAverage; return measurementAverage;
} }
String Measurements::pms5003FirmwareVersion(int fwCode) { String Measurements::pms5003FirmwareVersion(int fwCode) {
@@ -895,7 +895,7 @@ std::string Measurements::buildMeasuresPayload(Measures &mc) {
oss << ","; oss << ",";
// Temperature // Temperature
if (utils::isValidTemperature(mc.temperature[0]) && utils::isValidTemperature(mc.temperature[1])) { if (utils::isValidTemperature(mc.temperature[0]) && utils::isValidTemperature(mc.temperature[1])) {
float temp = (mc.temperature[0] + mc.temperature[1]) / 2.0f; float temp = (mc.temperature[0] + mc.temperature[1]) / 2.0f;
oss << std::round(temp * 10); oss << std::round(temp * 10);

View File

@@ -149,7 +149,7 @@ public:
* *
* @param type measurement type that will be retrieve * @param type measurement type that will be retrieve
* @param ch target type value channel * @param ch target type value channel
* @return moving average value of target measurements type * @return moving average value of target measurements type
*/ */
float getAverage(MeasurementType type, int ch = 1); float getAverage(MeasurementType type, int ch = 1);

View File

@@ -358,7 +358,7 @@ bool WifiConnector::isConnected(void) { return WiFi.isConnected(); }
* this method * this method
* *
*/ */
void WifiConnector::reset(void) { void WifiConnector::reset(void) {
if(this->wifi == NULL) { if(this->wifi == NULL) {
this->wifi = new WiFiManager(); this->wifi = new WiFiManager();
if(this->wifi == NULL){ if(this->wifi == NULL){
@@ -366,7 +366,7 @@ void WifiConnector::reset(void) {
return; return;
} }
} }
WIFI()->resetSettings(); WIFI()->resetSettings();
} }
/** /**
@@ -406,7 +406,7 @@ bool WifiConnector::isConfigurePorttalTimeout(void) { return connectorTimeout; }
/** /**
* @brief Set wifi connect to default WiFi * @brief Set wifi connect to default WiFi
* *
*/ */
void WifiConnector::setDefault(void) { void WifiConnector::setDefault(void) {
WiFi.begin("airgradient", "cleanair"); WiFi.begin("airgradient", "cleanair");

View File

@@ -1,7 +1,7 @@
#include "AirGradient.h" #include "AirGradient.h"
#ifdef ESP8266 #ifdef ESP8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#else #else
#include "WiFi.h" #include "WiFi.h"
#endif #endif
@@ -57,7 +57,7 @@ String AirGradient::getBoardName(void) {
/** /**
* @brief Board Type is ONE_INDOOR * @brief Board Type is ONE_INDOOR
* *
* @return true ONE_INDOOR * @return true ONE_INDOOR
* @return false Other * @return false Other
*/ */
@@ -65,15 +65,15 @@ bool AirGradient::isOne(void) {
return boardType == BoardType::ONE_INDOOR; return boardType == BoardType::ONE_INDOOR;
} }
bool AirGradient::isOpenAir(void) { bool AirGradient::isOpenAir(void) {
return boardType == BoardType::OPEN_AIR_OUTDOOR; return boardType == BoardType::OPEN_AIR_OUTDOOR;
} }
bool AirGradient::isPro4_2(void) { bool AirGradient::isPro4_2(void) {
return boardType == BoardType::DIY_PRO_INDOOR_V4_2; return boardType == BoardType::DIY_PRO_INDOOR_V4_2;
} }
bool AirGradient::isPro3_3(void) { bool AirGradient::isPro3_3(void) {
return boardType == BoardType::DIY_PRO_INDOOR_V3_3; return boardType == BoardType::DIY_PRO_INDOOR_V3_3;
} }

View File

@@ -177,9 +177,9 @@ public:
/** /**
* @brief Check that Airgradient object is OPEN_AIR * @brief Check that Airgradient object is OPEN_AIR
* *
* @return true * @return true
* @return false * @return false
*/ */
bool isOpenAir(void); bool isOpenAir(void);

View File

@@ -27,7 +27,7 @@ enum BoardType {
/** /**
* @brief Board definitions * @brief Board definitions
* *
*/ */
struct BoardDef { struct BoardDef {
/** Board Support CO2 SenseS8 */ /** Board Support CO2 SenseS8 */

View File

@@ -6,7 +6,7 @@
/** /**
* @brief The class define how to handle the LED * @brief The class define how to handle the LED
* *
*/ */
class StatusLed { class StatusLed {
public: public:

View File

@@ -316,10 +316,10 @@ int PMSBase::pm25ToAQI(int pm02) {
/** /**
* @brief SLR correction for PM2.5 * @brief SLR correction for PM2.5
* *
* Reference: https://www.airgradient.com/blog/low-readings-from-pms5003/ * Reference: https://www.airgradient.com/blog/low-readings-from-pms5003/
* *
* @param pm25 PM2.5 raw value * @param pm25 PM2.5 raw value
* @param pm003Count PM0.3 count * @param pm003Count PM0.3 count
* @param scalingFactor Scaling factor * @param scalingFactor Scaling factor

View File

@@ -35,7 +35,7 @@ public:
/** For PMS5003T*/ /** For PMS5003T*/
int16_t getTemp(void); int16_t getTemp(void);
uint16_t getHum(void); uint16_t getHum(void);
uint8_t getFirmwareVersion(void); uint8_t getFirmwareVersion(void);
uint8_t getErrorCode(void); uint8_t getErrorCode(void);
int pm25ToAQI(int pm02); int pm25ToAQI(int pm02);

View File

@@ -189,21 +189,21 @@ float PMS5003::compensate(float pm25, float humidity) { return pms.compensate(pm
/** /**
* @brief Get sensor firmware version * @brief Get sensor firmware version
* *
* @return int * @return int
*/ */
int PMS5003::getFirmwareVersion(void) { return _ver; } int PMS5003::getFirmwareVersion(void) { return _ver; }
/** /**
* @brief Get sensor error code * @brief Get sensor error code
* *
* @return uint8_t * @return uint8_t
*/ */
uint8_t PMS5003::getErrorCode(void) { return pms.getErrorCode(); } uint8_t PMS5003::getErrorCode(void) { return pms.getErrorCode(); }
/** /**
* @brief Is sensor connect with device * @brief Is sensor connect with device
* *
* @return true Connected * @return true Connected
* @return false Removed * @return false Removed
*/ */
@@ -255,14 +255,14 @@ void PMS5003::resetFailCount(void) {
/** /**
* @brief Get number of fail count * @brief Get number of fail count
* *
* @return int * @return int
*/ */
int PMS5003::getFailCount(void) { return pms.getFailCount(); } int PMS5003::getFailCount(void) { return pms.getFailCount(); }
/** /**
* @brief Get number of fail count max * @brief Get number of fail count max
* *
* @return int * @return int
*/ */
int PMS5003::getFailCountMax(void) { return pms.getFailCountMax(); } int PMS5003::getFailCountMax(void) { return pms.getFailCountMax(); }

View File

@@ -218,21 +218,21 @@ float PMS5003T::compensate(float pm25, float humidity) { return pms.compensate(p
/** /**
* @brief Get module(s) firmware version * @brief Get module(s) firmware version
* *
* @return int Version code * @return int Version code
*/ */
int PMS5003T::getFirmwareVersion(void) { return _ver; } int PMS5003T::getFirmwareVersion(void) { return _ver; }
/** /**
* @brief Get sensor error code * @brief Get sensor error code
* *
* @return uint8_t * @return uint8_t
*/ */
uint8_t PMS5003T::getErrorCode(void) { return pms.getErrorCode(); } uint8_t PMS5003T::getErrorCode(void) { return pms.getErrorCode(); }
/** /**
* @brief Is sensor connect to device * @brief Is sensor connect to device
* *
* @return true Connected * @return true Connected
* @return false Removed * @return false Removed
*/ */
@@ -281,14 +281,14 @@ void PMS5003T::resetFailCount(void) {
/** /**
* @brief Get fail count * @brief Get fail count
* *
* @return int * @return int
*/ */
int PMS5003T::getFailCount(void) { return pms.getFailCount(); } int PMS5003T::getFailCount(void) { return pms.getFailCount(); }
/** /**
* @brief Get fail count max * @brief Get fail count max
* *
* @return int * @return int
*/ */
int PMS5003T::getFailCountMax(void) { return pms.getFailCountMax(); } int PMS5003T::getFailCountMax(void) { return pms.getFailCountMax(); }

View File

@@ -6,11 +6,11 @@ PMS5003TBase::~PMS5003TBase() {}
/** /**
* @brief Compensate the temperature * @brief Compensate the temperature
* *
* Reference formula: https://www.airgradient.com/documentation/correction-algorithms/ * Reference formula: https://www.airgradient.com/documentation/correction-algorithms/
* *
* @param temp * @param temp
* @return * float * @return * float
*/ */
float PMS5003TBase::compensateTemp(float temp) { float PMS5003TBase::compensateTemp(float temp) {
if (temp < 10.0f) { if (temp < 10.0f) {
@@ -21,11 +21,11 @@ float PMS5003TBase::compensateTemp(float temp) {
/** /**
* @brief Compensate the humidity * @brief Compensate the humidity
* *
* Reference formula: https://www.airgradient.com/documentation/correction-algorithms/ * Reference formula: https://www.airgradient.com/documentation/correction-algorithms/
* *
* @param temp * @param temp
* @return * float * @return * float
*/ */
float PMS5003TBase::compensateHum(float hum) { float PMS5003TBase::compensateHum(float hum) {
hum = hum * 1.259f + 7.34f; hum = hum * 1.259f + 7.34f;

View File

@@ -4,7 +4,7 @@
class PMS5003TBase class PMS5003TBase
{ {
private: private:
public: public:
PMS5003TBase(); PMS5003TBase();
~PMS5003TBase(); ~PMS5003TBase();

View File

@@ -140,7 +140,7 @@ void Sgp41::pause() {
tvoc = utils::getInvalidVOC(); tvoc = utils::getInvalidVOC();
noxRaw = utils::getInvalidNOx(); noxRaw = utils::getInvalidNOx();
nox = utils::getInvalidNOx(); nox = utils::getInvalidNOx();
} }
void Sgp41::resume() { void Sgp41::resume() {
onPause = false; onPause = false;