mmrelay 1.1.0__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 CHANGED
@@ -14,4 +14,4 @@ else:
14
14
  __version__ = version("mmrelay")
15
15
  except PackageNotFoundError:
16
16
  # If all else fails, use hardcoded version
17
- __version__ = "1.1.0"
17
+ __version__ = "1.1.2"
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, supporting colorized output and log rotation.
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's level, color usage, and file logging behavior are determined by global configuration and command line arguments. Console output uses rich formatting if enabled. File logging supports log rotation and stores logs in a configurable or default location. The log file path is stored globally if the logger name is "M<>M Relay".
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, setup_upstream_logging_capture
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
- Sets up and runs the asynchronous relay between Meshtastic and Matrix, managing connections, event handling, and graceful shutdown.
54
+ Run the main asynchronous relay loop, managing connections between Meshtastic and Matrix, event handling, and graceful shutdown.
54
55
 
55
- This function initializes the database, configures logging, loads plugins, connects to both Meshtastic and Matrix, joins specified Matrix rooms, and registers event callbacks for message and membership events. It periodically updates node names from the Meshtastic network and manages the Matrix sync loop, handling reconnections and shutdown signals. If configured, it wipes the message map on startup and shutdown.
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
- meshtastic_utils.meshtastic_client.close()
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.warning(f"Error closing Meshtastic client: {e}")
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
@@ -47,7 +47,7 @@ reconnecting = False
47
47
  shutting_down = False
48
48
  reconnect_task = None # To keep track of the reconnect task
49
49
 
50
- # Track pubsub subscription state to prevent duplicate subscriptions during reconnections
50
+ # Subscription flags to prevent duplicate subscriptions
51
51
  subscribed_to_messages = False
52
52
  subscribed_to_connection_lost = False
53
53
 
@@ -57,7 +57,7 @@ def is_running_as_service():
57
57
  Determine if the application is running as a systemd service.
58
58
 
59
59
  Returns:
60
- bool: True if running under systemd (either via environment variable or parent process), False otherwise.
60
+ bool: True if running under systemd (as indicated by the INVOCATION_ID environment variable or parent process), False otherwise.
61
61
  """
62
62
  # Check for INVOCATION_ID environment variable (set by systemd)
63
63
  if os.environ.get("INVOCATION_ID"):
@@ -88,16 +88,16 @@ def serial_port_exists(port_name):
88
88
 
89
89
  def connect_meshtastic(passed_config=None, force_connect=False):
90
90
  """
91
- Establishes and manages a connection to a Meshtastic device using the configured connection type (serial, BLE, or TCP).
91
+ Establishes and manages a connection to a Meshtastic device using serial, BLE, or TCP, with automatic retries and event subscriptions.
92
92
 
93
- If a configuration is provided, updates the global configuration and Matrix room mappings. Handles reconnection logic, including closing any existing connection if `force_connect` is True. Retries connection attempts with exponential backoff until successful or shutdown is initiated. Subscribes to message and connection lost events only once per process to avoid duplicate subscriptions.
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
94
 
95
95
  Parameters:
96
- passed_config (dict, optional): Configuration dictionary to use for the connection. If provided, updates the global configuration.
96
+ passed_config (dict, optional): Configuration dictionary to use for the connection.
97
97
  force_connect (bool, optional): If True, forces a new connection even if one already exists.
98
98
 
99
99
  Returns:
100
- Meshtastic interface client if the connection is successful, or None if the connection fails or shutdown is in progress.
100
+ meshtastic_client: The connected Meshtastic client instance, or None if connection fails or shutdown is in progress.
101
101
  """
102
102
  global meshtastic_client, shutting_down, config, matrix_rooms
103
103
  if shutting_down:
@@ -202,7 +202,7 @@ def connect_meshtastic(passed_config=None, force_connect=False):
202
202
  f"Connected to {nodeInfo['user']['shortName']} / {nodeInfo['user']['hwModel']}"
203
203
  )
204
204
 
205
- # Subscribe to message and connection lost events (only if not already subscribed)
205
+ # Subscribe to message and connection lost events (only once per application run)
206
206
  global subscribed_to_messages, subscribed_to_connection_lost
207
207
  if not subscribed_to_messages:
208
208
  pub.subscribe(on_meshtastic_message, "meshtastic.receive")
@@ -241,10 +241,13 @@ def connect_meshtastic(passed_config=None, force_connect=False):
241
241
  return meshtastic_client
242
242
 
243
243
 
244
- def on_lost_meshtastic_connection(interface=None):
244
+ def on_lost_meshtastic_connection(interface=None, detection_source="unknown"):
245
245
  """
