Skip to content

Add hoplimit argument to override default hopLimit in config #745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions meshtastic/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,8 @@ def onConnected(interface):
wantAck=True,
channelIndex=channelIndex,
onResponse=interface.getNode(args.dest, False, **getNode_kwargs).onAckNak,
portNum=portnums_pb2.PortNum.PRIVATE_APP if args.private else portnums_pb2.PortNum.TEXT_MESSAGE_APP
portNum=portnums_pb2.PortNum.PRIVATE_APP if args.private else portnums_pb2.PortNum.TEXT_MESSAGE_APP,
hopLimit=args.hoplimit
)
else:
meshtastic.util.our_exit(
Expand All @@ -500,7 +501,7 @@ def onConnected(interface):

if args.traceroute:
loraConfig = getattr(interface.localNode.localConfig, "lora")
hopLimit = getattr(loraConfig, "hop_limit")
hopLimit = args.hoplimit or getattr(loraConfig, "hop_limit")
dest = str(args.traceroute)
channelIndex = mt_config.channel_index or 0
if checkChannel(interface, channelIndex):
Expand Down Expand Up @@ -533,6 +534,7 @@ def onConnected(interface):
wantResponse=True,
channelIndex=channelIndex,
telemetryType=telemType,
hopLimit=args.hoplimit
)

if args.request_position:
Expand All @@ -548,6 +550,7 @@ def onConnected(interface):
destinationId=args.dest,
wantResponse=True,
channelIndex=channelIndex,
hopLimit=args.hoplimit
)

if args.gpio_wrb or args.gpio_rd or args.gpio_watch:
Expand Down Expand Up @@ -1744,6 +1747,13 @@ def addRemoteActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPar
"--reply", help="Reply to received messages", action="store_true"
)

group.add_argument(
"--hoplimit",
help="Specify the hop limit for the message. Overrides the default hop limit set in the config.",
type=int,
default=None,
)

return parser

def addRemoteAdminArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
Expand Down
10 changes: 8 additions & 2 deletions meshtastic/mesh_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,8 @@ def sendText(
wantResponse: bool = False,
onResponse: Optional[Callable[[dict], Any]] = None,
channelIndex: int = 0,
portNum: portnums_pb2.PortNum.ValueType = portnums_pb2.PortNum.TEXT_MESSAGE_APP
portNum: portnums_pb2.PortNum.ValueType = portnums_pb2.PortNum.TEXT_MESSAGE_APP,
hopLimit: Optional[int] = None
):
"""Send a utf8 string to some other node, if the node has a display it
will also be shown on the device.
Expand Down Expand Up @@ -441,6 +442,7 @@ def sendText(
wantResponse=wantResponse,
onResponse=onResponse,
channelIndex=channelIndex,
hopLimit=hopLimit
)


Expand Down Expand Up @@ -560,6 +562,7 @@ def sendPosition(
wantAck: bool = False,
wantResponse: bool = False,
channelIndex: int = 0,
hopLimit: Optional[int] = None
):
"""
Send a position packet to some other node (normally a broadcast)
Expand Down Expand Up @@ -596,6 +599,7 @@ def sendPosition(
wantResponse=wantResponse,
onResponse=onResponse,
channelIndex=channelIndex,
hopLimit=hopLimit
)
if wantResponse:
self.waitForPosition()
Expand Down Expand Up @@ -701,7 +705,8 @@ def sendTelemetry(
destinationId: Union[int, str] = BROADCAST_ADDR,
wantResponse: bool = False,
channelIndex: int = 0,
telemetryType: str = "device_metrics"
telemetryType: str = "device_metrics",
hopLimit: Optional[int] = None
):
"""Send telemetry and optionally ask for a response"""
r = telemetry_pb2.Telemetry()
Expand Down Expand Up @@ -748,6 +753,7 @@ def sendTelemetry(
wantResponse=wantResponse,
onResponse=onResponse,
channelIndex=channelIndex,
hopLimit=hopLimit
)
if wantResponse:
self.waitForTelemetry()
Expand Down
243 changes: 221 additions & 22 deletions meshtastic/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,10 +593,10 @@ def test_main_sendtext(capsys):
iface = MagicMock(autospec=SerialInterface)

def mock_sendText(
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0, portNum=0
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0, portNum=0, hopLimit=None
):
print("inside mocked sendText")
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum}")
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum} {hopLimit}")

iface.sendText.side_effect = mock_sendText

Expand All @@ -620,10 +620,10 @@ def test_main_sendtext_with_channel(capsys):
iface = MagicMock(autospec=SerialInterface)

