Rescan I2C on AQ module init (#10593)

This commit is contained in:
oscgonfer
2026-07-03 15:41:05 +02:00
committed by GitHub
co-authored by GitHub
parent 66a78ff693
commit 375fe944a4
10 changed files with 74 additions and 19 deletions
+55 -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,12 @@ 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");
#if !MESHTASTIC_EXCLUDE_I2C
// Re-scan I2C bus
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
i2cScanFinished(i2cScanner.get());
#endif
// 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 (const 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
@@ -34,10 +34,7 @@ class PMSA003ISensor : public TelemetrySensor
uint32_t pmMeasureStarted = 0; uint32_t pmMeasureStarted = 0;
uint8_t buffer[PMSA003I_FRAME_LENGTH]{}; uint8_t buffer[PMSA003I_FRAME_LENGTH]{};
TwoWire *_bus{};
uint8_t _address{};
#ifdef PMSA003I_I2C_CLOCK_SPEED #ifdef PMSA003I_I2C_CLOCK_SPEED
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
ReClockI2C reClockI2C; ReClockI2C reClockI2C;
#endif #endif
}; };
@@ -13,10 +13,7 @@ class SCD30Sensor : public TelemetrySensor
{ {
private: private:
SensirionI2cScd30 scd30; SensirionI2cScd30 scd30;
TwoWire *_bus{};
uint8_t _address{};
#ifdef SCD30_I2C_CLOCK_SPEED #ifdef SCD30_I2C_CLOCK_SPEED
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
ReClockI2C reClockI2C; ReClockI2C reClockI2C;
#endif #endif
@@ -16,10 +16,7 @@ class SCD4XSensor : public TelemetrySensor
{ {
private: private:
SensirionI2cScd4x scd4x; SensirionI2cScd4x scd4x;
TwoWire *_bus{};
uint8_t _address{};
#ifdef SCD4X_I2C_CLOCK_SPEED #ifdef SCD4X_I2C_CLOCK_SPEED
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
ReClockI2C reClockI2C; ReClockI2C reClockI2C;
#endif #endif
@@ -61,10 +61,7 @@ struct _SEN5XMeasurements {
class SEN5XSensor : public TelemetrySensor class SEN5XSensor : public TelemetrySensor
{ {
private: private:
TwoWire *_bus{};
uint8_t _address{};
#ifdef SEN5X_I2C_CLOCK_SPEED #ifdef SEN5X_I2C_CLOCK_SPEED
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
ReClockI2C reClockI2C; ReClockI2C reClockI2C;
#endif #endif
@@ -20,10 +20,7 @@ class SFA30Sensor : public TelemetrySensor
uint32_t measureStarted = 0; uint32_t measureStarted = 0;
SensirionI2cSfa3x sfa30; SensirionI2cSfa3x sfa30;
TwoWire *_bus{};
uint8_t _address{};
#ifdef SFA30_I2C_CLOCK_SPEED #ifdef SFA30_I2C_CLOCK_SPEED
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
ReClockI2C reClockI2C; ReClockI2C reClockI2C;
#endif #endif
@@ -10,8 +10,6 @@ class SHTXXSensor : public TelemetrySensor
{ {
private: private:
SHTSensor sht; SHTSensor sht;
TwoWire *_bus{};
uint8_t _address{};
SHTSensor::SHTAccuracy accuracy{}; SHTSensor::SHTAccuracy accuracy{};
bool setAccuracy(SHTSensor::SHTAccuracy newAccuracy); bool setAccuracy(SHTSensor::SHTAccuracy newAccuracy);
@@ -56,6 +56,11 @@ class TelemetrySensor
} }
const char *sensorName; const char *sensorName;
// TODO: Rename?
uint8_t _address = 0;
TwoWire *_bus{};
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
// TODO: delete after migration // TODO: delete after migration
bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; } bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; }