Skip to content

Commit 2a36cb2

Browse files
authored
Merge pull request #56 from agessaman/dev
Version 0.8
2 parents ea7b92e + a38ac56 commit 2a36cb2

File tree

145 files changed

+27365
-1503
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+27365
-1503
lines changed

.dockerignore

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Git
2+
.git
3+
.gitignore
4+
.gitattributes
5+
6+
# Python
7+
__pycache__/
8+
*.py[cod]
9+
*$py.class
10+
*.so
11+
.Python
12+
*.egg-info/
13+
dist/
14+
build/
15+
*.egg
16+
17+
# Virtual environments
18+
venv/
19+
env/
20+
ENV/
21+
22+
# IDE
23+
.vscode/
24+
.idea/
25+
*.swp
26+
*.swo
27+
*~
28+
29+
# OS
30+
.DS_Store
31+
Thumbs.db
32+
33+
# Project specific
34+
*.db
35+
*.db-shm
36+
*.db-wal
37+
*.log
38+
logs/
39+
backups/
40+
*.ini
41+
config.ini
42+
config.ini.example
43+
config.ini.minimal-example
44+
config.min.ini
45+
46+
# Documentation
47+
docs/
48+
*.md
49+
!README.md
50+
51+
# Test files
52+
test_scripts/
53+
*.test.py
54+
*_test.py
55+
56+
# Development
57+
dev/
58+
flake.lock
59+
flake.nix
60+
nix/
61+
62+
# Service files
63+
*.service
64+
*.plist
65+
*.sh
66+
!install-service.sh
67+
!uninstall-service.sh
68+
69+
# Website
70+
website/
71+
72+
# MQTT bridge
73+
mctomqtt.py
74+
75+
# Database backups
76+
backup_database.py

.env.example

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Docker image configuration
2+
# This file is auto-generated by docker-setup.sh based on your current git branch
3+
# You can manually override these values if needed
4+
5+
# Docker image registry (default: ghcr.io/agessaman/meshcore-bot)
6+
DOCKER_IMAGE_REGISTRY=ghcr.io/agessaman/meshcore-bot
7+
8+
# Docker image tag (auto-detected from git branch)
9+
# - main/master branches -> latest
10+
# - dev branch -> dev
11+
# - other branches -> branch name (with / replaced by -)
12+
DOCKER_IMAGE_TAG=latest

.github/workflows/docker-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
type=semver,pattern={{version}}
5555
type=semver,pattern={{major}}.{{minor}}
5656
type=semver,pattern={{major}}
57-
type=sha,prefix={{branch}}-
57+
type=sha,prefix=sha-
5858
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }}
5959
6060
- name: Build and push Docker image

.github/workflows/docs.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Build and deploy Material for MkDocs to GitHub Pages
2+
name: Deploy docs
3+
4+
on:
5+
push:
6+
branches:
7+
- main
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: write
12+
13+
jobs:
14+
deploy:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: "3.x"
23+
24+
- name: Install MkDocs and Material
25+
run: pip install mkdocs-material
26+
27+
- name: Deploy to GitHub Pages
28+
run: mkdocs gh-deploy --force

.github/workflows/test.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
- dev
9+
pull_request:
10+
branches:
11+
- main
12+
- master
13+
- dev
14+
workflow_dispatch:
15+
16+
jobs:
17+
test:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: "3.11"
26+
27+
- name: Install dependencies
28+
run: |
29+
python -m pip install --upgrade pip
30+
pip install -e ".[test]"
31+
32+
- name: Run tests
33+
run: pytest tests/ -v --tb=short

.gitignore

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,28 @@ mctomqtt.py
129129
bot_cli.py
130130
bot_start_time.txt
131131

132-
# Test files and development artifacts
132+
# Test files and development artifacts (root level)
133133
test_*.py
134134
test_*.db
135135
test_*.log
136136
*_test.py
137137
*_test.db
138+
# Allow tests/ directory (pytest convention)
139+
!tests/
140+
!tests/**/*.py
138141

