Skip to content

Update hopsAway when packets are received#988

Open
esev wants to merge 1 commit intomeshtastic:mainfrom
esev:updatehops
Open

Update hopsAway when packets are received#988
esev wants to merge 1 commit intomeshtastic:mainfrom
esev:updatehops

Conversation

@esev
Copy link
Copy Markdown

@esev esev commented Jan 2, 2026

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

hopsAway for 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

  • Code follows project style guidelines
  • Documentation has been updated or added
  • Tests have been added or updated
  • All i18n translation labels have been added (read
    CONTRIBUTING_I18N_DEVELOPER_GUIDE.md for more details)

@esev esev added the feature request New feature or request label Jan 2, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented Jan 2, 2026

@esev is attempting to deploy a commit to the Meshtastic Team on Vercel.

A member of the Team first needs to authorize it.

@esev esev marked this pull request as ready for review January 2, 2026 07:33
@danditomaso
Copy link
Copy Markdown
Collaborator

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?

@esev
Copy link
Copy Markdown
Author

esev commented Mar 17, 2026

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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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-payload bitfield presence through subscriptions.ts into nodeDB.processPacket.
  • Extend ProcessPacketParams and compute/store hopsAway on each received packet in the NodeDB store.
  • Update NodeDB store unit tests to validate hopsAway updates 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.

Comment on lines +98 to +105
db.processPacket({
from: 50,
time: 1111,
snr: 7,
hopStart: 5,
hopLimit: 2,
hasBitfield: true,
} as any);
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
} 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();
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

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

Suggested change
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();

Copilot uses AI. Check for mistakes.
hopLimit: 0,
hasBitfield: false,
} as any);
expect(db.getNode(50)?.lastHeard).toBeCloseTo(Date.now() / 1000, -1); // within 1s, note lastHeard is in seconds
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
time: number;
hopStart: number;
hopLimit: number;
hasBitfield: boolean;
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
hasBitfield: boolean;
hasPayloadBitfield: boolean;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants