From 13bb23f43c1d9239ab765afee9a3040302148b63 Mon Sep 17 00:00:00 2001 From: "Colin B." Date: Fri, 11 Apr 2025 15:35:54 -0700 Subject: [PATCH] support manually shutting off power to the PMSA003I sensor when we aren't doing a telemetry reading --- src/modules/Telemetry/AirQualityTelemetry.cpp | 60 +++++++++++++++---- src/modules/Telemetry/AirQualityTelemetry.h | 14 +++++ 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 392bd6148..c1a70d2e7 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -14,6 +14,10 @@ #include "main.h" #include +#ifndef PMSA003I_WARMUP_MS +#define PMSA003I_WARMUP_MS 30000 +#endif + int32_t AirQualityTelemetryModule::runOnce() { /* @@ -34,6 +38,12 @@ int32_t AirQualityTelemetryModule::runOnce() if (moduleConfig.telemetry.air_quality_enabled) { LOG_INFO("Air quality Telemetry: init"); + +#ifdef PMSA003I_ENABLE_PIN + pinMode(PMSA003I_ENABLE_PIN, OUTPUT); + digitalWrite(PMSA003I_ENABLE_PIN, 0); +#endif /* PMSA003I_ENABLE_PIN */ + if (!aqi.begin_I2C()) { #ifndef I2C_NO_RESCAN LOG_WARN("Could not establish i2c connection to AQI sensor. Rescan"); @@ -63,21 +73,45 @@ int32_t AirQualityTelemetryModule::runOnce() if (!moduleConfig.telemetry.air_quality_enabled) return disable(); - if (((lastSentToMesh == 0) || - !Throttle::isWithinTimespanMs(lastSentToMesh, 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()) { - sendTelemetry(); - lastSentToMesh = millis(); - } else if (service->isToPhoneQueueEmpty()) { - // Just send to phone when it's not our time to send to mesh yet - // Only send while queue is empty (phone assumed connected) - sendTelemetry(NODENUM_BROADCAST, true); + 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, 1); + 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) || + !Throttle::isWithinTimespanMs(lastSentToMesh, 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()) { + sendTelemetry(); + lastSentToMesh = millis(); + } else if (service->isToPhoneQueueEmpty()) { + // Just send to phone when it's not our time to send to mesh yet + // Only send while queue is empty (phone assumed connected) + sendTelemetry(NODENUM_BROADCAST, true); + } + + // put sensor back to sleep +#if PMSA003I_ENABLE_PIN + digitalWrite(PMSA003I_ENABLE_PIN, 0); + state = State::IDLE; +#endif /* PMSA003I_ENABLE_PIN */ + + return sendToPhoneIntervalMs; + default: + return disable(); } } - return sendToPhoneIntervalMs; } bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t) diff --git a/src/modules/Telemetry/AirQualityTelemetry.h b/src/modules/Telemetry/AirQualityTelemetry.h index 3b983bd56..6d7398a72 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.h +++ b/src/modules/Telemetry/AirQualityTelemetry.h @@ -23,6 +23,14 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf setIntervalFromNow(10 * 1000); aqi = Adafruit_PM25AQI(); 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: @@ -42,6 +50,12 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); private: + enum State { + IDLE = 0, + ACTIVE = 1, + }; + + State state; Adafruit_PM25AQI aqi; PM25_AQI_Data data = {0}; bool firstTime = true;