Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
7f042a0
Move PMSA003I to separate class and update AQ telemetry
oscgonfer Jul 1, 2025
835adb2
AirQualityTelemetry module not depend on PM sensor presence
oscgonfer Jul 1, 2025
3b470b7
Remove commented line
oscgonfer Jul 2, 2025
2f68458
Fixes on PMS class
oscgonfer Jul 2, 2025
e4903eb
Add missing warmup period to wakeUp function
oscgonfer Jul 2, 2025
9111f88
Fixes on compilation for different variants
oscgonfer Jul 6, 2025
40af7b8
Add functions to check for I2C bus speed and set it
oscgonfer Jul 11, 2025
ff8691d
Add ScreenFonts.h
oscgonfer Jul 12, 2025
0dda175
PMSA003I 1st round test
Nashui-Yan Jul 22, 2025
14eaa3e
Fix I2C scan speed
oscgonfer Jul 23, 2025
8a811b2
Fix minor issues and bring back I2C SPEED def
oscgonfer Jul 23, 2025
ec5a752
Remove PMSA003I library as its no longer needed
oscgonfer Jul 25, 2025
f7a9e27
Merge branch 'master' into enhancement/air-quality-module
oscgonfer Aug 4, 2025
417f5a8
Add functional SCD4X
oscgonfer Jul 2, 2025
00349c3
Fix screen frame for CO2
oscgonfer Jul 17, 2025
8a4f5c1
Add admin commands to SCD4X class
oscgonfer Jul 29, 2025
2609f45
Add further admin commands and fixes.
oscgonfer Aug 4, 2025
b23605a
Merge branch 'master' into enhancement/air-quality-module
thebentern Aug 5, 2025
a129441
Remove unused I2C speed functions and cleanup
oscgonfer Aug 6, 2025
bb3ec31
Merge branch 'master' into enhancement/air-quality-module
oscgonfer Aug 30, 2025
8ec036a
Merge branch 'master' into enhancement/air-quality-module
thebentern Sep 9, 2025
6d45a86
Merge branch 'master' into enhancement/air-quality-module
thebentern Sep 10, 2025
24b3a22
Unify build epoch to add flag in platformio-custom.py (#7917)
thebentern Sep 10, 2025
0827bd0
Fix build error in rak_wismesh_tap_v2 (#7905)
fifieldt Sep 8, 2025
0b900dd
Put guards in place around debug heap operations (#7955)
thebentern Sep 11, 2025
7b75468
Cleanup
thebentern Sep 11, 2025
d7ef19b
Fix memory leak in NextHopRouter: always free packet copy when removi…
compumike Sep 12, 2025
ab09d9b
Formatting
thebentern Sep 12, 2025
4aa5e91
Only queue 2 client notification
thebentern Sep 12, 2025
8468bf9
Merge pull request #7965 from compumike/compumike/fix-nrf52-bluetooth…
thebentern Sep 12, 2025
8d1b20d
Merge pull request #7964 from compumike/compumike/fix-nimble-bluetoot…
thebentern Sep 12, 2025
9f25738
Update protobufs (#7973)
github-actions[bot] Sep 13, 2025
a5876f8
T-Lora Pager: Support LR1121 and SX1280 models (#7956)
WillyJL Sep 13, 2025
1d757ba
Trunk
thebentern Sep 13, 2025
375ab36
Trunk
thebentern Sep 13, 2025
33ffa8d
Static memory pool allocation (#7966)
thebentern Sep 13, 2025
55b42b9
Portduino dynamic alloc
thebentern Sep 13, 2025
1da6d28
Missed
thebentern Sep 13, 2025
3092ec7
Drop the limit
thebentern Sep 13, 2025
569c0d2
Update meshtastic-esp8266-oled-ssd1306 digest to 0cbc26b (#7977)
renovate[bot] Sep 13, 2025
2fe065d
Fix json report crashes on esp32 (#7978)
thebentern Sep 13, 2025
d9eb18f
Tweak maximums
thebentern Sep 13, 2025
9fdd31a
Fix DRAM overflow on old esp32 targets
thebentern Sep 14, 2025
e9fb1b5
Guard bad time warning logs using GPS_DEBUG (#7897)
fifieldt Sep 8, 2025
4b4609f
Scale probe buffer size based on current baud rate (#7975)
thebentern Sep 14, 2025
aea2072
Fix GPS gm_mktime memory leak (#7981)
compumike Sep 14, 2025
520c479
Fix overflow of time value (#7984)
thebentern Sep 14, 2025
7c1fea0
Remove PMSA003 include from modules
oscgonfer Sep 14, 2025
247b399
Merge branch 'master' into enhancement/air-quality-module
oscgonfer Jan 7, 2026
44f5e06
Add flag to exclude air quality module
oscgonfer Jan 7, 2026
d893954
Rework PMSA003I to align with new I2C scanner
oscgonfer Jan 8, 2026
23f82c9
Move add sensor template to separate file
oscgonfer Jan 10, 2026
80f63b6
Split telemetry on screen options
oscgonfer Jan 10, 2026
998726e
Add variable I2C clock compile flag
oscgonfer Jan 12, 2026
9d75bcc
Merge branch 'master' into enhancement/air-quality-module
oscgonfer Jan 12, 2026
aa943a9
Fix drawFrame in AQ module
oscgonfer Jan 12, 2026
7f35c38
Module settings override to i2cScan module function
oscgonfer Jan 12, 2026
25e4319
Move to CAN_RECLOCK_I2C per architecture
oscgonfer Jan 12, 2026
322b250
Merge branch 'master' into enhancement/air-quality-module
oscgonfer Jan 12, 2026
0d420eb
Minor fix
oscgonfer Jan 12, 2026
d9c6afc
Merge branch 'master' into enhancement/air-quality-module
thebentern Jan 12, 2026
a134f41
Move I2C reclock function to src/detect
oscgonfer Jan 14, 2026
886d542
Fix uninitMemberVar errors and compile issue
oscgonfer Jan 14, 2026
068009e
Make sleep, wakeUp functions generic
oscgonfer Jan 14, 2026
fa0d88d
Merge branch 'master' into enhancement/air-quality-module
oscgonfer Jan 14, 2026
d641206
Fix STM32 builds
oscgonfer Jan 14, 2026
d7b36d0
Merge branch 'master' into enhancement/air-quality-module
thebentern Jan 14, 2026
f61e4c9
SEN5X first pass
oscgonfer Jul 6, 2025
f9924d0
WIP Sen5X functions
oscgonfer Jul 7, 2025
aa02a24
Further (non-working) progress in SEN5X
oscgonfer Jul 8, 2025
2261ae5
WIP Sen5X functions
oscgonfer Jul 7, 2025
5788a7b
Changes on SEN5X library - removing pm_env as well
oscgonfer Jul 15, 2025
5068c8b
Small cleanup of SEN5X sensors
oscgonfer Jul 15, 2025
7988af4
Minor change for SEN5X detection
oscgonfer Jul 15, 2025
697c120
Remove dup code
oscgonfer Jul 15, 2025
e4de0d0
Enable PM sensor before sending telemetry.
oscgonfer Jul 17, 2025
03b10c4
Small cleanups in SEN5X sensor
oscgonfer Jul 17, 2025
4e9b66a
Add dynamic measurement interval for SEN5X
oscgonfer Jul 17, 2025
6df0f88
Only disable SEN5X if enough time after reading.
oscgonfer Jul 17, 2025
c9fd77a
Idle for SEN5X on communication error
oscgonfer Jul 17, 2025
e54acf5
Cleanup of logs and remove unnecessary delays
oscgonfer Jul 18, 2025
5284215
Small TODO
oscgonfer Jul 22, 2025
eaf6cb5
Settle on uint16_t for SEN5X PM data
oscgonfer Jul 23, 2025
c45e0bf
Make AQTelemetry sensors non-exclusive
oscgonfer Jul 23, 2025
94750ed
Implementation of cleaning in FS prefs and cleanup
oscgonfer Aug 5, 2025
7f51253
Bring back detection code for SEN5X after branch rebase
oscgonfer Aug 6, 2025
456ee95
Add placeholder for admin message
oscgonfer Aug 7, 2025
f722ce0
Add VOC measurements and persistence (WIP)
oscgonfer Aug 7, 2025
8194be0
Add one-shot mode config flag to SEN5X
oscgonfer Aug 26, 2025
53f43dc
Add nan checks on sensor data from SEN5X
oscgonfer Aug 26, 2025
972aec1
Working implementation on VOCState
oscgonfer Aug 30, 2025
9ac258d
Fixes on VOC state and mode swtiching
oscgonfer Sep 14, 2025
31da50a
Adapt SEN5X to new sensor list structure. Improve reclock.
oscgonfer Jan 17, 2026
4fd2ed7
Merge branch 'master' into feat/add-sen5x
oscgonfer Jan 17, 2026
457eac3
Fix merge errors
oscgonfer Jan 17, 2026
0d455e1
Merge branch 'feat/add-sen5x' into feat/add-scd4x
oscgonfer Jan 18, 2026
d547c4c
Small reordering in PMS class for consistency
oscgonfer Jan 18, 2026
2f95db2
If one sensor fails, AQ telemetry still reports data
oscgonfer Jan 18, 2026
f6cd9db
Small formatting fix
oscgonfer Jan 18, 2026
b4a2560
Add SEN5X to AQI in ScanI2C
oscgonfer Jan 18, 2026
52ca090
SCD4X now part of AQ module with template list
oscgonfer Jan 18, 2026
c6c97f1
Remove unnecessary import
oscgonfer Jan 18, 2026
26a05c3
Add co2 to serialized AQ metrics
oscgonfer Jan 20, 2026
7b995e1
Merge branch 'master' into feat/add-scd4x
oscgonfer Jan 20, 2026
46ff9ec
Merge branch 'master' into feat/add-sen5x
oscgonfer Jan 20, 2026
958923d
Update library dependencies in platformio.ini
oscgonfer Jan 20, 2026
8d8e116
Merge branch 'master' into feat/add-sen5x
oscgonfer Jan 27, 2026
588a700
Merge branch 'feat/add-sen5x' into feat/add-scd4x
oscgonfer Jan 27, 2026
1e34ee2
Merge branch 'master' into feat/add-scd4x
thebentern Jan 27, 2026
712c43a
Merge branch 'master' into feat/add-sen5x
oscgonfer Jan 28, 2026
d1f1cf4
Fix unitialized variables in SEN5X constructor
oscgonfer Jan 28, 2026
74aedc9
Merge branch 'feat/add-sen5x' into feat/add-scd4x
oscgonfer Jan 28, 2026
cdf6183
Fix missing import
oscgonfer Jan 28, 2026
18cf9f7
Merge branch 'feat/add-sen5x' into feat/add-scd4x
oscgonfer Jan 28, 2026
105206c
Fix uninitMemberVars
oscgonfer Jan 28, 2026
637e0c6
Fix import error for SCD4X
oscgonfer Jan 28, 2026
66a1fc0
Fix I2CClock logic
oscgonfer Jan 28, 2026
5cfbc65
Fix multiple sensors being read simultaneously
oscgonfer Jan 28, 2026
d44ceb6
Fix NimBLE deinit null check
thebentern Jan 28, 2026
94d7b71
Merge branch 'develop'
thebentern Jan 29, 2026
03084f6
PRs with needs-review still should get bot labeled
thebentern Jan 29, 2026
b18742c
Update libch341-spi-userspace digest to af9bc27 (#9472)
renovate[bot] Jan 29, 2026
4edfca9
Merge branch 'master' into feat/add-scd4x
thebentern Jan 29, 2026
7f4f078
Fix pending clock change in PMSA003
oscgonfer Jan 30, 2026
95a425b
First proposal for nested telemetry protos in AQ module
oscgonfer Jan 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/models_pr_triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ jobs:

# ─────────────────────────────────────────────────────────────────────────
# Step 3: Auto-label PR type (bugfix/hardware-support/enhancement)
# Only skip for spam/ai-generated; still classify needs-review PRs
# ─────────────────────────────────────────────────────────────────────────
- name: Classify PR for labeling
if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '')
if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && steps.quality.outputs.response != 'spam' && steps.quality.outputs.response != 'ai-generated'
uses: actions/ai-inference@v2
id: classify
continue-on-error: true
Expand Down
3 changes: 2 additions & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ lib_deps =
sensirion/Sensirion [email protected]
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
sensirion/Sensirion I2C [email protected]

; Same as environmental_extra but without BSEC (saves ~3.5KB DRAM for original ESP32 targets)
[environmental_extra_no_bsec]
lib_deps =
Expand All @@ -239,4 +240,4 @@ lib_deps =
# renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core
sensirion/Sensirion [email protected]
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
sensirion/Sensirion I2C [email protected]
sensirion/Sensirion I2C [email protected]
1 change: 1 addition & 0 deletions src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BQ27220_ADDR 0x55 // same address as TDECK_KB
#define BQ25896_ADDR 0x6B
#define LTR553ALS_ADDR 0x23
#define SEN5X_ADDR 0x69

// -----------------------------------------------------------------------------
// ACCELEROMETER
Expand Down
2 changes: 1 addition & 1 deletion src/detect/ScanI2C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const

ScanI2C::FoundDevice ScanI2C::firstAQI() const
{
ScanI2C::DeviceType types[] = {PMSA003I, SCD4X};
ScanI2C::DeviceType types[] = {PMSA003I, SEN5X, SCD4X};
return firstOfOrNONE(2, types);
}

Expand Down
3 changes: 2 additions & 1 deletion src/detect/ScanI2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ class ScanI2C
BH1750,
DA217,
CHSC6X,
CST226SE
CST226SE,
SEN5X
} DeviceType;

// typedef uint8_t DeviceAddress;
Expand Down
71 changes: 63 additions & 8 deletions src/detect/ScanI2CTwoWire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "meshUtils.h" // vformat

#endif

bool in_array(uint8_t *array, int size, uint8_t lookfor)
Expand Down Expand Up @@ -114,6 +115,42 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation
return value;
}

/// for SEN5X detection
// Note, this code needs to be called before setting the I2C bus speed
// for the screen at high speed. The speed needs to be at 100kHz, otherwise
// detection will not work
String readSEN5xProductName(TwoWire* i2cBus, uint8_t address) {
uint8_t cmd[] = { 0xD0, 0x14 };
uint8_t response[48] = {0};

i2cBus->beginTransmission(address);
i2cBus->write(cmd, 2);
if (i2cBus->endTransmission() != 0) return "";

delay(20);
if (i2cBus->requestFrom(address, (uint8_t)48) != 48) return "";

for (int i = 0; i < 48 && i2cBus->available(); ++i) {
response[i] = i2cBus->read();
}

char productName[33] = {0};
int j = 0;
for (int i = 0; i < 48 && j < 32; i += 3) {
if (response[i] >= 32 && response[i] <= 126)
productName[j++] = response[i];
else
break;

if (response[i + 1] >= 32 && response[i + 1] <= 126)
productName[j++] = response[i + 1];
else
break;
}

return String(productName);
}

#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
case ADDR: \
logFoundDevice(__VA_ARGS__); \
Expand Down Expand Up @@ -568,8 +605,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
break;

case ICM20948_ADDR: // same as BMX160_ADDR
case ICM20948_ADDR: // same as BMX160_ADDR and SEN5X_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
// ICM20948 Register check
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
#ifdef HAS_ICM20948
type = ICM20948;
Expand All @@ -580,14 +618,31 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
type = ICM20948;
logFoundDevice("ICM20948", (uint8_t)addr.address);
break;
} else if (addr.address == BMX160_ADDR) {
type = BMX160;
logFoundDevice("BMX160", (uint8_t)addr.address);
break;
} else {
type = MPU6050;
logFoundDevice("MPU6050", (uint8_t)addr.address);
break;
String prod = "";
prod = readSEN5xProductName(i2cBus, addr.address);
if (prod.startsWith("SEN55")) {
type = SEN5X;
logFoundDevice("Sensirion SEN55", addr.address);
break;
} else if (prod.startsWith("SEN54")) {
type = SEN5X;
logFoundDevice("Sensirion SEN54", addr.address);
break;
} else if (prod.startsWith("SEN50")) {
type = SEN5X;
logFoundDevice("Sensirion SEN50", addr.address);
break;
}
if (addr.address == BMX160_ADDR) {
type = BMX160;
logFoundDevice("BMX160", (uint8_t)addr.address);
break;
} else {
type = MPU6050;
logFoundDevice("MPU6050", (uint8_t)addr.address);
break;
}
}
break;

Expand Down
31 changes: 31 additions & 0 deletions src/detect/reClockI2C.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "reClockI2C.h"
#include "ScanI2CTwoWire.h"

uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, bool force) {

uint32_t currentClock = 0;

/* See https://github.com/arduino/Arduino/issues/11457
Currently, only ESP32 can getClock()
While all cores can setClock()
https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50
https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60
https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103
For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes)
we need to reclock I2C and set it back to the previous desired speed.
Only for cases where we can know OR predefine the speed, we can do this.
*/

// TODO add getClock function or return a predefined clock speed per variant?
#ifdef CAN_RECLOCK_I2C
currentClock = i2cBus->getClock();
#endif

if ((currentClock != desiredClock) || force){
LOG_DEBUG("Changing I2C clock to %u", desiredClock);
i2cBus->setClock(desiredClock);
}

return currentClock;
}

42 changes: 6 additions & 36 deletions src/detect/reClockI2C.h
Original file line number Diff line number Diff line change
@@ -1,41 +1,11 @@
#ifdef CAN_RECLOCK_I2C
#include "ScanI2CTwoWire.h"

uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus)
{

uint32_t currentClock;
#ifndef RECLOCK_I2C_
#define RECLOCK_I2C_

/* See https://github.com/arduino/Arduino/issues/11457
Currently, only ESP32 can getClock()
While all cores can setClock()
https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50
https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60
https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103
For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes)
we need to reclock I2C and set it back to the previous desired speed.
Only for cases where we can know OR predefine the speed, we can do this.
*/
#include "ScanI2CTwoWire.h"
#include <stdint.h>
#include <Wire.h>

#ifdef ARCH_ESP32
currentClock = i2cBus->getClock();
#elif defined(ARCH_NRF52)
// TODO add getClock function or return a predefined clock speed per variant?
return 0;
#elif defined(ARCH_RP2040)
// TODO add getClock function or return a predefined clock speed per variant
return 0;
#elif defined(ARCH_STM32WL)
// TODO add getClock function or return a predefined clock speed per variant
return 0;
#else
return 0;
#endif
uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, bool force);

if (currentClock != desiredClock) {
LOG_DEBUG("Changing I2C clock to %u", desiredClock);
i2cBus->setClock(desiredClock);
}
return currentClock;
}
#endif
1 change: 0 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,6 @@ void setup()
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948);
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102);
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X);

#endif

#ifdef HAS_SDCARD
Expand Down
Loading
Loading