diff --git a/docs/meshtastic/ble.html b/docs/meshtastic/ble.html new file mode 100644 index 0000000..064bcc3 --- /dev/null +++ b/docs/meshtastic/ble.html @@ -0,0 +1,53 @@ + + + + + + +meshtastic.ble API documentation + + + + + + + + + +
+
+
+

Module meshtastic.ble

+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + + + \ No newline at end of file diff --git a/docs/meshtastic/index.html b/docs/meshtastic/index.html index e44f687..d7d8d53 100644 --- a/docs/meshtastic/index.html +++ b/docs/meshtastic/index.html @@ -20,7 +20,7 @@

Package meshtastic

-

an API for Meshtastic devices

+

an API for Meshtastic devices

Primary class: StreamInterface Install with pip: "pip3 install meshtastic" Source code on github

@@ -34,7 +34,7 @@ node in the mesh. This is a read-only datastructure.
  • myNodeInfo - Contains read-only information about the local radio device (software version, hardware version, etc)
  • -

    Published PubSub topics

    +

    Published PubSub topics

    We use a publish-subscribe model to communicate asynchronous events. Available topics:

    @@ -48,7 +48,7 @@ If you want to see all packets, simply subscribe to "meshtastic.receive".
  • meshtastic.receive.data(packet)
  • meshtastic.node.updated(node = NodeInfo) - published when a node in the DB changes (appears, location changed, username changed, etc…)
  • -

    Example Usage

    +

    Example Usage

    import meshtastic
     from pubsub import pub
     
    @@ -56,11 +56,13 @@ def onReceive(packet): # called when a packet arrives
         print(f"Received: {packet}")
     
     def onConnection(): # called when we (re)connect to the radio
    -    interface.sendText("hello mesh") # defaults to broadcast, specify a destination ID if you wish
    +    # defaults to broadcast, specify a destination ID if you wish
    +    interface.sendText("hello mesh")
     
     pub.subscribe(onReceive, "meshtastic.receive")
     pub.subscribe(onConnection, "meshtastic.connection.established")
    -interface = meshtastic.StreamInterface() # By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0
    +# By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0
    +interface = meshtastic.StreamInterface()
     
     
    @@ -68,7 +70,7 @@ interface = meshtastic.StreamInterface() # By default will try to find a meshtas Expand source code
    """
    -## an API for Meshtastic devices
    +# an API for Meshtastic devices
     
     Primary class: StreamInterface
     Install with pip: "[pip3 install meshtastic](https://pypi.org/project/meshtastic/)"
    @@ -76,26 +78,26 @@ Source code on [github](https://github.com/meshtastic/Meshtastic-python)
     
     properties of StreamInterface:
     
    -- radioConfig - Current radio configuration and device settings, if you write to this the new settings will be applied to 
    +- radioConfig - Current radio configuration and device settings, if you write to this the new settings will be applied to
     the device.
    -- nodes - The database of received nodes.  Includes always up-to-date location and username information for each 
    +- nodes - The database of received nodes.  Includes always up-to-date location and username information for each
     node in the mesh.  This is a read-only datastructure.
     - myNodeInfo - Contains read-only information about the local radio device (software version, hardware version, etc)
     
    -## Published PubSub topics
    +# Published PubSub topics
     
     We use a [publish-subscribe](https://pypubsub.readthedocs.io/en/v4.0.3/) model to communicate asynchronous events.  Available
     topics:
     
     - meshtastic.connection.established - published once we've successfully connected to the radio and downloaded the node DB
     - meshtastic.connection.lost - published once we've lost our link to the radio
    -- meshtastic.receive.position(packet) - delivers a received packet as a dictionary, if you only care about a particular 
    +- meshtastic.receive.position(packet) - delivers a received packet as a dictionary, if you only care about a particular
     type of packet, you should subscribe to the full topic name.  If you want to see all packets, simply subscribe to "meshtastic.receive".
     - meshtastic.receive.user(packet)
     - meshtastic.receive.data(packet)
     - meshtastic.node.updated(node = NodeInfo) - published when a node in the DB changes (appears, location changed, username changed, etc...)
     
    -## Example Usage
    +# Example Usage
     ```
     import meshtastic
     from pubsub import pub
    @@ -104,16 +106,19 @@ def onReceive(packet): # called when a packet arrives
         print(f"Received: {packet}")
     
     def onConnection(): # called when we (re)connect to the radio
    -    interface.sendText("hello mesh") # defaults to broadcast, specify a destination ID if you wish
    +    # defaults to broadcast, specify a destination ID if you wish
    +    interface.sendText("hello mesh")
     
     pub.subscribe(onReceive, "meshtastic.receive")
     pub.subscribe(onConnection, "meshtastic.connection.established")
    -interface = meshtastic.StreamInterface() # By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0
    +# By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0
    +interface = meshtastic.StreamInterface()
     
     ```
     
     """
     
    +import pygatt
     import google.protobuf.json_format
     import serial
     import threading
    @@ -153,7 +158,7 @@ class MeshInterface:
             self.isConnected = False
             self._startConfig()
     
    -    def sendText(self, text, destinationId=BROADCAST_ADDR):
    +    def sendText(self, text, destinationId=BROADCAST_ADDR, wantAck=False):
             """Send a utf8 string to some other node, if the node has a display it will also be shown on the device.
     
             Arguments:
    @@ -163,30 +168,30 @@ class MeshInterface:
                 destinationId {nodeId or nodeNum} -- where to send this message (default: {BROADCAST_ADDR})
             """
             self.sendData(text.encode("utf-8"), destinationId,
    -                      dataType=mesh_pb2.Data.CLEAR_TEXT)
    +                      dataType=mesh_pb2.Data.CLEAR_TEXT, wantAck=wantAck)
     
    -    def sendData(self, byteData, destinationId=BROADCAST_ADDR, dataType=mesh_pb2.Data.OPAQUE):
    +    def sendData(self, byteData, destinationId=BROADCAST_ADDR, dataType=mesh_pb2.Data.OPAQUE, wantAck=False):
             """Send a data packet to some other node"""
             meshPacket = mesh_pb2.MeshPacket()
    -        meshPacket.payload.data.payload = byteData
    -        meshPacket.payload.data.typ = dataType
    -        self.sendPacket(meshPacket, destinationId)
    +        meshPacket.decoded.data.payload = byteData
    +        meshPacket.decoded.data.typ = dataType
    +        self.sendPacket(meshPacket, destinationId, wantAck=wantAck)
     
    -    def sendPacket(self, meshPacket, destinationId=BROADCAST_ADDR):
    -        """Send a MeshPacket to the specified node (or if unspecified, broadcast). 
    +    def sendPacket(self, meshPacket, destinationId=BROADCAST_ADDR, wantAck=False):
    +        """Send a MeshPacket to the specified node (or if unspecified, broadcast).
             You probably don't want this - use sendData instead."""
             toRadio = mesh_pb2.ToRadio()
             # FIXME add support for non broadcast addresses
     
             if isinstance(destinationId, int):
                 nodeNum = destinationId
    -        elif nodeNum == BROADCAST_ADDR:
    +        elif destinationId == BROADCAST_ADDR:
                 nodeNum = 255
             else:
    -            raise Exception(
    -                "invalid destination addr, we don't yet support nodeid lookup")
    +            nodeNum = self.nodes[destinationId].num
     
             meshPacket.to = nodeNum
    +        meshPacket.want_ack = wantAck
             toRadio.packet.CopyFrom(meshPacket)
             self._sendToRadio(toRadio)
     
    @@ -232,16 +237,17 @@ class MeshInterface:
             Called by subclasses."""
             fromRadio = mesh_pb2.FromRadio()
             fromRadio.ParseFromString(fromRadioBytes)
    -        json = google.protobuf.json_format.MessageToJson(fromRadio)
    -        logging.debug(f"Received: {json}")
    +        asDict = google.protobuf.json_format.MessageToDict(fromRadio)
    +        logging.debug(f"Received: {asDict}")
             if fromRadio.HasField("my_info"):
                 self.myInfo = fromRadio.my_info
             elif fromRadio.HasField("radio"):
                 self.radioConfig = fromRadio.radio
             elif fromRadio.HasField("node_info"):
    -            node = fromRadio.node_info
    -            self._nodesByNum[node.num] = node
    -            self.nodes[node.user.id] = node
    +            node = asDict["nodeInfo"]
    +            self._fixupPosition(node["position"])
    +            self._nodesByNum[node["num"]] = node
    +            self.nodes[node["user"]["id"]] = node
             elif fromRadio.config_complete_id == MY_CONFIG_ID:
                 # we ignore the config_complete_id, it is unneeded for our stream API fromRadio.config_complete_id
                 self._connected()
    @@ -253,12 +259,31 @@ class MeshInterface:
             else:
                 logging.warn("Unexpected FromRadio payload")
     
    +    def _fixupPosition(self, position):
    +        """Convert integer lat/lon into floats
    +
    +        Arguments:
    +            position {Position dictionary} -- object ot fix up
    +        """
    +        if "latitudeI" in position:
    +            position["latitude"] = position["latitudeI"] * 1e-7
    +        if "longitudeI" in position:
    +            position["longitude"] = position["longitudeI"] * 1e-7
    +
         def _nodeNumToId(self, num):
    +        """Map a node node number to a node ID
    +
    +        Arguments:
    +            num {int} -- Node number
    +
    +        Returns:
    +            string -- Node ID
    +        """
             if num == BROADCAST_NUM:
                 return BROADCAST_ADDR
     
             try:
    -            return self._nodesByNum[num].user.id
    +            return self._nodesByNum[num]["user"]["id"]
             except:
                 logging.error("Node not found for fromId")
                 return None
    @@ -278,29 +303,80 @@ class MeshInterface:
             asDict["toId"] = self._nodeNumToId(asDict["to"])
     
             # We could provide our objects as DotMaps - which work with . notation or as dictionaries
    -        #asObj = DotMap(asDict)
    -        topic = None
    -        if meshPacket.payload.HasField("position"):
    +        # asObj = DotMap(asDict)
    +        topic = "meshtastic.receive"  # Generic unknown packet type
    +        if meshPacket.decoded.HasField("position"):
                 topic = "meshtastic.receive.position"
    -            # FIXME, update node DB as needed
    -        if meshPacket.payload.HasField("user"):
    +            p = asDict["decoded"]["position"]
    +            self._fixupPosition(p)
    +            # update node DB as needed
    +            self._nodesByNum[asDict["from"]]["position"] = p
    +
    +        if meshPacket.decoded.HasField("user"):
                 topic = "meshtastic.receive.user"
    -            # FIXME, update node DB as needed
    -        if meshPacket.payload.HasField("data"):
    +            u = asDict["decoded"]["user"]
    +            # update node DB as needed
    +            self._nodesByNum[asDict["from"]]["user"] = u
    +
    +        if meshPacket.decoded.HasField("data"):
                 topic = "meshtastic.receive.data"
                 # For text messages, we go ahead and decode the text to ascii for our users
    -            # if asObj.payload.data.typ == "CLEAR_TEXT":
    -            #    asObj.payload.data.text = asObj.payload.data.payload.decode(
    -            #        "utf-8")
    +            if asDict["decoded"]["data"]["typ"] == "CLEAR_TEXT":
    +                asDict["decoded"]["data"]["text"] = meshPacket.decoded.data.payload.decode(
    +                    "utf-8")
     
             pub.sendMessage(topic, packet=asDict, interface=self)
     
     
    +# Our standard BLE characteristics
    +TORADIO_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7"
    +FROMRADIO_UUID = "8ba2bcc2-ee02-4a55-a531-c525c5e454d5"
    +FROMNUM_UUID = "ed9da18c-a800-4f66-a670-aa7547e34453"
    +
    +
    +class BLEInterface(MeshInterface):
    +    """A not quite ready - FIXME - BLE interface to devices"""
    +
    +    def __init__(self, address, debugOut=None):
    +        self.address = address
    +        self.adapter = pygatt.GATTToolBackend()  # BGAPIBackend()
    +        self.adapter.start()
    +        logging.debug(f"Connecting to {self.address}")
    +        self.device = self.adapter.connect(address)
    +        logging.debug("Connected to device")
    +        # fromradio = self.device.char_read(FROMRADIO_UUID)
    +        MeshInterface.__init__(self, debugOut=debugOut)
    +
    +        self._readFromRadio()  # read the initial responses
    +
    +        def handle_data(handle, data):
    +            self._handleFromRadio(data)
    +
    +        self.device.subscribe(FROMNUM_UUID, callback=handle_data)
    +
    +    def _sendToRadio(self, toRadio):
    +        """Send a ToRadio protobuf to the device"""
    +        logging.debug(f"Sending: {toRadio}")
    +        b = toRadio.SerializeToString()
    +        self.device.char_write(TORADIO_UUID, b)
    +
    +    def close(self):
    +        self.adapter.stop()
    +
    +    def _readFromRadio(self):
    +        wasEmpty = False
    +        while not wasEmpty:
    +            b = self.device.char_read(FROMRADIO_UUID)
    +            wasEmpty = len(b) == 0
    +            if not wasEmpty:
    +                self._handleFromRadio(b)
    +
    +
     class StreamInterface(MeshInterface):
         """Interface class for meshtastic devices over a stream link (serial, TCP, etc)"""
     
         def __init__(self, devPath=None, debugOut=None):
    -        """Constructor, opens a connection to a specified serial port, or if unspecified try to 
    +        """Constructor, opens a connection to a specified serial port, or if unspecified try to
             find one Meshtastic device by probing
     
             Keyword Arguments:
    @@ -403,6 +479,10 @@ class StreamInterface(MeshInterface):
     

    Sub-modules

    +
    meshtastic.ble
    +
    +
    +
    meshtastic.mesh_pb2
    @@ -424,6 +504,86 @@ class StreamInterface(MeshInterface):

    Classes

    +
    +class BLEInterface +(address, debugOut=None) +
    +
    +

    A not quite ready - FIXME - BLE interface to devices

    +

    Constructor

    +
    + +Expand source code + +
    class BLEInterface(MeshInterface):
    +    """A not quite ready - FIXME - BLE interface to devices"""
    +
    +    def __init__(self, address, debugOut=None):
    +        self.address = address
    +        self.adapter = pygatt.GATTToolBackend()  # BGAPIBackend()
    +        self.adapter.start()
    +        logging.debug(f"Connecting to {self.address}")
    +        self.device = self.adapter.connect(address)
    +        logging.debug("Connected to device")
    +        # fromradio = self.device.char_read(FROMRADIO_UUID)
    +        MeshInterface.__init__(self, debugOut=debugOut)
    +
    +        self._readFromRadio()  # read the initial responses
    +
    +        def handle_data(handle, data):
    +            self._handleFromRadio(data)
    +
    +        self.device.subscribe(FROMNUM_UUID, callback=handle_data)
    +
    +    def _sendToRadio(self, toRadio):
    +        """Send a ToRadio protobuf to the device"""
    +        logging.debug(f"Sending: {toRadio}")
    +        b = toRadio.SerializeToString()
    +        self.device.char_write(TORADIO_UUID, b)
    +
    +    def close(self):
    +        self.adapter.stop()
    +
    +    def _readFromRadio(self):
    +        wasEmpty = False
    +        while not wasEmpty:
    +            b = self.device.char_read(FROMRADIO_UUID)
    +            wasEmpty = len(b) == 0
    +            if not wasEmpty:
    +                self._handleFromRadio(b)
    +
    +

    Ancestors

    + +

    Methods

    +
    +
    +def close(self) +
    +
    +
    +
    + +Expand source code + +
    def close(self):
    +    self.adapter.stop()
    +
    +
    +
    +

    Inherited members

    + +
    class MeshInterface (debugOut=None) @@ -456,7 +616,7 @@ debugOut

    self.isConnected = False self._startConfig() - def sendText(self, text, destinationId=BROADCAST_ADDR): + def sendText(self, text, destinationId=BROADCAST_ADDR, wantAck=False): """Send a utf8 string to some other node, if the node has a display it will also be shown on the device. Arguments: @@ -466,30 +626,30 @@ debugOut

    destinationId {nodeId or nodeNum} -- where to send this message (default: {BROADCAST_ADDR}) """ self.sendData(text.encode("utf-8"), destinationId, - dataType=mesh_pb2.Data.CLEAR_TEXT) + dataType=mesh_pb2.Data.CLEAR_TEXT, wantAck=wantAck) - def sendData(self, byteData, destinationId=BROADCAST_ADDR, dataType=mesh_pb2.Data.OPAQUE): + def sendData(self, byteData, destinationId=BROADCAST_ADDR, dataType=mesh_pb2.Data.OPAQUE, wantAck=False): """Send a data packet to some other node""" meshPacket = mesh_pb2.MeshPacket() - meshPacket.payload.data.payload = byteData - meshPacket.payload.data.typ = dataType - self.sendPacket(meshPacket, destinationId) + meshPacket.decoded.data.payload = byteData + meshPacket.decoded.data.typ = dataType + self.sendPacket(meshPacket, destinationId, wantAck=wantAck) - def sendPacket(self, meshPacket, destinationId=BROADCAST_ADDR): - """Send a MeshPacket to the specified node (or if unspecified, broadcast). + def sendPacket(self, meshPacket, destinationId=BROADCAST_ADDR, wantAck=False): + """Send a MeshPacket to the specified node (or if unspecified, broadcast). You probably don't want this - use sendData instead.""" toRadio = mesh_pb2.ToRadio() # FIXME add support for non broadcast addresses if isinstance(destinationId, int): nodeNum = destinationId - elif nodeNum == BROADCAST_ADDR: + elif destinationId == BROADCAST_ADDR: nodeNum = 255 else: - raise Exception( - "invalid destination addr, we don't yet support nodeid lookup") + nodeNum = self.nodes[destinationId].num meshPacket.to = nodeNum + meshPacket.want_ack = wantAck toRadio.packet.CopyFrom(meshPacket) self._sendToRadio(toRadio) @@ -535,16 +695,17 @@ debugOut

    Called by subclasses.""" fromRadio = mesh_pb2.FromRadio() fromRadio.ParseFromString(fromRadioBytes) - json = google.protobuf.json_format.MessageToJson(fromRadio) - logging.debug(f"Received: {json}") + asDict = google.protobuf.json_format.MessageToDict(fromRadio) + logging.debug(f"Received: {asDict}") if fromRadio.HasField("my_info"): self.myInfo = fromRadio.my_info elif fromRadio.HasField("radio"): self.radioConfig = fromRadio.radio elif fromRadio.HasField("node_info"): - node = fromRadio.node_info - self._nodesByNum[node.num] = node - self.nodes[node.user.id] = node + node = asDict["nodeInfo"] + self._fixupPosition(node["position"]) + self._nodesByNum[node["num"]] = node + self.nodes[node["user"]["id"]] = node elif fromRadio.config_complete_id == MY_CONFIG_ID: # we ignore the config_complete_id, it is unneeded for our stream API fromRadio.config_complete_id self._connected() @@ -556,12 +717,31 @@ debugOut

    else: logging.warn("Unexpected FromRadio payload") + def _fixupPosition(self, position): + """Convert integer lat/lon into floats + + Arguments: + position {Position dictionary} -- object ot fix up + """ + if "latitudeI" in position: + position["latitude"] = position["latitudeI"] * 1e-7 + if "longitudeI" in position: + position["longitude"] = position["longitudeI"] * 1e-7 + def _nodeNumToId(self, num): + """Map a node node number to a node ID + + Arguments: + num {int} -- Node number + + Returns: + string -- Node ID + """ if num == BROADCAST_NUM: return BROADCAST_ADDR try: - return self._nodesByNum[num].user.id + return self._nodesByNum[num]["user"]["id"] except: logging.error("Node not found for fromId") return None @@ -581,31 +761,39 @@ debugOut

    asDict["toId"] = self._nodeNumToId(asDict["to"]) # We could provide our objects as DotMaps - which work with . notation or as dictionaries - #asObj = DotMap(asDict) - topic = None - if meshPacket.payload.HasField("position"): + # asObj = DotMap(asDict) + topic = "meshtastic.receive" # Generic unknown packet type + if meshPacket.decoded.HasField("position"): topic = "meshtastic.receive.position" - # FIXME, update node DB as needed - if meshPacket.payload.HasField("user"): + p = asDict["decoded"]["position"] + self._fixupPosition(p) + # update node DB as needed + self._nodesByNum[asDict["from"]]["position"] = p + + if meshPacket.decoded.HasField("user"): topic = "meshtastic.receive.user" - # FIXME, update node DB as needed - if meshPacket.payload.HasField("data"): + u = asDict["decoded"]["user"] + # update node DB as needed + self._nodesByNum[asDict["from"]]["user"] = u + + if meshPacket.decoded.HasField("data"): topic = "meshtastic.receive.data" # For text messages, we go ahead and decode the text to ascii for our users - # if asObj.payload.data.typ == "CLEAR_TEXT": - # asObj.payload.data.text = asObj.payload.data.payload.decode( - # "utf-8") + if asDict["decoded"]["data"]["typ"] == "CLEAR_TEXT": + asDict["decoded"]["data"]["text"] = meshPacket.decoded.data.payload.decode( + "utf-8") pub.sendMessage(topic, packet=asDict, interface=self)

    Subclasses

    Methods

    -def sendData(self, byteData, destinationId='all', dataType=0) +def sendData(self, byteData, destinationId='all', dataType=0, wantAck=False)

    Send a data packet to some other node

    @@ -613,16 +801,16 @@ debugOut

    Expand source code -
    def sendData(self, byteData, destinationId=BROADCAST_ADDR, dataType=mesh_pb2.Data.OPAQUE):
    +
    def sendData(self, byteData, destinationId=BROADCAST_ADDR, dataType=mesh_pb2.Data.OPAQUE, wantAck=False):
         """Send a data packet to some other node"""
         meshPacket = mesh_pb2.MeshPacket()
    -    meshPacket.payload.data.payload = byteData
    -    meshPacket.payload.data.typ = dataType
    -    self.sendPacket(meshPacket, destinationId)
    + meshPacket.decoded.data.payload = byteData + meshPacket.decoded.data.typ = dataType + self.sendPacket(meshPacket, destinationId, wantAck=wantAck)
    -def sendPacket(self, meshPacket, destinationId='all') +def sendPacket(self, meshPacket, destinationId='all', wantAck=False)

    Send a MeshPacket to the specified node (or if unspecified, broadcast). @@ -631,27 +819,27 @@ You probably don't want this - use sendData instead.

    Expand source code -
    def sendPacket(self, meshPacket, destinationId=BROADCAST_ADDR):
    -    """Send a MeshPacket to the specified node (or if unspecified, broadcast). 
    +
    def sendPacket(self, meshPacket, destinationId=BROADCAST_ADDR, wantAck=False):
    +    """Send a MeshPacket to the specified node (or if unspecified, broadcast).
         You probably don't want this - use sendData instead."""
         toRadio = mesh_pb2.ToRadio()
         # FIXME add support for non broadcast addresses
     
         if isinstance(destinationId, int):
             nodeNum = destinationId
    -    elif nodeNum == BROADCAST_ADDR:
    +    elif destinationId == BROADCAST_ADDR:
             nodeNum = 255
         else:
    -        raise Exception(
    -            "invalid destination addr, we don't yet support nodeid lookup")
    +        nodeNum = self.nodes[destinationId].num
     
         meshPacket.to = nodeNum
    +    meshPacket.want_ack = wantAck
         toRadio.packet.CopyFrom(meshPacket)
         self._sendToRadio(toRadio)
    -def sendText(self, text, destinationId='all') +def sendText(self, text, destinationId='all', wantAck=False)

    Send a utf8 string to some other node, if the node has a display it will also be shown on the device.

    @@ -663,7 +851,7 @@ destinationId {nodeId or nodeNum} – where to send this message (default: { Expand source code -
    def sendText(self, text, destinationId=BROADCAST_ADDR):
    +
    def sendText(self, text, destinationId=BROADCAST_ADDR, wantAck=False):
         """Send a utf8 string to some other node, if the node has a display it will also be shown on the device.
     
         Arguments:
    @@ -673,7 +861,7 @@ destinationId {nodeId or nodeNum} – where to send this message (default: {
             destinationId {nodeId or nodeNum} -- where to send this message (default: {BROADCAST_ADDR})
         """
         self.sendData(text.encode("utf-8"), destinationId,
    -                  dataType=mesh_pb2.Data.CLEAR_TEXT)
    + dataType=mesh_pb2.Data.CLEAR_TEXT, wantAck=wantAck)
    @@ -723,7 +911,7 @@ debugOut {stream} – If a stream is provided, any debug serial output from """Interface class for meshtastic devices over a stream link (serial, TCP, etc)""" def __init__(self, devPath=None, debugOut=None): - """Constructor, opens a connection to a specified serial port, or if unspecified try to + """Constructor, opens a connection to a specified serial port, or if unspecified try to find one Meshtastic device by probing Keyword Arguments: @@ -874,6 +1062,7 @@ debugOut {stream} – If a stream is provided, any debug serial output from
    • Sub-modules

        +
      • meshtastic.ble
      • meshtastic.mesh_pb2
      • meshtastic.test
      • meshtastic.util
      • @@ -882,6 +1071,12 @@ debugOut {stream} – If a stream is provided, any debug serial output from
      • Classes

        • +

          BLEInterface

          + +
        • +
        • MeshInterface

          • sendData
          • diff --git a/docs/meshtastic/mesh_pb2.html b/docs/meshtastic/mesh_pb2.html index f9c96b6..4c5b4bd 100644 --- a/docs/meshtastic/mesh_pb2.html +++ b/docs/meshtastic/mesh_pb2.html @@ -46,7 +46,7 @@ DESCRIPTOR = _descriptor.FileDescriptor( package='', syntax='proto3', serialized_options=_b('\n\023com.geeksville.meshB\nMeshProtos'), - serialized_pb=_b('\n\nmesh.proto\"f\n\x08Position\x12\x10\n\x08latitude\x18\x01 \x01(\x01\x12\x11\n\tlongitude\x18\x02 \x01(\x01\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x05\x12\x15\n\rbattery_level\x18\x04 \x01(\x05\x12\x0c\n\x04time\x18\x06 \x01(\r\"g\n\x04\x44\x61ta\x12\x17\n\x03typ\x18\x01 \x01(\x0e\x32\n.Data.Type\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\"5\n\x04Type\x12\n\n\x06OPAQUE\x10\x00\x12\x0e\n\nCLEAR_TEXT\x10\x01\x12\x11\n\rCLEAR_READACK\x10\x02\"J\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\tlong_name\x18\x02 \x01(\t\x12\x12\n\nshort_name\x18\x03 \x01(\t\x12\x0f\n\x07macaddr\x18\x04 \x01(\x0c\"\x1f\n\x0eRouteDiscovery\x12\r\n\x05route\x18\x02 \x03(\x05\"i\n\tSubPacket\x12\x1b\n\x08position\x18\x01 \x01(\x0b\x32\t.Position\x12\x13\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x05.Data\x12\x13\n\x04user\x18\x04 \x01(\x0b\x32\x05.User\x12\x15\n\rwant_response\x18\x05 \x01(\x08\"p\n\nMeshPacket\x12\x0c\n\x04\x66rom\x18\x01 \x01(\x05\x12\n\n\x02to\x18\x02 \x01(\x05\x12\x1b\n\x07payload\x18\x03 \x01(\x0b\x32\n.SubPacket\x12\x0f\n\x07rx_time\x18\x04 \x01(\r\x12\n\n\x02id\x18\x06 \x01(\r\x12\x0e\n\x06rx_snr\x18\x07 \x01(\x02\"\xd4\x01\n\x0f\x43hannelSettings\x12\x10\n\x08tx_power\x18\x01 \x01(\x05\x12\x32\n\x0cmodem_config\x18\x03 \x01(\x0e\x32\x1c.ChannelSettings.ModemConfig\x12\x0b\n\x03psk\x18\x04 \x01(\x0c\x12\x0c\n\x04name\x18\x05 \x01(\t\"`\n\x0bModemConfig\x12\x12\n\x0e\x42w125Cr45Sf128\x10\x00\x12\x12\n\x0e\x42w500Cr45Sf128\x10\x01\x12\x14\n\x10\x42w31_25Cr48Sf512\x10\x02\x12\x13\n\x0f\x42w125Cr48Sf4096\x10\x03\"\xd7\x03\n\x0bRadioConfig\x12\x31\n\x0bpreferences\x18\x01 \x01(\x0b\x32\x1c.RadioConfig.UserPreferences\x12*\n\x10\x63hannel_settings\x18\x02 \x01(\x0b\x32\x10.ChannelSettings\x1a\xe8\x02\n\x0fUserPreferences\x12\x1f\n\x17position_broadcast_secs\x18\x01 \x01(\r\x12\x1b\n\x13send_owner_interval\x18\x02 \x01(\r\x12\x1a\n\x12num_missed_to_fail\x18\x03 \x01(\r\x12\x1b\n\x13wait_bluetooth_secs\x18\x04 \x01(\r\x12\x16\n\x0escreen_on_secs\x18\x05 \x01(\r\x12\x1a\n\x12phone_timeout_secs\x18\x06 \x01(\r\x12\x1d\n\x15phone_sds_timeout_sec\x18\x07 \x01(\r\x12\x1d\n\x15mesh_sds_timeout_secs\x18\x08 \x01(\r\x12\x10\n\x08sds_secs\x18\t \x01(\r\x12\x0f\n\x07ls_secs\x18\n \x01(\r\x12\x15\n\rmin_wake_secs\x18\x0b \x01(\r\x12\x18\n\x10keep_all_packets\x18\x64 \x01(\x08\x12\x18\n\x10promiscuous_mode\x18\x65 \x01(\x08\"V\n\x08NodeInfo\x12\x0b\n\x03num\x18\x01 \x01(\x05\x12\x13\n\x04user\x18\x02 \x01(\x0b\x32\x05.User\x12\x1b\n\x08position\x18\x03 \x01(\x0b\x32\t.Position\x12\x0b\n\x03snr\x18\x07 \x01(\x02\"\xc4\x01\n\nMyNodeInfo\x12\x13\n\x0bmy_node_num\x18\x01 \x01(\x05\x12\x0f\n\x07has_gps\x18\x02 \x01(\x08\x12\x14\n\x0cnum_channels\x18\x03 \x01(\x05\x12\x0e\n\x06region\x18\x04 \x01(\t\x12\x10\n\x08hw_model\x18\x05 \x01(\t\x12\x18\n\x10\x66irmware_version\x18\x06 \x01(\t\x12\x12\n\nerror_code\x18\x07 \x01(\r\x12\x15\n\rerror_address\x18\x08 \x01(\r\x12\x13\n\x0b\x65rror_count\x18\t \x01(\r\"\xd5\x01\n\x0b\x44\x65viceState\x12\x1b\n\x05radio\x18\x01 \x01(\x0b\x32\x0c.RadioConfig\x12\x1c\n\x07my_node\x18\x02 \x01(\x0b\x32\x0b.MyNodeInfo\x12\x14\n\x05owner\x18\x03 \x01(\x0b\x32\x05.User\x12\x1a\n\x07node_db\x18\x04 \x03(\x0b\x32\t.NodeInfo\x12\"\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12$\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x0b.MeshPacket\"\x1e\n\x0b\x44\x65\x62ugString\x12\x0f\n\x07message\x18\x01 \x01(\t\"\xf9\x01\n\tFromRadio\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x1d\n\x06packet\x18\x02 \x01(\x0b\x32\x0b.MeshPacketH\x00\x12\x1e\n\x07my_info\x18\x03 \x01(\x0b\x32\x0b.MyNodeInfoH\x00\x12\x1e\n\tnode_info\x18\x04 \x01(\x0b\x32\t.NodeInfoH\x00\x12\x1d\n\x05radio\x18\x06 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12$\n\x0c\x64\x65\x62ug_string\x18\x07 \x01(\x0b\x32\x0c.DebugStringH\x00\x12\x1c\n\x12\x63onfig_complete_id\x18\x08 \x01(\rH\x00\x12\x12\n\x08rebooted\x18\t \x01(\x08H\x00\x42\t\n\x07variant\"\x8c\x01\n\x07ToRadio\x12\x1d\n\x06packet\x18\x01 \x01(\x0b\x32\x0b.MeshPacketH\x00\x12\x18\n\x0ewant_config_id\x18\x64 \x01(\rH\x00\x12!\n\tset_radio\x18\x65 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1a\n\tset_owner\x18\x66 \x01(\x0b\x32\x05.UserH\x00\x42\t\n\x07variant*\x17\n\tConstants\x12\n\n\x06Unused\x10\x00\x42!\n\x13\x63om.geeksville.meshB\nMeshProtosb\x06proto3') + serialized_pb=_b('\n\nmesh.proto\"\x93\x01\n\x08Position\x12\x12\n\nlatitude_d\x18\x01 \x01(\x01\x12\x13\n\x0blongitude_d\x18\x02 \x01(\x01\x12\x12\n\nlatitude_i\x18\x07 \x01(\x11\x12\x13\n\x0blongitude_i\x18\x08 \x01(\x11\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x05\x12\x15\n\rbattery_level\x18\x04 \x01(\x05\x12\x0c\n\x04time\x18\t \x01(\x07\"g\n\x04\x44\x61ta\x12\x17\n\x03typ\x18\x01 \x01(\x0e\x32\n.Data.Type\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\"5\n\x04Type\x12\n\n\x06OPAQUE\x10\x00\x12\x0e\n\nCLEAR_TEXT\x10\x01\x12\x11\n\rCLEAR_READACK\x10\x02\"J\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\tlong_name\x18\x02 \x01(\t\x12\x12\n\nshort_name\x18\x03 \x01(\t\x12\x0f\n\x07macaddr\x18\x04 \x01(\x0c\"\x1f\n\x0eRouteDiscovery\x12\r\n\x05route\x18\x02 \x03(\x05\"\xfe\x01\n\tSubPacket\x12\x1d\n\x08position\x18\x01 \x01(\x0b\x32\t.PositionH\x00\x12\x15\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x05.DataH\x00\x12\x15\n\x04user\x18\x04 \x01(\x0b\x32\x05.UserH\x00\x12\"\n\x07request\x18\x06 \x01(\x0b\x32\x0f.RouteDiscoveryH\x00\x12 \n\x05reply\x18\x07 \x01(\x0b\x32\x0f.RouteDiscoveryH\x00\x12\x15\n\rwant_response\x18\x05 \x01(\x08\x12\x14\n\nsuccess_id\x18\n \x01(\rH\x01\x12\x11\n\x07\x66\x61il_id\x18\x0b \x01(\rH\x01\x12\x0c\n\x04\x64\x65st\x18\t \x01(\rB\t\n\x07payloadB\x05\n\x03\x61\x63k\"\xb7\x01\n\nMeshPacket\x12\x0c\n\x04\x66rom\x18\x01 \x01(\r\x12\n\n\x02to\x18\x02 \x01(\r\x12\x1d\n\x07\x64\x65\x63oded\x18\x03 \x01(\x0b\x32\n.SubPacketH\x00\x12\x13\n\tencrypted\x18\x08 \x01(\x0cH\x00\x12\n\n\x02id\x18\x06 \x01(\r\x12\x0f\n\x07rx_time\x18\t \x01(\x07\x12\x0e\n\x06rx_snr\x18\x07 \x01(\x02\x12\x11\n\thop_limit\x18\n \x01(\r\x12\x10\n\x08want_ack\x18\x0b \x01(\x08\x42\t\n\x07payload\"\xd4\x01\n\x0f\x43hannelSettings\x12\x10\n\x08tx_power\x18\x01 \x01(\x05\x12\x32\n\x0cmodem_config\x18\x03 \x01(\x0e\x32\x1c.ChannelSettings.ModemConfig\x12\x0b\n\x03psk\x18\x04 \x01(\x0c\x12\x0c\n\x04name\x18\x05 \x01(\t\"`\n\x0bModemConfig\x12\x12\n\x0e\x42w125Cr45Sf128\x10\x00\x12\x12\n\x0e\x42w500Cr45Sf128\x10\x01\x12\x14\n\x10\x42w31_25Cr48Sf512\x10\x02\x12\x13\n\x0f\x42w125Cr48Sf4096\x10\x03\"\xd7\x03\n\x0bRadioConfig\x12\x31\n\x0bpreferences\x18\x01 \x01(\x0b\x32\x1c.RadioConfig.UserPreferences\x12*\n\x10\x63hannel_settings\x18\x02 \x01(\x0b\x32\x10.ChannelSettings\x1a\xe8\x02\n\x0fUserPreferences\x12\x1f\n\x17position_broadcast_secs\x18\x01 \x01(\r\x12\x1b\n\x13send_owner_interval\x18\x02 \x01(\r\x12\x1a\n\x12num_missed_to_fail\x18\x03 \x01(\r\x12\x1b\n\x13wait_bluetooth_secs\x18\x04 \x01(\r\x12\x16\n\x0escreen_on_secs\x18\x05 \x01(\r\x12\x1a\n\x12phone_timeout_secs\x18\x06 \x01(\r\x12\x1d\n\x15phone_sds_timeout_sec\x18\x07 \x01(\r\x12\x1d\n\x15mesh_sds_timeout_secs\x18\x08 \x01(\r\x12\x10\n\x08sds_secs\x18\t \x01(\r\x12\x0f\n\x07ls_secs\x18\n \x01(\r\x12\x15\n\rmin_wake_secs\x18\x0b \x01(\r\x12\x18\n\x10keep_all_packets\x18\x64 \x01(\x08\x12\x18\n\x10promiscuous_mode\x18\x65 \x01(\x08\"h\n\x08NodeInfo\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x13\n\x04user\x18\x02 \x01(\x0b\x32\x05.User\x12\x1b\n\x08position\x18\x03 \x01(\x0b\x32\t.Position\x12\x0b\n\x03snr\x18\x07 \x01(\x02\x12\x10\n\x08next_hop\x18\x05 \x01(\r\"\xc4\x01\n\nMyNodeInfo\x12\x13\n\x0bmy_node_num\x18\x01 \x01(\x05\x12\x0f\n\x07has_gps\x18\x02 \x01(\x08\x12\x14\n\x0cnum_channels\x18\x03 \x01(\x05\x12\x0e\n\x06region\x18\x04 \x01(\t\x12\x10\n\x08hw_model\x18\x05 \x01(\t\x12\x18\n\x10\x66irmware_version\x18\x06 \x01(\t\x12\x12\n\nerror_code\x18\x07 \x01(\r\x12\x15\n\rerror_address\x18\x08 \x01(\r\x12\x13\n\x0b\x65rror_count\x18\t \x01(\r\"\xd5\x01\n\x0b\x44\x65viceState\x12\x1b\n\x05radio\x18\x01 \x01(\x0b\x32\x0c.RadioConfig\x12\x1c\n\x07my_node\x18\x02 \x01(\x0b\x32\x0b.MyNodeInfo\x12\x14\n\x05owner\x18\x03 \x01(\x0b\x32\x05.User\x12\x1a\n\x07node_db\x18\x04 \x03(\x0b\x32\t.NodeInfo\x12\"\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12$\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x0b.MeshPacket\"\x1e\n\x0b\x44\x65\x62ugString\x12\x0f\n\x07message\x18\x01 \x01(\t\"\xf9\x01\n\tFromRadio\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x1d\n\x06packet\x18\x02 \x01(\x0b\x32\x0b.MeshPacketH\x00\x12\x1e\n\x07my_info\x18\x03 \x01(\x0b\x32\x0b.MyNodeInfoH\x00\x12\x1e\n\tnode_info\x18\x04 \x01(\x0b\x32\t.NodeInfoH\x00\x12\x1d\n\x05radio\x18\x06 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12$\n\x0c\x64\x65\x62ug_string\x18\x07 \x01(\x0b\x32\x0c.DebugStringH\x00\x12\x1c\n\x12\x63onfig_complete_id\x18\x08 \x01(\rH\x00\x12\x12\n\x08rebooted\x18\t \x01(\x08H\x00\x42\t\n\x07variant\"\x8c\x01\n\x07ToRadio\x12\x1d\n\x06packet\x18\x01 \x01(\x0b\x32\x0b.MeshPacketH\x00\x12\x18\n\x0ewant_config_id\x18\x64 \x01(\rH\x00\x12!\n\tset_radio\x18\x65 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1a\n\tset_owner\x18\x66 \x01(\x0b\x32\x05.UserH\x00\x42\t\n\x07variant\"f\n\x11ManufacturingData\x12\x12\n\nfradioFreq\x18\x01 \x01(\r\x12\x10\n\x08hw_model\x18\x02 \x01(\t\x12\x12\n\nhw_version\x18\x03 \x01(\t\x12\x17\n\x0fselftest_result\x18\x04 \x01(\x11*\x17\n\tConstants\x12\n\n\x06Unused\x10\x00\x42!\n\x13\x63om.geeksville.meshB\nMeshProtosb\x06proto3') ) _CONSTANTS = _descriptor.EnumDescriptor( @@ -62,8 +62,8 @@ _CONSTANTS = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=2172, - serialized_end=2195, + serialized_start=2562, + serialized_end=2585, ) _sym_db.RegisterEnumDescriptor(_CONSTANTS) @@ -92,8 +92,8 @@ _DATA_TYPE = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=168, - serialized_end=221, + serialized_start=214, + serialized_end=267, ) _sym_db.RegisterEnumDescriptor(_DATA_TYPE) @@ -122,8 +122,8 @@ _CHANNELSETTINGS_MODEMCONFIG = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=670, - serialized_end=766, + serialized_start=938, + serialized_end=1034, ) _sym_db.RegisterEnumDescriptor(_CHANNELSETTINGS_MODEMCONFIG) @@ -136,36 +136,50 @@ _POSITION = _descriptor.Descriptor( containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='latitude', full_name='Position.latitude', index=0, + name='latitude_d', full_name='Position.latitude_d', index=0, number=1, type=1, cpp_type=5, label=1, has_default_value=False, default_value=float(0), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='longitude', full_name='Position.longitude', index=1, + name='longitude_d', full_name='Position.longitude_d', index=1, number=2, type=1, cpp_type=5, label=1, has_default_value=False, default_value=float(0), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='altitude', full_name='Position.altitude', index=2, + name='latitude_i', full_name='Position.latitude_i', index=2, + number=7, type=17, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='longitude_i', full_name='Position.longitude_i', index=3, + number=8, type=17, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='altitude', full_name='Position.altitude', index=4, number=3, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='battery_level', full_name='Position.battery_level', index=3, + name='battery_level', full_name='Position.battery_level', index=5, number=4, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='time', full_name='Position.time', index=4, - number=6, type=13, cpp_type=3, label=1, + name='time', full_name='Position.time', index=6, + number=9, type=7, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, @@ -182,8 +196,8 @@ _POSITION = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=14, - serialized_end=116, + serialized_start=15, + serialized_end=162, ) @@ -221,8 +235,8 @@ _DATA = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=118, - serialized_end=221, + serialized_start=164, + serialized_end=267, ) @@ -273,8 +287,8 @@ _USER = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=223, - serialized_end=297, + serialized_start=269, + serialized_end=343, ) @@ -304,8 +318,8 @@ _ROUTEDISCOVERY = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=299, - serialized_end=330, + serialized_start=345, + serialized_end=376, ) @@ -338,12 +352,140 @@ _SUBPACKET = _descriptor.Descriptor( is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='want_response', full_name='SubPacket.want_response', index=3, + name='request', full_name='SubPacket.request', index=3, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='reply', full_name='SubPacket.reply', index=4, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='want_response', full_name='SubPacket.want_response', index=5, number=5, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='success_id', full_name='SubPacket.success_id', index=6, + number=10, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='fail_id', full_name='SubPacket.fail_id', index=7, + number=11, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dest', full_name='SubPacket.dest', index=8, + number=9, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='payload', full_name='SubPacket.payload', + index=0, containing_type=None, fields=[]), + _descriptor.OneofDescriptor( + name='ack', full_name='SubPacket.ack', + index=1, containing_type=None, fields=[]), + ], + serialized_start=379, + serialized_end=633, +) + + +_MESHPACKET = _descriptor.Descriptor( + name='MeshPacket', + full_name='MeshPacket', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='from', full_name='MeshPacket.from', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='to', full_name='MeshPacket.to', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='decoded', full_name='MeshPacket.decoded', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='encrypted', full_name='MeshPacket.encrypted', index=3, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='id', full_name='MeshPacket.id', index=4, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='rx_time', full_name='MeshPacket.rx_time', index=5, + number=9, type=7, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='rx_snr', full_name='MeshPacket.rx_snr', index=6, + number=7, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='hop_limit', full_name='MeshPacket.hop_limit', index=7, + number=10, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='want_ack', full_name='MeshPacket.want_ack', index=8, + number=11, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -355,75 +497,12 @@ _SUBPACKET = _descriptor.Descriptor( syntax='proto3', extension_ranges=[], oneofs=[ + _descriptor.OneofDescriptor( + name='payload', full_name='MeshPacket.payload', + index=0, containing_type=None, fields=[]), ], - serialized_start=332, - serialized_end=437, -) - - -_MESHPACKET = _descriptor.Descriptor( - name='MeshPacket', - full_name='MeshPacket', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='from', full_name='MeshPacket.from', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='to', full_name='MeshPacket.to', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='payload', full_name='MeshPacket.payload', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='rx_time', full_name='MeshPacket.rx_time', index=3, - number=4, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='id', full_name='MeshPacket.id', index=4, - number=6, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='rx_snr', full_name='MeshPacket.rx_snr', index=5, - number=7, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=439, - serialized_end=551, + serialized_start=636, + serialized_end=819, ) @@ -475,8 +554,8 @@ _CHANNELSETTINGS = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=554, - serialized_end=766, + serialized_start=822, + serialized_end=1034, ) @@ -590,8 +669,8 @@ _RADIOCONFIG_USERPREFERENCES = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=880, - serialized_end=1240, + serialized_start=1148, + serialized_end=1508, ) _RADIOCONFIG = _descriptor.Descriptor( @@ -627,8 +706,8 @@ _RADIOCONFIG = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=769, - serialized_end=1240, + serialized_start=1037, + serialized_end=1508, ) @@ -641,7 +720,7 @@ _NODEINFO = _descriptor.Descriptor( fields=[ _descriptor.FieldDescriptor( name='num', full_name='NodeInfo.num', index=0, - number=1, type=5, cpp_type=1, label=1, + number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, @@ -667,6 +746,13 @@ _NODEINFO = _descriptor.Descriptor( message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='next_hop', full_name='NodeInfo.next_hop', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -679,8 +765,8 @@ _NODEINFO = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1242, - serialized_end=1328, + serialized_start=1510, + serialized_end=1614, ) @@ -766,8 +852,8 @@ _MYNODEINFO = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1331, - serialized_end=1527, + serialized_start=1617, + serialized_end=1813, ) @@ -839,8 +925,8 @@ _DEVICESTATE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1530, - serialized_end=1743, + serialized_start=1816, + serialized_end=2029, ) @@ -870,8 +956,8 @@ _DEBUGSTRING = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1745, - serialized_end=1775, + serialized_start=2031, + serialized_end=2061, ) @@ -953,8 +1039,8 @@ _FROMRADIO = _descriptor.Descriptor( name='variant', full_name='FromRadio.variant', index=0, containing_type=None, fields=[]), ], - serialized_start=1778, - serialized_end=2027, + serialized_start=2064, + serialized_end=2313, ) @@ -1008,8 +1094,60 @@ _TORADIO = _descriptor.Descriptor( name='variant', full_name='ToRadio.variant', index=0, containing_type=None, fields=[]), ], - serialized_start=2030, - serialized_end=2170, + serialized_start=2316, + serialized_end=2456, +) + + +_MANUFACTURINGDATA = _descriptor.Descriptor( + name='ManufacturingData', + full_name='ManufacturingData', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='fradioFreq', full_name='ManufacturingData.fradioFreq', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='hw_model', full_name='ManufacturingData.hw_model', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='hw_version', full_name='ManufacturingData.hw_version', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='selftest_result', full_name='ManufacturingData.selftest_result', index=3, + number=4, type=17, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2458, + serialized_end=2560, ) _DATA.fields_by_name['typ'].enum_type = _DATA_TYPE @@ -1017,7 +1155,36 @@ _DATA_TYPE.containing_type = _DATA _SUBPACKET.fields_by_name['position'].message_type = _POSITION _SUBPACKET.fields_by_name['data'].message_type = _DATA _SUBPACKET.fields_by_name['user'].message_type = _USER -_MESHPACKET.fields_by_name['payload'].message_type = _SUBPACKET +_SUBPACKET.fields_by_name['request'].message_type = _ROUTEDISCOVERY +_SUBPACKET.fields_by_name['reply'].message_type = _ROUTEDISCOVERY +_SUBPACKET.oneofs_by_name['payload'].fields.append( + _SUBPACKET.fields_by_name['position']) +_SUBPACKET.fields_by_name['position'].containing_oneof = _SUBPACKET.oneofs_by_name['payload'] +_SUBPACKET.oneofs_by_name['payload'].fields.append( + _SUBPACKET.fields_by_name['data']) +_SUBPACKET.fields_by_name['data'].containing_oneof = _SUBPACKET.oneofs_by_name['payload'] +_SUBPACKET.oneofs_by_name['payload'].fields.append( + _SUBPACKET.fields_by_name['user']) +_SUBPACKET.fields_by_name['user'].containing_oneof = _SUBPACKET.oneofs_by_name['payload'] +_SUBPACKET.oneofs_by_name['payload'].fields.append( + _SUBPACKET.fields_by_name['request']) +_SUBPACKET.fields_by_name['request'].containing_oneof = _SUBPACKET.oneofs_by_name['payload'] +_SUBPACKET.oneofs_by_name['payload'].fields.append( + _SUBPACKET.fields_by_name['reply']) +_SUBPACKET.fields_by_name['reply'].containing_oneof = _SUBPACKET.oneofs_by_name['payload'] +_SUBPACKET.oneofs_by_name['ack'].fields.append( + _SUBPACKET.fields_by_name['success_id']) +_SUBPACKET.fields_by_name['success_id'].containing_oneof = _SUBPACKET.oneofs_by_name['ack'] +_SUBPACKET.oneofs_by_name['ack'].fields.append( + _SUBPACKET.fields_by_name['fail_id']) +_SUBPACKET.fields_by_name['fail_id'].containing_oneof = _SUBPACKET.oneofs_by_name['ack'] +_MESHPACKET.fields_by_name['decoded'].message_type = _SUBPACKET +_MESHPACKET.oneofs_by_name['payload'].fields.append( + _MESHPACKET.fields_by_name['decoded']) +_MESHPACKET.fields_by_name['decoded'].containing_oneof = _MESHPACKET.oneofs_by_name['payload'] +_MESHPACKET.oneofs_by_name['payload'].fields.append( + _MESHPACKET.fields_by_name['encrypted']) +_MESHPACKET.fields_by_name['encrypted'].containing_oneof = _MESHPACKET.oneofs_by_name['payload'] _CHANNELSETTINGS.fields_by_name['modem_config'].enum_type = _CHANNELSETTINGS_MODEMCONFIG _CHANNELSETTINGS_MODEMCONFIG.containing_type = _CHANNELSETTINGS _RADIOCONFIG_USERPREFERENCES.containing_type = _RADIOCONFIG @@ -1086,6 +1253,7 @@ DESCRIPTOR.message_types_by_name['DeviceState'] = _DEVICESTATE DESCRIPTOR.message_types_by_name['DebugString'] = _DEBUGSTRING DESCRIPTOR.message_types_by_name['FromRadio'] = _FROMRADIO DESCRIPTOR.message_types_by_name['ToRadio'] = _TORADIO +DESCRIPTOR.message_types_by_name['ManufacturingData'] = _MANUFACTURINGDATA DESCRIPTOR.enum_types_by_name['Constants'] = _CONSTANTS _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -1195,6 +1363,13 @@ ToRadio = _reflection.GeneratedProtocolMessageType('ToRadio', (_message. )) _sym_db.RegisterMessage(ToRadio) +ManufacturingData = _reflection.GeneratedProtocolMessageType('ManufacturingData', (_message.Message,), dict( + DESCRIPTOR = _MANUFACTURINGDATA, + __module__ = 'mesh_pb2' + # @@protoc_insertion_point(class_scope:ManufacturingData) + )) +_sym_db.RegisterMessage(ManufacturingData) + DESCRIPTOR._options = None # @@protoc_insertion_point(module_scope)
            @@ -1428,6 +1603,41 @@ DESCRIPTOR._options = None
    +
    +class ManufacturingData +(...) +
    +
    +

    A ProtocolMessage

    +

    Ancestors

    +
      +
    • google.protobuf.pyext._message.CMessage
    • +
    • google.protobuf.message.Message
    • +
    +

    Class variables

    +
    +
    var DESCRIPTOR
    +
    +
    +
    +
    var FRADIOFREQ_FIELD_NUMBER
    +
    +
    +
    +
    var HW_MODEL_FIELD_NUMBER
    +
    +
    +
    +
    var HW_VERSION_FIELD_NUMBER
    +
    +
    +
    +
    var SELFTEST_RESULT_FIELD_NUMBER
    +
    +
    +
    +
    +
    class MeshPacket (...) @@ -1441,19 +1651,27 @@ DESCRIPTOR._options = None

    Class variables

    +
    var DECODED_FIELD_NUMBER
    +
    +
    +
    var DESCRIPTOR
    +
    var ENCRYPTED_FIELD_NUMBER
    +
    +
    +
    var FROM_FIELD_NUMBER
    -
    var ID_FIELD_NUMBER
    +
    var HOP_LIMIT_FIELD_NUMBER
    -
    var PAYLOAD_FIELD_NUMBER
    +
    var ID_FIELD_NUMBER
    @@ -1469,6 +1687,10 @@ DESCRIPTOR._options = None
    +
    var WANT_ACK_FIELD_NUMBER
    +
    +
    +
    @@ -1543,6 +1765,10 @@ DESCRIPTOR._options = None
    +
    var NEXT_HOP_FIELD_NUMBER
    +
    +
    +
    var NUM_FIELD_NUMBER
    @@ -1586,11 +1812,19 @@ DESCRIPTOR._options = None
    -
    var LATITUDE_FIELD_NUMBER
    +
    var LATITUDE_D_FIELD_NUMBER
    -
    var LONGITUDE_FIELD_NUMBER
    +
    var LATITUDE_I_FIELD_NUMBER
    +
    +
    +
    +
    var LONGITUDE_D_FIELD_NUMBER
    +
    +
    +
    +
    var LONGITUDE_I_FIELD_NUMBER
    @@ -1675,10 +1909,30 @@ DESCRIPTOR._options = None
    +
    var DEST_FIELD_NUMBER
    +
    +
    +
    +
    var FAIL_ID_FIELD_NUMBER
    +
    +
    +
    var POSITION_FIELD_NUMBER
    +
    var REPLY_FIELD_NUMBER
    +
    +
    +
    +
    var REQUEST_FIELD_NUMBER
    +
    +
    +
    +
    var SUCCESS_ID_FIELD_NUMBER
    +
    +
    +
    var USER_FIELD_NUMBER
    @@ -1837,15 +2091,28 @@ DESCRIPTOR._options = None
  • +

    ManufacturingData

    + +
  • +
  • MeshPacket

  • @@ -1867,6 +2134,7 @@ DESCRIPTOR._options = None

    NodeInfo

  • @@ -1905,7 +2175,12 @@ DESCRIPTOR._options = None diff --git a/docs/meshtastic/test.html b/docs/meshtastic/test.html index 1f28d9e..1a06436 100644 --- a/docs/meshtastic/test.html +++ b/docs/meshtastic/test.html @@ -49,7 +49,7 @@ def onReceive(packet, interface): print(f"From {interface.devPath}: {packet}") p = DotMap(packet) - if p.payload.data.typ == "CLEAR_TEXT": + if p.decoded.data.typ == "CLEAR_TEXT": # We only care a about clear text packets receivedPackets.append(p) @@ -82,11 +82,11 @@ def testSend(fromInterface, toInterface): toNode = toInterface.myInfo.my_node_num # FIXME, hack to test broadcast - toNode = 255 + # toNode = 255 logging.info(f"Sending test packet from {fromNode} to {toNode}") - fromInterface.sendText(f"Test {testNumber}", toNode) - time.sleep(40) + fromInterface.sendText(f"Test {testNumber}", toNode, wantAck=True) + time.sleep(30) return (len(receivedPackets) >= 1) @@ -212,7 +212,7 @@ def testAll(): print(f"From {interface.devPath}: {packet}") p = DotMap(packet) - if p.payload.data.typ == "CLEAR_TEXT": + if p.decoded.data.typ == "CLEAR_TEXT": # We only care a about clear text packets receivedPackets.append(p)
    @@ -314,11 +314,11 @@ toInterface {[type]} – [description]

    toNode = toInterface.myInfo.my_node_num # FIXME, hack to test broadcast - toNode = 255 + # toNode = 255 logging.info(f"Sending test packet from {fromNode} to {toNode}") - fromInterface.sendText(f"Test {testNumber}", toNode) - time.sleep(40) + fromInterface.sendText(f"Test {testNumber}", toNode, wantAck=True) + time.sleep(30) return (len(receivedPackets) >= 1)
    diff --git a/setup.py b/setup.py index 2896e29..17e08a0 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ with open("README.md", "r") as fh: # This call to setup() does all the work setup( name="meshtastic", - version="0.5.2", + version="0.5.3", description="Python API & client shell for talking to Meshtastic devices", long_description=long_description, long_description_content_type="text/markdown", @@ -26,7 +26,7 @@ setup( packages=["meshtastic"], include_package_data=True, install_requires=["pyserial>=3.4", "protobuf>=3.6.1", - "pypubsub>=4.0.3", "dotmap>=1.3.14" ], + "pypubsub>=4.0.3", "dotmap>=1.3.14"], python_requires='>=3.4', entry_points={ "console_scripts": [