mmrelay 1.0__tar.gz → 1.0.1__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.
- {mmrelay-1.0/src/mmrelay.egg-info → mmrelay-1.0.1}/PKG-INFO +24 -9
- {mmrelay-1.0 → mmrelay-1.0.1}/README.md +19 -5
- {mmrelay-1.0 → mmrelay-1.0.1}/requirements.txt +4 -3
- {mmrelay-1.0 → mmrelay-1.0.1}/sample_config.yaml +3 -2
- {mmrelay-1.0 → mmrelay-1.0.1}/setup.cfg +5 -4
- mmrelay-1.0.1/src/mmrelay/__init__.py +13 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/cli.py +9 -2
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/config.py +2 -3
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/log_utils.py +56 -27
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/main.py +30 -1
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/meshtastic_utils.py +54 -4
- mmrelay-1.0.1/src/mmrelay/setup_utils.py +426 -0
- {mmrelay-1.0 → mmrelay-1.0.1/src/mmrelay.egg-info}/PKG-INFO +24 -9
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay.egg-info/requires.txt +4 -3
- mmrelay-1.0.1/tools/mmrelay.service +18 -0
- mmrelay-1.0/src/mmrelay/__init__.py +0 -9
- mmrelay-1.0/src/mmrelay/setup_utils.py +0 -263
- mmrelay-1.0/tools/mmrelay.service +0 -12
- {mmrelay-1.0 → mmrelay-1.0.1}/LICENSE +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/MANIFEST.in +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/pyproject.toml +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/config_checker.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/db_utils.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/matrix_utils.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugin_loader.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/__init__.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/base_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/debug_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/drop_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/health_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/help_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/map_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/mesh_relay_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/nodes_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/ping_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/telemetry_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay/plugins/weather_plugin.py +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay.egg-info/SOURCES.txt +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay.egg-info/dependency_links.txt +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay.egg-info/entry_points.txt +0 -0
- {mmrelay-1.0 → mmrelay-1.0.1}/src/mmrelay.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mmrelay
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.0.1
|
|
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
|
|
@@ -15,19 +15,32 @@ Requires-Python: >=3.8
|
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: meshtastic
|
|
18
|
-
Requires-Dist: Pillow==11.1
|
|
18
|
+
Requires-Dist: Pillow==11.2.1
|
|
19
19
|
Requires-Dist: matrix-nio==0.25.2
|
|
20
20
|
Requires-Dist: matplotlib==3.10.1
|
|
21
21
|
Requires-Dist: requests==2.32.3
|
|
22
|
-
Requires-Dist: markdown==3.
|
|
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.
|
|
25
|
+
Requires-Dist: platformdirs==4.3.7
|
|
26
26
|
Requires-Dist: py-staticmaps>=0.4.0
|
|
27
|
+
Requires-Dist: rich==14.0.0
|
|
27
28
|
Dynamic: license-file
|
|
28
29
|
|
|
29
30
|
# M<>M Relay
|
|
30
31
|
|
|
32
|
+
## ✨ Version 1.0 Released! ✨
|
|
33
|
+
|
|
34
|
+
**We're excited to announce MMRelay v1.0 with improved packaging, standardized directories, and enhanced CLI!**
|
|
35
|
+
|
|
36
|
+
**Existing users:** Version 1.0 requires a few quick migration steps:
|
|
37
|
+
|
|
38
|
+
1. Follow the [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) guide for a smooth transition
|
|
39
|
+
2. Move your configuration to the new standard location (`~/.mmrelay/config.yaml`)
|
|
40
|
+
3. See [ANNOUNCEMENT.md](ANNOUNCEMENT.md) for all the exciting new features
|
|
41
|
+
|
|
42
|
+
Not ready to upgrade yet? No problem! Run `git checkout 0.10.1` to continue using the previous version.
|
|
43
|
+
|
|
31
44
|
## (Meshtastic <=> Matrix Relay)
|
|
32
45
|
|
|
33
46
|
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,17 +54,19 @@ MMRelay runs on Linux, macOS, and Windows.
|
|
|
41
54
|
### Quick Installation
|
|
42
55
|
|
|
43
56
|
```bash
|
|
44
|
-
# Install using
|
|
45
|
-
pip install mmrelay
|
|
46
|
-
|
|
47
|
-
# Or use pipx for isolated installation (recommended)
|
|
57
|
+
# Install using pipx for isolated installation (recommended)
|
|
48
58
|
pipx install mmrelay
|
|
59
|
+
|
|
60
|
+
# Pip will also work if you prefer
|
|
61
|
+
pip install mmrelay
|
|
49
62
|
```
|
|
50
63
|
|
|
64
|
+
For pipx installation instructions, see: [pipx installation guide](https://pipx.pypa.io/stable/installation/#on-linux)
|
|
65
|
+
|
|
51
66
|
### Resources
|
|
52
67
|
|
|
53
68
|
- **New Users**: See [INSTRUCTIONS.md](INSTRUCTIONS.md) for setup and configuration
|
|
54
|
-
- **Existing Users**:
|
|
69
|
+
- **Existing Users**: See [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) for migration guidance
|
|
55
70
|
- **Configuration**: Review [sample_config.yaml](sample_config.yaml) for examples
|
|
56
71
|
|
|
57
72
|
### Command-Line Options
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# M<>M Relay
|
|
2
2
|
|
|
3
|
+
## ✨ Version 1.0 Released! ✨
|
|
4
|
+
|
|
5
|
+
**We're excited to announce MMRelay v1.0 with improved packaging, standardized directories, and enhanced CLI!**
|
|
6
|
+
|
|
7
|
+
**Existing users:** Version 1.0 requires a few quick migration steps:
|
|
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
|
|
12
|
+
|
|
13
|
+
Not ready to upgrade yet? No problem! Run `git checkout 0.10.1` to continue using the previous version.
|
|
14
|
+
|
|
3
15
|
## (Meshtastic <=> Matrix Relay)
|
|
4
16
|
|
|
5
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/).
|
|
@@ -13,17 +25,19 @@ MMRelay runs on Linux, macOS, and Windows.
|
|
|
13
25
|
### Quick Installation
|
|
14
26
|
|
|
15
27
|
```bash
|
|
16
|
-
# Install using
|
|
17
|
-
pip install mmrelay
|
|
18
|
-
|
|
19
|
-
# Or use pipx for isolated installation (recommended)
|
|
28
|
+
# Install using pipx for isolated installation (recommended)
|
|
20
29
|
pipx install mmrelay
|
|
30
|
+
|
|
31
|
+
# Pip will also work if you prefer
|
|
32
|
+
pip install mmrelay
|
|
21
33
|
```
|
|
22
34
|
|
|
35
|
+
For pipx installation instructions, see: [pipx installation guide](https://pipx.pypa.io/stable/installation/#on-linux)
|
|
36
|
+
|
|
23
37
|
### Resources
|
|
24
38
|
|
|
25
39
|
- **New Users**: See [INSTRUCTIONS.md](INSTRUCTIONS.md) for setup and configuration
|
|
26
|
-
- **Existing Users**:
|
|
40
|
+
- **Existing Users**: See [UPGRADE_TO_V1.md](UPGRADE_TO_V1.md) for migration guidance
|
|
27
41
|
- **Configuration**: Review [sample_config.yaml](sample_config.yaml) for examples
|
|
28
42
|
|
|
29
43
|
### Command-Line Options
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
meshtastic
|
|
2
|
-
Pillow==11.1
|
|
2
|
+
Pillow==11.2.1
|
|
3
3
|
matrix-nio==0.25.2
|
|
4
4
|
matplotlib==3.10.1
|
|
5
5
|
requests==2.32.3
|
|
6
|
-
markdown==3.
|
|
6
|
+
markdown==3.8
|
|
7
7
|
haversine==2.9.0
|
|
8
8
|
schedule==1.2.2
|
|
9
|
-
platformdirs==4.
|
|
9
|
+
platformdirs==4.3.7
|
|
10
10
|
py-staticmaps>=0.4.0
|
|
11
|
+
rich==14.0.0
|
|
@@ -22,10 +22,11 @@ meshtastic:
|
|
|
22
22
|
|
|
23
23
|
logging:
|
|
24
24
|
level: info
|
|
25
|
-
#log_to_file: true #
|
|
26
|
-
#filename: ~/.mmrelay/logs/mmrelay.log # Default location
|
|
25
|
+
#log_to_file: true # Set to true to enable file logging
|
|
26
|
+
#filename: ~/.mmrelay/logs/mmrelay.log # Default location if log_to_file is true
|
|
27
27
|
#max_log_size: 10485760 # 10 MB default if omitted
|
|
28
28
|
#backup_count: 1 # Keeps 1 backup as the default if omitted
|
|
29
|
+
#color_enabled: true # Set to false to disable colored console output
|
|
29
30
|
|
|
30
31
|
#database:
|
|
31
32
|
# path: ~/.mmrelay/data/meshtastic.sqlite # Default location
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = mmrelay
|
|
3
|
-
version = 1.0
|
|
3
|
+
version = 1.0.1
|
|
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
|
|
@@ -23,15 +23,16 @@ packages = find:
|
|
|
23
23
|
python_requires = >=3.8
|
|
24
24
|
install_requires =
|
|
25
25
|
meshtastic
|
|
26
|
-
Pillow==11.1
|
|
26
|
+
Pillow==11.2.1
|
|
27
27
|
matrix-nio==0.25.2
|
|
28
28
|
matplotlib==3.10.1
|
|
29
29
|
requests==2.32.3
|
|
30
|
-
markdown==3.
|
|
30
|
+
markdown==3.8
|
|
31
31
|
haversine==2.9.0
|
|
32
32
|
schedule==1.2.2
|
|
33
|
-
platformdirs==4.
|
|
33
|
+
platformdirs==4.3.7
|
|
34
34
|
py-staticmaps>=0.4.0
|
|
35
|
+
rich==14.0.0
|
|
35
36
|
|
|
36
37
|
[options.packages.find]
|
|
37
38
|
where = src
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Meshtastic Matrix Relay - Bridge between Meshtastic mesh networks and Matrix chat rooms.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import importlib.metadata
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
# Try to get version from package metadata (setup.cfg)
|
|
9
|
+
try:
|
|
10
|
+
__version__ = importlib.metadata.version("mmrelay")
|
|
11
|
+
except importlib.metadata.PackageNotFoundError:
|
|
12
|
+
# If package is not installed, fall back to environment variable or default
|
|
13
|
+
__version__ = os.environ.get("GITHUB_REF_NAME", "1.0.1")
|
|
@@ -94,6 +94,13 @@ def get_version():
|
|
|
94
94
|
return __version__
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
def print_version():
|
|
98
|
+
"""
|
|
99
|
+
Print the version in a simple format.
|
|
100
|
+
"""
|
|
101
|
+
print(f"MMRelay v{__version__}")
|
|
102
|
+
|
|
103
|
+
|
|
97
104
|
def check_config(args=None):
|
|
98
105
|
"""
|
|
99
106
|
Check if the configuration file is valid.
|
|
@@ -262,7 +269,7 @@ def main():
|
|
|
262
269
|
|
|
263
270
|
# Handle --version
|
|
264
271
|
if args.version:
|
|
265
|
-
|
|
272
|
+
print_version()
|
|
266
273
|
return 0
|
|
267
274
|
|
|
268
275
|
# If no command was specified, run the main functionality
|
|
@@ -289,7 +296,7 @@ def handle_cli_commands(args):
|
|
|
289
296
|
"""
|
|
290
297
|
# Handle --version
|
|
291
298
|
if args.version:
|
|
292
|
-
|
|
299
|
+
print_version()
|
|
293
300
|
return True
|
|
294
301
|
|
|
295
302
|
# Handle --install-service
|
|
@@ -187,7 +187,7 @@ def load_config(config_file=None, args=None):
|
|
|
187
187
|
|
|
188
188
|
# If a specific config file was provided, use it
|
|
189
189
|
if config_file and os.path.isfile(config_file):
|
|
190
|
-
|
|
190
|
+
# Store the config path but don't log it yet - will be logged by main.py
|
|
191
191
|
with open(config_file, "r") as f:
|
|
192
192
|
relay_config = yaml.load(f, Loader=SafeLoader)
|
|
193
193
|
config_path = config_file
|
|
@@ -200,10 +200,9 @@ def load_config(config_file=None, args=None):
|
|
|
200
200
|
for path in config_paths:
|
|
201
201
|
if os.path.isfile(path):
|
|
202
202
|
config_path = path
|
|
203
|
-
|
|
203
|
+
# Store the config path but don't log it yet - will be logged by main.py
|
|
204
204
|
with open(config_path, "r") as f:
|
|
205
205
|
relay_config = yaml.load(f, Loader=SafeLoader)
|
|
206
|
-
logger.info(f"Loaded configuration with keys: {list(relay_config.keys())}")
|
|
207
206
|
return relay_config
|
|
208
207
|
|
|
209
208
|
# No config file found
|
|
@@ -2,44 +2,84 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
from logging.handlers import RotatingFileHandler
|
|
4
4
|
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.logging import RichHandler
|
|
7
|
+
|
|
5
8
|
from mmrelay.cli import parse_arguments
|
|
6
9
|
from mmrelay.config import get_log_dir
|
|
7
10
|
|
|
11
|
+
# Initialize Rich console
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
# Define custom log level styles - not used directly but kept for reference
|
|
15
|
+
# Rich 14.0.0+ supports level_styles parameter, but we're using an approach
|
|
16
|
+
# that works with older versions too
|
|
17
|
+
LOG_LEVEL_STYLES = {
|
|
18
|
+
"DEBUG": "dim blue",
|
|
19
|
+
"INFO": "green",
|
|
20
|
+
"WARNING": "yellow",
|
|
21
|
+
"ERROR": "bold red",
|
|
22
|
+
"CRITICAL": "bold white on red",
|
|
23
|
+
}
|
|
24
|
+
|
|
8
25
|
# Global config variable that will be set from main.py
|
|
9
26
|
config = None
|
|
10
27
|
|
|
28
|
+
# Global variable to store the log file path
|
|
29
|
+
log_file_path = None
|
|
30
|
+
|
|
11
31
|
|
|
12
32
|
def get_logger(name):
|
|
13
33
|
logger = logging.getLogger(name=name)
|
|
14
34
|
|
|
15
35
|
# Default to INFO level if config is not available
|
|
16
36
|
log_level = logging.INFO
|
|
37
|
+
color_enabled = True # Default to using colors
|
|
17
38
|
|
|
18
|
-
# Try to get log level from config
|
|
39
|
+
# Try to get log level and color settings from config
|
|
19
40
|
global config
|
|
20
|
-
if config is not None and "logging" in config
|
|
21
|
-
|
|
41
|
+
if config is not None and "logging" in config:
|
|
42
|
+
if "level" in config["logging"]:
|
|
43
|
+
log_level = getattr(logging, config["logging"]["level"].upper())
|
|
44
|
+
# Check if colors should be disabled
|
|
45
|
+
if "color_enabled" in config["logging"]:
|
|
46
|
+
color_enabled = config["logging"]["color_enabled"]
|
|
22
47
|
|
|
23
48
|
logger.setLevel(log_level)
|
|
24
49
|
logger.propagate = False
|
|
25
50
|
|
|
26
|
-
# Add
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
51
|
+
# Add handler for console logging (with or without colors)
|
|
52
|
+
if color_enabled:
|
|
53
|
+
# Use Rich handler with colors
|
|
54
|
+
console_handler = RichHandler(
|
|
55
|
+
rich_tracebacks=True,
|
|
56
|
+
console=console,
|
|
57
|
+
show_time=True,
|
|
58
|
+
show_level=True,
|
|
59
|
+
show_path=False,
|
|
60
|
+
markup=True,
|
|
61
|
+
log_time_format="%Y-%m-%d %H:%M:%S",
|
|
62
|
+
omit_repeated_times=False,
|
|
63
|
+
)
|
|
64
|
+
console_handler.setFormatter(logging.Formatter("%(name)s: %(message)s"))
|
|
65
|
+
else:
|
|
66
|
+
# Use standard handler without colors
|
|
67
|
+
console_handler = logging.StreamHandler()
|
|
68
|
+
console_handler.setFormatter(
|
|
69
|
+
logging.Formatter(
|
|
70
|
+
fmt="%(asctime)s %(levelname)s:%(name)s:%(message)s",
|
|
71
|
+
datefmt="%Y-%m-%d %H:%M:%S %z",
|
|
72
|
+
)
|
|
32
73
|
)
|
|
33
|
-
)
|
|
34
|
-
logger.addHandler(stream_handler)
|
|
74
|
+
logger.addHandler(console_handler)
|
|
35
75
|
|
|
36
76
|
# Check command line arguments for log file path
|
|
37
77
|
args = parse_arguments()
|
|
38
78
|
|
|
39
|
-
# Check if file logging is enabled
|
|
79
|
+
# Check if file logging is enabled (default to True for better user experience)
|
|
40
80
|
if (
|
|
41
81
|
config is not None
|
|
42
|
-
and config.get("logging", {}).get("log_to_file",
|
|
82
|
+
and config.get("logging", {}).get("log_to_file", True)
|
|
43
83
|
or args.logfile
|
|
44
84
|
):
|
|
45
85
|
# Priority: 1. Command line arg, 2. Config file, 3. Default location (~/.mmrelay/logs)
|
|
@@ -64,21 +104,10 @@ def get_logger(name):
|
|
|
64
104
|
if log_dir: # Ensure non-empty directory paths exist
|
|
65
105
|
os.makedirs(log_dir, exist_ok=True)
|
|
66
106
|
|
|
67
|
-
#
|
|
107
|
+
# Store the log file path for later use
|
|
68
108
|
if name == "M<>M Relay":
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
basic_logger = logging.getLogger("LogSetup")
|
|
72
|
-
basic_logger.setLevel(logging.INFO)
|
|
73
|
-
basic_handler = logging.StreamHandler()
|
|
74
|
-
basic_handler.setFormatter(
|
|
75
|
-
logging.Formatter(
|
|
76
|
-
fmt="%(asctime)s %(levelname)s:%(name)s:%(message)s",
|
|
77
|
-
datefmt="%Y-%m-%d %H:%M:%S %z",
|
|
78
|
-
)
|
|
79
|
-
)
|
|
80
|
-
basic_logger.addHandler(basic_handler)
|
|
81
|
-
basic_logger.info(f"Writing logs to: {log_file}")
|
|
109
|
+
global log_file_path
|
|
110
|
+
log_file_path = log_file
|
|
82
111
|
|
|
83
112
|
# Create a file handler for logging
|
|
84
113
|
try:
|
|
@@ -10,8 +10,9 @@ import sys
|
|
|
10
10
|
|
|
11
11
|
from nio import ReactionEvent, RoomMessageEmote, RoomMessageNotice, RoomMessageText
|
|
12
12
|
|
|
13
|
+
# Import version from package
|
|
13
14
|
# Import meshtastic_utils as a module to set event_loop
|
|
14
|
-
from mmrelay import meshtastic_utils
|
|
15
|
+
from mmrelay import __version__, meshtastic_utils
|
|
15
16
|
from mmrelay.db_utils import (
|
|
16
17
|
initialize_database,
|
|
17
18
|
update_longnames,
|
|
@@ -33,6 +34,18 @@ logger = get_logger(name="M<>M Relay")
|
|
|
33
34
|
logging.getLogger("nio").setLevel(logging.ERROR)
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
# Flag to track if banner has been printed
|
|
38
|
+
_banner_printed = False
|
|
39
|
+
|
|
40
|
+
def print_banner():
|
|
41
|
+
"""Print a simple startup message with version information."""
|
|
42
|
+
global _banner_printed
|
|
43
|
+
# Only print the banner once
|
|
44
|
+
if not _banner_printed:
|
|
45
|
+
logger.info(f"Starting MMRelay v{__version__}")
|
|
46
|
+
_banner_printed = True
|
|
47
|
+
|
|
48
|
+
|
|
36
49
|
async def main(config):
|
|
37
50
|
"""
|
|
38
51
|
Main asynchronous function to set up and run the relay.
|
|
@@ -202,6 +215,9 @@ def run_main(args):
|
|
|
202
215
|
Returns:
|
|
203
216
|
int: Exit code (0 for success, non-zero for failure)
|
|
204
217
|
"""
|
|
218
|
+
# Print the banner at startup
|
|
219
|
+
print_banner()
|
|
220
|
+
|
|
205
221
|
# Handle the --data-dir option
|
|
206
222
|
if args and args.data_dir:
|
|
207
223
|
import os
|
|
@@ -245,6 +261,19 @@ def run_main(args):
|
|
|
245
261
|
set_config(db_utils, config)
|
|
246
262
|
set_config(base_plugin, config)
|
|
247
263
|
|
|
264
|
+
# Get config path and log file path for logging
|
|
265
|
+
from mmrelay.config import config_path
|
|
266
|
+
from mmrelay.log_utils import log_file_path
|
|
267
|
+
|
|
268
|
+
# Create a logger with a different name to avoid conflicts with the one in config.py
|
|
269
|
+
config_rich_logger = get_logger("ConfigInfo")
|
|
270
|
+
|
|
271
|
+
# Now log the config file and log file locations with the properly formatted logger
|
|
272
|
+
if config_path:
|
|
273
|
+
config_rich_logger.info(f"Config file location: {config_path}")
|
|
274
|
+
if log_file_path:
|
|
275
|
+
config_rich_logger.info(f"Log file location: {log_file_path}")
|
|
276
|
+
|
|
248
277
|
# Check if config exists and has the required keys
|
|
249
278
|
required_keys = ["matrix", "meshtastic", "matrix_rooms"]
|
|
250
279
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import contextlib
|
|
3
3
|
import io
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
4
6
|
import threading
|
|
5
7
|
import time
|
|
6
8
|
from typing import List
|
|
@@ -46,6 +48,32 @@ shutting_down = False
|
|
|
46
48
|
reconnect_task = None # To keep track of the reconnect task
|
|
47
49
|
|
|
48
50
|
|
|
51
|
+
def is_running_as_service():
|
|
52
|
+
"""
|
|
53
|
+
Check if the application is running as a systemd service.
|
|
54
|
+
This is used to determine whether to show Rich progress indicators.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
bool: True if running as a service, False otherwise
|
|
58
|
+
"""
|
|
59
|
+
# Check for INVOCATION_ID environment variable (set by systemd)
|
|
60
|
+
if os.environ.get("INVOCATION_ID"):
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
# Check if parent process is systemd
|
|
64
|
+
try:
|
|
65
|
+
with open("/proc/self/status") as f:
|
|
66
|
+
for line in f:
|
|
67
|
+
if line.startswith("PPid:"):
|
|
68
|
+
ppid = int(line.split()[1])
|
|
69
|
+
with open(f"/proc/{ppid}/comm") as p:
|
|
70
|
+
return p.read().strip() == "systemd"
|
|
71
|
+
except (FileNotFoundError, PermissionError, ValueError):
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
|
|
49
77
|
def serial_port_exists(port_name):
|
|
50
78
|
"""
|
|
51
79
|
Check if the specified serial port exists.
|
|
@@ -118,7 +146,7 @@ def connect_meshtastic(passed_config=None, force_connect=False):
|
|
|
118
146
|
if connection_type == "serial":
|
|
119
147
|
# Serial connection
|
|
120
148
|
serial_port = config["meshtastic"]["serial_port"]
|
|
121
|
-
logger.info(f"Connecting to serial port {serial_port}
|
|
149
|
+
logger.info(f"Connecting to serial port {serial_port}")
|
|
122
150
|
|
|
123
151
|
# Check if serial port exists before connecting
|
|
124
152
|
if not serial_port_exists(serial_port):
|
|
@@ -137,7 +165,9 @@ def connect_meshtastic(passed_config=None, force_connect=False):
|
|
|
137
165
|
# BLE connection
|
|
138
166
|
ble_address = config["meshtastic"].get("ble_address")
|
|
139
167
|
if ble_address:
|
|
140
|
-
logger.info(f"Connecting to BLE address {ble_address}
|
|
168
|
+
logger.info(f"Connecting to BLE address {ble_address}")
|
|
169
|
+
|
|
170
|
+
# Connect without progress indicator
|
|
141
171
|
meshtastic_client = meshtastic.ble_interface.BLEInterface(
|
|
142
172
|
address=ble_address,
|
|
143
173
|
noProto=False,
|
|
@@ -151,7 +181,9 @@ def connect_meshtastic(passed_config=None, force_connect=False):
|
|
|
151
181
|
elif connection_type == "tcp":
|
|
152
182
|
# TCP connection
|
|
153
183
|
target_host = config["meshtastic"]["host"]
|
|
154
|
-
logger.info(f"Connecting to host {target_host}
|
|
184
|
+
logger.info(f"Connecting to host {target_host}")
|
|
185
|
+
|
|
186
|
+
# Connect without progress indicator
|
|
155
187
|
meshtastic_client = meshtastic.tcp_interface.TCPInterface(
|
|
156
188
|
hostname=target_host
|
|
157
189
|
)
|
|
@@ -244,7 +276,25 @@ async def reconnect():
|
|
|
244
276
|
logger.info(
|
|
245
277
|
f"Reconnection attempt starting in {backoff_time} seconds..."
|
|
246
278
|
)
|
|
247
|
-
|
|
279
|
+
|
|
280
|
+
# Show reconnection countdown with Rich (if not in a service)
|
|
281
|
+
if not is_running_as_service():
|
|
282
|
+
from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn
|
|
283
|
+
with Progress(
|
|
284
|
+
TextColumn("[cyan]Meshtastic: Reconnecting in"),
|
|
285
|
+
BarColumn(),
|
|
286
|
+
TextColumn("[cyan]{task.percentage:.0f}%"),
|
|
287
|
+
TimeRemainingColumn(),
|
|
288
|
+
transient=True,
|
|
289
|
+
) as progress:
|
|
290
|
+
task = progress.add_task("Waiting", total=backoff_time)
|
|
291
|
+
for _ in range(backoff_time):
|
|
292
|
+
if shutting_down:
|
|
293
|
+
break
|
|
294
|
+
await asyncio.sleep(1)
|
|
295
|
+
progress.update(task, advance=1)
|
|
296
|
+
else:
|
|
297
|
+
await asyncio.sleep(backoff_time)
|
|
248
298
|
if shutting_down:
|
|
249
299
|
logger.debug(
|
|
250
300
|
"Shutdown in progress. Aborting reconnection attempts."
|