mirror of
https://github.com/meshtastic/python.git
synced 2025-12-27 01:47:50 -05:00
1.2.13
This commit is contained in:
@@ -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 = {
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.pskToString"><code class="name flex">
|
||||
<span>def <span class="ident">pskToString</span></span>(<span>psk: bytes)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">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"</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.waitForSet"><code class="name flex">
|
||||
<span>def <span class="ident">waitForSet</span></span>(<span>target, sleep=0.1, maxsecs=20, attrs=())</span>
|
||||
</code></dt>
|
||||
@@ -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
|
||||
</summary>
|
||||
<pre><code class="python">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))</code></pre>
|
||||
print(" " + stripnl(n))</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.MeshInterface.waitForConfig"><code class="name flex">
|
||||
@@ -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)</code></pre>
|
||||
</details>
|
||||
<h3>Instance variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.Node.channelURL"><code class="name">var <span class="ident">channelURL</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>The sharable URL that describes the current channel</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@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("=", "")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.Node.deleteChannel"><code class="name flex">
|
||||
@@ -2698,6 +2730,28 @@ def channelURL(self):
|
||||
return None</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.Node.getURL"><code class="name flex">
|
||||
<span>def <span class="ident">getURL</span></span>(<span>self, includeAll: bool = True)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>The sharable URL that describes the current channel</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">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("=", "")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.Node.requestConfig"><code class="name flex">
|
||||
<span>def <span class="ident">requestConfig</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
@@ -2799,6 +2853,29 @@ def channelURL(self):
|
||||
i = i + 1</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.Node.showChannels"><code class="name flex">
|
||||
<span>def <span class="ident">showChannels</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Show human readable description of our channels</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">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}")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.Node.showInfo"><code class="name flex">
|
||||
<span>def <span class="ident">showInfo</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
@@ -2810,13 +2887,8 @@ def channelURL(self):
|
||||
</summary>
|
||||
<pre><code class="python">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}")</code></pre>
|
||||
print(f"Preferences: {stripnl(MessageToJson(self.radioConfig.preferences))}\n")
|
||||
self.showChannels()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.Node.waitForConfig"><code class="name flex">
|
||||
@@ -3332,6 +3404,7 @@ hostname {string} – Hostname/IP address of the device to connect to</p></d
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.pskToString" href="#meshtastic.pskToString">pskToString</a></code></li>
|
||||
<li><code><a title="meshtastic.waitForSet" href="#meshtastic.waitForSet">waitForSet</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -3369,14 +3442,15 @@ hostname {string} – Hostname/IP address of the device to connect to</p></d
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.Node" href="#meshtastic.Node">Node</a></code></h4>
|
||||
<ul class="two-column">
|
||||
<li><code><a title="meshtastic.Node.channelURL" href="#meshtastic.Node.channelURL">channelURL</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.deleteChannel" href="#meshtastic.Node.deleteChannel">deleteChannel</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.exitSimulator" href="#meshtastic.Node.exitSimulator">exitSimulator</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.getChannelByName" href="#meshtastic.Node.getChannelByName">getChannelByName</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.getDisabledChannel" href="#meshtastic.Node.getDisabledChannel">getDisabledChannel</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.getURL" href="#meshtastic.Node.getURL">getURL</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.requestConfig" href="#meshtastic.Node.requestConfig">requestConfig</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.setOwner" href="#meshtastic.Node.setOwner">setOwner</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.setURL" href="#meshtastic.Node.setURL">setURL</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.showChannels" href="#meshtastic.Node.showChannels">showChannels</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.showInfo" href="#meshtastic.Node.showInfo">showInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.waitForConfig" href="#meshtastic.Node.waitForConfig">waitForConfig</a></code></li>
|
||||
<li><code><a title="meshtastic.Node.writeChannel" href="#meshtastic.Node.writeChannel">writeChannel</a></code></li>
|
||||
|
||||
@@ -37,8 +37,9 @@ blacklistVids = dict.fromkeys([0x1366])
|
||||
|
||||
|
||||
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())
|
||||
|
||||
|
||||
def fixme(message):
|
||||
@@ -160,14 +161,15 @@ class DeferredExecution():
|
||||
<span>def <span class="ident">stripnl</span></span>(<span>s)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>remove newlines from a string</p></div>
|
||||
<div class="desc"><p>remove newlines from a string (and remove extra whitespace)</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def stripnl(s):
|
||||
"""remove newlines from a string"""
|
||||
return str(s).replace("\n", " ")</code></pre>
|
||||
"""remove newlines from a string (and remove extra whitespace)"""
|
||||
s = str(s).replace("\n", " ")
|
||||
return ' '.join(s.split())</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
2
setup.py
2
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",
|
||||
|
||||
Reference in New Issue
Block a user