dw 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. #!/bin/bash
  2. #
  3. # Dune Weaver CLI
  4. #
  5. # Usage: dw <command>
  6. #
  7. # Commands:
  8. # install Run initial setup
  9. # start Start Dune Weaver
  10. # stop Stop Dune Weaver
  11. # restart Restart Dune Weaver
  12. # update Pull latest changes and restart
  13. # logs View live logs (Ctrl+C to exit)
  14. # status Show service status
  15. # shell Open a shell with the venv activated
  16. # checkout Switch to a branch and rebuild
  17. # touch Manage touch screen app
  18. # wifi Manage WiFi and hotspot
  19. # help Show this help message
  20. #
  21. set -e
  22. # Colors
  23. RED='\033[0;31m'
  24. GREEN='\033[0;32m'
  25. YELLOW='\033[1;33m'
  26. BLUE='\033[0;34m'
  27. NC='\033[0m'
  28. # Temporary swap for memory-constrained boards (e.g. Pi Zero 2W)
  29. SWAP_FILE="/tmp/dw-build-swap"
  30. enable_swap() {
  31. local total_mb
  32. total_mb=$(awk '/MemTotal/ {printf "%d", $2/1024}' /proc/meminfo)
  33. if [[ "$total_mb" -lt 1024 ]]; then
  34. echo "Low memory detected (${total_mb}MB). Enabling temporary swap..."
  35. sudo dd if=/dev/zero of="$SWAP_FILE" bs=1M count=1024 status=none 2>/dev/null || true
  36. sudo chmod 600 "$SWAP_FILE"
  37. sudo mkswap "$SWAP_FILE" > /dev/null 2>&1 || true
  38. sudo swapon "$SWAP_FILE" 2>/dev/null || true
  39. fi
  40. }
  41. disable_swap() {
  42. if [[ -f "$SWAP_FILE" ]]; then
  43. sudo swapoff "$SWAP_FILE" 2>/dev/null || true
  44. sudo rm -f "$SWAP_FILE"
  45. fi
  46. }
  47. # Find dune-weaver directory
  48. find_install_dir() {
  49. # Check common locations
  50. if [[ -f "$HOME/dune-weaver/main.py" ]]; then
  51. echo "$HOME/dune-weaver"
  52. elif [[ -f "/home/pi/dune-weaver/main.py" ]]; then
  53. echo "/home/pi/dune-weaver"
  54. elif [[ -f "./main.py" ]]; then
  55. pwd
  56. else
  57. echo ""
  58. fi
  59. }
  60. INSTALL_DIR=$(find_install_dir)
  61. # Check if installed
  62. check_installed() {
  63. if [[ -z "$INSTALL_DIR" ]]; then
  64. echo -e "${RED}Error: Dune Weaver not found${NC}"
  65. echo ""
  66. echo "Please install first:"
  67. echo " git clone https://github.com/tuanchris/dune-weaver --single-branch"
  68. echo " cd dune-weaver"
  69. echo " dw install"
  70. exit 1
  71. fi
  72. }
  73. # Commands
  74. cmd_install() {
  75. if [[ -z "$INSTALL_DIR" ]]; then
  76. # Not installed, check if we're in the right directory
  77. if [[ -f "./main.py" ]] && [[ -f "./requirements.txt" ]]; then
  78. INSTALL_DIR=$(pwd)
  79. else
  80. echo -e "${RED}Error: Run this from the dune-weaver directory${NC}"
  81. echo ""
  82. echo " git clone https://github.com/tuanchris/dune-weaver --single-branch"
  83. echo " cd dune-weaver"
  84. echo " dw install"
  85. exit 1
  86. fi
  87. fi
  88. cd "$INSTALL_DIR"
  89. bash setup-pi.sh "$@"
  90. }
  91. cmd_start() {
  92. check_installed
  93. echo -e "${BLUE}Starting Dune Weaver...${NC}"
  94. sudo systemctl start dune-weaver
  95. echo -e "${GREEN}Started!${NC} Access at http://$(hostname -I | awk '{print $1}')"
  96. }
  97. cmd_stop() {
  98. check_installed
  99. echo -e "${BLUE}Stopping Dune Weaver...${NC}"
  100. sudo systemctl stop dune-weaver
  101. echo -e "${GREEN}Stopped${NC}"
  102. }
  103. cmd_restart() {
  104. check_installed
  105. echo -e "${BLUE}Restarting Dune Weaver...${NC}"
  106. sudo systemctl restart dune-weaver
  107. echo -e "${GREEN}Restarted${NC}"
  108. }
  109. cmd_update() {
  110. check_installed
  111. echo -e "${BLUE}Updating Dune Weaver...${NC}"
  112. cd "$INSTALL_DIR"
  113. # Check if we should skip the pull phase (called after re-exec)
  114. if [[ "$1" != "--continue" ]]; then
  115. echo "Pulling latest code..."
  116. git pull
  117. # Update dw CLI
  118. echo "Updating dw command..."
  119. sudo cp "$INSTALL_DIR/dw" /usr/local/bin/dw
  120. sudo chmod +x /usr/local/bin/dw
  121. # Re-exec with the new script to ensure new code runs
  122. echo "Restarting with updated CLI..."
  123. exec /usr/local/bin/dw update --continue
  124. fi
  125. enable_swap
  126. echo "Updating Python dependencies..."
  127. source .venv/bin/activate
  128. pip install -r requirements.txt
  129. echo "Rebuilding frontend..."
  130. cd "$INSTALL_DIR/frontend"
  131. npm ci --loglevel=error
  132. npx vite build
  133. cd "$INSTALL_DIR"
  134. disable_swap
  135. # Update nginx config
  136. echo "Updating nginx config..."
  137. sudo cp "$INSTALL_DIR/nginx/dune-weaver.conf" /etc/nginx/sites-available/dune-weaver.conf
  138. sudo sed -i "s|INSTALL_DIR_PLACEHOLDER|$INSTALL_DIR|g" /etc/nginx/sites-available/dune-weaver.conf
  139. sudo nginx -t && sudo systemctl restart nginx
  140. # Update systemd service
  141. echo "Updating systemd service..."
  142. sudo cp "$INSTALL_DIR/dune-weaver.service" /etc/systemd/system/dune-weaver.service
  143. sudo sed -i "s|USER_PLACEHOLDER|$USER|g" /etc/systemd/system/dune-weaver.service
  144. sudo sed -i "s|INSTALL_DIR_PLACEHOLDER|$INSTALL_DIR|g" /etc/systemd/system/dune-weaver.service
  145. sudo systemctl daemon-reload
  146. echo "Restarting service..."
  147. sudo systemctl restart dune-weaver
  148. # Install/update WiFi host scripts if not present
  149. if [[ -f "$INSTALL_DIR/wifi/setup-wifi.sh" ]]; then
  150. if [[ ! -f /usr/local/bin/autohotspot ]]; then
  151. echo ""
  152. echo -e "${BLUE}Installing autohotspot WiFi scripts...${NC}"
  153. sudo bash "$INSTALL_DIR/wifi/setup-wifi.sh"
  154. else
  155. # Always update the script and service files to latest
  156. echo "Updating WiFi host scripts..."
  157. sudo cp "$INSTALL_DIR/wifi/autohotspot" /usr/local/bin/autohotspot
  158. sudo chmod +x /usr/local/bin/autohotspot
  159. # Update service/timer files
  160. sudo cp "$INSTALL_DIR/wifi/autohotspot.service" /etc/systemd/system/autohotspot.service
  161. sudo cp "$INSTALL_DIR/wifi/autohotspot-check.service" /etc/systemd/system/autohotspot-check.service 2>/dev/null || true
  162. sudo cp "$INSTALL_DIR/wifi/autohotspot-check.timer" /etc/systemd/system/autohotspot-check.timer 2>/dev/null || true
  163. sudo systemctl daemon-reload
  164. sudo systemctl enable autohotspot-check.timer 2>/dev/null || true
  165. fi
  166. fi
  167. # Update touch app if installed (check both directory and service exist)
  168. local touch_dir="$INSTALL_DIR/dune-weaver-touch"
  169. if [[ -d "$touch_dir" ]] && systemctl list-unit-files dune-weaver-touch.service 2>/dev/null | grep -q dune-weaver-touch; then
  170. echo ""
  171. echo -e "${BLUE}Updating touch app...${NC}"
  172. cd "$touch_dir"
  173. # Update Python dependencies (code already pulled with main repo)
  174. if [[ -f "requirements.txt" ]] && [[ -d ".venv" ]]; then
  175. echo "Updating touch app dependencies..."
  176. source .venv/bin/activate
  177. pip install -q -r requirements.txt
  178. deactivate
  179. fi
  180. # Restart to apply changes
  181. sudo systemctl restart dune-weaver-touch
  182. echo -e "${GREEN}Touch app updated!${NC}"
  183. fi
  184. echo -e "${GREEN}Update complete!${NC}"
  185. }
  186. cmd_logs() {
  187. check_installed
  188. # Parse optional line count (e.g., dw logs 100)
  189. local lines="${1:-}"
  190. if [[ -n "$lines" ]]; then
  191. sudo journalctl -u dune-weaver -n "$lines"
  192. else
  193. sudo journalctl -u dune-weaver -f
  194. fi
  195. }
  196. cmd_status() {
  197. check_installed
  198. sudo systemctl status dune-weaver
  199. }
  200. cmd_shell() {
  201. check_installed
  202. cd "$INSTALL_DIR"
  203. echo -e "${BLUE}Activating venv...${NC}"
  204. exec bash --init-file <(echo "source '$INSTALL_DIR/.venv/bin/activate'; cd '$INSTALL_DIR'; echo 'Dune Weaver venv activated. Type \"exit\" to leave.'")
  205. }
  206. # Touch app commands (systemd service)
  207. cmd_touch() {
  208. local subcmd="${1:-help}"
  209. case "$subcmd" in
  210. logs)
  211. local lines="${2:-}"
  212. if [[ -n "$lines" ]]; then
  213. sudo journalctl -u dune-weaver-touch -n "$lines"
  214. else
  215. sudo journalctl -u dune-weaver-touch -f
  216. fi
  217. ;;
  218. restart)
  219. echo -e "${BLUE}Restarting touch app...${NC}"
  220. sudo systemctl restart dune-weaver-touch
  221. echo -e "${GREEN}Touch app restarted${NC}"
  222. ;;
  223. stop)
  224. echo -e "${BLUE}Stopping touch app...${NC}"
  225. sudo systemctl stop dune-weaver-touch
  226. echo -e "${GREEN}Touch app stopped${NC}"
  227. ;;
  228. start)
  229. echo -e "${BLUE}Starting touch app...${NC}"
  230. sudo systemctl start dune-weaver-touch
  231. echo -e "${GREEN}Touch app started${NC}"
  232. ;;
  233. status)
  234. sudo systemctl status dune-weaver-touch
  235. ;;
  236. install)
  237. check_installed
  238. local touch_dir="$INSTALL_DIR/dune-weaver-touch"
  239. if [[ ! -f "$touch_dir/install.sh" ]]; then
  240. echo -e "${RED}Touch app installer not found at $touch_dir/install.sh${NC}"
  241. echo "Make sure you have the dune-weaver-touch directory in your dune-weaver folder."
  242. exit 1
  243. fi
  244. echo -e "${BLUE}Running touch app installer...${NC}"
  245. cd "$touch_dir"
  246. sudo bash install.sh
  247. ;;
  248. help|*)
  249. echo -e "${GREEN}Touch App Commands${NC}"
  250. echo ""
  251. echo "Usage: dw touch <command>"
  252. echo ""
  253. echo "Commands:"
  254. echo " install Install touch app (clone, setup, enable service)"
  255. echo " logs [N] View logs (N lines or follow if omitted)"
  256. echo " restart Restart touch app"
  257. echo " stop Stop touch app"
  258. echo " start Start touch app"
  259. echo " status Show touch app status"
  260. echo " help Show this help message"
  261. ;;
  262. esac
  263. }
  264. cmd_checkout() {
  265. check_installed
  266. local branch="$1"
  267. if [[ -z "$branch" ]]; then
  268. echo -e "${RED}Usage: dw checkout <branch>${NC}"
  269. echo ""
  270. echo "Examples:"
  271. echo " dw checkout main"
  272. echo " dw checkout feature/security-settings-split"
  273. echo ""
  274. echo "Current branch: $(git -C "$INSTALL_DIR" rev-parse --abbrev-ref HEAD)"
  275. exit 1
  276. fi
  277. cd "$INSTALL_DIR"
  278. # Repo may be cloned with --single-branch; fetch the target branch explicitly
  279. echo -e "${BLUE}Fetching branch ${branch}...${NC}"
  280. if ! git fetch origin "$branch" 2>/dev/null; then
  281. echo -e "${RED}Branch '${branch}' not found on remote${NC}"
  282. exit 1
  283. fi
  284. # Checkout: create local tracking branch if it doesn't exist
  285. if git show-ref --verify --quiet "refs/heads/$branch"; then
  286. git checkout "$branch"
  287. git pull
  288. else
  289. git checkout -b "$branch" "origin/$branch"
  290. fi
  291. echo -e "Switched to branch: ${GREEN}${branch}${NC}"
  292. enable_swap
  293. # Rebuild frontend
  294. echo "Rebuilding frontend..."
  295. cd "$INSTALL_DIR/frontend"
  296. npm ci --loglevel=error
  297. npx vite build
  298. cd "$INSTALL_DIR"
  299. # Update Python dependencies
  300. echo "Updating Python dependencies..."
  301. source .venv/bin/activate
  302. pip install -r requirements.txt
  303. disable_swap
  304. # Update dw CLI from the new branch
  305. sudo cp "$INSTALL_DIR/dw" /usr/local/bin/dw
  306. sudo chmod +x /usr/local/bin/dw
  307. # Restart service
  308. sudo systemctl restart dune-weaver
  309. # Install WiFi scripts if available on this branch but not yet installed
  310. if [[ -f "$INSTALL_DIR/wifi/setup-wifi.sh" ]] && [[ ! -f /usr/local/bin/autohotspot ]]; then
  311. echo ""
  312. echo -e "${BLUE}Installing autohotspot WiFi scripts...${NC}"
  313. sudo bash "$INSTALL_DIR/wifi/setup-wifi.sh"
  314. fi
  315. echo -e "${GREEN}Checkout complete!${NC}"
  316. }
  317. # WiFi / Hotspot commands
  318. cmd_wifi() {
  319. local subcmd="${1:-help}"
  320. case "$subcmd" in
  321. status)
  322. check_installed
  323. echo -e "${BLUE}WiFi Status${NC}"
  324. echo ""
  325. # Show current mode
  326. local mode="unknown"
  327. if [[ -f /tmp/dw-wifi-mode ]]; then
  328. mode=$(cat /tmp/dw-wifi-mode)
  329. fi
  330. echo -e "Mode: ${GREEN}${mode}${NC}"
  331. # Show connected network
  332. local ssid
  333. ssid=$(nmcli -t -f GENERAL.CONNECTION dev show wlan0 2>/dev/null | head -1 | cut -d: -f2)
  334. if [[ -n "$ssid" && "$ssid" != "--" ]]; then
  335. echo -e "Network: ${GREEN}${ssid}${NC}"
  336. fi
  337. # Show IP
  338. local ip
  339. ip=$(nmcli -t -f IP4.ADDRESS dev show wlan0 2>/dev/null | head -1 | cut -d: -f2 | cut -d/ -f1)
  340. if [[ -n "$ip" ]]; then
  341. echo -e "IP: ${GREEN}${ip}${NC}"
  342. fi
  343. ;;
  344. scan)
  345. echo -e "${BLUE}Scanning for WiFi networks...${NC}"
  346. nmcli dev wifi rescan 2>/dev/null || true
  347. sleep 2
  348. nmcli dev wifi list
  349. ;;
  350. connect)
  351. echo -e "${BLUE}Available WiFi networks:${NC}"
  352. nmcli dev wifi rescan 2>/dev/null || true
  353. sleep 2
  354. nmcli dev wifi list
  355. echo ""
  356. read -p "Enter SSID to connect to: " ssid
  357. if [[ -z "$ssid" ]]; then
  358. echo -e "${RED}No SSID provided${NC}"
  359. exit 1
  360. fi
  361. read -sp "Enter password (leave empty for open networks): " password
  362. echo ""
  363. # Delete any stale connection profile for this SSID
  364. sudo nmcli con delete "$ssid" 2>/dev/null || true
  365. if [[ -n "$password" ]]; then
  366. # Create connection with explicit security settings
  367. # (nmcli dev wifi connect can fail on Trixie without key-mgmt)
  368. sudo nmcli con add type wifi ifname wlan0 con-name "$ssid" \
  369. ssid "$ssid" \
  370. wifi-sec.key-mgmt wpa-psk \
  371. wifi-sec.psk "$password"
  372. else
  373. sudo nmcli con add type wifi ifname wlan0 con-name "$ssid" \
  374. ssid "$ssid"
  375. fi
  376. echo -e "${BLUE}Connecting to '$ssid'...${NC}"
  377. if sudo nmcli con up "$ssid"; then
  378. echo -e "${GREEN}Connected!${NC}"
  379. else
  380. echo -e "${RED}Failed to connect. Check password and try again.${NC}"
  381. sudo nmcli con delete "$ssid" 2>/dev/null || true
  382. exit 1
  383. fi
  384. ;;
  385. hotspot)
  386. echo -e "${BLUE}Switching to hotspot mode...${NC}"
  387. sudo nmcli dev disconnect wlan0 2>/dev/null || true
  388. sudo nmcli con up DuneWeaver-Hotspot 2>/dev/null
  389. echo "hotspot" | sudo tee /tmp/dw-wifi-mode > /dev/null
  390. echo -e "${GREEN}Hotspot active!${NC} Connect to the 'Dune Weaver' WiFi network."
  391. ;;
  392. setup)
  393. check_installed
  394. cd "$INSTALL_DIR"
  395. sudo bash wifi/setup-wifi.sh
  396. ;;
  397. help|*)
  398. echo -e "${GREEN}WiFi Commands${NC}"
  399. echo ""
  400. echo "Usage: dw wifi <command>"
  401. echo ""
  402. echo "Commands:"
  403. echo " status Show current WiFi mode and connection"
  404. echo " scan Scan for available networks"
  405. echo " connect Interactive: scan + select + connect"
  406. echo " hotspot Force hotspot mode"
  407. echo " setup Run initial autohotspot setup"
  408. echo " help Show this help message"
  409. ;;
  410. esac
  411. }
  412. cmd_help() {
  413. echo -e "${GREEN}Dune Weaver CLI${NC}"
  414. echo ""
  415. echo "Usage: dw <command>"
  416. echo ""
  417. echo "Commands:"
  418. echo " install Run initial setup"
  419. echo " start Start Dune Weaver"
  420. echo " stop Stop Dune Weaver"
  421. echo " restart Restart Dune Weaver"
  422. echo " update Pull latest changes and restart"
  423. echo " checkout Switch to a branch and rebuild"
  424. echo " logs [N] View logs (N=number of lines, or follow if omitted)"
  425. echo " status Show service status"
  426. echo " shell Open a shell with the venv activated"
  427. echo " touch Manage touch screen app (run 'dw touch help')"
  428. echo " wifi Manage WiFi and hotspot (run 'dw wifi help')"
  429. echo " help Show this help message"
  430. echo ""
  431. if [[ -n "$INSTALL_DIR" ]]; then
  432. echo -e "Install directory: ${BLUE}$INSTALL_DIR${NC}"
  433. fi
  434. }
  435. # Main
  436. case "${1:-help}" in
  437. install)
  438. shift
  439. cmd_install "$@"
  440. ;;
  441. start)
  442. cmd_start
  443. ;;
  444. stop)
  445. cmd_stop
  446. ;;
  447. restart)
  448. cmd_restart
  449. ;;
  450. update)
  451. cmd_update "$2"
  452. ;;
  453. checkout)
  454. cmd_checkout "$2"
  455. ;;
  456. logs)
  457. cmd_logs "$2"
  458. ;;
  459. status)
  460. cmd_status
  461. ;;
  462. shell)
  463. cmd_shell
  464. ;;
  465. touch)
  466. shift
  467. cmd_touch "$@"
  468. ;;
  469. wifi)
  470. shift
  471. cmd_wifi "$@"
  472. ;;
  473. help|--help|-h)
  474. cmd_help
  475. ;;
  476. *)
  477. echo -e "${RED}Unknown command: $1${NC}"
  478. echo ""
  479. cmd_help
  480. exit 1
  481. ;;
  482. esac