Skip to content

Commit 465bafe

Browse files
authored
Merge pull request #218 from mkinney/fix_remote_admin_message
refactor code to only call local node when necessary; fix tests
2 parents ec62259 + cb8dafb commit 465bafe

File tree

7 files changed

+102
-131
lines changed

7 files changed

+102
-131
lines changed

meshtastic/__main__.py

Lines changed: 63 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from meshtastic.ble_interface import BLEInterface
1919
from meshtastic import portnums_pb2, channel_pb2, radioconfig_pb2
2020
from meshtastic.globals import Globals
21+
from meshtastic.__init__ import BROADCAST_ADDR
2122

2223

2324
def onReceive(packet, interface):
@@ -140,14 +141,6 @@ def onConnected(interface):
140141
if not args.export_config:
141142
print("Connected to radio")
142143

143-
def getNode():
144-
"""This operation could be expensive, so we try to cache the results"""
145-
targetNode = our_globals.get_target_node()
146-
if not targetNode:
147-
targetNode = interface.getNode(args.destOrLocal)
148-
our_globals.set_target_node(targetNode)
149-
return targetNode
150-
151144
if args.setlat or args.setlon or args.setalt:
152145
closeNow = True
153146

@@ -179,12 +172,12 @@ def getNode():
179172
if args.set_owner:
180173
closeNow = True
181174
print(f"Setting device owner to {args.set_owner}")
182-
getNode().setOwner(args.set_owner)
175+
interface.getNode(args.dest).setOwner(args.set_owner)
183176

184177
if args.pos_fields:
185178
# If --pos-fields invoked with args, set position fields
186179
closeNow = True
187-
prefs = getNode().radioConfig.preferences
180+
prefs = interface.getNode(args.dest).radioConfig.preferences
188181
allFields = 0
189182

190183
try:
@@ -201,12 +194,12 @@ def getNode():
201194
print(f"Setting position fields to {allFields}")
202195
setPref(prefs, 'position_flags', ('%d' % allFields))
203196
print("Writing modified preferences to device")
204-
getNode().writeConfig()
197+
interface.getNode(args.dest).writeConfig()
205198

206199
elif args.pos_fields is not None:
207200
# If --pos-fields invoked without args, read and display current value
208201
closeNow = True
209-
prefs = getNode().radioConfig.preferences
202+
prefs = interface.getNode(args.dest).radioConfig.preferences
210203

211204
fieldNames = []
212205
for bit in radioconfig_pb2.PositionFlags.values():
@@ -225,86 +218,85 @@ def getNode():
225218
print(sorted(meshtastic.mesh_pb2.Team.keys()))
226219
else:
227220
print(f"Setting team to {meshtastic.mesh_pb2.Team.Name(v_team)}")
228-
getNode().setOwner(team=v_team)
221+
interface.getNode(args.dest).setOwner(team=v_team)
229222

230223
if args.set_ham:
231224
closeNow = True
232225
print(f"Setting Ham ID to {args.set_ham} and turning off encryption")
233-
getNode().setOwner(args.set_ham, is_licensed=True)
226+
interface.getNode(args.dest).setOwner(args.set_ham, is_licensed=True)
234227
# Must turn off encryption on primary channel
235-
getNode().turnOffEncryptionOnPrimaryChannel()
228+
interface.getNode(args.dest).turnOffEncryptionOnPrimaryChannel()
236229

237230
if args.reboot:
238231
closeNow = True
239-
getNode().reboot()
232+
interface.getNode(args.dest).reboot()
240233

241234
if args.sendtext:
242235
closeNow = True
243236
channelIndex = 0
244237
if args.ch_index is not None:
245238
channelIndex = int(args.ch_index)
246-
logging.debug(f'channelIndex:{channelIndex}')
247-
logging.debug(f'interface.localNode:{interface.localNode}')
248-
logging.debug(f'interface.localNode.channels:{interface.localNode.channels}')
249-
our_globals.set_target_node(interface.localNode)
250-
ch = getNode().getChannelByChannelIndex(channelIndex)
239+
ch = interface.localNode.getChannelByChannelIndex(channelIndex)
251240
logging.debug(f'ch:{ch}')
252241
if ch and ch.role != channel_pb2.Channel.Role.DISABLED:
253-
print(f"Sending text message {args.sendtext} to {args.destOrAll} on channelIndex:{channelIndex}")
254-
interface.sendText(args.sendtext, args.destOrAll, wantAck=True, channelIndex=channelIndex)
242+
print(f"Sending text message {args.sendtext} to {args.dest} on channelIndex:{channelIndex}")
243+
interface.sendText(args.sendtext, args.dest, wantAck=True, channelIndex=channelIndex)
255244
else:
256245
meshtastic.util.our_exit(f"Warning: {channelIndex} is not a valid channel. Channel must not be DISABLED.")
257246

