mmrelay 1.0.7__tar.gz → 1.0.9__tar.gz

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.

Files changed (39) hide show
  1. {mmrelay-1.0.7 → mmrelay-1.0.9}/MANIFEST.in +0 -2
  2. {mmrelay-1.0.7/src/mmrelay.egg-info → mmrelay-1.0.9}/PKG-INFO +24 -48
  3. {mmrelay-1.0.7 → mmrelay-1.0.9}/README.md +21 -45
  4. {mmrelay-1.0.7 → mmrelay-1.0.9}/requirements.txt +2 -2
  5. {mmrelay-1.0.7 → mmrelay-1.0.9}/setup.cfg +3 -3
  6. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/__init__.py +1 -1
  7. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/main.py +4 -1
  8. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/matrix_utils.py +34 -4
  9. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugin_loader.py +63 -0
  10. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/base_plugin.py +199 -16
  11. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/debug_plugin.py +13 -0
  12. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/drop_plugin.py +2 -3
  13. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/help_plugin.py +28 -4
  14. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/map_plugin.py +33 -3
  15. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/mesh_relay_plugin.py +89 -2
  16. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/ping_plugin.py +2 -3
  17. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/weather_plugin.py +2 -3
  18. {mmrelay-1.0.7 → mmrelay-1.0.9/src/mmrelay.egg-info}/PKG-INFO +24 -48
  19. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay.egg-info/requires.txt +2 -2
  20. {mmrelay-1.0.7 → mmrelay-1.0.9}/LICENSE +0 -0
  21. {mmrelay-1.0.7 → mmrelay-1.0.9}/pyproject.toml +0 -0
  22. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/cli.py +0 -0
  23. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/config.py +0 -0
  24. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/config_checker.py +0 -0
  25. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/db_utils.py +0 -0
  26. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/log_utils.py +0 -0
  27. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/meshtastic_utils.py +0 -0
  28. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/__init__.py +0 -0
  29. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/health_plugin.py +0 -0
  30. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/nodes_plugin.py +0 -0
  31. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/plugins/telemetry_plugin.py +0 -0
  32. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/setup_utils.py +0 -0
  33. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/tools/__init__.py +0 -0
  34. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/tools/mmrelay.service +0 -0
  35. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay/tools/sample_config.yaml +0 -0
  36. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay.egg-info/SOURCES.txt +0 -0
  37. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay.egg-info/dependency_links.txt +0 -0
  38. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay.egg-info/entry_points.txt +0 -0
  39. {mmrelay-1.0.7 → mmrelay-1.0.9}/src/mmrelay.egg-info/top_level.txt +0 -0
@@ -1,6 +1,4 @@
1
1
  include LICENSE
2
2
  include README.md
3
3
  include requirements.txt
4
- include sample_config.yaml
5
- recursive-include tools *
6
4
  recursive-include src/mmrelay/tools *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mmrelay
3
- Version: 1.0.7
3
+ Version: 1.0.9
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
@@ -22,72 +22,45 @@ Requires-Dist: requests==2.32.3
22
22
  Requires-Dist: markdown==3.8
23
23
  Requires-Dist: haversine==2.9.0
24
24
  Requires-Dist: schedule==1.2.2
25
- Requires-Dist: platformdirs==4.3.7
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
- Requires-Dist: setuptools==80.3.1
28
+ Requires-Dist: setuptools==80.9.0
29
29
  Dynamic: license-file
30
30
 
31
31
  # M<>M Relay
32
32
 
33
- ## Version 1.0 Released! ✨
33
+ ## (Meshtastic <=> Matrix Relay)
34
34
 
35
- **We're excited to announce MMRelay v1.0 with improved packaging, standardized directories, and enhanced CLI!**
35
+ 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
36
 
37
- **Existing users:** Version 1.0 requires a few quick migration steps:
37
+ ## Documentation
38
38
 
39
- 1. Follow the [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) guide for a smooth transition
40
- 2. Move your configuration to the new standard location (`~/.mmrelay/config.yaml`)
41
- 3. See [ANNOUNCEMENT.md](ANNOUNCEMENT.md) for all the exciting new features
39
+ Visit our [Wiki](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki) for comprehensive guides and information.
42
40
 
