Initial public khodo snapshot
ci / checks (push) Successful in 38m58s

This commit is contained in:
khodowany
2026-09-04 19:30:11 -05:00
commit 4f9a269f85
99 changed files with 59585 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
FROM debian:trixie-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
libdrm2 \
libegl1 \
libgbm1 \
libgl1 \
libgles2 \
libglvnd0 \
libstdc++6 \
libudev1 \
libx11-6 \
libxcb1 \
sqlite3 \
tini \
util-linux \
&& rm -rf /var/lib/apt/lists/*
COPY usr/ /usr/
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/usr/bin/vamp-zero", "--config", "/etc/product-vamp/vamp.json"]
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
bundle_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
zero_dir="$bundle_dir/zero"
image_tar="$zero_dir/product-vamp-zero-linux-arm64.docker.tar"
config_dir=/etc/product-vamp
state_dir=/var/lib/product-vamp
run_dir=/run/product-vamp
share_dir=/usr/share/product-vamp
required_packages=(
docker.io
docker-cli
network-manager
sqlite3
ca-certificates
python3
)
if [ "$(id -u)" -ne 0 ]; then
echo "install-zero.sh must be run as root" >&2
exit 1
fi
if [ ! -f "$image_tar" ]; then
echo "missing Docker archive: $image_tar" >&2
exit 1
fi
missing_packages=()
for package in "${required_packages[@]}"; do
if ! dpkg-query -W -f='${Status}' "$package" 2>/dev/null | grep -qx 'install ok installed'; then
missing_packages+=("$package")
fi
done
if [ "${#missing_packages[@]}" -eq 0 ]; then
echo "Required OS packages already installed; skipping apt."
else
echo "Installing missing OS packages: ${missing_packages[*]}"
if ! apt-get update -o APT::Update::Error-Mode=any; then
echo "Failed to refresh apt package indexes." >&2
echo "Connect the Zero to upstream internet, then rerun sudo zero/install-zero.sh." >&2
exit 1
fi
if ! apt-get install -y --no-install-recommends "${missing_packages[@]}"; then
echo "Failed to install required OS packages: ${missing_packages[*]}" >&2
echo "Connect the Zero to upstream internet, then rerun sudo zero/install-zero.sh." >&2
exit 1
fi
fi
systemctl enable --now docker NetworkManager
install -d -m 0755 "$config_dir" "$state_dir" "$run_dir" "$share_dir"
cp -R "$zero_dir/share/product-vamp/." "$share_dir/"
if [ ! -f "$config_dir/vamp.json" ]; then
cp "$zero_dir/config/vamp.example.json" "$config_dir/vamp.json"
fi
docker load -i "$image_tar"
install -m 0755 "$zero_dir/start-ap.sh" /usr/local/bin/product-vamp-start-ap
install -m 0755 "$zero_dir/start-zero.sh" /usr/local/bin/product-vamp-start-zero
install -m 0644 "$zero_dir/systemd/product-vamp-ap.service" /etc/systemd/system/product-vamp-ap.service
install -m 0644 "$zero_dir/systemd/product-vamp-zero.service" /etc/systemd/system/product-vamp-zero.service
systemctl daemon-reload
systemctl disable --now getty@tty1.service >/dev/null 2>&1 || true
systemctl enable --now getty@tty2.service >/dev/null 2>&1 || true
systemctl enable --now product-vamp-ap.service
systemctl enable product-vamp-zero.service
systemctl restart product-vamp-zero.service
echo "Product Vamp Zero installed. Control AP defaults to SSID 'Vamp Control' at http://192.168.42.1:8080."
+12
View File
@@ -0,0 +1,12 @@
[Unit]
Description=Product Vamp Wi-Fi control access point
After=NetworkManager.service
Requires=NetworkManager.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/product-vamp-start-ap
[Install]
WantedBy=multi-user.target
+22
View File
@@ -0,0 +1,22 @@
[Unit]
Description=Product Vamp Zero display and control service
After=docker.service product-vamp-ap.service getty@tty1.service
Requires=docker.service product-vamp-ap.service
Conflicts=getty@tty1.service
[Service]
Restart=always
RestartSec=3
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
StandardInput=tty-force
StandardOutput=journal
StandardError=journal
ExecStartPre=/usr/bin/install -d -m 0755 /run/product-vamp
ExecStart=/usr/local/bin/product-vamp-start-zero
ExecStop=/bin/sh -c '/usr/bin/docker stop product-vamp-zero >/dev/null 2>&1 || true'
[Install]
WantedBy=multi-user.target
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
config=${PRODUCT_VAMP_CONFIG:-/etc/product-vamp/vamp.json}
ssid=${PRODUCT_VAMP_AP_SSID:-Vamp Control}
passphrase=${PRODUCT_VAMP_AP_PASSPHRASE:-vamp-control}
interface=${PRODUCT_VAMP_AP_INTERFACE:-wlan0}
cidr=${PRODUCT_VAMP_ZERO_CIDR:-192.168.42.1/24}
connection=${PRODUCT_VAMP_AP_CONNECTION:-product-vamp-control}
configure_connection() {
nmcli connection modify "$connection" \
connection.interface-name "$interface" \
802-11-wireless.mode ap \
802-11-wireless.band bg \
802-11-wireless.channel 6 \
802-11-wireless.ssid "$ssid" \
802-11-wireless-security.key-mgmt wpa-psk \
802-11-wireless-security.proto rsn \
802-11-wireless-security.pairwise ccmp \
802-11-wireless-security.group ccmp \
802-11-wireless-security.pmf 1 \
802-11-wireless-security.psk "$passphrase" \
ipv4.method shared \
ipv4.addresses "$cidr" \
ipv6.method ignore \
connection.autoconnect yes
}
if [ -r "$config" ]; then
ssid=$(python3 -c 'import json,sys; data=json.load(open(sys.argv[1])); print(data.get("control",{}).get("ap_ssid","Vamp Control"))' "$config")
passphrase=$(python3 -c 'import json,sys; data=json.load(open(sys.argv[1])); print(data.get("control",{}).get("ap_passphrase","vamp-control"))' "$config")
interface=$(python3 -c 'import json,sys; data=json.load(open(sys.argv[1])); print(data.get("control",{}).get("ap_interface","wlan0"))' "$config")
cidr=$(python3 -c 'import json,sys; data=json.load(open(sys.argv[1])); print(data.get("control",{}).get("zero_cidr","192.168.42.1/24"))' "$config")
fi
if nmcli -t -f NAME connection show | grep -Fxq "$connection"; then
configure_connection
else
nmcli connection add type wifi ifname "$interface" con-name "$connection" autoconnect yes ssid "$ssid"
configure_connection
fi
nmcli connection up "$connection"
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env bash
set -euo pipefail
container_name=${PRODUCT_VAMP_ZERO_CONTAINER:-product-vamp-zero}
image_tag=${PRODUCT_VAMP_ZERO_IMAGE:-product-vamp-zero:dev}
config_dir=${PRODUCT_VAMP_CONFIG_DIR:-/etc/product-vamp}
state_dir=${PRODUCT_VAMP_STATE_DIR:-/var/lib/product-vamp}
run_dir=${PRODUCT_VAMP_RUN_DIR:-/run/product-vamp}
display_tty=${PRODUCT_VAMP_DISPLAY_TTY:-/dev/tty1}
install -d -m 0755 "$run_dir"
if command -v chvt >/dev/null 2>&1 && [ -c "$display_tty" ]; then
tty_number=${display_tty#/dev/tty}
case "$tty_number" in
''|*[!0-9]*)
;;
*)
chvt "$tty_number" || true
;;
esac
fi
if [ -c "$display_tty" ]; then
if command -v setterm >/dev/null 2>&1; then
setterm --cursor off > "$display_tty" || printf '\033[?25l' > "$display_tty" || true
else
printf '\033[?25l' > "$display_tty" || true
fi
fi
docker rm -f "$container_name" >/dev/null 2>&1 || true
echo "Starting Product Vamp Zero container '$container_name' from '$image_tag' on '$display_tty'"
exec docker run --rm --name "$container_name" --network host --privileged \
--env PRODUCT_VAMP_DISPLAY_TTY="$display_tty" \
-v "$config_dir:/etc/product-vamp:ro" \
-v "$state_dir:/var/lib/product-vamp" \
-v "$run_dir:/run/product-vamp" \
"$image_tag" \
sh -lc 'display_tty=${PRODUCT_VAMP_DISPLAY_TTY:-/dev/tty1}; exec setsid --wait --ctty /usr/bin/vamp-zero --config /etc/product-vamp/vamp.json < "$display_tty"'