#!/usr/bin/with-contenv bashio # -*- bash -*- # shellcheck shell=bash set -e # Database things DATABASE_HOST=$(bashio::config 'database_host') DATABASE_NAME=$(bashio::config 'database_name') DATABASE_PASS=$(bashio::config 'database_pass') DATABASE_PORT=$(bashio::config 'database_port') DATABASE_USER=$(bashio::config 'database_user') # MQTT things DISABLE_MQTT=$(bashio::config 'disable_mqtt') MQTT_HOST=$(bashio::config 'mqtt_host') MQTT_NAMESPACE=$(bashio::config 'mqtt_namespace') MQTT_PASSWORD=$(bashio::config 'mqtt_pass') MQTT_TLS_ACCEPT_INVALID_CERTS=$(bashio::config 'mqtt_tls_accept_invalid_certs') MQTT_TLS=$(bashio::config 'mqtt_tls') MQTT_USERNAME=$(bashio::config 'mqtt_user') # Other things IMPORT_DIR=$(bashio::config 'import_dir') PORT=4000 TZ=$(bashio::config 'timezone') DEFAULT_GEOFENCE=$(bashio::config 'default_geofence') encryption_key=$(bashio::config 'encryption_key') if bashio::config.is_empty 'encryption_key'; then encryption_key=$(openssl rand -hex 32) bashio::addon.option 'encryption_key' "$encryption_key" fi ENCRYPTION_KEY=$(bashio::config 'encryption_key') ingress_entry=$(curl -X GET \ -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \ -H "Content-Type: application/json" \ -s http://supervisor/addons/self/info | \ jq -r '.data.ingress_entry') export URL_PATH=$ingress_entry export DATABASE_HOST DATABASE_NAME DATABASE_PASS DATABASE_PORT DATABASE_USER \ DISABLE_MQTT MQTT_HOST MQTT_NAMESPACE MQTT_PASSWORD MQTT_TLS_ACCEPT_INVALID_CERTS \ MQTT_TLS MQTT_USERNAME IMPORT_DIR PORT TZ DEFAULT_GEOFENCE ENCRYPTION_KEY URL_PATH # These are optional and applied last so we can override those set above if needed. for env_var in $(bashio::config 'env_vars|keys'); do name=$(bashio::config "env_vars[${env_var}].name") value=$(bashio::config "env_vars[${env_var}].value") bashio::log.debug "Setting Env Variable ${name} to ${value}" export "${name}=${value}" done # Wait for PostgreSQL to be ready before continuing. The add-on can start # before the database is accepting connections (e.g. on a Home Assistant reboot # when both add-ons start together, or under load in CI), so retry instead of # failing immediately - TeslaMate has no built-in retry for this pre-check and # the s6 finish script would otherwise halt the whole add-on. bashio::log.info "Waiting for PostgreSQL at '$DATABASE_HOST:$DATABASE_PORT'..." pg_wait_attempt=0 pg_wait_max=30 until pg_isready -h "$DATABASE_HOST" -p "$DATABASE_PORT" > /dev/null 2>&1; do pg_wait_attempt=$((pg_wait_attempt + 1)) if [[ "$pg_wait_attempt" -ge "$pg_wait_max" ]]; then bashio::log.error "PostgreSQL at '$DATABASE_HOST' is not ready or unreachable after $((pg_wait_max * 2))s" # Distinguish a DNS/networking problem from a database that is simply down, # so the failure is actionable: resolve the host and report what we find. if getent hosts "$DATABASE_HOST" > /dev/null 2>&1; then bashio::log.error "Host '$DATABASE_HOST' resolves to $(getent hosts "$DATABASE_HOST" | awk '{print $1}' | tr '\n' ' ')but is not accepting connections on port $DATABASE_PORT - is the PostgreSQL add-on running and healthy?" else bashio::log.error "Host '$DATABASE_HOST' does not resolve - the PostgreSQL add-on may be stopped or on a different network" fi exit 1 fi bashio::log.info "PostgreSQL not ready yet, retrying in 2s (${pg_wait_attempt}/${pg_wait_max})..." sleep 2 done bashio::log.info "PostgreSQL is ready" # Create the PostgreSQL database if it doesn't exist bashio::log.info "Checking for database '$DATABASE_NAME' on $DATABASE_HOST" # Check the version of PostgreSQL database is v16.7 or later or v17.3 or later pg_version=$(PGPASSWORD="$DATABASE_PASS" psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER" postgres -Atqc "SELECT regexp_replace(version(), 'PostgreSQL ([^ ]+) .*', '\\1') AS version") major_version=$(echo "$pg_version" | cut -d '.' -f 1) minor_version=$(echo "$pg_version" | cut -d '.' -f 2) compat=true case "$major_version" in 16) [[ "$minor_version" -lt 7 ]] && compat=false ;; 17) [[ "$minor_version" -lt 3 ]] && compat=false ;; *) [[ "$major_version" -lt 16 ]] && compat=false ;; esac if [ $compat = false ]; then bashio::log.error "PostgreSQL version $pg_version is not supported. Please upgrade to v16.7 or later or v17.3 or later." exit 1 fi if [[ -n $(PGPASSWORD="$DATABASE_PASS" psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER" postgres -Atqc "SELECT datname FROM pg_database WHERE datname = '$DATABASE_NAME'") ]]; then bashio::log.info "Database $DATABASE_NAME already exists" else if PGPASSWORD="$DATABASE_PASS" psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER" postgres -qc "CREATE DATABASE \"$DATABASE_NAME\""; then bashio::log.info "Database $DATABASE_NAME created" else bashio::log.error "Failed to create database $DATABASE_NAME" exit 1 fi fi # Import dashboards if bashio::config.true 'grafana_import_dashboards'; then bashio::log.info "Importing Grafana dashboards..." /dashboards.sh restore || bashio::log.error "Failed to import dashboards" fi if [[ -z $(PGPASSWORD="$DATABASE_PASS" psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER" "$DATABASE_NAME" -Atqc "SELECT 1 FROM settings WHERE base_url LIKE '%api/hassio_ingress%'" 2> /dev/null ) ]]; then teslamate_ingress=$(bashio::addon.ingress_entry) grafana_ingress=$(bashio::addon.ingress_entry "$(bashio::supervisor.addons | grep grafana)") if [[ "$teslamate_ingress" == "$grafana_ingress" ]]; then grafana_ingress="** Grafana addon not found. Ensure the addon is installed and running. **" fi bashio::log.notice "" bashio::log.notice "Configure TeslaMate settings by adding these values" bashio::log.notice "to the URL you use to access your Home Assistant instance:" bashio::log.notice "" bashio::log.notice "=> Web App: $teslamate_ingress" bashio::log.notice "=> Dashboards: $grafana_ingress" bashio::log.notice "" fi # Set max open file limit to avoid memory allocation issues if [ "$(ulimit -Hn)" -gt 524288 ]; then ulimit -n 524288 fi bashio::log.info "Starting TeslaMate..." cd /opt/app exec $(/usr/bin/env sh) /entrypoint.sh bin/teslamate start