This commit is contained in:
geeksville
2020-08-11 18:19:54 -07:00
parent 0c9c8bca57
commit 848b52a437
3 changed files with 101 additions and 22 deletions

View File

@@ -206,7 +206,7 @@ class MeshInterface:
meshPacket.decoded.position.altitude = int(altitude)
if timeSec == 0:
timeSec = time.time() # returns unix timestamp in seconds
timeSec = time.time() # returns unix timestamp in seconds
meshPacket.decoded.position.time = int(timeSec)
meshPacket.decoded.want_response = wantResponse
@@ -377,6 +377,12 @@ class MeshInterface:
if meshPacket.decoded.HasField("data"):
topic = "meshtastic.receive.data"
# OPAQUE is the default protobuf typ value, and therefore if not set it will not be populated at all
# to make API usage easier, set it to prevent confusion
if not "typ" in asDict["decoded"]["data"]:
asDict["decoded"]["data"]["typ"] = "OPAQUE"
# For text messages, we go ahead and decode the text to ascii for our users
if asDict["decoded"]["data"]["typ"] == "CLEAR_TEXT":
asDict["decoded"]["data"]["text"] = meshPacket.decoded.data.payload.decode(
@@ -432,7 +438,7 @@ class BLEInterface(MeshInterface):
class StreamInterface(MeshInterface):
"""Interface class for meshtastic devices over a stream link (serial, TCP, etc)"""
def __init__(self, devPath=None, debugOut=None, noProto=False):
def __init__(self, devPath=None, debugOut=None, noProto=False, connectNow=True):
"""Constructor, opens a connection to a specified serial port, or if unspecified try to
find one Meshtastic device by probing
@@ -463,14 +469,24 @@ class StreamInterface(MeshInterface):
devPath, 921600, exclusive=True, timeout=0.5)
self._rxThread = threading.Thread(target=self.__reader, args=())
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
# Start the reader thread after superclass constructor completes init
if connectNow:
self.connect()
def connect(self):
"""Connect to our radio
Normally this is called automatically by the constructor, but if you passed in connectNow=False you can manually
start the reading thread later.
"""
# Send some bogus UART characters to force a sleeping device to wake
self.stream.write(bytes([START1, START1, START1, START1]))
self.stream.flush()
time.sleep(0.1) # wait 100ms to give device time to start running
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
# Start the reader thread after superclass constructor completes init
self._rxThread.start()
def _sendToRadio(self, toRadio):
@@ -730,7 +746,7 @@ debugOut</p>
meshPacket.decoded.position.altitude = int(altitude)
if timeSec == 0:
timeSec = time.time() # returns unix timestamp in seconds
timeSec = time.time() # returns unix timestamp in seconds
meshPacket.decoded.position.time = int(timeSec)
meshPacket.decoded.want_response = wantResponse
@@ -901,6 +917,12 @@ debugOut</p>
if meshPacket.decoded.HasField(&#34;data&#34;):
topic = &#34;meshtastic.receive.data&#34;
# OPAQUE is the default protobuf typ value, and therefore if not set it will not be populated at all
# to make API usage easier, set it to prevent confusion
if not &#34;typ&#34; in asDict[&#34;decoded&#34;][&#34;data&#34;]:
asDict[&#34;decoded&#34;][&#34;data&#34;][&#34;typ&#34;] = &#34;OPAQUE&#34;
# For text messages, we go ahead and decode the text to ascii for our users
if asDict[&#34;decoded&#34;][&#34;data&#34;][&#34;typ&#34;] == &#34;CLEAR_TEXT&#34;:
asDict[&#34;decoded&#34;][&#34;data&#34;][&#34;text&#34;] = meshPacket.decoded.data.payload.decode(
@@ -994,7 +1016,7 @@ the local position.</p>
meshPacket.decoded.position.altitude = int(altitude)
if timeSec == 0:
timeSec = time.time() # returns unix timestamp in seconds
timeSec = time.time() # returns unix timestamp in seconds
meshPacket.decoded.position.time = int(timeSec)
meshPacket.decoded.want_response = wantResponse
@@ -1050,7 +1072,7 @@ destinationId {nodeId or nodeNum} &ndash; where to send this message (default: {
</dd>
<dt id="meshtastic.StreamInterface"><code class="flex name class">
<span>class <span class="ident">StreamInterface</span></span>
<span>(</span><span>devPath=None, debugOut=None, noProto=False)</span>
<span>(</span><span>devPath=None, debugOut=None, noProto=False, connectNow=True)</span>
</code></dt>
<dd>
<div class="desc"><p>Interface class for meshtastic devices over a stream link (serial, TCP, etc)</p>
@@ -1073,7 +1095,7 @@ debugOut {stream} &ndash; If a stream is provided, any debug serial output from
<pre><code class="python">class StreamInterface(MeshInterface):
&#34;&#34;&#34;Interface class for meshtastic devices over a stream link (serial, TCP, etc)&#34;&#34;&#34;
def __init__(self, devPath=None, debugOut=None, noProto=False):
def __init__(self, devPath=None, debugOut=None, noProto=False, connectNow=True):
&#34;&#34;&#34;Constructor, opens a connection to a specified serial port, or if unspecified try to
find one Meshtastic device by probing
@@ -1104,14 +1126,24 @@ debugOut {stream} &ndash; If a stream is provided, any debug serial output from
devPath, 921600, exclusive=True, timeout=0.5)
self._rxThread = threading.Thread(target=self.__reader, args=())
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
# Start the reader thread after superclass constructor completes init
if connectNow:
self.connect()
def connect(self):
&#34;&#34;&#34;Connect to our radio
Normally this is called automatically by the constructor, but if you passed in connectNow=False you can manually
start the reading thread later.
&#34;&#34;&#34;
# Send some bogus UART characters to force a sleeping device to wake
self.stream.write(bytes([START1, START1, START1, START1]))
self.stream.flush()
time.sleep(0.1) # wait 100ms to give device time to start running
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
# Start the reader thread after superclass constructor completes init
self._rxThread.start()
def _sendToRadio(self, toRadio):
@@ -1205,6 +1237,32 @@ debugOut {stream} &ndash; If a stream is provided, any debug serial output from
self._rxThread.join() # wait for it to exit</code></pre>
</details>
</dd>
<dt id="meshtastic.StreamInterface.connect"><code class="name flex">
<span>def <span class="ident">connect</span></span>(<span>self)</span>
</code></dt>
<dd>
<div class="desc"><p>Connect to our radio</p>
<p>Normally this is called automatically by the constructor, but if you passed in connectNow=False you can manually
start the reading thread later.</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def connect(self):
&#34;&#34;&#34;Connect to our radio
Normally this is called automatically by the constructor, but if you passed in connectNow=False you can manually
start the reading thread later.
&#34;&#34;&#34;
# Send some bogus UART characters to force a sleeping device to wake
self.stream.write(bytes([START1, START1, START1, START1]))
self.stream.flush()
time.sleep(0.1) # wait 100ms to give device time to start running
self._rxThread.start()</code></pre>
</details>
</dd>
</dl>
<h3>Inherited members</h3>
<ul class="hlist">
@@ -1267,6 +1325,7 @@ debugOut {stream} &ndash; If a stream is provided, any debug serial output from
<h4><code><a title="meshtastic.StreamInterface" href="#meshtastic.StreamInterface">StreamInterface</a></code></h4>
<ul class="">
<li><code><a title="meshtastic.StreamInterface.close" href="#meshtastic.StreamInterface.close">close</a></code></li>
<li><code><a title="meshtastic.StreamInterface.connect" href="#meshtastic.StreamInterface.connect">connect</a></code></li>
</ul>
</li>
</ul>

View File

@@ -65,7 +65,7 @@ def subscribe():
pub.subscribe(onNode, &#34;meshtastic.node&#34;)
def testSend(fromInterface, toInterface, isBroadcast=False):
def testSend(fromInterface, toInterface, isBroadcast=False, asBinary=False):
&#34;&#34;&#34;
Sends one test packet between two nodes and then returns success or failure
@@ -86,7 +86,12 @@ def testSend(fromInterface, toInterface, isBroadcast=False):
toNode = toInterface.myInfo.my_node_num
logging.info(f&#34;Sending test packet from {fromNode} to {toNode}&#34;)
fromInterface.sendText(f&#34;Test {testNumber}&#34;, toNode, wantAck=True)
wantAck = True
if not asBinary:
fromInterface.sendText(f&#34;Test {testNumber}&#34;, toNode, wantAck=wantAck)
else:
fromInterface.sendData((f&#34;Binary {testNumber}&#34;).encode(
&#34;utf-8&#34;), toNode, wantAck=wantAck)
time.sleep(45)
return (len(receivedPackets) &gt;= 1)
@@ -99,7 +104,8 @@ def testThread(numTests=50):
global testNumber
testNumber = testNumber + 1
isBroadcast = True
success = testSend(interfaces[0], interfaces[1], isBroadcast)
success = testSend(
interfaces[0], interfaces[1], isBroadcast, asBinary=(i % 2 == 0))
if not success:
numFail = numFail + 1
logging.error(
@@ -121,6 +127,7 @@ def onConnection(topic=pub.AUTO_TOPIC):
print(f&#34;Connection changed: {topic.getName()}&#34;)
global testsRunning
global interfaces
if (all(iface.isConnected for iface in interfaces) and not testsRunning):
testsRunning = True
t = threading.Thread(target=testThread, args=())
@@ -148,7 +155,10 @@ def testAll():
pub.subscribe(onReceive, &#34;meshtastic.receive&#34;)
global interfaces
interfaces = list(map(lambda port: StreamInterface(
port, debugOut=openDebugLog(port)), ports))
port, debugOut=openDebugLog(port), connectNow=False), ports))
for i in interfaces:
i.connect()
logging.info(&#34;Ports opened, waiting for device to complete connection&#34;)</code></pre>
</details>
</section>
@@ -180,6 +190,7 @@ def testAll():
print(f&#34;Connection changed: {topic.getName()}&#34;)
global testsRunning
global interfaces
if (all(iface.isConnected for iface in interfaces) and not testsRunning):
testsRunning = True
t = threading.Thread(target=testThread, args=())
@@ -278,12 +289,15 @@ def testAll():
pub.subscribe(onReceive, &#34;meshtastic.receive&#34;)
global interfaces
interfaces = list(map(lambda port: StreamInterface(
port, debugOut=openDebugLog(port)), ports))
port, debugOut=openDebugLog(port), connectNow=False), ports))
for i in interfaces:
i.connect()
logging.info(&#34;Ports opened, waiting for device to complete connection&#34;)</code></pre>
</details>
</dd>
<dt id="meshtastic.test.testSend"><code class="name flex">
<span>def <span class="ident">testSend</span></span>(<span>fromInterface, toInterface, isBroadcast=False)</span>
<span>def <span class="ident">testSend</span></span>(<span>fromInterface, toInterface, isBroadcast=False, asBinary=False)</span>
</code></dt>
<dd>
<div class="desc"><p>Sends one test packet between two nodes and then returns success or failure</p>
@@ -299,7 +313,7 @@ toInterface {[type]} &ndash; [description]</p>
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def testSend(fromInterface, toInterface, isBroadcast=False):
<pre><code class="python">def testSend(fromInterface, toInterface, isBroadcast=False, asBinary=False):
&#34;&#34;&#34;
Sends one test packet between two nodes and then returns success or failure
@@ -320,7 +334,12 @@ toInterface {[type]} &ndash; [description]</p>
toNode = toInterface.myInfo.my_node_num
logging.info(f&#34;Sending test packet from {fromNode} to {toNode}&#34;)
fromInterface.sendText(f&#34;Test {testNumber}&#34;, toNode, wantAck=True)
wantAck = True
if not asBinary:
fromInterface.sendText(f&#34;Test {testNumber}&#34;, toNode, wantAck=wantAck)
else:
fromInterface.sendData((f&#34;Binary {testNumber}&#34;).encode(
&#34;utf-8&#34;), toNode, wantAck=wantAck)
time.sleep(45)
return (len(receivedPackets) &gt;= 1)</code></pre>
</details>
@@ -342,7 +361,8 @@ toInterface {[type]} &ndash; [description]</p>
global testNumber
testNumber = testNumber + 1
isBroadcast = True
success = testSend(interfaces[0], interfaces[1], isBroadcast)
success = testSend(
interfaces[0], interfaces[1], isBroadcast, asBinary=(i % 2 == 0))
if not success:
numFail = numFail + 1
logging.error(

View File

@@ -10,7 +10,7 @@ with open("README.md", "r") as fh:
# This call to setup() does all the work
setup(
name="meshtastic",
version="0.9.1",
version="0.9.2",
description="Python API & client shell for talking to Meshtastic devices",
long_description=long_description,
long_description_content_type="text/markdown",