246
- Callback invoked when the Meshtastic connection is lost.
247
- Initiates a reconnect sequence unless shutting_down is True.
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)
248
251
  """
249
252
  global meshtastic_client, reconnecting, shutting_down, event_loop, reconnect_task
250
253
  with meshtastic_lock:
@@ -257,7 +260,7 @@ def on_lost_meshtastic_connection(interface=None):
257
260
  )
258
261
  return
259
262
  reconnecting = True
260
- logger.error("Lost connection. Reconnecting...")
263
+ logger.error(f"Lost connection ({detection_source}). Reconnecting...")
261
264
 
262
265
  if meshtastic_client:
263
266
  try:
@@ -278,8 +281,9 @@ def on_lost_meshtastic_connection(interface=None):
278
281
 
279
282
  async def reconnect():
280
283
  """
281
- Asynchronously attempts to reconnect with exponential backoff.
282
- Stops if shutting_down is set.
284
+ Asynchronously attempts to reconnect to the Meshtastic device using exponential backoff, stopping if a shutdown is initiated.
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.
283
287
  """
284
288
  global meshtastic_client, reconnecting, shutting_down
285
289
  backoff_time = 10
@@ -336,9 +340,9 @@ async def reconnect():
336
340
 
337
341
  def on_meshtastic_message(packet, interface):
338
342
  """
339
- Processes incoming Meshtastic messages and relays them to Matrix rooms or plugins based on message type and interaction settings.
343
+ Process incoming Meshtastic messages and relay them to Matrix rooms or plugins according to message type and configuration.
340
344
 
341
- Handles reactions and replies by relaying them to Matrix if enabled in the interaction settings. 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. Filters out messages from unmapped channels or disabled detection sensors, and ensures sender information is retrieved or stored as needed.
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.
342
346
  """
343
347
  global config, matrix_rooms
344
348
 
@@ -643,53 +647,80 @@ def on_meshtastic_message(packet, interface):
643
647
 
644
648
  async def check_connection():
645
649
  """
