diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..f371354 --- /dev/null +++ b/config.yaml @@ -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" diff --git a/main.py b/main.py index 9109fea..933d580 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,7 @@ import logging import signal import threading -from meshbot import config, VERSION +from meshbot import config from meshbot.database import Database from meshbot.bot import MeshBot from meshbot.webserver import WebServer, WebSocketManager @@ -16,10 +16,10 @@ logger = logging.getLogger(__name__) 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 - db = Database(config.DB_PATH) + db = Database(config.get("database.path", "meshdd.db")) await db.connect() # WebSocket Manager @@ -32,12 +32,15 @@ async def main(): # Webserver 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_thread = threading.Thread(target=bot.connect, daemon=True) connect_thread.start() + # Watch config for changes + asyncio.create_task(config.watch()) + # Wait for shutdown stop_event = asyncio.Event() diff --git a/meshbot/__init__.py b/meshbot/__init__.py index caad2d3..bd38a8b 100644 --- a/meshbot/__init__.py +++ b/meshbot/__init__.py @@ -1 +1 @@ -from meshbot.version import VERSION +from meshbot import config diff --git a/meshbot/bot.py b/meshbot/bot.py index a5742b0..3e36166 100644 --- a/meshbot/bot.py +++ b/meshbot/bot.py @@ -8,7 +8,6 @@ from meshtastic.tcp_interface import TCPInterface from pubsub import pub from meshbot import config -from meshbot.version import VERSION from meshbot.database import Database logger = logging.getLogger(__name__) @@ -23,8 +22,10 @@ class MeshBot: self.ws_manager = None # set by main.py def connect(self): - logger.info("Connecting to Meshtastic at %s:%s", config.MESHTASTIC_HOST, config.MESHTASTIC_PORT) - self.interface = TCPInterface(hostname=config.MESHTASTIC_HOST, portNumber=config.MESHTASTIC_PORT) + host = config.get("meshtastic.host", "localhost") + 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_connection, "meshtastic.connection.established") pub.subscribe(self._on_node_updated, "meshtastic.node.updated") @@ -143,7 +144,7 @@ class MeshBot: elif cmd == "!info": 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": response = ( diff --git a/meshbot/config.py b/meshbot/config.py index ad53be6..2d2ceaf 100644 --- a/meshbot/config.py +++ b/meshbot/config.py @@ -1,11 +1,65 @@ +import asyncio +import logging import os -MESHTASTIC_HOST = os.environ.get("MESHTASTIC_HOST", "localhost") -MESHTASTIC_PORT = int(os.environ.get("MESHTASTIC_PORT", "4403")) +import yaml -WEB_HOST = os.environ.get("WEB_HOST", "0.0.0.0") -WEB_PORT = int(os.environ.get("WEB_PORT", "8080")) +logger = logging.getLogger(__name__) -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() diff --git a/meshbot/version.py b/meshbot/version.py deleted file mode 100644 index 854f9e4..0000000 --- a/meshbot/version.py +++ /dev/null @@ -1,5 +0,0 @@ -MAJOR = 0 -MINOR = 1 -PATCH = 2 - -VERSION = f"{MAJOR}.{MINOR}.{PATCH}" diff --git a/requirements.txt b/requirements.txt index 0ace4df..03866ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ -meshtastic>=2.3.0 +meshtastic>=2.7.7 aiohttp>=3.9.0 aiosqlite>=0.19.0 +pyyaml>=6.0 diff --git a/scripts/pre-commit b/scripts/pre-commit deleted file mode 100755 index bf2ea35..0000000 --- a/scripts/pre-commit +++ /dev/null @@ -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"