marilib-pkg 0.6.0__py3-none-any.whl → 0.7.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/frames.py +7 -1
- examples/mari_cloud.py +25 -7
- examples/mari_edge.py +4 -7
- examples/mari_edge_stats.py +26 -14
- examples/raspberry-pi/sense_hat_ui.py +244 -0
- marilib/__init__.py +1 -1
- marilib/communication_adapter.py +4 -3
- marilib/logger.py +41 -23
- marilib/mari_protocol.py +204 -0
- marilib/marilib_cloud.py +15 -3
- marilib/marilib_edge.py +57 -47
- marilib/metrics.py +141 -0
- marilib/model.py +221 -38
- marilib/pdr.py +99 -0
- marilib/serial_uart.py +7 -6
- marilib/tui_cloud.py +26 -1
- marilib/tui_edge.py +152 -44
- {marilib_pkg-0.6.0.dist-info → marilib_pkg-0.7.0rc1.dist-info}/METADATA +25 -3
- marilib_pkg-0.7.0rc1.dist-info/RECORD +33 -0
- marilib_pkg-0.7.0rc1.dist-info/entry_points.txt +2 -0
- marilib/latency.py +0 -78
- marilib_pkg-0.6.0.dist-info/RECORD +0 -30
- {marilib_pkg-0.6.0.dist-info → marilib_pkg-0.7.0rc1.dist-info}/WHEEL +0 -0
- {marilib_pkg-0.6.0.dist-info → marilib_pkg-0.7.0rc1.dist-info}/licenses/AUTHORS +0 -0
- {marilib_pkg-0.6.0.dist-info → marilib_pkg-0.7.0rc1.dist-info}/licenses/LICENSE +0 -0
marilib/tui_edge.py
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
+
from __future__ import annotations
|
1
2
|
from datetime import datetime, timedelta
|
3
|
+
from typing import TYPE_CHECKING
|
2
4
|
|
3
5
|
from rich.columns import Columns
|
4
6
|
from rich.console import Console, Group
|
@@ -8,10 +10,12 @@ from rich.panel import Panel
|
|
8
10
|
from rich.table import Table
|
9
11
|
from rich.text import Text
|
10
12
|
|
11
|
-
from marilib import MarilibEdge
|
12
13
|
from marilib.model import MariNode, TestState
|
13
14
|
from marilib.tui import MarilibTUI
|
14
15
|
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from marilib.marilib_edge import MarilibEdge
|
18
|
+
|
15
19
|
|
16
20
|
class MarilibTUIEdge(MarilibTUI):
|
17
21
|
"""A Text-based User Interface for MarilibEdge."""
|
@@ -36,7 +40,7 @@ class MarilibTUIEdge(MarilibTUI):
|
|
36
40
|
available_height = terminal_height - 10 - 2 - 2 - 1 - 2
|
37
41
|
return max(2, available_height)
|
38
42
|
|
39
|
-
def render(self, mari: MarilibEdge):
|
43
|
+
def render(self, mari: "MarilibEdge"):
|
40
44
|
"""Render the TUI layout."""
|
41
45
|
with mari.lock:
|
42
46
|
if datetime.now() - self.last_render_time < timedelta(seconds=self.re_render_max_freq):
|
@@ -49,64 +53,113 @@ class MarilibTUIEdge(MarilibTUI):
|
|
49
53
|
)
|
50
54
|
self.live.update(layout, refresh=True)
|
51
55
|
|
52
|
-
def create_header_panel(self, mari: MarilibEdge) -> Panel:
|
56
|
+
def create_header_panel(self, mari: "MarilibEdge") -> Panel:
|
53
57
|
"""Create the header panel with gateway and network stats."""
|
54
58
|
status = Text()
|
55
|
-
|
59
|
+
|
60
|
+
# UART Status Line
|
61
|
+
status.append("UART: ", style="bold cyan")
|
56
62
|
status.append(
|
57
63
|
"connected" if mari.serial_connected else "disconnected",
|
58
64
|
style="bold green" if mari.serial_connected else "bold red",
|
59
65
|
)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
status.append(" | ")
|
66
|
+
if mari.serial_connected:
|
67
|
+
status.append(
|
68
|
+
f" via {mari.serial_interface.port} at {mari.serial_interface.baudrate} baud "
|
69
|
+
)
|
65
70
|
secs = int((datetime.now() - mari.last_received_serial_data_ts).total_seconds())
|
66
71
|
status.append(
|
67
|
-
f"last
|
72
|
+
f"(last: {secs}s ago)",
|
68
73
|
style="bold green" if secs <= 1 else "bold red",
|
69
74
|
)
|
70
75
|
|
76
|
+
status.append(" | ")
|
77
|
+
|
78
|
+
# MQTT Status Line
|
79
|
+
status.append("MQTT: ", style="bold cyan")
|
80
|
+
if mari.uses_mqtt:
|
81
|
+
status.append(
|
82
|
+
"connected" if mari.mqtt_connected else "disconnected",
|
83
|
+
style="bold green" if mari.mqtt_connected else "bold red",
|
84
|
+
)
|
85
|
+
if mari.mqtt_connected:
|
86
|
+
status.append(f" to {mari.mqtt_interface.host}:{mari.mqtt_interface.port} ")
|
87
|
+
mqtt_secs = int((datetime.now() - mari.last_received_mqtt_data_ts).total_seconds())
|
88
|
+
status.append(
|
89
|
+
f"(last: {mqtt_secs}s ago)",
|
90
|
+
style="bold green" if mqtt_secs <= 1 else "bold red",
|
91
|
+
)
|
92
|
+
else:
|
93
|
+
status.append("disabled", style="bold yellow")
|
94
|
+
|
71
95
|
status.append("\n\nGateway: ", style="bold cyan")
|
72
96
|
status.append(f"0x{mari.gateway.info.address:016X} | ")
|
73
97
|
status.append("Network ID: ", style="bold cyan")
|
74
98
|
status.append(f"0x{mari.gateway.info.network_id:04X} | ")
|
99
|
+
status.append("ASN: ", style="bold cyan")
|
100
|
+
status.append(f"{mari.gateway.info.asn:020d}")
|
75
101
|
|
76
102
|
status.append("\n\n")
|
77
103
|
status.append("Schedule: ", style="bold cyan")
|
78
|
-
status.append(f"#{mari.gateway.info.schedule_id}
|
104
|
+
status.append(f"#{mari.gateway.info.schedule_id} {mari.gateway.info.schedule_name} | ")
|
105
|
+
status.append(f"{len(mari.gateway.nodes)} / {mari.gateway.info.max_nodes} nodes | ")
|
79
106
|
status.append(mari.gateway.info.repr_schedule_cells_with_colors())
|
80
|
-
status.append("\n\n")
|
81
107
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
108
|
+
# --- Latency and PDR Display ---
|
109
|
+
avg_latency_edge = mari.gateway.stats_avg_latency_roundtrip_node_edge_ms()
|
110
|
+
has_latency_info = avg_latency_edge > 0
|
111
|
+
|
112
|
+
# Check if we have PDR info by looking at the gateway averages
|
113
|
+
avg_uart_pdr_up = mari.gateway.stats_avg_pdr_uplink_uart()
|
114
|
+
avg_uart_pdr_down = mari.gateway.stats_avg_pdr_downlink_uart()
|
115
|
+
has_uart_pdr_info = avg_uart_pdr_up > 0 or avg_uart_pdr_down > 0
|
116
|
+
|
117
|
+
avg_radio_pdr_down = mari.gateway.stats_avg_pdr_downlink_radio()
|
118
|
+
avg_radio_pdr_up = mari.gateway.stats_avg_pdr_uplink_radio()
|
119
|
+
has_radio_pdr_info = avg_radio_pdr_down > 0 or avg_radio_pdr_up > 0
|
120
|
+
|
121
|
+
pdr_info = " | PDR:" if has_uart_pdr_info or has_radio_pdr_info else ""
|
122
|
+
radio_pdr_info = (
|
123
|
+
f" Radio ↓ {avg_radio_pdr_down:.1%} ↑ {avg_radio_pdr_up:.1%}"
|
124
|
+
if has_radio_pdr_info
|
125
|
+
else ""
|
126
|
+
)
|
127
|
+
uart_pdr_info = (
|
128
|
+
f" UART ↓ {avg_uart_pdr_down:.1%} ↑ {avg_uart_pdr_up:.1%}" if has_uart_pdr_info else ""
|
129
|
+
)
|
130
|
+
|
131
|
+
if has_latency_info or has_uart_pdr_info or has_radio_pdr_info:
|
132
|
+
status.append("\n\n")
|
133
|
+
|
134
|
+
# Display Latency
|
135
|
+
if has_latency_info:
|
136
|
+
status.append("Latency: ", style="bold yellow")
|
137
|
+
status.append(f"Avg: {avg_latency_edge:.1f}ms")
|
138
|
+
|
139
|
+
# Display PDR
|
140
|
+
status.append(f"{pdr_info}{radio_pdr_info}{uart_pdr_info}")
|
89
141
|
|
90
142
|
status.append("\n\nStats: ", style="bold yellow")
|
91
143
|
if self.test_state and self.test_state.load > 0 and self.test_state.rate > 0:
|
92
144
|
status.append(
|
93
145
|
"Test load: ",
|
94
|
-
# style="bold yellow",
|
95
146
|
)
|
96
147
|
status.append(f"{self.test_state.load}% of {self.test_state.rate} pps")
|
97
148
|
status.append(" | ")
|
98
149
|
|
99
150
|
stats = mari.gateway.stats
|
100
|
-
status.append(f"
|
101
|
-
status.append(f"Frames
|
102
|
-
status.append(f"
|
103
|
-
status.append(f"
|
104
|
-
status.append(f"RX/s: {stats.received_count(1, include_test_packets=False)}")
|
151
|
+
status.append(f"Frames TX: {stats.sent_count(include_test_packets=True)} | ")
|
152
|
+
status.append(f"Frames RX: {stats.received_count(include_test_packets=True)} | ")
|
153
|
+
status.append(f"TX/s: {stats.sent_count(1, include_test_packets=True)} | ")
|
154
|
+
status.append(f"RX/s: {stats.received_count(1, include_test_packets=True)}")
|
105
155
|
|
106
|
-
return Panel(
|
156
|
+
return Panel(
|
157
|
+
status,
|
158
|
+
title=f"[bold]MariEdge running since {mari.started_ts.strftime('%Y-%m-%d %H:%M:%S')}",
|
159
|
+
border_style="blue",
|
160
|
+
)
|
107
161
|
|
108
162
|
def create_nodes_table(self, nodes: list[MariNode], title="") -> Table:
|
109
|
-
"""Create a table displaying information about connected nodes."""
|
110
163
|
table = Table(
|
111
164
|
show_header=True,
|
112
165
|
header_style="bold cyan",
|
@@ -116,33 +169,88 @@ class MarilibTUIEdge(MarilibTUI):
|
|
116
169
|
)
|
117
170
|
table.add_column("Node Address", style="cyan")
|
118
171
|
table.add_column("TX", justify="right")
|
119
|
-
table.add_column("
|
172
|
+
table.add_column("/s", justify="right")
|
120
173
|
table.add_column("RX", justify="right")
|
121
|
-
table.add_column("
|
122
|
-
table.add_column("
|
123
|
-
table.add_column("PDR
|
124
|
-
table.add_column("PDR
|
125
|
-
table.add_column("
|
126
|
-
|
174
|
+
table.add_column("/s", justify="right")
|
175
|
+
table.add_column("Radio ↓ PDR | RSSI", justify="center")
|
176
|
+
table.add_column("Radio ↑ PDR | RSSI", justify="center")
|
177
|
+
table.add_column("UART PDR ↓ | ↑", justify="center")
|
178
|
+
table.add_column("Latency", justify="center")
|
179
|
+
|
127
180
|
for node in nodes:
|
128
181
|
lat_str = (
|
129
|
-
f"{node.
|
182
|
+
f"{node.stats_avg_latency_roundtrip_node_edge_ms():.1f} ms"
|
183
|
+
if node.stats_avg_latency_roundtrip_node_edge_ms() > 0
|
184
|
+
else "..."
|
130
185
|
)
|
186
|
+
# PDR Downlink with color coding
|
187
|
+
if node.stats_pdr_downlink_radio() > 0:
|
188
|
+
if node.stats_pdr_downlink_radio() > 0.9:
|
189
|
+
pdr_down_str = f"[white]{node.stats_pdr_downlink_radio():>4.0%}[/white]"
|
190
|
+
elif node.stats_pdr_downlink_radio() > 0.8:
|
191
|
+
pdr_down_str = f"[yellow]{node.stats_pdr_downlink_radio():>4.0%}[/yellow]"
|
192
|
+
else:
|
193
|
+
pdr_down_str = f"[red]{node.stats_pdr_downlink_radio():>4.0%}[/red]"
|
194
|
+
else:
|
195
|
+
pdr_down_str = "..."
|
196
|
+
|
197
|
+
# PDR Uplink with color coding
|
198
|
+
if node.stats_pdr_uplink_radio() > 0:
|
199
|
+
if node.stats_pdr_uplink_radio() > 0.9:
|
200
|
+
pdr_up_str = f"[white]{node.stats_pdr_uplink_radio():>4.0%}[/white]"
|
201
|
+
elif node.stats_pdr_uplink_radio() > 0.8:
|
202
|
+
pdr_up_str = f"[yellow]{node.stats_pdr_uplink_radio():>4.0%}[/yellow]"
|
203
|
+
else:
|
204
|
+
pdr_up_str = f"[red]{node.stats_pdr_uplink_radio():>4.0%}[/red]"
|
205
|
+
else:
|
206
|
+
pdr_up_str = "..."
|
207
|
+
|
208
|
+
# PDR UART Up / Down with color coding
|
209
|
+
if node.stats_pdr_downlink_uart() > 0:
|
210
|
+
if node.stats_pdr_downlink_uart() > 0.9:
|
211
|
+
pdr_down_gw_edge_str = f"[white]{node.stats_pdr_downlink_uart():>4.0%}[/white]"
|
212
|
+
elif node.stats_pdr_downlink_uart() > 0.8:
|
213
|
+
pdr_down_gw_edge_str = (
|
214
|
+
f"[yellow]{node.stats_pdr_downlink_uart():>4.0%}[/yellow]"
|
215
|
+
)
|
216
|
+
else:
|
217
|
+
pdr_down_gw_edge_str = f"[red]{node.stats_pdr_downlink_uart():>4.0%}[/red]"
|
218
|
+
else:
|
219
|
+
pdr_down_gw_edge_str = "..."
|
220
|
+
|
221
|
+
if node.stats_pdr_uplink_uart() > 0:
|
222
|
+
if node.stats_pdr_uplink_uart() > 0.9:
|
223
|
+
pdr_up_gw_edge_str = f"[white]{node.stats_pdr_uplink_uart():>4.0%}[/white]"
|
224
|
+
elif node.stats_pdr_uplink_uart() > 0.8:
|
225
|
+
pdr_up_gw_edge_str = f"[yellow]{node.stats_pdr_uplink_uart():>4.0%}[/yellow]"
|
226
|
+
else:
|
227
|
+
pdr_up_gw_edge_str = f"[red]{node.stats_pdr_uplink_uart():>4.0%}[/red]"
|
228
|
+
else:
|
229
|
+
pdr_up_gw_edge_str = "..."
|
230
|
+
|
231
|
+
rssi_node_str = (
|
232
|
+
f"{node.stats_rssi_node_dbm():.0f}"
|
233
|
+
if node.stats_rssi_node_dbm() is not None
|
234
|
+
else "..."
|
235
|
+
)
|
236
|
+
rssi_gw_str = (
|
237
|
+
f"{node.stats_rssi_gw_dbm():.0f}" if node.stats_rssi_gw_dbm() is not None else "..."
|
238
|
+
)
|
239
|
+
|
131
240
|
table.add_row(
|
132
241
|
f"0x{node.address:016X}",
|
133
|
-
str(node.stats.sent_count(include_test_packets=
|
134
|
-
str(node.stats.sent_count(1, include_test_packets=
|
135
|
-
str(node.stats.received_count(include_test_packets=
|
136
|
-
str(node.stats.received_count(1, include_test_packets=
|
137
|
-
f"{
|
138
|
-
f"{
|
139
|
-
f"{
|
140
|
-
f"{node.stats.received_rssi_dbm(5)}",
|
242
|
+
str(node.stats.sent_count(include_test_packets=True)),
|
243
|
+
str(node.stats.sent_count(1, include_test_packets=True)),
|
244
|
+
str(node.stats.received_count(include_test_packets=True)),
|
245
|
+
str(node.stats.received_count(1, include_test_packets=True)),
|
246
|
+
f"{pdr_down_str} | {rssi_node_str} dBm",
|
247
|
+
f"{pdr_up_str} | {rssi_gw_str} dBm",
|
248
|
+
f"{pdr_down_gw_edge_str} | {pdr_up_gw_edge_str}",
|
141
249
|
lat_str,
|
142
250
|
)
|
143
251
|
return table
|
144
252
|
|
145
|
-
def create_nodes_panel(self, mari: MarilibEdge) -> Panel:
|
253
|
+
def create_nodes_panel(self, mari: "MarilibEdge") -> Panel:
|
146
254
|
"""Create the panel that contains the nodes table."""
|
147
255
|
nodes = mari.gateway.nodes
|
148
256
|
max_rows = self.get_max_rows()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: marilib-pkg
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.0rc1
|
4
4
|
Summary: MariLib is a Python library for interacting with the Mari network.
|
5
5
|
Project-URL: Homepage, https://github.com/DotBots/marilib
|
6
6
|
Project-URL: Bug Tracker, https://github.com/DotBots/marilib/issues
|
@@ -25,14 +25,36 @@ Description-Content-Type: text/markdown
|
|
25
25
|
# MariLib 💫 👀 🐍
|
26
26
|
|
27
27
|
MariLib is a Python library to interact with a local [Mari](https://github.com/DotBots/mari) network.
|
28
|
-
It connects to a Mari gateway via
|
28
|
+
It connects to a Mari gateway via:
|
29
|
+
- UART, using MarilibEdge
|
30
|
+
- MQTT, using MarilibCloud
|
29
31
|
|
30
32
|
## Example with TUI
|
31
33
|
MariLib provides a stateful class with gateway and node information, network statistics, and a rich real-time TUI:
|
32
34
|
|
33
35
|
[mari-edge-2.webm](https://github.com/user-attachments/assets/fe50f2ba-8e67-4522-8700-69730f8e3aee)
|
34
36
|
|
35
|
-
|
37
|
+
To run with a gateway connected via UART:
|
38
|
+
```bash
|
39
|
+
# for example, using the Inria Argus MQTT broker
|
40
|
+
(.venv) $ python examples/mari_edge.py -m mqtts://argus.paris.inria.fr:8883
|
41
|
+
```
|
42
|
+
You can see how it works using `examples/mari_edge.py --help`.
|
43
|
+
|
44
|
+
To run with a gateway connected via MQTT:
|
45
|
+
```bash
|
46
|
+
# for example, using the Inria Argus MQTT broker
|
47
|
+
(.venv) $ python examples/mari_cloud.py -n 0x0100 -m mqtts://argus.paris.inria.fr:8883
|
48
|
+
```
|
49
|
+
|
50
|
+
## Setup and dependencies
|
51
|
+
To setup the environment, do:
|
52
|
+
|
53
|
+
```bash
|
54
|
+
$ python -m venv .venv
|
55
|
+
$ source .venv/bin/activate
|
56
|
+
(.venv) $ pip install -e .
|
57
|
+
```
|
36
58
|
|
37
59
|
## Minimal example
|
38
60
|
Here is a minimal example showcasing how to use MariLib:
|
@@ -0,0 +1,33 @@
|
|
1
|
+
examples/frames.py,sha256=LQ-eWWtv3plFmNzXVVMESidkLpU54vuUir0DjGCZLPI,964
|
2
|
+
examples/mari_cloud.py,sha256=GsxnX0V1a3wcx503xTbCoQKwS6niaedG4Ne73zW_V4E,2408
|
3
|
+
examples/mari_cloud_minimal.py,sha256=zaLnd61gkqht5AclJC6Hfc1CPS_8BzTmGE-tItbWlao,1125
|
4
|
+
examples/mari_edge.py,sha256=3B6_kM3jCyO7bZhVRTlHIn4lSAOFdJhJ9Gh3qJNie-U,1875
|
5
|
+
examples/mari_edge_minimal.py,sha256=9vOsIdW9WnS_GQg9fBw_G1wkvGFokwsiM83Q8etoUpA,1090
|
6
|
+
examples/mari_edge_stats.py,sha256=0wfgZ5hJjcpX35VrtzxSRD5YYOcZtQnpXqMIteDaxbE,4719
|
7
|
+
examples/uart.py,sha256=pUvkpVf64T94XFLzgyHSzMOZISMrm0wqyurjNyS3JhY,823
|
8
|
+
examples/raspberry-pi/sense_hat_ui.py,sha256=y1Rseqs0fCK-2HuQ0yCVU9SlHBCeN4ylifjvzlqhJn0,7170
|
9
|
+
marilib/__init__.py,sha256=8Fr_Z__t3Wovz4aHwLeqVQqqK0FLAXktcIWJKKKnviw,134
|
10
|
+
marilib/communication_adapter.py,sha256=SNYDrIQqDRk5rbZJB02KTyVrFY_xJVvRu0KNEwA_qbU,7084
|
11
|
+
marilib/logger.py,sha256=UHM4v6fXl5uvporz6-No8Pe3rw60rACv2BN11h7h5vA,8867
|
12
|
+
marilib/mari_protocol.py,sha256=4gzl3v0w4i54KPBkzZ-0pF3RREjQ2thL535ocFfXxBI,10571
|
13
|
+
marilib/marilib.py,sha256=m7drdxhAMnjTrqYjUvwqunreYpffz7-AKgaOkuXHukg,939
|
14
|
+
marilib/marilib_cloud.py,sha256=s9S8YCP2_adIkdnvyh9TzJ0EvDCSQ4j1G22XXElevPA,7820
|
15
|
+
marilib/marilib_edge.py,sha256=WyQ0ItBzM5XDfnReFV4x-EQHJiplm4SiVj_AsOA5x9M,9605
|
16
|
+
marilib/metrics.py,sha256=eH3toxToZF-a-NAx5q5iRD4Qw-fi8zKC-mGFwZqd-qg,5936
|
17
|
+
marilib/model.py,sha256=oh54K7MrXXdwOfYJ7prRkkSoxhkuaroO475ZLJb4vKU,19476
|
18
|
+
marilib/pdr.py,sha256=V0J3zgneVyvikZhA-6_4Bc6Q_JxJevpb9QXs9k9Sq2I,3359
|
19
|
+
marilib/protocol.py,sha256=wOsG_oIk2Ls6gnbDYa5_g1sbHGuYgsj6liiax_yTn34,3786
|
20
|
+
marilib/serial_hdlc.py,sha256=6EDbjkJ5RU_1Gv3OhHaIhLAXscce_2-yCv-602sw2-8,8119
|
21
|
+
marilib/serial_uart.py,sha256=vc8FhUXDEV5XZ9H-cHHZR1Hk_T9z_rM_U7sj7TiOwvg,2801
|
22
|
+
marilib/tui.py,sha256=doTpHnZqyHEglSck_a1cl9DU1uTCZavVOlcZjA8aTV4,231
|
23
|
+
marilib/tui_cloud.py,sha256=Cl5V63_7RZWePd8FdmGiZd1vqdeYUxtlH5dIgIUCHiM,6866
|
24
|
+
marilib/tui_edge.py,sha256=y3jnxOZiPJ-NZW7Aar0K5d7v7lvg0RUDnksTF7rR7tc,12273
|
25
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
|
+
tests/test_hdlc.py,sha256=SSgDpdTa2ga-P5tlXZtGvjliame4Ug9FwyreSw_nT9k,2450
|
27
|
+
tests/test_protocol.py,sha256=JJRtzCV2BygogSFFmss4FwYLb7x3Zy8sIEWxzopfxNE,1167
|
28
|
+
marilib_pkg-0.7.0rc1.dist-info/METADATA,sha256=nL7jVhrdHLD3pHh3MqnuiUEweYDly1CF2iyUU1NW7Zw,2579
|
29
|
+
marilib_pkg-0.7.0rc1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
30
|
+
marilib_pkg-0.7.0rc1.dist-info/entry_points.txt,sha256=hDmlCur_i2xCiPm4GiD98fAfZBp1duLRinNwv8YO1yg,50
|
31
|
+
marilib_pkg-0.7.0rc1.dist-info/licenses/AUTHORS,sha256=gGgRHmEH6klwG7KQd4rYVy0AT8MkA9mMimfiN1NvOHU,96
|
32
|
+
marilib_pkg-0.7.0rc1.dist-info/licenses/LICENSE,sha256=j97C1uBc5chpQWi4bv_2SrqExuvKaJK2Ch6L2LFkoc4,1492
|
33
|
+
marilib_pkg-0.7.0rc1.dist-info/RECORD,,
|
marilib/latency.py
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
import struct
|
2
|
-
import threading
|
3
|
-
import time
|
4
|
-
from typing import TYPE_CHECKING
|
5
|
-
import math
|
6
|
-
|
7
|
-
from marilib.mari_protocol import Frame
|
8
|
-
|
9
|
-
if TYPE_CHECKING:
|
10
|
-
from marilib.marilib import MariLib
|
11
|
-
|
12
|
-
LATENCY_PACKET_MAGIC = b"\x4c\x54" # "LT" for Latency Test
|
13
|
-
|
14
|
-
|
15
|
-
class LatencyTester:
|
16
|
-
"""A thread-based class to periodically test latency to all nodes."""
|
17
|
-
|
18
|
-
def __init__(self, marilib: "MariLib", interval: float = 10.0):
|
19
|
-
self.marilib = marilib
|
20
|
-
self.interval = interval
|
21
|
-
self._stop_event = threading.Event()
|
22
|
-
self._thread = threading.Thread(target=self._run, daemon=True)
|
23
|
-
|
24
|
-
def start(self):
|
25
|
-
"""Starts the latency testing thread."""
|
26
|
-
print("[yellow]Latency tester started.[/]")
|
27
|
-
self._thread.start()
|
28
|
-
|
29
|
-
def stop(self):
|
30
|
-
"""Stops the latency testing thread."""
|
31
|
-
self._stop_event.set()
|
32
|
-
self._thread.join()
|
33
|
-
print("[yellow]Latency tester stopped.[/]")
|
34
|
-
|
35
|
-
def _run(self):
|
36
|
-
"""The main loop for the testing thread."""
|
37
|
-
while not self._stop_event.is_set():
|
38
|
-
if not self.marilib.gateway.nodes:
|
39
|
-
time.sleep(self.interval)
|
40
|
-
continue
|
41
|
-
|
42
|
-
for node in list(self.marilib.gateway.nodes):
|
43
|
-
if self._stop_event.is_set():
|
44
|
-
break
|
45
|
-
self.send_latency_request(node.address)
|
46
|
-
time.sleep(self.interval / len(self.marilib.gateway.nodes))
|
47
|
-
|
48
|
-
def send_latency_request(self, address: int):
|
49
|
-
"""Sends a latency request packet to a specific address."""
|
50
|
-
|
51
|
-
payload = LATENCY_PACKET_MAGIC + struct.pack("<d", time.time())
|
52
|
-
self.marilib.send_frame(address, payload)
|
53
|
-
|
54
|
-
def handle_response(self, frame: Frame):
|
55
|
-
"""
|
56
|
-
Processes a latency response frame.
|
57
|
-
This should be called when a LATENCY_DATA event is received.
|
58
|
-
"""
|
59
|
-
if not frame.payload.startswith(LATENCY_PACKET_MAGIC):
|
60
|
-
return
|
61
|
-
try:
|
62
|
-
# Unpack the original timestamp from the payload
|
63
|
-
original_ts = struct.unpack("<d", frame.payload[2:10])[0]
|
64
|
-
rtt = time.time() - original_ts
|
65
|
-
if math.isnan(rtt) or math.isinf(rtt):
|
66
|
-
return # Ignore corrupted/invalid packets
|
67
|
-
if rtt < 0 or rtt > 5.0:
|
68
|
-
return # Ignore this outlier
|
69
|
-
|
70
|
-
node = self.marilib.gateway.get_node(frame.header.source)
|
71
|
-
if node:
|
72
|
-
# Update statistics for both the specific node and the whole gateway
|
73
|
-
node.latency_stats.add_latency(rtt)
|
74
|
-
self.marilib.gateway.latency_stats.add_latency(rtt)
|
75
|
-
|
76
|
-
except (struct.error, IndexError):
|
77
|
-
# Ignore packets that are too short or malformed
|
78
|
-
pass
|
@@ -1,30 +0,0 @@
|
|
1
|
-
examples/frames.py,sha256=SSC36A66kFwL-U5HtFgAuK6_BI1ik_84EFJ7DoG0oBo,780
|
2
|
-
examples/mari_cloud.py,sha256=EQmQb6AiZt49j6bI4h9kAe8nfy6Zg5PfY0WTYKc8Kes,1860
|
3
|
-
examples/mari_cloud_minimal.py,sha256=zaLnd61gkqht5AclJC6Hfc1CPS_8BzTmGE-tItbWlao,1125
|
4
|
-
examples/mari_edge.py,sha256=VI5iv46f5ejbNn7H6A7pQjSDrdWsj3pDM6DrLos5SuI,1936
|
5
|
-
examples/mari_edge_minimal.py,sha256=9vOsIdW9WnS_GQg9fBw_G1wkvGFokwsiM83Q8etoUpA,1090
|
6
|
-
examples/mari_edge_stats.py,sha256=LQx4gtfFCp1rP0uBo1UCLg5e5eusDKsH_beoKj5_CAI,4340
|
7
|
-
examples/uart.py,sha256=pUvkpVf64T94XFLzgyHSzMOZISMrm0wqyurjNyS3JhY,823
|
8
|
-
marilib/__init__.py,sha256=PCxfi_8iZpMbc5DscErorPXqdO7qghp6t1MFU0NnYfk,130
|
9
|
-
marilib/communication_adapter.py,sha256=IEcSLm5lbtFMtFCZ784QdvZZ5zcqL1IZQ90CSSp-XvM,6998
|
10
|
-
marilib/latency.py,sha256=jz-7Yvgmk-BO40FHW_pltHbRV2OL1QD-dCkV9iSJiiY,2729
|
11
|
-
marilib/logger.py,sha256=IgkC1JM9sf3JxiSBYUcHeuYpiRrwcODVR2Y54GA2LPA,7867
|
12
|
-
marilib/mari_protocol.py,sha256=b1hQdSJX8CjPtKgosO7F-vt8ZHsnZ9QqMI2oKNL4r0E,2516
|
13
|
-
marilib/marilib.py,sha256=m7drdxhAMnjTrqYjUvwqunreYpffz7-AKgaOkuXHukg,939
|
14
|
-
marilib/marilib_cloud.py,sha256=0yPTea0J2h4EkWwTcU4QAr001srd9_P6LOPtmJmhH24,7346
|
15
|
-
marilib/marilib_edge.py,sha256=tzjeNtI_SpvghYxgV_y8j27d6xXX-1HIQc2TGKuNOg0,9743
|
16
|
-
marilib/model.py,sha256=0WAEtMxqnqziSG0epZfLXlXVAzVRNfou4n6suhtdB1k,12831
|
17
|
-
marilib/protocol.py,sha256=wOsG_oIk2Ls6gnbDYa5_g1sbHGuYgsj6liiax_yTn34,3786
|
18
|
-
marilib/serial_hdlc.py,sha256=6EDbjkJ5RU_1Gv3OhHaIhLAXscce_2-yCv-602sw2-8,8119
|
19
|
-
marilib/serial_uart.py,sha256=7sv8Ouj-y7k2Yry6cINil9WgVYvy1cRPPpIbW4JLVQo,2764
|
20
|
-
marilib/tui.py,sha256=doTpHnZqyHEglSck_a1cl9DU1uTCZavVOlcZjA8aTV4,231
|
21
|
-
marilib/tui_cloud.py,sha256=LZQVYLSwdLBubUcbUy7Eoahma_98b690ndCVgXSm_EA,5672
|
22
|
-
marilib/tui_edge.py,sha256=N2i0aUZ2zeaC0oPcCamNd5FY0wTDtmp2KWFF1yL6ABA,7573
|
23
|
-
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
-
tests/test_hdlc.py,sha256=SSgDpdTa2ga-P5tlXZtGvjliame4Ug9FwyreSw_nT9k,2450
|
25
|
-
tests/test_protocol.py,sha256=JJRtzCV2BygogSFFmss4FwYLb7x3Zy8sIEWxzopfxNE,1167
|
26
|
-
marilib_pkg-0.6.0.dist-info/METADATA,sha256=FuhL1nVncSyrIJ1mpqqReAajGZSCQcCJW-gEsQbE0h4,1992
|
27
|
-
marilib_pkg-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
28
|
-
marilib_pkg-0.6.0.dist-info/licenses/AUTHORS,sha256=gGgRHmEH6klwG7KQd4rYVy0AT8MkA9mMimfiN1NvOHU,96
|
29
|
-
marilib_pkg-0.6.0.dist-info/licenses/LICENSE,sha256=j97C1uBc5chpQWi4bv_2SrqExuvKaJK2Ch6L2LFkoc4,1492
|
30
|
-
marilib_pkg-0.6.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|