refactor: Replace env-based config and version.py with config.yaml

Move all configuration to config.yaml with live-reload (file watcher).
Version is now managed in config.yaml instead of version.py.
Remove pre-commit hook for automatic version bumping.
Pin meshtastic dependency to >=2.7.7.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ppfeiffer 2026-02-15 13:11:09 +01:00
parent 6e5573aa0b
commit a6c09b19eb
8 changed files with 90 additions and 93 deletions

15
config.yaml Normal file
View file

@ -0,0 +1,15 @@
version: "0.1.2"
bot:
name: "MeshDD-Bot"
meshtastic:
host: "192.168.11.11"
port: 4403
web:
host: "0.0.0.0"
port: 8080
database:
path: "meshdd.db"

11
main.py
View file

@ -3,7 +3,7 @@ import logging
import signal import signal
import threading import threading
from meshbot import config, VERSION from meshbot import config
from meshbot.database import Database from meshbot.database import Database
from meshbot.bot import MeshBot from meshbot.bot import MeshBot
from meshbot.webserver import WebServer, WebSocketManager from meshbot.webserver import WebServer, WebSocketManager
@ -16,10 +16,10 @@ logger = logging.getLogger(__name__)
async def main(): async def main():
logger.info("Starting %s v%s", config.BOT_NAME, VERSION) logger.info("Starting %s v%s", config.get("bot.name"), config.get("version"))
# Database # Database
db = Database(config.DB_PATH) db = Database(config.get("database.path", "meshdd.db"))
await db.connect() await db.connect()
# WebSocket Manager # WebSocket Manager
@ -32,12 +32,15 @@ async def main():
# Webserver # Webserver
webserver = WebServer(db, ws_manager) webserver = WebServer(db, ws_manager)
runner = await webserver.start(config.WEB_HOST, config.WEB_PORT) runner = await webserver.start(config.get("web.host", "0.0.0.0"), config.get("web.port", 8080))
# Connect Meshtastic in a thread (blocking call) # Connect Meshtastic in a thread (blocking call)
connect_thread = threading.Thread(target=bot.connect, daemon=True) connect_thread = threading.Thread(target=bot.connect, daemon=True)
connect_thread.start() connect_thread.start()
# Watch config for changes
asyncio.create_task(config.watch())
# Wait for shutdown # Wait for shutdown
stop_event = asyncio.Event() stop_event = asyncio.Event()

View file

@ -1 +1 @@
from meshbot.version import VERSION from meshbot import config

View file

