PMSA003I: add support for driving SET pin low while not actively taking a telemetry reading (#6569)

* support manually shutting off power to the PMSA003I sensor when we aren't doing a telemetry reading

* add comment about PMSA003I_WARMUP_MS to AirQualityTelemetry.cpp

* fix typos, use arduino gpio defines instead of magic numbers

* support manually shutting off power to the PMSA003I sensor when we aren't doing a telemetry reading

* add comment about PMSA003I_WARMUP_MS to AirQualityTelemetry.cpp

* fix typos, use arduino gpio defines instead of magic numbers

* RAK4631: add PMSA003I_ENABLE_PIN define

* fix indentation

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
Colin 2025-04-29 04:31:01 -07:00 committed by GitHub
parent b4e8f7dbb6
commit 72eae42b81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 71 additions and 13 deletions

View File

@ -14,6 +14,13 @@
#include "main.h" #include "main.h"
#include <Throttle.h> #include <Throttle.h>
#ifndef PMSA003I_WARMUP_MS
// from the PMSA003I datasheet:
// "Stable data should be got at least 30 seconds after the sensor wakeup
// from the sleep mode because of the fans performance."
#define PMSA003I_WARMUP_MS 30000
#endif
int32_t AirQualityTelemetryModule::runOnce() int32_t AirQualityTelemetryModule::runOnce()
{ {
/* /*
@ -34,6 +41,13 @@ int32_t AirQualityTelemetryModule::runOnce()
if (moduleConfig.telemetry.air_quality_enabled) { if (moduleConfig.telemetry.air_quality_enabled) {
LOG_INFO("Air quality Telemetry: init"); LOG_INFO("Air quality Telemetry: init");
#ifdef PMSA003I_ENABLE_PIN
// put the sensor to sleep on startup
pinMode(PMSA003I_ENABLE_PIN, OUTPUT);
digitalWrite(PMSA003I_ENABLE_PIN, LOW);
#endif /* PMSA003I_ENABLE_PIN */
if (!aqi.begin_I2C()) { if (!aqi.begin_I2C()) {
#ifndef I2C_NO_RESCAN #ifndef I2C_NO_RESCAN
LOG_WARN("Could not establish i2c connection to AQI sensor. Rescan"); LOG_WARN("Could not establish i2c connection to AQI sensor. Rescan");
@ -63,6 +77,20 @@ int32_t AirQualityTelemetryModule::runOnce()
if (!moduleConfig.telemetry.air_quality_enabled) if (!moduleConfig.telemetry.air_quality_enabled)
return disable(); return disable();
switch (state) {
#ifdef PMSA003I_ENABLE_PIN
case State::IDLE:
// sensor is in standby; fire it up and sleep
LOG_DEBUG("runOnce(): state = idle");
digitalWrite(PMSA003I_ENABLE_PIN, HIGH);
state = State::ACTIVE;
return PMSA003I_WARMUP_MS;
#endif /* PMSA003I_ENABLE_PIN */
case State::ACTIVE:
// sensor is already warmed up; grab telemetry and send it
LOG_DEBUG("runOnce(): state = active");
if (((lastSentToMesh == 0) || if (((lastSentToMesh == 0) ||
!Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled( !Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled(
moduleConfig.telemetry.air_quality_interval, moduleConfig.telemetry.air_quality_interval,
@ -76,8 +104,18 @@ int32_t AirQualityTelemetryModule::runOnce()
// Only send while queue is empty (phone assumed connected) // Only send while queue is empty (phone assumed connected)
sendTelemetry(NODENUM_BROADCAST, true); sendTelemetry(NODENUM_BROADCAST, true);
} }
}
#ifdef PMSA003I_ENABLE_PIN
// put sensor back to sleep
digitalWrite(PMSA003I_ENABLE_PIN, LOW);
state = State::IDLE;
#endif /* PMSA003I_ENABLE_PIN */
return sendToPhoneIntervalMs; return sendToPhoneIntervalMs;
default:
return disable();
}
}
} }
bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t) bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)

View File

@ -23,6 +23,14 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf
setIntervalFromNow(10 * 1000); setIntervalFromNow(10 * 1000);
aqi = Adafruit_PM25AQI(); aqi = Adafruit_PM25AQI();
nodeStatusObserver.observe(&nodeStatus->onNewStatus); nodeStatusObserver.observe(&nodeStatus->onNewStatus);
#ifdef PMSA003I_ENABLE_PIN
// the PMSA003I sensor uses about 300mW on its own; support powering it off when it's not actively taking
// a reading
state = State::IDLE;
#else
state = State::ACTIVE;
#endif
} }
protected: protected:
@ -42,6 +50,12 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf
bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
private: private:
enum State {
IDLE = 0,
ACTIVE = 1,
};
State state;
Adafruit_PM25AQI aqi; Adafruit_PM25AQI aqi;
PM25_AQI_Data data = {0}; PM25_AQI_Data data = {0};
bool firstTime = true; bool firstTime = true;

View File

@ -197,6 +197,12 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
*/ */
// configure the SET pin on the RAK12039 sensor board to disable the sensor while not reading
// air quality telemetry. PIN_NFC2 doesn't seem to be used anywhere else in the codebase, but if
// you're having problems with your node behaving weirdly when a RAK12039 board isn't connected,
// try disabling this.
#define PMSA003I_ENABLE_PIN PIN_NFC2
#define DETECTION_SENSOR_EN 4 #define DETECTION_SENSOR_EN 4
#define USE_SX1262 #define USE_SX1262