Add debug info

This commit is contained in:
Colin Seymour
2026-06-14 12:49:27 +00:00
parent 6d11bf974b
commit 1f3345f01e
+77 -19
View File
@@ -12,11 +12,21 @@
# broker / Grafana instance is available. # broker / Grafana instance is available.
# #
# Usage: bash .devcontainer/setup-ha.sh # Usage: bash .devcontainer/setup-ha.sh
# DEBUG=1 bash .devcontainer/setup-ha.sh # verbose output + error details
# #
# Safe to run multiple times (idempotent). # Safe to run multiple times (idempotent).
set -euo pipefail set -euo pipefail
# DEBUG: when set to a truthy value (1/true/yes/on), print verbose diagnostics
# and surface API responses/errors that are normally hidden. Unset (or 0/false)
# keeps the default, quiet output.
DEBUG="${DEBUG:-0}"
case "${DEBUG,,}" in
1 | true | yes | on) DEBUG=1 ;;
*) DEBUG=0 ;;
esac
HA_URL="http://localhost:8123" HA_URL="http://localhost:8123"
ALEXBELGIUM_REPO="https://github.com/alexbelgium/hassio-addons" ALEXBELGIUM_REPO="https://github.com/alexbelgium/hassio-addons"
ADMIN_USER="admin" ADMIN_USER="admin"
@@ -47,6 +57,7 @@ GREEN='\033[0;32m'
YELLOW='\033[0;33m' YELLOW='\033[0;33m'
RED='\033[0;31m' RED='\033[0;31m'
CYAN='\033[0;36m' CYAN='\033[0;36m'
DIM='\033[2m'
BOLD='\033[1m' BOLD='\033[1m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
@@ -54,20 +65,62 @@ log() { echo -e "${CYAN}==>${NC} ${BOLD}$*${NC}"; }
warn() { echo -e "${YELLOW}WARNING:${NC} $*" >&2; } warn() { echo -e "${YELLOW}WARNING:${NC} $*" >&2; }
err() { echo -e "${RED}ERROR:${NC} $*" >&2; exit 1; } err() { echo -e "${RED}ERROR:${NC} $*" >&2; exit 1; }
ok() { echo -e "${CYAN}==>${NC} ${GREEN}$*${NC}"; } ok() { echo -e "${CYAN}==>${NC} ${GREEN}$*${NC}"; }
# debug() prints only when DEBUG is enabled and writes to stderr, so it never
# pollutes function output captured via $(...).
debug() {
[ "$DEBUG" = "1" ] || return 0
echo -e "${DIM}DEBUG:${NC} $*" >&2
}
# debug_response() logs an API response when debugging, truncated so large
# payloads (e.g. addon logs) stay readable.
debug_response() {
[ "$DEBUG" = "1" ] || return 0
local resp="$1" max=800
if [ "${#resp}" -gt "$max" ]; then
debug "response (truncated): ${resp:0:$max}..."
else
debug "response: ${resp}"
fi
}
# Run Supervisor API call via hassio_cli container # Run Supervisor API call via hassio_cli container
# IMPORTANT: Use single quotes for outer sh -c argument so $SUPERVISOR_TOKEN # IMPORTANT: Use single quotes for outer sh -c argument so $SUPERVISOR_TOKEN
# is expanded by the inner shell (where the env var exists), not the outer bash. # is expanded by the inner shell (where the env var exists), not the outer bash.
supervisor_api() { supervisor_api() {
local method="$1" endpoint="$2" local method="$1" endpoint="$2"
docker exec hassio_cli sh -c \ debug "API ${method} ${endpoint}"
'curl -s -X '"${method}"' -H "Authorization: Bearer $SUPERVISOR_TOKEN" -H "Content-Type: application/json" http://supervisor'"${endpoint}" local resp
resp=$(docker exec hassio_cli sh -c \
'curl -s -X '"${method}"' -H "Authorization: Bearer $SUPERVISOR_TOKEN" -H "Content-Type: application/json" http://supervisor'"${endpoint}")
debug_response "$resp"
printf '%s\n' "$resp"
} }
supervisor_api_with_body() { supervisor_api_with_body() {
local method="$1" endpoint="$2" body="$3" local method="$1" endpoint="$2" body="$3"
docker exec -e "BODY=${body}" hassio_cli sh -c \ debug "API ${method} ${endpoint} body=${body}"
'curl -s -X '"${method}"' -H "Authorization: Bearer $SUPERVISOR_TOKEN" -H "Content-Type: application/json" -d "$BODY" http://supervisor'"${endpoint}" local resp
resp=$(docker exec -e "BODY=${body}" hassio_cli sh -c \
'curl -s -X '"${method}"' -H "Authorization: Bearer $SUPERVISOR_TOKEN" -H "Content-Type: application/json" -d "$BODY" http://supervisor'"${endpoint}")
debug_response "$resp"
printf '%s\n' "$resp"
}
# POST to the local HA API for an optional onboarding step. Failures are
# non-fatal; the request and any response/error are shown only when debugging.
ha_post_optional() {
local token="$1" endpoint="$2" data="$3"
debug "POST ${endpoint} ${data}"
local resp rc=0
resp=$(curl -sS -X POST "${HA_URL}${endpoint}" \
-H "Authorization: Bearer ${token}" \
-H "Content-Type: application/json" \
-d "$data" 2>&1) || rc=$?
if [ "$rc" -ne 0 ]; then
debug "${endpoint} failed (rc=${rc}): ${resp}"
elif [ -n "$resp" ]; then
debug "${endpoint} response: ${resp}"
fi
} }
# Query a specific jq field from a Supervisor API response # Query a specific jq field from a Supervisor API response
@@ -96,6 +149,7 @@ wait_for_ha() {
ok "Home Assistant is ready" ok "Home Assistant is ready"
return 0 return 0
fi fi
debug "Attempt $((attempt + 1))/${max_attempts}: Home Assistant not ready yet"
sleep 5 sleep 5
attempt=$((attempt + 1)) attempt=$((attempt + 1))
done done
@@ -122,6 +176,7 @@ complete_onboarding() {
auth_response=$(curl -sf -X POST "${HA_URL}/api/onboarding/users" \ auth_response=$(curl -sf -X POST "${HA_URL}/api/onboarding/users" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "{\"client_id\":\"${CLIENT_ID}\",\"name\":\"Admin\",\"username\":\"${ADMIN_USER}\",\"password\":\"${ADMIN_PASS}\",\"language\":\"en\"}") -d "{\"client_id\":\"${CLIENT_ID}\",\"name\":\"Admin\",\"username\":\"${ADMIN_USER}\",\"password\":\"${ADMIN_PASS}\",\"language\":\"en\"}")
debug "users response: ${auth_response}"
local auth_code local auth_code
auth_code=$(echo "$auth_response" | jq -r '.auth_code') auth_code=$(echo "$auth_response" | jq -r '.auth_code')
@@ -136,6 +191,7 @@ complete_onboarding() {
--data-urlencode "grant_type=authorization_code" \ --data-urlencode "grant_type=authorization_code" \
--data-urlencode "code=${auth_code}" \ --data-urlencode "code=${auth_code}" \
--data-urlencode "client_id=${CLIENT_ID}") --data-urlencode "client_id=${CLIENT_ID}")
debug "token response: ${token_response}"
local access_token local access_token
access_token=$(echo "$token_response" | jq -r '.access_token') access_token=$(echo "$token_response" | jq -r '.access_token')
@@ -144,22 +200,12 @@ complete_onboarding() {
err "Failed to get access token: ${token_response}" err "Failed to get access token: ${token_response}"
fi fi
# Complete remaining onboarding steps # Complete remaining onboarding steps (best-effort; failures are non-fatal)
log "Completing onboarding steps..." log "Completing onboarding steps..."
curl -sf -X POST "${HA_URL}/api/onboarding/core_config" \ ha_post_optional "$access_token" "/api/onboarding/core_config" "{}"
-H "Authorization: Bearer ${access_token}" \ ha_post_optional "$access_token" "/api/onboarding/analytics" "{}"
-H "Content-Type: application/json" \ ha_post_optional "$access_token" "/api/onboarding/integration" \
-d "{}" > /dev/null 2>&1 || true "{\"client_id\":\"${CLIENT_ID}\",\"redirect_uri\":\"${HA_URL}/\"}"
curl -sf -X POST "${HA_URL}/api/onboarding/analytics" \
-H "Authorization: Bearer ${access_token}" \
-H "Content-Type: application/json" \
-d "{}" > /dev/null 2>&1 || true
curl -sf -X POST "${HA_URL}/api/onboarding/integration" \
-H "Authorization: Bearer ${access_token}" \
-H "Content-Type: application/json" \
-d "{\"client_id\":\"${CLIENT_ID}\",\"redirect_uri\":\"${HA_URL}/\"}" > /dev/null 2>&1 || true
ok "Onboarding complete" ok "Onboarding complete"
} }
@@ -187,6 +233,7 @@ add_addon_repo() {
ok "Store refreshed successfully" ok "Store refreshed successfully"
return 0 return 0
fi fi
debug "Attempt $((attempt + 1))/${max_attempts}: postgres addon not in store yet"
sleep 5 sleep 5
attempt=$((attempt + 1)) attempt=$((attempt + 1))
done done
@@ -222,6 +269,7 @@ install_postgres() {
ok "PostgreSQL addon installed (version: ${version})" ok "PostgreSQL addon installed (version: ${version})"
return 0 return 0
fi fi
debug "Attempt $((attempt + 1))/${max_attempts}: PostgreSQL not installed yet"
sleep 5 sleep 5
attempt=$((attempt + 1)) attempt=$((attempt + 1))
done done
@@ -267,6 +315,7 @@ configure_and_start_postgres() {
sleep 10 sleep 10
return 0 return 0
fi fi
debug "Attempt $((attempt + 1))/${max_attempts}: PostgreSQL state=${state}"
sleep 5 sleep 5
attempt=$((attempt + 1)) attempt=$((attempt + 1))
done done
@@ -322,6 +371,7 @@ install_teslamate() {
ok "TeslaMate addon installed (version: ${version})" ok "TeslaMate addon installed (version: ${version})"
return 0 return 0
fi fi
debug "Attempt $((attempt + 1))/${max_attempts}: TeslaMate not installed yet"
sleep 5 sleep 5
attempt=$((attempt + 1)) attempt=$((attempt + 1))
done done
@@ -350,6 +400,7 @@ configure_and_start_teslamate() {
--arg tz "$TIMEZONE" \ --arg tz "$TIMEZONE" \
'{database_user: $user, database_pass: $pass, database_port: $port, database_host: $host, database_name: $db, database_ssl: false, disable_mqtt: true, grafana_import_dashboards: false, timezone: $tz}') '{database_user: $user, database_pass: $pass, database_port: $port, database_host: $host, database_name: $db, database_ssl: false, disable_mqtt: true, grafana_import_dashboards: false, timezone: $tz}')
options_json=$(jq -n --argjson cur "$current_options" --argjson ovr "$overrides" '{options: ($cur + $ovr)}') options_json=$(jq -n --argjson cur "$current_options" --argjson ovr "$overrides" '{options: ($cur + $ovr)}')
debug "options payload: ${options_json}"
local response local response
response=$(supervisor_api_with_body POST "/addons/${TESLAMATE_SLUG}/options" "${options_json}") response=$(supervisor_api_with_body POST "/addons/${TESLAMATE_SLUG}/options" "${options_json}")
@@ -379,6 +430,7 @@ configure_and_start_teslamate() {
if [ "$state" = "started" ]; then if [ "$state" = "started" ]; then
break break
fi fi
debug "Attempt $((attempt + 1))/${max_attempts}: TeslaMate state=${state}"
sleep 5 sleep 5
attempt=$((attempt + 1)) attempt=$((attempt + 1))
done done
@@ -401,6 +453,9 @@ wait_for_teslamate_ready() {
ok "TeslaMate is ready" ok "TeslaMate is ready"
return 0 return 0
fi fi
if [ "$DEBUG" = "1" ]; then
debug "Attempt $((attempt + 1))/${max_attempts}: endpoint not up yet; last log: $(echo "$logs" | tail -n 1)"
fi
sleep 5 sleep 5
attempt=$((attempt + 1)) attempt=$((attempt + 1))
done done
@@ -413,6 +468,9 @@ main() {
log "Setting up Home Assistant for TeslaMate development" log "Setting up Home Assistant for TeslaMate development"
echo "" echo ""
debug "Verbose debug output enabled"
debug "HA_URL=${HA_URL} POSTGRES_SLUG=${POSTGRES_SLUG} TESLAMATE_SLUG=${TESLAMATE_SLUG}"
wait_for_ha wait_for_ha
complete_onboarding complete_onboarding
add_addon_repo add_addon_repo