mirror of
https://github.com/meshtastic/python.git
synced 2026-01-10 00:37:55 -05:00
Merge remote-tracking branch 'root/master' into pr-powermon
# Conflicts: # meshtastic/mesh_interface.py # poetry.lock # pyproject.toml
This commit is contained in:
@@ -77,7 +77,7 @@ from typing import *
|
||||
|
||||
import google.protobuf.json_format
|
||||
import serial # type: ignore[import-untyped]
|
||||
import timeago # type: ignore[import-untyped]
|
||||
from dotmap import DotMap # type: ignore[import-untyped]
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
from pubsub import pub # type: ignore[import-untyped]
|
||||
from tabulate import tabulate
|
||||
|
||||
@@ -14,7 +14,6 @@ from decimal import Decimal
|
||||
from typing import Any, Callable, Dict, List, Optional, Union
|
||||
|
||||
import google.protobuf.json_format
|
||||
import timeago # type: ignore[import-untyped]
|
||||
from pubsub import pub # type: ignore[import-untyped]
|
||||
from tabulate import tabulate
|
||||
|
||||
@@ -41,6 +40,29 @@ from meshtastic.util import (
|
||||
message_to_json,
|
||||
)
|
||||
|
||||
def _timeago(delta_secs: int) -> str:
|
||||
"""Convert a number of seconds in the past into a short, friendly string
|
||||
e.g. "now", "30 sec ago", "1 hour ago"
|
||||
Zero or negative intervals simply return "now"
|
||||
"""
|
||||
intervals = (
|
||||
("year", 60 * 60 * 24 * 365),
|
||||
("month", 60 * 60 * 24 * 30),
|
||||
("day", 60 * 60 * 24),
|
||||
("hour", 60 * 60),
|
||||
("min", 60),
|
||||
("sec", 1),
|
||||
)
|
||||
for name, interval_duration in intervals:
|
||||
if delta_secs < interval_duration:
|
||||
continue
|
||||
x = delta_secs // interval_duration
|
||||
plur = "s" if x > 1 else ""
|
||||
return f"{x} {name}{plur} ago"
|
||||
|
||||
return "now"
|
||||
|
||||
|
||||
class MeshInterface: # pylint: disable=R0902
|
||||
"""Interface class for meshtastic devices
|
||||
|
||||
@@ -172,11 +194,13 @@ class MeshInterface: # pylint: disable=R0902
|
||||
|
||||
def getTimeAgo(ts) -> Optional[str]:
|
||||
"""Format how long ago have we heard from this node (aka timeago)."""
|
||||
return (
|
||||
timeago.format(datetime.fromtimestamp(ts), datetime.now())
|
||||
if ts
|
||||
else None
|
||||
)
|
||||
if ts is None:
|
||||
return None
|
||||
delta = datetime.now() - datetime.fromtimestamp(ts)
|
||||
delta_secs = int(delta.total_seconds())
|
||||
if delta_secs < 0:
|
||||
return None # not handling a timestamp from the future
|
||||
return _timeago(delta_secs)
|
||||
|
||||
rows: List[Dict[str, Any]] = []
|
||||
if self.nodesByNum:
|
||||
|
||||
@@ -5,9 +5,10 @@ import re
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from hypothesis import given, strategies as st
|
||||
|
||||
from .. import mesh_pb2, config_pb2, BROADCAST_ADDR, LOCAL_ADDR
|
||||
from ..mesh_interface import MeshInterface
|
||||
from ..mesh_interface import MeshInterface, _timeago
|
||||
from ..node import Node
|
||||
|
||||
# TODO
|
||||
@@ -684,3 +685,21 @@ def test_waitConnected_isConnected_timeout(capsys):
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r"warn about something", err, re.MULTILINE)
|
||||
assert out == ""
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_timeago():
|
||||
"""Test that the _timeago function returns sane values"""
|
||||
assert _timeago(0) == "now"
|
||||
assert _timeago(1) == "1 sec ago"
|
||||
assert _timeago(15) == "15 secs ago"
|
||||
assert _timeago(333) == "5 mins ago"
|
||||
assert _timeago(99999) == "1 day ago"
|
||||
assert _timeago(9999999) == "3 months ago"
|
||||
assert _timeago(-999) == "now"
|
||||
|
||||
@given(seconds=st.integers())
|
||||
def test_timeago_fuzz(seconds):
|
||||
"""Fuzz _timeago to ensure it works with any integer"""
|
||||
val = _timeago(seconds)
|
||||
assert re.match(r"(now|\d+ (secs?|mins?|hours?|days?|months?|years?))", val)
|
||||
|
||||
12
poetry.lock
generated
12
poetry.lock
generated
@@ -2863,16 +2863,6 @@ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"]
|
||||
test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"]
|
||||
typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "timeago"
|
||||
version = "1.0.16"
|
||||
description = "A very simple python library, used to format datetime with `*** time ago` statement. eg: \"3 hours ago\"."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "timeago-1.0.16-py3-none-any.whl", hash = "sha256:9b8cb2e3102b329f35a04aa4531982d867b093b19481cfbb1dac7845fa2f79b0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinycss2"
|
||||
version = "1.3.0"
|
||||
@@ -3351,4 +3341,4 @@ tunnel = []
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.9,<3.13"
|
||||
content-hash = "f5f6125129dc3a7a3b1eb805a0315d0ff6db80eca9fd96a77429b034a1f47bc7"
|
||||
content-hash = "c06a63c0dc330add8ff30c22a1c351f31e90a3cdb71afce7ce4644feb48c1038"
|
||||
|
||||
@@ -14,7 +14,6 @@ dotmap = "^1.3.30"
|
||||
pexpect = "^4.9.0"
|
||||
pyqrcode = "^1.2.1"
|
||||
tabulate = "^0.9.0"
|
||||
timeago = "^1.0.16"
|
||||
webencodings = "^0.5.1"
|
||||
requests = "^2.31.0"
|
||||
pyparsing = "^3.1.2"
|
||||
@@ -46,15 +45,19 @@ types-setuptools = "^69.5.0.20240423"
|
||||
types-pyyaml = "^6.0.12.20240311"
|
||||
pyarrow-stubs = "^10.0.1.7"
|
||||
|
||||
|
||||
|
||||
|
||||
# If you are doing power analysis you probably want these extra devtools
|
||||
[tool.poetry.group.analysis]
|
||||
optional = true
|
||||
|
||||
[tool.poetry.group.analysis.dependencies]
|
||||
jupyterlab = "^4.2.2"
|
||||
mypy = "^1.10.0"
|
||||
mypy-protobuf = "^3.6.0"
|
||||
types-protobuf = "^5.26.0.20240422"
|
||||
types-tabulate = "^0.9.0.20240106"
|
||||
types-requests = "^2.31.0.20240406"
|
||||
types-setuptools = "^69.5.0.20240423"
|
||||
types-pyyaml = "^6.0.12.20240311"
|
||||
|
||||
[tool.poetry.extras]
|
||||
tunnel = ["pytap2"]
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import time
|
||||
|
||||
import meshtastic
|
||||
import meshtastic.serial_interface
|
||||
|
||||
interface = (
|
||||
meshtastic.SerialInterface()
|
||||
meshtastic.serial_interface.SerialInterface()
|
||||
) # By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0
|
||||
interface.sendText("hello mesh")
|
||||
interface.close()
|
||||
|
||||
Reference in New Issue
Block a user