#!/usr/bin/env bash set -Eeuo pipefail CONFIG=/data/options.json readonly HA_HTTP_PORT=8787 SUPERVISOR_API="${SUPERVISOR:-http://supervisor}" read_option() { local key="$1" default_value="${2-}" if [[ -f "$CONFIG" ]]; then jq -r --arg key "$key" --arg default "$default_value" \ 'if has($key) and .[$key] != null then .[$key] else $default end' "$CONFIG" else printf '%s\n' "$default_value" fi } supervisor_get() { local path="$1" [[ -n "${SUPERVISOR_TOKEN:-}" ]] || return 1 curl --fail --silent --show-error --max-time 5 \ -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \ "${SUPERVISOR_API%/}${path}" } validate_ingress_port_contract() { local payload ingress_port payload="$(supervisor_get /addons/self/info 2>/dev/null || true)" [[ -n "$payload" ]] || return 0 ingress_port="$(jq -r '.data.ingress_port // empty' <<<"$payload" 2>/dev/null || true)" if [[ "$ingress_port" =~ ^[0-9]+$ ]] && (( ingress_port != HA_HTTP_PORT )); then printf 'GREE Controller: refusing to start: HA ingress_port=%s but the add-on HTTP port contract is %s. Reinstall/update the official add-on package instead of changing ingress_port manually.\n' \ "$ingress_port" "$HA_HTTP_PORT" >&2 exit 78 fi } detect_primary_host_ipv4() { local payload address payload="$(supervisor_get /network/info 2>/dev/null || true)" [[ -n "$payload" ]] || return 1 address="$(jq -r ' (.data.interfaces // []) | (if type == "object" then [to_entries[] | (.value + {interface: (.value.interface // .key)})] else . end) | map(select((.enabled // true) == true and (.connected // true) == true)) | map(. + {candidate_ipv4: (.ipv4.ip_address // .ip_address // (try .ipv4.address[0] catch empty) // empty)}) | map(select(.candidate_ipv4 != "")) | ((map(select((.primary // false) == true)) | .[0]) // .[0] // {}) | (.candidate_ipv4 // empty) ' <<<"$payload" 2>/dev/null || true)" address="${address%%/*}" [[ "$address" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] || return 1 printf '%s\n' "$address" } GREE_INTERFACE="$(read_option gree_interface '')" DISCOVERY_BROADCAST="$(read_option discovery_broadcast '255.255.255.255:7000')" SIMULATE="$(read_option simulate 'false')" AUTO_SEED="$(read_option auto_seed 'false')" POLL_INTERVAL="$(read_option poll_interval_seconds '15')" ZONE_INTERVAL="$(read_option zone_interval_seconds '5')" DISCOVERY_TIMEOUT="$(read_option discovery_timeout_ms '3000')" APP_TOKEN="$(read_option app_token '')" PUBLIC_CHART_BASE_URL="$(read_option public_chart_base_url '')" LOG_LEVEL="$(read_option log_level 'info')" validate_ingress_port_contract PUBLIC_CHART_BASE_SOURCE="configured" if [[ -z "$PUBLIC_CHART_BASE_URL" ]]; then PUBLIC_CHART_BASE_SOURCE="browser-fallback" if PRIMARY_HOST_IPV4="$(detect_primary_host_ipv4)"; then PUBLIC_CHART_BASE_URL="http://${PRIMARY_HOST_IPV4}:${HA_HTTP_PORT}" PUBLIC_CHART_BASE_SOURCE="supervisor-primary-ipv4" fi fi export GREE_CONTROLLER_BIND="0.0.0.0:${HA_HTTP_PORT}" export GREE_CONTROLLER_DATABASE="/data/gree-controller.db" export GREE_CONTROLLER_GREE_INTERFACE="$GREE_INTERFACE" export GREE_CONTROLLER_DISCOVERY_BROADCAST="$DISCOVERY_BROADCAST" export GREE_CONTROLLER_SIMULATE="$SIMULATE" export GREE_CONTROLLER_AUTO_SEED="$AUTO_SEED" export GREE_CONTROLLER_POLL_INTERVAL_SECONDS="$POLL_INTERVAL" export GREE_CONTROLLER_ZONE_INTERVAL_SECONDS="$ZONE_INTERVAL" export GREE_CONTROLLER_DISCOVERY_TIMEOUT_MS="$DISCOVERY_TIMEOUT" export GREE_CONTROLLER_APP_TOKEN="$APP_TOKEN" export GREE_CONTROLLER_PUBLIC_CHART_BASE_URL="$PUBLIC_CHART_BASE_URL" export GREE_CONTROLLER_HA_AUTH="supervisor" export RUST_LOG="gree_controller=${LOG_LEVEL},tower_http=${LOG_LEVEL}" printf 'GREE Controller: interface=%s discovery=%s database=%s http_port=%s public_chart_base_source=%s\n' \ "${GREE_INTERFACE:-auto}" "$DISCOVERY_BROADCAST" "$GREE_CONTROLLER_DATABASE" "$HA_HTTP_PORT" \ "$PUBLIC_CHART_BASE_SOURCE" exec /usr/local/bin/gree-controller