From 69ac3ccdfba3647a6d535c83a391852d9d8bf424 Mon Sep 17 00:00:00 2001 From: agessaman Date: Fri, 6 Mar 2026 22:03:13 -0800 Subject: [PATCH] Update requirements and enhance documentation for service installation and message handling - Changed `meshcore` dependency version in `requirements.txt` from `>=2.2.14` to `==2.2.14` for consistency. - Added detailed instructions in `SERVICE-INSTALLATION.md` regarding Python version compatibility and potential f-string issues with Python 3.11. - Introduced a new section in `local-plugins.md` explaining how to handle message chunking and bot rate limits, providing code examples for better clarity. --- docs/SERVICE-INSTALLATION.md | 12 +++++++++++- docs/local-plugins.md | 31 +++++++++++++++++++++++++++++++ requirements.txt | 2 +- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/SERVICE-INSTALLATION.md b/docs/SERVICE-INSTALLATION.md index f12cef0..017c412 100644 --- a/docs/SERVICE-INSTALLATION.md +++ b/docs/SERVICE-INSTALLATION.md @@ -5,7 +5,7 @@ This guide explains how to install the MeshCore Bot as a systemd service on Linu ## Prerequisites - Linux system with systemd -- Python 3.7+ +- Python 3.7+ (Python 3.12+ recommended; on 3.11 the meshcore dependency has an f-string bug — the install script patches it automatically) - Root/sudo access - MeshCore-compatible device @@ -144,6 +144,16 @@ sudo systemctl restart meshcore-bot 3. Check configuration: `sudo nano /opt/meshcore-bot/config.ini` 4. Verify dependencies: `sudo pip3 list | grep meshcore` +### SyntaxError: f-string: unmatched '[' (Python 3.11) +If the bot fails on import with this error in `meshcore/commands/contact.py`, you are on Python 3.11 and the **meshcore** dependency uses an f-string that only works on Python 3.12+. + +**Options:** +- **Recommended:** Use Python 3.12+ (create the venv with `python3.12` if available, then re-run `./install-service.sh --upgrade`). +- **Or:** Re-run the install script so it can patch the installed package: + `sudo ./install-service.sh --upgrade` + The script detects Python 3.11 and patches the meshcore file in the venv. +- **Manual patch:** Edit `/opt/meshcore-bot/venv/lib/python3.11/site-packages/meshcore/commands/contact.py`, find the line containing `contact["adv_name"]` inside the f-string, and change it to `contact['adv_name']` (single quotes around `adv_name`). + ### Permission Issues 1. Check file ownership: `ls -la /opt/meshcore-bot/` 2. Fix permissions: `sudo chown -R meshcore:meshcore /opt/meshcore-bot` diff --git a/docs/local-plugins.md b/docs/local-plugins.md index 9656596..5c39d4e 100644 --- a/docs/local-plugins.md +++ b/docs/local-plugins.md @@ -80,6 +80,37 @@ Restart the bot so the service is loaded and started. If a local command or service has the same **name** as an already-loaded plugin or service (e.g. you add `local/commands/ping.py` with `name = "ping"`), the local one is **skipped** and a warning is logged. Choose a different name (e.g. `pinglocal`) to avoid the conflict. +## Sending multiple messages (chunking) + +When a service plugin sends a long message by splitting it into chunks and calling `send_channel_message` multiple times, the bot’s **rate limiters** can block the second and later sends. You’ll see a warning like “Rate limited. Wait X seconds.” + +**What’s going on** + +- **Global rate limit** (`[Bot]` `rate_limit_seconds`, default 10): minimum time between *any* two bot replies. If you don’t skip it, the first send uses the “slot” and the next send within that window is blocked. +- **Bot TX rate limit** (`bot_tx_rate_limit_seconds`, default 1.0): minimum time between bot transmissions on the mesh. This is always enforced. + +**What to do** + +1. **Use `skip_user_rate_limit=True`** for every chunk. That skips the global (and per-user) limits so automated service messages aren’t blocked by the “10 second” global window. +2. **Space chunks in time** so the bot TX limit is satisfied: before each chunk after the first, wait for the bot TX rate limiter and then sleep. Same pattern as the greeter and other multi-part senders: + +```python +import asyncio + +# chunks = ["first part...", "second part...", ...] +for i, chunk in enumerate(chunks): + if i > 0: + await self.bot.bot_tx_rate_limiter.wait_for_tx() + rate_limit = self.bot.config.getfloat('Bot', 'bot_tx_rate_limit_seconds', fallback=1.0) + sleep_time = max(rate_limit + 0.5, 1.0) + await asyncio.sleep(sleep_time) + await self.bot.command_manager.send_channel_message( + self.channel, chunk, skip_user_rate_limit=True + ) +``` + +So you are allowed to send multiple messages in sequence; you do **not** need 10 seconds between chunks. Use `skip_user_rate_limit=True` and about 1–1.5 seconds (or your configured `bot_tx_rate_limit_seconds` + buffer) between chunks. + ## References - [Service plugins](service-plugins.md) — built-in services and how they are enabled. diff --git a/requirements.txt b/requirements.txt index 9a1c109..323b080 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ pytz>=2023.3 aiohttp>=3.8.0 cryptography>=41.0.0 pynacl>=1.5.0 -meshcore>=2.2.14 +meshcore==2.2.14 openmeteo-requests>=1.7.2 requests-cache>=1.1.1 retry-requests>=1.0.0