Files
WiFiManager/tools/portal-hardware
T

158 lines
5.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=tools/lib/portal-hardware-session.sh
source "$root/tools/lib/portal-hardware-session.sh"
usage() {
cat <<'USAGE' >&2
Usage:
./tools/portal-hardware doctor --client-interface IFACE [--take-over-client-adapter]
./tools/portal-hardware up --platform esp8266|esp32 --port /dev/serial/by-id/... \
--client-interface IFACE [--take-over-client-adapter] [--output DIRECTORY]
./tools/portal-hardware run --platform esp8266|esp32 --port /dev/serial/by-id/... \
--client-interface IFACE [--take-over-client-adapter] [--keep] \
[--browser auto|skip] [--station-env PATH] [--output DIRECTORY]
./tools/portal-hardware down
Only the named client interface may be disconnected or reconfigured. The tool
refuses the host default-route interface and preserves the created connection
in a 0600 state file until `down` or normal `run` cleanup.
USAGE
exit 2
}
command_name="${1:-}"
[[ -n "$command_name" ]] || usage
shift || true
platform=""
port=""
client_interface=""
takeover="no"
keep="no"
browser="auto"
station_env=""
output_dir=""
while [[ $# -gt 0 ]]; do
case "$1" in
--platform) [[ $# -ge 2 ]] || usage; platform="$2"; shift 2 ;;
--port) [[ $# -ge 2 ]] || usage; port="$2"; shift 2 ;;
--client-interface) [[ $# -ge 2 ]] || usage; client_interface="$2"; shift 2 ;;
--take-over-client-adapter) takeover="yes"; shift ;;
--keep) keep="yes"; shift ;;
--browser) [[ $# -ge 2 ]] || usage; browser="$2"; shift 2 ;;
--station-env) [[ $# -ge 2 ]] || usage; station_env="$2"; shift 2 ;;
--output) [[ $# -ge 2 ]] || usage; output_dir="$2"; shift 2 ;;
*) usage ;;
esac
done
require_common() {
wm_require ip
wm_require nmcli
wm_require pio
wm_require docker
docker compose version >/dev/null
}
prepare_output_dir() {
if [[ -z "$output_dir" ]]; then
output_dir="$(wm_portal_state_root)/runs/$(date -u +%Y%m%dT%H%M%SZ)-$platform"
fi
install -d -m 700 "$output_dir"
output_dir="$(cd "$output_dir" && pwd)"
}
validate_run_arguments() {
[[ "$platform" == "esp8266" || "$platform" == "esp32" ]] || usage
[[ -n "$client_interface" ]] || usage
[[ -n "$port" && -e "$port" ]] || {
echo "Serial port not found: $port" >&2
exit 1
}
[[ "$browser" == "auto" || "$browser" == "skip" ]] || usage
[[ -z "$station_env" || -r "$station_env" ]] || {
echo "Station environment file is not readable: $station_env" >&2
exit 1
}
}
start_portal_session() {
local ssid
validate_run_arguments
require_common
wm_acquire_hardware_lock
wm_require_no_active_session
wm_require_client_adapter "$client_interface" "$takeover"
prepare_output_dir
ssid="$(wm_portal_ssid "$platform")"
pio run -d "$root/test/portal-harness" -e "$platform" -t upload --upload-port "$port"
if ! wm_create_portal_connection "$client_interface" "$ssid" "default1"; then
return 1
fi
if ! wm_verify_portal_route "$client_interface"; then
wm_remove_connection "$WM_PORTAL_CONNECTION_UUID"
return 1
fi
if ! wm_write_state "$client_interface" "$platform" "$WM_PORTAL_CONNECTION_UUID" "$WM_PORTAL_CONNECTION_NAME"; then
wm_remove_connection "$WM_PORTAL_CONNECTION_UUID"
return 1
fi
printf 'Portal connected on %s. Artifacts: %s\n' "$client_interface" "$output_dir"
}
finish_portal_session() {
wm_load_state
wm_remove_connection "$WM_PORTAL_CONNECTION_UUID"
wm_clear_state
}
case "$command_name" in
doctor)
[[ -n "$client_interface" ]] || usage
require_common
wm_acquire_hardware_lock
wm_require_client_adapter "$client_interface" "$takeover"
printf 'Portal hardware prerequisites are ready. Main route is untouched; client adapter: %s\n' "$client_interface"
;;
up)
start_portal_session
;;
down)
[[ -z "$platform$port$client_interface$station_env$output_dir" ]] || usage
wm_acquire_hardware_lock
finish_portal_session
echo 'Portal client connection removed.'
;;
run)
start_portal_session
cleanup() {
if [[ "$keep" != "yes" ]]; then
finish_portal_session || true
fi
}
trap cleanup EXIT INT TERM
export PORTAL_ARTIFACT_DIR="$output_dir"
export LOCAL_UID="$(id -u)"
export LOCAL_GID="$(id -g)"
export PORTAL_BROWSER_MODE="$browser"
compose_files=(-f "$root/tests/portal-contract/compose.yaml")
if [[ -n "$station_env" ]]; then
export PORTAL_STATION_ENV_HOST="$(cd "$(dirname "$station_env")" && pwd)/$(basename "$station_env")"
compose_files+=(-f "$root/tests/portal-contract/compose.station.yaml")
fi
# The contract source is copied into the image; rebuild with Docker cache so
# this invocation always tests the checked-out files, not a stale image.
docker compose "${compose_files[@]}" build portal-contract
docker compose "${compose_files[@]}" run --rm portal-contract
printf 'Portal contract passed. Artifacts: %s\n' "$output_dir"
if [[ "$keep" == "yes" ]]; then
printf 'Portal session remains connected; run ./tools/portal-hardware down when finished.\n'
fi
;;
*) usage ;;
esac