From 6d52fea75efe33277d14d8e30d231eab3d39daa6 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 31 May 2026 20:06:34 +0200 Subject: [PATCH] Allow re-scan of AirQualityModule for late-coming sensors * Define map for sensors to re-scan * Add re-scan on runOnce --- src/modules/Telemetry/AirQualityTelemetry.cpp | 54 ++++++++++++++++++- src/modules/Telemetry/AirQualityTelemetry.h | 6 ++- .../Telemetry/Sensor/AddI2CSensorTemplate.h | 9 ++++ 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 49c5bedb4..dba594da4 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -13,6 +13,7 @@ #include "Router.h" #include "TransmitHistory.h" #include "UnitConversions.h" +#include "detect/ScanI2CTwoWire.h" #include "graphics/ScreenFonts.h" #include "graphics/SharedUIDisplay.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) { return; } + LOG_INFO("Air Quality Telemetry adding I2C devices..."); /* Uncomment the preferences below if you want to use the module 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) */ @@ -54,6 +56,52 @@ void AirQualityTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) // moduleConfig.telemetry.air_quality_screen_enabled = 1; // 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() + if (!supportedSensors.count(SCD4X_ADDR)) + supportedSensors[SCD4X_ADDR] = ScanI2C::DeviceType::SCD4X; +#endif +#if __has_include() + if (!supportedSensors.count(SFA30_ADDR)) + supportedSensors[SFA30_ADDR] = ScanI2C::DeviceType::SFA30; +#endif +#if __has_include() + 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) addSensor(i2cScanner, ScanI2C::DeviceType::PMSA003I); addSensor(i2cScanner, ScanI2C::DeviceType::SEN5X); @@ -94,6 +142,10 @@ int32_t AirQualityTelemetryModule::runOnce() if (moduleConfig.telemetry.air_quality_enabled) { LOG_INFO("Air quality Telemetry: init"); + // Re-scan I2C bus + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + i2cScanFinished(i2cScanner.get()); + // check if we have at least one sensor if (!sensors.empty()) { result = DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; diff --git a/src/modules/Telemetry/AirQualityTelemetry.h b/src/modules/Telemetry/AirQualityTelemetry.h index 04936d8c1..4cc5af420 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.h +++ b/src/modules/Telemetry/AirQualityTelemetry.h @@ -3,8 +3,8 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR #pragma once - #include "BaseTelemetryModule.h" +#include #ifndef AIR_QUALITY_TELEMETRY_MODULE_ENABLE #define AIR_QUALITY_TELEMETRY_MODULE_ENABLE 0 @@ -13,6 +13,7 @@ #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "NodeDB.h" #include "ProtobufModule.h" +#include "detect/ScanI2C.h" #include "detect/ScanI2CConsumer.h" #include #include @@ -69,6 +70,9 @@ class AirQualityTelemetryModule : private concurrency::OSThread, uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute // uint32_t sendToPhoneIntervalMs = 1000; // Send to phone every minute uint32_t lastSentToPhone = 0; + + // Map for supported sensors to re-scan + std::map supportedSensors; }; #endif diff --git a/src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h b/src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h index b7029986b..ba0ab4c1e 100644 --- a/src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h +++ b/src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h @@ -11,6 +11,15 @@ static std::forward_list sensors; template void addSensor(const ScanI2C *i2cScanner, ScanI2C::DeviceType 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) { TelemetrySensor *sensor = new T(); #if WIRE_INTERFACES_COUNT > 1