Allow re-scan of AirQualityModule for late-coming sensors

* Define map for sensors to re-scan
* Add re-scan on runOnce
This commit is contained in:
oscgonfer
2026-06-14 14:48:40 +02:00
parent 6c61f12b10
commit 301c5e014a
3 changed files with 67 additions and 2 deletions
+53 -1
View File
@@ -13,6 +13,7 @@
#include "Router.h" #include "Router.h"
#include "TransmitHistory.h" #include "TransmitHistory.h"
#include "UnitConversions.h" #include "UnitConversions.h"
#include "detect/ScanI2CTwoWire.h"
#include "graphics/ScreenFonts.h" #include "graphics/ScreenFonts.h"
#include "graphics/SharedUIDisplay.h" #include "graphics/SharedUIDisplay.h"
#include "graphics/images.h" #include "graphics/images.h"
@@ -41,12 +42,13 @@ void AirQualityTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
if (!moduleConfig.telemetry.air_quality_enabled && !AIR_QUALITY_TELEMETRY_MODULE_ENABLE) { if (!moduleConfig.telemetry.air_quality_enabled && !AIR_QUALITY_TELEMETRY_MODULE_ENABLE) {
return; return;
} }
LOG_INFO("Air Quality Telemetry adding I2C devices..."); LOG_INFO("Air Quality Telemetry adding I2C devices...");
/* /*
Uncomment the preferences below if you want to use the module Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI. without having to configure it from the PythonAPI or WebUI.
Note: this was previously on runOnce, which didnt take effect Note: this was previously on runOnce, which didn't take effect
as other modules already had already been initialized (screen) as other modules already had already been initialized (screen)
*/ */
@@ -54,6 +56,52 @@ void AirQualityTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
// moduleConfig.telemetry.air_quality_screen_enabled = 1; // moduleConfig.telemetry.air_quality_screen_enabled = 1;
// moduleConfig.telemetry.air_quality_interval = 15; // moduleConfig.telemetry.air_quality_interval = 15;
// Add here supported sensors in the Air Quality module
// These sensors will be scanned twice, once in the first scan,
// and secondly in the first run of the module
if (!supportedSensors.count(PMSA003I_ADDR))
supportedSensors[PMSA003I_ADDR] = ScanI2C::DeviceType::PMSA003I;
if (!supportedSensors.count(SEN5X_ADDR))
supportedSensors[SEN5X_ADDR] = ScanI2C::DeviceType::SEN5X;
#if __has_include(<SensirionI2cScd4x.h>)
if (!supportedSensors.count(SCD4X_ADDR))
supportedSensors[SCD4X_ADDR] = ScanI2C::DeviceType::SCD4X;
#endif
#if __has_include(<SensirionI2cSfa3x.h>)
if (!supportedSensors.count(SFA30_ADDR))
supportedSensors[SFA30_ADDR] = ScanI2C::DeviceType::SFA30;
#endif
#if __has_include(<SensirionI2cScd30.h>)
if (!supportedSensors.count(SCD30_ADDR))
supportedSensors[SCD30_ADDR] = ScanI2C::DeviceType::SCD30;
#endif
if (!firstTime) {
// Re-scan for late comming sensors
LOG_INFO("Re-scanning supported sensors...");
for (const auto &[address, type] : supportedSensors) {
if (!i2cScanner->exists(type)) {
LOG_INFO("Re-scanning on address 0x%x", address);
uint8_t array_address[1] = {address};
#if defined(I2C_SDA1) || (defined(NRF52840_XXAA) && (WIRE_INTERFACES_COUNT == 2))
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, array_address, sizeof(array_address));
#endif
#if defined(I2C_SDA)
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, array_address, sizeof(array_address));
#elif defined(ARCH_PORTDUINO)
if (portduino_config.i2cdev != "") {
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, array_address, sizeof(array_address));
}
#elif HAS_WIRE
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, array_address, sizeof(array_address));
#endif
}
}
}
// order by priority of metrics/values (low top, high bottom) // order by priority of metrics/values (low top, high bottom)
addSensor<PMSA003ISensor>(i2cScanner, ScanI2C::DeviceType::PMSA003I); addSensor<PMSA003ISensor>(i2cScanner, ScanI2C::DeviceType::PMSA003I);
addSensor<SEN5XSensor>(i2cScanner, ScanI2C::DeviceType::SEN5X); addSensor<SEN5XSensor>(i2cScanner, ScanI2C::DeviceType::SEN5X);
@@ -94,6 +142,10 @@ 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");
// Re-scan I2C bus
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
i2cScanFinished(i2cScanner.get());
// check if we have at least one sensor // check if we have at least one sensor
if (!sensors.empty()) { if (!sensors.empty()) {
result = DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; result = DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+5 -1
View File
@@ -3,8 +3,8 @@
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
#pragma once #pragma once
#include "BaseTelemetryModule.h" #include "BaseTelemetryModule.h"
#include <map>
#ifndef AIR_QUALITY_TELEMETRY_MODULE_ENABLE #ifndef AIR_QUALITY_TELEMETRY_MODULE_ENABLE
#define AIR_QUALITY_TELEMETRY_MODULE_ENABLE 0 #define AIR_QUALITY_TELEMETRY_MODULE_ENABLE 0
@@ -13,6 +13,7 @@
#include "../mesh/generated/meshtastic/telemetry.pb.h" #include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "ProtobufModule.h" #include "ProtobufModule.h"
#include "detect/ScanI2C.h"
#include "detect/ScanI2CConsumer.h" #include "detect/ScanI2CConsumer.h"
#include <OLEDDisplay.h> #include <OLEDDisplay.h>
#include <OLEDDisplayUi.h> #include <OLEDDisplayUi.h>
@@ -69,6 +70,9 @@ class AirQualityTelemetryModule : private concurrency::OSThread,
uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
// uint32_t sendToPhoneIntervalMs = 1000; // Send to phone every minute // uint32_t sendToPhoneIntervalMs = 1000; // Send to phone every minute
uint32_t lastSentToPhone = 0; uint32_t lastSentToPhone = 0;
// Map for supported sensors to re-scan
std::map<uint8_t, ScanI2C::DeviceType> supportedSensors;
}; };
#endif #endif
@@ -11,6 +11,15 @@ static std::forward_list<TelemetrySensor *> sensors;
template <typename T> void addSensor(const ScanI2C *i2cScanner, ScanI2C::DeviceType type) template <typename T> void addSensor(const ScanI2C *i2cScanner, ScanI2C::DeviceType type)
{ {
ScanI2C::FoundDevice dev = i2cScanner->find(type); ScanI2C::FoundDevice dev = i2cScanner->find(type);
// Avoid adding the same device twice
if (dev.type != ScanI2C::DeviceType::NONE) {
for (TelemetrySensor *_sensor : sensors) {
if ((_sensor->_address == dev.address.address) && (_sensor->_port == dev.address.port)) {
return;
}
}
}
if (dev.type != ScanI2C::DeviceType::NONE || type == ScanI2C::DeviceType::NONE) { if (dev.type != ScanI2C::DeviceType::NONE || type == ScanI2C::DeviceType::NONE) {
TelemetrySensor *sensor = new T(); TelemetrySensor *sensor = new T();
#if WIRE_INTERFACES_COUNT > 1 #if WIRE_INTERFACES_COUNT > 1