Merge branch 'meshtastic:master' into master

This commit is contained in:
Manuel
2023-03-31 10:41:10 +02:00
committed by GitHub
6 changed files with 100 additions and 4 deletions

View File

@@ -35,7 +35,7 @@ jobs:
which meshtastic
meshtastic --version
- name: Run pylint
run: pylint meshtastic examples/
run: pylint meshtastic examples/ --ignore-patterns ".*_pb2.py$"
- name: Run tests with pytest
run: pytest --cov=meshtastic
- name: Generate coverage report

View File

@@ -633,6 +633,10 @@ def onConnected(interface):
interface.getNode(args.dest).showInfo()
closeNow = True
print("")
pypi_version = meshtastic.util.check_if_newer_version()
if pypi_version:
print(f'*** A newer version v{pypi_version} is available!'
' Consider running "pip install --upgrade meshtastic" ***\n')
else:
print("Showing info of remote node is not supported.")
print("Use the '--get' command for a specific configuration (e.g. 'lora') instead.")

View File

@@ -5,6 +5,7 @@ import random
import time
import json
import logging
import collections
from typing import AnyStr
import threading
from datetime import datetime
@@ -56,6 +57,8 @@ class MeshInterface:
self.configId = None
self.gotResponse = False # used in gpio read
self.mask = None # used in gpio read and gpio watch
self.queueStatus = None
self.queue = collections.OrderedDict()
def close(self):
"""Shutdown this interface"""
@@ -509,13 +512,61 @@ class MeshInterface:
m.disconnect = True
self._sendToRadio(m)
def _queueHasFreeSpace(self):
# We never got queueStatus, maybe the firmware is old
if self.queueStatus is None:
return True
return self.queueStatus.free > 0
def _queueClaim(self):
if self.queueStatus is None:
return
self.queueStatus.free -= 1
def _sendToRadio(self, toRadio):
"""Send a ToRadio protobuf to the device"""
if self.noProto:
logging.warning(f"Not sending packet because protocol use is disabled by noProto")
else:
#logging.debug(f"Sending toRadio: {stripnl(toRadio)}")
self._sendToRadioImpl(toRadio)
if not toRadio.HasField('packet'):
# not a meshpacket -- send immediately, give queue a chance,
# this makes heartbeat trigger queue
self._sendToRadioImpl(toRadio)
else:
# meshpacket -- queue
self.queue[toRadio.packet.id] = toRadio
resentQueue = collections.OrderedDict()
while self.queue:
#logging.warn("queue: " + " ".join(f'{k:08x}' for k in self.queue))
while not self._queueHasFreeSpace():
logging.debug("Waiting for free space in TX Queue")
time.sleep(0.5)
try:
toResend = self.queue.popitem(last=False)
except KeyError:
break
packetId, packet = toResend
#logging.warn(f"packet: {packetId:08x} {packet}")
resentQueue[packetId] = packet
if packet is False:
continue
self._queueClaim()
if packet != toRadio:
logging.debug(f"Resending packet ID {packetId:08x} {packet}")
self._sendToRadioImpl(packet)
#logging.warn("resentQueue: " + " ".join(f'{k:08x}' for k in resentQueue))
for packetId, packet in resentQueue.items():
if self.queue.pop(packetId, False) is False: # Packet got acked under us
logging.debug(f"packet {packetId:08x} got acked under us")
continue
if packet:
self.queue[packetId] = packet
#logging.warn("queue + resentQueue: " + " ".join(f'{k:08x}' for k in self.queue))
def _sendToRadioImpl(self, toRadio):
"""Send a ToRadio protobuf to the device"""
@@ -528,6 +579,21 @@ class MeshInterface:
"""
self.localNode.requestChannels()
def _handleQueueStatusFromRadio(self, queueStatus):
self.queueStatus = queueStatus
logging.debug(f"TX QUEUE free {queueStatus.free} of {queueStatus.maxlen}, res = {queueStatus.res}, id = {queueStatus.mesh_packet_id:08x} ")
if queueStatus.res:
return
#logging.warn("queue: " + " ".join(f'{k:08x}' for k in self.queue))
justQueued = self.queue.pop(queueStatus.mesh_packet_id, None)
if justQueued is None and queueStatus.mesh_packet_id != 0:
self.queue[queueStatus.mesh_packet_id] = False
logging.debug(f"Reply for unexpected packet ID {queueStatus.mesh_packet_id:08x}")
#logging.warn("queue: " + " ".join(f'{k:08x}' for k in self.queue))
def _handleFromRadio(self, fromRadioBytes):
"""
Handle a packet that arrived from the radio(update model and publish events)
@@ -584,6 +650,9 @@ class MeshInterface:
elif fromRadio.HasField("packet"):
self._handlePacketFromRadio(fromRadio.packet)
elif fromRadio.HasField('queueStatus'):
self._handleQueueStatusFromRadio(fromRadio.queueStatus)
elif fromRadio.rebooted:
# Tell clients the device went away. Careful not to call the overridden
# subclass version that closes the serial port

View File

@@ -14,6 +14,8 @@ import subprocess
import serial
import serial.tools.list_ports
import pkg_resources
import requests
from meshtastic.supported_device import supported_devices
@@ -241,7 +243,11 @@ def support_info():
print(f' Encoding (stdin): {sys.stdin.encoding}')
print(f' Encoding (stdout): {sys.stdout.encoding}')
the_version = pkg_resources.get_distribution("meshtastic").version
print(f' meshtastic: v{the_version}')
pypi_version = check_if_newer_version()
if pypi_version:
print(f' meshtastic: v{the_version} (*** newer version v{pypi_version} available ***)')
else:
print(f' meshtastic: v{the_version}')
print(f' Executable: {sys.argv[0]}')
print(f' Python: {platform.python_version()} {platform.python_implementation()} {platform.python_compiler()}')
print('')
@@ -545,3 +551,19 @@ def detect_windows_port(sd):
#print(f'x:{x}')
ports.add(f'COM{x}')
return ports
def check_if_newer_version():
"""Check pip to see if we are running the latest version."""
pypi_version = None
try:
url = "https://pypi.org/pypi/meshtastic/json"
data = requests.get(url).json()
pypi_version = data["info"]["version"]
except Exception as e:
#print(f"could not get version from pypi e:{e}")
pass
act_version = pkg_resources.get_distribution("meshtastic").version
if pypi_version and pkg_resources.parse_version(pypi_version) <= pkg_resources.parse_version(act_version):
return None
return pypi_version

View File

@@ -7,6 +7,7 @@ pyqrcode
tabulate
timeago
webencodings
requests
pyparsing
twine
autopep8

View File

@@ -30,7 +30,7 @@ setup(
],
packages=["meshtastic"],
include_package_data=True,
install_requires=["pyserial>=3.4", "protobuf>=3.13.0",
install_requires=["pyserial>=3.4", "protobuf>=3.13.0", "requests>=2.25.0",
"pypubsub>=4.0.3", "dotmap>=1.3.14", "pexpect>=4.6.0", "pyqrcode>=1.2.1",
"tabulate>=0.8.9", "timeago>=1.0.15", "pyyaml",
"pygatt>=4.0.5 ; platform_system=='Linux'"],