Serial1 on ESP32-C3 defaults to wrong GPIOs. SPS30 wrapper
called begin(115200) without pin args, so Serial1 mapped to
floating pins instead of GPIO 0/1 (S8 connector).
Mirror PMS5003T::begin() pattern: Serial0 uses UART0 defaults,
Serial1 uses SenseAirS8 rx/tx pins from BoardDef.
- iaqsHandleLeds renders one LED per score tick (score 10 -> 1 LED,
score 0 -> 11 LEDs); old 9-LED cap removed.
- In IAQS mode, WiFiLost/ServerLost/SensorConfigFailed clear the bar
and light only LED 0 with the status color, so the notification
stays visible at any score. PM/CO2 modes keep their overlay path.
New 'iaqs' value for ledBarMode renders the GO IAQS Starter Score
(PM2.5 + CO2) on the ONE_INDOOR LED bar. Color from category
(Good/Moderate/Unhealthy), LEDs lit from severity; 9-LED cap
mirrors existing PM/CO2 modes so LEDs 0-1 stay free for
connectivity overlays.
Server sends "scalingFactorViaPm25" instead of "scalingFactor"
when correctionAlgorithm is custom_via_pm25_raw. Previous code
always looked for "scalingFactor", causing validation failure.
Skips 10-minute AT+COPS=? scan on boot when prior operator
state exists. Saves serialized operator list and last successful
operator ID to SPIFFS via Configuration class. Restores before
registration in begin() and ensureClientConnection(), saves only
on success.
- Replace #error with inline stub class on ESP8266 so AirGradient.h
compiles on all platforms
- Fully reset serial port before SPS30 detection (end/begin cycle,
flush RX buffer) to clear stale 9600-baud state from PMS5003
- Add deviceReset() call to put sensor in known state before probing
Add Sensirion SPS30 as an alternative PM sensor on the ONE_INDOOR
board, auto-detected at boot when PMS5003 is not found on Serial0.
- Add SPS30 UART wrapper class (src/SPS30/) following PMS5003 pattern
- Auto-detect: try PMS5003 (9600 baud) first, fall back to SPS30
(115200 baud) on the same serial port
- Map SPS30 mass concentrations to both Ae and SP fields
- Convert SPS30 number concentrations from #/cm³ to #/0.1L (×100)
- PM0.3 and PM5.0 bins set to invalid (SPS30 lacks these)
- Remove bundled SensirionCore v0.6.0 in favor of PlatformIO-managed
v0.7.3 to avoid duplicate symbol conflicts
Use sizeof on the names arrays instead of hardcoding the last enum
value. Prevents the loop from missing new algorithms when the enum
is extended. Also fixes the same pattern in matchTempHumAlgorithm.
The loop bound in matchPmAlgorithm was set to COR_ALGO_PM_SLR_CUSTOM + 1,
which excluded COR_ALGO_PM_SLR_FACTORY_CALIBRATION from being matched.
Devices configured with factory calibration silently fell back to
COR_ALGO_PM_UNKNOWN, resulting in uncorrected PM2.5 readings.