def mock_sendText(
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0, portNum=0
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0, portNum=0, hopLimit=None
):
print("inside mocked sendText")
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum}")
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum} {hopLimit}")

iface.sendText.side_effect = mock_sendText

Expand Down Expand Up @@ -1360,26 +1360,27 @@ def test_main_ch_enable_primary_channel(capsys):
# TODO
# @pytest.mark.unit
# @pytest.mark.usefixtures("reset_mt_config")
# def test_main_ch_range_options(capsys):
# """Test changing the various range options."""
# range_options = ['--ch-vlongslow', '--ch-longslow', '--ch-longfast', '--ch-midslow',
# '--ch-midfast', '--ch-shortslow', '--ch-shortfast']
# for range_option in range_options:
# sys.argv = ['', f"{range_option}" ]
# mt_config.args = sys.argv
# @pytest.mark.parametrize("range_option", [
# '--ch-vlongslow', '--ch-longslow', '--ch-longfast', '--ch-midslow',
# '--ch-midfast', '--ch-shortslow', '--ch-shortfast'
# ])
# def test_main_ch_range_options(range_option, capsys):
# """Test changing the various range options."""
# sys.argv = ['', f"{range_option}"]
# mt_config.args = sys.argv
#
# mocked_node = MagicMock(autospec=Node)
# mocked_node = MagicMock(autospec=Node)
#
# iface = MagicMock(autospec=SerialInterface)
# iface.getNode.return_value = mocked_node
# iface = MagicMock(autospec=SerialInterface)
# iface.getNode.return_value = mocked_node
#
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# main()
# out, err = capsys.readouterr()
# assert re.search(r'Connected to radio', out, re.MULTILINE)
# assert re.search(r'Writing modified channels', out, re.MULTILINE)
# assert err == ''
# mo.assert_called()
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# main()
# out, err = capsys.readouterr()
# assert re.search(r'Connected to radio', out, re.MULTILINE)
# assert re.search(r'Writing modified channels', out, re.MULTILINE)
# assert err == ''
# mo.assert_called()


@pytest.mark.unit
Expand Down Expand Up @@ -1828,7 +1829,7 @@ def test_main_export_config(capsys):
@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_gpio_rd_no_gpio_channel(capsys):
"""Test --gpio_rd with no named gpio channel"""
"""Test --gpio-rd with no named gpio channel"""
sys.argv = ["", "--gpio-rd", "0x10", "--dest", "!foo"]
mt_config.args = sys.argv

Expand Down Expand Up @@ -2713,3 +2714,201 @@ def test_remove_ignored_node():
main()

mocked_node.removeIgnored.assert_called_once_with("!12345678")

@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_traceroute_with_hoplimit(capsys):
"""Test --traceroute with --hoplimit"""
sys.argv = ["", "--traceroute", "!12345678", "--hoplimit", "5"]
mt_config.args = sys.argv

iface = MagicMock(autospec=SerialInterface)

def mock_sendTraceRoute(dest, hopLimit, channelIndex=0):
print("inside mocked sendTraceRoute")
print(f"{dest} {hopLimit} {channelIndex}")

iface.sendTraceRoute.side_effect = mock_sendTraceRoute

with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r"Connected to radio", out, re.MULTILINE)
assert re.search(r"inside mocked sendTraceRoute", out, re.MULTILINE)
assert re.search(r"!12345678 5 0", out, re.MULTILINE)
assert err == ""
mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_request_telemetry_with_hoplimit(capsys):
"""Test --request-telemetry with --hoplimit"""
sys.argv = ["", "--request-telemetry", "--hoplimit", "5"]
mt_config.args = sys.argv

iface = MagicMock(autospec=SerialInterface)

def mock_sendTelemetry(destinationId, wantResponse=False, channelIndex=0, telemetryType="device_metrics", hopLimit=None):
print("inside mocked sendTelemetry")
print(f"{destinationId} {wantResponse} {channelIndex} {telemetryType} {hopLimit}")

iface.sendTelemetry.side_effect = mock_sendTelemetry

with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r"Connected to radio", out, re.MULTILINE)
assert re.search(r"inside mocked sendTelemetry", out, re.MULTILINE)
assert re.search(r"4294967295 False 0 device_metrics 5", out, re.MULTILINE)
assert err == ""
mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_request_position_with_hoplimit(capsys):
"""Test --request-position with --hoplimit"""
sys.argv = ["", "--request-position", "--hoplimit", "5"]
mt_config.args = sys.argv

iface = MagicMock(autospec=SerialInterface)

