mirror of
https://github.com/meshtastic/python.git
synced 2026-01-17 04:08:13 -05:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a3a840269 | ||
|
|
fe69f05e75 | ||
|
|
5c662822b9 | ||
|
|
c049d3424a | ||
|
|
471535853b | ||
|
|
676148cc14 | ||
|
|
a915b05240 | ||
|
|
a1668e8c66 | ||
|
|
e7664cb40b | ||
|
|
83c18f4008 | ||
|
|
8b6321ce7f | ||
|
|
9fac981ba6 | ||
|
|
ccc71930f7 | ||
|
|
9380f048fa |
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
@@ -10,12 +10,17 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version:
|
||||||
|
- "3.6"
|
||||||
|
- "3.7"
|
||||||
|
- "3.8"
|
||||||
|
- "3.9"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Install Python 3
|
- name: Install Python 3
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v1
|
||||||
with:
|
|
||||||
python-version: 3.9
|
|
||||||
- name: Uninstall meshtastic
|
- name: Uninstall meshtastic
|
||||||
run: |
|
run: |
|
||||||
pip3 uninstall meshtastic
|
pip3 uninstall meshtastic
|
||||||
@@ -46,12 +51,17 @@ jobs:
|
|||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
validate:
|
validate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version:
|
||||||
|
- "3.6"
|
||||||
|
- "3.7"
|
||||||
|
- "3.8"
|
||||||
|
- "3.9"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Install Python 3
|
- name: Install Python 3
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v1
|
||||||
with:
|
|
||||||
python-version: 3.9
|
|
||||||
- name: Install meshtastic from local
|
- name: Install meshtastic from local
|
||||||
run: |
|
run: |
|
||||||
pip3 install .
|
pip3 install .
|
||||||
|
|||||||
@@ -77,9 +77,11 @@ from pubsub import pub
|
|||||||
from dotmap import DotMap
|
from dotmap import DotMap
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
from google.protobuf.json_format import MessageToJson
|
from google.protobuf.json_format import MessageToJson
|
||||||
from .util import fixme, catchAndIgnore, stripnl, DeferredExecution, Timeout
|
from meshtastic.util import fixme, catchAndIgnore, stripnl, DeferredExecution, Timeout
|
||||||
from .node import Node
|
from meshtastic.node import Node
|
||||||
from . import mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2, environmental_measurement_pb2, remote_hardware_pb2, channel_pb2, radioconfig_pb2, util
|
from meshtastic import (mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2,
|
||||||
|
environmental_measurement_pb2, remote_hardware_pb2,
|
||||||
|
channel_pb2, radioconfig_pb2, util)
|
||||||
|
|
||||||
# Note: To follow PEP224, comments should be after the module variable.
|
# Note: To follow PEP224, comments should be after the module variable.
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import pyqrcode
|
|||||||
import pkg_resources
|
import pkg_resources
|
||||||
import meshtastic.util
|
import meshtastic.util
|
||||||
import meshtastic.test
|
import meshtastic.test
|
||||||
from . import remote_hardware
|
from meshtastic import remote_hardware
|
||||||
from .ble_interface import BLEInterface
|
from meshtastic.ble_interface import BLEInterface
|
||||||
from . import portnums_pb2, channel_pb2, radioconfig_pb2
|
from meshtastic import portnums_pb2, channel_pb2, radioconfig_pb2
|
||||||
from .globals import Globals
|
from meshtastic.globals import Globals
|
||||||
|
|
||||||
|
|
||||||
def onReceive(packet, interface):
|
def onReceive(packet, interface):
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import logging
|
|||||||
import pygatt
|
import pygatt
|
||||||
|
|
||||||
|
|
||||||
from .mesh_interface import MeshInterface
|
from meshtastic.mesh_interface import MeshInterface
|
||||||
|
|
||||||
# Our standard BLE characteristics
|
# Our standard BLE characteristics
|
||||||
TORADIO_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7"
|
TORADIO_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7"
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ from google.protobuf.json_format import MessageToJson
|
|||||||
|
|
||||||
|
|
||||||
import meshtastic.node
|
import meshtastic.node
|
||||||
from . import portnums_pb2, mesh_pb2
|
from meshtastic import portnums_pb2, mesh_pb2
|
||||||
from .util import stripnl, Timeout, our_exit, remove_keys_from_dict, convert_mac_addr
|
from meshtastic.util import stripnl, Timeout, our_exit, remove_keys_from_dict, convert_mac_addr
|
||||||
from .__init__ import LOCAL_ADDR, BROADCAST_NUM, BROADCAST_ADDR, ResponseHandler, publishingThread, OUR_APP_VERSION, protocols
|
from meshtastic.__init__ import LOCAL_ADDR, BROADCAST_NUM, BROADCAST_ADDR, ResponseHandler, publishingThread, OUR_APP_VERSION, protocols
|
||||||
|
|
||||||
class MeshInterface:
|
class MeshInterface:
|
||||||
"""Interface class for meshtastic devices
|
"""Interface class for meshtastic devices
|
||||||
@@ -68,8 +68,7 @@ class MeshInterface:
|
|||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
if exc_type is not None and exc_value is not None:
|
if exc_type is not None and exc_value is not None:
|
||||||
logging.error(
|
logging.error(f'An exception of type {exc_type} with value {exc_value} has occurred')
|
||||||
f'An exception of type {exc_type} with value {exc_value} has occurred')
|
|
||||||
if traceback is not None:
|
if traceback is not None:
|
||||||
logging.error(f'Traceback: {traceback}')
|
logging.error(f'Traceback: {traceback}')
|
||||||
self.close()
|
self.close()
|
||||||
@@ -84,10 +83,10 @@ class MeshInterface:
|
|||||||
nodes = ""
|
nodes = ""
|
||||||
if self.nodes:
|
if self.nodes:
|
||||||
for n in self.nodes.values():
|
for n in self.nodes.values():
|
||||||
# when the TBeam is first booted, it sometimes shows the 'raw' data
|
# when the TBeam is first booted, it sometimes shows the raw data
|
||||||
# so, we will just remove any raw keys
|
# so, we will just remove any raw keys
|
||||||
n2 = remove_keys_from_dict('raw', n)
|
keys_to_remove = ('raw', 'decoded', 'payload')
|
||||||
n2 = remove_keys_from_dict('decode', n2)
|
n2 = remove_keys_from_dict(keys_to_remove, n)
|
||||||
|
|
||||||
# if we have 'macaddr', re-format it
|
# if we have 'macaddr', re-format it
|
||||||
if 'macaddr' in n2['user']:
|
if 'macaddr' in n2['user']:
|
||||||
@@ -394,11 +393,11 @@ class MeshInterface:
|
|||||||
return user.get('shortName', None)
|
return user.get('shortName', None)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _waitConnected(self):
|
def _waitConnected(self, timeout=15.0):
|
||||||
"""Block until the initial node db download is complete, or timeout
|
"""Block until the initial node db download is complete, or timeout
|
||||||
and raise an exception"""
|
and raise an exception"""
|
||||||
if not self.noProto:
|
if not self.noProto:
|
||||||
if not self.isConnected.wait(15.0): # timeout after x seconds
|
if not self.isConnected.wait(timeout): # timeout after x seconds
|
||||||
raise Exception("Timed out waiting for connection completion")
|
raise Exception("Timed out waiting for connection completion")
|
||||||
|
|
||||||
# If we failed while connecting, raise the connection to the client
|
# If we failed while connecting, raise the connection to the client
|
||||||
@@ -416,8 +415,7 @@ class MeshInterface:
|
|||||||
def _disconnected(self):
|
def _disconnected(self):
|
||||||
"""Called by subclasses to tell clients this interface has disconnected"""
|
"""Called by subclasses to tell clients this interface has disconnected"""
|
||||||
self.isConnected.clear()
|
self.isConnected.clear()
|
||||||
publishingThread.queueWork(lambda: pub.sendMessage(
|
publishingThread.queueWork(lambda: pub.sendMessage("meshtastic.connection.lost", interface=self))
|
||||||
"meshtastic.connection.lost", interface=self))
|
|
||||||
|
|
||||||
def _startHeartbeat(self):
|
def _startHeartbeat(self):
|
||||||
"""We need to send a heartbeat message to the device every X seconds"""
|
"""We need to send a heartbeat message to the device every X seconds"""
|
||||||
@@ -443,8 +441,7 @@ class MeshInterface:
|
|||||||
if not self.isConnected.is_set():
|
if not self.isConnected.is_set():
|
||||||
self.isConnected.set()
|
self.isConnected.set()
|
||||||
self._startHeartbeat()
|
self._startHeartbeat()
|
||||||
publishingThread.queueWork(lambda: pub.sendMessage(
|
publishingThread.queueWork(lambda: pub.sendMessage("meshtastic.connection.established", interface=self))
|
||||||
"meshtastic.connection.established", interface=self))
|
|
||||||
|
|
||||||
def _startConfig(self):
|
def _startConfig(self):
|
||||||
"""Start device packets flowing"""
|
"""Start device packets flowing"""
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
import logging
|
import logging
|
||||||
import base64
|
import base64
|
||||||
from google.protobuf.json_format import MessageToJson
|
from google.protobuf.json_format import MessageToJson
|
||||||
from . import portnums_pb2, apponly_pb2, admin_pb2, channel_pb2
|
from meshtastic import portnums_pb2, apponly_pb2, admin_pb2, channel_pb2
|
||||||
from .util import pskToString, stripnl, Timeout, our_exit, fromPSK
|
from meshtastic.util import pskToString, stripnl, Timeout, our_exit, fromPSK
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
from . import portnums_pb2, remote_hardware_pb2
|
from meshtastic import portnums_pb2, remote_hardware_pb2
|
||||||
from .util import our_exit
|
from meshtastic.util import our_exit
|
||||||
|
|
||||||
|
|
||||||
def onGPIOreceive(packet, interface):
|
def onGPIOreceive(packet, interface):
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import platform
|
|||||||
import serial
|
import serial
|
||||||
|
|
||||||
import meshtastic.util
|
import meshtastic.util
|
||||||
from .stream_interface import StreamInterface
|
from meshtastic.stream_interface import StreamInterface
|
||||||
|
|
||||||
if platform.system() != 'Windows':
|
if platform.system() != 'Windows':
|
||||||
import termios
|
import termios
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import traceback
|
|||||||
import serial
|
import serial
|
||||||
|
|
||||||
|
|
||||||
from .mesh_interface import MeshInterface
|
from meshtastic.mesh_interface import MeshInterface
|
||||||
from .util import stripnl
|
from meshtastic.util import stripnl
|
||||||
|
|
||||||
|
|
||||||
START1 = 0x94
|
START1 = 0x94
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import logging
|
|||||||
import socket
|
import socket
|
||||||
from typing import AnyStr
|
from typing import AnyStr
|
||||||
|
|
||||||
from .stream_interface import StreamInterface
|
from meshtastic.stream_interface import StreamInterface
|
||||||
|
|
||||||
class TCPInterface(StreamInterface):
|
class TCPInterface(StreamInterface):
|
||||||
"""Interface class for meshtastic devices over a TCP link"""
|
"""Interface class for meshtastic devices over a TCP link"""
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import traceback
|
|||||||
from dotmap import DotMap
|
from dotmap import DotMap
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
import meshtastic.util
|
import meshtastic.util
|
||||||
from .__init__ import BROADCAST_NUM
|
from meshtastic.__init__ import BROADCAST_NUM
|
||||||
from .serial_interface import SerialInterface
|
from meshtastic.serial_interface import SerialInterface
|
||||||
from .tcp_interface import TCPInterface
|
from meshtastic.tcp_interface import TCPInterface
|
||||||
|
|
||||||
|
|
||||||
"""The interfaces we are using for our tests"""
|
"""The interfaces we are using for our tests"""
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ from ..mesh_interface import MeshInterface
|
|||||||
from ..node import Node
|
from ..node import Node
|
||||||
from .. import mesh_pb2
|
from .. import mesh_pb2
|
||||||
from ..__init__ import LOCAL_ADDR, BROADCAST_ADDR
|
from ..__init__ import LOCAL_ADDR, BROADCAST_ADDR
|
||||||
|
from ..radioconfig_pb2 import RadioConfig
|
||||||
|
from ..util import Timeout
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@@ -164,6 +166,22 @@ def test_sendPosition(reset_globals, caplog):
|
|||||||
assert re.search(r'p.time:', caplog.text, re.MULTILINE)
|
assert re.search(r'p.time:', caplog.text, re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_close_with_heartbeatTimer(reset_globals, caplog):
|
||||||
|
"""Test close() with heartbeatTimer"""
|
||||||
|
iface = MeshInterface(noProto=True)
|
||||||
|
anode = Node('foo', 'bar')
|
||||||
|
radioConfig = RadioConfig()
|
||||||
|
radioConfig.preferences.phone_timeout_secs = 10
|
||||||
|
anode.radioConfig = radioConfig
|
||||||
|
iface.localNode = anode
|
||||||
|
assert iface.heartbeatTimer is None
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
iface._startHeartbeat()
|
||||||
|
assert iface.heartbeatTimer is not None
|
||||||
|
iface.close()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
def test_handleFromRadio_empty_payload(reset_globals, caplog):
|
def test_handleFromRadio_empty_payload(reset_globals, caplog):
|
||||||
"""Test _handleFromRadio"""
|
"""Test _handleFromRadio"""
|
||||||
@@ -543,3 +561,70 @@ def test_getOrCreateByNum(capsys, reset_globals, iface_with_nodes):
|
|||||||
iface.myInfo.my_node_num = 2475227164
|
iface.myInfo.my_node_num = 2475227164
|
||||||
tmp = iface._getOrCreateByNum(2475227164)
|
tmp = iface._getOrCreateByNum(2475227164)
|
||||||
assert tmp['num'] == 2475227164
|
assert tmp['num'] == 2475227164
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_enter():
|
||||||
|
"""Test __enter__()"""
|
||||||
|
iface = MeshInterface(noProto=True)
|
||||||
|
assert iface == iface.__enter__()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_exit_with_exception(caplog):
|
||||||
|
"""Test __exit__()"""
|
||||||
|
iface = MeshInterface(noProto=True)
|
||||||
|
with caplog.at_level(logging.ERROR):
|
||||||
|
iface.__exit__('foo', 'bar', 'baz')
|
||||||
|
assert re.search(r'An exception of type foo with value bar has occurred', caplog.text, re.MULTILINE)
|
||||||
|
assert re.search(r'Traceback: baz', caplog.text, re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_showNodes_exclude_self(capsys, caplog, reset_globals, iface_with_nodes):
|
||||||
|
"""Test that we hit that continue statement"""
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
iface = iface_with_nodes
|
||||||
|
iface.localNode.nodeNum = 2475227164
|
||||||
|
iface.showNodes()
|
||||||
|
iface.showNodes(includeSelf=False)
|
||||||
|
capsys.readouterr()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_waitForConfig(caplog, capsys):
|
||||||
|
"""Test waitForConfig()"""
|
||||||
|
iface = MeshInterface(noProto=True)
|
||||||
|
# override how long to wait
|
||||||
|
iface._timeout = Timeout(0.01)
|
||||||
|
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||||
|
iface.waitForConfig()
|
||||||
|
assert pytest_wrapped_e.type == Exception
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert re.search(r'Exception: Timed out waiting for interface config', err, re.MULTILINE)
|
||||||
|
assert out == ''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_waitConnected_raises_an_exception(caplog, capsys):
|
||||||
|
"""Test waitConnected()"""
|
||||||
|
iface = MeshInterface(noProto=True)
|
||||||
|
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||||
|
iface.failure = "warn about something"
|
||||||
|
iface._waitConnected(0.01)
|
||||||
|
assert pytest_wrapped_e.type == Exception
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert re.search(r'warn about something', err, re.MULTILINE)
|
||||||
|
assert out == ''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_waitConnected_isConnected_timeout(caplog, capsys):
|
||||||
|
"""Test waitConnected()"""
|
||||||
|
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||||
|
iface = MeshInterface()
|
||||||
|
iface._waitConnected(0.01)
|
||||||
|
assert pytest_wrapped_e.type == Exception
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert re.search(r'warn about something', err, re.MULTILINE)
|
||||||
|
assert out == ''
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from ..serial_interface import SerialInterface
|
|||||||
from ..admin_pb2 import AdminMessage
|
from ..admin_pb2 import AdminMessage
|
||||||
from ..channel_pb2 import Channel
|
from ..channel_pb2 import Channel
|
||||||
from ..radioconfig_pb2 import RadioConfig
|
from ..radioconfig_pb2 import RadioConfig
|
||||||
|
from ..util import Timeout
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@@ -90,6 +91,16 @@ def test_setOwner_no_short_name_and_long_name_has_words(caplog):
|
|||||||
assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)
|
assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_setOwner_long_name_no_short(caplog):
|
||||||
|
"""Test setOwner"""
|
||||||
|
anode = Node('foo', 'bar', noProto=True)
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
anode.setOwner(long_name ='Aabo', is_licensed=True)
|
||||||
|
assert re.search(r'p.set_owner.long_name:Aabo:', caplog.text, re.MULTILINE)
|
||||||
|
assert re.search(r'p.set_owner.short_name:Aab:', caplog.text, re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
def test_exitSimulator(caplog):
|
def test_exitSimulator(caplog):
|
||||||
"""Test exitSimulator"""
|
"""Test exitSimulator"""
|
||||||
@@ -869,3 +880,14 @@ def test_onResponseRequestSetting_with_error(capsys):
|
|||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert re.search(r'Error on response', out)
|
assert re.search(r'Error on response', out)
|
||||||
assert err == ''
|
assert err == ''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_waitForConfig():
|
||||||
|
"""Test waitForConfig()"""
|
||||||
|
anode = Node('foo', 'bar')
|
||||||
|
radioConfig = RadioConfig()
|
||||||
|
anode.radioConfig = radioConfig
|
||||||
|
anode._timeout = Timeout(0.01)
|
||||||
|
result = anode.waitForConfig()
|
||||||
|
assert not result
|
||||||
|
|||||||
@@ -184,6 +184,23 @@ def test_remove_keys_from_dict():
|
|||||||
assert remove_keys_from_dict(('b'), {'a':1, 'b':2}) == {'a':1}
|
assert remove_keys_from_dict(('b'), {'a':1, 'b':2}) == {'a':1}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_remove_keys_from_dict_multiple_keys():
|
||||||
|
"""Test remove_keys_from_dict()"""
|
||||||
|
keys = ('a', 'b')
|
||||||
|
adict = {'a': 1, 'b': 2, 'c': 3}
|
||||||
|
assert remove_keys_from_dict(keys, adict) == {'c':3}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_remove_keys_from_dict_nested():
|
||||||
|
"""Test remove_keys_from_dict()"""
|
||||||
|
keys = ('b')
|
||||||
|
adict = {'a': {'b': 1}, 'b': 2, 'c': 3}
|
||||||
|
exp = {'a': {}, 'c': 3}
|
||||||
|
assert remove_keys_from_dict(keys, adict) == exp
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unitslow
|
@pytest.mark.unitslow
|
||||||
def test_Timeout_not_found():
|
def test_Timeout_not_found():
|
||||||
"""Test Timeout()"""
|
"""Test Timeout()"""
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ from pubsub import pub
|
|||||||
|
|
||||||
from pytap2 import TapDevice
|
from pytap2 import TapDevice
|
||||||
|
|
||||||
from . import portnums_pb2
|
from meshtastic import portnums_pb2
|
||||||
from .util import ipstr, readnet_u16
|
from meshtastic.util import ipstr, readnet_u16
|
||||||
from .globals import Globals
|
from meshtastic.globals import Globals
|
||||||
|
|
||||||
|
|
||||||
def onTunnelReceive(packet, interface):
|
def onTunnelReceive(packet, interface):
|
||||||
|
|||||||
@@ -204,12 +204,18 @@ def support_info():
|
|||||||
|
|
||||||
|
|
||||||
def remove_keys_from_dict(keys, adict):
|
def remove_keys_from_dict(keys, adict):
|
||||||
"""Return a dictionary without some keys in it."""
|
"""Return a dictionary without some keys in it.
|
||||||
newdict = adict
|
Will removed nested keys.
|
||||||
|
"""
|
||||||
for key in keys:
|
for key in keys:
|
||||||
if key in adict:
|
try:
|
||||||
del newdict[key]
|
del adict[key]
|
||||||
return newdict
|
except:
|
||||||
|
pass
|
||||||
|
for val in adict.values():
|
||||||
|
if isinstance(val, dict):
|
||||||
|
remove_keys_from_dict(keys, val)
|
||||||
|
return adict
|
||||||
|
|
||||||
|
|
||||||
def hexstr(barray):
|
def hexstr(barray):
|
||||||
|
|||||||
2
proto
2
proto
Submodule proto updated: 1d3b4806ab...7b80bde421
5
setup.py
5
setup.py
@@ -12,7 +12,7 @@ with open("README.md", "r") as fh:
|
|||||||
# This call to setup() does all the work
|
# This call to setup() does all the work
|
||||||
setup(
|
setup(
|
||||||
name="meshtastic",
|
name="meshtastic",
|
||||||
version="1.2.49",
|
version="1.2.52",
|
||||||
description="Python API & client shell for talking to Meshtastic devices",
|
description="Python API & client shell for talking to Meshtastic devices",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
@@ -23,7 +23,10 @@ setup(
|
|||||||
classifiers=[
|
classifiers=[
|
||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.6",
|
||||||
"Programming Language :: Python :: 3.7",
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
],
|
],
|
||||||
packages=["meshtastic"],
|
packages=["meshtastic"],
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
|
|||||||
Reference in New Issue
Block a user