diff --git a/docs/chelsty-runtime.md b/docs/chelsty-runtime.md new file mode 100644 index 0000000..f8e4ab3 --- /dev/null +++ b/docs/chelsty-runtime.md @@ -0,0 +1,60 @@ +# CHELSTY Runtime + +This document describes the runtime environment and deployment flow for CHELSTY, an offline-capable home automation edge node. + +## Runtime Layout + +The CHELSTY runtime is located at `/opt/homelab`. + +- `/opt/homelab/config/`: Service-specific configurations and compose overrides. +- `/opt/homelab/data/`: Persistent data for services. +- `/opt/homelab/logs/`: Service logs. + +### Key Service Locations +- **Mosquitto**: `/opt/homelab/config/mosquitto/` +- **Zigbee2MQTT**: `/opt/homelab/config/zigbee2mqtt/` + +## SLZB-06U Integration + +CHELSTY uses a SMLIGHT SLZB-06U Zigbee coordinator connected via Ethernet/TCP. + +- **Coordinator IP**: 192.168.1.105 +- **Port**: 6638 +- **Protocol**: TCP (ezsp adapter) + +Zigbee2MQTT is configured to connect to this coordinator over the local network. + +## Offline & LTE Assumptions + +- **WAN Resilience**: All core automation (Zigbee, MQTT) runs locally on CHELSTY. +- **Connectivity**: LTE provides intermittent uplink for remote management and Tailscale access. +- **Home Assistant**: Runs in a separate VM, connecting to the Mosquitto broker on CHELSTY. + +## Deployment Flow + +1. **Initial Bootstrap**: + Run the bootstrap script on the CHELSTY node: + ```bash + ./scripts/bootstrap/chelsty-runtime.sh + ``` + +2. **Manual Configuration**: + - Edit `/opt/homelab/config/zigbee2mqtt/.env` with MQTT credentials. + - Add Mosquitto user: + ```bash + sudo mosquitto_passwd -b /opt/homelab/data/mosquitto/config/password.txt + ``` + +3. **Service Deployment**: + Use the staged deployment runtime: + ```bash + ./scripts/deploy/deploy-node.sh chelsty + ``` + +## Recovery Procedure + +In case of runtime failure: +1. Verify Docker and Compose plugin: `docker compose version` +2. Re-run bootstrap script to ensure directory structure and basic configs. +3. Check Mosquitto logs: `tail -f /opt/homelab/data/mosquitto/log/mosquitto.log` +4. Verify SLZB-06U reachability: `ping 192.168.1.105` diff --git a/hosts/chelsty/runtime/mosquitto/docker-compose.override.yml b/hosts/chelsty/runtime/mosquitto/docker-compose.override.yml new file mode 100644 index 0000000..ca59d9c --- /dev/null +++ b/hosts/chelsty/runtime/mosquitto/docker-compose.override.yml @@ -0,0 +1,11 @@ +services: + mosquitto: + volumes: + - ./mosquitto.conf:/mosquitto/config/mosquitto.conf:ro + - /opt/homelab/data/mosquitto/config/password.txt:/mosquitto/config/password.txt:ro + # Healthcheck compatibility + healthcheck: + test: ["CMD-SHELL", "mosquitto_sub -t '$SYS/broker/version' -C 1 || exit 1"] + interval: 10s + timeout: 5s + retries: 5 diff --git a/hosts/chelsty/runtime/mosquitto/mosquitto.conf b/hosts/chelsty/runtime/mosquitto/mosquitto.conf new file mode 100644 index 0000000..609d365 --- /dev/null +++ b/hosts/chelsty/runtime/mosquitto/mosquitto.conf @@ -0,0 +1,13 @@ +persistence true +persistence_location /mosquitto/data/ +log_dest file /mosquitto/log/mosquitto.log +log_dest stdout + +# Default listener +listener 1883 +allow_anonymous false +password_file /mosquitto/config/password.txt + +# Local-only listener by default (inside Docker network, it's open to other containers) +# To expose to Tailscale, one might add: +# listener 1883 diff --git a/hosts/chelsty/runtime/zigbee2mqtt/configuration.yaml b/hosts/chelsty/runtime/zigbee2mqtt/configuration.yaml new file mode 100644 index 0000000..7d04139 --- /dev/null +++ b/hosts/chelsty/runtime/zigbee2mqtt/configuration.yaml @@ -0,0 +1,23 @@ +# Zigbee2MQTT configuration for CHELSTY +homeassistant: true +permit_join: false + +mqtt: + base_topic: zigbee2mqtt + server: mqtt://mosquitto:1883 + user: ${MQTT_USER} + password: ${MQTT_PASSWORD} + +serial: + # SLZB-06U network coordinator + port: tcp://192.168.1.105:6638 + adapter: ezsp + +frontend: + port: 8080 + +advanced: + network_key: GENERATE + pan_id: GENERATE + ext_pan_id: GENERATE + channel: 11 diff --git a/hosts/chelsty/runtime/zigbee2mqtt/docker-compose.override.yml b/hosts/chelsty/runtime/zigbee2mqtt/docker-compose.override.yml new file mode 100644 index 0000000..7f4d641 --- /dev/null +++ b/hosts/chelsty/runtime/zigbee2mqtt/docker-compose.override.yml @@ -0,0 +1,13 @@ +services: + zigbee2mqtt: + volumes: + - ./configuration.yaml:/app/data/configuration.yaml:ro + environment: + - MQTT_USER=${MQTT_USER} + - MQTT_PASSWORD=${MQTT_PASSWORD} + # Healthcheck is already defined in base service, but we ensure compatibility + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080"] + interval: 10s + timeout: 5s + retries: 3 diff --git a/scripts/bootstrap/chelsty-runtime.sh b/scripts/bootstrap/chelsty-runtime.sh new file mode 100755 index 0000000..ba7da9d --- /dev/null +++ b/scripts/bootstrap/chelsty-runtime.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# chelsty-runtime.sh - Bootstrap script for CHELSTY edge node runtime + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +RUNTIME_DIR="/opt/homelab" +CHELSTY_CONFIG="$REPO_ROOT/hosts/chelsty/runtime" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +log() { echo -e "${GREEN}[INFO]${NC} $1"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } + +log "Starting CHELSTY runtime bootstrap..." + +# 1. Validate Docker availability +if ! command -v docker &> /dev/null; then + error "Docker is not installed. Please install Docker first." +fi + +# 2. Validate compose plugin +if ! docker compose version &> /dev/null; then + error "Docker Compose plugin is not installed." +fi + +log "Docker and Compose plugin verified." + +# 3. Create runtime directories +log "Creating runtime directories in $RUNTIME_DIR..." +sudo mkdir -p "$RUNTIME_DIR/data/mosquitto/config" \ + "$RUNTIME_DIR/data/mosquitto/data" \ + "$RUNTIME_DIR/data/mosquitto/log" \ + "$RUNTIME_DIR/data/zigbee2mqtt/data" \ + "$RUNTIME_DIR/config/mosquitto" \ + "$RUNTIME_DIR/config/zigbee2mqtt" + +# 4. Copy runtime templates if absent +log "Deploying runtime configurations..." +# Mosquitto +if [ ! -f "$RUNTIME_DIR/config/mosquitto/mosquitto.conf" ]; then + sudo cp "$CHELSTY_CONFIG/mosquitto/mosquitto.conf" "$RUNTIME_DIR/config/mosquitto/" + log "Copied mosquitto.conf" +fi + +if [ ! -f "$RUNTIME_DIR/config/mosquitto/docker-compose.override.yml" ]; then + sudo cp "$CHELSTY_CONFIG/mosquitto/docker-compose.override.yml" "$RUNTIME_DIR/config/mosquitto/" +fi + +# Zigbee2MQTT +if [ ! -f "$RUNTIME_DIR/config/zigbee2mqtt/configuration.yaml" ]; then + sudo cp "$CHELSTY_CONFIG/zigbee2mqtt/configuration.yaml" "$RUNTIME_DIR/config/zigbee2mqtt/" + log "Copied zigbee2mqtt configuration.yaml" +fi + +if [ ! -f "$RUNTIME_DIR/config/zigbee2mqtt/docker-compose.override.yml" ]; then + sudo cp "$CHELSTY_CONFIG/zigbee2mqtt/docker-compose.override.yml" "$RUNTIME_DIR/config/zigbee2mqtt/" +fi + +# 5. Create missing .env files from examples +log "Checking for environment files..." +if [ ! -f "$RUNTIME_DIR/config/zigbee2mqtt/.env" ]; then + warn "Creating template .env for Zigbee2MQTT. PLEASE EDIT IT!" + echo "MQTT_USER=admin" | sudo tee "$RUNTIME_DIR/config/zigbee2mqtt/.env" > /dev/null + echo "MQTT_PASSWORD=password" | sudo tee -a "$RUNTIME_DIR/config/zigbee2mqtt/.env" > /dev/null +fi + +# 6. Ensure password file exists for Mosquitto +if [ ! -f "$RUNTIME_DIR/data/mosquitto/config/password.txt" ]; then + log "Creating empty mosquitto password file..." + sudo touch "$RUNTIME_DIR/data/mosquitto/config/password.txt" + warn "Mosquitto password file is empty. Use 'mosquitto_passwd' to add users." +fi + +log "Bootstrap complete!" + +echo -e "\n${YELLOW}Next-step instructions:${NC}" +echo "1. Edit $RUNTIME_DIR/config/zigbee2mqtt/.env with real credentials." +echo "2. Add Mosquitto user: sudo mosquitto_passwd -b $RUNTIME_DIR/data/mosquitto/config/password.txt " +echo "3. Deploy services using the homelab deployment framework:" +echo " ./scripts/deploy/deploy-node.sh chelsty" +echo "4. Verify Zigbee2MQTT logs to ensure it connects to SLZB-06U." +echo "5. Check Home Assistant (separate VM) for MQTT discovery."