mirror of
https://github.com/meshtastic/python.git
synced 2026-01-02 21:07:55 -05:00
wip on validating --set-owner on remote node
This commit is contained in:
@@ -241,8 +241,7 @@ def onConnected(interface):
|
||||
if args.sendtext:
|
||||
closeNow = True
|
||||
print(f"Sending text message {args.sendtext} to {args.destOrAll}")
|
||||
interface.sendText(args.sendtext, args.destOrAll,
|
||||
wantAck=True)
|
||||
interface.sendText(args.sendtext, args.destOrAll, wantAck=True)
|
||||
|
||||
if args.sendping:
|
||||
print(f"Sending ping message {args.sendtext} to {args.destOrAll}")
|
||||
@@ -259,8 +258,7 @@ def onConnected(interface):
|
||||
for wrpair in (args.gpio_wrb or []):
|
||||
bitmask |= 1 << int(wrpair[0])
|
||||
bitval |= int(wrpair[1]) << int(wrpair[0])
|
||||
print(
|
||||
f"Writing GPIO mask 0x{bitmask:x} with value 0x{bitval:x} to {args.dest}")
|
||||
print(f"Writing GPIO mask 0x{bitmask:x} with value 0x{bitval:x} to {args.dest}")
|
||||
rhc.writeGPIOs(args.dest, bitmask, bitval)
|
||||
closeNow = True
|
||||
|
||||
@@ -275,6 +273,7 @@ def onConnected(interface):
|
||||
sys.exit(0) # Just force an exit (FIXME - ugly)
|
||||
|
||||
rhc.readGPIOs(args.dest, bitmask, onResponse)
|
||||
time.sleep(10)
|
||||
|
||||
if args.gpio_watch:
|
||||
bitmask = int(args.gpio_watch, 16)
|
||||
@@ -752,13 +751,13 @@ def initParser():
|
||||
action="store_true")
|
||||
|
||||
parser.add_argument(
|
||||
"--gpio-wrb", nargs=2, help="Set a particlar GPIO # to 1 or 0", action='append')
|
||||
"--gpio-wrb", nargs=2, help="Set a particular GPIO # to 1 or 0", action='append')
|
||||
|
||||
parser.add_argument(
|
||||
"--gpio-rd", help="Read from a GPIO mask")
|
||||
"--gpio-rd", help="Read from a GPIO mask (ex: '0x10')")
|
||||
|
||||
parser.add_argument(
|
||||
"--gpio-watch", help="Start watching a GPIO mask for changes")
|
||||
"--gpio-watch", help="Start watching a GPIO mask for changes (ex: '0x10')")
|
||||
|
||||
parser.add_argument(
|
||||
"--no-time", help="Suppress sending the current time to the mesh", action="store_true")
|
||||
|
||||
@@ -21,10 +21,6 @@ from . import portnums_pb2, mesh_pb2
|
||||
from .util import stripnl, Timeout, our_exit
|
||||
from .__init__ import LOCAL_ADDR, BROADCAST_NUM, BROADCAST_ADDR, ResponseHandler, publishingThread, OUR_APP_VERSION, protocols
|
||||
|
||||
|
||||
defaultHopLimit = 3
|
||||
|
||||
|
||||
class MeshInterface:
|
||||
"""Interface class for meshtastic devices
|
||||
|
||||
@@ -56,6 +52,7 @@ class MeshInterface:
|
||||
self.currentPacketId = random.randint(0, 0xffffffff)
|
||||
self.nodesByNum = None
|
||||
self.configId = None
|
||||
self.defaultHopLimit = 3
|
||||
|
||||
def close(self):
|
||||
"""Shutdown this interface"""
|
||||
@@ -162,7 +159,7 @@ class MeshInterface:
|
||||
destinationId=BROADCAST_ADDR,
|
||||
wantAck=False,
|
||||
wantResponse=False,
|
||||
hopLimit=defaultHopLimit,
|
||||
hopLimit=None,
|
||||
onResponse=None,
|
||||
channelIndex=0):
|
||||
"""Send a utf8 string to some other node, if the node has a display it
|
||||
@@ -184,6 +181,9 @@ class MeshInterface:
|
||||
Returns the sent packet. The id field will be populated in this packet
|
||||
and can be used to track future message acks/naks.
|
||||
"""
|
||||
if hopLimit is None:
|
||||
hopLimit = self.defaultHopLimit
|
||||
|
||||
return self.sendData(text.encode("utf-8"), destinationId,
|
||||
portNum=portnums_pb2.PortNum.TEXT_MESSAGE_APP,
|
||||
wantAck=wantAck,
|
||||
@@ -195,7 +195,7 @@ class MeshInterface:
|
||||
def sendData(self, data, destinationId=BROADCAST_ADDR,
|
||||
portNum=portnums_pb2.PortNum.PRIVATE_APP, wantAck=False,
|
||||
wantResponse=False,
|
||||
hopLimit=defaultHopLimit,
|
||||
hopLimit=None,
|
||||
onResponse=None,
|
||||
channelIndex=0):
|
||||
"""Send a data packet to some other node
|
||||
@@ -219,6 +219,9 @@ class MeshInterface:
|
||||
Returns the sent packet. The id field will be populated in this packet
|
||||
and can be used to track future message acks/naks.
|
||||
"""
|
||||
if hopLimit is None:
|
||||
hopLimit = self.defaultHopLimit
|
||||
|
||||
if getattr(data, "SerializeToString", None):
|
||||
logging.debug(f"Serializing protobuf as data: {stripnl(data)}")
|
||||
data = data.SerializeToString()
|
||||
@@ -280,13 +283,15 @@ class MeshInterface:
|
||||
|
||||
def _sendPacket(self, meshPacket,
|
||||
destinationId=BROADCAST_ADDR,
|
||||
wantAck=False, hopLimit=defaultHopLimit):
|
||||
wantAck=False, hopLimit=None):
|
||||
"""Send a MeshPacket to the specified node (or if unspecified, broadcast).
|
||||
You probably don't want this - use sendData instead.
|
||||
|
||||
Returns the sent packet. The id field will be populated in this packet and
|
||||
can be used to track future message acks/naks.
|
||||
"""
|
||||
if hopLimit is None:
|
||||
hopLimit = self.defaultHopLimit
|
||||
|
||||
# We allow users to talk to the local node before we've completed the full connection flow...
|
||||
if(self.myInfo is not None and destinationId != self.myInfo.my_node_num):
|
||||
@@ -365,7 +370,7 @@ class MeshInterface:
|
||||
def _waitConnected(self):
|
||||
"""Block until the initial node db download is complete, or timeout
|
||||
and raise an exception"""
|
||||
if not self.isConnected.wait(10.0): # timeout after 10 seconds
|
||||
if not self.isConnected.wait(15.0): # timeout after x seconds
|
||||
raise Exception("Timed out waiting for connection completion")
|
||||
|
||||
# If we failed while connecting, raise the connection to the client
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Node class
|
||||
"""
|
||||
|
||||
import re
|
||||
import logging
|
||||
import base64
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
@@ -20,7 +21,7 @@ class Node:
|
||||
self.nodeNum = nodeNum
|
||||
self.radioConfig = None
|
||||
self.channels = None
|
||||
self._timeout = Timeout(maxSecs=60)
|
||||
self._timeout = Timeout(maxSecs=300)
|
||||
self.partialChannels = None
|
||||
self.noProto = noProto
|
||||
|
||||
@@ -49,6 +50,7 @@ class Node:
|
||||
|
||||
def requestConfig(self):
|
||||
"""Send regular MeshPackets to ask for settings and channels."""
|
||||
logging.debug(f"requestConfig for nodeNum:{self.nodeNum}")
|
||||
self.radioConfig = None
|
||||
self.channels = None
|
||||
self.partialChannels = [] # We keep our channels in a temp array until finished
|
||||
@@ -134,6 +136,7 @@ class Node:
|
||||
|
||||
def setOwner(self, long_name=None, short_name=None, is_licensed=False, team=None):
|
||||
"""Set device owner name"""
|
||||
logging.debug(f"in setOwner nodeNum:{self.nodeNum}")
|
||||
nChars = 3
|
||||
minChars = 2
|
||||
if long_name is not None:
|
||||
@@ -227,19 +230,39 @@ class Node:
|
||||
def onResponse(p):
|
||||
"""A closure to handle the response packet"""
|
||||
errorFound = False
|
||||
if 'routing' in p["decoded"]:
|
||||
if p["decoded"]["routing"]["errorReason"] != "NONE":
|
||||
errorFound = True
|
||||
print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
|
||||
if 'routing' in p['decoded']:
|
||||
if 'errorReason' in p['decoded']:
|
||||
if p['decoded']['routing']['errorReason'] != 'NONE':
|
||||
errorFound = True
|
||||
print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
|
||||
if errorFound is False:
|
||||
self.radioConfig = p["decoded"]["admin"]["raw"].get_radio_response
|
||||
logging.debug("Received radio config, now fetching channels...")
|
||||
self._timeout.reset() # We made foreward progress
|
||||
self._requestChannel(0) # now start fetching channels
|
||||
logging.debug(f'p:{p}')
|
||||
if "decoded" in p:
|
||||
if "admin" in p["decoded"]:
|
||||
if "raw" in p["decoded"]["admin"]:
|
||||
self.radioConfig = p["decoded"]["admin"]["raw"].get_radio_response
|
||||
logging.debug("Received radio config, now fetching channels...")
|
||||
self._timeout.reset() # We made foreward progress
|
||||
self._requestChannel(0) # now start fetching channels
|
||||
else:
|
||||
print("Warning: There was no 'raw' in packet in onResponse() in _requestSettings()")
|
||||
print(f"p:{p}")
|
||||
#else:
|
||||
#print("Warning: There was no 'admin' in packet in onResponse() in _requestSettings()")
|
||||
#print(f"p:{p}")
|
||||
else:
|
||||
print("Warning: There was no 'decoded' in packet in onResponse() in _requestSettings()")
|
||||
print(f"p:{p}")
|
||||
|
||||
# Show progress message for super slow operations
|
||||
if self != self.iface.localNode:
|
||||
print("Requesting preferences from remote node (this could take a while)")
|
||||
print("Requesting preferences from remote node.")
|
||||
print("Be sure:")
|
||||
print(" 1. There is a SECONDARY channel named 'admin'.")
|
||||
print(" 2. The '--seturl' was used to configure.")
|
||||
print(" 3. All devices have the same modem config. (i.e., '--ch-longfast')")
|
||||
print(" 4. All devices have been rebooted after all of the above. (optional, but recommended)")
|
||||
print("Note: This could take a while (it requests remote channel configs, then writes config)")
|
||||
|
||||
return self._sendAdmin(p, wantResponse=True, onResponse=onResponse)
|
||||
|
||||
@@ -290,25 +313,49 @@ class Node:
|
||||
|
||||
# Show progress message for super slow operations
|
||||
if self != self.iface.localNode:
|
||||
logging.info(f"Requesting channel {channelNum} info from remote node (this could take a while)")
|
||||
print(f"Requesting channel {channelNum} info from remote node (this could take a while)")
|
||||
logging.debug(f"Requesting channel {channelNum} info from remote node (this could take a while)")
|
||||
else:
|
||||
logging.debug(f"Requesting channel {channelNum}")
|
||||
|
||||
def onResponse(p):
|
||||
"""A closure to handle the response packet for requesting a channel"""
|
||||
c = p["decoded"]["admin"]["raw"].get_channel_response
|
||||
self.partialChannels.append(c)
|
||||
self._timeout.reset() # We made foreward progress
|
||||
logging.debug(f"Received channel {stripnl(c)}")
|
||||
index = c.index
|
||||
|
||||
# for stress testing, we can always download all channels
|
||||
fastChannelDownload = True
|
||||
quitEarly = False
|
||||
|
||||
# Once we see a response that has NO settings, assume
|
||||
# we are at the end of channels and stop fetching
|
||||
quitEarly = (c.role == channel_pb2.Channel.Role.DISABLED) and fastChannelDownload
|
||||
index = len(self.partialChannels)
|
||||
logging.debug(f'index:{index}')
|
||||
logging.debug(f' p:{p}')
|
||||
|
||||
if 'decoded' in p:
|
||||
if 'admin' in p['decoded']:
|
||||
if 'raw' in p['decoded']['admin']:
|
||||
c = p["decoded"]["admin"]["raw"].get_channel_response
|
||||
# Once we see a response that has NO settings, assume
|
||||
# we are at the end of channels and stop fetching
|
||||
tmp = f"{stripnl(c)}"
|
||||
logging.debug(f'tmp:{tmp}:')
|
||||
if re.search(r'settings { }', tmp):
|
||||
quitEarly = True
|
||||
logging.debug(f'Set quitEarly')
|
||||
else:
|
||||
self.partialChannels.append(c)
|
||||
logging.debug(f"Received channel {stripnl(c)}")
|
||||
#index = c.index
|
||||
self._timeout.reset() # We made foreward progress
|
||||
else:
|
||||
print("Warning: There was no 'raw' in packet to onResponse() in _requestChannel.")
|
||||
print(f"p:{p}")
|
||||
else:
|
||||
#print("Warning: There was no 'admin' in packet to onResponse() in _requestChannel.")
|
||||
#print(f"p:{p}")
|
||||
pass
|
||||
else:
|
||||
print("Warning: There was no 'decoded' in packet to onResponse() in _requestChannel.")
|
||||
print(f"p:{p}")
|
||||
|
||||
# TODO: is myInfo.max_channels the same as the remote's max channels?
|
||||
logging.debug(f'index:{index} self.iface.myInfo.max_channels:{self.iface.myInfo.max_channels}')
|
||||
if quitEarly or index >= self.iface.myInfo.max_channels - 1:
|
||||
logging.debug("Finished downloading channels")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user