mmrelay 1.1.1__py3-none-any.whl → 1.1.2__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.
Potentially problematic release.
This version of mmrelay might be problematic. Click here for more details.
- mmrelay/__init__.py +1 -1
- mmrelay/log_utils.py +40 -48
- mmrelay/main.py +31 -11
- mmrelay/meshtastic_utils.py +71 -77
- mmrelay/tools/sample_config.yaml +13 -1
- {mmrelay-1.1.1.dist-info → mmrelay-1.1.2.dist-info}/METADATA +2 -2
- {mmrelay-1.1.1.dist-info → mmrelay-1.1.2.dist-info}/RECORD +11 -11
- {mmrelay-1.1.1.dist-info → mmrelay-1.1.2.dist-info}/WHEEL +0 -0
- {mmrelay-1.1.1.dist-info → mmrelay-1.1.2.dist-info}/entry_points.txt +0 -0
- {mmrelay-1.1.1.dist-info → mmrelay-1.1.2.dist-info}/licenses/LICENSE +0 -0
- {mmrelay-1.1.1.dist-info → mmrelay-1.1.2.dist-info}/top_level.txt +0 -0
mmrelay/__init__.py
CHANGED
mmrelay/log_utils.py
CHANGED
|
@@ -28,15 +28,52 @@ config = None
|
|
|
28
28
|
# Global variable to store the log file path
|
|
29
29
|
log_file_path = None
|
|
30
30
|
|
|
31
|
+
# Track if component debug logging has been configured
|
|
32
|
+
_component_debug_configured = False
|
|
33
|
+
|
|
34
|
+
# Component logger mapping for data-driven configuration
|
|
35
|
+
_COMPONENT_LOGGERS = {
|
|
36
|
+
"matrix_nio": ["nio", "nio.client", "nio.http", "nio.crypto"],
|
|
37
|
+
"bleak": ["bleak", "bleak.backends"],
|
|
38
|
+
"meshtastic": [
|
|
39
|
+
"meshtastic",
|
|
40
|
+
"meshtastic.serial_interface",
|
|
41
|
+
"meshtastic.tcp_interface",
|
|
42
|
+
"meshtastic.ble_interface",
|
|
43
|
+
],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def configure_component_debug_logging():
|
|
48
|
+
"""
|
|
49
|
+
Enables debug-level logging for selected external components based on configuration settings.
|
|
50
|
+
|
|
51
|
+
This function sets the log level to DEBUG for specific libraries (matrix_nio, bleak, meshtastic) if enabled in the global configuration under `logging.debug`. It ensures that component debug logging is configured only once per application run.
|
|
52
|
+
"""
|
|
53
|
+
global _component_debug_configured, config
|
|
54
|
+
|
|
55
|
+
# Only configure once
|
|
56
|
+
if _component_debug_configured or config is None:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
debug_config = config.get("logging", {}).get("debug", {})
|
|
60
|
+
|
|
61
|
+
for component, loggers in _COMPONENT_LOGGERS.items():
|
|
62
|
+
if debug_config.get(component, False):
|
|
63
|
+
for logger_name in loggers:
|
|
64
|
+
logging.getLogger(logger_name).setLevel(logging.DEBUG)
|
|
65
|
+
|
|
66
|
+
_component_debug_configured = True
|
|
67
|
+
|
|
31
68
|
|
|
32
69
|
def get_logger(name):
|
|
33
70
|
"""
|
|
34
|
-
Create and configure a logger with console and optional file output,
|
|
71
|
+
Create and configure a logger with console and optional rotating file output, using global configuration and command-line arguments.
|
|
35
72
|
|
|
36
|
-
The logger
|
|
73
|
+
The logger supports colorized console output via Rich if enabled, and writes logs to a rotating file if configured or requested via command-line arguments. Log file location and rotation parameters are determined by priority: command-line argument, configuration file, or a default directory. The function ensures the log directory exists and stores the log file path globally if the logger name is "M<>M Relay".
|
|
37
74
|
|
|
38
75
|
Parameters:
|
|
39
|
-
name (str): The name of the logger to create.
|
|
76
|
+
name (str): The name of the logger to create and configure.
|
|
40
77
|
|
|
41
78
|
Returns:
|
|
42
79
|
logging.Logger: The configured logger instance.
|
|
@@ -145,48 +182,3 @@ def get_logger(name):
|
|
|
145
182
|
logger.addHandler(file_handler)
|
|
146
183
|
|
|
147
184
|
return logger
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def setup_upstream_logging_capture():
|
|
151
|
-
"""
|
|
152
|
-
Redirects warning and error log messages from upstream libraries and the root logger into the application's formatted logging system.
|
|
153
|
-
|
|
154
|
-
This ensures that log output from external dependencies (such as "meshtastic", "bleak", and "asyncio") appears with consistent formatting alongside the application's own logs. Only messages at WARNING level or higher are captured, and messages originating from the application's own loggers are excluded to prevent recursion.
|
|
155
|
-
"""
|
|
156
|
-
# Get our main logger
|
|
157
|
-
main_logger = get_logger("Upstream")
|
|
158
|
-
|
|
159
|
-
# Create a custom handler that redirects root logger messages
|
|
160
|
-
class UpstreamLogHandler(logging.Handler):
|
|
161
|
-
def emit(self, record):
|
|
162
|
-
# Skip if this is already from our logger to avoid recursion
|
|
163
|
-
"""
|
|
164
|
-
Redirects log records from external sources to the main logger, mapping their severity and prefixing with the original logger name.
|
|
165
|
-
|
|
166
|
-
Skips records originating from the application's own loggers to prevent recursion.
|
|
167
|
-
"""
|
|
168
|
-
if record.name.startswith("mmrelay") or record.name == "Upstream":
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
# Map the log level and emit through our logger
|
|
172
|
-
if record.levelno >= logging.ERROR:
|
|
173
|
-
main_logger.error(f"[{record.name}] {record.getMessage()}")
|
|
174
|
-
elif record.levelno >= logging.WARNING:
|
|
175
|
-
main_logger.warning(f"[{record.name}] {record.getMessage()}")
|
|
176
|
-
elif record.levelno >= logging.INFO:
|
|
177
|
-
main_logger.info(f"[{record.name}] {record.getMessage()}")
|
|
178
|
-
else:
|
|
179
|
-
main_logger.debug(f"[{record.name}] {record.getMessage()}")
|
|
180
|
-
|
|
181
|
-
# Add our handler to the root logger
|
|
182
|
-
root_logger = logging.getLogger()
|
|
183
|
-
upstream_handler = UpstreamLogHandler()
|
|
184
|
-
upstream_handler.setLevel(logging.WARNING) # Only capture warnings and errors
|
|
185
|
-
root_logger.addHandler(upstream_handler)
|
|
186
|
-
|
|
187
|
-
# Also set up specific loggers for known upstream libraries
|
|
188
|
-
for logger_name in ["meshtastic", "bleak", "asyncio"]:
|
|
189
|
-
upstream_logger = logging.getLogger(logger_name)
|
|
190
|
-
upstream_logger.addHandler(upstream_handler)
|
|
191
|
-
upstream_logger.setLevel(logging.WARNING)
|
|
192
|
-
upstream_logger.propagate = False # Prevent duplicate messages via root logger
|
mmrelay/main.py
CHANGED
|
@@ -4,6 +4,7 @@ It uses Meshtastic-python and Matrix nio client library to interface with the ra
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import asyncio
|
|
7
|
+
import concurrent.futures
|
|
7
8
|
import logging
|
|
8
9
|
import signal
|
|
9
10
|
import sys
|
|
@@ -20,7 +21,7 @@ from mmrelay.db_utils import (
|
|
|
20
21
|
update_shortnames,
|
|
21
22
|
wipe_message_map,
|
|
22
23
|
)
|
|
23
|
-
from mmrelay.log_utils import get_logger
|
|
24
|
+
from mmrelay.log_utils import get_logger
|
|
24
25
|
from mmrelay.matrix_utils import connect_matrix, join_matrix_room
|
|
25
26
|
from mmrelay.matrix_utils import logger as matrix_logger
|
|
26
27
|
from mmrelay.matrix_utils import on_room_member, on_room_message
|
|
@@ -50,12 +51,9 @@ def print_banner():
|
|
|
50
51
|
|
|
51
52
|
async def main(config):
|
|
52
53
|
"""
|
|
53
|
-
|
|
54
|
+
Run the main asynchronous relay loop, managing connections between Meshtastic and Matrix, event handling, and graceful shutdown.
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
Parameters:
|
|
58
|
-
config: The loaded configuration dictionary containing Matrix, Meshtastic, and database settings.
|
|
56
|
+
Initializes the database, loads plugins, connects to Meshtastic and Matrix, joins configured Matrix rooms, and registers event callbacks for message and membership events. Periodically updates node names from the Meshtastic network and manages the Matrix sync loop, handling reconnections and shutdown signals. If configured, wipes the message map on both startup and shutdown.
|
|
59
57
|
"""
|
|
60
58
|
# Extract Matrix configuration
|
|
61
59
|
from typing import List
|
|
@@ -68,9 +66,6 @@ async def main(config):
|
|
|
68
66
|
# Initialize the SQLite database
|
|
69
67
|
initialize_database()
|
|
70
68
|
|
|
71
|
-
# Set up upstream logging capture to format library messages consistently
|
|
72
|
-
setup_upstream_logging_capture()
|
|
73
|
-
|
|
74
69
|
# Check database config for wipe_on_restart (preferred format)
|
|
75
70
|
database_config = config.get("database", {})
|
|
76
71
|
msg_map_config = database_config.get("msg_map", {})
|
|
@@ -183,9 +178,31 @@ async def main(config):
|
|
|
183
178
|
if meshtastic_utils.meshtastic_client:
|
|
184
179
|
meshtastic_logger.info("Closing Meshtastic client...")
|
|
185
180
|
try:
|
|
186
|
-
|
|
181
|
+
# Timeout wrapper to prevent infinite hanging during shutdown
|
|
182
|
+
# The meshtastic library can sometimes hang indefinitely during close()
|
|
183
|
+
# operations, especially with BLE connections. This timeout ensures
|
|
184
|
+
# the application can shut down gracefully within 10 seconds.
|
|
185
|
+
|
|
186
|
+
def _close_meshtastic():
|
|
187
|
+
"""
|
|
188
|
+
Closes the Meshtastic client connection synchronously.
|
|
189
|
+
"""
|
|
190
|
+
meshtastic_utils.meshtastic_client.close()
|
|
191
|
+
|
|
192
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
|
193
|
+
future = executor.submit(_close_meshtastic)
|
|
194
|
+
future.result(timeout=10.0) # 10-second timeout
|
|
195
|
+
|
|
196
|
+
meshtastic_logger.info("Meshtastic client closed successfully")
|
|
197
|
+
except concurrent.futures.TimeoutError:
|
|
198
|
+
meshtastic_logger.warning(
|
|
199
|
+
"Meshtastic client close timed out - forcing shutdown"
|
|
200
|
+
)
|
|
187
201
|
except Exception as e:
|
|
188
|
-
meshtastic_logger.
|
|
202
|
+
meshtastic_logger.error(
|
|
203
|
+
f"Unexpected error during Meshtastic client close: {e}",
|
|
204
|
+
exc_info=True,
|
|
205
|
+
)
|
|
189
206
|
|
|
190
207
|
# Attempt to wipe message_map on shutdown if enabled
|
|
191
208
|
if wipe_on_restart:
|
|
@@ -264,6 +281,9 @@ def run_main(args):
|
|
|
264
281
|
set_config(db_utils, config)
|
|
265
282
|
set_config(base_plugin, config)
|
|
266
283
|
|
|
284
|
+
# Configure component debug logging now that config is available
|
|
285
|
+
log_utils.configure_component_debug_logging()
|
|
286
|
+
|
|
267
287
|
# Get config path and log file path for logging
|
|
268
288
|
from mmrelay.config import config_path
|
|
269
289
|
from mmrelay.log_utils import log_file_path
|
mmrelay/meshtastic_utils.py
CHANGED
|
@@ -47,18 +47,17 @@ reconnecting = False
|
|
|
47
47
|
shutting_down = False
|
|
48
48
|
reconnect_task = None # To keep track of the reconnect task
|
|
49
49
|
|
|
50
|
-
#
|
|
50
|
+
# Subscription flags to prevent duplicate subscriptions
|
|
51
51
|
subscribed_to_messages = False
|
|
52
52
|
subscribed_to_connection_lost = False
|
|
53
|
-
subscribed_to_connection_established = False
|
|
54
53
|
|
|
55
54
|
|
|
56
55
|
def is_running_as_service():
|
|
57
56
|
"""
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
Determine if the application is running as a systemd service.
|
|
58
|
+
|
|
60
59
|
Returns:
|
|
61
|
-
True if
|
|
60
|
+
bool: True if running under systemd (as indicated by the INVOCATION_ID environment variable or parent process), False otherwise.
|
|
62
61
|
"""
|
|
63
62
|
# Check for INVOCATION_ID environment variable (set by systemd)
|
|
64
63
|
if os.environ.get("INVOCATION_ID"):
|
|
@@ -89,16 +88,16 @@ def serial_port_exists(port_name):
|
|
|
89
88
|
|
|
90
89
|
def connect_meshtastic(passed_config=None, force_connect=False):
|
|
91
90
|
"""
|
|
92
|
-
Establishes and manages a connection to a Meshtastic device using
|
|
93
|
-
|
|
94
|
-
If a configuration is provided, updates the global configuration and Matrix room mappings.
|
|
95
|
-
|
|
91
|
+
Establishes and manages a connection to a Meshtastic device using serial, BLE, or TCP, with automatic retries and event subscriptions.
|
|
92
|
+
|
|
93
|
+
If a configuration is provided, updates the global configuration and Matrix room mappings. If already connected and not forced, returns the existing client. Handles reconnection logic with exponential backoff, verifies serial port existence, and subscribes to message and connection lost events upon successful connection.
|
|
94
|
+
|
|
96
95
|
Parameters:
|
|
97
|
-
passed_config (dict, optional): Configuration dictionary to use for the connection.
|
|
96
|
+
passed_config (dict, optional): Configuration dictionary to use for the connection.
|
|
98
97
|
force_connect (bool, optional): If True, forces a new connection even if one already exists.
|
|
99
|
-
|
|
98
|
+
|
|
100
99
|
Returns:
|
|
101
|
-
|
|
100
|
+
meshtastic_client: The connected Meshtastic client instance, or None if connection fails or shutdown is in progress.
|
|
102
101
|
"""
|
|
103
102
|
global meshtastic_client, shutting_down, config, matrix_rooms
|
|
104
103
|
if shutting_down:
|
|
@@ -203,8 +202,8 @@ def connect_meshtastic(passed_config=None, force_connect=False):
|
|
|
203
202
|
f"Connected to {nodeInfo['user']['shortName']} / {nodeInfo['user']['hwModel']}"
|
|
204
203
|
)
|
|
205
204
|
|
|
206
|
-
# Subscribe to message and connection events (only
|
|
207
|
-
global subscribed_to_messages, subscribed_to_connection_lost
|
|
205
|
+
# Subscribe to message and connection lost events (only once per application run)
|
|
206
|
+
global subscribed_to_messages, subscribed_to_connection_lost
|
|
208
207
|
if not subscribed_to_messages:
|
|
209
208
|
pub.subscribe(on_meshtastic_message, "meshtastic.receive")
|
|
210
209
|
subscribed_to_messages = True
|
|
@@ -217,13 +216,6 @@ def connect_meshtastic(passed_config=None, force_connect=False):
|
|
|
217
216
|
subscribed_to_connection_lost = True
|
|
218
217
|
logger.debug("Subscribed to meshtastic.connection.lost")
|
|
219
218
|
|
|
220
|
-
if not subscribed_to_connection_established:
|
|
221
|
-
pub.subscribe(
|
|
222
|
-
on_established_meshtastic_connection, "meshtastic.connection.established"
|
|
223
|
-
)
|
|
224
|
-
subscribed_to_connection_established = True
|
|
225
|
-
logger.debug("Subscribed to meshtastic.connection.established")
|
|
226
|
-
|
|
227
219
|
except (
|
|
228
220
|
serial.SerialException,
|
|
229
221
|
BleakDBusError,
|
|
@@ -249,13 +241,13 @@ def connect_meshtastic(passed_config=None, force_connect=False):
|
|
|
249
241
|
return meshtastic_client
|
|
250
242
|
|
|
251
243
|
|
|
252
|
-
def on_lost_meshtastic_connection(interface=None, detection_source="
|
|
244
|
+
def on_lost_meshtastic_connection(interface=None, detection_source="unknown"):
|
|
253
245
|
"""
|
|
254
|
-
Handles Meshtastic connection
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
interface: The interface
|
|
258
|
-
detection_source
|
|
246
|
+
Handles loss of Meshtastic connection by initiating a reconnection sequence unless the system is shutting down or already reconnecting.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
interface: The Meshtastic interface (optional, for compatibility)
|
|
250
|
+
detection_source: Source that detected the connection loss (for debugging)
|
|
259
251
|
"""
|
|
260
252
|
global meshtastic_client, reconnecting, shutting_down, event_loop, reconnect_task
|
|
261
253
|
with meshtastic_lock:
|
|
@@ -290,8 +282,8 @@ def on_lost_meshtastic_connection(interface=None, detection_source="detected by
|
|
|
290
282
|
async def reconnect():
|
|
291
283
|
"""
|
|
292
284
|
Asynchronously attempts to reconnect to the Meshtastic device using exponential backoff, stopping if a shutdown is initiated.
|
|
293
|
-
|
|
294
|
-
|
|
285
|
+
|
|
286
|
+
Reconnection attempts start with a 10-second delay, doubling up to a maximum of 5 minutes between attempts. If not running as a service, a progress bar is displayed during the wait. The process stops immediately if `shutting_down` is set to True or upon successful reconnection.
|
|
295
287
|
"""
|
|
296
288
|
global meshtastic_client, reconnecting, shutting_down
|
|
297
289
|
backoff_time = 10
|
|
@@ -346,23 +338,11 @@ async def reconnect():
|
|
|
346
338
|
reconnecting = False
|
|
347
339
|
|
|
348
340
|
|
|
349
|
-
def on_established_meshtastic_connection(interface=None):
|
|
350
|
-
"""
|
|
351
|
-
Callback triggered when a Meshtastic connection is successfully established.
|
|
352
|
-
|
|
353
|
-
Clears the reconnecting flag and logs the connection event.
|
|
354
|
-
"""
|
|
355
|
-
global reconnecting
|
|
356
|
-
with meshtastic_lock:
|
|
357
|
-
logger.info("Connection established (detected by library)")
|
|
358
|
-
reconnecting = False # Clear reconnecting flag when connection is confirmed
|
|
359
|
-
|
|
360
|
-
|
|
361
341
|
def on_meshtastic_message(packet, interface):
|
|
362
342
|
"""
|
|
363
|
-
Process incoming Meshtastic messages and relay them to Matrix rooms or plugins according to message type and
|
|
364
|
-
|
|
365
|
-
Handles reactions and replies by relaying them to Matrix if enabled. Normal text messages are relayed to all mapped Matrix rooms unless handled by a plugin or directed to the relay node. Non-text messages are passed to plugins for processing. Messages from unmapped channels or disabled detection sensors are
|
|
343
|
+
Process incoming Meshtastic messages and relay them to Matrix rooms or plugins according to message type and configuration.
|
|
344
|
+
|
|
345
|
+
Handles reactions and replies by relaying them to Matrix if enabled. Normal text messages are relayed to all mapped Matrix rooms unless handled by a plugin or directed to the relay node. Non-text messages are passed to plugins for processing. Messages from unmapped channels or disabled detection sensors are ignored. Ensures sender information is retrieved or stored as needed.
|
|
366
346
|
"""
|
|
367
347
|
global config, matrix_rooms
|
|
368
348
|
|
|
@@ -667,28 +647,42 @@ def on_meshtastic_message(packet, interface):
|
|
|
667
647
|
|
|
668
648
|
async def check_connection():
|
|
669
649
|
"""
|
|
670
|
-
Periodically
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
650
|
+
Periodically checks the health of the Meshtastic connection and triggers reconnection if the connection is lost.
|
|
651
|
+
|
|
652
|
+
Health checks can be enabled/disabled via configuration. When enabled, for non-BLE connections,
|
|
653
|
+
invokes `localNode.getMetadata()` at configurable intervals (default 60 seconds) to verify connectivity.
|
|
654
|
+
If the check fails or the firmware version is missing, initiates reconnection logic.
|
|
655
|
+
|
|
656
|
+
BLE connections rely on real-time disconnection detection and skip periodic health checks.
|
|
657
|
+
The function runs continuously until shutdown is requested.
|
|
658
|
+
|
|
659
|
+
Configuration:
|
|
660
|
+
health_check.enabled: Enable/disable health checks (default: true)
|
|
661
|
+
health_check.heartbeat_interval: Interval between checks in seconds (default: 60)
|
|
675
662
|
"""
|
|
676
|
-
global meshtastic_client, shutting_down, config
|
|
663
|
+
global meshtastic_client, shutting_down, config
|
|
677
664
|
|
|
678
665
|
# Check if config is available
|
|
679
666
|
if config is None:
|
|
680
667
|
logger.error("No configuration available. Cannot check connection.")
|
|
681
668
|
return
|
|
682
669
|
|
|
683
|
-
# Get heartbeat interval from config, default to 180 seconds
|
|
684
|
-
heartbeat_interval = config["meshtastic"].get("heartbeat_interval", 180)
|
|
685
670
|
connection_type = config["meshtastic"]["connection_type"]
|
|
686
671
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
)
|
|
672
|
+
# Get health check configuration
|
|
673
|
+
health_config = config["meshtastic"].get("health_check", {})
|
|
674
|
+
health_check_enabled = health_config.get("enabled", True)
|
|
675
|
+
heartbeat_interval = health_config.get("heartbeat_interval", 60)
|
|
676
|
+
|
|
677
|
+
# Support legacy heartbeat_interval configuration for backward compatibility
|
|
678
|
+
if "heartbeat_interval" in config["meshtastic"]:
|
|
679
|
+
heartbeat_interval = config["meshtastic"]["heartbeat_interval"]
|
|
680
|
+
|
|
681
|
+
# Exit early if health checks are disabled
|
|
682
|
+
if not health_check_enabled:
|
|
683
|
+
logger.info("Connection health checks are disabled in configuration")
|
|
684
|
+
return
|
|
690
685
|
|
|
691
|
-
# Track if we've logged the BLE skip message to avoid spam
|
|
692
686
|
ble_skip_logged = False
|
|
693
687
|
|
|
694
688
|
while not shutting_down:
|
|
@@ -697,13 +691,12 @@ async def check_connection():
|
|
|
697
691
|
# Skip periodic health checks to avoid duplicate reconnection attempts
|
|
698
692
|
if connection_type == "ble":
|
|
699
693
|
if not ble_skip_logged:
|
|
700
|
-
logger.info(
|
|
694
|
+
logger.info(
|
|
695
|
+
"BLE connection uses real-time disconnection detection - health checks disabled"
|
|
696
|
+
)
|
|
701
697
|
ble_skip_logged = True
|
|
702
698
|
else:
|
|
703
699
|
try:
|
|
704
|
-
logger.debug(
|
|
705
|
-
f"Checking {connection_type} connection health using getMetadata()"
|
|
706
|
-
)
|
|
707
700
|
output_capture = io.StringIO()
|
|
708
701
|
with contextlib.redirect_stdout(
|
|
709
702
|
output_capture
|
|
@@ -714,18 +707,20 @@ async def check_connection():
|
|
|
714
707
|
if "firmware_version" not in console_output:
|
|
715
708
|
raise Exception("No firmware_version in getMetadata output.")
|
|
716
709
|
|
|
717
|
-
logger.debug(f"{connection_type.capitalize()} connection healthy")
|
|
718
|
-
|
|
719
710
|
except Exception as e:
|
|
720
711
|
# Only trigger reconnection if we're not already reconnecting
|
|
721
712
|
if not reconnecting:
|
|
722
|
-
logger.
|
|
713
|
+
logger.error(
|
|
723
714
|
f"{connection_type.capitalize()} connection health check failed: {e}"
|
|
724
715
|
)
|
|
725
|
-
|
|
726
|
-
|
|
716
|
+
on_lost_meshtastic_connection(
|
|
717
|
+
interface=meshtastic_client,
|
|
718
|
+
detection_source=f"health check failed: {str(e)}",
|
|
719
|
+
)
|
|
727
720
|
else:
|
|
728
|
-
logger.debug(
|
|
721
|
+
logger.debug(
|
|
722
|
+
"Skipping reconnection trigger - already reconnecting"
|
|
723
|
+
)
|
|
729
724
|
elif reconnecting:
|
|
730
725
|
logger.debug("Skipping connection check - reconnection in progress")
|
|
731
726
|
elif not meshtastic_client:
|
|
@@ -743,21 +738,20 @@ def sendTextReply(
|
|
|
743
738
|
channelIndex: int = 0,
|
|
744
739
|
):
|
|
745
740
|
"""
|
|
746
|
-
Send a text message as a reply to a previous message.
|
|
741
|
+
Send a Meshtastic text message as a reply to a specific previous message.
|
|
747
742
|
|
|
748
|
-
|
|
749
|
-
in the Data protobuf message, which the standard sendText() method doesn't support.
|
|
743
|
+
Creates and sends a reply message by setting the `reply_id` field in the Meshtastic Data protobuf, enabling proper reply threading. Returns the sent packet with its ID populated.
|
|
750
744
|
|
|
751
|
-
|
|
752
|
-
interface: The Meshtastic interface to send through
|
|
753
|
-
text: The
|
|
754
|
-
reply_id: The ID of the message
|
|
755
|
-
destinationId:
|
|
756
|
-
wantAck: Whether to request acknowledgment
|
|
757
|
-
channelIndex:
|
|
745
|
+
Parameters:
|
|
746
|
+
interface: The Meshtastic interface to send through.
|
|
747
|
+
text (str): The message content to send.
|
|
748
|
+
reply_id (int): The ID of the message being replied to.
|
|
749
|
+
destinationId: The recipient address (defaults to broadcast).
|
|
750
|
+
wantAck (bool): Whether to request acknowledgment for the message.
|
|
751
|
+
channelIndex (int): The channel index to send the message on.
|
|
758
752
|
|
|
759
753
|
Returns:
|
|
760
|
-
The sent
|
|
754
|
+
The sent MeshPacket with its ID field populated.
|
|
761
755
|
"""
|
|
762
756
|
logger.debug(f"Sending text reply: '{text}' replying to message ID {reply_id}")
|
|
763
757
|
|
mmrelay/tools/sample_config.yaml
CHANGED
|
@@ -18,11 +18,17 @@ meshtastic:
|
|
|
18
18
|
broadcast_enabled: true # Must be set to true to enable Matrix to Meshtastic messages
|
|
19
19
|
detection_sensor: true # Must be set to true to forward messages of Meshtastic's detection sensor module
|
|
20
20
|
plugin_response_delay: 3 # Default response delay in seconds for plugins that respond on the mesh;
|
|
21
|
-
# heartbeat_interval: 180 # Interval in seconds to check connection health using getMetadata() (default: 180)
|
|
22
21
|
message_interactions: # Configure reactions and replies (both require message storage in database)
|
|
23
22
|
reactions: false # Enable reaction relaying between platforms
|
|
24
23
|
replies: false # Enable reply relaying between platforms
|
|
25
24
|
|
|
25
|
+
# Connection health monitoring configuration
|
|
26
|
+
#health_check:
|
|
27
|
+
# enabled: true # Enable/disable periodic health checks (default: true)
|
|
28
|
+
# heartbeat_interval: 60 # Interval in seconds between health checks (default: 60)
|
|
29
|
+
# # Note: BLE connections use real-time disconnection detection and skip periodic checks
|
|
30
|
+
# # Legacy: heartbeat_interval at meshtastic level still supported but deprecated
|
|
31
|
+
|
|
26
32
|
logging:
|
|
27
33
|
level: info
|
|
28
34
|
#log_to_file: true # Set to true to enable file logging
|
|
@@ -31,6 +37,12 @@ logging:
|
|
|
31
37
|
#backup_count: 1 # Keeps 1 backup as the default if omitted
|
|
32
38
|
#color_enabled: true # Set to false to disable colored console output
|
|
33
39
|
|
|
40
|
+
# Component-specific debug logging (useful for troubleshooting)
|
|
41
|
+
#debug:
|
|
42
|
+
# matrix_nio: false # Enable matrix-nio debug logging for Matrix client issues
|
|
43
|
+
# bleak: false # Enable BLE (bleak) debug logging for Bluetooth connection issues
|
|
44
|
+
# meshtastic: false # Enable meshtastic library debug logging for device communication issues
|
|
45
|
+
|
|
34
46
|
#database:
|
|
35
47
|
# path: ~/.mmrelay/data/meshtastic.sqlite # Default location
|
|
36
48
|
# msg_map: # The message map is necessary for the relay_reactions functionality. If `relay_reactions` is set to false, nothing will be saved to the message map.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mmrelay
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.2
|
|
4
4
|
Summary: Bridge between Meshtastic mesh networks and Matrix chat rooms
|
|
5
5
|
Home-page: https://github.com/geoffwhittington/meshtastic-matrix-relay
|
|
6
6
|
Author: Geoff Whittington, Jeremiah K., and contributors
|
|
@@ -173,5 +173,5 @@ See our Wiki page [Getting Started With Matrix & MM Relay](https://github.com/ge
|
|
|
173
173
|
Join us!
|
|
174
174
|
|
|
175
175
|
- Our project's room: [#mmrelay:matrix.org](https://matrix.to/#/#mmrelay:matrix.org)
|
|
176
|
-
- Part of the
|
|
176
|
+
- Part of the Meshnet Club Matrix space: [#meshnetclub:matrix.org](https://matrix.to/#/#meshnetclub:matrix.org)
|
|
177
177
|
- Public Relay Room: [#mmrelay-relay-room:matrix.org](https://matrix.to/#/#mmrelay-relay-room:matrix.org) - Where we bridge multiple meshnets. Feel free to join us, with or without a relay!
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
mmrelay/__init__.py,sha256=
|
|
1
|
+
mmrelay/__init__.py,sha256=ofK1VtDZwWBsSvfj0gcmsvkTTVHq_Go5MpGdU5NxdHM,594
|
|
2
2
|
mmrelay/cli.py,sha256=hdPTlcGsXTJC9GEUiScG7b3IFp02B3lwhqgwFpU3NsM,13835
|
|
3
3
|
mmrelay/config.py,sha256=5VZag8iSc5yLQgvwI76bbpizbtqag74cHnfXCrWHNyA,7910
|
|
4
4
|
mmrelay/config_checker.py,sha256=UnoHVTXzfdTfFkbmXv9r_Si76v-sxXLb5FOaQSOM45E,4909
|
|
5
5
|
mmrelay/db_utils.py,sha256=eTMMkYVWsmO_DkrBfnZMw4ohg_xa0S9TXJoBjRFTwzo,13590
|
|
6
|
-
mmrelay/log_utils.py,sha256=
|
|
7
|
-
mmrelay/main.py,sha256
|
|
6
|
+
mmrelay/log_utils.py,sha256=1zVHBJ5qSOG1O4cq4Ebngq9dp81vaZOEq5khulAFuuM,6611
|
|
7
|
+
mmrelay/main.py,sha256=-usvB02bl4ubwQ4obUzncV-5pKTRaplfOvvKcVNWBK8,12493
|
|
8
8
|
mmrelay/matrix_utils.py,sha256=XSOHztRrdIjFGyYt8QhGBL6nMv_6iodeYL288pG9voA,45813
|
|
9
|
-
mmrelay/meshtastic_utils.py,sha256=
|
|
9
|
+
mmrelay/meshtastic_utils.py,sha256=9H5kt7X5KXx8FvnWm4fU-CVoFq35JjE-YQC2j98Miq0,31012
|
|
10
10
|
mmrelay/plugin_loader.py,sha256=NRiXF6Ty1WD9jNXXKvzJh7kE0ba5oICXNVAfMaTPqH4,39247
|
|
11
11
|
mmrelay/setup_utils.py,sha256=N6qdScHKHEMFKDmT1l7dcLDPNTusZXPkyxrLXjFLhRI,19910
|
|
12
12
|
mmrelay/plugins/__init__.py,sha256=KVMQIXRhe0wlGj4O3IZ0vOIQRKFkfPYejHXhJL17qrc,51
|
|
@@ -25,10 +25,10 @@ mmrelay/tools/__init__.py,sha256=WFjDQjdevgg19_zT6iEoL29rvb1JPqYSd8708Jn5D7A,838
|
|
|
25
25
|
mmrelay/tools/mmrelay.service,sha256=3vqK1VbfXvVftkTrTEOan77aTHeOT36hIAL7HqJsmTg,567
|
|
26
26
|
mmrelay/tools/sample-docker-compose.yaml,sha256=vVgJrh-6l48hkj5F-52JA5tpDWPBjiPQ36CE9Pkqn44,1251
|
|
27
27
|
mmrelay/tools/sample.env,sha256=RP-o3rX3jnEIrVG2rqCZq31O1yRXou4HcGrXWLVbKKw,311
|
|
28
|
-
mmrelay/tools/sample_config.yaml,sha256=
|
|
29
|
-
mmrelay-1.1.
|
|
30
|
-
mmrelay-1.1.
|
|
31
|
-
mmrelay-1.1.
|
|
32
|
-
mmrelay-1.1.
|
|
33
|
-
mmrelay-1.1.
|
|
34
|
-
mmrelay-1.1.
|
|
28
|
+
mmrelay/tools/sample_config.yaml,sha256=57LkzZUuCFNmfLzeBn9Vs1rtZ_DLdwjWLjiH3-bN6GY,4094
|
|
29
|
+
mmrelay-1.1.2.dist-info/licenses/LICENSE,sha256=yceWauM1c0-FHxVplsD7W1-AbSeRaUNlmqT4UO1msBU,1073
|
|
30
|
+
mmrelay-1.1.2.dist-info/METADATA,sha256=OeWp6ooATRMHmJuFjpdYHtKLZioC03-GYU2ci5WnFOg,6705
|
|
31
|
+
mmrelay-1.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
32
|
+
mmrelay-1.1.2.dist-info/entry_points.txt,sha256=SJZwGUOEpQ-qx4H8UL4xKFnKeInGUaZNW1I0ddjK7Ws,45
|
|
33
|
+
mmrelay-1.1.2.dist-info/top_level.txt,sha256=B_ZLCRm7NYAmI3PipRUyHGymP-C-q16LSeMGzmqJfo4,8
|
|
34
|
+
mmrelay-1.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|