|
14 | 14 | from typing import Any, Callable, Dict, List, Optional, Union |
15 | 15 |
|
16 | 16 | import google.protobuf.json_format |
17 | | -import timeago # type: ignore[import-untyped] |
18 | 17 | from pubsub import pub # type: ignore[import-untyped] |
19 | 18 | from tabulate import tabulate |
20 | 19 |
|
|
42 | 41 | ) |
43 | 42 |
|
44 | 43 |
|
| 44 | +def _timeago(delta_secs: int) -> str: |
| 45 | + """Convert a number of seconds in the past into a short, friendly string |
| 46 | + e.g. "now", "30 sec ago", "1 hour ago" |
| 47 | + Zero or negative intervals simply return "now" |
| 48 | + """ |
| 49 | + intervals = ( |
| 50 | + ("year", 60 * 60 * 24 * 365), |
| 51 | + ("month", 60 * 60 * 24 * 30), |
| 52 | + ("day", 60 * 60 * 24), |
| 53 | + ("hour", 60 * 60), |
| 54 | + ("min", 60), |
| 55 | + ("sec", 1), |
| 56 | + ) |
| 57 | + for name, interval_duration in intervals: |
| 58 | + if delta_secs < interval_duration: |
| 59 | + continue |
| 60 | + x = delta_secs // interval_duration |
| 61 | + plur = "s" if x > 1 else "" |
| 62 | + return f"{x} {name}{plur} ago" |
| 63 | + |
| 64 | + return "now" |
| 65 | + |
| 66 | + |
45 | 67 | class MeshInterface: # pylint: disable=R0902 |
46 | 68 | """Interface class for meshtastic devices |
47 | 69 |
|
@@ -158,11 +180,13 @@ def getLH(ts) -> Optional[str]: |
158 | 180 |
|
159 | 181 | def getTimeAgo(ts) -> Optional[str]: |
160 | 182 | """Format how long ago have we heard from this node (aka timeago).""" |
161 | | - return ( |
162 | | - timeago.format(datetime.fromtimestamp(ts), datetime.now()) |
163 | | - if ts |
164 | | - else None |
165 | | - ) |
| 183 | + if ts is None: |
| 184 | + return None |
| 185 | + delta = datetime.now() - datetime.fromtimestamp(ts) |
| 186 | + delta_secs = int(delta.total_seconds()) |
| 187 | + if delta_secs < 0: |
| 188 | + return None # not handling a timestamp from the future |
| 189 | + return _timeago(delta_secs) |
166 | 190 |
|
167 | 191 | rows: List[Dict[str, Any]] = [] |
168 | 192 | if self.nodesByNum: |
|
0 commit comments