From d604689d06bb2ff6bee44ce26d0da21b5333aa33 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Wed, 14 Oct 2026 12:33:57 +0000 Subject: [PATCH] Add deploy_lights() (LXC 133) and wire into --only dispatch Co-Authored-By: Claude Sonnet 5.5 --- install-stack.sh | 91 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/install-stack.sh b/install-stack.sh index 4f54ce8..5479d9d 100755 --- a/install-stack.sh +++ b/install-stack.sh @@ -2115,6 +2115,93 @@ ${build_out}" msg_warn "plant deployed but the shared MQTT broker (LXC 104) is separate infra — telemetry ingestion will retry/backoff until it's reachable and the water-softener (or any other) asset is created with its mqtt_topic_prefix set on the Assets page." } +# Tasmota smart-switch lighting — manual control screen plus a schedule engine +# (fixed times, sunrise/sunset with offsets) over the shared MQTT broker. +# Fully internal, no admin-VLAN NIC (same shape as deploy_plant): it only talks +# to the broker, never to the switches directly. +deploy_lights() { + msg_step "Lighting (LXC 133 · 10.10.10.133)" + + if [[ -z "${LIGHTS_DB_PASS:-}" ]]; then + LIGHTS_DB_PASS=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 24) + printf '\nLIGHTS_DB_PASS=%s\n' "$LIGHTS_DB_PASS" >> "$CREDS_FILE" + msg_ok "Generated LIGHTS_DB_PASS → ${CREDS_FILE}" + fi + + msg_info "Creating LXC 133" + create_lxc 133 "10.10.10.133" "lights" 1024 1 + msg_ok "LXC 133 created" + + msg_info "Installing Docker" + install_docker 133 + install_mgmt_key 133 + msg_ok "Docker + SSH ready" + + msg_info "Creating lights database" + pct exec 100 -- bash -c " + docker exec hotel-manage-postgres psql -U postgres -c \ + \"CREATE USER lights WITH PASSWORD '${LIGHTS_DB_PASS}';\" 2>/dev/null || true + docker exec hotel-manage-postgres psql -U postgres -c \ + \"CREATE DATABASE lights_db OWNER lights;\" 2>/dev/null || true + docker exec hotel-manage-postgres psql -U postgres -d lights_db -c \ + \"GRANT ALL ON SCHEMA public TO lights;\" 2>/dev/null || true + " &>/dev/null + msg_ok "Database lights_db ready" + + msg_info "Deploying lights" + deploy_service 133 "lights" "${REPO_ROOT}/lights" /opt/lights + + push_file 133 /opt/lights/.env <&1"); then + msg_error "docker compose build failed in LXC 133: +${build_out}" + fi + + msg_info "Waiting for lights" + wait_healthy 133 "http://localhost:3080/lights/health" \ + && msg_ok "Lighting running at 10.10.10.133:3080" \ + || msg_warn "Lighting may need extra time — check LXC 133" + + msg_info "Seeding lights into auth DB" + pct exec 100 -- docker exec hotel-manage-postgres psql -U postgres -d auth_db -c " + INSERT INTO apps (slug, name, description, base_path, icon, theme_color, category, internal_host, internal_port) + VALUES ('lights', 'Lighting', 'Tasmota smart-switch lighting — manual control plus on/off and sunrise/sunset schedules via MQTT', '/lights', 'Lightbulb', '#b45309', 'Hotel', '10.10.10.133', 3080) + ON CONFLICT (slug) DO UPDATE SET + name=EXCLUDED.name, description=EXCLUDED.description, base_path=EXCLUDED.base_path, + icon=EXCLUDED.icon, theme_color=EXCLUDED.theme_color, category=EXCLUDED.category, + internal_host=EXCLUDED.internal_host, internal_port=EXCLUDED.internal_port; + INSERT INTO app_capabilities (app_id, slug, name, description, sort_order) + SELECT a.id, c.slug, c.name, c.description, c.sort_order + FROM apps a, (VALUES + ('view','View','See the lighting control screen, schedules and activity log',1), + ('control','Control','Switch lights and groups on/off manually',2), + ('schedules','Schedules','Create, edit and delete on/off and sunrise/sunset schedules',3), + ('manage_devices','Manage Devices','Add, edit and remove lights and light groups',4), + ('settings','Settings','Configure site location, timezone and view MQTT status',5) + ) AS c(slug, name, description, sort_order) + WHERE a.slug = 'lights' + ON CONFLICT (app_id, slug) DO NOTHING; + " &>/dev/null \ + && msg_ok "lights seeded into auth DB" \ + || msg_warn "Seed failed — run lights/seed-app.js manually" + + npm_add_location "/lights/" "10.10.10.133" 3080 + + msg_warn "lights deployed but needs manual follow-up before it can switch anything: (1) create a SERVICE client named 'lights-backend' under Settings -> MQTT Clients (the app fetches its broker login from it), (2) point the Tasmota switches at the broker and note each one's MQTT Topic, (3) set the site latitude/longitude under Lighting -> Settings for sunrise/sunset schedules." +} + deploy_kitchen() { msg_step "Kitchen (LXC 110 · 10.10.10.110)" @@ -2846,7 +2933,7 @@ SUMMARY # Sources existing credentials and redeploys just the named service. if [[ "${1:-}" == "--only" ]]; then ONLY="${2:-}" - VALID="postgres auth portal npm management noticeboard settings cashup hk-planner twin-optimiser room-planner maintenance forecasting rates reports kitchen kds wages utilities mqtt-broker hvac calendar plant tasks weather tablet-checkin" + VALID="postgres auth portal npm management noticeboard settings cashup hk-planner twin-optimiser room-planner maintenance forecasting rates reports kitchen kds wages utilities mqtt-broker hvac calendar plant tasks weather tablet-checkin lights" [[ -z "$ONLY" ]] && msg_error "Usage: install-stack.sh --only (one of: ${VALID})" grep -qw "$ONLY" <<< "$VALID" || msg_error "Unknown service '${ONLY}'. Valid: ${VALID}" CREDS_FILE=/root/hotel-manage-credentials.txt @@ -2931,6 +3018,7 @@ if [[ "${1:-}" == "--only" ]]; then tasks) deploy_tasks ;; weather) deploy_weather ;; tablet-checkin) deploy_tablet_checkin ;; + lights) deploy_lights ;; esac exit 0 fi @@ -2968,5 +3056,6 @@ deploy_calendar deploy_plant deploy_weather deploy_tablet_checkin +deploy_lights configure_npm_proxy_hosts print_summary