Skip to content

Commit 8761b32

Browse files
committed
Merge remote-tracking branch 'root/master' into pr-powermon
# Conflicts: # meshtastic/mesh_interface.py # poetry.lock # pyproject.toml
2 parents 4ca9aa2 + 68836b1 commit 8761b32

File tree

6 files changed

+61
-27
lines changed

6 files changed

+61
-27
lines changed

Diff for: meshtastic/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def onConnection(interface, topic=pub.AUTO_TOPIC): # called when we (re)connect
7777

7878
import google.protobuf.json_format
7979
import serial # type: ignore[import-untyped]
80-
import timeago # type: ignore[import-untyped]
80+
from dotmap import DotMap # type: ignore[import-untyped]
8181
from google.protobuf.json_format import MessageToJson
8282
from pubsub import pub # type: ignore[import-untyped]
8383
from tabulate import tabulate

Diff for: meshtastic/mesh_interface.py

+30-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from typing import Any, Callable, Dict, List, Optional, Union
1515

1616
import google.protobuf.json_format
17-
import timeago # type: ignore[import-untyped]
1817
from pubsub import pub # type: ignore[import-untyped]
1918
from tabulate import tabulate
2019

@@ -41,6 +40,29 @@
4140
message_to_json,
4241
)
4342

43+
def _timeago(delta_secs: int) -> str:
44+
"""Convert a number of seconds in the past into a short, friendly string
45+
e.g. "now", "30 sec ago", "1 hour ago"
46+
Zero or negative intervals simply return "now"
47+
"""
48+
intervals = (
49+
("year", 60 * 60 * 24 * 365),
50+
("month", 60 * 60 * 24 * 30),
51+
("day", 60 * 60 * 24),
52+
("hour", 60 * 60),
53+
("min", 60),
54+
("sec", 1),
55+
)
56+
for name, interval_duration in intervals:
57+
if delta_secs < interval_duration:
58+
continue
59+
x = delta_secs // interval_duration
60+
plur = "s" if x > 1 else ""
61+
return f"{x} {name}{plur} ago"
62+
63+
return "now"
64+
65+
4466
class MeshInterface: # pylint: disable=R0902
4567
"""Interface class for meshtastic devices
4668
@@ -172,11 +194,13 @@ def getLH(ts) -> Optional[str]:
172194

173195
def getTimeAgo(ts) -> Optional[str]:
174196
"""Format how long ago have we heard from this node (aka timeago)."""
175-
return (
176-
timeago.format(datetime.fromtimestamp(ts), datetime.now())
177-
if ts
178-
else None
179-
)
197+
if ts is None:
198+
return None
199+
delta = datetime.now() - datetime.fromtimestamp(ts)
200+
delta_secs = int(delta.total_seconds())
201+
if delta_secs < 0:
202+
return None # not handling a timestamp from the future
203+
return _timeago(delta_secs)
180204

181205
rows: List[Dict[str, Any]] = []
182206
if self.nodesByNum:

Diff for: meshtastic/tests/test_mesh_interface.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
from unittest.mock import MagicMock, patch
66

77
import pytest
8+
from hypothesis import given, strategies as st
89

910
from .. import mesh_pb2, config_pb2, BROADCAST_ADDR, LOCAL_ADDR
10-
from ..mesh_interface import MeshInterface
11+
from ..mesh_interface import MeshInterface, _timeago
1112
from ..node import Node
1213

1314
# TODO
@@ -684,3 +685,21 @@ def test_waitConnected_isConnected_timeout(capsys):
684685
out, err = capsys.readouterr()
685686
assert re.search(r"warn about something", err, re.MULTILINE)
686687
assert out == ""
688+
689+
690+
@pytest.mark.unit
691+
def test_timeago():
692+
"""Test that the _timeago function returns sane values"""
693+
assert _timeago(0) == "now"
694+
assert _timeago(1) == "1 sec ago"
695+
assert _timeago(15) == "15 secs ago"
696+
assert _timeago(333) == "5 mins ago"
697+
assert _timeago(99999) == "1 day ago"
698+
assert _timeago(9999999) == "3 months ago"
699+
assert _timeago(-999) == "now"
700+
701+
@given(seconds=st.integers())
702+
def test_timeago_fuzz(seconds):
703+
"""Fuzz _timeago to ensure it works with any integer"""
704+
val = _timeago(seconds)
705+
assert re.match(r"(now|\d+ (secs?|mins?|hours?|days?|months?|years?))", val)

Diff for: poetry.lock

+1-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: pyproject.toml

+7-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ dotmap = "^1.3.30"
1414
pexpect = "^4.9.0"
1515
pyqrcode = "^1.2.1"
1616
tabulate = "^0.9.0"
17-
timeago = "^1.0.16"
1817
webencodings = "^0.5.1"
1918
requests = "^2.31.0"
2019
pyparsing = "^3.1.2"
@@ -46,15 +45,19 @@ types-setuptools = "^69.5.0.20240423"
4645
types-pyyaml = "^6.0.12.20240311"
4746
pyarrow-stubs = "^10.0.1.7"
4847

49-
50-
51-
5248
# If you are doing power analysis you probably want these extra devtools
5349
[tool.poetry.group.analysis]
5450
optional = true
5551

5652
[tool.poetry.group.analysis.dependencies]
5753
jupyterlab = "^4.2.2"
54+
mypy = "^1.10.0"
55+
mypy-protobuf = "^3.6.0"
56+
types-protobuf = "^5.26.0.20240422"
57+
types-tabulate = "^0.9.0.20240106"
58+
types-requests = "^2.31.0.20240406"
59+
types-setuptools = "^69.5.0.20240423"
60+
types-pyyaml = "^6.0.12.20240311"
5861

5962
[tool.poetry.extras]
6063
tunnel = ["pytap2"]

Diff for: tests/hello_world.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import time
2-
3-
import meshtastic
1+
import meshtastic.serial_interface
42

53
interface = (
6-
meshtastic.SerialInterface()
4+
meshtastic.serial_interface.SerialInterface()
75
) # By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0
86
interface.sendText("hello mesh")
97
interface.close()

0 commit comments

Comments
 (0)