Skip to content
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

Retry admin channel setting retrieval and add configurable timeout #665

Merged
merged 15 commits into from
Sep 18, 2024
Merged
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
105 changes: 63 additions & 42 deletions meshtastic/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,12 @@
try:
args = mt_config.args

# convenient place to store any keyword args we pass to getNode
getNode_kwargs = {
"requestChannelAttempts": args.channel_fetch_attempts,
"timeout": args.timeout
}

# do not print this line if we are exporting the config
if not args.export_config:
print("Connected to radio")
Expand Down Expand Up @@ -324,14 +330,14 @@
print(f"Setting device owner to {args.set_owner}")
else: # short name only
print(f"Setting device owner short to {args.set_owner_short}")
interface.getNode(args.dest, False).setOwner(long_name=args.set_owner, short_name=args.set_owner_short)
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(long_name=args.set_owner, short_name=args.set_owner_short)

# TODO: add to export-config and configure
if args.set_canned_message:
closeNow = True
waitForAckNak = True
print(f"Setting canned plugin message to {args.set_canned_message}")
interface.getNode(args.dest, False).set_canned_message(
interface.getNode(args.dest, False, **getNode_kwargs).set_canned_message(
args.set_canned_message
)

Expand All @@ -340,12 +346,12 @@
closeNow = True
waitForAckNak = True
print(f"Setting ringtone to {args.set_ringtone}")
interface.getNode(args.dest, False).set_ringtone(args.set_ringtone)
interface.getNode(args.dest, False, **getNode_kwargs).set_ringtone(args.set_ringtone)

Check warning on line 349 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L349

Added line #L349 was not covered by tests

if args.pos_fields:
# If --pos-fields invoked with args, set position fields
closeNow = True
positionConfig = interface.getNode(args.dest).localConfig.position
positionConfig = interface.getNode(args.dest, **getNode_kwargs).localConfig.position

Check warning on line 354 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L354

Added line #L354 was not covered by tests
allFields = 0

try:
Expand All @@ -364,12 +370,12 @@
print(f"Setting position fields to {allFields}")
setPref(positionConfig, "position_flags", f"{allFields:d}")
print("Writing modified preferences to device")
interface.getNode(args.dest).writeConfig("position")
interface.getNode(args.dest, **getNode_kwargs).writeConfig("position")

Check warning on line 373 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L373

Added line #L373 was not covered by tests

elif args.pos_fields is not None:
# If --pos-fields invoked without args, read and display current value
closeNow = True
positionConfig = interface.getNode(args.dest).localConfig.position
positionConfig = interface.getNode(args.dest, **getNode_kwargs).localConfig.position

Check warning on line 378 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L378

Added line #L378 was not covered by tests

fieldNames = []
for bit in positionConfig.PositionFlags.values():
Expand All @@ -380,57 +386,58 @@
if args.set_ham:
closeNow = True
print(f"Setting Ham ID to {args.set_ham} and turning off encryption")
interface.getNode(args.dest).setOwner(args.set_ham, is_licensed=True)
interface.getNode(args.dest, **getNode_kwargs).setOwner(args.set_ham, is_licensed=True)
# Must turn off encryption on primary channel
interface.getNode(args.dest).turnOffEncryptionOnPrimaryChannel()
interface.getNode(args.dest, **getNode_kwargs).turnOffEncryptionOnPrimaryChannel()

if args.reboot:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).reboot()
interface.getNode(args.dest, False, **getNode_kwargs).reboot()

if args.reboot_ota:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).rebootOTA()
interface.getNode(args.dest, False, **getNode_kwargs).rebootOTA()

Check warning on line 401 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L401

Added line #L401 was not covered by tests

if args.enter_dfu:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).enterDFUMode()
interface.getNode(args.dest, False, **getNode_kwargs).enterDFUMode()

Check warning on line 406 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L406

Added line #L406 was not covered by tests

