Skip to content

Fixes on 0x69 address detection#10715

Merged
oscgonfer merged 21 commits into
meshtastic:developfrom
fablabbcn:bugfix/detection-on-0x69-address
Jul 3, 2026
Merged

Fixes on 0x69 address detection#10715
oscgonfer merged 21 commits into
meshtastic:developfrom
fablabbcn:bugfix/detection-on-0x69-address

Conversation

@oscgonfer

@oscgonfer oscgonfer commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

This PR fixes some detection issues on devices with shared address 0x69
BMX160 detection has recently been improved by @caveman99, but there was some leftover code that assumed BMX160 as a default if everything else failed. Similar to MPU6050, which a WHO_AM_I register check was added.

The SEN5X sensor detection process is also improved, avoiding a custom probe for the model, but instead using the class methods, which account for all the I2C speed shebang (#9898 and #10593).

Changes:

  • Change SEN5X detection method, using class itself
  • MPU6050 register check
  • BMX160 default removed

🤝 Attestations

  • I have tested that my proposed changes behave as described.
  • I have tested that my proposed changes do not cause any obvious regressions on the following devices:
    • Seeed Xiao ESP S3 with SEN5X and other sensors

Tagging @caveman99 for checks if possible with the BMX160 code.

Caution

Rebased onto #9898 and #10593

Summary by CodeRabbit

  • New Features

    • Air quality sensor discovery now covers more supported I2C sensors and can rescan for sensors that appear later.
    • SEN5X devices are now detected more reliably during I2C scanning.
  • Bug Fixes

    • Prevented duplicate I2C sensor entries from being added.
    • Improved sensor handling so I2C device detection and setup are more consistent across supported sensors.

* Change SEN5X detection method, using class itself
* MPU6050 register check
* BMX160 default removed
@oscgonfer oscgonfer self-assigned this Jun 14, 2026
@oscgonfer oscgonfer requested a review from caveman99 June 14, 2026 11:50
@oscgonfer oscgonfer added tech debt Code or lib references that are not up to date or propper standards hardware-support Hardware related: new devices or modules, problems specific to hardware cleanup Code cleanup or refactor labels Jun 14, 2026
@thebentern thebentern requested a review from Copilot June 14, 2026 12:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR improves I2C device detection on shared address 0x69, removing fallback assumptions and making detection more explicit—especially for SEN5X air quality sensors and MPU6050 IMUs.

Changes:

  • Add a SEN5XSensor::probe(...) method and use it from the I2C scanner instead of a custom product-name probe.
  • Add an MPU6050 WHO_AM_I register value check.
  • Remove the previous “default to BMX160/MPU6050” behavior when detection fails.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/modules/Telemetry/Sensor/SEN5XSensor.h Exposes a new probe(...) API to support scanner-based detection.
src/modules/Telemetry/Sensor/SEN5XSensor.cpp Implements probe(...) by resetting the sensor and identifying the model.
src/detect/ScanI2CTwoWire.cpp Replaces custom SEN5X probing with SEN5XSensor::probe() and adds MPU6050 WHO_AM_I detection while removing old default fallbacks.

Comment thread src/modules/Telemetry/Sensor/SEN5XSensor.cpp Outdated
Comment thread src/modules/Telemetry/Sensor/SEN5XSensor.cpp
Comment thread src/modules/Telemetry/Sensor/SEN5XSensor.cpp Outdated
Comment on lines +140 to 145
#include "../modules/Telemetry/Sensor/SEN5XSensor.h"
bool probeSEN5X(TwoWire *i2cBus, uint8_t address, ScanI2C::I2CPort port)
{
uint8_t cmd[] = {0xD0, 0x14};
uint8_t response[48] = {0};

i2cBus->beginTransmission(address);
i2cBus->write(cmd, 2);
if (i2cBus->endTransmission() != 0)
return "";

delay(20);
if (i2cBus->requestFrom(address, (uint8_t)48) != 48)
return "";

for (int i = 0; i < 48 && i2cBus->available(); ++i) {
response[i] = i2cBus->read();
}

char productName[33] = {0};
int j = 0;
for (int i = 0; i < 48 && j < 32; i += 3) {
if (response[i] >= 32 && response[i] <= 126)
productName[j++] = response[i];
else
break;

if (response[i + 1] >= 32 && response[i + 1] <= 126)
productName[j++] = response[i + 1];
else
break;
}

return String(productName);
SEN5XSensor sen5xsensor = SEN5XSensor();
return sen5xsensor.probe(i2cBus, address, port);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure I agree with this. I understand the module coupling, but there are two considerations:

  1. The sensor has quite a bit of details that are handled in the class directly (changing bus speed when sending commands, for one) that would need to be replicated in a separate class
  2. The sensor also has an internal firmware versioning, which is also detected in the class. If in the future there are new firmware versions for the sensor, we would only need to update de class, and not the probing on a different function.

@github-actions github-actions Bot added the bugfix Pull request that fixes bugs label Jun 14, 2026
@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

⚡ Try this PR in the Web Flasher

Flash this PR in the Web Flasher

firmware commit boards expires

Warning

This is an automated, unreviewed CI test build. Back up your device configuration
before flashing, and only flash devices you are able to recover.

Supported boards built by this PR (26)
Device Board Platform
Crowpanel Adv 3.5 TFT elecrow-adv-35-tft esp32-s3
Heltec HT62 heltec-ht62-esp32c3-sx1262 esp32-c3
Heltec Mesh Node 096 heltec-mesh-node-t096 nrf52840
Heltec Mesh Node T1 heltec-mesh-node-t1 nrf52840
Heltec Mesh Node T114 heltec-mesh-node-t114 nrf52840
Heltec V3 heltec-v3 esp32-s3
Heltec V4 heltec-v4 esp32-s3
Raspberry Pi Pico pico rp2040
Raspberry Pi Pico W picow rp2040
RAK WisMesh Tag rak_wismeshtag nrf52840
RAK WisBlock 11200 rak11200 esp32
RAK WisBlock 11310 rak11310 rp2040
RAK3312 rak3312 esp32-s3
RAK WisBlock 4631 rak4631 nrf52840
Seeed SenseCAP Mesh-Tracker-X1 seeed_mesh_tracker_X1 nrf52840
Seeed Wio Tracker L1 seeed_wio_tracker_L1 nrf52840
Seeed Xiao NRF52840 Kit seeed_xiao_nrf52840_kit nrf52840
Seeed Xiao ESP32-S3 seeed-xiao-s3 esp32-s3
Station G2 station-g2 esp32-s3
Station G3 station-g3 esp32-s3
LILYGO T-Deck t-deck-tft esp32-s3
LILYGO T-Echo t-echo nrf52840
LILYGO T-Echo Plus t-echo-plus nrf52840
LILYGO T-Impulse Plus t-impulse-plus nrf52840
LilyGo T3-C6 tlora-c6 esp32-c6
Seeed SenseCAP T1000-E tracker-t1000-e nrf52840

Build artifacts expire on 2026-08-02. Updated for c61d32c.

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Firmware Size Report

22 targets | vs develop: 21 increased, 1 decreased, net +362,468 (+354.0 KB)

Target Size vs develop
picow 1,271,952 📈 +27,072 (+26.4 KB)
pico2w 1,246,620 📈 +26,104 (+25.5 KB)
rak11310 831,240 📈 +25,816 (+25.2 KB)
pico 808,488 📈 +25,800 (+25.2 KB)
seeed_xiao_rp2040 806,704 📈 +25,800 (+25.2 KB)
Show 17 more target(s)
Target Size vs develop
pico2 794,744 📈 +24,968 (+24.4 KB)
seeed_xiao_rp2350 792,888 📈 +24,952 (+24.4 KB)
t-deck-tft 3,829,888 📈 +19,216 (+18.8 KB)
heltec-vision-master-e213-inkhud 2,245,152 📈 +17,792 (+17.4 KB)
rak11200 1,875,776 📈 +15,168 (+14.8 KB)
elecrow-adv-35-tft 3,431,680 📈 +15,056 (+14.7 KB)
seeed-xiao-s3 2,290,240 📈 +14,096 (+13.8 KB)
tlora-c6 2,382,304 📈 +14,000 (+13.7 KB)
heltec-v3 2,277,504 📈 +13,424 (+13.1 KB)
heltec-ht62-esp32c3-sx1262 2,148,272 📈 +13,280 (+13.0 KB)
rak3312 2,285,424 📈 +13,184 (+12.9 KB)
station-g3 2,278,864 📈 +12,512 (+12.2 KB)
station-g2 2,278,848 📈 +12,496 (+12.2 KB)
t-eth-elite 2,503,904 📈 +12,416 (+12.1 KB)
heltec-v4 2,289,600 📈 +12,304 (+12.0 KB)
rak3172 182,492 📉 -3,804 (-3.7 KB)
wio-e5 239,444 📈 +816

Updated for b7d039b

caveman99 added 2 commits July 3, 2026 11:12
# Conflicts:
#	src/graphics/Screen.cpp
#	src/modules/Telemetry/Sensor/PMSA003ISensor.h
#	src/modules/Telemetry/Sensor/SCD30Sensor.h
#	src/modules/Telemetry/Sensor/SCD4XSensor.h
#	src/modules/Telemetry/Sensor/SEN5XSensor.cpp
#	src/modules/Telemetry/Sensor/SEN5XSensor.h
#	src/modules/Telemetry/Sensor/SFA30Sensor.h
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.
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

SEN5X I2C detection now uses a new SEN5XSensor::probe(...) method instead of manual product-name parsing. I2C bus/address/port members were consolidated into the base TelemetrySensor class, removing duplicates from PMSA003I, SCD30, SCD4X, and SFA30 sensor headers. AirQualityTelemetryModule gained a supportedSensors map and re-scan logic for late-arriving sensors, and addSensor now guards against duplicate device entries.

Changes

SEN5X probe and I2C re-scan

Layer / File(s) Summary
Shared I2C member state
src/modules/Telemetry/Sensor/TelemetrySensor.h
Adds _address, _bus, and _port members to the base TelemetrySensor class.
SEN5X probe implementation and detection
src/modules/Telemetry/Sensor/SEN5XSensor.h, src/modules/Telemetry/Sensor/SEN5XSensor.cpp, src/detect/ScanI2CTwoWire.cpp
Adds SEN5XSensor::probe(...) that configures the bus/address/clock and calls findModel(); scanning code replaces product-name string parsing with a probeSEN5X(...) helper.
Remove redundant sensor header members
src/modules/Telemetry/Sensor/PMSA003ISensor.h, .../SCD30Sensor.h, .../SCD4XSensor.h, .../SFA30Sensor.h
Removes duplicated _bus/_address/_port declarations now inherited from TelemetrySensor.
Re-scan flow and duplicate guard
src/modules/Telemetry/AirQualityTelemetry.h, src/modules/Telemetry/AirQualityTelemetry.cpp, src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h
Adds supportedSensors map, expands i2cScanFinished to build the map and re-scan late-coming sensors, triggers an extra scan in runOnce, and addSensor skips already-registered devices.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AirQualityTelemetryModule
  participant ScanI2CTwoWire
  participant SEN5XSensor
  participant AddI2CSensorTemplate

  AirQualityTelemetryModule->>ScanI2CTwoWire: i2cScanFinished(firstTime)
  ScanI2CTwoWire->>SEN5XSensor: probeSEN5X(bus, address, port)
  SEN5XSensor->>SEN5XSensor: findModel()
  SEN5XSensor-->>ScanI2CTwoWire: true/false
  ScanI2CTwoWire-->>AirQualityTelemetryModule: detected devices
  AirQualityTelemetryModule->>AddI2CSensorTemplate: addSensor(dev)
  AddI2CSensorTemplate->>AddI2CSensorTemplate: check for duplicate address/port
  AddI2CSensorTemplate-->>AirQualityTelemetryModule: return early or register sensor
Loading

Poem

A rabbit hopped through wires and bus,
Found SEN5X without much fuss,
One probe to rule the scan,
No dupes allowed in the plan,
Late sensors join without a fuss! 🐇🔌

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main change: fixing detection behavior around the shared 0x69 I2C address.
Description check ✅ Passed The description covers the bug, key changes, and testing attestations, though it doesn't fully mirror the template's suggested structure.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/modules/Telemetry/AirQualityTelemetry.cpp (1)

147-147: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer std::make_unique over raw new.

As per coding guidelines, "Use C++17 features when appropriate." std::make_unique is the idiomatic C++14/17 way to construct owned objects and avoids a naked new.

♻️ Proposed refactor
-            auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
+            auto i2cScanner = std::make_unique<ScanI2CTwoWire>();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/modules/Telemetry/AirQualityTelemetry.cpp` at line 147, Replace the
manual heap allocation in the AirQualityTelemetry setup with the idiomatic C++17
ownership helper: update the i2cScanner initialization in the code path that
creates ScanI2CTwoWire to use std::make_unique instead of std::unique_ptr
constructed from new. This keeps ownership semantics the same while removing the
naked new and aligning with the existing C++17 style used in this module.

Source: Coding guidelines

src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h (1)

14-21: 📐 Maintainability & Code Quality | 🔵 Trivial

Minor: duplicate NONE check across the two conditionals.

dev.type != ScanI2C::DeviceType::NONE is evaluated here (Line 15) and again as part of the condition on Line 23. Could combine into a single early-return path for clarity, but the current structure is still correct and readable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h` around lines 14 - 21,
The duplicate `ScanI2C::DeviceType::NONE` check in `AddI2CSensorTemplate` should
be simplified by using a single early-return flow. Update the logic around the
device scan and sensor deduplication so the `dev.type !=
ScanI2C::DeviceType::NONE` guard is evaluated only once, and then perform the
`sensors` address/port duplicate check within that path for clearer control
flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/modules/Telemetry/AirQualityTelemetry.cpp`:
- Line 147: Replace the manual heap allocation in the AirQualityTelemetry setup
with the idiomatic C++17 ownership helper: update the i2cScanner initialization
in the code path that creates ScanI2CTwoWire to use std::make_unique instead of
std::unique_ptr constructed from new. This keeps ownership semantics the same
while removing the naked new and aligning with the existing C++17 style used in
this module.

In `@src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h`:
- Around line 14-21: The duplicate `ScanI2C::DeviceType::NONE` check in
`AddI2CSensorTemplate` should be simplified by using a single early-return flow.
Update the logic around the device scan and sensor deduplication so the
`dev.type != ScanI2C::DeviceType::NONE` guard is evaluated only once, and then
perform the `sensors` address/port duplicate check within that path for clearer
control flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 00df52d3-5e09-4cf7-b04e-a0a7a3ff387b

📥 Commits

Reviewing files that changed from the base of the PR and between 397ff85 and c61d32c.

📒 Files selected for processing (11)
  • src/detect/ScanI2CTwoWire.cpp
  • src/modules/Telemetry/AirQualityTelemetry.cpp
  • src/modules/Telemetry/AirQualityTelemetry.h
  • src/modules/Telemetry/Sensor/AddI2CSensorTemplate.h
  • src/modules/Telemetry/Sensor/PMSA003ISensor.h
  • src/modules/Telemetry/Sensor/SCD30Sensor.h
  • src/modules/Telemetry/Sensor/SCD4XSensor.h
  • src/modules/Telemetry/Sensor/SEN5XSensor.cpp
  • src/modules/Telemetry/Sensor/SEN5XSensor.h
  • src/modules/Telemetry/Sensor/SFA30Sensor.h
  • src/modules/Telemetry/Sensor/TelemetrySensor.h
💤 Files with no reviewable changes (1)
  • src/modules/Telemetry/Sensor/SFA30Sensor.h

Comment thread src/modules/Telemetry/Sensor/SEN5XSensor.cpp

@caveman99 caveman99 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See review comment.

@oscgonfer

Copy link
Copy Markdown
Contributor Author

All good on my end too for this one @caveman99

@oscgonfer oscgonfer merged commit 9b6b4cb into meshtastic:develop Jul 3, 2026
94 checks passed
@oscgonfer oscgonfer deleted the bugfix/detection-on-0x69-address branch July 3, 2026 13:56
@oscgonfer oscgonfer restored the bugfix/detection-on-0x69-address branch July 3, 2026 13:57
caveman99 pushed a commit that referenced this pull request Jul 3, 2026
@thebentern thebentern deleted the bugfix/detection-on-0x69-address branch July 3, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Pull request that fixes bugs cleanup Code cleanup or refactor hardware-support Hardware related: new devices or modules, problems specific to hardware tech debt Code or lib references that are not up to date or propper standards

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants