diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index ff4f9b89023..151e559f15b 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -156,44 +156,11 @@ bool ScanI2CTwoWire::i2cCommandResponseLength(ScanI2C::DeviceAddress addr, uint1 } #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR -// FIXME Move to a separate file for detection of sensors that require more complex interactions? -// For SEN5X detection -// Note, this code needs to be called before setting the I2C bus speed -// for the screen at high speed. The speed needs to be at 100kHz, otherwise -// detection will not work -String readSEN5xProductName(TwoWire *i2cBus, uint8_t address) +#include "../modules/Telemetry/Sensor/SEN5XSensor.h" +bool probeSEN5X(TwoWire *i2cBus, uint8_t address, ScanI2C::I2CPort port) { - uint8_t cmd[] = {0xD0, 0x14}; - uint8_t response[48] = {0}; - - i2cBus->beginTransmission(address); - i2cBus->write(cmd, 2); - if (i2cBus->endTransmission() != 0) - return ""; - - delay(20); - if (i2cBus->requestFrom(address, (uint8_t)48) != 48) - return ""; - - for (int i = 0; i < 48 && i2cBus->available(); ++i) { - response[i] = i2cBus->read(); - } - - char productName[33] = {0}; - int j = 0; - for (int i = 0; i < 48 && j < 32; i += 3) { - if (response[i] >= 32 && response[i] <= 126) - productName[j++] = response[i]; - else - break; - - if (response[i + 1] >= 32 && response[i + 1] <= 126) - productName[j++] = response[i + 1]; - else - break; - } - - return String(productName); + SEN5XSensor sen5xsensor; + return sen5xsensor.probe(i2cBus, address, port); } #endif @@ -861,33 +828,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) type = ICM42607P; logFoundDevice("ICM-42607-P", (uint8_t)addr.address); break; + } else if (registerValue == 0x68) { // WHO_AM_I from datasheet + type = MPU6050; + logFoundDevice("MPU6050", (uint8_t)addr.address); + break; } #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR - String prod = ""; - prod = readSEN5xProductName(i2cBus, addr.address); - if (prod.startsWith("SEN55")) { - type = SEN5X; - logFoundDevice("Sensirion SEN55", addr.address); - break; - } else if (prod.startsWith("SEN54")) { + if (probeSEN5X(i2cBus, addr.address, port)) { type = SEN5X; - logFoundDevice("Sensirion SEN54", addr.address); - break; - } else if (prod.startsWith("SEN50")) { - type = SEN5X; - logFoundDevice("Sensirion SEN50", addr.address); + logFoundDevice("SEN5X", addr.address); break; } #endif - if (addr.address == BMX160_ADDR) { - type = BMX160; - logFoundDevice("BMX160", (uint8_t)addr.address); - break; - } else { - type = MPU6050; - logFoundDevice("MPU6050", (uint8_t)addr.address); - break; - } } break; diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 96206852388..8320b0ab5dd 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,12 @@ int32_t AirQualityTelemetryModule::runOnce() if (moduleConfig.telemetry.air_quality_enabled) { LOG_INFO("Air quality Telemetry: init"); +#if !MESHTASTIC_EXCLUDE_I2C + // Re-scan I2C bus + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + i2cScanFinished(i2cScanner.get()); +#endif + // 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 04936d8c18e..4cc5af420bf 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 b7029986bea..ba1c5e2e90c 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 (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) { TelemetrySensor *sensor = new T(); #if WIRE_INTERFACES_COUNT > 1 diff --git a/src/modules/Telemetry/Sensor/PMSA003ISensor.h b/src/modules/Telemetry/Sensor/PMSA003ISensor.h index ce7bba4bbc0..9b9cad37a74 100644 --- a/src/modules/Telemetry/Sensor/PMSA003ISensor.h +++ b/src/modules/Telemetry/Sensor/PMSA003ISensor.h @@ -34,12 +34,9 @@ class PMSA003ISensor : public TelemetrySensor uint32_t pmMeasureStarted = 0; uint8_t buffer[PMSA003I_FRAME_LENGTH]{}; - TwoWire *_bus{}; - uint8_t _address{}; #ifdef PMSA003I_I2C_CLOCK_SPEED - ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; ReClockI2C reClockI2C; #endif }; -#endif \ No newline at end of file +#endif diff --git a/src/modules/Telemetry/Sensor/SCD30Sensor.h b/src/modules/Telemetry/Sensor/SCD30Sensor.h index 64ca7342029..82c9a5532a3 100644 --- a/src/modules/Telemetry/Sensor/SCD30Sensor.h +++ b/src/modules/Telemetry/Sensor/SCD30Sensor.h @@ -13,10 +13,7 @@ class SCD30Sensor : public TelemetrySensor { private: SensirionI2cScd30 scd30; - TwoWire *_bus{}; - uint8_t _address{}; #ifdef SCD30_I2C_CLOCK_SPEED - ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; ReClockI2C reClockI2C; #endif @@ -55,4 +52,4 @@ class SCD30Sensor : public TelemetrySensor meshtastic_AdminMessage *response) override; }; -#endif \ No newline at end of file +#endif diff --git a/src/modules/Telemetry/Sensor/SCD4XSensor.h b/src/modules/Telemetry/Sensor/SCD4XSensor.h index 03ff4abc224..0e1a46f44ef 100644 --- a/src/modules/Telemetry/Sensor/SCD4XSensor.h +++ b/src/modules/Telemetry/Sensor/SCD4XSensor.h @@ -16,10 +16,7 @@ class SCD4XSensor : public TelemetrySensor { private: SensirionI2cScd4x scd4x; - TwoWire *_bus{}; - uint8_t _address{}; #ifdef SCD4X_I2C_CLOCK_SPEED - ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; ReClockI2C reClockI2C; #endif @@ -65,4 +62,4 @@ class SCD4XSensor : public TelemetrySensor meshtastic_AdminMessage *response) override; }; -#endif \ No newline at end of file +#endif diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp index 4f5688b4695..e88e81b9e68 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp @@ -75,6 +75,24 @@ bool SEN5XSensor::findModel() return true; } +bool SEN5XSensor::probe(TwoWire *bus, uint8_t address, ScanI2C::I2CPort port) +{ + LOG_INFO("SEN5X: probing sensor"); + + _bus = bus; + _address = address; +#ifdef SEN5X_I2C_CLOCK_SPEED + _port = port; + reClockI2C.setup(_bus, _port); +#endif /* SEN5X_I2C_CLOCK_SPEED */ + + if (!findModel()) { + LOG_DEBUG("SEN5X: can't find SEN5X model"); + return false; + } + return true; +} + bool SEN5XSensor::sendCommand(uint16_t command) { uint8_t nothing; diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.h b/src/modules/Telemetry/Sensor/SEN5XSensor.h index ce037fc4d51..935c8cb21b1 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.h +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.h @@ -61,10 +61,7 @@ struct _SEN5XMeasurements { class SEN5XSensor : public TelemetrySensor { private: - TwoWire *_bus{}; - uint8_t _address{}; #ifdef SEN5X_I2C_CLOCK_SPEED - ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; ReClockI2C reClockI2C; #endif @@ -158,6 +155,7 @@ See: https://sensirion.com/resource/application_note/low_power_mode/sen5x public: SEN5XSensor(); + bool probe(TwoWire *bus, uint8_t address, ScanI2C::I2CPort port); virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; @@ -172,4 +170,4 @@ See: https://sensirion.com/resource/application_note/low_power_mode/sen5x meshtastic_AdminMessage *response) override; }; -#endif \ No newline at end of file +#endif diff --git a/src/modules/Telemetry/Sensor/SFA30Sensor.h b/src/modules/Telemetry/Sensor/SFA30Sensor.h index 299a9fdf0e4..009138b90d3 100644 --- a/src/modules/Telemetry/Sensor/SFA30Sensor.h +++ b/src/modules/Telemetry/Sensor/SFA30Sensor.h @@ -20,10 +20,7 @@ class SFA30Sensor : public TelemetrySensor uint32_t measureStarted = 0; SensirionI2cSfa3x sfa30; - TwoWire *_bus{}; - uint8_t _address{}; #ifdef SFA30_I2C_CLOCK_SPEED - ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; ReClockI2C reClockI2C; #endif diff --git a/src/modules/Telemetry/Sensor/TelemetrySensor.h b/src/modules/Telemetry/Sensor/TelemetrySensor.h index 47deaa936dd..2c87c0e2336 100644 --- a/src/modules/Telemetry/Sensor/TelemetrySensor.h +++ b/src/modules/Telemetry/Sensor/TelemetrySensor.h @@ -56,6 +56,11 @@ class TelemetrySensor } const char *sensorName; + // TODO: Rename? + uint8_t _address = 0; + TwoWire *_bus{}; + ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; + // TODO: delete after migration bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; }