From 5f43a32242138b308ebffd1520253abf7f52e035 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 20 Mar 2021 10:47:04 +0800 Subject: [PATCH] 1.2.12 --- docs/meshtastic/index.html | 171 ++++++++++++++++++++++++++++++------- setup.py | 2 +- 2 files changed, 143 insertions(+), 30 deletions(-) diff --git a/docs/meshtastic/index.html b/docs/meshtastic/index.html index 81797b8..9715d8b 100644 --- a/docs/meshtastic/index.html +++ b/docs/meshtastic/index.html @@ -258,15 +258,37 @@ class Node: self._sendAdmin(p) logging.debug("Wrote config") - def writeChannel(self, channelIndex): + def writeChannel(self, channelIndex, adminIndex = 0): """Write the current (edited) channel to the device""" p = admin_pb2.AdminMessage() p.set_channel.CopyFrom(self.channels[channelIndex]) - self._sendAdmin(p) + self._sendAdmin(p, adminIndex=adminIndex) logging.debug("Wrote channel {channelIndex}") + def deleteChannel(self, channelIndex): + """Delete the specifed channelIndex and shift other channels up""" + ch = self.channels[channelIndex] + if ch.role != channel_pb2.Channel.Role.SECONDARY: + raise Exception("Only SECONDARY channels can be deleted") + + # we are careful here because if we move the "admin" channel the channelIndex we need to use + # for sending admin channels will also change + adminIndex = self.iface.localNode._getAdminChannelIndex() + + self.channels.pop(channelIndex) + self._fixupChannels() # expand back to 8 channels + + index = channelIndex + while index < self.iface.myInfo.max_channels: + self.writeChannel(index, adminIndex=adminIndex) + index += 1 + + # if we are updating the local node, we might end up *moving* the admin channel index as we are writing + if (self.iface.localNode == self) and index >= adminIndex: + adminIndex = 0 # We've now passed the old location for admin index (and writen it), so we can start finding it by name again + def getChannelByName(self, name): """Try to find the named channel or return None""" for c in (self.channels or []): @@ -389,6 +411,27 @@ class Node: return self._sendAdmin(p) + def _fixupChannels(self): + """Fixup indexes and add disabled channels as needed""" + + # Add extra disabled channels as needed + for index, ch in enumerate(self.channels): + ch.index = index # fixup indexes + + self._fillChannels() + + def _fillChannels(self): + """Mark unused channels as disabled""" + + # Add extra disabled channels as needed + index = len(self.channels) + while index < self.iface.myInfo.max_channels: + ch = channel_pb2.Channel() + ch.role = channel_pb2.Channel.Role.DISABLED + ch.index = index + self.channels.append(ch) + index += 1 + def _requestChannel(self, channelNum: int): """ Done with initial config messages, now send regular MeshPackets to ask for settings @@ -414,16 +457,9 @@ class Node: if quitEarly or index >= self.iface.myInfo.max_channels - 1: logging.debug("Finished downloading channels") - # Fill the rest of array with DISABLED channels - index += 1 - while index < self.iface.myInfo.max_channels: - ch = channel_pb2.Channel() - ch.role = channel_pb2.Channel.Role.DISABLED - ch.index = index - self.partialChannels.append(ch) - index += 1 - self.channels = self.partialChannels + self._fixupChannels() + # FIXME, the following should only be called after we have settings and channels self.iface._connected() # Tell everone else we are ready to go else: @@ -434,15 +470,19 @@ class Node: onResponse=onResponse) def _sendAdmin(self, p: admin_pb2.AdminMessage, wantResponse=False, - onResponse=None): + onResponse=None, + adminIndex=0): """Send an admin message to the specified node (or the local node if destNodeNum is zero)""" + if adminIndex == 0: # unless a special channel index was used, we want to use the admin index + adminIndex = self.iface.localNode._getAdminChannelIndex() + return self.iface.sendData(p, self.nodeNum, portNum=portnums_pb2.PortNum.ADMIN_APP, wantAck=True, wantResponse=wantResponse, onResponse=onResponse, - channelIndex=self.iface.localNode._getAdminChannelIndex()) + channelIndex=adminIndex) class MeshInterface: @@ -2321,15 +2361,37 @@ wantResponse – True if you want the service on the other side to send an a self._sendAdmin(p) logging.debug("Wrote config") - def writeChannel(self, channelIndex): + def writeChannel(self, channelIndex, adminIndex = 0): """Write the current (edited) channel to the device""" p = admin_pb2.AdminMessage() p.set_channel.CopyFrom(self.channels[channelIndex]) - self._sendAdmin(p) + self._sendAdmin(p, adminIndex=adminIndex) logging.debug("Wrote channel {channelIndex}") + def deleteChannel(self, channelIndex): + """Delete the specifed channelIndex and shift other channels up""" + ch = self.channels[channelIndex] + if ch.role != channel_pb2.Channel.Role.SECONDARY: + raise Exception("Only SECONDARY channels can be deleted") + + # we are careful here because if we move the "admin" channel the channelIndex we need to use + # for sending admin channels will also change + adminIndex = self.iface.localNode._getAdminChannelIndex() + + self.channels.pop(channelIndex) + self._fixupChannels() # expand back to 8 channels + + index = channelIndex + while index < self.iface.myInfo.max_channels: + self.writeChannel(index, adminIndex=adminIndex) + index += 1 + + # if we are updating the local node, we might end up *moving* the admin channel index as we are writing + if (self.iface.localNode == self) and index >= adminIndex: + adminIndex = 0 # We've now passed the old location for admin index (and writen it), so we can start finding it by name again + def getChannelByName(self, name): """Try to find the named channel or return None""" for c in (self.channels or []): @@ -2452,6 +2514,27 @@ wantResponse – True if you want the service on the other side to send an a return self._sendAdmin(p) + def _fixupChannels(self): + """Fixup indexes and add disabled channels as needed""" + + # Add extra disabled channels as needed + for index, ch in enumerate(self.channels): + ch.index = index # fixup indexes + + self._fillChannels() + + def _fillChannels(self): + """Mark unused channels as disabled""" + + # Add extra disabled channels as needed + index = len(self.channels) + while index < self.iface.myInfo.max_channels: + ch = channel_pb2.Channel() + ch.role = channel_pb2.Channel.Role.DISABLED + ch.index = index + self.channels.append(ch) + index += 1 + def _requestChannel(self, channelNum: int): """ Done with initial config messages, now send regular MeshPackets to ask for settings @@ -2477,16 +2560,9 @@ wantResponse – True if you want the service on the other side to send an a if quitEarly or index >= self.iface.myInfo.max_channels - 1: logging.debug("Finished downloading channels") - # Fill the rest of array with DISABLED channels - index += 1 - while index < self.iface.myInfo.max_channels: - ch = channel_pb2.Channel() - ch.role = channel_pb2.Channel.Role.DISABLED - ch.index = index - self.partialChannels.append(ch) - index += 1 - self.channels = self.partialChannels + self._fixupChannels() + # FIXME, the following should only be called after we have settings and channels self.iface._connected() # Tell everone else we are ready to go else: @@ -2497,15 +2573,19 @@ wantResponse – True if you want the service on the other side to send an a onResponse=onResponse) def _sendAdmin(self, p: admin_pb2.AdminMessage, wantResponse=False, - onResponse=None): + onResponse=None, + adminIndex=0): """Send an admin message to the specified node (or the local node if destNodeNum is zero)""" + if adminIndex == 0: # unless a special channel index was used, we want to use the admin index + adminIndex = self.iface.localNode._getAdminChannelIndex() + return self.iface.sendData(p, self.nodeNum, portNum=portnums_pb2.PortNum.ADMIN_APP, wantAck=True, wantResponse=wantResponse, onResponse=onResponse, - channelIndex=self.iface.localNode._getAdminChannelIndex()) + channelIndex=adminIndex)