def mock_sendPosition(latitude=0.0, longitude=0.0, altitude=0, destinationId=4294967295, wantAck=False, wantResponse=False, channelIndex=0, hopLimit=None):
print("inside mocked sendPosition")
print(f"{latitude} {longitude} {altitude} {destinationId} {wantAck} {wantResponse} {channelIndex} {hopLimit}")

iface.sendPosition.side_effect = mock_sendPosition

with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r"Connected to radio", out, re.MULTILINE)
assert re.search(r"inside mocked sendPosition", out, re.MULTILINE)
assert re.search(r"0.0 0.0 0 4294967295 False True 0 5", out, re.MULTILINE)
assert err == ""
mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_sendtext_with_hoplimit(capsys):
"""Test --sendtext with --hoplimit"""
sys.argv = ["", "--sendtext", "hello", "--hoplimit", "5"]
mt_config.args = sys.argv

iface = MagicMock(autospec=SerialInterface)

def mock_sendText(
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0, portNum=0, hopLimit=None
):
print("inside mocked sendText")
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum} {hopLimit}")

iface.sendText.side_effect = mock_sendText

with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r"Connected to radio", out, re.MULTILINE)
assert re.search(r"Sending text message", out, re.MULTILINE)
assert re.search(r"inside mocked sendText", out, re.MULTILINE)
assert re.search(r"hello 4294967295 False False 0 0 5", out, re.MULTILINE)
assert err == ""
mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_sendtext_without_hoplimit(capsys):
"""Test --sendtext without --hoplimit"""
sys.argv = ["", "--sendtext", "hello"]
mt_config.args = sys.argv

iface = MagicMock(autospec=SerialInterface)

def mock_sendText(
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0, portNum=0, hopLimit=None
):
print("inside mocked sendText")
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum} {hopLimit}")

iface.sendText.side_effect = mock_sendText

with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r"Connected to radio", out, re.MULTILINE)
assert re.search(r"Sending text message", out, re.MULTILINE)
assert re.search(r"inside mocked sendText", out, re.MULTILINE)
assert re.search(r"hello 4294967295 False False 0 0 None", out, re.MULTILINE)
assert err == ""
mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_traceroute_without_hoplimit(capsys):
"""Test --traceroute without --hoplimit"""
sys.argv = ["", "--traceroute", "!12345678"]
mt_config.args = sys.argv

iface = MagicMock(autospec=SerialInterface)

def mock_sendTraceRoute(dest, hopLimit, channelIndex=0):
print("inside mocked sendTraceRoute")
print(f"{dest} {hopLimit} {channelIndex}")

iface.sendTraceRoute.side_effect = mock_sendTraceRoute

with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r"Connected to radio", out, re.MULTILINE)
assert re.search(r"inside mocked sendTraceRoute", out, re.MULTILINE)
assert re.search(r"!12345678 None 0", out, re.MULTILINE)
assert err == ""
mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_request_telemetry_without_hoplimit(capsys):
"""Test --request-telemetry without --hoplimit"""
sys.argv = ["", "--request-telemetry"]
mt_config.args = sys.argv

iface = MagicMock(autospec=SerialInterface)

def mock_sendTelemetry(destinationId, wantResponse=False, channelIndex=0, telemetryType="device_metrics", hopLimit=None):
print("inside mocked sendTelemetry")
print(f"{destinationId} {wantResponse} {channelIndex} {telemetryType} {hopLimit}")

iface.sendTelemetry.side_effect = mock_sendTelemetry

with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r"Connected to radio", out, re.MULTILINE)
assert re.search(r"inside mocked sendTelemetry", out, re.MULTILINE)
assert re.search(r"4294967295 False 0 device_metrics None", out, re.MULTILINE)
assert err == ""
mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_main_request_position_without_hoplimit(capsys):
"""Test --request-position without --hoplimit"""
sys.argv = ["", "--request-position"]
mt_config.args = sys.argv

iface = MagicMock(autospec=SerialInterface)

def mock_sendPosition(latitude=0.0, longitude=0.0, altitude=0, destinationId=4294967295, wantAck=False, wantResponse=False, channelIndex=0, hopLimit=None):
print("inside mocked sendPosition")
print(f"{latitude} {longitude} {altitude} {destinationId} {wantAck} {wantResponse} {channelIndex} {hopLimit}")

iface.sendPosition.side_effect = mock_sendPosition

with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r"Connected to radio", out, re.MULTILINE)
assert re.search(r"inside mocked sendPosition", out, re.MULTILINE)
assert re.search(r"0.0 0.0 0 4294967295 False True 0 None", out, re.MULTILINE)
assert err == ""
mo.assert_called()
Loading