if args.shutdown:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).shutdown()
interface.getNode(args.dest, False, **getNode_kwargs).shutdown()

if args.device_metadata:
closeNow = True
interface.getNode(args.dest, False).getMetadata()
interface.getNode(args.dest, False, **getNode_kwargs).getMetadata()

Check warning on line 415 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L415

Added line #L415 was not covered by tests

if args.begin_edit:
closeNow = True
interface.getNode(args.dest, False).beginSettingsTransaction()
interface.getNode(args.dest, False, **getNode_kwargs).beginSettingsTransaction()

Check warning on line 419 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L419

Added line #L419 was not covered by tests

if args.commit_edit:
closeNow = True
interface.getNode(args.dest, False).commitSettingsTransaction()
interface.getNode(args.dest, False, **getNode_kwargs).commitSettingsTransaction()

Check warning on line 423 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L423

Added line #L423 was not covered by tests

if args.factory_reset or args.factory_reset_device:
closeNow = True
waitForAckNak = True

full = bool(args.factory_reset_device)
interface.getNode(args.dest, False).factoryReset(full=full)
interface.getNode(args.dest, False, **getNode_kwargs).factoryReset(full=full)

Check warning on line 430 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L430

Added line #L430 was not covered by tests

if args.remove_node:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).removeNode(args.remove_node)
interface.getNode(args.dest, False, **getNode_kwargs).removeNode(args.remove_node)

Check warning on line 435 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L435

Added line #L435 was not covered by tests

if args.reset_nodedb:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).resetNodeDb()
interface.getNode(args.dest, False, **getNode_kwargs).resetNodeDb()

Check warning on line 440 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L440

Added line #L440 was not covered by tests

