Skip to content

Add HM330X PM Sensor#11026

Draft
oscgonfer wants to merge 2 commits into
meshtastic:masterfrom
oscgonfer:feat/add-hm330x
Draft

Add HM330X PM Sensor#11026
oscgonfer wants to merge 2 commits into
meshtastic:masterfrom
oscgonfer:feat/add-hm330x

Conversation

@oscgonfer

@oscgonfer oscgonfer commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

This is a PR for the FAB26 event in Boston using a HM330X (datasheet).

Tested locally with a XIAO ESP32-S3 and working properly.

Caution

I'd wait until tomorrow (17/07/2026) for confirming that it works well with "at home testing".

Summary by CodeRabbit

  • New Features
    • Added support for Seeed HM330X air-quality sensors.
    • Automatically detects compatible sensors over I2C.
    • Reports PM1.0, PM2.5, and PM10 particulate-matter readings through telemetry.
    • Validates sensor data before publishing measurements.

@oscgonfer oscgonfer self-assigned this Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Seeed HM330X air-quality sensor support, including its dependency, I2C discovery, telemetry registration, warmup lifecycle, checksum validation, and PM10/PM2.5/PM100 metric reporting.

Changes

HM330X sensor integration

Layer / File(s) Summary
Sensor dependency and contract
platformio.ini, src/configuration.h, src/detect/ScanI2C.h, src/modules/Telemetry/Sensor/HM330XSensor.h
Adds the pinned HM330X library, I2C address, device type, and HM330XSensor interface.
Detection and telemetry registration
src/detect/ScanI2CTwoWire.cpp, src/modules/Telemetry/AirQualityTelemetry.cpp
Probes shared-address devices for HM330X and registers the sensor when its library is available.
Measurement lifecycle and telemetry
src/modules/Telemetry/Sensor/HM330XSensor.cpp
Initializes the driver, manages warmup timing, validates sensor frames, and reports particulate measurements.

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

Sequence Diagram(s)

sequenceDiagram
  participant I2CScanner
  participant HM330XSensor
  participant TelemetryModule
  I2CScanner->>I2CScanner: Probe HM330X at 0x40
  I2CScanner->>TelemetryModule: Register detected HM330X
  TelemetryModule->>HM330XSensor: Initialize and wake sensor
  HM330XSensor-->>TelemetryModule: Return PM10, PM2.5, and PM100 metrics
Loading

Suggested reviewers: caveman99, jp-bennett, quency-d

Poem

