Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 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
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
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
712c43a
Merge branch 'master' into feat/add-sen5x
oscgonfer Jan 28, 2026
d1f1cf4
Fix unitialized variables in SEN5X constructor
oscgonfer Jan 28, 2026
cdf6183
Fix missing import
oscgonfer Jan 28, 2026
f3c5a33
Merge branch 'master' into feat/add-sen5x
oscgonfer Jan 31, 2026
7b125aa
Cleanup of SEN5X class
oscgonfer Feb 6, 2026
b5681dc
Exclude AQ sensor from wio-e5 due to flash limitations
oscgonfer Feb 6, 2026
a031e0e
Merge branch 'master' into feat/add-sen5x
oscgonfer Feb 6, 2026
8faeeb5
Fix I2C clock change logic
oscgonfer Feb 6, 2026
2d02273
Fix trunk
oscgonfer Feb 6, 2026
960c1c6
Fix on condition in reclock
oscgonfer Feb 6, 2026
ed72d0b
Merge branch 'master' into feat/add-sen5x
thebentern Feb 7, 2026
a4697d8
Add check on polling interval of sen5x
oscgonfer Feb 8, 2026
a8eb8e6
Merge branch 'master' into feat/add-sen5x
oscgonfer Feb 8, 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 platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ lib_deps =
sensirion/Sensirion Core@0.7.2
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
sensirion/Sensirion I2C SCD4x@1.1.0

; 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 Core@0.7.2
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
sensirion/Sensirion I2C SCD4x@1.1.0
sensirion/Sensirion I2C SCD4x@1.1.0
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
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
74 changes: 66 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,45 @@ 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 +608,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 +621,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 <Wire.h>
#include <stdint.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
80 changes: 61 additions & 19 deletions src/modules/Telemetry/AirQualityTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "PowerFSM.h"
#include "RTC.h"
#include "Router.h"
#include "Sensor/AddI2CSensorTemplate.h"
#include "UnitConversions.h"
#include "graphics/ScreenFonts.h"
#include "graphics/SharedUIDisplay.h"
Expand All @@ -20,7 +19,9 @@
#include <Throttle.h>

// Sensors
#include "Sensor/AddI2CSensorTemplate.h"
#include "Sensor/PMSA003ISensor.h"
#include "Sensor/SEN5XSensor.h"

void AirQualityTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
{
Expand All @@ -42,6 +43,7 @@ void AirQualityTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)

// order by priority of metrics/values (low top, high bottom)
addSensor<PMSA003ISensor>(i2cScanner, ScanI2C::DeviceType::PMSA003I);
addSensor<SEN5XSensor>(i2cScanner, ScanI2C::DeviceType::SEN5X);
}

int32_t AirQualityTelemetryModule::runOnce()
Expand Down Expand Up @@ -85,10 +87,27 @@ int32_t AirQualityTelemetryModule::runOnce()
}