if args.sendtext:
closeNow = True
Expand All @@ -444,7 +451,7 @@
args.dest,
wantAck=True,
channelIndex=channelIndex,
onResponse=interface.getNode(args.dest, False).onAckNak,
onResponse=interface.getNode(args.dest, False, **getNode_kwargs).onAckNak,
)
else:
meshtastic.util.our_exit(
Expand Down Expand Up @@ -535,7 +542,7 @@
if args.set:
closeNow = True
waitForAckNak = True
node = interface.getNode(args.dest, False)
node = interface.getNode(args.dest, False, **getNode_kwargs)

# Handle the int/float/bool arguments
pref = None
Expand Down Expand Up @@ -574,19 +581,19 @@
configuration = yaml.safe_load(file)
closeNow = True

interface.getNode(args.dest, False).beginSettingsTransaction()
interface.getNode(args.dest, False, **getNode_kwargs).beginSettingsTransaction()

if "owner" in configuration:
print(f"Setting device owner to {configuration['owner']}")
waitForAckNak = True
interface.getNode(args.dest, False).setOwner(configuration["owner"])
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(configuration["owner"])

Check warning on line 589 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L589

Added line #L589 was not covered by tests

if "owner_short" in configuration:
print(
f"Setting device owner short to {configuration['owner_short']}"
)
waitForAckNak = True
interface.getNode(args.dest, False).setOwner(
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(

Check warning on line 596 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L596

Added line #L596 was not covered by tests
long_name=None, short_name=configuration["owner_short"]
)

Expand All @@ -595,17 +602,17 @@
f"Setting device owner short to {configuration['ownerShort']}"
)
waitForAckNak = True
interface.getNode(args.dest, False).setOwner(
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(

Check warning on line 605 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L605

Added line #L605 was not covered by tests
long_name=None, short_name=configuration["ownerShort"]
)

if "channel_url" in configuration:
print("Setting channel url to", configuration["channel_url"])
interface.getNode(args.dest).setURL(configuration["channel_url"])
interface.getNode(args.dest, **getNode_kwargs).setURL(configuration["channel_url"])

Check warning on line 611 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L611

Added line #L611 was not covered by tests

if "channelUrl" in configuration:
print("Setting channel url to", configuration["channelUrl"])
interface.getNode(args.dest).setURL(configuration["channelUrl"])
interface.getNode(args.dest, **getNode_kwargs).setURL(configuration["channelUrl"])

Check warning on line 615 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L615

Added line #L615 was not covered by tests

if "location" in configuration:
alt = 0
Expand All @@ -630,28 +637,28 @@
interface.localNode.writeConfig("position")

if "config" in configuration:
localConfig = interface.getNode(args.dest).localConfig
localConfig = interface.getNode(args.dest, **getNode_kwargs).localConfig

Check warning on line 640 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L640

Added line #L640 was not covered by tests
for section in configuration["config"]:
traverseConfig(
section, configuration["config"][section], localConfig
)
interface.getNode(args.dest).writeConfig(
interface.getNode(args.dest, **getNode_kwargs).writeConfig(

Check warning on line 645 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L645

Added line #L645 was not covered by tests
meshtastic.util.camel_to_snake(section)
)

if "module_config" in configuration:
moduleConfig = interface.getNode(args.dest).moduleConfig
moduleConfig = interface.getNode(args.dest, **getNode_kwargs).moduleConfig

Check warning on line 650 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L650

Added line #L650 was not covered by tests
for section in configuration["module_config"]:
traverseConfig(
section,
configuration["module_config"][section],
moduleConfig,
)
interface.getNode(args.dest).writeConfig(
interface.getNode(args.dest, **getNode_kwargs).writeConfig(

Check warning on line 657 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L657

Added line #L657 was not covered by tests
meshtastic.util.camel_to_snake(section)
)

interface.getNode(args.dest, False).commitSettingsTransaction()
interface.getNode(args.dest, False, **getNode_kwargs).commitSettingsTransaction()
print("Writing modified configuration to device")

if args.export_config:
Expand All @@ -664,7 +671,7 @@

if args.seturl:
closeNow = True
interface.getNode(args.dest).setURL(args.seturl)
interface.getNode(args.dest, **getNode_kwargs).setURL(args.seturl)

# handle changing channels

Expand All @@ -680,7 +687,7 @@
meshtastic.util.our_exit(
"Warning: Channel name must be shorter. Channel not added."
)
n = interface.getNode(args.dest)
n = interface.getNode(args.dest, **getNode_kwargs)
ch = n.getChannelByName(args.ch_add)
if ch:
meshtastic.util.our_exit(
Expand Down Expand Up @@ -719,7 +726,7 @@
)
else:
print(f"Deleting channel {channelIndex}")
ch = interface.getNode(args.dest).deleteChannel(channelIndex)
ch = interface.getNode(args.dest, **getNode_kwargs).deleteChannel(channelIndex)

def setSimpleConfig(modem_preset):
"""Set one of the simple modem_config"""
Expand All @@ -729,7 +736,7 @@
"Warning: Cannot set modem preset for non-primary channel", 1
)
# Overwrite modem_preset
node = interface.getNode(args.dest, False)
node = interface.getNode(args.dest, False, **getNode_kwargs)

Check warning on line 739 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L739

Added line #L739 was not covered by tests
if len(node.localConfig.ListFields()) == 0:
node.requestConfig(node.localConfig.DESCRIPTOR.fields_by_name.get("lora"))
node.localConfig.lora.modem_preset = modem_preset
Expand Down Expand Up @@ -763,7 +770,7 @@
channelIndex = mt_config.channel_index
if channelIndex is None:
meshtastic.util.our_exit("Warning: Need to specify '--ch-index'.", 1)
node = interface.getNode(args.dest)
node = interface.getNode(args.dest, **getNode_kwargs)
ch = node.channels[channelIndex]

if args.ch_enable or args.ch_disable:
Expand Down Expand Up @@ -827,20 +834,20 @@
if args.get_canned_message:
closeNow = True
print("")
interface.getNode(args.dest).get_canned_message()
interface.getNode(args.dest, **getNode_kwargs).get_canned_message()

if args.get_ringtone:
closeNow = True
print("")
interface.getNode(args.dest).get_ringtone()
interface.getNode(args.dest, **getNode_kwargs).get_ringtone()

Check warning on line 842 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L842

Added line #L842 was not covered by tests

if args.info:
print("")
# If we aren't trying to talk to our local node, don't show it
if args.dest == BROADCAST_ADDR:
interface.showInfo()
print("")
interface.getNode(args.dest).showInfo()
interface.getNode(args.dest, **getNode_kwargs).showInfo()
closeNow = True
print("")
pypi_version = meshtastic.util.check_if_newer_version()
Expand All @@ -857,7 +864,7 @@

if args.get:
closeNow = True
node = interface.getNode(args.dest, False)
node = interface.getNode(args.dest, False, **getNode_kwargs)
for pref in args.get:
found = getPref(node, pref[0])

Expand All @@ -873,7 +880,7 @@

if args.qr or args.qr_all:
closeNow = True
url = interface.getNode(args.dest, True).getURL(includeAll=args.qr_all)
url = interface.getNode(args.dest, True, **getNode_kwargs).getURL(includeAll=args.qr_all)
if args.qr_all:
urldesc = "Complete URL (includes all channels)"
else:
Expand Down Expand Up @@ -928,7 +935,7 @@
print(
f"Waiting for an acknowledgment from remote node (this could take a while)"
)
interface.getNode(args.dest, False).iface.waitForAckNak()
interface.getNode(args.dest, False, **getNode_kwargs).iface.waitForAckNak()

Check warning on line 938 in meshtastic/__main__.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/__main__.py#L938

Added line #L938 was not covered by tests

if args.wait_to_disconnect:
print(f"Waiting {args.wait_to_disconnect} seconds before disconnecting")
Expand Down Expand Up @@ -1408,6 +1415,20 @@
action="append",
)

group.add_argument(
"--channel-fetch-attempts",
help=("Attempt to retrieve channel settings for --ch-set this many times before giving up."),
default=3,
type=int,
)

group.add_argument(
"--timeout",
help="How long to wait for replies",
default=300,
type=int,
)

group.add_argument(
"--ch-vlongslow",
help="Change to the very long-range and slow channel",
Expand Down
22 changes: 18 additions & 4 deletions meshtastic/mesh_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,19 +315,33 @@
return table

def getNode(
self, nodeId: str, requestChannels: bool = True
self, nodeId: str, requestChannels: bool = True, requestChannelAttempts: int = 3, timeout: int = 300
) -> meshtastic.node.Node:
"""Return a node object which contains device settings and channel info"""
if nodeId in (LOCAL_ADDR, BROADCAST_ADDR):
return self.localNode
else:
n = meshtastic.node.Node(self, nodeId)
n = meshtastic.node.Node(self, nodeId, timeout=timeout)
# Only request device settings and channel info when necessary
if requestChannels:
logging.debug("About to requestChannels")
n.requestChannels()
if not n.waitForConfig():
our_exit("Error: Timed out waiting for channels")
retries_left = requestChannelAttempts
last_index: int = 0
while retries_left > 0:
retries_left -= 1
if not n.waitForConfig():
new_index: int = len(n.partialChannels) if n.partialChannels else 0
# each time we get a new channel, reset the counter
if new_index != last_index:
retries_left = requestChannelAttempts - 1

Check warning on line 337 in meshtastic/mesh_interface.py

View check run for this annotation

Codecov / codecov/patch

meshtastic/mesh_interface.py#L337

Added line #L337 was not covered by tests
if retries_left <= 0:
our_exit(f"Error: Timed out waiting for channels, giving up")
print("Timed out trying to retrieve channel info, retrying")
n.requestChannels(startingIndex=new_index)
last_index = new_index
else:
break
return n

def sendText(
Expand Down
Loading
Loading