258247
if args.sendping:
259248
payload = str.encode("test string")
260-
print(f"Sending ping message to {args.destOrAll}")
261-
interface.sendData(payload, args.destOrAll, portNum=portnums_pb2.PortNum.REPLY_APP,
249+
print(f"Sending ping message to {args.dest}")
250+
interface.sendData(payload, args.dest, portNum=portnums_pb2.PortNum.REPLY_APP,
262251
wantAck=True, wantResponse=True)
263252

264253
if args.gpio_wrb or args.gpio_rd or args.gpio_watch:
265-
rhc = remote_hardware.RemoteHardwareClient(interface)
266-
267-
if args.gpio_wrb:
268-
bitmask = 0
269-
bitval = 0
270-
for wrpair in (args.gpio_wrb or []):
271-
bitmask |= 1 << int(wrpair[0])
272-
bitval |= int(wrpair[1]) << int(wrpair[0])
273-
print(f"Writing GPIO mask 0x{bitmask:x} with value 0x{bitval:x} to {args.dest}")
274-
rhc.writeGPIOs(args.dest, bitmask, bitval)
275-
closeNow = True
276-
277-
if args.gpio_rd:
278-
bitmask = int(args.gpio_rd, 16)
279-
print(f"Reading GPIO mask 0x{bitmask:x} from {args.dest}")
280-
interface.mask = bitmask
281-
rhc.readGPIOs(args.dest, bitmask, None)
282-
if not interface.noProto:
283-
# wait up to X seconds for a response
284-
for _ in range(10):
254+
if args.dest == BROADCAST_ADDR:
255+
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
256+
else:
257+
rhc = remote_hardware.RemoteHardwareClient(interface)
258+
259+
if args.gpio_wrb:
260+
bitmask = 0
261+
bitval = 0
262+
for wrpair in (args.gpio_wrb or []):
263+
bitmask |= 1 << int(wrpair[0])
264+
bitval |= int(wrpair[1]) << int(wrpair[0])
265+
print(f"Writing GPIO mask 0x{bitmask:x} with value 0x{bitval:x} to {args.dest}")
266+
rhc.writeGPIOs(args.dest, bitmask, bitval)
267+
closeNow = True
268+
269+
if args.gpio_rd:
270+
bitmask = int(args.gpio_rd, 16)
271+
print(f"Reading GPIO mask 0x{bitmask:x} from {args.dest}")
272+
interface.mask = bitmask
273+
rhc.readGPIOs(args.dest, bitmask, None)
274+
if not interface.noProto:
275+
# wait up to X seconds for a response
276+
for _ in range(10):
277+
time.sleep(1)
278+
if interface.gotResponse:
279+
break
280+
logging.debug(f'end of gpio_rd')
281+
282+
if args.gpio_watch:
283+
bitmask = int(args.gpio_watch, 16)
284+
print(f"Watching GPIO mask 0x{bitmask:x} from {args.dest}. Press ctrl-c to exit")
285+
while True:
286+
rhc.watchGPIOs(args.dest, bitmask)
285287
time.sleep(1)
286-
if interface.gotResponse:
287-
break
288-
logging.debug(f'end of gpio_rd')
289-
290-
if args.gpio_watch:
291-
bitmask = int(args.gpio_watch, 16)
292-
print(f"Watching GPIO mask 0x{bitmask:x} from {args.dest}. Press ctrl-c to exit")
293-
while True:
294-
rhc.watchGPIOs(args.dest, bitmask)
295-
time.sleep(1)
296288

297289
# handle settings
298290
if args.set:
299291
closeNow = True
300-
prefs = getNode().radioConfig.preferences
292+
prefs = interface.getNode(args.dest).radioConfig.preferences
301293

302294
# Handle the int/float/bool arguments
303295
for pref in args.set:
304296
setPref(prefs, pref[0], pref[1])
305297

306298
print("Writing modified preferences to device")
307-
getNode().writeConfig()
299+
interface.getNode(args.dest).writeConfig()
308300

309301
if args.configure:
310302
with open(args.configure[0], encoding='utf8') as file:
@@ -313,11 +305,11 @@ def getNode():
313305

314306
if 'owner' in configuration:
315307
print(f"Setting device owner to {configuration['owner']}")
316-
getNode().setOwner(configuration['owner'])
308+
interface.getNode(args.dest).setOwner(configuration['owner'])
317309

318310
if 'channel_url' in configuration:
319311
print("Setting channel url to", configuration['channel_url'])
320-
getNode().setURL(configuration['channel_url'])
312+
interface.getNode(args.dest).setURL(configuration['channel_url'])
321313

322314
if 'location' in configuration:
323315
alt = 0
@@ -342,11 +334,11 @@ def getNode():
342334
interface.localNode.writeConfig()
343335

344336
if 'user_prefs' in configuration:
345-
prefs = getNode().radioConfig.preferences
337+
prefs = interface.getNode(args.dest).radioConfig.preferences
346338
for pref in configuration['user_prefs']:
347339
setPref(prefs, pref, str(configuration['user_prefs'][pref]))
348340
print("Writing modified preferences to device")
349-
getNode().writeConfig()
341+
interface.getNode(args.dest).writeConfig()
350342

351343
if args.export_config:
352344
# export the configuration (the opposite of '--configure')
@@ -355,15 +347,15 @@ def getNode():
355347

356348
if args.seturl:
357349
closeNow = True
358-
getNode().setURL(args.seturl)
350+
interface.getNode(args.dest).setURL(args.seturl)
359351

360352
# handle changing channels
361353

362354
if args.ch_add:
363355
closeNow = True
364356
if len(args.ch_add) > 10:
365357
meshtastic.util.our_exit("Warning: Channel name must be shorter. Channel not added.")
366-
n = getNode()
358+
n = interface.getNode(args.dest)
367359
ch = n.getChannelByName(args.ch_add)
368360
if ch:
369361
meshtastic.util.our_exit(f"Warning: This node already has a '{args.ch_add}' channel. No changes were made.")
@@ -391,7 +383,7 @@ def getNode():
391383
meshtastic.util.our_exit("Warning: Cannot delete primary channel.", 1)
392384
else:
393385
print(f"Deleting channel {channelIndex}")
394-
ch = getNode().deleteChannel(channelIndex)
386+
ch = interface.getNode(args.dest).deleteChannel(channelIndex)
395387

396388
ch_changes = [args.ch_longslow, args.ch_longfast,
397389
args.ch_mediumslow, args.ch_mediumfast,
@@ -407,7 +399,7 @@ def getNode():
407399
channelIndex = 0
408400
else:
409401
meshtastic.util.our_exit("Warning: Need to specify '--ch-index'.", 1)
410-
ch = getNode().channels[channelIndex]
402+
ch = interface.getNode(args.dest).channels[channelIndex]
411403

412404
if any_primary_channel_changes or args.ch_enable or args.ch_disable:
413405

@@ -468,21 +460,22 @@ def setSimpleChannel(modem_config):
468460
ch.role = channel_pb2.Channel.Role.DISABLED
469461

470462
print(f"Writing modified channels to device")
471-
getNode().writeChannel(channelIndex)
463+
interface.getNode(args.dest).writeChannel(channelIndex)
472464

473465
if args.info:
474466
print("")
475-
if not args.dest: # If we aren't trying to talk to our local node, don't show it
467+
# If we aren't trying to talk to our local node, don't show it
468+
if args.dest == BROADCAST_ADDR:
476469
interface.showInfo()
477470

478471
print("")
479-
getNode().showInfo()
472+
interface.getNode(args.dest).showInfo()
480473
closeNow = True # FIXME, for now we leave the link up while talking to remote nodes
481474
print("")
482475

483476
if args.get:
484477
closeNow = True
485-
prefs = getNode().radioConfig.preferences
478+
prefs = interface.getNode(args.dest).radioConfig.preferences
486479

487480
# Handle the int/float/bool arguments
488481
for pref in args.get:
@@ -596,13 +589,8 @@ def common():
596589
channelIndex = int(args.ch_index)
597590
our_globals.set_channel_index(channelIndex)
598591

599-
# Some commands require dest to be set, so we now use destOrAll/destOrLocal for more lenient commands
600592
if not args.dest:
601-
args.destOrAll = "^all"
602-
args.destOrLocal = "^local"
603-
else:
604-
args.destOrAll = args.dest
605-
args.destOrLocal = args.dest # FIXME, temp hack for debugging remove
593+
args.dest = BROADCAST_ADDR
606594

607595
if not args.seriallog:
608596
if args.noproto:

meshtastic/globals.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ def __init__(self):
2727
Globals.__instance = self
2828
self.args = None
2929
self.parser = None
30-
self.target_node = None
3130
self.channel_index = None
3231
self.logfile = None
3332
self.tunnelInstance = None
@@ -36,7 +35,6 @@ def reset(self):
3635
"""Reset all of our globals. If you add a member, add it to this method, too."""
3736
self.args = None
3837
self.parser = None
39-
self.target_node = None
4038
self.channel_index = None
4139
self.logfile = None
4240
self.tunnelInstance = None
@@ -50,10 +48,6 @@ def set_parser(self, parser):
5048
"""Set the parser"""
5149
self.parser = parser
5250

53-
def set_target_node(self, target_node):
54-
"""Set the target_node"""
55-
self.target_node = target_node
56-
5751
def set_channel_index(self, channel_index):
5852
"""Set the channel_index"""
5953
self.channel_index = channel_index
@@ -75,10 +69,6 @@ def get_parser(self):
7569
"""Get parser"""
7670
return self.parser
7771

78-
def get_target_node(self):
79-
"""Get target_node"""
80-
return self.target_node
81-
8272
def get_channel_index(self):
8373
"""Get channel_index"""
8474
return self.channel_index

meshtastic/mesh_interface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ def getTimeAgo(ts):
159159

160160
def getNode(self, nodeId):
161161
"""Return a node object which contains device settings and channel info"""
162-
if nodeId == LOCAL_ADDR:
162+
if nodeId in (LOCAL_ADDR, BROADCAST_ADDR):
163163
return self.localNode
164164
else:
165165
n = meshtastic.node.Node(self, nodeId)

meshtastic/node.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ def _requestSettings(self):
257257
p = admin_pb2.AdminMessage()
258258
p.get_radio_request = True
259259

260+
# TODO: should we check that localNode has an 'admin' channel?
260261
# Show progress message for super slow operations
261262
if self != self.iface.localNode:
262263
print("Requesting preferences from remote node.")

meshtastic/serial_interface.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,25 @@ def __init__(self, devPath=None, debugOut=None, noProto=False, connectNow=True):
4040

4141
# first we need to set the HUPCL so the device will not reboot based on RTS and/or DTR
4242
# see https://github.com/pyserial/pyserial/issues/124
43-
if not self.noProto:
44-
if platform.system() != 'Windows':
45-
with open(devPath, encoding='utf8') as f:
46-
attrs = termios.tcgetattr(f)
47-
attrs[2] = attrs[2] & ~termios.HUPCL
48-
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
49-
f.close()
50-
time.sleep(0.1)
43+
if platform.system() != 'Windows':
44+
with open(devPath, encoding='utf8') as f:
45+
attrs = termios.tcgetattr(f)
46+
attrs[2] = attrs[2] & ~termios.HUPCL
47+
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
48+
f.close()
49+
time.sleep(0.1)
5150

5251
self.stream = serial.Serial(devPath, 921600, exclusive=True, timeout=0.5, write_timeout=0)
53-
if not self.noProto:
54-
self.stream.flush()
55-
time.sleep(0.1)
52+
self.stream.flush()
53+
time.sleep(0.1)
5654

5755
StreamInterface.__init__(self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
5856

5957
def close(self):
6058
"""Close a connection to the device"""
61-
if not self.noProto:
62-
self.stream.flush()
63-
time.sleep(0.1)
64-
self.stream.flush()
65-
time.sleep(0.1)
59+
self.stream.flush()
60+
time.sleep(0.1)
61+
self.stream.flush()
62+
time.sleep(0.1)
6663
logging.debug("Closing Serial stream")
6764
StreamInterface.close(self)

0 commit comments

Comments
 (0)