Update hopsAway when packets are received#988
Conversation
|
@esev is attempting to deploy a commit to the Meshtastic Team on Vercel. A member of the Team first needs to authorize it. |
|
Thanks for the PR, i'm reviewing and I'd like to get this merged. I noticed there wasn't any UI specific changes in this PR. Are you planning to add the hopsAway to the message bubble in a later PR? |
I was mainly interested in having the 'Nodes' view show the correct number of hops. |
There was a problem hiding this comment.
Pull request overview
Updates hopsAway for nodes in the NodeDB whenever new mesh packets are received, using hopStart - hopLimit and leveraging decoded payload bitfield presence to disambiguate legacy packets where hop_start is effectively unknown.
Changes:
- Pass
hopStart,hopLimit, and decoded-payloadbitfieldpresence throughsubscriptions.tsintonodeDB.processPacket. - Extend
ProcessPacketParamsand compute/storehopsAwayon each received packet in the NodeDB store. - Update NodeDB store unit tests to validate
hopsAwayupdates and the legacy ambiguity case.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| packages/web/src/core/subscriptions.ts | Adds hop/bitfield metadata when calling nodeDB.processPacket on each received MeshPacket. |
| packages/web/src/core/stores/nodeDBStore/types.ts | Extends ProcessPacketParams with hop and bitfield fields needed for hopsAway calculation. |
| packages/web/src/core/stores/nodeDBStore/index.ts | Computes hopsAway during processPacket and stores it on NodeInfo. |
| packages/web/src/core/stores/nodeDBStore/nodeDBStore.test.tsx | Updates/extends unit test expectations for hopsAway behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| db.processPacket({ | ||
| from: 50, | ||
| time: 1111, | ||
| snr: 7, | ||
| hopStart: 5, | ||
| hopLimit: 2, | ||
| hasBitfield: true, | ||
| } as any); |
There was a problem hiding this comment.
These processPacket(...) calls now satisfy ProcessPacketParams, so the as any casts are no longer needed. Dropping them will keep the test type-safe and prevent accidentally omitting fields in future updates.
| } as any); | ||
| expect(db.getNode(50)?.lastHeard).toBeCloseTo(Date.now() / 1000, -1); // within 1s, note lastHeard is in seconds | ||
| expect(db.getNode(50)?.snr).toBe(9); | ||
| expect(db.getNode(50)?.hopsAway).toBeUndefined(); |
There was a problem hiding this comment.
The new hopsAway disambiguation logic has a few key branches, but the test only covers the hopStart===0 && !hasBitfield (undefined) path. Please add assertions for at least: (1) hopStart===0 && hasBitfield===true (should yield hopsAway === 0), and (2) hopLimit > hopStart (should yield undefined).
| expect(db.getNode(50)?.hopsAway).toBeUndefined(); | |
| expect(db.getNode(50)?.hopsAway).toBeUndefined(); | |
| // when hopStart===0 and hasBitfield is true, hopsAway should be 0 | |
| db.processPacket({ | |
| from: 50, | |
| time: 3333, | |
| snr: 10, | |
| hopStart: 0, | |
| hopLimit: 0, | |
| hasBitfield: true, | |
| } as any); | |
| expect(db.getNode(50)?.lastHeard).toBe(3333); | |
| expect(db.getNode(50)?.snr).toBe(10); | |
| expect(db.getNode(50)?.hopsAway).toBe(0); | |
| // when hopLimit > hopStart, hopsAway should be undefined | |
| db.processPacket({ | |
| from: 50, | |
| time: 4444, | |
| snr: 11, | |
| hopStart: 1, | |
| hopLimit: 2, | |
| hasBitfield: true, | |
| } as any); | |
| expect(db.getNode(50)?.lastHeard).toBe(4444); | |
| expect(db.getNode(50)?.snr).toBe(11); | |
| expect(db.getNode(50)?.hopsAway).toBeUndefined(); |
| hopLimit: 0, | ||
| hasBitfield: false, | ||
| } as any); | ||
| expect(db.getNode(50)?.lastHeard).toBeCloseTo(Date.now() / 1000, -1); // within 1s, note lastHeard is in seconds |
There was a problem hiding this comment.
This assertion comment says “within 1s”, but toBeCloseTo(..., -1) allows a ~5 second delta. Either adjust the numDigits (or use fake timers/vi.setSystemTime) to match the intended tolerance, or update the comment to reflect the actual tolerance.
| expect(db.getNode(50)?.lastHeard).toBeCloseTo(Date.now() / 1000, -1); // within 1s, note lastHeard is in seconds | |
| expect(db.getNode(50)?.lastHeard).toBeCloseTo(Date.now() / 1000, -1); // approximate current time in seconds, with broad tolerance |
| time: number; | ||
| hopStart: number; | ||
| hopLimit: number; | ||
| hasBitfield: boolean; |
There was a problem hiding this comment.
hasBitfield is ambiguous (which bitfield/where?) and is being used specifically as a packet capability/version signal. Consider renaming it to something more explicit like hasPayloadBitfield / hasDecodedBitfield (or similar) so it’s clear it refers to the decoded payload’s optional bitfield presence, not a generic node property.
| hasBitfield: boolean; | |
| hasPayloadBitfield: boolean; |
Description
Update the number of hops away for each node in the 'Connections' column of the node list table as new packets arrive.
Related Issues
Follows the logic from the firmware project: meshtastic/firmware#9120
Changes Made
hopsAwayfor a node is calculated each time a new packet is received. It is set based on the difference between the hop_start & hop_limit in the MeshPacket.Prior to firmware version v2.3.0 nodes did not provide a hop_start in packets. This meant that receiving a hop_start value of 0 could mean two different things; either the node was older and didn't supply a hop_start, or the transmitting node had LoRa number of hops set to 0. This PR uses the presence of the bitfield, added in v2.5.0, to distinguish between these two cases.
When hop_start=0 and the bitfield is present, we can trust that the transmitting node had LoRa number of hops set to 0. Otherwise the value for hopsAway is undefined.
Testing Done
Updated existing unit tests and verified the hops are calculated correctly by connecting to a bluetooth device.
Checklist
CONTRIBUTING_I18N_DEVELOPER_GUIDE.md for more details)