@ -8,7 +8,6 @@ from meshtastic.tcp_interface import TCPInterface
from pubsub import pub from pubsub import pub
from meshbot import config from meshbot import config
from meshbot.version import VERSION
from meshbot.database import Database from meshbot.database import Database
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -23,8 +22,10 @@ class MeshBot:
self.ws_manager = None # set by main.py self.ws_manager = None # set by main.py
def connect(self): def connect(self):
logger.info("Connecting to Meshtastic at %s:%s", config.MESHTASTIC_HOST, config.MESHTASTIC_PORT) host = config.get("meshtastic.host", "localhost")
self.interface = TCPInterface(hostname=config.MESHTASTIC_HOST, portNumber=config.MESHTASTIC_PORT) port = config.get("meshtastic.port", 4403)
logger.info("Connecting to Meshtastic at %s:%s", host, port)
self.interface = TCPInterface(hostname=host, portNumber=port)
pub.subscribe(self._on_receive, "meshtastic.receive") pub.subscribe(self._on_receive, "meshtastic.receive")
pub.subscribe(self._on_connection, "meshtastic.connection.established") pub.subscribe(self._on_connection, "meshtastic.connection.established")
pub.subscribe(self._on_node_updated, "meshtastic.node.updated") pub.subscribe(self._on_node_updated, "meshtastic.node.updated")
@ -143,7 +144,7 @@ class MeshBot:
elif cmd == "!info": elif cmd == "!info":
uptime = self._format_uptime() uptime = self._format_uptime()
response = f" {config.BOT_NAME} v{VERSION}\nUptime: {uptime}" response = f" {config.get('bot.name', 'MeshDD-Bot')} v{config.get('version', '0.0.0')}\nUptime: {uptime}"
elif cmd == "!help": elif cmd == "!help":
response = ( response = (

View file

@ -1,11 +1,65 @@
import asyncio
import logging
import os import os
MESHTASTIC_HOST = os.environ.get("MESHTASTIC_HOST", "localhost") import yaml
MESHTASTIC_PORT = int(os.environ.get("MESHTASTIC_PORT", "4403"))
WEB_HOST = os.environ.get("WEB_HOST", "0.0.0.0") logger = logging.getLogger(__name__)
WEB_PORT = int(os.environ.get("WEB_PORT", "8080"))
DB_PATH = os.environ.get("DB_PATH", "meshdd.db") CONFIG_PATH = os.environ.get("CONFIG_PATH", os.path.join(os.path.dirname(os.path.dirname(__file__)), "config.yaml"))
BOT_NAME = os.environ.get("BOT_NAME", "MeshDD-Bot") _config = {}
_mtime = 0.0
_callbacks = []
def _load():
global _config, _mtime
with open(CONFIG_PATH, "r") as f:
_config = yaml.safe_load(f)
_mtime = os.path.getmtime(CONFIG_PATH)
logger.info("Config loaded from %s", CONFIG_PATH)
def _reload_if_changed():
global _mtime
try:
current_mtime = os.path.getmtime(CONFIG_PATH)
if current_mtime != _mtime:
old_config = _config.copy()
_load()
logger.info("Config reloaded (changed)")
for cb in _callbacks:
try:
cb(old_config, _config)
except Exception:
logger.exception("Error in config reload callback")
except Exception:
logger.exception("Error checking config file")
def on_reload(callback):
_callbacks.append(callback)
async def watch(interval: float = 2.0):
while True:
await asyncio.sleep(interval)
_reload_if_changed()
def get(key: str, default=None):
keys = key.split(".")
val = _config
for k in keys:
if isinstance(val, dict):
val = val.get(k)
else:
return default
if val is None:
return default
return val
# Load on import
_load()

View file

@ -1,5 +0,0 @@
MAJOR = 0
MINOR = 1
PATCH = 2
VERSION = f"{MAJOR}.{MINOR}.{PATCH}"

View file

@ -1,3 +1,4 @@
meshtastic>=2.3.0 meshtastic>=2.7.7
aiohttp>=3.9.0 aiohttp>=3.9.0
aiosqlite>=0.19.0 aiosqlite>=0.19.0
pyyaml>=6.0

View file

@ -1,72 +0,0 @@
#!/bin/bash
# Git pre-commit hook: Auto-increment patch version, optional minor bump
# Install: cp scripts/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
VERSION_FILE="meshbot/version.py"
CHANGELOG_FILE="CHANGELOG.md"
if [ ! -f "$VERSION_FILE" ]; then
exit 0
fi
# Read current version
MAJOR=$(grep "^MAJOR" "$VERSION_FILE" | awk -F'= ' '{print $2}')
MINOR=$(grep "^MINOR" "$VERSION_FILE" | awk -F'= ' '{print $2}')
PATCH=$(grep "^PATCH" "$VERSION_FILE" | awk -F'= ' '{print $2}')
echo "Current version: $MAJOR.$MINOR.$PATCH"
# Ask for minor bump (only if interactive terminal)
if [ -t 0 ]; then
read -p "Minor-Version erhöhen? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
MINOR=$((MINOR + 1))
PATCH=0
else
PATCH=$((PATCH + 1))
fi
else
PATCH=$((PATCH + 1))
fi
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo "New version: $NEW_VERSION"
# Update version.py
cat > "$VERSION_FILE" << EOF
MAJOR = $MAJOR
MINOR = $MINOR
PATCH = $PATCH
VERSION = f"{MAJOR}.{MINOR}.{PATCH}"
EOF
# Update CHANGELOG.md - add entry after first "## " line
DATE=$(date +%Y-%m-%d)
COMMIT_MSG=$(git log --format=%B -1 HEAD 2>/dev/null || echo "Update")
# Get staged files for changelog context
STAGED_FILES=$(git diff --cached --name-only)
# Add changelog entry
TEMP_FILE=$(mktemp)
HEADER_DONE=false
while IFS= read -r line; do
echo "$line" >> "$TEMP_FILE"
if [[ "$line" == "# Changelog" ]] && [ "$HEADER_DONE" = false ]; then
echo "" >> "$TEMP_FILE"
echo "## [$NEW_VERSION] - $DATE" >> "$TEMP_FILE"
echo "### Changed" >> "$TEMP_FILE"
echo "- Auto-commit update" >> "$TEMP_FILE"
HEADER_DONE=true
fi
done < "$CHANGELOG_FILE"
mv "$TEMP_FILE" "$CHANGELOG_FILE"
# Stage updated files
git add "$VERSION_FILE" "$CHANGELOG_FILE"
echo "Version updated to $NEW_VERSION"