Instance variables

@@ -2533,6 +2613,38 @@ def channelURL(self):

Methods

+
+def deleteChannel(self, channelIndex) +
+
+

Delete the specifed channelIndex and shift other channels up

+
+ +Expand source code + +
def deleteChannel(self, channelIndex):
+    """Delete the specifed channelIndex and shift other channels up"""
+    ch = self.channels[channelIndex]
+    if ch.role != channel_pb2.Channel.Role.SECONDARY:
+        raise Exception("Only SECONDARY channels can be deleted")
+
+    # we are careful here because if we move the "admin" channel the channelIndex we need to use
+    # for sending admin channels will also change
+    adminIndex = self.iface.localNode._getAdminChannelIndex()
+
+    self.channels.pop(channelIndex)
+    self._fixupChannels() # expand back to 8 channels
+
+    index = channelIndex
+    while index < self.iface.myInfo.max_channels:
+        self.writeChannel(index, adminIndex=adminIndex)
+        index += 1
+
+        # if we are updating the local node, we might end up *moving* the admin channel index as we are writing
+        if (self.iface.localNode == self) and index >= adminIndex:
+            adminIndex = 0 # We've now passed the old location for admin index (and writen it), so we can start finding it by name again
+
+
def exitSimulator(self)
@@ -2722,7 +2834,7 @@ def channelURL(self):
-def writeChannel(self, channelIndex) +def writeChannel(self, channelIndex, adminIndex=0)

Write the current (edited) channel to the device

@@ -2730,13 +2842,13 @@ def channelURL(self): Expand source code -
def writeChannel(self, channelIndex):
+
def writeChannel(self, channelIndex, adminIndex = 0):
     """Write the current (edited) channel to the device"""
 
     p = admin_pb2.AdminMessage()
     p.set_channel.CopyFrom(self.channels[channelIndex])
 
-    self._sendAdmin(p)
+    self._sendAdmin(p, adminIndex=adminIndex)
     logging.debug("Wrote channel {channelIndex}")
@@ -3258,6 +3370,7 @@ hostname {string} – Hostname/IP address of the device to connect to

Node
  • channelURL
  • +
  • deleteChannel
  • exitSimulator
  • getChannelByName
  • getDisabledChannel
  • diff --git a/setup.py b/setup.py index 5f768c5..27e16fc 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ with open("README.md", "r") as fh: # This call to setup() does all the work setup( name="meshtastic", - version="1.2.11", + version="1.2.12", description="Python API & client shell for talking to Meshtastic devices", long_description=long_description, long_description_content_type="text/markdown",