From 0e6ad7632b829aafe86ec47da58a0bc2b45320cd Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 22 Mar 2021 09:44:01 +0800 Subject: [PATCH] 1.2.13 --- docs/meshtastic/index.html | 192 +++++++++++++++++++++++++------------ docs/meshtastic/util.html | 12 ++- setup.py | 2 +- 3 files changed, 141 insertions(+), 65 deletions(-) diff --git a/docs/meshtastic/index.html b/docs/meshtastic/index.html index 9715d8b..964b829 100644 --- a/docs/meshtastic/index.html +++ b/docs/meshtastic/index.html @@ -210,6 +210,21 @@ def waitForSet(target, sleep=.1, maxsecs=20, attrs=()): return False +def pskToString(psk: bytes): + """Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string""" + if len(psk) == 0: + return "unencrypted" + elif len(psk) == 1: + b = psk[0] + if b == 0: + return "unencrypted" + elif b == 1: + return "default" + else: + return f"simple{b - 1}" + else: + return "secret" + class Node: """A model of a (local or remote) node in the mesh @@ -223,15 +238,24 @@ class Node: self.radioConfig = None self.channels = None - def showInfo(self): - """Show human readable description of our node""" - print(self.radioConfig) + def showChannels(self): + """Show human readable description of our channels""" print("Channels:") for c in self.channels: if c.role != channel_pb2.Channel.Role.DISABLED: - cStr = MessageToJson(c.settings).replace("\n", "") - print(f" {channel_pb2.Channel.Role.Name(c.role)} {cStr}") - print(f"\nChannel URL {self.channelURL}") + cStr = stripnl(MessageToJson(c.settings)) + print(f" {channel_pb2.Channel.Role.Name(c.role)} psk={pskToString(c.settings.psk)} {cStr}") + publicURL = self.getURL(includeAll = False) + adminURL = self.getURL(includeAll = True) + print(f"\nPrimary channel URL: {publicURL}") + if adminURL != publicURL: + print(f"Complete URL (includes all channels): {adminURL}") + + def showInfo(self): + """Show human readable description of our node""" + print(f"Preferences: {stripnl(MessageToJson(self.radioConfig.preferences))}\n") + self.showChannels() + def requestConfig(self): """ @@ -341,14 +365,13 @@ class Node: return self._sendAdmin(p) - @property - def channelURL(self): + def getURL(self, includeAll: bool = True): """The sharable URL that describes the current channel """ # Only keep the primary/secondary channels, assume primary is first channelSet = apponly_pb2.ChannelSet() for c in self.channels: - if c.role != channel_pb2.Channel.Role.DISABLED: + if c.role == channel_pb2.Channel.Role.PRIMARY or (includeAll and c.role == channel_pb2.Channel.Role.SECONDARY): channelSet.settings.append(c.settings) bytes = channelSet.SerializeToString() s = base64.urlsafe_b64encode(bytes).decode('ascii') @@ -526,10 +549,10 @@ class MeshInterface: def showInfo(self): """Show human readable summary about this object""" - print(self.myInfo) - print("Nodes in mesh:") + print(f"My info: {stripnl(MessageToJson(self.myInfo))}") + print("\nNodes in mesh:") for n in self.nodes.values(): - print(stripnl(n)) + print(" " + stripnl(n)) def getNode(self, nodeId): """Return a node object which contains device settings and channel info""" @@ -1377,6 +1400,31 @@ protocols = {

Functions

+
+def pskToString(psk: bytes) +
+
+

Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string

+
+ +Expand source code + +
def pskToString(psk: bytes):
+    """Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string"""
+    if len(psk) == 0:
+        return "unencrypted"
+    elif len(psk) == 1: 
+        b = psk[0]
+        if b == 0:
+            return "unencrypted"
+        elif b == 1:
+            return "default"
+        else:
+            return f"simple{b - 1}"
+    else:
+        return "secret"
+
+
def waitForSet(target, sleep=0.1, maxsecs=20, attrs=())
@@ -1581,10 +1629,10 @@ noProto – If True, don't try to run our protocol on the link - just be a d def showInfo(self): """Show human readable summary about this object""" - print(self.myInfo) - print("Nodes in mesh:") + print(f"My info: {stripnl(MessageToJson(self.myInfo))}") + print("\nNodes in mesh:") for n in self.nodes.values(): - print(stripnl(n)) + print(" " + stripnl(n)) def getNode(self, nodeId): """Return a node object which contains device settings and channel info""" @@ -2277,10 +2325,10 @@ wantResponse – True if you want the service on the other side to send an a
def showInfo(self):
     """Show human readable summary about this object"""
-    print(self.myInfo)
-    print("Nodes in mesh:")
+    print(f"My info: {stripnl(MessageToJson(self.myInfo))}")
+    print("\nNodes in mesh:")
     for n in self.nodes.values():
