From 7c17e489c207ab5464af5d5455e7c376cbfeaa1b Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 14 Jun 2026 13:45:15 +0200 Subject: [PATCH 01/19] Fixes on 0x69 address detection * Change SEN5X detection method, using class itself * MPU6050 register check * BMX160 default removed --- src/detect/ScanI2CTwoWire.cpp | 102 +++++++++---------- src/modules/Telemetry/Sensor/SEN5XSensor.cpp | 26 +++++ src/modules/Telemetry/Sensor/SEN5XSensor.h | 1 + 3 files changed, 74 insertions(+), 55 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 5a9ec9a6563..af3ff44dce5 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -137,45 +137,52 @@ bool ScanI2CTwoWire::i2cCommandResponseLength(ScanI2C::DeviceAddress addr, uint1 } #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR +#include "../modules/Telemetry/Sensor/SEN5XSensor.h" +bool probeSEN5X(TwoWire *i2cBus, uint8_t address, ScanI2C::I2CPort port) +{ + SEN5XSensor sen5xsensor = SEN5XSensor(); + return sen5xsensor.probe(i2cBus, address, port); +} + // 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) -{ - 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); -} +// String readSEN5xProductName(TwoWire *i2cBus, uint8_t address) +// { +// 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); +// } #endif #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR @@ -789,33 +796,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")) { - type = SEN5X; - logFoundDevice("Sensirion SEN54", addr.address); - break; - } else if (prod.startsWith("SEN50")) { + if (probeSEN5X(i2cBus, addr.address, port)) { 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/Sensor/SEN5XSensor.cpp b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp index 2feac6d5f38..b638bf47f58 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp @@ -76,6 +76,32 @@ 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 */ + + delay(50); // without this there is an error on the deviceReset function + + if (!sendCommand(SEN5X_RESET)) { + LOG_ERROR("SEN5X: error resetting device"); + return false; + } + delay(200); // From Sensirion Datasheet + + if (!findModel()) { + LOG_ERROR("SEN5X: error finding sensor 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 ef5ad5c2922..9fb25fdd693 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.h +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.h @@ -153,6 +153,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; From 560e2d395e69b69190e5360f94616415e02bcd13 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 14 Jun 2026 13:52:00 +0200 Subject: [PATCH 02/19] Remove commented code --- src/detect/ScanI2CTwoWire.cpp | 40 ----------------------------------- 1 file changed, 40 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index af3ff44dce5..38d860f65f3 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -143,46 +143,6 @@ bool probeSEN5X(TwoWire *i2cBus, uint8_t address, ScanI2C::I2CPort port) SEN5XSensor sen5xsensor = SEN5XSensor(); return sen5xsensor.probe(i2cBus, address, port); } - -// 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) -// { -// 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); -// } #endif #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR From 92f32eb9516e3f4e0f43668a1a96ae085490417f Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Fri, 13 Mar 2026 12:23:12 +0100 Subject: [PATCH 03/19] Add define for screen I2C frequency --- src/graphics/Screen.cpp | 17 ++++++++++------- src/graphics/Screen.h | 4 ++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index bc65a08c832..3564f9d059f 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -480,7 +480,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64) dispdev = new SH1106Wire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, SCREEN_I2C_FREQUENCY); #elif defined(USE_ST7789) #ifdef ESP_PLATFORM dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7789_SDA, @@ -496,8 +496,9 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); #endif #elif defined(USE_SSD1306) - dispdev = new SSD1306Wire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); + dispdev = + new SSD1306Wire(address.address, -1, -1, geometry, + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, SCREEN_I2C_FREQUENCY); #if defined(OLED_Y_OFFSET_PAGES) // Panels whose active window does not start at GDDRAM row 0 (e.g. 72x40 // modules on pages 3..7) need a fixed vertical page shift on every write. @@ -525,7 +526,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O dispdev = new EInkParallelDisplay(EPD_WIDTH, EPD_HEIGHT, EInkParallelDisplay::EPD_ROT_PORTRAIT); #elif defined(USE_ST7567) dispdev = new ST7567Wire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, SCREEN_I2C_FREQUENCY); #elif ARCH_PORTDUINO if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { if (portduino_config.displayPanel != no_screen) { @@ -534,13 +535,15 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); } else { dispdev = new AutoOLEDWire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, + SCREEN_I2C_FREQUENCY); isAUTOOled = true; } } #else - dispdev = new AutoOLEDWire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); + dispdev = + new AutoOLEDWire(address.address, -1, -1, geometry, + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, SCREEN_I2C_FREQUENCY); isAUTOOled = true; #endif diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 37acfbc963b..d9ed2614d49 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -9,6 +9,10 @@ #include #include +#ifndef SCREEN_I2C_FREQUENCY +#define SCREEN_I2C_FREQUENCY 700000 +#endif + #define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2) namespace graphics { From 1a1f906b7acd1dd1a0fe88d98bac1846a0e9da36 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 24 May 2026 20:03:34 +0200 Subject: [PATCH 04/19] Add functions to get I2C screen frequency and port --- src/graphics/Screen.cpp | 22 ++++++++++++---------- src/graphics/Screen.h | 24 ++++++++++++++++++++---- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 3564f9d059f..d890952d749 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -480,7 +480,8 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64) dispdev = new SH1106Wire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, SCREEN_I2C_FREQUENCY); + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); + isI2cScreen = true; #elif defined(USE_ST7789) #ifdef ESP_PLATFORM dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7789_SDA, @@ -496,9 +497,9 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); #endif #elif defined(USE_SSD1306) - dispdev = - new SSD1306Wire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, SCREEN_I2C_FREQUENCY); + dispdev = new SSD1306Wire(address.address, -1, -1, geometry, + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); + isI2cScreen = true; #if defined(OLED_Y_OFFSET_PAGES) // Panels whose active window does not start at GDDRAM row 0 (e.g. 72x40 // modules on pages 3..7) need a fixed vertical page shift on every write. @@ -526,7 +527,8 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O dispdev = new EInkParallelDisplay(EPD_WIDTH, EPD_HEIGHT, EInkParallelDisplay::EPD_ROT_PORTRAIT); #elif defined(USE_ST7567) dispdev = new ST7567Wire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, SCREEN_I2C_FREQUENCY); + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); + isI2cScreen = true; #elif ARCH_PORTDUINO if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { if (portduino_config.displayPanel != no_screen) { @@ -535,16 +537,16 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); } else { dispdev = new AutoOLEDWire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, - SCREEN_I2C_FREQUENCY); + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); isAUTOOled = true; + isI2cScreen = true; } } #else - dispdev = - new AutoOLEDWire(address.address, -1, -1, geometry, - (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE, SCREEN_I2C_FREQUENCY); + dispdev = new AutoOLEDWire(address.address, -1, -1, geometry, + (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); isAUTOOled = true; + isI2cScreen = true; #endif #if defined(USE_ST7789) diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index d9ed2614d49..0804ec97eff 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -9,10 +9,6 @@ #include #include -#ifndef SCREEN_I2C_FREQUENCY -#define SCREEN_I2C_FREQUENCY 700000 -#endif - #define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2) namespace graphics { @@ -77,6 +73,9 @@ class Screen void showOverlayBanner(BannerOverlayOptions) {} void setFrames(FrameFocus focus) {} void endAlert() {} + bool getIsI2CScreen() { return false; } + uint32_t getI2cFrequency() { return 0; } + ScanI2C::I2CPort getI2CPort() { return ScanI2C::I2CPort::NO_I2C; } }; } // namespace graphics #else @@ -264,6 +263,22 @@ class Screen : public concurrency::OSThread Screen &operator=(const Screen &) = delete; ScanI2C::DeviceAddress address_found; + bool getIsI2CScreen() { return isI2cScreen; } + // Return I2C Speed, or 0 if none + uint32_t getI2cFrequency() + { + if (getIsI2CScreen()) + return dispdev->getI2cFrequency(); + else + return 0; + } + ScanI2C::I2CPort getI2CPort() + { + if (getIsI2CScreen()) + return address_found.port; + else + return ScanI2C::I2CPort::NO_I2C; + } meshtastic_Config_DisplayConfig_OledType model; OLEDDISPLAY_GEOMETRY geometry; @@ -658,6 +673,7 @@ class Screen : public concurrency::OSThread int32_t runOnce() final; bool isAUTOOled = false; + bool isI2cScreen = false; // Screen dimensions (for convenience) // Defined during Screen::setup From 0200d452415e40554c1c0b6fe027447009aedbeb Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Mon, 25 May 2026 13:51:29 +0200 Subject: [PATCH 05/19] Make reclock function aware of screen-set I2C speeds --- src/detect/reClockI2C.cpp | 43 ++-- src/detect/reClockI2C.h | 5 +- .../Telemetry/Sensor/PMSA003ISensor.cpp | 39 ++-- src/modules/Telemetry/Sensor/PMSA003ISensor.h | 1 + src/modules/Telemetry/Sensor/SCD30Sensor.cpp | 116 +++++------ src/modules/Telemetry/Sensor/SCD30Sensor.h | 1 + src/modules/Telemetry/Sensor/SCD4XSensor.cpp | 186 +++++++++--------- src/modules/Telemetry/Sensor/SCD4XSensor.h | 1 + src/modules/Telemetry/Sensor/SEN5XSensor.cpp | 40 ++-- src/modules/Telemetry/Sensor/SEN5XSensor.h | 1 + src/modules/Telemetry/Sensor/SFA30Sensor.cpp | 110 ++++++----- src/modules/Telemetry/Sensor/SFA30Sensor.h | 2 + 12 files changed, 280 insertions(+), 265 deletions(-) diff --git a/src/detect/reClockI2C.cpp b/src/detect/reClockI2C.cpp index 60cd3c8084c..df81a7e2318 100644 --- a/src/detect/reClockI2C.cpp +++ b/src/detect/reClockI2C.cpp @@ -1,29 +1,42 @@ #include "reClockI2C.h" #include "ScanI2CTwoWire.h" -uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, bool force) +/* See https://github.com/arduino/Arduino/issues/11457 + Currently, only ESP32 can getClock() + While all cores can setClock() + https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50 + https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60 + https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103 + For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes) + we need to reclock I2C and set it back to the previous stablished speed. + Only for cases where we can know it (ESP32 or known screen) we can do this. +*/ + +uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, ScanI2C::I2CPort port) { uint32_t currentClock = 0; + uint32_t screenClock = 0; + ScanI2C::I2CPort screenPort = ScanI2C::I2CPort::NO_I2C; - /* See https://github.com/arduino/Arduino/issues/11457 - Currently, only ESP32 can getClock() - While all cores can setClock() - https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50 - https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60 - https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103 - For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes) - we need to reclock I2C and set it back to the previous desired speed. - Only for cases where we can know OR predefine the speed, we can do this. - */ - -// TODO add getClock function or return a predefined clock speed per variant? + // Assume that if we can't getClock, or there is no screen, we can set the clock speed at will #ifdef CAN_RECLOCK_I2C currentClock = i2cBus->getClock(); + LOG_DEBUG("Current I2C frequency: %uHz", currentClock); +#elif HAS_SCREEN + if (screen) { + // If we get a non-zero response here, the screen has set a speed + screenClock = screen->getI2cFrequency(); + screenPort = screen->getI2CPort(); + // Check if i2c port is the same, and that we got a screenClock back (0 means the screen didn't set it) + if (screenClock && (screenPort == port)) + currentClock = screenClock; + LOG_DEBUG("Screen defined I2C frequency: %uHz", screenClock); + } #endif - if ((currentClock != desiredClock) || force) { - LOG_DEBUG("Changing I2C clock to %u", desiredClock); + if (currentClock != desiredClock) { + LOG_DEBUG("Changing I2C clock to %uHz", desiredClock); i2cBus->setClock(desiredClock); } diff --git a/src/detect/reClockI2C.h b/src/detect/reClockI2C.h index 9c53efc4fe5..b2852541403 100644 --- a/src/detect/reClockI2C.h +++ b/src/detect/reClockI2C.h @@ -2,10 +2,13 @@ #ifndef RECLOCK_I2C_ #define RECLOCK_I2C_ +#include "../graphics/Screen.h" #include "ScanI2CTwoWire.h" #include #include -uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, bool force); +uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, ScanI2C::I2CPort port); + +extern graphics::Screen *screen; #endif diff --git a/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp b/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp index e34b70a1ff8..c6711fc5ae6 100644 --- a/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp +++ b/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp @@ -20,16 +20,11 @@ bool PMSA003ISensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) _bus = bus; _address = dev->address.address; + _port = dev->address.port; #ifdef PMSA003I_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, _port); #endif /* PMSA003I_I2C_CLOCK_SPEED */ _bus->beginTransmission(_address); @@ -38,9 +33,12 @@ bool PMSA003ISensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) return false; } -#if defined(PMSA003I_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef PMSA003I_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* PMSA003I_I2C_CLOCK_SPEED */ status = 1; LOG_INFO("%s Enabled", sensorName); @@ -57,14 +55,8 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement) } #ifdef PMSA003I_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, _port); #endif /* PMSA003I_I2C_CLOCK_SPEED */ _bus->requestFrom(_address, (uint8_t)PMSA003I_FRAME_LENGTH); @@ -77,9 +69,12 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement) buffer[i] = _bus->read(); } -#if defined(PMSA003I_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef PMSA003I_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* PMSA003I_I2C_CLOCK_SPEED */ if (buffer[0] != 0x42 || buffer[1] != 0x4D) { LOG_WARN("%s frame header invalid: 0x%02X 0x%02X", sensorName, buffer[0], buffer[1]); diff --git a/src/modules/Telemetry/Sensor/PMSA003ISensor.h b/src/modules/Telemetry/Sensor/PMSA003ISensor.h index 3fe96888ddf..ed01a188ddd 100644 --- a/src/modules/Telemetry/Sensor/PMSA003ISensor.h +++ b/src/modules/Telemetry/Sensor/PMSA003ISensor.h @@ -35,6 +35,7 @@ class PMSA003ISensor : public TelemetrySensor uint8_t buffer[PMSA003I_FRAME_LENGTH]{}; TwoWire *_bus{}; uint8_t _address{}; + ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SCD30Sensor.cpp b/src/modules/Telemetry/Sensor/SCD30Sensor.cpp index 0478b6651bd..b9c7617ad7b 100644 --- a/src/modules/Telemetry/Sensor/SCD30Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SCD30Sensor.cpp @@ -16,25 +16,23 @@ bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) _bus = bus; _address = dev->address.address; + _port = dev->address.port; #ifdef SCD30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD30_I2C_CLOCK_SPEED */ scd30.begin(*_bus, _address); if (!startMeasurement()) { LOG_ERROR("%s: Failed to start periodic measurement", sensorName); -#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD30_I2C_CLOCK_SPEED */ return false; } @@ -42,9 +40,12 @@ bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) LOG_WARN("%s: Could not determine ASC state", sensorName); } -#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD30_I2C_CLOCK_SPEED */ if (state == SCD30_MEASUREMENT) { status = 1; @@ -62,27 +63,28 @@ bool SCD30Sensor::getMetrics(meshtastic_Telemetry *measurement) float co2, temperature, humidity; #ifdef SCD30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD30_I2C_CLOCK_SPEED */ if (scd30.readMeasurementData(co2, temperature, humidity) != SCD30_NO_ERROR) { LOG_ERROR("SCD30: Failed to read measurement data."); -#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD30_I2C_CLOCK_SPEED */ + return false; } -#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD30_I2C_CLOCK_SPEED */ if (co2 == 0) { LOG_ERROR("SCD30: Invalid CO₂ reading."); @@ -372,23 +374,19 @@ bool SCD30Sensor::isActive() */ uint32_t SCD30Sensor::wakeUp() { - #ifdef SCD30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return 0; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD30_I2C_CLOCK_SPEED */ startMeasurement(); -#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD30_I2C_CLOCK_SPEED */ return 0; } @@ -400,21 +398,18 @@ uint32_t SCD30Sensor::wakeUp() void SCD30Sensor::sleep() { #ifdef SCD30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD30_I2C_CLOCK_SPEED */ stopMeasurement(); -#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD30_I2C_CLOCK_SPEED */ } bool SCD30Sensor::canSleep() @@ -438,14 +433,8 @@ AdminMessageHandleResult SCD30Sensor::handleAdminMessage(const meshtastic_MeshPa AdminMessageHandleResult result; #ifdef SCD30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return AdminMessageHandleResult::NOT_HANDLED; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD30_I2C_CLOCK_SPEED */ switch (request->which_payload_variant) { @@ -501,9 +490,12 @@ AdminMessageHandleResult SCD30Sensor::handleAdminMessage(const meshtastic_MeshPa result = AdminMessageHandleResult::NOT_HANDLED; } -#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD30_I2C_CLOCK_SPEED */ return result; } diff --git a/src/modules/Telemetry/Sensor/SCD30Sensor.h b/src/modules/Telemetry/Sensor/SCD30Sensor.h index 6e03e2dda60..067b9b73b23 100644 --- a/src/modules/Telemetry/Sensor/SCD30Sensor.h +++ b/src/modules/Telemetry/Sensor/SCD30Sensor.h @@ -14,6 +14,7 @@ class SCD30Sensor : public TelemetrySensor SensirionI2cScd30 scd30; TwoWire *_bus{}; uint8_t _address{}; + ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; bool performFRC(uint16_t targetCO2); bool setASC(bool ascEnabled); diff --git a/src/modules/Telemetry/Sensor/SCD4XSensor.cpp b/src/modules/Telemetry/Sensor/SCD4XSensor.cpp index c6ab7bb043b..d5f88312bf4 100644 --- a/src/modules/Telemetry/Sensor/SCD4XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SCD4XSensor.cpp @@ -18,14 +18,8 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) _address = dev->address.address; #ifdef SCD4X_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD4X_I2C_CLOCK_SPEED */ scd4x.begin(*_bus, _address); @@ -35,9 +29,12 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) // Stop periodic measurement if (!stopMeasurement()) { -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } @@ -48,33 +45,45 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) LOG_INFO("%s: Found SCD41", sensorName); if (!powerUp()) { LOG_ERROR("%s: Error trying to execute powerUp()", sensorName); -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } } if (!getASC(ascActive)) { LOG_ERROR("%s: Unable to check if ASC is enabled", sensorName); -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } // Start measurement in selected power mode (low power by default) if (!startMeasurement()) { LOG_ERROR("%s: Couldn't start measurement", sensorName); -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ if (state == SCD4X_MEASUREMENT) { status = 1; @@ -99,31 +108,31 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement) float temperature, humidity; #ifdef SCD4X_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD4X_I2C_CLOCK_SPEED */ bool dataReady; error = scd4x.getDataReadyStatus(dataReady); if (error != SCD4X_NO_ERROR || !dataReady) { -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ LOG_ERROR("SCD4X: Data is not ready"); return false; } error = scd4x.readMeasurement(co2, temperature, humidity); -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ LOG_DEBUG("Got %s readings: co2=%u, co2_temp=%.2f, co2_hum%.2f", sensorName, co2, temperature, humidity); if (error != SCD4X_NO_ERROR) { @@ -637,34 +646,37 @@ bool SCD4XSensor::powerDown() } #ifdef SCD4X_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD4X_I2C_CLOCK_SPEED */ if (!stopMeasurement()) { -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } if (scd4x.powerDown() != SCD4X_NO_ERROR) { LOG_ERROR("%s: Error trying to execute sleep()", sensorName); -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ state = SCD4X_OFF; return true; @@ -711,27 +723,27 @@ uint32_t SCD4XSensor::wakeUp() { #ifdef SCD4X_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return 0; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD4X_I2C_CLOCK_SPEED */ if (startMeasurement()) { co2MeasureStarted = getTime(); -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return SCD4X_WARMUP_MS; } -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return 0; } @@ -743,21 +755,18 @@ uint32_t SCD4XSensor::wakeUp() void SCD4XSensor::sleep() { #ifdef SCD4X_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD4X_I2C_CLOCK_SPEED */ stopMeasurement(); -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ } /** @@ -797,14 +806,8 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa AdminMessageHandleResult result; #ifdef SCD4X_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return AdminMessageHandleResult::NOT_HANDLED; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); #endif /* SCD4X_I2C_CLOCK_SPEED */ // TODO: potentially add selftest command? @@ -907,9 +910,12 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa // Start measurement mode this->startMeasurement(); -#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SCD4X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SCD4X_I2C_CLOCK_SPEED */ return result; } diff --git a/src/modules/Telemetry/Sensor/SCD4XSensor.h b/src/modules/Telemetry/Sensor/SCD4XSensor.h index 1ed86a183b9..76d36dda829 100644 --- a/src/modules/Telemetry/Sensor/SCD4XSensor.h +++ b/src/modules/Telemetry/Sensor/SCD4XSensor.h @@ -17,6 +17,7 @@ class SCD4XSensor : public TelemetrySensor SensirionI2cScd4x scd4x; TwoWire *_bus{}; uint8_t _address{}; + ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; bool performFRC(uint32_t targetCO2); bool setASCBaseline(uint32_t targetCO2); diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp index b638bf47f58..4dd9b5db66f 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp @@ -134,14 +134,8 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum } #ifdef SEN5X_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, _port); #endif /* SEN5X_I2C_CLOCK_SPEED */ // Transmit the data @@ -152,9 +146,12 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum size_t writtenBytes = _bus->write(toSend, bufferSize); uint8_t i2c_error = _bus->endTransmission(); -#if defined(SEN5X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SEN5X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SEN5X_I2C_CLOCK_SPEED */ if (writtenBytes != bufferSize) { LOG_ERROR("SEN5X: Error writting on I2C bus"); @@ -171,14 +168,8 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber) { #ifdef SEN5X_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, _port); #endif /* SEN5X_I2C_CLOCK_SPEED */ size_t readBytes = _bus->requestFrom(_address, byteNumber); @@ -201,9 +192,13 @@ uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber) readBytes -= 3; receivedBytes += 2; } -#if defined(SEN5X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif + +#ifdef SEN5X_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SEN5X_I2C_CLOCK_SPEED */ return receivedBytes; } @@ -567,6 +562,7 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) _bus = bus; _address = dev->address.address; + _port = dev->address.port; delay(50); // without this there is an error on the deviceReset function diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.h b/src/modules/Telemetry/Sensor/SEN5XSensor.h index 9fb25fdd693..22b1c584609 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.h +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.h @@ -62,6 +62,7 @@ class SEN5XSensor : public TelemetrySensor private: TwoWire *_bus{}; uint8_t _address{}; + ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; bool getVersion(); float firmwareVer = -1; diff --git a/src/modules/Telemetry/Sensor/SFA30Sensor.cpp b/src/modules/Telemetry/Sensor/SFA30Sensor.cpp index c5b5845d9e5..7c8a0854424 100644 --- a/src/modules/Telemetry/Sensor/SFA30Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SFA30Sensor.cpp @@ -14,41 +14,45 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) _bus = bus; _address = dev->address.address; + _port = dev->address.port; #ifdef SFA30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SFA30_I2C_CLOCK_SPEED */ sfa30.begin(*_bus, _address); delay(20); if (this->isError(sfa30.deviceReset())) { -#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SFA30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SFA30_I2C_CLOCK_SPEED */ return false; } state = State::IDLE; if (this->isError(sfa30.startContinuousMeasurement())) { -#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SFA30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SFA30_I2C_CLOCK_SPEED */ return false; } LOG_INFO("%s starting measurement", sensorName); -#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SFA30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SFA30_I2C_CLOCK_SPEED */ status = 1; state = State::ACTIVE; @@ -72,14 +76,8 @@ bool SFA30Sensor::isError(uint16_t response) void SFA30Sensor::sleep() { #ifdef SFA30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SFA30_I2C_CLOCK_SPEED */ // Note - not recommended for this sensor on a periodic basis @@ -87,9 +85,12 @@ void SFA30Sensor::sleep() LOG_ERROR("%s: can't stop measurement", sensorName); }; -#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SFA30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SFA30_I2C_CLOCK_SPEED */ LOG_INFO("%s: stop measurement", sensorName); state = State::IDLE; @@ -99,27 +100,27 @@ void SFA30Sensor::sleep() uint32_t SFA30Sensor::wakeUp() { #ifdef SFA30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SFA30_I2C_CLOCK_SPEED */ LOG_INFO("Waking up %s", sensorName); if (this->isError(sfa30.startContinuousMeasurement())) { -#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SFA30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SFA30_I2C_CLOCK_SPEED */ return 0; } -#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SFA30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SFA30_I2C_CLOCK_SPEED */ state = State::ACTIVE; measureStarted = getTime(); @@ -164,24 +165,27 @@ bool SFA30Sensor::getMetrics(meshtastic_Telemetry *measurement) float temperature = 0.0; #ifdef SFA30_I2C_CLOCK_SPEED -#ifdef CAN_RECLOCK_I2C - uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, false); -#elif !HAS_SCREEN - reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, true); -#else - LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; -#endif /* CAN_RECLOCK_I2C */ + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); + uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port); #endif /* SFA30_I2C_CLOCK_SPEED */ if (this->isError(sfa30.readMeasuredValues(hcho, humidity, temperature))) { LOG_WARN("%s: No values", sensorName); +#ifdef SFA30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SFA30_I2C_CLOCK_SPEED */ return false; } -#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) - reClockI2C(currentClock, _bus, false); -#endif +#ifdef SFA30_I2C_CLOCK_SPEED + if (currentClock) { + LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); + reClockI2C(currentClock, _bus, _port); + } +#endif /* SFA30_I2C_CLOCK_SPEED */ measurement->variant.air_quality_metrics.has_form_temperature = true; measurement->variant.air_quality_metrics.has_form_humidity = true; diff --git a/src/modules/Telemetry/Sensor/SFA30Sensor.h b/src/modules/Telemetry/Sensor/SFA30Sensor.h index 9fa9c85fc5e..038a70e1ec7 100644 --- a/src/modules/Telemetry/Sensor/SFA30Sensor.h +++ b/src/modules/Telemetry/Sensor/SFA30Sensor.h @@ -21,6 +21,8 @@ class SFA30Sensor : public TelemetrySensor SensirionI2cSfa3x sfa30; TwoWire *_bus{}; uint8_t _address{}; + ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; + bool isError(uint16_t response); public: From b7ec5cd35a5e2ed59e76854c8dc36d86fa32ab84 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Tue, 26 May 2026 09:55:32 +0200 Subject: [PATCH 06/19] Refurbish ReClockI2C API * Make ReClockI2C API class * Use new API in AirQualityTelemetry module * Minor changes on some logs --- src/detect/ReClockI2C.h | 98 ++++++++++ src/detect/reClockI2C.cpp | 44 ----- src/detect/reClockI2C.h | 14 -- src/modules/Telemetry/AirQualityTelemetry.cpp | 4 +- .../Telemetry/Sensor/PMSA003ISensor.cpp | 44 +++-- src/modules/Telemetry/Sensor/PMSA003ISensor.h | 4 + src/modules/Telemetry/Sensor/SCD30Sensor.cpp | 76 +++----- src/modules/Telemetry/Sensor/SCD30Sensor.h | 4 + src/modules/Telemetry/Sensor/SCD4XSensor.cpp | 112 +++++------ src/modules/Telemetry/Sensor/SCD4XSensor.h | 6 +- src/modules/Telemetry/Sensor/SEN5XSensor.cpp | 177 +++++++++--------- src/modules/Telemetry/Sensor/SEN5XSensor.h | 4 + src/modules/Telemetry/Sensor/SFA30Sensor.cpp | 61 +++--- src/modules/Telemetry/Sensor/SFA30Sensor.h | 4 + variants/esp32/esp32-common.ini | 2 +- 15 files changed, 336 insertions(+), 318 deletions(-) create mode 100644 src/detect/ReClockI2C.h delete mode 100644 src/detect/reClockI2C.cpp delete mode 100644 src/detect/reClockI2C.h diff --git a/src/detect/ReClockI2C.h b/src/detect/ReClockI2C.h new file mode 100644 index 00000000000..90cc859cb9f --- /dev/null +++ b/src/detect/ReClockI2C.h @@ -0,0 +1,98 @@ +#pragma once + +#ifndef RECLOCK_I2C_ +#define RECLOCK_I2C_ + +#include "../graphics/Screen.h" +#include "ScanI2CTwoWire.h" +#include +#include + +/* Class to set and restore the I2C clock temporarily on a i2cBus + See https://github.com/arduino/Arduino/issues/11457 + Currently, only ESP32 can getClock() + While all cores can setClock() + https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50 + https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60 + https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103 + For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes) + we need to reclock I2C and set it back to the previous stablished speed. + Only for cases where we can know it (ESP32 or known screen) we can do this. +*/ + +extern graphics::Screen *screen; + +class ReClockI2C +{ + public: + void setup(TwoWire *i2cBus, ScanI2C::I2CPort port) + { + this->i2cBus = i2cBus; + this->port = port; + this->previousClock = 0; + } + + bool setClock(uint32_t desiredClock) + { + uint32_t currentClock = this->getClock(); + + if (currentClock) { + LOG_DEBUG("Current I2C frequency: %uHz", currentClock); + } + + if (currentClock != desiredClock) { + LOG_DEBUG("Changing I2C clock to %uHz", desiredClock); + this->i2cBus->setClock(desiredClock); + // If the clock is 0Hz, we still store it + // We'll check in restoreClock function + setPreviousClock(currentClock); + LOG_DEBUG("Stored previous clock I2C clock: %uHz", this->previousClock); + return true; + } + + LOG_DEBUG("I2C clock was already %uHz. Skipping", desiredClock); + return false; + } + + bool restoreClock() + { + if (this->previousClock) { + LOG_DEBUG("Restoring I2C clock to %uHz", this->previousClock); + i2cBus->setClock(this->previousClock); + return true; + } + LOG_DEBUG("I2C clock was unknown. Not restored"); + return false; + } + + private: + TwoWire *i2cBus{}; + ScanI2C::I2CPort port{}; + uint32_t previousClock = 0; + + void setPreviousClock(uint32_t clock) { this->previousClock = clock; } + + uint32_t getClock() + { + +#ifdef CAN_GET_I2C_CLOCK + return this->i2cBus->getClock(); +#elif HAS_SCREEN + if (screen) { + // If we get a non-zero response here, the screen has set a speed + uint32_t screenClock = 0; + ScanI2C::I2CPort screenPort = ScanI2C::I2CPort::NO_I2C; + screenClock = screen->getI2cFrequency(); + screenPort = screen->getI2CPort(); + // Check if i2c port is the same, and that we got a screenClock back (0 means the screen didn't set it) + if (screenClock && (screenPort == this->port)) { + LOG_DEBUG("Screen defined I2C frequency: %uHz", screenClock); + return screenClock; + } + } +#endif + return 0; + } +}; + +#endif diff --git a/src/detect/reClockI2C.cpp b/src/detect/reClockI2C.cpp deleted file mode 100644 index df81a7e2318..00000000000 --- a/src/detect/reClockI2C.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "reClockI2C.h" -#include "ScanI2CTwoWire.h" - -/* See https://github.com/arduino/Arduino/issues/11457 - Currently, only ESP32 can getClock() - While all cores can setClock() - https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50 - https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60 - https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103 - For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes) - we need to reclock I2C and set it back to the previous stablished speed. - Only for cases where we can know it (ESP32 or known screen) we can do this. -*/ - -uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, ScanI2C::I2CPort port) -{ - - uint32_t currentClock = 0; - uint32_t screenClock = 0; - ScanI2C::I2CPort screenPort = ScanI2C::I2CPort::NO_I2C; - - // Assume that if we can't getClock, or there is no screen, we can set the clock speed at will -#ifdef CAN_RECLOCK_I2C - currentClock = i2cBus->getClock(); - LOG_DEBUG("Current I2C frequency: %uHz", currentClock); -#elif HAS_SCREEN - if (screen) { - // If we get a non-zero response here, the screen has set a speed - screenClock = screen->getI2cFrequency(); - screenPort = screen->getI2CPort(); - // Check if i2c port is the same, and that we got a screenClock back (0 means the screen didn't set it) - if (screenClock && (screenPort == port)) - currentClock = screenClock; - LOG_DEBUG("Screen defined I2C frequency: %uHz", screenClock); - } -#endif - - if (currentClock != desiredClock) { - LOG_DEBUG("Changing I2C clock to %uHz", desiredClock); - i2cBus->setClock(desiredClock); - } - - return currentClock; -} diff --git a/src/detect/reClockI2C.h b/src/detect/reClockI2C.h deleted file mode 100644 index b2852541403..00000000000 --- a/src/detect/reClockI2C.h +++ /dev/null @@ -1,14 +0,0 @@ - -#ifndef RECLOCK_I2C_ -#define RECLOCK_I2C_ - -#include "../graphics/Screen.h" -#include "ScanI2CTwoWire.h" -#include -#include - -uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, ScanI2C::I2CPort port); - -extern graphics::Screen *screen; - -#endif diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 3d7cb73510b..a50ea8e5726 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -110,10 +110,10 @@ int32_t AirQualityTelemetryModule::runOnce() } // Wake up the sensors that need it - LOG_INFO("Waking up sensors..."); uint32_t lastTelemetry = transmitHistory ? transmitHistory->getLastSentToMeshMillis(TX_HISTORY_KEY_AIR_QUALITY_TELEMETRY) : 0; for (TelemetrySensor *sensor : sensors) { + LOG_DEBUG("Checking if %s needs to wake up", sensor->sensorName); if (!sensor->canSleep()) { LOG_DEBUG("%s sensor doesn't have sleep feature. Skipping", sensor->sensorName); } else if (((lastTelemetry == 0) || !Throttle::isWithinTimespanMs(lastTelemetry - sensor->wakeUpTimeMs(), @@ -154,8 +154,8 @@ int32_t AirQualityTelemetryModule::runOnce() } // Send to sleep sensors that consume power - LOG_DEBUG("Sending sensors to sleep"); for (TelemetrySensor *sensor : sensors) { + LOG_DEBUG("Checking if %s can be sent to sleep", sensor->sensorName); if (sensor->isActive() && sensor->canSleep()) { if (sensor->wakeUpTimeMs() < (int32_t)Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.air_quality_interval, diff --git a/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp b/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp index c6711fc5ae6..357545f27ca 100644 --- a/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp +++ b/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp @@ -2,7 +2,6 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR -#include "../detect/reClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "PMSA003ISensor.h" #include "TelemetrySensor.h" @@ -13,31 +12,36 @@ PMSA003ISensor::PMSA003ISensor() : TelemetrySensor(meshtastic_TelemetrySensorTyp bool PMSA003ISensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { - LOG_INFO("Init sensor: %s", sensorName); + LOG_INFO("%s: Init sensor", sensorName); #ifdef PMSA003I_ENABLE_PIN pinMode(PMSA003I_ENABLE_PIN, OUTPUT); #endif + // TODO PMS5003I sometimes get late to the party... + _bus = bus; _address = dev->address.address; +#ifdef PMSA003I_I2C_CLOCK_SPEED _port = dev->address.port; + reClockI2C.setup(_bus, _port); -#ifdef PMSA003I_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED); + reClockI2C.setClock(PMSA003I_I2C_CLOCK_SPEED); #endif /* PMSA003I_I2C_CLOCK_SPEED */ _bus->beginTransmission(_address); if (_bus->endTransmission() != 0) { LOG_WARN("%s not found on I2C at 0x12", sensorName); +#ifdef PMSA003I_I2C_CLOCK_SPEED + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); +#endif /* PMSA003I_I2C_CLOCK_SPEED */ return false; } #ifdef PMSA003I_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* PMSA003I_I2C_CLOCK_SPEED */ status = 1; @@ -55,13 +59,17 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement) } #ifdef PMSA003I_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED); + reClockI2C.setClock(PMSA003I_I2C_CLOCK_SPEED); #endif /* PMSA003I_I2C_CLOCK_SPEED */ _bus->requestFrom(_address, (uint8_t)PMSA003I_FRAME_LENGTH); if (_bus->available() < PMSA003I_FRAME_LENGTH) { - LOG_WARN("%s read failed: incomplete data (%d bytes)", sensorName, _bus->available()); + LOG_WARN("%s: read failed: incomplete data (%d bytes)", sensorName, _bus->available()); +#ifdef PMSA003I_I2C_CLOCK_SPEED + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); +#endif /* PMSA003I_I2C_CLOCK_SPEED */ return false; } @@ -70,14 +78,12 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement) } #ifdef PMSA003I_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* PMSA003I_I2C_CLOCK_SPEED */ if (buffer[0] != 0x42 || buffer[1] != 0x4D) { - LOG_WARN("%s frame header invalid: 0x%02X 0x%02X", sensorName, buffer[0], buffer[1]); + LOG_WARN("%s: frame header invalid: 0x%02X 0x%02X", sensorName, buffer[0], buffer[1]); return false; } @@ -133,7 +139,7 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement) measurement->variant.air_quality_metrics.has_particles_100um = true; measurement->variant.air_quality_metrics.particles_100um = read16(buffer, 26); - LOG_DEBUG("Got %s readings: pM1p0_standard=%u, pM2p5_standard=%u, pM10p0_standard=%u", sensorName, + LOG_DEBUG("%s: Got readings: pM1p0_standard=%u, pM2p5_standard=%u, pM10p0_standard=%u", sensorName, measurement->variant.air_quality_metrics.pm10_standard, measurement->variant.air_quality_metrics.pm25_standard, measurement->variant.air_quality_metrics.pm100_standard); @@ -192,7 +198,7 @@ void PMSA003ISensor::sleep() uint32_t PMSA003ISensor::wakeUp() { #ifdef PMSA003I_ENABLE_PIN - LOG_INFO("Waking up %s", sensorName); + LOG_INFO("%s: Waking up", sensorName); digitalWrite(PMSA003I_ENABLE_PIN, HIGH); state = State::ACTIVE; pmMeasureStarted = getTime(); diff --git a/src/modules/Telemetry/Sensor/PMSA003ISensor.h b/src/modules/Telemetry/Sensor/PMSA003ISensor.h index ed01a188ddd..ce7bba4bbc0 100644 --- a/src/modules/Telemetry/Sensor/PMSA003ISensor.h +++ b/src/modules/Telemetry/Sensor/PMSA003ISensor.h @@ -2,6 +2,7 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR +#include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "RTC.h" #include "TelemetrySensor.h" @@ -35,7 +36,10 @@ class PMSA003ISensor : public TelemetrySensor 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 diff --git a/src/modules/Telemetry/Sensor/SCD30Sensor.cpp b/src/modules/Telemetry/Sensor/SCD30Sensor.cpp index b9c7617ad7b..a752b105deb 100644 --- a/src/modules/Telemetry/Sensor/SCD30Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SCD30Sensor.cpp @@ -2,7 +2,6 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include() -#include "../detect/reClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "SCD30Sensor.h" @@ -12,15 +11,16 @@ SCD30Sensor::SCD30Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SCD3 bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { - LOG_INFO("Init sensor: %s", sensorName); + LOG_INFO("%s: Init sensor", sensorName); _bus = bus; _address = dev->address.address; +#ifdef SCD30_I2C_CLOCK_SPEED _port = dev->address.port; + reClockI2C.setup(_bus, _port); -#ifdef SCD30_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED); #endif /* SCD30_I2C_CLOCK_SPEED */ scd30.begin(*_bus, _address); @@ -28,10 +28,8 @@ bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) if (!startMeasurement()) { LOG_ERROR("%s: Failed to start periodic measurement", sensorName); #ifdef SCD30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ return false; } @@ -41,10 +39,8 @@ bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) } #ifdef SCD30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ if (state == SCD30_MEASUREMENT) { @@ -63,31 +59,27 @@ bool SCD30Sensor::getMetrics(meshtastic_Telemetry *measurement) float co2, temperature, humidity; #ifdef SCD30_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED); #endif /* SCD30_I2C_CLOCK_SPEED */ if (scd30.readMeasurementData(co2, temperature, humidity) != SCD30_NO_ERROR) { - LOG_ERROR("SCD30: Failed to read measurement data."); + LOG_ERROR("%s: Failed to read measurement data", sensorName); #ifdef SCD30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ return false; } #ifdef SCD30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ if (co2 == 0) { - LOG_ERROR("SCD30: Invalid CO₂ reading."); + LOG_ERROR("%s: Invalid CO₂ reading", sensorName); return false; } @@ -98,7 +90,7 @@ bool SCD30Sensor::getMetrics(meshtastic_Telemetry *measurement) measurement->variant.air_quality_metrics.co2_temperature = temperature; measurement->variant.air_quality_metrics.co2_humidity = humidity; - LOG_DEBUG("Got %s readings: co2=%u, co2_temp=%.2f, co2_hum=%.2f", sensorName, (uint32_t)co2, temperature, humidity); + LOG_DEBUG("%s: Got readings: co2=%u, co2_temp=%.2f, co2_hum=%.2f", sensorName, (uint32_t)co2, temperature, humidity); return true; } @@ -285,7 +277,7 @@ bool SCD30Sensor::setTemperature(float tempReference) tempOffset = (temperature - tempReference); if (tempOffset < 0) { - LOG_ERROR("%s temperature offset is only positive", sensorName); + LOG_ERROR("%s: temperature offset is only positive", sensorName); return false; } @@ -375,17 +367,15 @@ bool SCD30Sensor::isActive() uint32_t SCD30Sensor::wakeUp() { #ifdef SCD30_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED); #endif /* SCD30_I2C_CLOCK_SPEED */ startMeasurement(); #ifdef SCD30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ return 0; @@ -398,17 +388,15 @@ uint32_t SCD30Sensor::wakeUp() void SCD30Sensor::sleep() { #ifdef SCD30_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED); #endif /* SCD30_I2C_CLOCK_SPEED */ stopMeasurement(); #ifdef SCD30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ } @@ -433,8 +421,8 @@ AdminMessageHandleResult SCD30Sensor::handleAdminMessage(const meshtastic_MeshPa AdminMessageHandleResult result; #ifdef SCD30_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED); #endif /* SCD30_I2C_CLOCK_SPEED */ switch (request->which_payload_variant) { @@ -491,10 +479,8 @@ AdminMessageHandleResult SCD30Sensor::handleAdminMessage(const meshtastic_MeshPa } #ifdef SCD30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ return result; diff --git a/src/modules/Telemetry/Sensor/SCD30Sensor.h b/src/modules/Telemetry/Sensor/SCD30Sensor.h index 067b9b73b23..64ca7342029 100644 --- a/src/modules/Telemetry/Sensor/SCD30Sensor.h +++ b/src/modules/Telemetry/Sensor/SCD30Sensor.h @@ -2,6 +2,7 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include() +#include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" #include @@ -14,7 +15,10 @@ class SCD30Sensor : public TelemetrySensor SensirionI2cScd30 scd30; TwoWire *_bus{}; uint8_t _address{}; +#ifdef SCD30_I2C_CLOCK_SPEED ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; + ReClockI2C reClockI2C; +#endif bool performFRC(uint16_t targetCO2); bool setASC(bool ascEnabled); diff --git a/src/modules/Telemetry/Sensor/SCD4XSensor.cpp b/src/modules/Telemetry/Sensor/SCD4XSensor.cpp index d5f88312bf4..aa9ac91653b 100644 --- a/src/modules/Telemetry/Sensor/SCD4XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SCD4XSensor.cpp @@ -2,7 +2,6 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include() -#include "../detect/reClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "SCD4XSensor.h" @@ -18,8 +17,11 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) _address = dev->address.address; #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); + _port = dev->address.port; + reClockI2C.setup(_bus, _port); + + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED); #endif /* SCD4X_I2C_CLOCK_SPEED */ scd4x.begin(*_bus, _address); @@ -30,10 +32,8 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) // Stop periodic measurement if (!stopMeasurement()) { #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } @@ -46,10 +46,8 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) if (!powerUp()) { LOG_ERROR("%s: Error trying to execute powerUp()", sensorName); #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } @@ -58,10 +56,8 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) if (!getASC(ascActive)) { LOG_ERROR("%s: Unable to check if ASC is enabled", sensorName); #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } @@ -70,19 +66,15 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) if (!startMeasurement()) { LOG_ERROR("%s: Couldn't start measurement", sensorName); #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ if (state == SCD4X_MEASUREMENT) { @@ -108,18 +100,16 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement) float temperature, humidity; #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED); #endif /* SCD4X_I2C_CLOCK_SPEED */ bool dataReady; error = scd4x.getDataReadyStatus(dataReady); if (error != SCD4X_NO_ERROR || !dataReady) { #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ LOG_ERROR("SCD4X: Data is not ready"); return false; @@ -128,10 +118,8 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement) error = scd4x.readMeasurement(co2, temperature, humidity); #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ LOG_DEBUG("Got %s readings: co2=%u, co2_temp=%.2f, co2_hum%.2f", sensorName, co2, temperature, humidity); @@ -646,16 +634,14 @@ bool SCD4XSensor::powerDown() } #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED); #endif /* SCD4X_I2C_CLOCK_SPEED */ if (!stopMeasurement()) { #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } @@ -663,19 +649,15 @@ bool SCD4XSensor::powerDown() if (scd4x.powerDown() != SCD4X_NO_ERROR) { LOG_ERROR("%s: Error trying to execute sleep()", sensorName); #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return false; } #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ state = SCD4X_OFF; @@ -723,26 +705,22 @@ uint32_t SCD4XSensor::wakeUp() { #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED); #endif /* SCD4X_I2C_CLOCK_SPEED */ if (startMeasurement()) { co2MeasureStarted = getTime(); #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return SCD4X_WARMUP_MS; } #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return 0; @@ -755,17 +733,15 @@ uint32_t SCD4XSensor::wakeUp() void SCD4XSensor::sleep() { #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED); #endif /* SCD4X_I2C_CLOCK_SPEED */ stopMeasurement(); #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ } @@ -806,8 +782,8 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa AdminMessageHandleResult result; #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port); + LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED); #endif /* SCD4X_I2C_CLOCK_SPEED */ // TODO: potentially add selftest command? @@ -911,10 +887,8 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa this->startMeasurement(); #ifdef SCD4X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ return result; diff --git a/src/modules/Telemetry/Sensor/SCD4XSensor.h b/src/modules/Telemetry/Sensor/SCD4XSensor.h index 76d36dda829..03ff4abc224 100644 --- a/src/modules/Telemetry/Sensor/SCD4XSensor.h +++ b/src/modules/Telemetry/Sensor/SCD4XSensor.h @@ -2,13 +2,14 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include() +#include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "RTC.h" #include "TelemetrySensor.h" #include // Max speed 400kHz -#define SCD4X_I2C_CLOCK_SPEED 100000 +#define SCD4X_I2C_CLOCK_SPEED 400000 #define SCD4X_WARMUP_MS 5000 class SCD4XSensor : public TelemetrySensor @@ -17,7 +18,10 @@ class SCD4XSensor : public TelemetrySensor SensirionI2cScd4x scd4x; TwoWire *_bus{}; uint8_t _address{}; +#ifdef SCD4X_I2C_CLOCK_SPEED ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; + ReClockI2C reClockI2C; +#endif bool performFRC(uint32_t targetCO2); bool setASCBaseline(uint32_t targetCO2); diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp index 4dd9b5db66f..ab14215b64c 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp @@ -2,7 +2,6 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR -#include "../detect/reClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "FSCommon.h" #include "SEN5XSensor.h" @@ -18,7 +17,7 @@ SEN5XSensor::SEN5XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SEN5 bool SEN5XSensor::getVersion() { if (!sendCommand(SEN5X_GET_FIRMWARE_VERSION)) { - LOG_ERROR("SEN5X: Error sending version command"); + LOG_ERROR("%s: Error sending version command", sensorName); return false; } delay(20); // From Sensirion Datasheet @@ -26,7 +25,7 @@ bool SEN5XSensor::getVersion() uint8_t versionBuffer[12]{}; size_t charNumber = readBuffer(&versionBuffer[0], 3); if (charNumber == 0) { - LOG_ERROR("SEN5X: Error getting data ready flag value"); + LOG_ERROR("%s: Error getting data ready flag value", sensorName); return false; } @@ -34,9 +33,9 @@ bool SEN5XSensor::getVersion() hardwareVer = versionBuffer[3] + (versionBuffer[4] / 10); protocolVer = versionBuffer[5] + (versionBuffer[6] / 10); - LOG_INFO("SEN5X Firmware Version: %0.2f", firmwareVer); - LOG_INFO("SEN5X Hardware Version: %0.2f", hardwareVer); - LOG_INFO("SEN5X Protocol Version: %0.2f", protocolVer); + LOG_INFO("%s: Firmware Version: %0.2f", sensorName, firmwareVer); + LOG_INFO("%s: Hardware Version: %0.2f", sensorName, hardwareVer); + LOG_INFO("%s: Protocol Version: %0.2f", sensorName, protocolVer); return true; } @@ -44,7 +43,7 @@ bool SEN5XSensor::getVersion() bool SEN5XSensor::findModel() { if (!sendCommand(SEN5X_GET_PRODUCT_NAME)) { - LOG_ERROR("SEN5X: Error asking for product name"); + LOG_ERROR("%s: Error asking for product name", sensorName); return false; } delay(50); // From Sensirion Datasheet @@ -53,7 +52,7 @@ bool SEN5XSensor::findModel() uint8_t name[nameSize]; size_t charNumber = readBuffer(&name[0], nameSize); if (charNumber == 0) { - LOG_ERROR("SEN5X: Error getting device name"); + LOG_ERROR("%s: Error getting device name", sensorName); return false; } @@ -61,15 +60,15 @@ bool SEN5XSensor::findModel() switch (name[4]) { case 48: model = SEN50; - LOG_INFO("SEN5X: found sensor model SEN50"); + LOG_INFO("%s: found sensor model SEN50", sensorName); break; case 52: model = SEN54; - LOG_INFO("SEN5X: found sensor model SEN54"); + LOG_INFO("%s: found sensor model SEN54", sensorName); break; case 53: model = SEN55; - LOG_INFO("SEN5X: found sensor model SEN55"); + LOG_INFO("%s: found sensor model SEN55", sensorName); break; } @@ -134,8 +133,8 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum } #ifdef SEN5X_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, _port); + LOG_DEBUG("%s: Attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED); + reClockI2C.setClock(SEN5X_I2C_CLOCK_SPEED); #endif /* SEN5X_I2C_CLOCK_SPEED */ // Transmit the data @@ -147,19 +146,17 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum uint8_t i2c_error = _bus->endTransmission(); #ifdef SEN5X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_DEBUG("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SEN5X_I2C_CLOCK_SPEED */ if (writtenBytes != bufferSize) { - LOG_ERROR("SEN5X: Error writting on I2C bus"); + LOG_ERROR("%s: Error writting on I2C bus", sensorName); return false; } if (i2c_error != 0) { - LOG_ERROR("SEN5X: Error on I2C communication: %x", i2c_error); + LOG_ERROR("%s: Error on I2C communication: %x", sensorName, i2c_error); return false; } return true; @@ -168,13 +165,17 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber) { #ifdef SEN5X_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, _port); + LOG_DEBUG("%s: Attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED); + reClockI2C.setClock(SEN5X_I2C_CLOCK_SPEED); #endif /* SEN5X_I2C_CLOCK_SPEED */ size_t readBytes = _bus->requestFrom(_address, byteNumber); if (readBytes != byteNumber) { - LOG_ERROR("SEN5X: Error reading I2C bus"); + LOG_ERROR("%s: Error reading I2C bus", sensorName); +#ifdef SEN5X_I2C_CLOCK_SPEED + LOG_DEBUG("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); +#endif /* SEN5X_I2C_CLOCK_SPEED */ return 0; } @@ -186,7 +187,11 @@ uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber) uint8_t recvCRC = _bus->read(); uint8_t calcCRC = sen5xCRC(&buffer[i - 2]); if (recvCRC != calcCRC) { - LOG_ERROR("SEN5X: Checksum error while receiving msg"); + LOG_ERROR("%s: Checksum error while receiving msg", sensorName); +#ifdef SEN5X_I2C_CLOCK_SPEED + LOG_DEBUG("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); +#endif /* SEN5X_I2C_CLOCK_SPEED */ return 0; } readBytes -= 3; @@ -194,10 +199,8 @@ uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber) } #ifdef SEN5X_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_DEBUG("%s: restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SEN5X_I2C_CLOCK_SPEED */ return receivedBytes; @@ -326,24 +329,24 @@ bool SEN5XSensor::vocStateToSensor() } if (!vocStateValid()) { - LOG_INFO("SEN5X: VOC state is invalid, not sending"); + LOG_INFO("%s: VOC state is invalid, not sending", sensorName); return true; } if (!sendCommand(SEN5X_STOP_MEASUREMENT)) { - LOG_ERROR("SEN5X: Error stoping measurement"); + LOG_ERROR("%s: Error stoping measurement", sensorName); return false; } delay(200); // From Sensirion Datasheet - LOG_DEBUG("SEN5X: Sending VOC state to sensor"); + LOG_DEBUG("%s: Sending VOC state to sensor", sensorName); LOG_DEBUG("[%u, %u, %u, %u, %u, %u, %u, %u]", vocState[0], vocState[1], vocState[2], vocState[3], vocState[4], vocState[5], vocState[6], vocState[7]); // Note: send command already takes into account the CRC // buffer size increment needed if (!sendCommand(SEN5X_RW_VOCS_STATE, vocState, SEN5X_VOC_STATE_BUFFER_SIZE)) { - LOG_ERROR("SEN5X: Error sending VOC's state command'"); + LOG_ERROR("%s: Error sending VOC's state command'", sensorName); return false; } @@ -356,10 +359,10 @@ bool SEN5XSensor::vocStateFromSensor() return true; } - LOG_INFO("SEN5X: Getting VOC state from sensor"); + LOG_INFO("%s: Getting VOC state from sensor", sensorName); // Ask VOCs state from the sensor if (!sendCommand(SEN5X_RW_VOCS_STATE)) { - LOG_ERROR("SEN5X: Error sending VOC's state command'"); + LOG_ERROR("%s: Error sending VOC's state command'", sensorName); return false; } @@ -371,13 +374,13 @@ bool SEN5XSensor::vocStateFromSensor() delay(20); // From Sensirion Datasheet if (receivedNumber == 0) { - LOG_DEBUG("SEN5X: Error getting VOC's state"); + LOG_DEBUG("%s: Error getting VOC's state", sensorName); return false; } // Print the state (if debug is on) - LOG_DEBUG("SEN5X: VOC state retrieved from sensor: [%u, %u, %u, %u, %u, %u, %u, %u]", vocState[0], vocState[1], vocState[2], - vocState[3], vocState[4], vocState[5], vocState[6], vocState[7]); + LOG_DEBUG("%s: VOC state retrieved from sensor: [%u, %u, %u, %u, %u, %u, %u, %u]", sensorName, vocState[0], vocState[1], + vocState[2], vocState[3], vocState[4], vocState[5], vocState[6], vocState[7]); return true; } @@ -389,11 +392,11 @@ bool SEN5XSensor::loadState() auto file = FSCom.open(sen5XStateFileName, FILE_O_READ); bool okay = false; if (file) { - LOG_INFO("%s state read from %s", sensorName, sen5XStateFileName); + LOG_INFO("%s: state read from %s", sensorName, sen5XStateFileName); pb_istream_t stream = {&readcb, &file, meshtastic_SEN5XState_size}; if (!pb_decode(&stream, &meshtastic_SEN5XState_msg, &sen5xstate)) { - LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream)); + LOG_ERROR("%s: can't decode protobuf %s", sensorName, PB_GET_ERROR(&stream)); } else { lastCleaning = sen5xstate.last_cleaning_time; lastCleaningValid = sen5xstate.last_cleaning_valid; @@ -425,12 +428,12 @@ bool SEN5XSensor::loadState() } file.close(); } else { - LOG_INFO("No %s state found (File: %s)", sensorName, sen5XStateFileName); + LOG_INFO("%s: No state found (File: %s)", sensorName, sen5XStateFileName); } spiLock->unlock(); return okay; #else - LOG_ERROR("SEN5X: ERROR - Filesystem not implemented"); + LOG_ERROR("%s: Filesystem not implemented", sensorName); #endif } @@ -463,7 +466,7 @@ bool SEN5XSensor::saveState() pb_ostream_t stream = {&writecb, static_cast(&file), meshtastic_SEN5XState_size}; if (!pb_encode(&stream, &meshtastic_SEN5XState_msg, &sen5xstate)) { - LOG_ERROR("Error: can't encode protobuf %s", PB_GET_ERROR(&stream)); + LOG_ERROR("%s: can't encode protobuf %s", sensorName, PB_GET_ERROR(&stream)); } else { okay = true; } @@ -475,7 +478,7 @@ bool SEN5XSensor::saveState() return okay; #else - LOG_ERROR("%s: ERROR - Filesystem not implemented", sensorName); + LOG_ERROR("%s: Filesystem not implemented", sensorName); #endif } @@ -487,10 +490,10 @@ bool SEN5XSensor::isActive() uint32_t SEN5XSensor::wakeUp() { - LOG_DEBUG("SEN5X: Waking up sensor"); + LOG_DEBUG("%s: Waking up sensor", sensorName); if (!sendCommand(SEN5X_START_MEASUREMENT)) { - LOG_ERROR("SEN5X: Error starting measurement"); + LOG_ERROR("%s: Error starting measurement", sensorName); // TODO - what should this return?? Something actually on the default interval? return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } @@ -502,7 +505,7 @@ uint32_t SEN5XSensor::wakeUp() pmMeasureStarted = getTime(); state = SEN5X_MEASUREMENT; if (state == SEN5X_MEASUREMENT) - LOG_INFO("SEN5X: Started measurement mode"); + LOG_INFO("%s: Started measurement mode", sensorName); return SEN5X_WARMUP_MS_1; } @@ -511,7 +514,7 @@ bool SEN5XSensor::vocStateStable() uint32_t now; now = getTime(); uint32_t sinceFirstMeasureStarted = (now - rhtGasMeasureStarted); - LOG_DEBUG("sinceFirstMeasureStarted: %us", sinceFirstMeasureStarted); + LOG_DEBUG("%s: sinceFirstMeasureStarted: %us", sensorName, sinceFirstMeasureStarted); return sinceFirstMeasureStarted > SEN5X_VOC_STATE_WARMUP_S; } @@ -523,25 +526,25 @@ bool SEN5XSensor::startCleaning() // Note that cleaning command can only be run when the sensor is in measurement mode if (!sendCommand(SEN5X_START_MEASUREMENT)) { - LOG_ERROR("SEN5X: Error starting measurment mode"); + LOG_ERROR("%s: Error starting measurment mode", sensorName); return false; } delay(50); // From Sensirion Datasheet if (!sendCommand(SEN5X_START_FAN_CLEANING)) { - LOG_ERROR("SEN5X: Error starting fan cleaning"); + LOG_ERROR("%s: Error starting fan cleaning", sensorName); return false; } delay(20); // From Sensirion Datasheet // This message will be always printed so the user knows the device it's not hung - LOG_INFO("SEN5X: Started fan cleaning it will take 10 seconds..."); + LOG_INFO("%s: Started fan cleaning it will take 10 seconds...", sensorName); uint16_t started = millis(); while (millis() - started < 10500) { delay(500); } - LOG_INFO("SEN5X: Cleaning done!!"); + LOG_INFO("%s: Cleaning done", sensorName); // Save timestamp in flash so we know when a week has passed uint32_t now; @@ -558,22 +561,25 @@ bool SEN5XSensor::startCleaning() bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { state = SEN5X_NOT_DETECTED; - LOG_INFO("Init sensor: %s", sensorName); + LOG_INFO("%s: Init sensor", sensorName); _bus = bus; _address = dev->address.address; +#ifdef SEN5X_I2C_CLOCK_SPEED _port = dev->address.port; + reClockI2C.setup(_bus, _port); +#endif /* SEN5X_I2C_CLOCK_SPEED */ delay(50); // without this there is an error on the deviceReset function if (!sendCommand(SEN5X_RESET)) { - LOG_ERROR("SEN5X: Error reseting device"); + LOG_ERROR("%s: error reseting device", sensorName); return false; } delay(200); // From Sensirion Datasheet if (!findModel()) { - LOG_ERROR("SEN5X: error finding sensor model"); + LOG_ERROR("%s: error finding sensor model", sensorName); return false; } @@ -581,7 +587,7 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) if (!getVersion()) return false; if (firmwareVer < 2) { - LOG_ERROR("SEN5X: error firmware is too old and will not work with this implementation"); + LOG_ERROR("%s: firmware is too old and will not work with this implementation", sensorName); return false; } delay(200); // From Sensirion Datasheet @@ -606,11 +612,12 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) if (passed > ONE_WEEK_IN_SECONDS && (now > SEN5X_VOC_VALID_DATE)) { // If current date greater than 01/01/2018 (validity check) - LOG_INFO("SEN5X: More than a week (%us) since last cleaning in epoch (%us). Trigger, cleaning...", passed, - lastCleaning); + LOG_INFO("%s: More than a week (%us) since last cleaning in epoch (%us). Trigger, cleaning...", sensorName, + passed, lastCleaning); startCleaning(); } else { - LOG_INFO("SEN5X: Cleaning not needed (%ds passed). Last cleaning date (in epoch): %us", passed, lastCleaning); + LOG_INFO("%s: Cleaning not needed (%ds passed). Last cleaning date (in epoch): %us", sensorName, passed, + lastCleaning); } } else { // We assume the device has just been updated or it is new, @@ -619,29 +626,29 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) // Otherwise, we will never trigger cleaning in some cases lastCleaning = now; lastCleaningValid = true; - LOG_INFO("SEN5X: No valid last cleaning date found, saving it now: %us", lastCleaning); + LOG_INFO("%s: No valid last cleaning date found, saving it now: %us", sensorName, lastCleaning); saveState(); } if (model != SEN50) { if (!vocValid) { - LOG_INFO("SEN5X: No valid VOC's state found"); + LOG_INFO("%s: No valid VOC's state found", sensorName); } else { // Check if state is recent if (vocStateRecent(now)) { // If current date greater than 01/01/2018 (validity check) // Send it to the sensor - LOG_INFO("SEN5X: VOC state is valid and recent"); + LOG_INFO("%s: VOC state is valid and recent", sensorName); vocStateToSensor(); } else { - LOG_INFO("SEN5X: VOC state is too old or date is invalid"); - LOG_DEBUG("SEN5X: vocTime %u, Passed %u, and now %u", vocTime, passed, now); + LOG_INFO("%s: VOC state is too old or date is invalid", sensorName); + LOG_DEBUG("%s: vocTime %u, Passed %u, and now %u", sensorName, vocTime, passed, now); } } } } else { // TODO - Should this actually ignore? We could end up never cleaning... - LOG_INFO("SEN5X: Not enough RTCQuality, ignoring saved cleaning and VOC state"); + LOG_INFO("%s: Not enough RTCQuality, ignoring saved cleaning and VOC state", sensorName); } idle(false); @@ -654,16 +661,16 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) bool SEN5XSensor::readValues() { if (!sendCommand(SEN5X_READ_VALUES)) { - LOG_ERROR("SEN5X: Error sending read command"); + LOG_ERROR("%s: Error sending read command", sensorName); return false; } - LOG_DEBUG("SEN5X: Reading PM Values"); + LOG_DEBUG("%s: Reading PM Values", sensorName); delay(20); // From Sensirion Datasheet uint8_t dataBuffer[16]{}; size_t receivedNumber = readBuffer(&dataBuffer[0], 24); if (receivedNumber == 0) { - LOG_ERROR("SEN5X: Error getting values"); + LOG_ERROR("%s: Error getting values", sensorName); return false; } @@ -688,16 +695,16 @@ bool SEN5XSensor::readValues() sen5xmeasurement.vocIndex = !isnan(int_vocIndex) ? int_vocIndex / 10.0f : FLT_MAX; sen5xmeasurement.noxIndex = !isnan(int_noxIndex) ? int_noxIndex / 10.0f : FLT_MAX; - LOG_DEBUG("Got %s readings: pM1p0=%u, pM2p5=%u, pM4p0=%u, pM10p0=%u", sensorName, sen5xmeasurement.pM1p0, + LOG_DEBUG("%s: Got readings: pM1p0=%u, pM2p5=%u, pM4p0=%u, pM10p0=%u", sensorName, sen5xmeasurement.pM1p0, sen5xmeasurement.pM2p5, sen5xmeasurement.pM4p0, sen5xmeasurement.pM10p0); if (model != SEN50) { - LOG_DEBUG("Got %s readings: humidity=%.2f, temperature=%.2f, vocIndex=%.2f", sensorName, sen5xmeasurement.humidity, + LOG_DEBUG("%s: Got readings: humidity=%.2f, temperature=%.2f, vocIndex=%.2f", sensorName, sen5xmeasurement.humidity, sen5xmeasurement.temperature, sen5xmeasurement.vocIndex); } if (model == SEN55) { - LOG_DEBUG("Got %s readings: noxIndex=%.2f", sensorName, sen5xmeasurement.noxIndex); + LOG_DEBUG("%s: Got readings: noxIndex=%.2f", sensorName, sen5xmeasurement.noxIndex); } return true; @@ -706,17 +713,17 @@ bool SEN5XSensor::readValues() bool SEN5XSensor::readPNValues(bool cumulative) { if (!sendCommand(SEN5X_READ_PM_VALUES)) { - LOG_ERROR("SEN5X: Error sending read command"); + LOG_ERROR("%s: Error sending read command", sensorName); return false; } - LOG_DEBUG("SEN5X: Reading PN Values"); + LOG_DEBUG("%s: Reading PN Values", sensorName); delay(20); // From Sensirion Datasheet uint8_t dataBuffer[20]{}; size_t receivedNumber = readBuffer(&dataBuffer[0], 30); if (receivedNumber == 0) { - LOG_ERROR("SEN5X: Error getting PN values"); + LOG_ERROR("%s: Error getting PN values", sensorName); return false; } @@ -750,7 +757,7 @@ bool SEN5XSensor::readPNValues(bool cumulative) sen5xmeasurement.pN1p0 -= sen5xmeasurement.pN0p5; } - LOG_DEBUG("Got %s readings: pN0p5=%u, pN1p0=%u, pN2p5=%u, pN4p0=%u, pN10p0=%u, tSize=%.2f", sensorName, + LOG_DEBUG("%s: Got readings: pN0p5=%u, pN1p0=%u, pN2p5=%u, pN4p0=%u, pN10p0=%u, tSize=%.2f", sensorName, sen5xmeasurement.pN0p5, sen5xmeasurement.pN1p0, sen5xmeasurement.pN2p5, sen5xmeasurement.pN4p0, sen5xmeasurement.pN10p0, sen5xmeasurement.tSize); @@ -764,7 +771,7 @@ uint8_t SEN5XSensor::getMeasurements() // Try to get new data if (!sendCommand(SEN5X_READ_DATA_READY)) { - LOG_ERROR("SEN5X: Error sending command data ready flag"); + LOG_ERROR("%s: Error sending command data ready flag", sensorName); return 2; } delay(20); // From Sensirion Datasheet @@ -772,7 +779,7 @@ uint8_t SEN5XSensor::getMeasurements() uint8_t dataReadyBuffer[3]; size_t charNumber = readBuffer(&dataReadyBuffer[0], 3); if (charNumber == 0) { - LOG_ERROR("SEN5X: Error getting device version value"); + LOG_ERROR("%s: Error getting device version value", sensorName); return 2; } @@ -780,17 +787,17 @@ uint8_t SEN5XSensor::getMeasurements() uint32_t sinceLastDataPollMs = (now - lastDataPoll) * 1000; // Check if data is ready, and if since last time we requested is less than SEN5X_POLL_INTERVAL if (!dataReady && (sinceLastDataPollMs > SEN5X_POLL_INTERVAL)) { - LOG_INFO("SEN5X: Data is not ready"); + LOG_INFO("%s: Data is not ready", sensorName); return 1; } if (!readValues()) { - LOG_ERROR("SEN5X: Error getting readings"); + LOG_ERROR("%s: Error getting readings", sensorName); return 2; } if (!readPNValues(false)) { - LOG_ERROR("SEN5X: Error getting PN readings"); + LOG_ERROR("%s: Error getting PN readings", sensorName); return 2; } @@ -809,13 +816,13 @@ int32_t SEN5XSensor::pendingForReadyMs() uint32_t now; now = getTime(); uint32_t sincePmMeasureStarted = (now - pmMeasureStarted) * 1000; - LOG_DEBUG("SEN5X: Since measure started: %ums", sincePmMeasureStarted); + LOG_DEBUG("%s: Since measure started: %ums", sensorName, sincePmMeasureStarted); switch (state) { case SEN5X_MEASUREMENT: { if (sincePmMeasureStarted < SEN5X_WARMUP_MS_1) { - LOG_INFO("SEN5X: not enough time passed since starting measurement"); + LOG_INFO("%s: not enough time passed since starting measurement", sensorName); return SEN5X_WARMUP_MS_1 - sincePmMeasureStarted; } @@ -829,7 +836,7 @@ int32_t SEN5XSensor::pendingForReadyMs() // If the reading is low (the tyhreshold is in #/cm3) and second warmUp hasn't passed we return to come back later if ((sen5xmeasurement.pN4p0 / 100) < SEN5X_PN4P0_CONC_THD && sincePmMeasureStarted < SEN5X_WARMUP_MS_2) { - LOG_INFO("SEN5X: Concentration is low, we will ask again in the second warm up period"); + LOG_INFO("%s: Concentration is low, we will ask again in the second warm up period", sensorName); state = SEN5X_MEASUREMENT_2; // Report how many seconds are pending to cover the first warm up period return SEN5X_WARMUP_MS_2 - sincePmMeasureStarted; @@ -851,9 +858,9 @@ int32_t SEN5XSensor::pendingForReadyMs() bool SEN5XSensor::getMetrics(meshtastic_Telemetry *measurement) { - LOG_INFO("SEN5X: Attempting to get metrics"); + LOG_INFO("%s: Attempting to get metrics", sensorName); if (!isActive()) { - LOG_INFO("SEN5X: not in measurement mode"); + LOG_INFO("%s: not in measurement mode", sensorName); return false; } @@ -943,9 +950,9 @@ void SEN5XSensor::setMode(bool setOneShot) { oneShotMode = setOneShot; if (oneShotMode) { - LOG_INFO("%s setting mode to one shot mode", sensorName); + LOG_INFO("%s: setting mode to one shot mode", sensorName); } else { - LOG_INFO("%s setting mode to continuous mode", sensorName); + LOG_INFO("%s: setting mode to continuous mode", sensorName); } } diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.h b/src/modules/Telemetry/Sensor/SEN5XSensor.h index 22b1c584609..a6608d30cca 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.h +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.h @@ -2,6 +2,7 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR +#include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "RTC.h" #include "TelemetrySensor.h" @@ -62,7 +63,10 @@ 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 bool getVersion(); float firmwareVer = -1; diff --git a/src/modules/Telemetry/Sensor/SFA30Sensor.cpp b/src/modules/Telemetry/Sensor/SFA30Sensor.cpp index 7c8a0854424..286d9fd472f 100644 --- a/src/modules/Telemetry/Sensor/SFA30Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SFA30Sensor.cpp @@ -2,7 +2,6 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include() -#include "../detect/reClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "SFA30Sensor.h" @@ -14,11 +13,13 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) _bus = bus; _address = dev->address.address; - _port = dev->address.port; #ifdef SFA30_I2C_CLOCK_SPEED + _port = dev->address.port; + reClockI2C.setup(_bus, _port); + LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port); + reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED); #endif /* SFA30_I2C_CLOCK_SPEED */ sfa30.begin(*_bus, _address); @@ -26,10 +27,8 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) if (this->isError(sfa30.deviceReset())) { #ifdef SFA30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ return false; } @@ -37,10 +36,8 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) state = State::IDLE; if (this->isError(sfa30.startContinuousMeasurement())) { #ifdef SFA30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ return false; } @@ -48,10 +45,8 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) LOG_INFO("%s starting measurement", sensorName); #ifdef SFA30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ status = 1; @@ -77,7 +72,7 @@ void SFA30Sensor::sleep() { #ifdef SFA30_I2C_CLOCK_SPEED LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port); + reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED); #endif /* SFA30_I2C_CLOCK_SPEED */ // Note - not recommended for this sensor on a periodic basis @@ -86,10 +81,8 @@ void SFA30Sensor::sleep() }; #ifdef SFA30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ LOG_INFO("%s: stop measurement", sensorName); @@ -101,25 +94,21 @@ uint32_t SFA30Sensor::wakeUp() { #ifdef SFA30_I2C_CLOCK_SPEED LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port); + reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED); #endif /* SFA30_I2C_CLOCK_SPEED */ LOG_INFO("Waking up %s", sensorName); if (this->isError(sfa30.startContinuousMeasurement())) { #ifdef SFA30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ return 0; } #ifdef SFA30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ state = State::ACTIVE; @@ -166,25 +155,21 @@ bool SFA30Sensor::getMetrics(meshtastic_Telemetry *measurement) #ifdef SFA30_I2C_CLOCK_SPEED LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); - uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port); + reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED); #endif /* SFA30_I2C_CLOCK_SPEED */ if (this->isError(sfa30.readMeasuredValues(hcho, humidity, temperature))) { LOG_WARN("%s: No values", sensorName); #ifdef SFA30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ return false; } #ifdef SFA30_I2C_CLOCK_SPEED - if (currentClock) { - LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock); - reClockI2C(currentClock, _bus, _port); - } + LOG_INFO("%s restoring clock speed", sensorName); + reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ measurement->variant.air_quality_metrics.has_form_temperature = true; diff --git a/src/modules/Telemetry/Sensor/SFA30Sensor.h b/src/modules/Telemetry/Sensor/SFA30Sensor.h index 038a70e1ec7..299a9fdf0e4 100644 --- a/src/modules/Telemetry/Sensor/SFA30Sensor.h +++ b/src/modules/Telemetry/Sensor/SFA30Sensor.h @@ -2,6 +2,7 @@ #if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include() +#include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "RTC.h" #include "TelemetrySensor.h" @@ -21,7 +22,10 @@ class SFA30Sensor : public TelemetrySensor SensirionI2cSfa3x sfa30; TwoWire *_bus{}; uint8_t _address{}; +#ifdef SFA30_I2C_CLOCK_SPEED ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C; + ReClockI2C reClockI2C; +#endif bool isError(uint16_t response); diff --git a/variants/esp32/esp32-common.ini b/variants/esp32/esp32-common.ini index a94defff234..a910d50c90f 100644 --- a/variants/esp32/esp32-common.ini +++ b/variants/esp32/esp32-common.ini @@ -56,7 +56,7 @@ build_flags = -DLIBPAX_BLE -DHAS_UDP_MULTICAST=1 ;-DDEBUG_HEAP - -DCAN_RECLOCK_I2C + -DCAN_GET_I2C_CLOCK lib_deps = ${arduino_base.lib_deps} From e7ab45a32ac5aba03ea742fcb092b9bea9495ad0 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 31 May 2026 20:35:36 +0200 Subject: [PATCH 07/19] Update esp8266-oled library --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index bedd42a1e54..8cc420b0ef0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -69,7 +69,7 @@ monitor_speed = 115200 monitor_filters = direct lib_deps = # renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master - https://github.com/meshtastic/esp8266-oled-ssd1306/archive/6bfd1f135e1ebe37afd6050bb4b9964cea3fcfda.zip + https://github.com/meshtastic/esp8266-oled-ssd1306/commit/2e26010040e028baee72e2093402fa7b3c59e430 # renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip # renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master From 36b72c6edb8d29e4cdae301d891dd6f74ae8ae3c Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 31 May 2026 20:40:00 +0200 Subject: [PATCH 08/19] Fix esp8266 library --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 8cc420b0ef0..9ec39e4edf0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -69,7 +69,7 @@ monitor_speed = 115200 monitor_filters = direct lib_deps = # renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master - https://github.com/meshtastic/esp8266-oled-ssd1306/commit/2e26010040e028baee72e2093402fa7b3c59e430 + https://github.com/meshtastic/esp8266-oled-ssd1306/archive/2e26010040e028baee72e2093402fa7b3c59e430.zip # renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip # renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master From 70588f01e568891d4f1c5d72abeed73f394b68d8 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sat, 13 Jun 2026 21:30:30 +0200 Subject: [PATCH 09/19] Minor logging changes --- src/modules/Telemetry/Sensor/PMSA003ISensor.cpp | 6 +++--- src/modules/Telemetry/Sensor/SCD30Sensor.cpp | 7 +++---- src/modules/Telemetry/Sensor/SCD4XSensor.cpp | 6 +++--- src/modules/Telemetry/Sensor/SEN5XSensor.cpp | 4 ++-- src/modules/Telemetry/Sensor/SFA30Sensor.cpp | 6 +++--- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp b/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp index 357545f27ca..2073eb3cdc2 100644 --- a/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp +++ b/src/modules/Telemetry/Sensor/PMSA003ISensor.cpp @@ -59,7 +59,7 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement) } #ifdef PMSA003I_I2C_CLOCK_SPEED - LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED); + LOG_DEBUG("%s: attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED); reClockI2C.setClock(PMSA003I_I2C_CLOCK_SPEED); #endif /* PMSA003I_I2C_CLOCK_SPEED */ @@ -67,7 +67,7 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement) if (_bus->available() < PMSA003I_FRAME_LENGTH) { LOG_WARN("%s: read failed: incomplete data (%d bytes)", sensorName, _bus->available()); #ifdef PMSA003I_I2C_CLOCK_SPEED - LOG_INFO("%s: restoring clock speed", sensorName); + LOG_DEBUG("%s: restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* PMSA003I_I2C_CLOCK_SPEED */ return false; @@ -78,7 +78,7 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement) } #ifdef PMSA003I_I2C_CLOCK_SPEED - LOG_INFO("%s: restoring clock speed", sensorName); + LOG_DEBUG("%s: restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* PMSA003I_I2C_CLOCK_SPEED */ diff --git a/src/modules/Telemetry/Sensor/SCD30Sensor.cpp b/src/modules/Telemetry/Sensor/SCD30Sensor.cpp index a752b105deb..59a50779c3f 100644 --- a/src/modules/Telemetry/Sensor/SCD30Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SCD30Sensor.cpp @@ -59,22 +59,21 @@ bool SCD30Sensor::getMetrics(meshtastic_Telemetry *measurement) float co2, temperature, humidity; #ifdef SCD30_I2C_CLOCK_SPEED - LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); + LOG_DEBUG("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED); reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED); #endif /* SCD30_I2C_CLOCK_SPEED */ if (scd30.readMeasurementData(co2, temperature, humidity) != SCD30_NO_ERROR) { LOG_ERROR("%s: Failed to read measurement data", sensorName); #ifdef SCD30_I2C_CLOCK_SPEED - LOG_INFO("%s: restoring clock speed", sensorName); + LOG_DEBUG("%s: restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ - return false; } #ifdef SCD30_I2C_CLOCK_SPEED - LOG_INFO("%s: restoring clock speed", sensorName); + LOG_DEBUG("%s: restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SCD30_I2C_CLOCK_SPEED */ diff --git a/src/modules/Telemetry/Sensor/SCD4XSensor.cpp b/src/modules/Telemetry/Sensor/SCD4XSensor.cpp index aa9ac91653b..bae0cf12a24 100644 --- a/src/modules/Telemetry/Sensor/SCD4XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SCD4XSensor.cpp @@ -100,7 +100,7 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement) float temperature, humidity; #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); + LOG_DEBUG("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED); reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED); #endif /* SCD4X_I2C_CLOCK_SPEED */ @@ -108,7 +108,7 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement) error = scd4x.getDataReadyStatus(dataReady); if (error != SCD4X_NO_ERROR || !dataReady) { #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s: restoring clock speed", sensorName); + LOG_DEBUG("%s: restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ LOG_ERROR("SCD4X: Data is not ready"); @@ -118,7 +118,7 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement) error = scd4x.readMeasurement(co2, temperature, humidity); #ifdef SCD4X_I2C_CLOCK_SPEED - LOG_INFO("%s: restoring clock speed", sensorName); + LOG_DEBUG("%s: restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SCD4X_I2C_CLOCK_SPEED */ diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp index ab14215b64c..4199242b555 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp @@ -151,7 +151,7 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum #endif /* SEN5X_I2C_CLOCK_SPEED */ if (writtenBytes != bufferSize) { - LOG_ERROR("%s: Error writting on I2C bus", sensorName); + LOG_ERROR("%s: Error writing on I2C bus", sensorName); return false; } @@ -573,7 +573,7 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) delay(50); // without this there is an error on the deviceReset function if (!sendCommand(SEN5X_RESET)) { - LOG_ERROR("%s: error reseting device", sensorName); + LOG_ERROR("%s: error resetting device", sensorName); return false; } delay(200); // From Sensirion Datasheet diff --git a/src/modules/Telemetry/Sensor/SFA30Sensor.cpp b/src/modules/Telemetry/Sensor/SFA30Sensor.cpp index 286d9fd472f..71d98e2c94d 100644 --- a/src/modules/Telemetry/Sensor/SFA30Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SFA30Sensor.cpp @@ -154,21 +154,21 @@ bool SFA30Sensor::getMetrics(meshtastic_Telemetry *measurement) float temperature = 0.0; #ifdef SFA30_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); + LOG_DEBUG("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED); #endif /* SFA30_I2C_CLOCK_SPEED */ if (this->isError(sfa30.readMeasuredValues(hcho, humidity, temperature))) { LOG_WARN("%s: No values", sensorName); #ifdef SFA30_I2C_CLOCK_SPEED - LOG_INFO("%s restoring clock speed", sensorName); + LOG_DEBUG("%s restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ return false; } #ifdef SFA30_I2C_CLOCK_SPEED - LOG_INFO("%s restoring clock speed", sensorName); + LOG_DEBUG("%s restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ From 8b08431fd726410077e83268f3c17bdc4101d5ed Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sat, 13 Jun 2026 21:32:19 +0200 Subject: [PATCH 10/19] Improve setClock and restoreClock cases --- src/detect/ReClockI2C.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detect/ReClockI2C.h b/src/detect/ReClockI2C.h index 90cc859cb9f..857040e6f41 100644 --- a/src/detect/ReClockI2C.h +++ b/src/detect/ReClockI2C.h @@ -51,6 +51,7 @@ class ReClockI2C } LOG_DEBUG("I2C clock was already %uHz. Skipping", desiredClock); + setPreviousClock(0); return false; } @@ -59,6 +60,7 @@ class ReClockI2C if (this->previousClock) { LOG_DEBUG("Restoring I2C clock to %uHz", this->previousClock); i2cBus->setClock(this->previousClock); + setPreviousClock(0); return true; } LOG_DEBUG("I2C clock was unknown. Not restored"); From 07f1779e7b4f36d5b0b324f6e0077a28ad2a0c3d Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 14 Jun 2026 14:12:13 +0200 Subject: [PATCH 11/19] Make getter functions const, fix capitalisaiton of new functions --- src/graphics/Screen.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 0804ec97eff..2128e85c237 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -73,8 +73,8 @@ class Screen void showOverlayBanner(BannerOverlayOptions) {} void setFrames(FrameFocus focus) {} void endAlert() {} - bool getIsI2CScreen() { return false; } - uint32_t getI2cFrequency() { return 0; } + const bool getIsI2cScreen() { return false; } + const uint32_t getI2cFrequency() { return 0; } ScanI2C::I2CPort getI2CPort() { return ScanI2C::I2CPort::NO_I2C; } }; } // namespace graphics @@ -263,18 +263,18 @@ class Screen : public concurrency::OSThread Screen &operator=(const Screen &) = delete; ScanI2C::DeviceAddress address_found; - bool getIsI2CScreen() { return isI2cScreen; } + const bool getIsI2cScreen() { return isI2cScreen; } // Return I2C Speed, or 0 if none - uint32_t getI2cFrequency() + const uint32_t getI2cFrequency() { - if (getIsI2CScreen()) + if (getIsI2cScreen()) return dispdev->getI2cFrequency(); else return 0; } - ScanI2C::I2CPort getI2CPort() + const ScanI2C::I2CPort getI2CPort() { - if (getIsI2CScreen()) + if (getIsI2cScreen()) return address_found.port; else return ScanI2C::I2CPort::NO_I2C; From 5025d0e61eaad0d52b1ed73f5fb0fb3ab7ab1cb1 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 14 Jun 2026 14:12:29 +0200 Subject: [PATCH 12/19] Minor typo, remove pragma once --- src/detect/ReClockI2C.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/detect/ReClockI2C.h b/src/detect/ReClockI2C.h index 857040e6f41..c8a81fb0928 100644 --- a/src/detect/ReClockI2C.h +++ b/src/detect/ReClockI2C.h @@ -1,5 +1,3 @@ -#pragma once - #ifndef RECLOCK_I2C_ #define RECLOCK_I2C_ @@ -16,7 +14,7 @@ https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60 https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103 For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes) - we need to reclock I2C and set it back to the previous stablished speed. + we need to reclock I2C and set it back to the previous established speed. Only for cases where we can know it (ESP32 or known screen) we can do this. */ From 81c0f14217ff27e4f101aa926e8af116c7b93d10 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 14 Jun 2026 14:12:49 +0200 Subject: [PATCH 13/19] Low prio debug fixes --- src/modules/Telemetry/Sensor/SEN5XSensor.cpp | 4 ++-- src/modules/Telemetry/Sensor/SFA30Sensor.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp index 4199242b555..0070a7598dc 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp @@ -334,7 +334,7 @@ bool SEN5XSensor::vocStateToSensor() } if (!sendCommand(SEN5X_STOP_MEASUREMENT)) { - LOG_ERROR("%s: Error stoping measurement", sensorName); + LOG_ERROR("%s: Error stopping measurement", sensorName); return false; } delay(200); // From Sensirion Datasheet @@ -526,7 +526,7 @@ bool SEN5XSensor::startCleaning() // Note that cleaning command can only be run when the sensor is in measurement mode if (!sendCommand(SEN5X_START_MEASUREMENT)) { - LOG_ERROR("%s: Error starting measurment mode", sensorName); + LOG_ERROR("%s: Error starting measurement mode", sensorName); return false; } delay(50); // From Sensirion Datasheet diff --git a/src/modules/Telemetry/Sensor/SFA30Sensor.cpp b/src/modules/Telemetry/Sensor/SFA30Sensor.cpp index 71d98e2c94d..5befb44748d 100644 --- a/src/modules/Telemetry/Sensor/SFA30Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SFA30Sensor.cpp @@ -71,7 +71,7 @@ bool SFA30Sensor::isError(uint16_t response) void SFA30Sensor::sleep() { #ifdef SFA30_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); + LOG_DEBUG("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED); #endif /* SFA30_I2C_CLOCK_SPEED */ @@ -81,11 +81,11 @@ void SFA30Sensor::sleep() }; #ifdef SFA30_I2C_CLOCK_SPEED - LOG_INFO("%s restoring clock speed", sensorName); + LOG_DEBUG("%s restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ - LOG_INFO("%s: stop measurement", sensorName); + LOG_DEBUG("%s: stop measurement", sensorName); state = State::IDLE; measureStarted = 0; } @@ -93,21 +93,21 @@ void SFA30Sensor::sleep() uint32_t SFA30Sensor::wakeUp() { #ifdef SFA30_I2C_CLOCK_SPEED - LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); + LOG_DEBUG("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED); reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED); #endif /* SFA30_I2C_CLOCK_SPEED */ - LOG_INFO("Waking up %s", sensorName); + LOG_DEBUG("Waking up %s", sensorName); if (this->isError(sfa30.startContinuousMeasurement())) { #ifdef SFA30_I2C_CLOCK_SPEED - LOG_INFO("%s restoring clock speed", sensorName); + LOG_DEBUG("%s restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ return 0; } #ifdef SFA30_I2C_CLOCK_SPEED - LOG_INFO("%s restoring clock speed", sensorName); + LOG_DEBUG("%s restoring clock speed", sensorName); reClockI2C.restoreClock(); #endif /* SFA30_I2C_CLOCK_SPEED */ From 6c61f12b101bc56516e8a5c4940fbd4d1e509a3f Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 31 May 2026 20:00:02 +0200 Subject: [PATCH 14/19] Move address, bus and port to TelemetrySensor --- src/modules/Telemetry/Sensor/PMSA003ISensor.h | 3 --- src/modules/Telemetry/Sensor/SCD30Sensor.h | 3 --- src/modules/Telemetry/Sensor/SCD4XSensor.h | 3 --- src/modules/Telemetry/Sensor/SEN5XSensor.h | 3 --- src/modules/Telemetry/Sensor/SFA30Sensor.h | 3 --- src/modules/Telemetry/Sensor/TelemetrySensor.h | 5 +++++ 6 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/modules/Telemetry/Sensor/PMSA003ISensor.h b/src/modules/Telemetry/Sensor/PMSA003ISensor.h index ce7bba4bbc0..51af73087be 100644 --- a/src/modules/Telemetry/Sensor/PMSA003ISensor.h +++ b/src/modules/Telemetry/Sensor/PMSA003ISensor.h @@ -34,10 +34,7 @@ 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 }; diff --git a/src/modules/Telemetry/Sensor/SCD30Sensor.h b/src/modules/Telemetry/Sensor/SCD30Sensor.h index 64ca7342029..373d8e41ccf 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 diff --git a/src/modules/Telemetry/Sensor/SCD4XSensor.h b/src/modules/Telemetry/Sensor/SCD4XSensor.h index 03ff4abc224..50df60bd36a 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 diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.h b/src/modules/Telemetry/Sensor/SEN5XSensor.h index a6608d30cca..e63d5fc68c6 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 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; } From 301c5e014ada99b6c2bcaf5a7fb44c711ed24c58 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 31 May 2026 20:06:34 +0200 Subject: [PATCH 15/19] 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 a50ea8e5726..97f8f9ebe4b 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 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..ba0ab4c1e11 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 From 2ef8d9cd3a5d1cce95d9a14dacd498ccf9980658 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Mon, 1 Jun 2026 10:08:54 +0200 Subject: [PATCH 16/19] Style fix --- src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h b/src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h index ba0ab4c1e11..ba1c5e2e90c 100644 --- a/src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h +++ b/src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h @@ -13,7 +13,7 @@ template void addSensor(const ScanI2C *i2cScanner, ScanI2C::DeviceT ScanI2C::FoundDevice dev = i2cScanner->find(type); // Avoid adding the same device twice if (dev.type != ScanI2C::DeviceType::NONE) { - for (TelemetrySensor *_sensor : sensors) { + for (const TelemetrySensor *_sensor : sensors) { if ((_sensor->_address == dev.address.address) && (_sensor->_port == dev.address.port)) { return; } From fc5dc5fc9003d728200b14d95f840d3d78719783 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 14 Jun 2026 14:45:39 +0200 Subject: [PATCH 17/19] Mark getter functions as const (properly) --- src/graphics/Screen.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 2128e85c237..c65b2da7a2f 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -73,9 +73,9 @@ class Screen void showOverlayBanner(BannerOverlayOptions) {} void setFrames(FrameFocus focus) {} void endAlert() {} - const bool getIsI2cScreen() { return false; } - const uint32_t getI2cFrequency() { return 0; } - ScanI2C::I2CPort getI2CPort() { return ScanI2C::I2CPort::NO_I2C; } + bool getIsI2cScreen() const { return false; } + uint32_t getI2cFrequency() const { return 0; } + ScanI2C::I2CPort getI2CPort() const { return ScanI2C::I2CPort::NO_I2C; } }; } // namespace graphics #else @@ -263,16 +263,16 @@ class Screen : public concurrency::OSThread Screen &operator=(const Screen &) = delete; ScanI2C::DeviceAddress address_found; - const bool getIsI2cScreen() { return isI2cScreen; } + bool getIsI2cScreen() const { return isI2cScreen; } // Return I2C Speed, or 0 if none - const uint32_t getI2cFrequency() + uint32_t getI2cFrequency() const { if (getIsI2cScreen()) return dispdev->getI2cFrequency(); else return 0; } - const ScanI2C::I2CPort getI2CPort() + ScanI2C::I2CPort getI2CPort() const { if (getIsI2cScreen()) return address_found.port; From f604a4e17241848f2d099822f440a22160e0898d Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 14 Jun 2026 14:44:38 +0200 Subject: [PATCH 18/19] Reduce overhead in SEN5X probing --- src/detect/ScanI2CTwoWire.cpp | 2 +- src/modules/Telemetry/Sensor/SEN5XSensor.cpp | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 38d860f65f3..849e223486f 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -140,7 +140,7 @@ bool ScanI2CTwoWire::i2cCommandResponseLength(ScanI2C::DeviceAddress addr, uint1 #include "../modules/Telemetry/Sensor/SEN5XSensor.h" bool probeSEN5X(TwoWire *i2cBus, uint8_t address, ScanI2C::I2CPort port) { - SEN5XSensor sen5xsensor = SEN5XSensor(); + SEN5XSensor sen5xsensor; return sen5xsensor.probe(i2cBus, address, port); } #endif diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp index 0070a7598dc..d15f543e8ca 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.cpp @@ -86,16 +86,8 @@ bool SEN5XSensor::probe(TwoWire *bus, uint8_t address, ScanI2C::I2CPort port) reClockI2C.setup(_bus, _port); #endif /* SEN5X_I2C_CLOCK_SPEED */ - delay(50); // without this there is an error on the deviceReset function - - if (!sendCommand(SEN5X_RESET)) { - LOG_ERROR("SEN5X: error resetting device"); - return false; - } - delay(200); // From Sensirion Datasheet - if (!findModel()) { - LOG_ERROR("SEN5X: error finding sensor model"); + LOG_DEBUG("SEN5X: can't find SEN5X model"); return false; } return true; From c61d32c0fad5741b9e612e9effdc4890d6bf37cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 3 Jul 2026 11:13:02 +0200 Subject: [PATCH 19/19] Guard AirQuality I2C re-scan behind !MESHTASTIC_EXCLUDE_I2C ScanI2CTwoWire is compiled out on builds that define MESHTASTIC_EXCLUDE_I2C (e.g. native-wasm/portduino), while the AirQuality module still builds there. Skip the re-scan when I2C is excluded; there is nothing to scan. --- src/modules/Telemetry/AirQualityTelemetry.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index bd11a26b455..8320b0ab5dd 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -142,9 +142,11 @@ 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()) {