646
- Periodically checks the Meshtastic connection by calling localNode.getMetadata().
647
- This creates an admin message to verify the connection is alive for all interface types.
648
- If it fails or doesn't return the firmware version, we assume the connection is lost
649
- and attempt to reconnect.
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)
650
662
  """
651
- global meshtastic_client, shutting_down, config, reconnecting
663
+ global meshtastic_client, shutting_down, config
652
664
 
653
665
  # Check if config is available
654
666
  if config is None:
655
667
  logger.error("No configuration available. Cannot check connection.")
656
668
  return
657
669
 
658
- # Get heartbeat interval from config, default to 180 seconds
659
- heartbeat_interval = config["meshtastic"].get("heartbeat_interval", 180)
660
670
  connection_type = config["meshtastic"]["connection_type"]
661
671
 
662
- logger.info(
663
- f"Starting connection heartbeat monitor (interval: {heartbeat_interval}s)"
664
- )
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)
665
676
 
666
- while not shutting_down:
667
- if meshtastic_client and not reconnecting:
668
- try:
669
- logger.debug(
670
- f"Checking {connection_type} connection health using getMetadata()"
671
- )
672
- output_capture = io.StringIO()
673
- with contextlib.redirect_stdout(
674
- output_capture
675
- ), contextlib.redirect_stderr(output_capture):
676
- meshtastic_client.localNode.getMetadata()
677
+ # Support legacy heartbeat_interval configuration for backward compatibility
678
+ if "heartbeat_interval" in config["meshtastic"]:
679
+ heartbeat_interval = config["meshtastic"]["heartbeat_interval"]
677
680
 
678
- console_output = output_capture.getvalue()
679
- if "firmware_version" not in console_output:
680
- raise Exception("No firmware_version in getMetadata output.")
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
681
685
 
682
- logger.debug(f"{connection_type.capitalize()} connection healthy")
686
+ ble_skip_logged = False
683
687
 
684
- except Exception as e:
685
- # Only trigger reconnection if we're not already reconnecting
686
- if not reconnecting:
687
- logger.warning(
688
- f"{connection_type.capitalize()} connection health check failed: {e}"
688
+ while not shutting_down:
689
+ if meshtastic_client and not reconnecting:
690
+ # BLE has real-time disconnection detection in the library
691
+ # Skip periodic health checks to avoid duplicate reconnection attempts
692
+ if connection_type == "ble":
693
+ if not ble_skip_logged:
694
+ logger.info(
695
+ "BLE connection uses real-time disconnection detection - health checks disabled"
689
696
  )
690
- on_lost_meshtastic_connection(meshtastic_client)
691
- else:
692
- logger.debug("Skipping reconnection trigger - already reconnecting")
697
+ ble_skip_logged = True
698
+ else:
699
+ try:
700
+ output_capture = io.StringIO()
701
+ with contextlib.redirect_stdout(
702
+ output_capture
703
+ ), contextlib.redirect_stderr(output_capture):
704
+ meshtastic_client.localNode.getMetadata()
705
+
706
+ console_output = output_capture.getvalue()
707
+ if "firmware_version" not in console_output:
708
+ raise Exception("No firmware_version in getMetadata output.")
709
+
710
+ except Exception as e:
711
+ # Only trigger reconnection if we're not already reconnecting
712
+ if not reconnecting:
713
+ logger.error(
714
+ f"{connection_type.capitalize()} connection health check failed: {e}"
715
+ )
716
+ on_lost_meshtastic_connection(
717
+ interface=meshtastic_client,
718
+ detection_source=f"health check failed: {str(e)}",
719
+ )
720
+ else:
721
+ logger.debug(
722
+ "Skipping reconnection trigger - already reconnecting"
723
+ )
693
724
  elif reconnecting:
694
725
  logger.debug("Skipping connection check - reconnection in progress")
695
726
  elif not meshtastic_client:
@@ -707,21 +738,20 @@ def sendTextReply(
707
738
  channelIndex: int = 0,
708
739
  ):
709
740
  """
710
- 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.
711
742
 
712
- This function creates a proper Meshtastic reply by setting the reply_id field
713
- 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.
714
744
 
715
- Args:
716
- interface: The Meshtastic interface to send through
717
- text: The text message to send
718
- reply_id: The ID of the message this is replying to
719
- destinationId: Where to send the message (default: broadcast)
720
- wantAck: Whether to request acknowledgment
721
- channelIndex: Which channel to send on
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.
722
752
 
723
753
  Returns:
724
- The sent packet with populated ID field
754
+ The sent MeshPacket with its ID field populated.
725
755
  """
726
756
  logger.debug(f"Sending text reply: '{text}' replying to message ID {reply_id}")
727
757
 
@@ -3,6 +3,7 @@ services:
3
3
  build: .
4
4
  container_name: meshtastic-matrix-relay
5
5
  restart: unless-stopped
6
+ user: "${UID:-1000}:${GID:-1000}"
6
7
 
7
8
  environment:
8
9
  - TZ=UTC
@@ -28,5 +29,11 @@ services:
28
29
  # - /dev/ttyUSB0:/dev/ttyUSB0
29
30
  # - /dev/ttyACM0:/dev/ttyACM0
30
31
 
31
- # For BLE connections, uncomment this:
32
+ # For BLE connections, uncomment these:
32
33
  # privileged: true
34
+ # network_mode: host
35
+ # Additional volumes for BLE (add to existing volumes section above):
36
+ # - /var/run/dbus:/var/run/dbus:ro
37
+ # - /sys/bus/usb:/sys/bus/usb:ro
38
+ # - /sys/class/bluetooth:/sys/class/bluetooth:ro
39
+ # - /sys/devices:/sys/devices:ro
@@ -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.0
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
@@ -56,6 +56,7 @@ A powerful and easy-to-use relay between Meshtastic devices and Matrix chat room
56
56
  - Supports mapping multiple rooms and channels 1:1
57
57
  - Relays messages to/from an MQTT broker, if configured in the Meshtastic firmware
58
58
  - ✨️ _Bidirectional replies and reactions support_ ✨️ **NEW!!**
59
+ - ✨️ _Native Docker support_ ✨️ **NEW!!**
59
60
 
60
61
  _We would love to support [Matrix E2EE rooms](https://github.com/geoffwhittington/meshtastic-matrix-relay/issues/33), but this is currently not implemented._
61
62
 
@@ -98,7 +99,7 @@ make logs # View logs
98
99
 
99
100
  Docker provides isolated environment, easy deployment, automatic restarts, and volume persistence.
100
101
 
101
- For detailed Docker setup instructions, see the [Docker Guide](DOCKER.md).
102
+ For detailed Docker setup instructions, see the [Docker Guide](docs/DOCKER.md).
102
103
 
103
104
  > **Note**: Docker builds currently use a temporary fork of the meshtastic library with BLE hanging fixes. PyPI releases use the upstream library. This will be resolved when the fixes are merged upstream.
104
105
 
@@ -172,5 +173,5 @@ See our Wiki page [Getting Started With Matrix & MM Relay](https://github.com/ge
172
173
  Join us!
173
174
 
174
175
  - Our project's room: [#mmrelay:matrix.org](https://matrix.to/#/#mmrelay:matrix.org)
175
- - Part of the Meshtastic Community Matrix space: [#meshnetclub:matrix.org](https://matrix.to/#/#meshnetclub:matrix.org)
176
+ - Part of the Meshnet Club Matrix space: [#meshnetclub:matrix.org](https://matrix.to/#/#meshnetclub:matrix.org)
176
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=wo5bAmayppAqLHI02pEu7w2K2_YUxHWbnanigSNlXa8,594
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=ot0GpYppyNuPOWY8d3EXdLPojoJYEqfmUjVlcYm8neY,7532
7
- mmrelay/main.py,sha256=TL5xWFXIGwAQKau-hN4sRB0wxtNWzc629ry_qPbovv0,11585
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=WdRiqbmCtUJrd45VZdJvfbrXct6rD09rtusi9nHMzc4,29163
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
@@ -23,12 +23,12 @@ mmrelay/plugins/telemetry_plugin.py,sha256=8SxWv4BLXMUTbiVaD3MjlMMdQyS7S_1OfLlVN
23
23
  mmrelay/plugins/weather_plugin.py,sha256=1bQhmiX-enNphzGoFVprU0LcZQX9BvGxWAJAG8Wekg0,8596
24
24
  mmrelay/tools/__init__.py,sha256=WFjDQjdevgg19_zT6iEoL29rvb1JPqYSd8708Jn5D7A,838
25
25
  mmrelay/tools/mmrelay.service,sha256=3vqK1VbfXvVftkTrTEOan77aTHeOT36hIAL7HqJsmTg,567
26
- mmrelay/tools/sample-docker-compose.yaml,sha256=eXi-7TGb4fjC4g0Q-qs55pBZ4UWNKAstSO1ozOXlrUI,939
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=0BKND0qbke8z9X9J9iHleu567dZt3RmHUxhZlQEEdFk,3290
29
- mmrelay-1.1.0.dist-info/licenses/LICENSE,sha256=yceWauM1c0-FHxVplsD7W1-AbSeRaUNlmqT4UO1msBU,1073
30
- mmrelay-1.1.0.dist-info/METADATA,sha256=IstoM9NyCmerUqL9QOEygC2BfAoxrHJLfXWY-J7kEd0,6658
31
- mmrelay-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
- mmrelay-1.1.0.dist-info/entry_points.txt,sha256=SJZwGUOEpQ-qx4H8UL4xKFnKeInGUaZNW1I0ddjK7Ws,45
33
- mmrelay-1.1.0.dist-info/top_level.txt,sha256=B_ZLCRm7NYAmI3PipRUyHGymP-C-q16LSeMGzmqJfo4,8
34
- mmrelay-1.1.0.dist-info/RECORD,,
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,,