diff --git a/.gitignore b/.gitignore index 1ac59df..856fa33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Project /data/ !example/data/ +/seed/ +!example/seed/ # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/docker-compose.yml.example b/docker-compose.yml.example deleted file mode 100644 index ec2daa0..0000000 --- a/docker-compose.yml.example +++ /dev/null @@ -1,355 +0,0 @@ -# MeshCore Hub - Docker Compose Configuration -# -# Usage with profiles: -# docker compose --profile mqtt --profile collector --profile api up -# docker compose --profile all up -# docker compose --profile mock up # For testing with mock devices -# -# Available profiles: -# - mqtt: MQTT broker (Eclipse Mosquitto) -# - interface-receiver: Interface in RECEIVER mode -# - interface-sender: Interface in SENDER mode -# - collector: Event collector and database storage -# - api: REST API server -# - web: Web dashboard -# - mock: All components with mock device (for testing) -# - all: All production components (requires real device) -# - migrate: Run database migrations -# - seed: Import seed data (node_tags.json, members.json) -# -# Data Directory (DATA_HOME): -# The DATA_HOME environment variable controls where instance data is stored. -# Default: ./data (local) or /data (in containers) -# -# Structure: -# ${DATA_HOME}/ -# └── collector/ -# └── meshcore.db # SQLite database -# -# Seed Directory (SEED_HOME): -# The SEED_HOME environment variable controls where seed data files are read from. -# Default: ./seed (local) or /seed (in containers) -# -# Structure: -# ${SEED_HOME}/ -# ├── node_tags.json # Node tag definitions -# └── members.json # Network member definitions -# -# Example seed files are provided in ./example/seed/ -# -# To import seed data: -# docker compose --profile seed run --rm seed - -services: - # ========================================================================== - # MQTT Broker - Eclipse Mosquitto - # ========================================================================== - mqtt: - image: eclipse-mosquitto:2 - container_name: meshcore-mqtt - profiles: - - mqtt - - all - - mock - restart: unless-stopped - ports: - - "${MQTT_EXTERNAL_PORT:-1883}:1883" - - "${MQTT_WS_PORT:-9001}:9001" - volumes: - - ./etc/mosquitto.conf:/mosquitto/config/mosquitto.conf:ro - - mosquitto_data:/mosquitto/data - - mosquitto_log:/mosquitto/log - healthcheck: - test: ["CMD", "mosquitto_sub", "-t", "$$SYS/#", "-C", "1", "-i", "healthcheck", "-W", "3"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 10s - - # ========================================================================== - # Interface Receiver - MeshCore device to MQTT bridge (events) - # ========================================================================== - interface-receiver: - build: - context: . - dockerfile: Dockerfile - container_name: meshcore-interface-receiver - profiles: - - interface-receiver - - all - restart: unless-stopped - depends_on: - mqtt: - condition: service_healthy - devices: - - "${SERIAL_PORT:-/dev/ttyUSB0}:${SERIAL_PORT:-/dev/ttyUSB0}" - user: root # Required for device access - environment: - - LOG_LEVEL=${LOG_LEVEL:-INFO} - - MQTT_HOST=${MQTT_HOST:-mqtt} - - MQTT_PORT=${MQTT_PORT:-1883} - - MQTT_USERNAME=${MQTT_USERNAME:-} - - MQTT_PASSWORD=${MQTT_PASSWORD:-} - - MQTT_PREFIX=${MQTT_PREFIX:-meshcore} - - SERIAL_PORT=${SERIAL_PORT:-/dev/ttyUSB0} - - SERIAL_BAUD=${SERIAL_BAUD:-115200} - - NODE_ADDRESS=${NODE_ADDRESS:-} - command: ["interface", "receiver"] - healthcheck: - test: ["CMD", "meshcore-hub", "health", "interface"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 30s - - # ========================================================================== - # Interface Sender - MQTT to MeshCore device bridge (commands) - # ========================================================================== - interface-sender: - build: - context: . - dockerfile: Dockerfile - container_name: meshcore-interface-sender - profiles: - - interface-sender - - all - restart: unless-stopped - depends_on: - mqtt: - condition: service_healthy - devices: - - "${SERIAL_PORT_SENDER:-/dev/ttyUSB1}:${SERIAL_PORT_SENDER:-/dev/ttyUSB1}" - user: root # Required for device access - environment: - - LOG_LEVEL=${LOG_LEVEL:-INFO} - - MQTT_HOST=${MQTT_HOST:-mqtt} - - MQTT_PORT=${MQTT_PORT:-1883} - - MQTT_USERNAME=${MQTT_USERNAME:-} - - MQTT_PASSWORD=${MQTT_PASSWORD:-} - - MQTT_PREFIX=${MQTT_PREFIX:-meshcore} - - SERIAL_PORT=${SERIAL_PORT_SENDER:-/dev/ttyUSB1} - - SERIAL_BAUD=${SERIAL_BAUD:-115200} - - NODE_ADDRESS=${NODE_ADDRESS_SENDER:-} - command: ["interface", "sender"] - healthcheck: - test: ["CMD", "meshcore-hub", "health", "interface"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 30s - - # ========================================================================== - # Interface Mock Receiver - For testing without real devices - # ========================================================================== - interface-mock-receiver: - build: - context: . - dockerfile: Dockerfile - container_name: meshcore-interface-mock-receiver - profiles: - - mock - restart: unless-stopped - depends_on: - mqtt: - condition: service_healthy - environment: - - LOG_LEVEL=${LOG_LEVEL:-INFO} - - MQTT_HOST=${MQTT_HOST:-mqtt} - - MQTT_PORT=${MQTT_PORT:-1883} - - MQTT_USERNAME=${MQTT_USERNAME:-} - - MQTT_PASSWORD=${MQTT_PASSWORD:-} - - MQTT_PREFIX=${MQTT_PREFIX:-meshcore} - - MOCK_DEVICE=true - - NODE_ADDRESS=${NODE_ADDRESS:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef} - command: ["interface", "receiver", "--mock"] - healthcheck: - test: ["CMD", "meshcore-hub", "health", "interface"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 10s - - # ========================================================================== - # Collector - MQTT subscriber and database storage - # ========================================================================== - collector: - build: - context: . - dockerfile: Dockerfile - container_name: meshcore-collector - profiles: - - collector - - all - - mock - restart: unless-stopped - depends_on: - mqtt: - condition: service_healthy - volumes: - # Mount data directory (contains collector/meshcore.db) - - ${DATA_HOME:-./data}:/data - environment: - - LOG_LEVEL=${LOG_LEVEL:-INFO} - - MQTT_HOST=${MQTT_HOST:-mqtt} - - MQTT_PORT=${MQTT_PORT:-1883} - - MQTT_USERNAME=${MQTT_USERNAME:-} - - MQTT_PASSWORD=${MQTT_PASSWORD:-} - - MQTT_PREFIX=${MQTT_PREFIX:-meshcore} - - DATA_HOME=/data - # Explicitly unset to use DATA_HOME-based default path - - DATABASE_URL= - # Webhook configuration - - WEBHOOK_ADVERTISEMENT_URL=${WEBHOOK_ADVERTISEMENT_URL:-} - - WEBHOOK_ADVERTISEMENT_SECRET=${WEBHOOK_ADVERTISEMENT_SECRET:-} - - WEBHOOK_MESSAGE_URL=${WEBHOOK_MESSAGE_URL:-} - - WEBHOOK_MESSAGE_SECRET=${WEBHOOK_MESSAGE_SECRET:-} - - WEBHOOK_CHANNEL_MESSAGE_URL=${WEBHOOK_CHANNEL_MESSAGE_URL:-} - - WEBHOOK_CHANNEL_MESSAGE_SECRET=${WEBHOOK_CHANNEL_MESSAGE_SECRET:-} - - WEBHOOK_DIRECT_MESSAGE_URL=${WEBHOOK_DIRECT_MESSAGE_URL:-} - - WEBHOOK_DIRECT_MESSAGE_SECRET=${WEBHOOK_DIRECT_MESSAGE_SECRET:-} - - WEBHOOK_TIMEOUT=${WEBHOOK_TIMEOUT:-10.0} - - WEBHOOK_MAX_RETRIES=${WEBHOOK_MAX_RETRIES:-3} - - WEBHOOK_RETRY_BACKOFF=${WEBHOOK_RETRY_BACKOFF:-2.0} - command: ["collector"] - healthcheck: - test: ["CMD", "meshcore-hub", "health", "collector"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 10s - - # ========================================================================== - # API Server - REST API for querying data and sending commands - # ========================================================================== - api: - build: - context: . - dockerfile: Dockerfile - container_name: meshcore-api - profiles: - - api - - all - - mock - restart: unless-stopped - depends_on: - mqtt: - condition: service_healthy - collector: - condition: service_started - ports: - - "${API_PORT:-8000}:8000" - volumes: - # Mount data directory (uses collector/meshcore.db) - - ${DATA_HOME:-./data}:/data - environment: - - LOG_LEVEL=${LOG_LEVEL:-INFO} - - MQTT_HOST=${MQTT_HOST:-mqtt} - - MQTT_PORT=${MQTT_PORT:-1883} - - MQTT_USERNAME=${MQTT_USERNAME:-} - - MQTT_PASSWORD=${MQTT_PASSWORD:-} - - MQTT_PREFIX=${MQTT_PREFIX:-meshcore} - - DATA_HOME=/data - # Explicitly unset to use DATA_HOME-based default path - - DATABASE_URL= - - API_HOST=0.0.0.0 - - API_PORT=8000 - - API_READ_KEY=${API_READ_KEY:-} - - API_ADMIN_KEY=${API_ADMIN_KEY:-} - command: ["api"] - healthcheck: - test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 10s - - # ========================================================================== - # Web Dashboard - Web interface for network visualization - # ========================================================================== - web: - build: - context: . - dockerfile: Dockerfile - container_name: meshcore-web - profiles: - - web - - all - - mock - restart: unless-stopped - depends_on: - api: - condition: service_healthy - ports: - - "${WEB_PORT:-8080}:8080" - environment: - - LOG_LEVEL=${LOG_LEVEL:-INFO} - - API_BASE_URL=http://api:8000 - - API_KEY=${API_READ_KEY:-} - - WEB_HOST=0.0.0.0 - - WEB_PORT=8080 - - NETWORK_NAME=${NETWORK_NAME:-MeshCore Network} - - NETWORK_CITY=${NETWORK_CITY:-} - - NETWORK_COUNTRY=${NETWORK_COUNTRY:-} - - NETWORK_LOCATION=${NETWORK_LOCATION:-} - - NETWORK_RADIO_CONFIG=${NETWORK_RADIO_CONFIG:-} - - NETWORK_CONTACT_EMAIL=${NETWORK_CONTACT_EMAIL:-} - - NETWORK_CONTACT_DISCORD=${NETWORK_CONTACT_DISCORD:-} - command: ["web"] - healthcheck: - test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 10s - - # ========================================================================== - # Database Migrations - Run Alembic migrations - # ========================================================================== - db-migrate: - build: - context: . - dockerfile: Dockerfile - container_name: meshcore-db-migrate - profiles: - - migrate - volumes: - # Mount data directory (uses collector/meshcore.db) - - ${DATA_HOME:-./data}:/data - environment: - - DATA_HOME=/data - # Explicitly unset to use DATA_HOME-based default path - - DATABASE_URL= - command: ["db", "upgrade"] - - # ========================================================================== - # Seed Data - Import node_tags.json and members.json from SEED_HOME - # ========================================================================== - seed: - build: - context: . - dockerfile: Dockerfile - container_name: meshcore-seed - profiles: - - seed - volumes: - # Mount data directory for database (read-write) - - ${DATA_HOME:-./data}:/data - # Mount seed directory for seed files (read-only) - - ${SEED_HOME:-./seed}:/seed:ro - environment: - - DATA_HOME=/data - - SEED_HOME=/seed - - LOG_LEVEL=${LOG_LEVEL:-INFO} - # Explicitly unset to use DATA_HOME-based default path - - DATABASE_URL= - # Imports both node_tags.json and members.json if they exist - command: ["collector", "seed"] - -# ========================================================================== -# Volumes -# ========================================================================== -volumes: - mosquitto_data: - name: meshcore_mosquitto_data - mosquitto_log: - name: meshcore_mosquitto_log