This commit is contained in:
Kevin Hester
2021-03-05 11:50:30 +08:00
parent 54e9599981
commit fcb4d3ec5b
3 changed files with 81 additions and 27 deletions

View File

@@ -155,7 +155,7 @@ import base64
import platform
import socket
from . import mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2, environmental_measurement_pb2, remote_hardware_pb2, channel_pb2, radioconfig_pb2, util
from .util import fixme, catchAndIgnore
from .util import fixme, catchAndIgnore, stripnl
from pubsub import pub
from dotmap import DotMap
from typing import *
@@ -275,7 +275,7 @@ 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 getattr(data, "SerializeToString", None):
logging.debug(f"Serializing protobuf as data: {data}")
logging.debug(f"Serializing protobuf as data: {stripnl(data)}")
data = data.SerializeToString()
if len(data) > mesh_pb2.Constants.DATA_PAYLOAD_LEN:
@@ -357,6 +357,7 @@ class MeshInterface:
meshPacket.id = self._generatePacketId()
toRadio.packet.CopyFrom(meshPacket)
#logging.debug(f"Sending packet: {stripnl(meshPacket)}")
self._sendToRadio(toRadio)
return meshPacket
@@ -532,7 +533,7 @@ class MeshInterface:
logging.warn(
f"Not sending packet because protocol use is disabled by noProto")
else:
logging.debug(f"Sending toRadio: {toRadio}")
#logging.debug(f"Sending toRadio: {stripnl(toRadio)}")
self._sendToRadioImpl(toRadio)
def _sendToRadioImpl(self, toRadio):
@@ -575,16 +576,21 @@ class MeshInterface:
"""A closure to handle the response packet"""
c = p["decoded"]["admin"]["raw"].get_channel_response
self.partialChannels.append(c)
logging.debug(f"Received channel {c}")
# for stress testing, download all channels
# if channelNum >= self.myInfo.max_channels - 1:
if c.role == channel_pb2.Channel.Role.DISABLED or channelNum >= self.myInfo.max_channels - 1:
# Once we see a response that has NO settings, assume we are at the end of channels and stop fetching
logging.debug(f"Received channel {stripnl(c)}")
index = c.index
# for stress testing, we can always download all channels
fastChannelDownload = True
# 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
if quitEarly or index >= self.myInfo.max_channels - 1:
self.channels = self.partialChannels
# FIXME, the following should only be called after we have settings and channels
self._connected() # Tell everone else we are ready to go
else:
self._requestChannel(channelNum + 1)
self._requestChannel(index + 1)
return self.sendData(p, self.myInfo.my_node_num,
portNum=portnums_pb2.PortNum.ADMIN_APP,
@@ -600,9 +606,9 @@ class MeshInterface:
fromRadio = mesh_pb2.FromRadio()
fromRadio.ParseFromString(fromRadioBytes)
asDict = google.protobuf.json_format.MessageToDict(fromRadio)
logging.debug(f"Received: {asDict}")
if fromRadio.HasField("my_info"):
self.myInfo = fromRadio.my_info
logging.debug(f"Received myinfo: {stripnl(fromRadio.my_info)}")
failmsg = None
# Check for app too old
@@ -624,6 +630,9 @@ class MeshInterface:
self._fixupPosition(node["position"])
except:
logging.debug("Node without position")
logging.debug(f"Received nodeinfo: {node}")
self.nodesByNum[node["num"]] = node
if "user" in node: # Some nodes might not have user/ids assigned yet
self.nodes[node["user"]["id"]] = node
@@ -700,6 +709,14 @@ class MeshInterface:
# want the raw protobuf, so we provide it in "raw"
asDict["raw"] = meshPacket
# from might be missing if the nodenum was zero.
if not "from" in asDict:
asDict["from"] = 0
logging.error(f"Device returned a packet we sent, ignoring: {stripnl(asDict)}")
return
if not "to" in asDict:
asDict["to"] = 0
# /add fromId and toId fields based on the node ID
asDict["fromId"] = self._nodeNumToId(asDict["from"])
asDict["toId"] = self._nodeNumToId(asDict["to"])
@@ -758,7 +775,7 @@ class MeshInterface:
if handler is not None:
handler.callback(asDict)
logging.debug(f"Publishing topic {topic}")
logging.debug(f"Publishing {topic}: packet={stripnl(asDict)} ")
catchAndIgnore(f"publishing {topic}", lambda: pub.sendMessage(
topic, packet=asDict, interface=self))
@@ -791,7 +808,7 @@ class BLEInterface(MeshInterface):
def _sendToRadioImpl(self, toRadio):
"""Send a ToRadio protobuf to the device"""
logging.debug(f"Sending: {toRadio}")
# logging.debug(f"Sending: {stripnl(toRadio)}")
b = toRadio.SerializeToString()
self.device.char_write(TORADIO_UUID, b)
@@ -871,7 +888,7 @@ class StreamInterface(MeshInterface):
def _sendToRadioImpl(self, toRadio):
"""Send a ToRadio protobuf to the device"""
logging.debug(f"Sending: {toRadio}")
logging.debug(f"Sending: {stripnl(toRadio)}")
b = toRadio.SerializeToString()
bufLen = len(b)
# We convert into a string, because the TCP code doesn't work with byte arrays
@@ -1194,7 +1211,7 @@ noProto – If True, don't try to run our protocol on the link - just be a d
def _sendToRadioImpl(self, toRadio):
"""Send a ToRadio protobuf to the device"""
logging.debug(f"Sending: {toRadio}")
# logging.debug(f"Sending: {stripnl(toRadio)}")
b = toRadio.SerializeToString()
self.device.char_write(TORADIO_UUID, b)
@@ -1381,7 +1398,7 @@ noProto – If True, don't try to run our protocol on the link - just be a d
Returns the sent packet. The id field will be populated in this packet and can be used to track future message acks/naks.
"""
if getattr(data, "SerializeToString", None):
logging.debug(f"Serializing protobuf as data: {data}")
logging.debug(f"Serializing protobuf as data: {stripnl(data)}")
data = data.SerializeToString()
if len(data) > mesh_pb2.Constants.DATA_PAYLOAD_LEN:
@@ -1463,6 +1480,7 @@ noProto – If True, don't try to run our protocol on the link - just be a d
meshPacket.id = self._generatePacketId()
toRadio.packet.CopyFrom(meshPacket)
#logging.debug(f"Sending packet: {stripnl(meshPacket)}")
self._sendToRadio(toRadio)
return meshPacket
@@ -1638,7 +1656,7 @@ noProto – If True, don't try to run our protocol on the link - just be a d
logging.warn(
f"Not sending packet because protocol use is disabled by noProto")
else:
logging.debug(f"Sending toRadio: {toRadio}")
#logging.debug(f"Sending toRadio: {stripnl(toRadio)}")
self._sendToRadioImpl(toRadio)
def _sendToRadioImpl(self, toRadio):
@@ -1681,16 +1699,21 @@ noProto – If True, don't try to run our protocol on the link - just be a d
"""A closure to handle the response packet"""
c = p["decoded"]["admin"]["raw"].get_channel_response
self.partialChannels.append(c)
logging.debug(f"Received channel {c}")
# for stress testing, download all channels
# if channelNum >= self.myInfo.max_channels - 1:
if c.role == channel_pb2.Channel.Role.DISABLED or channelNum >= self.myInfo.max_channels - 1:
# Once we see a response that has NO settings, assume we are at the end of channels and stop fetching
logging.debug(f"Received channel {stripnl(c)}")
index = c.index
# for stress testing, we can always download all channels
fastChannelDownload = True
# 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
if quitEarly or index >= self.myInfo.max_channels - 1:
self.channels = self.partialChannels
# FIXME, the following should only be called after we have settings and channels
self._connected() # Tell everone else we are ready to go
else:
self._requestChannel(channelNum + 1)
self._requestChannel(index + 1)
return self.sendData(p, self.myInfo.my_node_num,
portNum=portnums_pb2.PortNum.ADMIN_APP,
@@ -1706,9 +1729,9 @@ noProto – If True, don't try to run our protocol on the link - just be a d
fromRadio = mesh_pb2.FromRadio()
fromRadio.ParseFromString(fromRadioBytes)
asDict = google.protobuf.json_format.MessageToDict(fromRadio)
logging.debug(f"Received: {asDict}")
if fromRadio.HasField("my_info"):
self.myInfo = fromRadio.my_info
logging.debug(f"Received myinfo: {stripnl(fromRadio.my_info)}")
failmsg = None
# Check for app too old
@@ -1730,6 +1753,9 @@ noProto – If True, don't try to run our protocol on the link - just be a d
self._fixupPosition(node["position"])
except:
logging.debug("Node without position")
logging.debug(f"Received nodeinfo: {node}")
self.nodesByNum[node["num"]] = node
if "user" in node: # Some nodes might not have user/ids assigned yet
self.nodes[node["user"]["id"]] = node
@@ -1806,6 +1832,14 @@ noProto – If True, don't try to run our protocol on the link - just be a d
# want the raw protobuf, so we provide it in "raw"
asDict["raw"] = meshPacket
# from might be missing if the nodenum was zero.
if not "from" in asDict:
asDict["from"] = 0
logging.error(f"Device returned a packet we sent, ignoring: {stripnl(asDict)}")
return
if not "to" in asDict:
asDict["to"] = 0
# /add fromId and toId fields based on the node ID
asDict["fromId"] = self._nodeNumToId(asDict["from"])
asDict["toId"] = self._nodeNumToId(asDict["to"])
@@ -1864,7 +1898,7 @@ noProto – If True, don't try to run our protocol on the link - just be a d
if handler is not None:
handler.callback(asDict)
logging.debug(f"Publishing topic {topic}")
logging.debug(f"Publishing {topic}: packet={stripnl(asDict)} ")
catchAndIgnore(f"publishing {topic}", lambda: pub.sendMessage(
topic, packet=asDict, interface=self))</code></pre>
</details>
@@ -1996,7 +2030,7 @@ onResponse &ndash; A closure of the form funct(packet), that will be called when
Returns the sent packet. The id field will be populated in this packet and can be used to track future message acks/naks.
&#34;&#34;&#34;
if getattr(data, &#34;SerializeToString&#34;, None):
logging.debug(f&#34;Serializing protobuf as data: {data}&#34;)
logging.debug(f&#34;Serializing protobuf as data: {stripnl(data)}&#34;)
data = data.SerializeToString()
if len(data) &gt; mesh_pb2.Constants.DATA_PAYLOAD_LEN:
@@ -2429,7 +2463,7 @@ debugOut {stream} &ndash; If a stream is provided, any debug serial output from
def _sendToRadioImpl(self, toRadio):
&#34;&#34;&#34;Send a ToRadio protobuf to the device&#34;&#34;&#34;
logging.debug(f&#34;Sending: {toRadio}&#34;)
logging.debug(f&#34;Sending: {stripnl(toRadio)}&#34;)
b = toRadio.SerializeToString()
bufLen = len(b)
# We convert into a string, because the TCP code doesn&#39;t work with byte arrays

View File

@@ -34,6 +34,11 @@ import serial.tools.list_ports
blacklistVids = dict.fromkeys([0x1366])
def stripnl(s):
&#34;&#34;&#34;remove newlines from a string&#34;&#34;&#34;
return str(s).replace(&#34;\n&#34;, &#34; &#34;)
def fixme(message):
raise Exception(f&#34;FIXME: {message}&#34;)
@@ -127,6 +132,20 @@ class dotdict(dict):
raise Exception(f&#34;FIXME: {message}&#34;)</code></pre>
</details>
</dd>
<dt id="meshtastic.util.stripnl"><code class="name flex">
<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>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def stripnl(s):
&#34;&#34;&#34;remove newlines from a string&#34;&#34;&#34;
return str(s).replace(&#34;\n&#34;, &#34; &#34;)</code></pre>
</details>
</dd>
</dl>
</section>
<section>
@@ -172,6 +191,7 @@ class dotdict(dict):
<li><code><a title="meshtastic.util.catchAndIgnore" href="#meshtastic.util.catchAndIgnore">catchAndIgnore</a></code></li>
<li><code><a title="meshtastic.util.findPorts" href="#meshtastic.util.findPorts">findPorts</a></code></li>
<li><code><a title="meshtastic.util.fixme" href="#meshtastic.util.fixme">fixme</a></code></li>
<li><code><a title="meshtastic.util.stripnl" href="#meshtastic.util.stripnl">stripnl</a></code></li>
</ul>
</li>
<li><h3><a href="#header-classes">Classes</a></h3>

View File

@@ -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.3",
version="1.2.4",
description="Python API & client shell for talking to Meshtastic devices",
long_description=long_description,
long_description_content_type="text/markdown",