fix(telemetry): collect air-quality particle counts (protobuf.js snake_case quirk)#3483
Merged
Merged
Conversation
…e_case quirk) Particle counts from an air-quality sensor (particles_03um … particles_100um) were never stored or graphed. protobuf.js only camelCases an underscore that precedes a *letter*, so these underscore-before-digit fields stay snake_case on the decoded message. The serial/direct ingestion path read them as `aqMetrics.particles03um` (camelCase) → undefined → saveTelemetryMetrics dropped them. PM/CO2 fields were fine because their underscores precede letters. - Read the snake_case form the decoder produces, camelCase as a fallback, for the six particle bins and for EnvironmentMetrics rainfall_1h / rainfall_24h (same quirk). Stored telemetryType stays canonical camelCase for the UI. - Regression test feeds payloads shaped exactly as protobuf.js decodes them. Empirically verified against the bundled telemetry.proto: particles_03um decodes to `particles_03um`, while pm10_standard → pm10Standard and co2_temperature → co2Temperature. The MQTT ingestion path was already correct (its snakeToCamel handles digits). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @Yeraze's task —— View job PR Review AnalysisI've completed a thorough review of this PR. Here's my comprehensive feedback: Todo List:
✅ Overall Assessment: Excellent QualityThis is a high-quality, well-researched fix with comprehensive testing. I recommend approval. 🎯 StrengthsProblem Analysis & Root Cause
Code Quality
Test Coverage
🔍 Technical AnalysisPerformance: ✅ No Concerns
Security: ✅ No Issues
Compatibility: ✅ Backward/Forward Compatible
💡 Architecture ValidationIntegration Points Verified:
Error Handling: ✅ Robust
📋 Code Review Checklist
🧪 Testing QualityThe test file demonstrates excellent testing practices:
📚 Documentation Excellence
🏁 Recommendation: APPROVE & MERGEThis PR demonstrates best practices in:
No changes required - ready to merge. |
Merged
Yeraze
added a commit
that referenced
this pull request
Jun 15, 2026
Bump version to 4.10.4 across package.json, package-lock.json, helm/meshmonitor/Chart.yaml, desktop/package.json, and desktop/src-tauri/tauri.conf.json. Promote CHANGELOG [Unreleased] to [4.10.4] and add the user-facing fixes merged since 4.10.3: timed-events cross-source firing (#3479), module config save for Traffic Management/Status Message (#3464), Auto Favorites firmware-support cache (#3482), MeshCore Share Contact error surfacing (#3481), and the Firefox-Android delivered-icon CSS fix (#3477). The air-quality particle-count fix (#3483) was already in [Unreleased]. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Yeraze
added a commit
that referenced
this pull request
Jun 17, 2026
#3506) (#3514) * fix(telemetry): unify serial ingest onto shared digit-aware normalizer (#3506) The serial telemetry path (processTelemetryMessageProtobuf) read each device/environment/airQuality/power metric by a hand-maintained camelCase property name, with per-field `?? particles_NNum` / `?? rainfall_Nh` fallbacks bolted on to survive the protobuf.js underscore-before-digit quirk (#3483). Any new underscore-before-digit field added upstream would silently drop again until someone remembered to add another fallback. Replace the four static metric lists with buildCanonicalMetrics(group, decoded), which iterates the fields the decoder actually produced and resolves each leaf through the shared canonicalTelemetryType/canonicalTelemetryUnit map (the same digit-aware snakeToCamel the MQTT path uses). New `_<digit>` fields are now picked up automatically once their unit lands in CANONICAL_TELEMETRY_UNITS — no per-field fallback to maintain. Verified against the real decoder shape: Object.entries yields only wire-present own fields (unset scalars are null and excluded), genuine 0 readings are own properties and preserved, and protobuf.js repeated fields (own `[]`) plus untracked leaves are skipped via the typeof-number + known-unit guards. Behavior-preserving for the current protobuf; adds coverage for the env leaf renames, device/power channels, genuine-0, and the repeated/unknown-field skips. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test+docs: NaN/Infinity guard test + dual-path comment (review #3514) - Add a test pinning the Number.isFinite guard (NaN/Infinity excluded, finite values still stored). - Comment the deviceMetrics nodeData copies vs telemetry-history rows so the apparent duplication reads clearly. Follow-up for the unconverted localStats/host/trafficManagement branches tracked in #3515. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A user hooked up an air-quality sensor; the PM/CO₂ values graphed but the particle counts never rendered. Root cause is a protobuf.js field-naming quirk in the serial/direct telemetry ingestion path — the data was dropped before it ever reached the database.
Root cause (empirically verified)
protobuf.js's camelCase only collapses an underscore followed by a letter, not a digit. Decoding the bundled
telemetry.proto:processTelemetryMessageProtobufread the particle bins asaqMetrics.particles03um(camelCase) →undefined→saveTelemetryMetricsfilters out undefined → nothing stored → nothing to graph. The PM and CO₂ fields were unaffected because their underscores precede letters, which is why only the particle data went missing.The same quirk affects
EnvironmentMetrics.rainfall_1h/rainfall_24h, fixed alongside.Fix
Read the snake_case form the decoder actually produces, with the camelCase as a fallback (so a future protobuf.js/keepCase change can't re-break it). The stored
telemetryTypestays the canonical camelCase the UI graphs/colors already key on (particles03um, etc.) — so no frontend change is needed; labels, colors and integer-formatting for these types already exist.Note: the MQTT ingestion path was already correct — its own
snakeToCamel(telemetryKeys.ts) includes digits — so only the direct/serial path needed fixing.Testing
meshtasticManager.airQualityParticles.test.ts: feeds payloads shaped exactly as protobuf.js decodes them (snake_case digit fields) and asserts all six particle bins + rainfall_1h/24h are stored under canonical types, including zero-valued readings. Would fail on the unfixed code.tsc --noEmitclean.🤖 Generated with Claude Code