43
- Not ready to upgrade yet? No problem! Run `git checkout 0.10.1` to continue using the previous version.
44
-
45
- ## (Meshtastic <=> Matrix Relay)
46
-
47
- 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/).
41
+ - [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
48
44
 
49
45
  ---
50
46
 
51
- ## Getting Started
47
+ ## Quick Start
52
48
 
53
49
  MMRelay runs on Linux, macOS, and Windows.
54
50
 
55
- ### Quick Installation
56
-
57
51
  ```bash
58
52
  # Install using pipx for isolated installation (recommended)
59
53
  pipx install mmrelay
60
54
 
61
- # Pip will also work if you prefer
62
- pip install mmrelay
63
- ```
64
-
65
- For pipx installation instructions, see: [pipx installation guide](https://pipx.pypa.io/stable/installation/#on-linux)
55
+ # Generate a sample configuration file & then edit it
56
+ mmrelay --generate-config
66
57
 
67
- ### Resources
68
-
69
- - **New Users**: See [INSTRUCTIONS.md](INSTRUCTIONS.md) for setup and configuration
70
- - **Existing Users**: See [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) for migration guidance
71
- - **Configuration**: Review [sample_config.yaml](src/mmrelay/tools/sample_config.yaml) for examples
72
-
73
- ### Command-Line Options
74
-
75
- ```bash
76
- usage: mmrelay [-h] [--config CONFIG] [--data-dir DATA_DIR] [--log-level {error,warning,info,debug}] [--logfile LOGFILE] [--version] [--generate-config] [--install-service] [--check-config]
77
-
78
- Options:
79
- -h, --help Show this help message and exit
80
- --config CONFIG Path to config file
81
- --data-dir DATA_DIR Base directory for all data (logs, database, plugins)
82
- --log-level {error,warning,info,debug}
83
- Set logging level
84
- --logfile LOGFILE Path to log file (can be overridden by --data-dir)
85
- --version Show version and exit
86
- --generate-config Generate a sample config.yaml file
87
- --install-service Install or update the systemd user service
88
- --check-config Check if the configuration file is valid
58
+ # Start the relay (without --install-service to run manually)
59
+ mmrelay --install-service
89
60
  ```
90
61
 
62
+ For detailed installation and configuration instructions, see the [Installation Guide](docs/INSTRUCTIONS.md).
63
+
91
64
  ---
92
65
 
93
66
  ## Features
@@ -133,7 +106,12 @@ See the full list of core plugins [here](https://github.com/geoffwhittington/mes
133
106
 
134
107
  ### Community & Custom Plugins
135
108
 
136
- It is possible to create custom plugins and share them with the community. Check [example_plugins/README.md](https://github.com/geoffwhittington/meshtastic-matrix-relay/tree/main/example_plugins) and the [Community Plugins Development Guide](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-Development-Guide).
109
+ MMRelay's plugin system allows you to extend functionality in two ways:
110
+
111
+ - **Custom Plugins**: Create personal plugins for your own use, stored in `~/.mmrelay/plugins/custom/`
112
+ - **Community Plugins**: Share your creations with others or use plugins developed by the community
113
+
114
+ Check the [Community Plugins Development Guide](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-Development-Guide) in our wiki to get started.
137
115
 
138
116
  ✨️ Visit the [Community Plugins List](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-List)!
139
117
 
@@ -151,14 +129,12 @@ community-plugins:
151
129
 
152
130
  ### Plugin System
153
131
 
154
- MMRelay features a powerful plugin system with standardized locations:
132
+ Plugins make it easy to extend functionality without modifying the core program. MMRelay features a powerful plugin system with standardized locations:
155
133
 
156
134
  - **Core Plugins**: Pre-installed with the package
157
135
  - **Custom Plugins**: Your own plugins in `~/.mmrelay/plugins/custom/`
158
136
  - **Community Plugins**: Third-party plugins in `~/.mmrelay/plugins/community/`
159
137
 
160
- Plugins make it easy to extend functionality without modifying the core code.
161
-
162
138
  ---
163
139
 
164
140
  ## Getting Started with Matrix
@@ -1,63 +1,36 @@
1
1
  # M<>M Relay
2
2
 
3
- ## Version 1.0 Released! ✨
3
+ ## (Meshtastic <=> Matrix Relay)
4
4
 
5
- **We're excited to announce MMRelay v1.0 with improved packaging, standardized directories, and enhanced CLI!**
5
+ 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/).
6
6
 
7
- **Existing users:** Version 1.0 requires a few quick migration steps:
7
+ ## Documentation
8
8
 
9
- 1. Follow the [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) guide for a smooth transition
10
- 2. Move your configuration to the new standard location (`~/.mmrelay/config.yaml`)
11
- 3. See [ANNOUNCEMENT.md](ANNOUNCEMENT.md) for all the exciting new features
9
+ Visit our [Wiki](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki) for comprehensive guides and information.
12
10
 
13
- Not ready to upgrade yet? No problem! Run `git checkout 0.10.1` to continue using the previous version.
14
-
15
- ## (Meshtastic <=> Matrix Relay)
16
-
17
- 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/).
11
+ - [Installation Instructions](docs/INSTRUCTIONS.md) - Setup and configuration guide
12
+ - [v1.0 Release Announcement](docs/ANNOUNCEMENT.md) - New changes in v1.0
13
+ - [Upgrade Guide](docs/UPGRADE_TO_V1.md) - Migration guidance for existing users
18
14
 
19
15
  ---
20
16
 
21
- ## Getting Started
17
+ ## Quick Start
22
18
 
23
19
  MMRelay runs on Linux, macOS, and Windows.
24
20
 
25
- ### Quick Installation
26
-
27
21
  ```bash
28
22
  # Install using pipx for isolated installation (recommended)
29
23
  pipx install mmrelay
30
24
 
31
- # Pip will also work if you prefer
32
- pip install mmrelay
33
- ```
34
-
35
- For pipx installation instructions, see: [pipx installation guide](https://pipx.pypa.io/stable/installation/#on-linux)
25
+ # Generate a sample configuration file & then edit it
26
+ mmrelay --generate-config
36
27
 
37
- ### Resources
38
-
39
- - **New Users**: See [INSTRUCTIONS.md](INSTRUCTIONS.md) for setup and configuration
40
- - **Existing Users**: See [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) for migration guidance
41
- - **Configuration**: Review [sample_config.yaml](src/mmrelay/tools/sample_config.yaml) for examples
42
-
43
- ### Command-Line Options
44
-
45
- ```bash
46
- usage: mmrelay [-h] [--config CONFIG] [--data-dir DATA_DIR] [--log-level {error,warning,info,debug}] [--logfile LOGFILE] [--version] [--generate-config] [--install-service] [--check-config]
47
-
48
- Options:
49
- -h, --help Show this help message and exit
50
- --config CONFIG Path to config file
51
- --data-dir DATA_DIR Base directory for all data (logs, database, plugins)
52
- --log-level {error,warning,info,debug}
53
- Set logging level
54
- --logfile LOGFILE Path to log file (can be overridden by --data-dir)
55
- --version Show version and exit
56
- --generate-config Generate a sample config.yaml file
57
- --install-service Install or update the systemd user service
58
- --check-config Check if the configuration file is valid
28
+ # Start the relay (without --install-service to run manually)
29
+ mmrelay --install-service
59
30
  ```
60
31
 
32
+ For detailed installation and configuration instructions, see the [Installation Guide](docs/INSTRUCTIONS.md).
33
+
61
34
  ---
62
35
 
63
36
  ## Features
@@ -103,7 +76,12 @@ See the full list of core plugins [here](https://github.com/geoffwhittington/mes
103
76
 
104
77
  ### Community & Custom Plugins
105
78
 
106
- It is possible to create custom plugins and share them with the community. Check [example_plugins/README.md](https://github.com/geoffwhittington/meshtastic-matrix-relay/tree/main/example_plugins) and the [Community Plugins Development Guide](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-Development-Guide).
79
+ MMRelay's plugin system allows you to extend functionality in two ways:
80
+
81
+ - **Custom Plugins**: Create personal plugins for your own use, stored in `~/.mmrelay/plugins/custom/`
82
+ - **Community Plugins**: Share your creations with others or use plugins developed by the community
83
+
84
+ Check the [Community Plugins Development Guide](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-Development-Guide) in our wiki to get started.
107
85
 
108
86
  ✨️ Visit the [Community Plugins List](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-List)!
109
87
 
@@ -121,14 +99,12 @@ community-plugins:
121
99
 
122
100
  ### Plugin System
123
101
 
124
- MMRelay features a powerful plugin system with standardized locations:
102
+ Plugins make it easy to extend functionality without modifying the core program. MMRelay features a powerful plugin system with standardized locations:
125
103
 
126
104
  - **Core Plugins**: Pre-installed with the package
127
105
  - **Custom Plugins**: Your own plugins in `~/.mmrelay/plugins/custom/`
128
106
  - **Community Plugins**: Third-party plugins in `~/.mmrelay/plugins/community/`
129
107
 
130
- Plugins make it easy to extend functionality without modifying the core code.
131
-
132
108
  ---
133
109
 
134
110
  ## Getting Started with Matrix
@@ -6,7 +6,7 @@ requests==2.32.3
6
6
  markdown==3.8
7
7
  haversine==2.9.0
8
8
  schedule==1.2.2
9
- platformdirs==4.3.7
9
+ platformdirs==4.3.8
10
10
  py-staticmaps>=0.4.0
11
11
  rich==14.0.0
12
- setuptools==80.3.1
12
+ setuptools==80.9.0
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = mmrelay
3
- version = 1.0.7
3
+ version = 1.0.9
4
4
  author = Geoff Whittington, Jeremiah K., and contributors
5
5
  author_email = jeremiahk@gmx.com
6
6
  description = Bridge between Meshtastic mesh networks and Matrix chat rooms
@@ -30,10 +30,10 @@ install_requires =
30
30
  markdown==3.8
31
31
  haversine==2.9.0
32
32
  schedule==1.2.2
33
- platformdirs==4.3.7
33
+ platformdirs==4.3.8
34
34
  py-staticmaps>=0.4.0
35
35
  rich==14.0.0
36
- setuptools==80.3.1
36
+ setuptools==80.9.0
37
37
  include_package_data = True
38
38
 
39
39
  [options.packages.find]
@@ -15,4 +15,4 @@ else:
15
15
  __version__ = pkg_resources.get_distribution("mmrelay").version
16
16
  except pkg_resources.DistributionNotFound:
17
17
  # If all else fails, use hardcoded version
18
- __version__ = "1.0.1"
18
+ __version__ = "1.0.8"
@@ -9,6 +9,7 @@ import signal
9
9
  import sys
10
10
 
11
11
  from nio import ReactionEvent, RoomMessageEmote, RoomMessageNotice, RoomMessageText
12
+ from nio.events.room_events import RoomMemberEvent
12
13
 
13
14
  # Import version from package
14
15
  # Import meshtastic_utils as a module to set event_loop
@@ -22,7 +23,7 @@ from mmrelay.db_utils import (
22
23
  from mmrelay.log_utils import get_logger
23
24
  from mmrelay.matrix_utils import connect_matrix, join_matrix_room
24
25
  from mmrelay.matrix_utils import logger as matrix_logger
25
- from mmrelay.matrix_utils import on_room_message
26
+ from mmrelay.matrix_utils import on_room_member, on_room_message
26
27
  from mmrelay.meshtastic_utils import connect_meshtastic
27
28
  from mmrelay.meshtastic_utils import logger as meshtastic_logger
28
29
  from mmrelay.plugin_loader import load_plugins
@@ -109,6 +110,8 @@ async def main(config):
109
110
  )
110
111
  # Add ReactionEvent callback so we can handle matrix reactions
111
112
  matrix_client.add_event_callback(on_room_message, ReactionEvent)
113
+ # Add RoomMemberEvent callback to track room-specific display name changes
114
+ matrix_client.add_event_callback(on_room_member, RoomMemberEvent)
112
115
 
113
116
  # Set up shutdown event
114
117
  shutdown_event = asyncio.Event()
@@ -18,6 +18,7 @@ from nio import (
18
18
  UploadResponse,
19
19
  WhoamiError,
20
20
  )
21
+ from nio.events.room_events import RoomMemberEvent
21
22
  from PIL import Image
22
23
 
23
24
  from mmrelay.db_utils import (
@@ -517,8 +518,16 @@ async def on_room_message(
517
518
  meshtastic_id, matrix_room_id, meshtastic_text_db, meshtastic_meshnet_db = (
518
519
  orig
519
520
  )
520
- display_name_response = await matrix_client.get_displayname(event.sender)
521
- full_display_name = display_name_response.displayname or event.sender
521
+ # Get room-specific display name if available, fallback to global display name
522
+ room_display_name = room.user_name(event.sender)
523
+ if room_display_name:
524
+ full_display_name = room_display_name
525
+ else:
526
+ # Fallback to global display name if room-specific name is not available
527
+ display_name_response = await matrix_client.get_displayname(
528
+ event.sender
529
+ )
530
+ full_display_name = display_name_response.displayname or event.sender
522
531
 
523
532
  # If not from a remote meshnet, proceed as normal to relay back to the originating meshnet
524
533
  short_display_name = full_display_name[:5]
@@ -578,8 +587,14 @@ async def on_room_message(
578
587
  return
579
588
  else:
580
589
  # Normal Matrix message from a Matrix user
581
- display_name_response = await matrix_client.get_displayname(event.sender)
582
- full_display_name = display_name_response.displayname or event.sender
590
+ # Get room-specific display name if available, fallback to global display name
591
+ room_display_name = room.user_name(event.sender)
592
+ if room_display_name:
593
+ full_display_name = room_display_name
594
+ else:
595
+ # Fallback to global display name if room-specific name is not available
596
+ display_name_response = await matrix_client.get_displayname(event.sender)
597
+ full_display_name = display_name_response.displayname or event.sender
583
598
  short_display_name = full_display_name[:5]
584
599
  prefix = f"{short_display_name}[M]: "
585
600
  logger.debug(f"Processing matrix message from [{full_display_name}]: {text}")
@@ -752,3 +767,18 @@ async def send_room_image(
752
767
  message_type="m.room.message",
753
768
  content={"msgtype": "m.image", "url": upload_response.content_uri, "body": ""},
754
769
  )
770
+
771
+
772
+ async def on_room_member(room: MatrixRoom, event: RoomMemberEvent) -> None:
773
+ """
774
+ Callback to handle room member events, specifically tracking room-specific display name changes.
775
+ This ensures we detect when users update their display names in specific rooms.
776
+
777
+ Note: This callback doesn't need to do any explicit processing since matrix-nio
778
+ automatically updates the room state and room.user_name() will return the
779
+ updated room-specific display name immediately after this event.
780
+ """
781
+ # The callback is registered to ensure matrix-nio processes the event,
782
+ # but no explicit action is needed since room.user_name() automatically
783
+ # handles room-specific display names after the room state is updated.
784
+ pass
@@ -57,6 +57,28 @@ def get_community_plugin_dirs():
57
57
 
58
58
 
59
59
  def clone_or_update_repo(repo_url, ref, plugins_dir):
60
+ """Clone or update a Git repository for community plugins.
61
+
62
+ Args:
63
+ repo_url (str): Git repository URL to clone/update
64
+ ref (dict): Reference specification with keys:
65
+ - type: "tag" or "branch"
66
+ - value: tag name or branch name
67
+ plugins_dir (str): Directory where the repository should be cloned
68
+
69
+ Returns:
70
+ bool: True if successful, False if clone/update failed
71
+
72
+ Handles complex Git operations including:
73
+ - Cloning new repositories with specific tags/branches
74
+ - Updating existing repositories and switching refs
75
+ - Installing requirements.txt dependencies via pip or pipx
76
+ - Fallback to default branches (main/master) when specified ref fails
77
+ - Robust error handling and logging
78
+
79
+ The function automatically installs Python dependencies if a requirements.txt
80
+ file is found in the repository root.
81
+ """
60
82
  # Extract the repository name from the URL
61
83
  repo_name = os.path.splitext(os.path.basename(repo_url.rstrip("/")))[0]
62
84
  repo_path = os.path.join(plugins_dir, repo_name)
@@ -497,6 +519,27 @@ def clone_or_update_repo(repo_url, ref, plugins_dir):
497
519
 
498
520
 
499
521
  def load_plugins_from_directory(directory, recursive=False):
522
+ """Load plugin classes from Python files in a directory.
523
+
524
+ Args:
525
+ directory (str): Directory path to search for plugin files
526
+ recursive (bool): Whether to search subdirectories recursively
527
+
528
+ Returns:
529
+ list: List of instantiated plugin objects found in the directory
530
+
531
+ Scans for .py files and attempts to import each as a module. Looks for
532
+ a 'Plugin' class in each module and instantiates it if found.
533
+
534
+ Features:
535
+ - Automatic dependency installation for missing imports (via pip/pipx)
536
+ - Compatibility layer for import paths (plugins vs mmrelay.plugins)
537
+ - Proper sys.path management for plugin directory imports
538
+ - Comprehensive error handling and logging
539
+
540
+ Skips files that don't define a Plugin class or have import errors
541
+ that can't be automatically resolved.
542
+ """
500
543
  plugins = []
501
544
  if os.path.isdir(directory):
502
545
  for root, _dirs, files in os.walk(directory):
@@ -617,6 +660,26 @@ def load_plugins_from_directory(directory, recursive=False):
617
660
 
618
661
 
619
662
  def load_plugins(passed_config=None):
663
+ """Load and initialize all active plugins based on configuration.
664
+
665
+ Args:
666
+ passed_config (dict, optional): Configuration dictionary to use.
667
+ If None, uses global config variable.
668
+
669
+ Returns:
670
+ list: List of active plugin instances sorted by priority
671
+
672
+ This is the main plugin loading function that:
673
+ - Loads core plugins from mmrelay.plugins package
674
+ - Processes custom plugins from ~/.mmrelay/plugins/custom and plugins/custom
675
+ - Downloads and loads community plugins from configured Git repositories
676
+ - Filters plugins based on active status in configuration
677
+ - Sorts active plugins by priority and calls their start() method
678
+ - Sets up proper plugin configuration and channel mapping
679
+
680
+ Only plugins explicitly marked as active=true in config are loaded.
681
+ Custom and community plugins are cloned/updated automatically.
682
+ """
620
683
  global sorted_active_plugins
621
684
  global plugins_loaded
622
685
  global config
@@ -20,6 +20,27 @@ config = None
20
20
 
21
21
 
22
22
  class BasePlugin(ABC):
23
+ """Abstract base class for all mmrelay plugins.
24
+
25
+ Provides common functionality for plugin development including:
26
+ - Configuration management and validation
27
+ - Database storage for plugin-specific data
28
+ - Channel and direct message handling
29
+ - Matrix message sending capabilities
30
+ - Scheduling support for background tasks
31
+ - Command matching and routing
32
+
33
+ Attributes:
34
+ plugin_name (str): Unique identifier for the plugin
35
+ max_data_rows_per_node (int): Maximum data rows stored per node (default: 100)
36
+ priority (int): Plugin execution priority (lower = higher priority, default: 10)
37
+
38
+ Subclasses must:
39
+ - Set plugin_name as a class attribute
40
+ - Implement handle_meshtastic_message() and handle_room_message()
41
+ - Optionally override other methods for custom behavior
42
+ """
43
+
23
44
  # Class-level default attributes
24
45
  plugin_name = None # Must be overridden in subclasses
25
46
  max_data_rows_per_node = 100
@@ -27,27 +48,53 @@ class BasePlugin(ABC):
27
48
 
28
49
  @property
29
50
  def description(self):
51
+ """Get the plugin description for help text.
52
+
53
+ Returns:
54
+ str: Human-readable description of plugin functionality
55
+
56
+ Override this property in subclasses to provide meaningful help text
57
+ that will be displayed by the help plugin.
58
+ """
30
59
  return ""
31
60
 
32
- def __init__(self) -> None:
33
- # IMPORTANT NOTE FOR PLUGIN DEVELOPERS:
34
- # When creating a plugin that inherits from BasePlugin, you MUST set
35
- # self.plugin_name in your __init__ method BEFORE calling super().__init__()
36
- # Example:
37
- # def __init__(self):
38
- # self.plugin_name = "your_plugin_name" # Set this FIRST
39
- # super().__init__() # Then call parent
40
- #
41
- # Failure to do this will cause command recognition issues and other problems.
61
+ def __init__(self, plugin_name=None) -> None:
62
+ """Initialize the plugin with configuration and logging.
42
63
 
64
+ Args:
65
+ plugin_name (str, optional): Plugin name override. If not provided,
66
+ uses class-level plugin_name attribute.
67
+
68
+ Raises:
69
+ ValueError: If plugin_name is not set via parameter or class attribute
70
+
71
+ Sets up:
72
+ - Plugin-specific logger
73
+ - Configuration from global config
74
+ - Channel mapping and validation
75
+ - Response delay settings
76
+ """
77
+ # Allow plugin_name to be passed as a parameter for simpler initialization
78
+ # This maintains backward compatibility while providing a cleaner API
43
79
  super().__init__()
44
80
 
45
- # Verify plugin_name is properly defined
81
+ # If plugin_name is provided as a parameter, use it
82
+ if plugin_name is not None:
83
+ self.plugin_name = plugin_name
84
+
85
+ # For backward compatibility: if plugin_name is not provided as a parameter,
86
+ # check if it's set as an instance attribute (old way) or use the class attribute
46
87
  if not hasattr(self, "plugin_name") or self.plugin_name is None:
47
- raise ValueError(
48
- f"{self.__class__.__name__} is missing plugin_name definition. "
49
- f"Make sure to set self.plugin_name BEFORE calling super().__init__()"
50
- )
88
+ # Try to get the class-level plugin_name
89
+ class_plugin_name = getattr(self.__class__, "plugin_name", None)
90
+ if class_plugin_name is not None:
91
+ self.plugin_name = class_plugin_name
92
+ else:
93
+ raise ValueError(
94
+ f"{self.__class__.__name__} is missing plugin_name definition. "
95
+ f"Either set class.plugin_name, pass plugin_name to __init__, "
96
+ f"or set self.plugin_name before calling super().__init__()"
97
+ )
51
98
 
52
99
  self.logger = get_logger(f"Plugin:{self.plugin_name}")
53
100
  self.config = {"active": False}
@@ -66,6 +113,8 @@ class BasePlugin(ABC):
66
113
  room.get("meshtastic_channel")
67
114
  for room in config.get("matrix_rooms", [])
68
115
  ]
116
+ else:
117
+ self.mapped_channels = []
69
118
 
70
119
  # Get the channels specified for this plugin, or default to all mapped channels
71
120
  self.channels = self.config.get("channels", self.mapped_channels)
@@ -91,6 +140,19 @@ class BasePlugin(ABC):
91
140
  )
92
141
 
93
142
  def start(self):
143
+ """Start the plugin and set up scheduled tasks if configured.
144
+
145
+ Called automatically when the plugin is loaded. Checks plugin configuration
146
+ for scheduling settings and sets up background jobs accordingly.
147
+
148
+ Supported schedule formats in config:
149
+ - schedule.hours + schedule.at: Run every N hours at specific time
150
+ - schedule.minutes + schedule.at: Run every N minutes at specific time
151
+ - schedule.hours: Run every N hours
152
+ - schedule.minutes: Run every N minutes
153
+
154
+ Creates a daemon thread to run the scheduler if any schedule is configured.
155
+ """
94
156
  if "schedule" not in self.config or (
95
157
  "at" not in self.config["schedule"]
96
158
  and "hours" not in self.config["schedule"]
@@ -132,9 +194,27 @@ class BasePlugin(ABC):
132
194
 
133
195
  # trunk-ignore(ruff/B027)
134
196
  def background_job(self):
197
+ """Background task executed on schedule.
198
+
199
+ Override this method in subclasses to implement scheduled functionality.
200
+ Called automatically based on schedule configuration in start().
201
+
202
+ Default implementation does nothing.
203
+ """
135
204
  pass # Implement in subclass if needed
136
205
 
137
206
  def strip_raw(self, data):
207
+ """Recursively remove 'raw' keys from data structures.
208
+
209
+ Args:
210
+ data: Data structure (dict, list, or other) to clean
211
+
212
+ Returns:
213
+ Cleaned data structure with 'raw' keys removed
214
+
215
+ Useful for cleaning packet data before logging or storage to remove
216
+ binary protobuf data that's not human-readable.
217
+ """
138
218
  if isinstance(data, dict):
139
219
  data.pop("raw", None)
140
220
  for k, v in data.items():
@@ -144,19 +224,59 @@ class BasePlugin(ABC):
144
224
  return data
145
225
 
146
226
  def get_response_delay(self):
227
+ """Get the configured response delay for meshtastic messages.
228
+
229
+ Returns:
230
+ int: Delay in seconds before sending responses (default: 3)
231
+
232
+ Used to prevent message flooding and ensure proper radio etiquette.
233
+ Delay is configured via meshtastic.plugin_response_delay in config.
234
+ """
147
235
  return self.response_delay
148
236
 
149
- # Modified method to accept is_direct_message parameter
150
237
  def is_channel_enabled(self, channel, is_direct_message=False):
238
+ """Check if the plugin should respond on a specific channel.
239
+
240
+ Args:
241
+ channel: Channel identifier to check
242
+ is_direct_message (bool): Whether this is a direct message
243
+
244
+ Returns:
245
+ bool: True if plugin should respond, False otherwise
246
+
247
+ Direct messages always return True if the plugin is active.
248
+ For channel messages, checks if channel is in plugin's configured channels list.
249
+ """
151
250
  if is_direct_message:
152
251
  return True # Always respond to DMs if the plugin is active
153
252
  else:
154
253
  return channel in self.channels
155
254
 
156
255
  def get_matrix_commands(self):
256
+ """Get list of Matrix commands this plugin responds to.
257
+
258
+ Returns:
259
+ list: List of command strings (without ! prefix)
260
+
261
+ Default implementation returns [plugin_name]. Override to provide
262
+ custom commands or multiple command aliases.
263
+ """
157
264
  return [self.plugin_name]
158
265
 
159
266
  async def send_matrix_message(self, room_id, message, formatted=True):
267
+ """Send a message to a Matrix room.
268
+
269
+ Args:
270
+ room_id (str): Matrix room identifier
271
+ message (str): Message content to send
272
+ formatted (bool): Whether to send as formatted HTML (default: True)
273
+
274
+ Returns:
275
+ dict: Response from Matrix API room_send
276
+
277
+ Connects to Matrix using matrix_utils and sends a room message
278
+ with optional HTML formatting via markdown.
279
+ """
160
280
  from mmrelay.matrix_utils import connect_matrix
161
281
 
162
282
  matrix_client = await connect_matrix()
@@ -173,9 +293,26 @@ class BasePlugin(ABC):
173
293
  )
174
294
 
175
295
  def get_mesh_commands(self):
296
+ """Get list of mesh/radio commands this plugin responds to.
297
+
298
+ Returns:
299
+ list: List of command strings (without ! prefix)
300
+
301
+ Default implementation returns empty list. Override to handle
302
+ commands sent over the mesh radio network.
303
+ """
176
304
  return []
177
305
 
178
306
  def store_node_data(self, meshtastic_id, node_data):
307
+ """Store data for a specific node, appending to existing data.
308
+
309
+ Args:
310
+ meshtastic_id (str): Node identifier
311
+ node_data: Data to store (single item or list)
312
+
313
+ Retrieves existing data, appends new data, trims to max_data_rows_per_node,
314
+ and stores back to database. Use for accumulating time-series data.
315
+ """
179
316
  data = self.get_node_data(meshtastic_id=meshtastic_id)
180
317
  data = data[-self.max_data_rows_per_node :]
181
318
  if isinstance(node_data, list):
@@ -185,21 +322,56 @@ class BasePlugin(ABC):
185
322
  store_plugin_data(self.plugin_name, meshtastic_id, data)
186
323
 
187
324
  def set_node_data(self, meshtastic_id, node_data):
325
+ """Replace all data for a specific node.
326
+
327
+ Args:
328
+ meshtastic_id (str): Node identifier
329
+ node_data: Data to store (replaces existing data)
330
+
331
+ Completely replaces existing data for the node, trimming to
332
+ max_data_rows_per_node if needed. Use when you want to reset
333
+ or completely replace a node's data.
334
+ """
188
335
  node_data = node_data[-self.max_data_rows_per_node :]
189
336
  store_plugin_data(self.plugin_name, meshtastic_id, node_data)
190
337
 
191
338
  def delete_node_data(self, meshtastic_id):
339
+ """Delete all stored data for a specific node.
340
+
341
+ Args:
342
+ meshtastic_id (str): Node identifier
343
+
344
+ Returns:
345
+ bool: True if deletion succeeded, False otherwise
346
+ """
192
347
  return delete_plugin_data(self.plugin_name, meshtastic_id)
193
348
 
194
349
  def get_node_data(self, meshtastic_id):
350
+ """Retrieve stored data for a specific node.
351
+
352
+ Args:
353
+ meshtastic_id (str): Node identifier
354
+
355
+ Returns:
356
+ list: Stored data for the node (JSON deserialized)
357
+ """
195
358
  return get_plugin_data_for_node(self.plugin_name, meshtastic_id)
196
359
 
197
360
  def get_data(self):
361
+ """Retrieve all stored data for this plugin across all nodes.
362
+
363
+ Returns:
364
+ list: List of tuples containing raw data entries
365
+
366
+ Returns raw data without JSON deserialization. Use get_node_data()
367
+ for individual node data that's automatically deserialized.
368
+ """
198
369
  return get_plugin_data(self.plugin_name)
199
370
 
200
371
  def get_plugin_data_dir(self, subdir=None):
201
372
  """
202
373
  Returns the directory for storing plugin-specific data files.
374
+
203
375
  Creates the directory if it doesn't exist.
204
376
 
205
377
  Args:
@@ -225,6 +397,17 @@ class BasePlugin(ABC):
225
397
  return plugin_dir
226
398
 
227
399
  def matches(self, event):
400
+ """Check if a Matrix event matches this plugin's commands.
401
+
402
+ Args:
403
+ event: Matrix room event to check
404
+
405
+ Returns:
406
+ bool: True if event matches plugin commands, False otherwise
407
+
408
+ Uses bot_command() utility to check if the event contains any of
409
+ the plugin's matrix commands with proper bot command syntax.
410
+ """
228
411
  from mmrelay.matrix_utils import bot_command
229
412
 
230
413
  # Pass the entire event to bot_command
@@ -2,6 +2,19 @@ from mmrelay.plugins.base_plugin import BasePlugin
2
2
 
3
3
 
4
4
  class Plugin(BasePlugin):
5
+ """Debug plugin for logging packet information.
6
+
7
+ A low-priority plugin that logs all received meshtastic packets
8
+ for debugging and development purposes. Strips raw binary data
9
+ before logging to keep output readable.
10
+
11
+ Configuration:
12
+ priority: 1 (runs first, before other plugins)
13
+
14
+ Never intercepts messages (always returns False) so other plugins
15
+ can still process the same packets.
16
+ """
17
+
5
18
  plugin_name = "debug"
6
19
  priority = 1
7
20
 
@@ -10,9 +10,8 @@ class Plugin(BasePlugin):
10
10
  plugin_name = "drop"
11
11
  special_node = "!NODE_MSGS!"
12
12
 
13
- def __init__(self):
14
- self.plugin_name = "drop"
15
- super().__init__()
13
+ # No __init__ method needed with the simplified plugin system
14
+ # The BasePlugin will automatically use the class-level plugin_name
16
15
 
17
16
  def get_position(self, meshtastic_client, node_id):
18
17
  for _node, info in meshtastic_client.nodes.items():
@@ -5,14 +5,28 @@ from mmrelay.plugins.base_plugin import BasePlugin
5
5
 
6
6
 
7
7
  class Plugin(BasePlugin):
8
- plugin_name = "help"
8
+ """Help command plugin for listing available commands.
9
+
10
+ Provides users with information about available relay commands
11
+ and plugin functionality.
12
+
13
+ Commands:
14
+ !help: List all available commands
15
+ !help <command>: Show detailed help for a specific command
16
+
17
+ Dynamically discovers available commands from all loaded plugins
18
+ and their descriptions.
19
+ """
9
20
 
10
- def __init__(self):
11
- self.plugin_name = "help"
12
- super().__init__()
21
+ plugin_name = "help"
13
22
 
14
23
  @property
15
24
  def description(self):
25
+ """Get plugin description.
26
+
27
+ Returns:
28
+ str: Description of help functionality
29
+ """
16
30
  return "List supported relay commands"
17
31
 
18
32
  async def handle_meshtastic_message(
@@ -21,9 +35,19 @@ class Plugin(BasePlugin):
21
35
  return False
22
36
 
23
37
  def get_matrix_commands(self):
38
+ """Get Matrix commands handled by this plugin.
39
+
40
+ Returns:
41
+ list: List containing the help command
42
+ """
24
43
  return [self.plugin_name]
25
44
 
26
45
  def get_mesh_commands(self):
46
+ """Get mesh commands handled by this plugin.
47
+
48
+ Returns:
49
+ list: Empty list (help only works via Matrix)
50
+ """
27
51
  return []
28
52
 
29
53
  async def handle_room_message(self, room, event, full_message):
@@ -156,6 +156,19 @@ class TextLabel(staticmaps.Object):
156
156
 
157
157
 
158
158
  def anonymize_location(lat, lon, radius=1000):
159
+ """Add random offset to GPS coordinates for privacy protection.
160
+
161
+ Args:
162
+ lat (float): Original latitude
163
+ lon (float): Original longitude
164
+ radius (int): Maximum offset distance in meters (default: 1000)
165
+
166
+ Returns:
167
+ tuple: (new_lat, new_lon) with random offset applied
168
+
169
+ Adds random offset within specified radius to obscure exact locations
170
+ while maintaining general geographic area for mapping purposes.
171
+ """
159
172
  # Generate random offsets for latitude and longitude
160
173
  lat_offset = random.uniform(-radius / 111320, radius / 111320)
161
174
  lon_offset = random.uniform(
@@ -233,11 +246,28 @@ async def send_image(client: AsyncClient, room_id: str, image: Image.Image):
233
246
 
234
247
 
235
248
  class Plugin(BasePlugin):
249
+ """Static map generation plugin for mesh node locations.
250
+
251
+ Generates static maps showing positions of mesh nodes with labeled markers.
252
+ Supports customizable zoom levels, image sizes, and privacy features.
253
+
254
+ Commands:
255
+ !map: Generate map with default settings
256
+ !map zoom=N: Set zoom level (0-30)
257
+ !map size=W,H: Set image dimensions (max 1000x1000)
258
+
259
+ Configuration:
260
+ zoom (int): Default zoom level (default: 8)
261
+ image_width/image_height (int): Default image size (default: 1000x1000)
262
+ anonymize (bool): Whether to offset coordinates for privacy (default: true)
263
+ radius (int): Anonymization offset radius in meters (default: 1000)
264
+
265
+ Uploads generated maps as images to Matrix rooms.
266
+ """
236
267
  plugin_name = "map"
237
268
 
238
- def __init__(self):
239
- self.plugin_name = "map"
240
- super().__init__()
269
+ # No __init__ method needed with the simplified plugin system
270
+ # The BasePlugin will automatically use the class-level plugin_name
241
271
 
242
272
  @property
243
273
  def description(self):
@@ -1,3 +1,5 @@
1
+ # Note: This plugin was experimental and is not functional.
2
+
1
3
  import base64
2
4
  import json
3
5
  import re
@@ -8,12 +10,36 @@ from mmrelay.plugins.base_plugin import BasePlugin, config
8
10
 
9
11
 
10
12
  class Plugin(BasePlugin):
13
+ """Core mesh-to-Matrix relay plugin.
14
+
15
+ Handles bidirectional message relay between Meshtastic mesh network
16
+ and Matrix chat rooms. Processes radio packets and forwards them
17
+ to configured Matrix rooms, and vice versa.
18
+
19
+ This plugin is fundamental to the relay's core functionality and
20
+ typically runs with high priority to ensure messages are properly
21
+ bridged between the two networks.
22
+
23
+ Configuration:
24
+ max_data_rows_per_node: 50 (reduced storage for performance)
25
+ """
26
+
11
27
  plugin_name = "mesh_relay"
12
28
  max_data_rows_per_node = 50
13
29
 
14
30
  def normalize(self, dict_obj):
15
- """
16
- Packets are either a dict, string dict or string
31
+ """Normalize packet data to consistent dictionary format.
32
+
33
+ Args:
34
+ dict_obj: Packet data (dict, JSON string, or plain string)
35
+
36
+ Returns:
37
+ dict: Normalized packet dictionary with raw data stripped
38
+
39
+ Handles various packet formats:
40
+ - Dict objects (passed through)
41
+ - JSON strings (parsed)
42
+ - Plain strings (wrapped in TEXT_MESSAGE_APP format)
17
43
  """
18
44
  if not isinstance(dict_obj, dict):
19
45
  try:
@@ -24,6 +50,17 @@ class Plugin(BasePlugin):
24
50
  return self.strip_raw(dict_obj)
25
51
 
26
52
  def process(self, packet):
53
+ """Process and prepare packet data for relay.
54
+
55
+ Args:
56
+ packet: Raw packet data to process
57
+
58
+ Returns:
59
+ dict: Processed packet with base64-encoded binary payloads
60
+
61
+ Normalizes packet format and encodes binary payloads as base64
62
+ for JSON serialization and Matrix transmission.
63
+ """
27
64
  packet = self.normalize(packet)
28
65
 
29
66
  if "decoded" in packet and "payload" in packet["decoded"]:
@@ -35,14 +72,39 @@ class Plugin(BasePlugin):
35
72
  return packet
36
73
 
37
74
  def get_matrix_commands(self):
75
+ """Get Matrix commands handled by this plugin.
76
+
77
+ Returns:
78
+ list: Empty list (this plugin handles all traffic, not specific commands)
79
+ """
38
80
  return []
39
81
 
40
82
  def get_mesh_commands(self):
83
+ """Get mesh commands handled by this plugin.
84
+
85
+ Returns:
86
+ list: Empty list (this plugin handles all traffic, not specific commands)
87
+ """
41
88
  return []
42
89
 
43
90
  async def handle_meshtastic_message(
44
91
  self, packet, formatted_message, longname, meshnet_name
45
92
  ):
93
+ """Handle incoming meshtastic message and relay to Matrix.
94
+
95
+ Args:
96
+ packet: Raw packet data (dict or JSON) to relay
97
+ formatted_message (str): Human-readable message extracted from packet
98
+ longname (str): Long name of the sender node
99
+ meshnet_name (str): Name of the mesh network
100
+
101
+ Returns:
102
+ bool: Always returns False to allow other plugins to process the same packet
103
+
104
+ Processes the packet by normalizing and preparing it, connects to the Matrix client,
105
+ checks if the meshtastic channel is mapped to a Matrix room based on config,
106
+ and sends the packet to the appropriate Matrix room.
107
+ """
46
108
  from mmrelay.matrix_utils import connect_matrix
47
109
 
48
110
  packet = self.process(packet)
@@ -80,6 +142,17 @@ class Plugin(BasePlugin):
80
142
  return False
81
143
 
82
144
  def matches(self, event):
145
+ """Check if Matrix event is a relayed radio packet.
146
+
147
+ Args:
148
+ event: Matrix room event object
149
+
150
+ Returns:
151
+ bool: True if event contains embedded meshtastic packet JSON
152
+
153
+ Identifies Matrix messages that contain embedded meshtastic packet
154
+ data by matching the default relay message format "Processed <portnum> radio packet".
155
+ """
83
156
  # Check for the presence of necessary keys in the event
84
157
  content = event.source.get("content", {})
85
158
  body = content.get("body", "")
@@ -90,6 +163,20 @@ class Plugin(BasePlugin):
90
163
  return False
91
164
 
92
165
  async def handle_room_message(self, room, event, full_message):
166
+ """Handle incoming Matrix room message and relay to meshtastic mesh.
167
+
168
+ Args:
169
+ room: Matrix Room object where message was received
170
+ event: Matrix room event containing the message
171
+ full_message (str): Raw message body text
172
+
173
+ Returns:
174
+ bool: True if packet relaying succeeded, False otherwise
175
+
176
+ Checks if the Matrix event matches the expected embedded packet format,
177
+ retrieves the packet JSON, decodes it, reconstructs a MeshPacket,
178
+ connects to the meshtastic client, and sends the packet via the radio.
179
+ """
93
180
  # Use the event for matching instead of full_message
94
181
  if not self.matches(event):
95
182
  return False
@@ -17,9 +17,8 @@ class Plugin(BasePlugin):
17
17
  plugin_name = "ping"
18
18
  punctuation = string.punctuation
19
19
 
20
- def __init__(self):
21
- self.plugin_name = "ping"
22
- super().__init__()
20
+ # No __init__ method needed with the simplified plugin system
21
+ # The BasePlugin will automatically use the class-level plugin_name
23
22
 
24
23
  @property
25
24
  def description(self):
@@ -9,9 +9,8 @@ from mmrelay.plugins.base_plugin import BasePlugin
9
9
  class Plugin(BasePlugin):
10
10
  plugin_name = "weather"
11
11
 
12
- def __init__(self):
13
- self.plugin_name = "weather"
14
- super().__init__()
12
+ # No __init__ method needed with the simplified plugin system
13
+ # The BasePlugin will automatically use the class-level plugin_name
15
14
 
16
15
  @property
17
16
  def description(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mmrelay
3
- Version: 1.0.7
3
+ Version: 1.0.9
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
@@ -22,72 +22,45 @@ Requires-Dist: requests==2.32.3
22
22
  Requires-Dist: markdown==3.8
23
23
  Requires-Dist: haversine==2.9.0
24
24
  Requires-Dist: schedule==1.2.2
25
- Requires-Dist: platformdirs==4.3.7
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
- Requires-Dist: setuptools==80.3.1
28
+ Requires-Dist: setuptools==80.9.0
29
29
  Dynamic: license-file
30
30
 
31
31
  # M<>M Relay
32
32
 
33
- ## Version 1.0 Released! ✨
33
+ ## (Meshtastic <=> Matrix Relay)
34
34
 
35
- **We're excited to announce MMRelay v1.0 with improved packaging, standardized directories, and enhanced CLI!**
35
+ 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
36
 
37
- **Existing users:** Version 1.0 requires a few quick migration steps:
37
+ ## Documentation
38
38
 
39
- 1. Follow the [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) guide for a smooth transition
40
- 2. Move your configuration to the new standard location (`~/.mmrelay/config.yaml`)
41
- 3. See [ANNOUNCEMENT.md](ANNOUNCEMENT.md) for all the exciting new features
39
+ Visit our [Wiki](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki) for comprehensive guides and information.
42
40
 
43
- Not ready to upgrade yet? No problem! Run `git checkout 0.10.1` to continue using the previous version.
44
-
45
- ## (Meshtastic <=> Matrix Relay)
46
-
47
- 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/).
41
+ - [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
48
44
 
49
45
  ---
50
46
 
51
- ## Getting Started
47
+ ## Quick Start
52
48
 
53
49
  MMRelay runs on Linux, macOS, and Windows.
54
50
 
55
- ### Quick Installation
56
-
57
51
  ```bash
58
52
  # Install using pipx for isolated installation (recommended)
59
53
  pipx install mmrelay
60
54
 
61
- # Pip will also work if you prefer
62
- pip install mmrelay
63
- ```
64
-
65
- For pipx installation instructions, see: [pipx installation guide](https://pipx.pypa.io/stable/installation/#on-linux)
55
+ # Generate a sample configuration file & then edit it
56
+ mmrelay --generate-config
66
57
 
67
- ### Resources
68
-
69
- - **New Users**: See [INSTRUCTIONS.md](INSTRUCTIONS.md) for setup and configuration
70
- - **Existing Users**: See [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) for migration guidance
71
- - **Configuration**: Review [sample_config.yaml](src/mmrelay/tools/sample_config.yaml) for examples
72
-
73
- ### Command-Line Options
74
-
75
- ```bash
76
- usage: mmrelay [-h] [--config CONFIG] [--data-dir DATA_DIR] [--log-level {error,warning,info,debug}] [--logfile LOGFILE] [--version] [--generate-config] [--install-service] [--check-config]
77
-
78
- Options:
79
- -h, --help Show this help message and exit
80
- --config CONFIG Path to config file
81
- --data-dir DATA_DIR Base directory for all data (logs, database, plugins)
82
- --log-level {error,warning,info,debug}
83
- Set logging level
84
- --logfile LOGFILE Path to log file (can be overridden by --data-dir)
85
- --version Show version and exit
86
- --generate-config Generate a sample config.yaml file
87
- --install-service Install or update the systemd user service
88
- --check-config Check if the configuration file is valid
58
+ # Start the relay (without --install-service to run manually)
59
+ mmrelay --install-service
89
60
  ```
90
61
 
62
+ For detailed installation and configuration instructions, see the [Installation Guide](docs/INSTRUCTIONS.md).
63
+
91
64
  ---
92
65
 
93
66
  ## Features
@@ -133,7 +106,12 @@ See the full list of core plugins [here](https://github.com/geoffwhittington/mes
133
106
 
134
107
  ### Community & Custom Plugins
135
108
 
136
- It is possible to create custom plugins and share them with the community. Check [example_plugins/README.md](https://github.com/geoffwhittington/meshtastic-matrix-relay/tree/main/example_plugins) and the [Community Plugins Development Guide](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-Development-Guide).
109
+ MMRelay's plugin system allows you to extend functionality in two ways:
110
+
111
+ - **Custom Plugins**: Create personal plugins for your own use, stored in `~/.mmrelay/plugins/custom/`
112
+ - **Community Plugins**: Share your creations with others or use plugins developed by the community
113
+
114
+ Check the [Community Plugins Development Guide](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-Development-Guide) in our wiki to get started.
137
115
 
138
116
  ✨️ Visit the [Community Plugins List](https://github.com/geoffwhittington/meshtastic-matrix-relay/wiki/Community-Plugin-List)!
139
117
 
@@ -151,14 +129,12 @@ community-plugins:
151
129
 
152
130
  ### Plugin System
153
131
 
154
- MMRelay features a powerful plugin system with standardized locations:
132
+ Plugins make it easy to extend functionality without modifying the core program. MMRelay features a powerful plugin system with standardized locations:
155
133
 
156
134
  - **Core Plugins**: Pre-installed with the package
157
135
  - **Custom Plugins**: Your own plugins in `~/.mmrelay/plugins/custom/`
158
136
  - **Community Plugins**: Third-party plugins in `~/.mmrelay/plugins/community/`
159
137
 
160
- Plugins make it easy to extend functionality without modifying the core code.
161
-
162
138
  ---
163
139
 
164
140
  ## Getting Started with Matrix
@@ -6,7 +6,7 @@ requests==2.32.3
6
6
  markdown==3.8
7
7
  haversine==2.9.0
8
8
  schedule==1.2.2
9
- platformdirs==4.3.7
9
+ platformdirs==4.3.8
10
10
  py-staticmaps>=0.4.0
11
11
  rich==14.0.0
12
- setuptools==80.3.1
12
+ setuptools==80.9.0
File without changes
File without changes
File without changes
File without changes
File without changes