-        print(stripnl(n))
+ print(" " + stripnl(n))
@@ -2326,15 +2374,24 @@ wantResponse – True if you want the service on the other side to send an a self.radioConfig = None self.channels = None - def showInfo(self): - """Show human readable description of our node""" - print(self.radioConfig) + def showChannels(self): + """Show human readable description of our channels""" print("Channels:") for c in self.channels: if c.role != channel_pb2.Channel.Role.DISABLED: - cStr = MessageToJson(c.settings).replace("\n", "") - print(f" {channel_pb2.Channel.Role.Name(c.role)} {cStr}") - print(f"\nChannel URL {self.channelURL}") + cStr = stripnl(MessageToJson(c.settings)) + print(f" {channel_pb2.Channel.Role.Name(c.role)} psk={pskToString(c.settings.psk)} {cStr}") + publicURL = self.getURL(includeAll = False) + adminURL = self.getURL(includeAll = True) + print(f"\nPrimary channel URL: {publicURL}") + if adminURL != publicURL: + print(f"Complete URL (includes all channels): {adminURL}") + + def showInfo(self): + """Show human readable description of our node""" + print(f"Preferences: {stripnl(MessageToJson(self.radioConfig.preferences))}\n") + self.showChannels() + def requestConfig(self): """ @@ -2444,14 +2501,13 @@ wantResponse – True if you want the service on the other side to send an a return self._sendAdmin(p) - @property - def channelURL(self): + def getURL(self, includeAll: bool = True): """The sharable URL that describes the current channel """ # Only keep the primary/secondary channels, assume primary is first channelSet = apponly_pb2.ChannelSet() for c in self.channels: - if c.role != channel_pb2.Channel.Role.DISABLED: + if c.role == channel_pb2.Channel.Role.PRIMARY or (includeAll and c.role == channel_pb2.Channel.Role.SECONDARY): channelSet.settings.append(c.settings) bytes = channelSet.SerializeToString() s = base64.urlsafe_b64encode(bytes).decode('ascii') @@ -2587,30 +2643,6 @@ wantResponse – True if you want the service on the other side to send an a onResponse=onResponse, channelIndex=adminIndex) -

Instance variables

-
-
var channelURL
-
-

The sharable URL that describes the current channel

-
- -Expand source code - -
@property
-def channelURL(self):
-    """The sharable URL that describes the current channel
-    """
-    # Only keep the primary/secondary channels, assume primary is first
-    channelSet = apponly_pb2.ChannelSet()
-    for c in self.channels:
-        if c.role != channel_pb2.Channel.Role.DISABLED:
-            channelSet.settings.append(c.settings)
-    bytes = channelSet.SerializeToString()
-    s = base64.urlsafe_b64encode(bytes).decode('ascii')
-    return f"https://www.meshtastic.org/d/#{s}".replace("=", "")
-
-
-

Methods

@@ -2698,6 +2730,28 @@ def channelURL(self): return None +
+def getURL(self, includeAll: bool = True) +
+
+

The sharable URL that describes the current channel

+
+ +Expand source code + +
def getURL(self, includeAll: bool = True):
+    """The sharable URL that describes the current channel
+    """
+    # Only keep the primary/secondary channels, assume primary is first
+    channelSet = apponly_pb2.ChannelSet()
+    for c in self.channels:
+        if c.role == channel_pb2.Channel.Role.PRIMARY or (includeAll and c.role == channel_pb2.Channel.Role.SECONDARY):
+            channelSet.settings.append(c.settings)
+    bytes = channelSet.SerializeToString()
+    s = base64.urlsafe_b64encode(bytes).decode('ascii')
+    return f"https://www.meshtastic.org/d/#{s}".replace("=", "")
+
+
def requestConfig(self)
@@ -2799,6 +2853,29 @@ def channelURL(self): i = i + 1 +
+def showChannels(self) +
+
+

Show human readable description of our channels

+
+ +Expand source code + +
def showChannels(self):
+    """Show human readable description of our channels"""
+    print("Channels:")
+    for c in self.channels:
+        if c.role != channel_pb2.Channel.Role.DISABLED:
+            cStr = stripnl(MessageToJson(c.settings))
+            print(f"  {channel_pb2.Channel.Role.Name(c.role)} psk={pskToString(c.settings.psk)} {cStr}")
+    publicURL = self.getURL(includeAll = False)
+    adminURL = self.getURL(includeAll = True)
+    print(f"\nPrimary channel URL: {publicURL}")
+    if adminURL != publicURL:
+        print(f"Complete URL (includes all channels): {adminURL}")
+
+
def showInfo(self)
@@ -2810,13 +2887,8 @@ def channelURL(self):
def showInfo(self):
     """Show human readable description of our node"""
-    print(self.radioConfig)
-    print("Channels:")
-    for c in self.channels:
-        if c.role != channel_pb2.Channel.Role.DISABLED:
-            cStr = MessageToJson(c.settings).replace("\n", "")
-            print(f"  {channel_pb2.Channel.Role.Name(c.role)} {cStr}")
-    print(f"\nChannel URL {self.channelURL}")
+ print(f"Preferences: {stripnl(MessageToJson(self.radioConfig.preferences))}\n") + self.showChannels()
@@ -3332,6 +3404,7 @@ hostname {string} – Hostname/IP address of the device to connect to

  • Functions

  • @@ -3369,14 +3442,15 @@ hostname {string} – Hostname/IP address of the device to connect to

    Node

    -

    remove newlines from a string

    +

    remove newlines from a string (and remove extra whitespace)

    Expand source code
    def stripnl(s):
    -    """remove newlines from a string"""
    -    return str(s).replace("\n", " ")
    + """remove newlines from a string (and remove extra whitespace)""" + s = str(s).replace("\n", " ") + return ' '.join(s.split())
    diff --git a/setup.py b/setup.py index 27e16fc..2d12526 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.12", + version="1.2.13", description="Python API & client shell for talking to Meshtastic devices", long_description=long_description, long_description_content_type="text/markdown",