139142
# Local documentation and development files
140143
docs/local/
141-
tests/
142144
test_scripts/
143145
dev/
146+
website/
147+
# pytest.ini committed for asyncio_mode and test discovery
148+
pymc-test/*
149+
config-pymc.ini
150+
*.key
151+
152+
# Docker data directory (user-specific config, databases, logs)
153+
# Ignore contents but keep directory structure
154+
data/*
155+
!data/.gitkeep
156+

Dockerfile

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Multi-stage build for meshcore-bot
2+
FROM python:3.11-slim AS builder
3+
4+
# Install build dependencies (with cache mount for apt)
5+
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
6+
--mount=type=cache,target=/var/lib/apt,sharing=locked \
7+
apt-get update && apt-get install -y --no-install-recommends \
8+
build-essential \
9+
&& rm -rf /var/lib/apt/lists/*
10+
11+
# Set working directory
12+
WORKDIR /build
13+
14+
# Copy dependency files
15+
COPY requirements.txt pyproject.toml ./
16+
17+
# Install Python dependencies (with cache mount for pip)
18+
RUN --mount=type=cache,target=/root/.cache/pip \
19+
pip install --user -r requirements.txt
20+
21+
# Final stage
22+
FROM python:3.11-slim
23+
24+
# Install runtime dependencies (with cache mount for apt)
25+
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
26+
--mount=type=cache,target=/var/lib/apt,sharing=locked \
27+
apt-get update && apt-get install -y --no-install-recommends \
28+
# For serial port access
29+
udev \
30+
# For BLE support (optional, but commonly needed)
31+
libbluetooth3 \
32+
# Cleanup
33+
&& rm -rf /var/lib/apt/lists/*
34+
35+
# Create non-root user and add to dialout group for serial port access
36+
RUN useradd -m -u 1000 -G dialout,tty meshcore && \
37+
mkdir -p /app /data/config /data/databases /data/logs /data/backups && \
38+
chown -R meshcore:meshcore /app /data
39+
40+
# Copy Python dependencies from builder
41+
COPY --from=builder /root/.local /home/meshcore/.local
42+
43+
# Set working directory
44+
WORKDIR /app
45+
46+
# Copy application files
47+
COPY --chown=meshcore:meshcore . /app/
48+
49+
# Set PATH to include user's local bin
50+
ENV PATH=/home/meshcore/.local/bin:$PATH \
51+
PYTHONUNBUFFERED=1 \
52+
PYTHONDONTWRITEBYTECODE=1
53+
54+
# Switch to non-root user
55+
USER meshcore
56+
57+
# Health check: verify the main process (PID 1, the bot) is still running
58+
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
59+
CMD ["sh", "-c", "kill -0 1"]
60+
61+
# Default command
62+
CMD ["python3", "meshcore_bot.py", "--config", "/data/config/config.ini"]

README.md

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ A Python bot that connects to MeshCore mesh networks via serial port, BLE, or TC
77
- **Connection Methods**: Serial port, BLE (Bluetooth Low Energy), or TCP/IP
88
- **Keyword Responses**: Configurable keyword-response pairs with template variables
99
- **Command System**: Plugin-based command architecture with built-in commands
10-
- **Rate Limiting**: Configurable rate limiting to prevent network spam
10+
- **Rate Limiting**: Global, per-user (by pubkey or name), and bot transmission rate limits to prevent spam
1111
- **User Management**: Ban/unban users with persistent storage
1212
- **Scheduled Messages**: Send messages at configured times
1313
- **Direct Message Support**: Respond to private messages
@@ -84,6 +84,43 @@ sudo systemctl status meshcore-bot
8484

8585
See [SERVICE-INSTALLATION.md](SERVICE-INSTALLATION.md) for detailed service installation instructions.
8686

87+
### Docker Deployment
88+
For containerized deployment using Docker:
89+
90+
1. **Create data directories and configuration**:
91+
```bash
92+
mkdir -p data/{config,databases,logs,backups}
93+
cp config.ini.example data/config/config.ini
94+
# Edit data/config/config.ini with your settings
95+
```
96+
97+
2. **Update paths in config.ini** to use `/data/` directories:
98+
```ini
99+
[Bot]
100+
db_path = /data/databases/meshcore_bot.db
101+
102+
[Logging]
103+
log_file = /data/logs/meshcore_bot.log
104+
```
105+
106+
3. **Build and start with Docker Compose**:
107+
```bash
108+
docker compose build
109+
docker compose up -d
110+
```
111+
112+
Or build and start in one command:
113+
```bash
114+
docker compose up -d --build
115+
```
116+
117+
4. **View logs**:
118+
```bash
119+
docker-compose logs -f
120+
```
121+
122+
See [DOCKER.md](docs/DOCKER.md) for detailed Docker deployment instructions, including serial port access, web viewer configuration, and troubleshooting.
123+
87124
## NixOS
88125
Use the Nix flake via flake.nix
89126
```nix
@@ -127,7 +164,10 @@ timeout = 30 # Connection timeout
127164
[Bot]
128165
bot_name = MeshCoreBot # Bot identification name
129166
enabled = true # Enable/disable bot
130-
rate_limit_seconds = 2 # Rate limiting interval
167+
rate_limit_seconds = 2 # Global: min seconds between any bot reply
168+
bot_tx_rate_limit_seconds = 1.0 # Min seconds between bot transmissions
169+
per_user_rate_limit_seconds = 5 # Per-user: min seconds between replies to same user (pubkey or name)
170+
per_user_rate_limit_enabled = true
131171
startup_advert = flood # Send advert on startup
132172
```
133173

@@ -145,6 +185,8 @@ help = "Bot Help: test, ping, help, hello, cmd, wx, aqi, sun, moon, solar, hfcon
145185
[Channels]
146186
monitor_channels = general,test,emergency # Channels to monitor
147187
respond_to_dms = true # Enable DM responses
188+
# Optional: limit channel responses to certain keywords (DM gets all triggers)
189+
# channel_keywords = help,ping,test,hello
148190
```
149191

150192
### External Data APIs
@@ -158,7 +200,7 @@ airnow_api_key = # Air quality data
158200
### Alert Command
159201
```ini
160202
[Alert_Command]
161-
alert_enabled = true # Enable/disable alert command
203+
enabled = true # Enable/disable alert command
162204
max_incident_age_hours = 24 # Maximum age for incidents (hours)
163205
max_distance_km = 20.0 # Maximum distance for proximity queries (km)
164206
agency.city.<city_name> = <agency_ids> # City-specific agency IDs (e.g., agency.city.seattle = 17D20,17M15)
@@ -183,7 +225,7 @@ python meshcore_bot.py
183225

184226
### Available Commands
185227

186-
For a comprehensive list of all available commands with examples and detailed explanations, see [COMMANDS.md](COMMANDS.md).
228+
For a comprehensive list of all available commands with examples and detailed explanations, see [COMMANDS.md](docs/COMMANDS.md).
187229

188230
Quick reference:
189231
- **Basic:** `test`, `ping`, `help`, `hello`, `cmd`
@@ -205,6 +247,25 @@ Keyword responses support these template variables:
205247
- `{timestamp}` - Message timestamp
206248
- `{path}` - Message routing path
207249

250+
### Adding Newlines
251+
252+
To add newlines in keyword responses, use `\n` (single backslash + n):
253+
254+
```ini
255+
[Keywords]
256+
test = "Line 1\nLine 2\nLine 3"
257+
```
258+
259+
This will output:
260+
```
261+
Line 1
262+
Line 2
263+
Line 3
264+
```
265+
266+
To use a literal backslash + n, use `\\n` (double backslash + n).
267+
Other escape sequences: `\t` (tab), `\r` (carriage return), `\\` (literal backslash)
268+
208269
Example:
209270
```ini
210271
[Keywords]
@@ -275,7 +336,9 @@ help = "Bot Help: test, ping, help, hello, cmd, wx, gwx, aqi, sun, moon, solar,
275336
- Check meshcore library documentation for protocol details
276337

277338
5. **Rate Limiting**:
278-
- Adjust `rate_limit_seconds` in config
339+
- **Global**: `rate_limit_seconds` — minimum time between any two bot replies
340+
- **Per-user**: `per_user_rate_limit_seconds` and `per_user_rate_limit_enabled` — minimum time between replies to the same user (user identified by public key when available, else sender name; channel senders often matched by name)
341+
- **Bot TX**: `bot_tx_rate_limit_seconds` — minimum time between bot transmissions on the mesh
279342
- Check logs for rate limiting messages
280343

281344
### Debug Mode

0 commit comments

Comments
 (0)