A rabbit found dust in the air,
And wired a sensor with care.
PM readings now hop,
Through telemetry’s shop,
While checksums keep every byte fair.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description is brief and misses the required attestations/testing checklist from the template. Add the template's attestation checklist and note whether regression testing was run on the listed devices or specify the hardware tested.
✅ Passed checks (3 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title is clear and matches the new HM330X PM sensor support.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@oscgonfer oscgonfer added the hardware-support Hardware related: new devices or modules, problems specific to hardware label Jul 16, 2026
@oscgonfer oscgonfer marked this pull request as draft July 16, 2026 17:45
@oscgonfer oscgonfer requested a review from caveman99 July 16, 2026 17:50

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/modules/Telemetry/Sensor/HM330XSensor.h (1)

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

Remove unimplemented declaration.

This checksum method is declared but never implemented or used. The implementation uses hm330x.checksum_calc from the library instead.

♻️ Proposed fix
-    HM330XErrorCode checksum(uint8_t* data);
🤖 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/HM330XSensor.h` at line 27, Remove the unused,
unimplemented checksum declaration from the HM330X sensor interface. Keep
checksum handling through the existing hm330x.checksum_calc library call and do
not add a replacement method.
src/modules/Telemetry/Sensor/HM330XSensor.cpp (2)

48-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Throttle for the warmup interval.

Replace the getTime() subtraction and unit conversion with the repository’s Throttle helper to avoid duplicated elapsed-time logic and unit ambiguity.

As per coding guidelines, “Use Throttle from src/mesh/Throttle.h for time-based rate limiting and elapsed-time checks.”

Also applies to: 71-80

🤖 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/HM330XSensor.cpp` around lines 48 - 52, Update
HM330XSensor::wakeUp and the related warmup timing logic to use the repository’s
Throttle helper from src/mesh/Throttle.h instead of manual getTime subtraction
and unit conversion. Preserve the existing warmup interval behavior while
routing elapsed-time checks through Throttle.

Source: Coding guidelines


117-119: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Correct and shorten this particulate-size comment.

For cumulative mass concentrations, PM1.0 is normally less than or equal to PM2.5, which is less than or equal to PM10. The current comment states the inverse and exceeds the two-line comment limit.

As per coding guidelines, “Keep comments minimal—one or two lines maximum.”

Proposed change
-    // TODO - This is suspiciously not in terms of PM1, PM2.5 and PM10.0 relationship
-    // Normally, PM1.0 > PM2.5 > PM10, but in this case it's not. Are the buckets cumulative?
-    // It's not documented in the datasheet, so safely assuming that it's correct as in the datasheet
+    // HM330X reports cumulative PM1.0, PM2.5, and PM10 standard concentrations.
🤖 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/HM330XSensor.cpp` around lines 117 - 119,
Replace the three-line comment near the HM330X particulate readings with a
concise one- or two-line comment stating that cumulative mass concentrations
should satisfy PM1.0 ≤ PM2.5 ≤ PM10 and that the datasheet-defined bucket
behavior is being followed.

Source: Coding guidelines

🤖 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.

Inline comments:
In `@src/modules/Telemetry/Sensor/HM330XSensor.cpp`:
- Around line 60-64: Update HM330XSensor::canSleep() to return true so
AirQualityTelemetryModule applies wake-up and pendingForReadyMs readiness
tracking before reading the sensor. Keep sleep() as a no-op if necessary, but do
not change the readiness flow.

---

Nitpick comments:
In `@src/modules/Telemetry/Sensor/HM330XSensor.cpp`:
- Around line 48-52: Update HM330XSensor::wakeUp and the related warmup timing
logic to use the repository’s Throttle helper from src/mesh/Throttle.h instead
of manual getTime subtraction and unit conversion. Preserve the existing warmup
interval behavior while routing elapsed-time checks through Throttle.
- Around line 117-119: Replace the three-line comment near the HM330X
particulate readings with a concise one- or two-line comment stating that
cumulative mass concentrations should satisfy PM1.0 ≤ PM2.5 ≤ PM10 and that the
datasheet-defined bucket behavior is being followed.

In `@src/modules/Telemetry/Sensor/HM330XSensor.h`:
- Line 27: Remove the unused, unimplemented checksum declaration from the HM330X
sensor interface. Keep checksum handling through the existing
hm330x.checksum_calc library call and do not add a replacement method.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5320e741-8f0a-4b68-8d73-dfa8396c3fe7

📥 Commits

Reviewing files that changed from the base of the PR and between bfa5c1c and fc60f8d.

📒 Files selected for processing (7)
  • platformio.ini
  • src/configuration.h
  • src/detect/ScanI2C.h
  • src/detect/ScanI2CTwoWire.cpp
  • src/modules/Telemetry/AirQualityTelemetry.cpp
  • src/modules/Telemetry/Sensor/HM330XSensor.cpp
  • src/modules/Telemetry/Sensor/HM330XSensor.h

Comment on lines +60 to +64
bool HM330XSensor::canSleep()
{
// Sleep not available in this sensor
return false;
}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the base lifecycle contract and comparable air-quality sensors.
fd -t f 'TelemetrySensor|Sensor' src/modules/Telemetry |
  xargs rg -n -C3 '\b(canSleep|wakeUp|pendingForReadyMs|isActive)\s*\('

Repository: meshtastic/firmware

Length of output: 20253


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- HM330XSensor.cpp ---'
sed -n '1,220p' src/modules/Telemetry/Sensor/HM330XSensor.cpp

echo
echo '--- TelemetrySensor.h ---'
sed -n '1,140p' src/modules/Telemetry/Sensor/TelemetrySensor.h

echo
echo '--- AirQualityTelemetryModule.cpp ---'
sed -n '1,260p' src/modules/Telemetry/AirQualityTelemetryModule.cpp

Repository: meshtastic/firmware

Length of output: 8147


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline src/modules/Telemetry/AirQualityTelemetryModule.cpp --view expanded || true
echo
rg -n -C4 'canSleep|wakeUp|pendingForReadyMs|isActive|getMetrics' src/modules/Telemetry/AirQualityTelemetryModule.cpp src/modules/Telemetry/Sensor/*.cpp

Repository: meshtastic/firmware

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -t f 'AirQualityTelemetryModule.cpp' src/modules/Telemetry
sed -n '1,260p' src/modules/Telemetry/AirQualityTelemetryModule.cpp

Repository: meshtastic/firmware

Length of output: 252


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C4 'pendingForReadyMs\(|wakeUpTimeMs\(|canSleep\(\)|isActive\(\)|sleep\(\)|wakeUp\(\)' src/modules/Telemetry src/modules | sed -n '1,260p'

Repository: meshtastic/firmware

Length of output: 19542


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- HM330XSensor.h ---'
sed -n '1,160p' src/modules/Telemetry/Sensor/HM330XSensor.h

echo
echo '--- AirQualityTelemetry.cpp (top/middle) ---'
sed -n '1,260p' src/modules/Telemetry/AirQualityTelemetry.cpp

echo
echo '--- AirQualityTelemetry.cpp (rest) ---'
sed -n '261,520p' src/modules/Telemetry/AirQualityTelemetry.cpp

Repository: meshtastic/firmware

Length of output: 22122


Keep canSleep() true for HM330X AirQualityTelemetryModule only calls wakeUp() and pendingForReadyMs() when this returns true, so returning false skips the warmup gate and the sensor is read immediately. Leave sleep() as a no-op if needed, but don’t block readiness tracking.

🤖 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/HM330XSensor.cpp` around lines 60 - 64, Update
HM330XSensor::canSleep() to return true so AirQualityTelemetryModule applies
wake-up and pendingForReadyMs readiness tracking before reading the sensor. Keep
sleep() as a no-op if necessary, but do not change the readiness flow.

@github-actions

Copy link
Copy Markdown
Contributor

⚡ Try this PR in the Web Flasher

Note

Building this pull request… the flash button, badges and supported-board
list will appear here automatically once CI finishes.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

An error occurred during the review process. Please try again later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hardware-support Hardware related: new devices or modules, problems specific to hardware

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant