mmrelay 1.0.10__py3-none-any.whl → 1.1.0__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/db_utils.py +61 -9
- mmrelay/log_utils.py +56 -0
- mmrelay/main.py +11 -12
- mmrelay/matrix_utils.py +385 -73
- mmrelay/meshtastic_utils.py +158 -30
- mmrelay/tools/sample-docker-compose.yaml +32 -0
- mmrelay/tools/sample.env +10 -0
- mmrelay/tools/sample_config.yaml +6 -3
- {mmrelay-1.0.10.dist-info → mmrelay-1.1.0.dist-info}/METADATA +49 -25
- {mmrelay-1.0.10.dist-info → mmrelay-1.1.0.dist-info}/RECORD +15 -13
- {mmrelay-1.0.10.dist-info → mmrelay-1.1.0.dist-info}/WHEEL +0 -0
- {mmrelay-1.0.10.dist-info → mmrelay-1.1.0.dist-info}/entry_points.txt +0 -0
- {mmrelay-1.0.10.dist-info → mmrelay-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {mmrelay-1.0.10.dist-info → mmrelay-1.1.0.dist-info}/top_level.txt +0 -0
mmrelay/meshtastic_utils.py
CHANGED
|
@@ -12,6 +12,7 @@ import meshtastic.tcp_interface
|
|
|
12
12
|
import serial # For serial port exceptions
|
|
13
13
|
import serial.tools.list_ports # Import serial tools for port listing
|
|
14
14
|
from bleak.exc import BleakDBusError, BleakError
|
|
15
|
+
from meshtastic.protobuf import mesh_pb2, portnums_pb2
|
|
15
16
|
from pubsub import pub
|
|
16
17
|
|
|
17
18
|
from mmrelay.db_utils import (
|
|
@@ -46,14 +47,17 @@ reconnecting = False
|
|
|
46
47
|
shutting_down = False
|
|
47
48
|
reconnect_task = None # To keep track of the reconnect task
|
|
48
49
|
|
|
50
|
+
# Track pubsub subscription state to prevent duplicate subscriptions during reconnections
|
|
51
|
+
subscribed_to_messages = False
|
|
52
|
+
subscribed_to_connection_lost = False
|
|
53
|
+
|
|
49
54
|
|
|
50
55
|
def is_running_as_service():
|
|
51
56
|
"""
|
|
52
|
-
|
|
53
|
-
This is used to determine whether to show Rich progress indicators.
|
|
57
|
+
Determine if the application is running as a systemd service.
|
|
54
58
|
|
|
55
59
|
Returns:
|
|
56
|
-
bool: True if running
|
|
60
|
+
bool: True if running under systemd (either via environment variable or parent process), False otherwise.
|
|
57
61
|
"""
|
|
58
62
|
# Check for INVOCATION_ID environment variable (set by systemd)
|
|
59
63
|
if os.environ.get("INVOCATION_ID"):
|
|
@@ -84,14 +88,16 @@ def serial_port_exists(port_name):
|
|
|
84
88
|
|
|
85
89
|
def connect_meshtastic(passed_config=None, force_connect=False):
|
|
86
90
|
"""
|
|
87
|
-
|
|
88
|
-
Attempts a connection based on connection_type (serial/ble/network).
|
|
89
|
-
Retries until successful or shutting_down is set.
|
|
90
|
-
If already connected and not force_connect, returns the existing client.
|
|
91
|
+
Establishes and manages a connection to a Meshtastic device using the configured connection type (serial, BLE, or TCP).
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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.
|
|
94
|
+
|
|
95
|
+
Parameters:
|
|
96
|
+
passed_config (dict, optional): Configuration dictionary to use for the connection. If provided, updates the global configuration.
|
|
97
|
+
force_connect (bool, optional): If True, forces a new connection even if one already exists.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Meshtastic interface client if the connection is successful, or None if the connection fails or shutdown is in progress.
|
|
95
101
|
"""
|
|
96
102
|
global meshtastic_client, shutting_down, config, matrix_rooms
|
|
97
103
|
if shutting_down:
|
|
@@ -196,11 +202,19 @@ def connect_meshtastic(passed_config=None, force_connect=False):
|
|
|
196
202
|
f"Connected to {nodeInfo['user']['shortName']} / {nodeInfo['user']['hwModel']}"
|
|
197
203
|
)
|
|
198
204
|
|
|
199
|
-
# Subscribe to message and connection lost events
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
205
|
+
# Subscribe to message and connection lost events (only if not already subscribed)
|
|
206
|
+
global subscribed_to_messages, subscribed_to_connection_lost
|
|
207
|
+
if not subscribed_to_messages:
|
|
208
|
+
pub.subscribe(on_meshtastic_message, "meshtastic.receive")
|
|
209
|
+
subscribed_to_messages = True
|
|
210
|
+
logger.debug("Subscribed to meshtastic.receive")
|
|
211
|
+
|
|
212
|
+
if not subscribed_to_connection_lost:
|
|
213
|
+
pub.subscribe(
|
|
214
|
+
on_lost_meshtastic_connection, "meshtastic.connection.lost"
|
|
215
|
+
)
|
|
216
|
+
subscribed_to_connection_lost = True
|
|
217
|
+
logger.debug("Subscribed to meshtastic.connection.lost")
|
|
204
218
|
|
|
205
219
|
except (
|
|
206
220
|
serial.SerialException,
|
|
@@ -322,9 +336,9 @@ async def reconnect():
|
|
|
322
336
|
|
|
323
337
|
def on_meshtastic_message(packet, interface):
|
|
324
338
|
"""
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
339
|
+
Processes incoming Meshtastic messages and relays them to Matrix rooms or plugins based on message type and interaction settings.
|
|
340
|
+
|
|
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.
|
|
328
342
|
"""
|
|
329
343
|
global config, matrix_rooms
|
|
330
344
|
|
|
@@ -341,15 +355,24 @@ def on_meshtastic_message(packet, interface):
|
|
|
341
355
|
logger.error("No configuration available. Cannot process Meshtastic message.")
|
|
342
356
|
return
|
|
343
357
|
|
|
344
|
-
#
|
|
345
|
-
|
|
358
|
+
# Import the configuration helpers
|
|
359
|
+
from mmrelay.matrix_utils import get_interaction_settings, message_storage_enabled
|
|
360
|
+
|
|
361
|
+
# Get interaction settings
|
|
362
|
+
interactions = get_interaction_settings(config)
|
|
363
|
+
message_storage_enabled(interactions)
|
|
346
364
|
|
|
347
|
-
#
|
|
365
|
+
# Filter packets based on interaction settings
|
|
348
366
|
if packet.get("decoded", {}).get("portnum") == "TEXT_MESSAGE_APP":
|
|
349
367
|
decoded = packet.get("decoded", {})
|
|
350
|
-
|
|
368
|
+
# Filter out reactions if reactions are disabled
|
|
369
|
+
if (
|
|
370
|
+
not interactions["reactions"]
|
|
371
|
+
and "emoji" in decoded
|
|
372
|
+
and decoded.get("emoji") == 1
|
|
373
|
+
):
|
|
351
374
|
logger.debug(
|
|
352
|
-
"Filtered out reaction
|
|
375
|
+
"Filtered out reaction packet due to reactions being disabled."
|
|
353
376
|
)
|
|
354
377
|
return
|
|
355
378
|
|
|
@@ -391,8 +414,8 @@ def on_meshtastic_message(packet, interface):
|
|
|
391
414
|
meshnet_name = config["meshtastic"]["meshnet_name"]
|
|
392
415
|
|
|
393
416
|
# Reaction handling (Meshtastic -> Matrix)
|
|
394
|
-
# If replyId and emoji_flag are present and
|
|
395
|
-
if replyId and emoji_flag and
|
|
417
|
+
# If replyId and emoji_flag are present and reactions are enabled, we relay as text reactions in Matrix
|
|
418
|
+
if replyId and emoji_flag and interactions["reactions"]:
|
|
396
419
|
longname = get_longname(sender) or str(sender)
|
|
397
420
|
shortname = get_shortname(sender) or str(sender)
|
|
398
421
|
orig = get_message_map_by_meshtastic_id(replyId)
|
|
@@ -432,6 +455,42 @@ def on_meshtastic_message(packet, interface):
|
|
|
432
455
|
logger.debug("Original message for reaction not found in DB.")
|
|
433
456
|
return
|
|
434
457
|
|
|
458
|
+
# Reply handling (Meshtastic -> Matrix)
|
|
459
|
+
# If replyId is present but emoji is not (or not 1), this is a reply
|
|
460
|
+
if replyId and not emoji_flag and interactions["replies"]:
|
|
461
|
+
longname = get_longname(sender) or str(sender)
|
|
462
|
+
shortname = get_shortname(sender) or str(sender)
|
|
463
|
+
orig = get_message_map_by_meshtastic_id(replyId)
|
|
464
|
+
if orig:
|
|
465
|
+
# orig = (matrix_event_id, matrix_room_id, meshtastic_text, meshtastic_meshnet)
|
|
466
|
+
matrix_event_id, matrix_room_id, meshtastic_text, meshtastic_meshnet = orig
|
|
467
|
+
|
|
468
|
+
# Format the reply message for Matrix
|
|
469
|
+
full_display_name = f"{longname}/{meshnet_name}"
|
|
470
|
+
formatted_message = f"[{full_display_name}]: {text}"
|
|
471
|
+
|
|
472
|
+
logger.info(f"Relaying Meshtastic reply from {longname} to Matrix")
|
|
473
|
+
|
|
474
|
+
# Relay the reply to Matrix with proper reply formatting
|
|
475
|
+
asyncio.run_coroutine_threadsafe(
|
|
476
|
+
matrix_relay(
|
|
477
|
+
matrix_room_id,
|
|
478
|
+
formatted_message,
|
|
479
|
+
longname,
|
|
480
|
+
shortname,
|
|
481
|
+
meshnet_name,
|
|
482
|
+
decoded.get("portnum"),
|
|
483
|
+
meshtastic_id=packet.get("id"),
|
|
484
|
+
meshtastic_replyId=replyId,
|
|
485
|
+
meshtastic_text=text,
|
|
486
|
+
reply_to_event_id=matrix_event_id,
|
|
487
|
+
),
|
|
488
|
+
loop=loop,
|
|
489
|
+
)
|
|
490
|
+
else:
|
|
491
|
+
logger.debug("Original message for reply not found in DB.")
|
|
492
|
+
return
|
|
493
|
+
|
|
435
494
|
# Normal text messages or detection sensor messages
|
|
436
495
|
if text:
|
|
437
496
|
# Determine the channel for this message
|
|
@@ -585,20 +644,31 @@ def on_meshtastic_message(packet, interface):
|
|
|
585
644
|
async def check_connection():
|
|
586
645
|
"""
|
|
587
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.
|
|
588
648
|
If it fails or doesn't return the firmware version, we assume the connection is lost
|
|
589
649
|
and attempt to reconnect.
|
|
590
650
|
"""
|
|
591
|
-
global meshtastic_client, shutting_down, config
|
|
651
|
+
global meshtastic_client, shutting_down, config, reconnecting
|
|
592
652
|
|
|
593
653
|
# Check if config is available
|
|
594
654
|
if config is None:
|
|
595
655
|
logger.error("No configuration available. Cannot check connection.")
|
|
596
656
|
return
|
|
597
657
|
|
|
658
|
+
# Get heartbeat interval from config, default to 180 seconds
|
|
659
|
+
heartbeat_interval = config["meshtastic"].get("heartbeat_interval", 180)
|
|
598
660
|
connection_type = config["meshtastic"]["connection_type"]
|
|
661
|
+
|
|
662
|
+
logger.info(
|
|
663
|
+
f"Starting connection heartbeat monitor (interval: {heartbeat_interval}s)"
|
|
664
|
+
)
|
|
665
|
+
|
|
599
666
|
while not shutting_down:
|
|
600
|
-
if meshtastic_client:
|
|
667
|
+
if meshtastic_client and not reconnecting:
|
|
601
668
|
try:
|
|
669
|
+
logger.debug(
|
|
670
|
+
f"Checking {connection_type} connection health using getMetadata()"
|
|
671
|
+
)
|
|
602
672
|
output_capture = io.StringIO()
|
|
603
673
|
with contextlib.redirect_stdout(
|
|
604
674
|
output_capture
|
|
@@ -609,10 +679,68 @@ async def check_connection():
|
|
|
609
679
|
if "firmware_version" not in console_output:
|
|
610
680
|
raise Exception("No firmware_version in getMetadata output.")
|
|
611
681
|
|
|
682
|
+
logger.debug(f"{connection_type.capitalize()} connection healthy")
|
|
683
|
+
|
|
612
684
|
except Exception as e:
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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}"
|
|
689
|
+
)
|
|
690
|
+
on_lost_meshtastic_connection(meshtastic_client)
|
|
691
|
+
else:
|
|
692
|
+
logger.debug("Skipping reconnection trigger - already reconnecting")
|
|
693
|
+
elif reconnecting:
|
|
694
|
+
logger.debug("Skipping connection check - reconnection in progress")
|
|
695
|
+
elif not meshtastic_client:
|
|
696
|
+
logger.debug("Skipping connection check - no client available")
|
|
697
|
+
|
|
698
|
+
await asyncio.sleep(heartbeat_interval)
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def sendTextReply(
|
|
702
|
+
interface,
|
|
703
|
+
text: str,
|
|
704
|
+
reply_id: int,
|
|
705
|
+
destinationId=meshtastic.BROADCAST_ADDR,
|
|
706
|
+
wantAck: bool = False,
|
|
707
|
+
channelIndex: int = 0,
|
|
708
|
+
):
|
|
709
|
+
"""
|
|
710
|
+
Send a text message as a reply to a previous message.
|
|
711
|
+
|
|
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.
|
|
714
|
+
|
|
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
|
|
722
|
+
|
|
723
|
+
Returns:
|
|
724
|
+
The sent packet with populated ID field
|
|
725
|
+
"""
|
|
726
|
+
logger.debug(f"Sending text reply: '{text}' replying to message ID {reply_id}")
|
|
727
|
+
|
|
728
|
+
# Create the Data protobuf message with reply_id set
|
|
729
|
+
data_msg = mesh_pb2.Data()
|
|
730
|
+
data_msg.portnum = portnums_pb2.PortNum.TEXT_MESSAGE_APP
|
|
731
|
+
data_msg.payload = text.encode("utf-8")
|
|
732
|
+
data_msg.reply_id = reply_id
|
|
733
|
+
|
|
734
|
+
# Create the MeshPacket
|
|
735
|
+
mesh_packet = mesh_pb2.MeshPacket()
|
|
736
|
+
mesh_packet.channel = channelIndex
|
|
737
|
+
mesh_packet.decoded.CopyFrom(data_msg)
|
|
738
|
+
mesh_packet.id = interface._generatePacketId()
|
|
739
|
+
|
|
740
|
+
# Send the packet using the existing infrastructure
|
|
741
|
+
return interface._sendPacket(
|
|
742
|
+
mesh_packet, destinationId=destinationId, wantAck=wantAck
|
|
743
|
+
)
|
|
616
744
|
|
|
617
745
|
|
|
618
746
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
services:
|
|
2
|
+
mmrelay:
|
|
3
|
+
build: .
|
|
4
|
+
container_name: meshtastic-matrix-relay
|
|
5
|
+
restart: unless-stopped
|
|
6
|
+
|
|
7
|
+
environment:
|
|
8
|
+
- TZ=UTC
|
|
9
|
+
- PYTHONUNBUFFERED=1
|
|
10
|
+
- MPLCONFIGDIR=/tmp/matplotlib
|
|
11
|
+
|
|
12
|
+
volumes:
|
|
13
|
+
# Configuration - uses standard ~/.mmrelay/config.yaml location
|
|
14
|
+
# Create this first with: make config
|
|
15
|
+
- ${MMRELAY_HOME}/.mmrelay/config.yaml:/app/config.yaml:ro
|
|
16
|
+
|
|
17
|
+
# Data and logs - same locations as standalone installation
|
|
18
|
+
# These directories will be created automatically
|
|
19
|
+
- ${MMRELAY_HOME}/.mmrelay/data:/app/data
|
|
20
|
+
- ${MMRELAY_HOME}/.mmrelay/logs:/app/logs
|
|
21
|
+
|
|
22
|
+
# For TCP connections (most common) - Meshtastic typically uses port 4403
|
|
23
|
+
ports:
|
|
24
|
+
- 4403:4403
|
|
25
|
+
|
|
26
|
+
# For serial connections, uncomment the device you need:
|
|
27
|
+
# devices:
|
|
28
|
+
# - /dev/ttyUSB0:/dev/ttyUSB0
|
|
29
|
+
# - /dev/ttyACM0:/dev/ttyACM0
|
|
30
|
+
|
|
31
|
+
# For BLE connections, uncomment this:
|
|
32
|
+
# privileged: true
|
mmrelay/tools/sample.env
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Docker Compose environment variables
|
|
2
|
+
# Customize these paths if needed
|
|
3
|
+
|
|
4
|
+
# Base directory for mmrelay data
|
|
5
|
+
# This will be expanded by your shell when docker compose runs
|
|
6
|
+
MMRELAY_HOME=$HOME
|
|
7
|
+
|
|
8
|
+
# Preferred editor for config editing
|
|
9
|
+
# Will be set automatically when you select an editor via 'make edit'
|
|
10
|
+
EDITOR=nano
|
mmrelay/tools/sample_config.yaml
CHANGED
|
@@ -10,15 +10,18 @@ matrix_rooms: # Needs at least 1 room & channel, but supports all Meshtastic cha
|
|
|
10
10
|
meshtastic_channel: 2
|
|
11
11
|
|
|
12
12
|
meshtastic:
|
|
13
|
-
connection_type:
|
|
14
|
-
serial_port: /dev/ttyUSB0 # Only used when connection is "serial"
|
|
13
|
+
connection_type: tcp # Choose either "tcp", "serial", or "ble"
|
|
15
14
|
host: meshtastic.local # Only used when connection is "tcp"
|
|
15
|
+
serial_port: /dev/ttyUSB0 # Only used when connection is "serial"
|
|
16
16
|
ble_address: AA:BB:CC:DD:EE:FF # Only used when connection is "ble" - Uses either an address or name from a `meshtastic --ble-scan`
|
|
17
17
|
meshnet_name: Your Meshnet Name # This is displayed in full on Matrix, but is truncated when sent to a Meshnet
|
|
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
|
-
|
|
21
|
+
# heartbeat_interval: 180 # Interval in seconds to check connection health using getMetadata() (default: 180)
|
|
22
|
+
message_interactions: # Configure reactions and replies (both require message storage in database)
|
|
23
|
+
reactions: false # Enable reaction relaying between platforms
|
|
24
|
+
replies: false # Enable reply relaying between platforms
|
|
22
25
|
|
|
23
26
|
logging:
|
|
24
27
|
level: info
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mmrelay
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
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
|
|
@@ -14,19 +14,29 @@ Classifier: Topic :: Communications
|
|
|
14
14
|
Requires-Python: >=3.8
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: meshtastic
|
|
18
|
-
Requires-Dist: Pillow==11.
|
|
17
|
+
Requires-Dist: meshtastic>=2.6.4
|
|
18
|
+
Requires-Dist: Pillow==11.3.0
|
|
19
19
|
Requires-Dist: matrix-nio==0.25.2
|
|
20
20
|
Requires-Dist: matplotlib==3.10.1
|
|
21
|
-
Requires-Dist: requests==2.32.
|
|
22
|
-
Requires-Dist: markdown==3.8
|
|
21
|
+
Requires-Dist: requests==2.32.4
|
|
22
|
+
Requires-Dist: markdown==3.8.2
|
|
23
23
|
Requires-Dist: haversine==2.9.0
|
|
24
24
|
Requires-Dist: schedule==1.2.2
|
|
25
25
|
Requires-Dist: platformdirs==4.3.8
|
|
26
26
|
Requires-Dist: py-staticmaps>=0.4.0
|
|
27
27
|
Requires-Dist: rich==14.0.0
|
|
28
28
|
Requires-Dist: setuptools==80.9.0
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
29
35
|
Dynamic: license-file
|
|
36
|
+
Dynamic: project-url
|
|
37
|
+
Dynamic: requires-dist
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
Dynamic: summary
|
|
30
40
|
|
|
31
41
|
# M<>M Relay
|
|
32
42
|
|
|
@@ -34,13 +44,26 @@ Dynamic: license-file
|
|
|
34
44
|
|
|
35
45
|
A powerful and easy-to-use relay between Meshtastic devices and Matrix chat rooms, allowing seamless communication across platforms. This opens the door for bridging Meshtastic devices to [many other platforms](https://matrix.org/bridges/).
|
|
36
46
|
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- Bidirectional message relay between Meshtastic devices and Matrix chat rooms, capable of supporting multiple meshnets
|
|
50
|
+
- Supports serial, network, and **_BLE (now too!)_** connections for Meshtastic devices
|
|
51
|
+
- Custom fields are embedded in Matrix messages for relaying messages between multiple meshnets
|
|
52
|
+
- Truncates long messages to fit within Meshtastic's payload size
|
|
53
|
+
- SQLite database to store node information for improved functionality
|
|
54
|
+
- Customizable logging level for easy debugging
|
|
55
|
+
- Configurable through a simple YAML file
|
|
56
|
+
- Supports mapping multiple rooms and channels 1:1
|
|
57
|
+
- Relays messages to/from an MQTT broker, if configured in the Meshtastic firmware
|
|
58
|
+
- ✨️ _Bidirectional replies and reactions support_ ✨️ **NEW!!**
|
|
59
|
+
|
|
60
|
+
_We would love to support [Matrix E2EE rooms](https://github.com/geoffwhittington/meshtastic-matrix-relay/issues/33), but this is currently not implemented._
|
|
61
|
+
|
|
37
62
|
## Documentation
|
|
38
63
|
|
|
39
64
|
Visit our [Wiki](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki) for comprehensive guides and information.
|
|
40
65
|
|
|
41
66
|
- [Installation Instructions](docs/INSTRUCTIONS.md) - Setup and configuration guide
|
|
42
|
-
- [v1.0 Release Announcement](docs/ANNOUNCEMENT.md) - New changes in v1.0
|
|
43
|
-
- [Upgrade Guide](docs/UPGRADE_TO_V1.md) - Migration guidance for existing users
|
|
44
67
|
|
|
45
68
|
---
|
|
46
69
|
|
|
@@ -61,22 +84,23 @@ mmrelay --install-service
|
|
|
61
84
|
|
|
62
85
|
For detailed installation and configuration instructions, see the [Installation Guide](docs/INSTRUCTIONS.md).
|
|
63
86
|
|
|
64
|
-
|
|
87
|
+
## Docker
|
|
65
88
|
|
|
66
|
-
|
|
89
|
+
MMRelay includes official Docker support for easy deployment and management:
|
|
67
90
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- Supports mapping multiple rooms and channels 1:1
|
|
76
|
-
- Relays messages to/from an MQTT broker, if configured in the Meshtastic firmware
|
|
77
|
-
- ✨️ _Cross-platform reactions support_ ✨️ **NEW!!**
|
|
91
|
+
```bash
|
|
92
|
+
# Quick setup with Docker
|
|
93
|
+
make setup # Copy config and open editor (first time)
|
|
94
|
+
make build # Build the Docker image
|
|
95
|
+
make run # Start the container
|
|
96
|
+
make logs # View logs
|
|
97
|
+
```
|
|
78
98
|
|
|
79
|
-
|
|
99
|
+
Docker provides isolated environment, easy deployment, automatic restarts, and volume persistence.
|
|
100
|
+
|
|
101
|
+
For detailed Docker setup instructions, see the [Docker Guide](DOCKER.md).
|
|
102
|
+
|
|
103
|
+
> **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.
|
|
80
104
|
|
|
81
105
|
---
|
|
82
106
|
|
|
@@ -84,7 +108,7 @@ _We would love to support [Matrix E2EE rooms](https://github.com/geoffwhittingto
|
|
|
84
108
|
|
|
85
109
|

|
|
86
110
|
|
|
87
|
-
The latest installer is available [
|
|
111
|
+
The latest installer is available in the [releases section](https://github.com/geoffwhittington/meshtastic-matrix-relay/releases).
|
|
88
112
|
|
|
89
113
|
---
|
|
90
114
|
|
|
@@ -102,7 +126,7 @@ Produce high-level details about your mesh:
|
|
|
102
126
|
|
|
103
127
|

|
|
104
128
|
|
|
105
|
-
See the full list of core plugins
|
|
129
|
+
See the full list of [core plugins](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Core-Plugins).
|
|
106
130
|
|
|
107
131
|
### Community & Custom Plugins
|
|
108
132
|
|
|
@@ -147,6 +171,6 @@ See our Wiki page [Getting Started With Matrix & MM Relay](https://github.com/ge
|
|
|
147
171
|
|
|
148
172
|
Join us!
|
|
149
173
|
|
|
150
|
-
- Our project's room: [#mmrelay:
|
|
151
|
-
- Part of the Meshtastic Community Matrix space: [#
|
|
152
|
-
- Public Relay Room: [#relay-room:
|
|
174
|
+
- 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
|
+
- 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=wo5bAmayppAqLHI02pEu7w2K2_YUxHWbnanigSNlXa8,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
|
-
mmrelay/db_utils.py,sha256=
|
|
6
|
-
mmrelay/log_utils.py,sha256=
|
|
7
|
-
mmrelay/main.py,sha256=
|
|
8
|
-
mmrelay/matrix_utils.py,sha256=
|
|
9
|
-
mmrelay/meshtastic_utils.py,sha256=
|
|
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
|
|
8
|
+
mmrelay/matrix_utils.py,sha256=XSOHztRrdIjFGyYt8QhGBL6nMv_6iodeYL288pG9voA,45813
|
|
9
|
+
mmrelay/meshtastic_utils.py,sha256=WdRiqbmCtUJrd45VZdJvfbrXct6rD09rtusi9nHMzc4,29163
|
|
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,10 +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/
|
|
27
|
-
mmrelay
|
|
28
|
-
mmrelay
|
|
29
|
-
mmrelay-1.0.
|
|
30
|
-
mmrelay-1.0.
|
|
31
|
-
mmrelay-1.0.
|
|
32
|
-
mmrelay-1.0.
|
|
26
|
+
mmrelay/tools/sample-docker-compose.yaml,sha256=eXi-7TGb4fjC4g0Q-qs55pBZ4UWNKAstSO1ozOXlrUI,939
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|