// Wake up the sensors that need it
LOG_INFO("Waking up sensors");
LOG_INFO("Waking up sensors...");
for (TelemetrySensor *sensor : sensors) {
if (!sensor->isActive()) {
return sensor->wakeUp();
if (!sensor->canSleep()) {
LOG_DEBUG("%s sensor doesn't have sleep feature. Skipping", sensor->sensorName);
} else if (((lastSentToMesh == 0) ||
!Throttle::isWithinTimespanMs(lastSentToMesh - sensor->wakeUpTimeMs(),
Default::getConfiguredOrDefaultMsScaled(
moduleConfig.telemetry.air_quality_interval,
default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil()) {
if (!sensor->isActive()) {
LOG_DEBUG("Waking up: %s", sensor->sensorName);
return sensor->wakeUp();
} else {
int32_t pendingForReadyMs = sensor->pendingForReadyMs();
LOG_DEBUG("%s. Pending for ready %ums", sensor->sensorName, pendingForReadyMs);
if (pendingForReadyMs) {
return pendingForReadyMs;
}
}
}
}

Expand All @@ -109,9 +128,18 @@ int32_t AirQualityTelemetryModule::runOnce()
}

// Send to sleep sensors that consume power
LOG_INFO("Sending sensors to sleep");
LOG_DEBUG("Sending sensors to sleep");
for (TelemetrySensor *sensor : sensors) {
sensor->sleep();
if (sensor->isActive() && sensor->canSleep()) {
if (sensor->wakeUpTimeMs() < Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.air_quality_interval,
default_telemetry_broadcast_interval_secs,
numOnlineNodes)) {
LOG_DEBUG("Disabling %s until next period", sensor->sensorName);
sensor->sleep();
} else {
LOG_DEBUG("Sensor stays enabled due to warm up period");
}
}
}
}
return min(sendToPhoneIntervalMs, result);
Expand Down Expand Up @@ -158,8 +186,7 @@ void AirQualityTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSta
const auto &m = telemetry.variant.air_quality_metrics;

// Check if any telemetry field has valid data
bool hasAny = m.has_pm10_standard || m.has_pm25_standard || m.has_pm100_standard || m.has_pm10_environmental ||
m.has_pm25_environmental || m.has_pm100_environmental;
bool hasAny = m.has_pm10_standard || m.has_pm25_standard || m.has_pm100_standard;

if (!hasAny) {
display->drawString(x, currentY, "No Telemetry");
Expand Down Expand Up @@ -225,9 +252,10 @@ bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPack
t->variant.air_quality_metrics.pm10_standard, t->variant.air_quality_metrics.pm25_standard,
t->variant.air_quality_metrics.pm100_standard);

LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i",
t->variant.air_quality_metrics.pm10_environmental, t->variant.air_quality_metrics.pm25_environmental,
t->variant.air_quality_metrics.pm100_environmental);
// TODO - Decide what to do with these
// LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i",
// t->variant.air_quality_metrics.pm10_environmental, t->variant.air_quality_metrics.pm25_environmental,
// t->variant.air_quality_metrics.pm100_environmental);
#endif
// release previous packet before occupying a new spot
if (lastMeasurementPacket != nullptr)
Expand All @@ -247,10 +275,8 @@ bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m)
m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
m->variant.air_quality_metrics = meshtastic_AirQualityMetrics_init_zero;

// TODO - Should we check for sensor state here?
// If a sensor is sleeping, we should know and check to wake it up
for (TelemetrySensor *sensor : sensors) {
LOG_INFO("Reading AQ sensors");
LOG_DEBUG("Reading %s", sensor->sensorName);
valid = valid && sensor->getMetrics(m);
hasSensor = true;
}
Expand Down Expand Up @@ -291,12 +317,14 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
m.which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
m.time = getTime();

if (getAirQualityTelemetry(&m)) {
LOG_INFO("Send: pm10_standard=%u, pm25_standard=%u, pm100_standard=%u, \
pm10_environmental=%u, pm25_environmental=%u, pm100_environmental=%u",
m.variant.air_quality_metrics.pm10_standard, m.variant.air_quality_metrics.pm25_standard,
m.variant.air_quality_metrics.pm100_standard, m.variant.air_quality_metrics.pm10_environmental,
m.variant.air_quality_metrics.pm25_environmental, m.variant.air_quality_metrics.pm100_environmental);
LOG_INFO("Send: pm10_standard=%u, pm25_standard=%u, pm100_standard=%u", m.variant.air_quality_metrics.pm10_standard,
m.variant.air_quality_metrics.pm25_standard, m.variant.air_quality_metrics.pm100_standard);
if (m.variant.air_quality_metrics.has_pm10_environmental)
LOG_INFO("pm10_environmental=%u, pm25_environmental=%u, pm100_environmental=%u",
m.variant.air_quality_metrics.pm10_environmental, m.variant.air_quality_metrics.pm25_environmental,
m.variant.air_quality_metrics.pm100_environmental);

meshtastic_MeshPacket *p = allocDataProtobuf(m);
p->to = dest;
Expand Down Expand Up @@ -331,6 +359,20 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
LOG_DEBUG("Start next execution in 5s, then sleep");
setIntervalFromNow(FIVE_SECONDS_MS);
}

if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR && config.power.is_power_saving) {
meshtastic_ClientNotification *notification = clientNotificationPool.allocZeroed();
notification->level = meshtastic_LogRecord_Level_INFO;
notification->time = getValidTime(RTCQualityFromNet);
sprintf(notification->message, "Sending telemetry and sleeping for %us interval in a moment",
Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval,
default_telemetry_broadcast_interval_secs) /
1000U);
service->sendClientNotification(notification);
sleepOnNextExecution = true;
LOG_DEBUG("Start next execution in 5s, then sleep");
setIntervalFromNow(FIVE_SECONDS_MS);
}
}
return true;
}
Expand Down
Loading