From 5bec26e5fff5a9e0d3554188fed7f31fa4440486 Mon Sep 17 00:00:00 2001 From: Louis King Date: Fri, 17 Apr 2026 18:16:25 +0100 Subject: [PATCH] Align MQTT_TRANSPORT and MQTT_WS_PATH defaults with MeshCore broker requirements The MeshCore MQTT broker requires WebSocket transport, but Python defaults were still tcp and /mqtt from the Mosquitto era. Align all defaults to websockets and / to match Docker Compose and documented behavior. Also fixes docs-sync audit findings: - Remove stale PLAN.md/TASKS.md references from AGENTS.md - Add missing NETWORK_DOMAIN, NETWORK_NAME vars to AGENTS.md env list - Add missing WEBHOOK_CHANNEL_MESSAGE_SECRET and WEBHOOK_DIRECT_MESSAGE_SECRET to AGENTS.md webhook table - Add native install note for MQTT_HOST in .env.example - Update UPGRADING.md note to reflect aligned defaults --- .env.example | 1 + AGENTS.md | 8 +++++--- UPGRADING.md | 2 +- src/meshcore_hub/api/app.py | 4 ++-- src/meshcore_hub/api/cli.py | 4 ++-- src/meshcore_hub/api/dependencies.py | 4 ++-- src/meshcore_hub/collector/cli.py | 4 ++-- src/meshcore_hub/collector/subscriber.py | 8 ++++---- src/meshcore_hub/common/config.py | 4 ++-- 9 files changed, 21 insertions(+), 18 deletions(-) diff --git a/.env.example b/.env.example index a2116b1..51269cd 100644 --- a/.env.example +++ b/.env.example @@ -77,6 +77,7 @@ SEED_HOME=./seed # MQTT Broker host # When using the local MQTT broker (--profile mqtt), use "mqtt" # When using an external broker, set the hostname/IP +# For native (non-Docker) installs, use "localhost" (the Python default) MQTT_HOST=mqtt # MQTT Broker port diff --git a/AGENTS.md b/AGENTS.md index ac53424..3346229 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ This document provides context and guidelines for AI coding assistants working o - `source .venv/bin/activate` * You MUST install all project dependencies using `pip install -e ".[dev]"` command` * You MUST install `pre-commit` for quality checks -* You MUST keep project documentation in sync with behavior/config/schema changes made in code (at minimum update relevant sections in `README.md`, `SCHEMAS.md`, `PLAN.md`, and/or `TASKS.md` when applicable) +* You MUST keep project documentation in sync with behavior/config/schema changes made in code (at minimum update relevant sections in `README.md`, `SCHEMAS.md`, and/or `UPGRADING.md` when applicable) * Before commiting: - Run **targeted tests** for the components you changed, not the full suite: - `pytest tests/test_web/` for web-only changes (templates, static JS, web routes) @@ -593,8 +593,6 @@ meshcore-hub collector ## Environment Variables -See [PLAN.md](PLAN.md#configuration-environment-variables) for complete list. - Key variables: - `COMPOSE_PROJECT_NAME` - Docker Compose project prefix for containers and volumes (default: `hub`) - `DATA_HOME` - Base directory for runtime data (default: `./data`) @@ -613,6 +611,8 @@ Key variables: - `WEB_AUTO_REFRESH_SECONDS` - Auto-refresh interval in seconds for list pages (default: `30`, `0` to disable) - `TZ` - Timezone for web dashboard date/time display (default: `UTC`, e.g., `America/New_York`, `Europe/London`) - `FEATURE_DASHBOARD`, `FEATURE_NODES`, `FEATURE_ADVERTISEMENTS`, `FEATURE_MESSAGES`, `FEATURE_MAP`, `FEATURE_MEMBERS`, `FEATURE_PAGES` - Feature flags to enable/disable specific web dashboard pages (default: all `true`). Dependencies: Dashboard auto-disables when all of Nodes/Advertisements/Messages are disabled. Map auto-disables when Nodes is disabled. +- `NETWORK_DOMAIN` - Network domain name (default: none) +- `NETWORK_NAME` - Network display name (default: `MeshCore Network`) - `METRICS_ENABLED` - Enable Prometheus metrics endpoint at /metrics (default: `true`) - `METRICS_CACHE_TTL` - Seconds to cache metrics output (default: `60`) - `LOG_LEVEL` - Logging verbosity @@ -692,7 +692,9 @@ The collector supports forwarding events to external HTTP endpoints: | `WEBHOOK_MESSAGE_URL` | Webhook for all message events (channel + direct) | | `WEBHOOK_MESSAGE_SECRET` | Secret for message webhook | | `WEBHOOK_CHANNEL_MESSAGE_URL` | Override for channel messages only | +| `WEBHOOK_CHANNEL_MESSAGE_SECRET` | Secret for channel message webhook | | `WEBHOOK_DIRECT_MESSAGE_URL` | Override for direct messages only | +| `WEBHOOK_DIRECT_MESSAGE_SECRET` | Secret for direct message webhook | | `WEBHOOK_TIMEOUT` | Request timeout (default: 10.0s) | | `WEBHOOK_MAX_RETRIES` | Max retries on failure (default: 3) | | `WEBHOOK_RETRY_BACKOFF` | Exponential backoff multiplier (default: 2.0) | diff --git a/UPGRADING.md b/UPGRADING.md index 89d7f1f..1ca2388 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -157,7 +157,7 @@ MQTT_WS_PORT=9001 | `MQTT_USERNAME` | (empty/optional) | Subscriber username | Now **required** for collector subscriber auth. Set to match your broker's `SUBSCRIBER_1` config. | | `MQTT_PASSWORD` | (empty/optional) | Subscriber password | Now **required** for collector subscriber auth. Generate a secure password: `openssl rand -base64 32` | -> **Note:** The Python-level defaults for `MQTT_TRANSPORT` and `MQTT_WS_PATH` remain `tcp` and `/mqtt` respectively. The new values above are set in `.env.example` and `docker-compose.yml`, which override the Python defaults for Docker deployments. Non-Docker users must set these environment variables explicitly. +> **Note:** The Python-level defaults for `MQTT_TRANSPORT` and `MQTT_WS_PATH` are now `websockets` and `/`, matching the Docker Compose and `.env.example` values. No additional configuration is needed for non-Docker users. ### Variables to Add diff --git a/src/meshcore_hub/api/app.py b/src/meshcore_hub/api/app.py index fd9b3ee..e9c287e 100644 --- a/src/meshcore_hub/api/app.py +++ b/src/meshcore_hub/api/app.py @@ -55,8 +55,8 @@ def create_app( mqtt_password: str | None = None, mqtt_prefix: str = "meshcore", mqtt_tls: bool = False, - mqtt_transport: str = "tcp", - mqtt_ws_path: str = "/mqtt", + mqtt_transport: str = "websockets", + mqtt_ws_path: str = "/", cors_origins: list[str] | None = None, metrics_enabled: bool = True, metrics_cache_ttl: int = 60, diff --git a/src/meshcore_hub/api/cli.py b/src/meshcore_hub/api/cli.py index e50eec4..3fcfe23 100644 --- a/src/meshcore_hub/api/cli.py +++ b/src/meshcore_hub/api/cli.py @@ -91,14 +91,14 @@ import click @click.option( "--mqtt-transport", type=click.Choice(["tcp", "websockets"], case_sensitive=False), - default="tcp", + default="websockets", envvar="MQTT_TRANSPORT", help="MQTT transport protocol", ) @click.option( "--mqtt-ws-path", type=str, - default="/mqtt", + default="/", envvar="MQTT_WS_PATH", help="MQTT WebSocket path (used when transport=websockets)", ) diff --git a/src/meshcore_hub/api/dependencies.py b/src/meshcore_hub/api/dependencies.py index 1e4dca0..a2a264c 100644 --- a/src/meshcore_hub/api/dependencies.py +++ b/src/meshcore_hub/api/dependencies.py @@ -60,8 +60,8 @@ def get_mqtt_client(request: Request) -> MQTTClient: mqtt_password = getattr(request.app.state, "mqtt_password", None) mqtt_prefix = getattr(request.app.state, "mqtt_prefix", "meshcore") mqtt_tls = getattr(request.app.state, "mqtt_tls", False) - mqtt_transport = getattr(request.app.state, "mqtt_transport", "tcp") - mqtt_ws_path = getattr(request.app.state, "mqtt_ws_path", "/mqtt") + mqtt_transport = getattr(request.app.state, "mqtt_transport", "websockets") + mqtt_ws_path = getattr(request.app.state, "mqtt_ws_path", "/") # Use unique client ID to allow multiple API instances unique_id = uuid.uuid4().hex[:8] diff --git a/src/meshcore_hub/collector/cli.py b/src/meshcore_hub/collector/cli.py index 3bf95e0..5328f73 100644 --- a/src/meshcore_hub/collector/cli.py +++ b/src/meshcore_hub/collector/cli.py @@ -57,14 +57,14 @@ if TYPE_CHECKING: @click.option( "--mqtt-transport", type=click.Choice(["tcp", "websockets"], case_sensitive=False), - default="tcp", + default="websockets", envvar="MQTT_TRANSPORT", help="MQTT transport protocol", ) @click.option( "--mqtt-ws-path", type=str, - default="/mqtt", + default="/", envvar="MQTT_WS_PATH", help="MQTT WebSocket path (used when transport=websockets)", ) diff --git a/src/meshcore_hub/collector/subscriber.py b/src/meshcore_hub/collector/subscriber.py index e555ad9..5b5c08b 100644 --- a/src/meshcore_hub/collector/subscriber.py +++ b/src/meshcore_hub/collector/subscriber.py @@ -473,8 +473,8 @@ def create_subscriber( mqtt_password: Optional[str] = None, mqtt_prefix: str = "meshcore", mqtt_tls: bool = False, - mqtt_transport: str = "tcp", - mqtt_ws_path: str = "/mqtt", + mqtt_transport: str = "websockets", + mqtt_ws_path: str = "/", database_url: str = "sqlite:///./meshcore.db", webhook_dispatcher: Optional["WebhookDispatcher"] = None, cleanup_enabled: bool = False, @@ -556,8 +556,8 @@ def run_collector( mqtt_password: Optional[str] = None, mqtt_prefix: str = "meshcore", mqtt_tls: bool = False, - mqtt_transport: str = "tcp", - mqtt_ws_path: str = "/mqtt", + mqtt_transport: str = "websockets", + mqtt_ws_path: str = "/", database_url: str = "sqlite:///./meshcore.db", webhook_dispatcher: Optional["WebhookDispatcher"] = None, cleanup_enabled: bool = False, diff --git a/src/meshcore_hub/common/config.py b/src/meshcore_hub/common/config.py index ab95bde..d1ae246 100644 --- a/src/meshcore_hub/common/config.py +++ b/src/meshcore_hub/common/config.py @@ -57,11 +57,11 @@ class CommonSettings(BaseSettings): default=False, description="Enable TLS/SSL for MQTT connection" ) mqtt_transport: MQTTTransport = Field( - default=MQTTTransport.TCP, + default=MQTTTransport.WEBSOCKETS, description="MQTT transport protocol (tcp or websockets)", ) mqtt_ws_path: str = Field( - default="/mqtt", + default="/", description="WebSocket path for MQTT transport (used when MQTT_TRANSPORT=websockets)", )