1
0

setup-pi.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. #!/bin/bash
  2. #
  3. # Dune Weaver Raspberry Pi Setup Script
  4. #
  5. # ONE-COMMAND INSTALL (recommended):
  6. # curl -fsSL https://raw.githubusercontent.com/tuanchris/dune-weaver/main/setup-pi.sh | bash
  7. #
  8. # OR from existing clone:
  9. # git clone https://github.com/tuanchris/dune-weaver --single-branch
  10. # cd dune-weaver
  11. # bash setup-pi.sh
  12. #
  13. # Options:
  14. # --no-wifi-fix Skip WiFi stability fix
  15. # --no-hotspot Skip autohotspot setup
  16. # --help Show help
  17. #
  18. set -e
  19. # Colors for output
  20. RED='\033[0;31m'
  21. GREEN='\033[0;32m'
  22. YELLOW='\033[1;33m'
  23. BLUE='\033[0;34m'
  24. NC='\033[0m' # No Color
  25. # Default options
  26. FIX_WIFI=true # Applied by default for stability
  27. SETUP_HOTSPOT=true # Autohotspot for first-time WiFi setup
  28. INSTALL_DIR="$HOME/dune-weaver"
  29. REPO_URL="https://github.com/tuanchris/dune-weaver"
  30. # Parse arguments
  31. while [[ $# -gt 0 ]]; do
  32. case $1 in
  33. --no-wifi-fix)
  34. FIX_WIFI=false
  35. shift
  36. ;;
  37. --no-hotspot)
  38. SETUP_HOTSPOT=false
  39. shift
  40. ;;
  41. --help|-h)
  42. echo "Dune Weaver Raspberry Pi Setup Script"
  43. echo ""
  44. echo "One-command install:"
  45. echo " curl -fsSL https://raw.githubusercontent.com/tuanchris/dune-weaver/main/setup-pi.sh | bash"
  46. echo ""
  47. echo "Or from existing clone:"
  48. echo " cd ~/dune-weaver && bash setup-pi.sh [OPTIONS]"
  49. echo ""
  50. echo "Options:"
  51. echo " --no-wifi-fix Skip WiFi stability fix (applied by default)"
  52. echo " --no-hotspot Skip autohotspot setup"
  53. echo " --help, -h Show this help message"
  54. exit 0
  55. ;;
  56. *)
  57. echo -e "${RED}Unknown option: $1${NC}"
  58. echo "Use --help for usage information"
  59. exit 1
  60. ;;
  61. esac
  62. done
  63. # Helper functions
  64. print_step() {
  65. echo -e "\n${BLUE}==>${NC} ${GREEN}$1${NC}"
  66. }
  67. print_warning() {
  68. echo -e "${YELLOW}Warning:${NC} $1"
  69. }
  70. print_error() {
  71. echo -e "${RED}Error:${NC} $1"
  72. }
  73. print_success() {
  74. echo -e "${GREEN}$1${NC}"
  75. }
  76. # Install system dependencies
  77. install_system_deps() {
  78. print_step "Installing system dependencies..."
  79. sudo apt update
  80. sudo DEBIAN_FRONTEND=noninteractive apt install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" \
  81. python3-venv python3-pip python3-dev \
  82. gcc g++ make swig \
  83. libjpeg-dev zlib1g-dev \
  84. libgpiod-dev gpiod \
  85. nginx git vim
  86. print_success "System dependencies installed"
  87. }
  88. # Install Node.js 20 via nodesource
  89. install_nodejs() {
  90. print_step "Installing Node.js..."
  91. if command -v node &> /dev/null; then
  92. local node_version
  93. node_version=$(node --version)
  94. echo "Node.js already installed: $node_version"
  95. # Check if version is 20+
  96. local major
  97. major=$(echo "$node_version" | sed 's/v//' | cut -d. -f1)
  98. if [[ "$major" -ge 20 ]]; then
  99. print_success "Node.js version is sufficient"
  100. return
  101. fi
  102. echo "Upgrading to Node.js 20..."
  103. fi
  104. curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
  105. sudo DEBIAN_FRONTEND=noninteractive apt install -y nodejs
  106. print_success "Node.js $(node --version) installed"
  107. }
  108. # Check if running on Raspberry Pi
  109. check_raspberry_pi() {
  110. print_step "Checking system compatibility..."
  111. if [[ ! -f /proc/device-tree/model ]]; then
  112. print_warning "Could not detect Raspberry Pi model. Continuing anyway..."
  113. return
  114. fi
  115. MODEL=$(tr -d '\0' < /proc/device-tree/model)
  116. echo "Detected: $MODEL"
  117. # Check for 64-bit OS
  118. ARCH=$(uname -m)
  119. if [[ "$ARCH" != "aarch64" && "$ARCH" != "arm64" ]]; then
  120. print_error "64-bit OS required. Detected: $ARCH"
  121. echo "Please reinstall Raspberry Pi OS (64-bit) using Raspberry Pi Imager"
  122. exit 1
  123. fi
  124. print_success "64-bit OS detected ($ARCH)"
  125. }
  126. # Disable WLAN power save
  127. disable_wlan_powersave() {
  128. print_step "Disabling WLAN power save for better stability..."
  129. # Check if already disabled
  130. if iwconfig wlan0 2>/dev/null | grep -q "Power Management:off"; then
  131. echo "WLAN power save already disabled"
  132. return
  133. fi
  134. # Create config to persist across reboots
  135. sudo tee /etc/NetworkManager/conf.d/wifi-powersave-off.conf > /dev/null << 'EOF'
  136. [connection]
  137. wifi.powersave = 2
  138. EOF
  139. # Also try immediate disable
  140. sudo iwconfig wlan0 power off 2>/dev/null || true
  141. print_success "WLAN power save disabled"
  142. }
  143. # Apply WiFi stability fix
  144. apply_wifi_fix() {
  145. print_step "Applying WiFi stability fix..."
  146. CMDLINE_FILE="/boot/firmware/cmdline.txt"
  147. if [[ ! -f "$CMDLINE_FILE" ]]; then
  148. CMDLINE_FILE="/boot/cmdline.txt"
  149. fi
  150. if [[ ! -f "$CMDLINE_FILE" ]]; then
  151. print_warning "Could not find cmdline.txt, skipping WiFi fix"
  152. return
  153. fi
  154. # Check if fix already applied
  155. if grep -q "brcmfmac.feature_disable=0x82000" "$CMDLINE_FILE"; then
  156. echo "WiFi fix already applied"
  157. return
  158. fi
  159. # Backup and apply fix
  160. sudo cp "$CMDLINE_FILE" "${CMDLINE_FILE}.backup"
  161. sudo sed -i 's/$/ brcmfmac.feature_disable=0x82000/' "$CMDLINE_FILE"
  162. print_success "WiFi fix applied. A reboot is recommended after setup."
  163. NEEDS_REBOOT=true
  164. }
  165. # Update system packages
  166. update_system() {
  167. print_step "Updating system packages..."
  168. sudo apt update
  169. sudo DEBIAN_FRONTEND=noninteractive apt full-upgrade -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"
  170. print_success "System updated"
  171. }
  172. # Verify we're in the dune-weaver directory
  173. ensure_repo() {
  174. print_step "Setting up dune-weaver repository..."
  175. # Check if we're already in the dune-weaver directory
  176. if [[ -f "main.py" ]] && [[ -f "requirements.txt" ]]; then
  177. INSTALL_DIR="$(pwd)"
  178. print_success "Using existing repo at $INSTALL_DIR"
  179. return
  180. fi
  181. # Check if repo exists in home directory
  182. if [[ -d "$INSTALL_DIR" ]] && [[ -f "$INSTALL_DIR/main.py" ]]; then
  183. print_success "Found existing repo at $INSTALL_DIR"
  184. cd "$INSTALL_DIR"
  185. echo "Pulling latest changes..."
  186. git pull
  187. return
  188. fi
  189. # Clone the repository
  190. print_step "Cloning dune-weaver repository..."
  191. git clone "$REPO_URL" --single-branch "$INSTALL_DIR"
  192. cd "$INSTALL_DIR"
  193. print_success "Cloned to $INSTALL_DIR"
  194. }
  195. # Deploy native (venv + systemd + nginx)
  196. deploy_native() {
  197. print_step "Setting up Python virtual environment..."
  198. cd "$INSTALL_DIR"
  199. # Create venv
  200. python3 -m venv .venv
  201. source .venv/bin/activate
  202. # Install dependencies
  203. print_step "Installing Python packages..."
  204. pip install --upgrade pip
  205. pip install -r requirements.txt
  206. # Build frontend
  207. print_step "Building frontend..."
  208. cd "$INSTALL_DIR/frontend"
  209. npm ci
  210. npm run build
  211. cd "$INSTALL_DIR"
  212. # Configure nginx
  213. print_step "Configuring nginx..."
  214. sudo cp "$INSTALL_DIR/nginx/dune-weaver.conf" /etc/nginx/sites-available/dune-weaver.conf
  215. sudo sed -i "s|INSTALL_DIR_PLACEHOLDER|$INSTALL_DIR|g" /etc/nginx/sites-available/dune-weaver.conf
  216. sudo ln -sf /etc/nginx/sites-available/dune-weaver.conf /etc/nginx/sites-enabled/dune-weaver.conf
  217. sudo rm -f /etc/nginx/sites-enabled/default
  218. sudo nginx -t
  219. sudo systemctl restart nginx
  220. sudo systemctl enable nginx
  221. # Create systemd service
  222. print_step "Creating systemd service..."
  223. sudo cp "$INSTALL_DIR/dune-weaver.service" /etc/systemd/system/dune-weaver.service
  224. sudo sed -i "s|USER_PLACEHOLDER|$USER|g" /etc/systemd/system/dune-weaver.service
  225. sudo sed -i "s|INSTALL_DIR_PLACEHOLDER|$INSTALL_DIR|g" /etc/systemd/system/dune-weaver.service
  226. # Enable and start service
  227. sudo systemctl daemon-reload
  228. sudo systemctl enable dune-weaver
  229. sudo systemctl start dune-weaver
  230. # Create sudoers entry for passwordless systemctl commands
  231. print_step "Configuring sudo permissions..."
  232. sudo tee /etc/sudoers.d/dune-weaver > /dev/null << EOF
  233. $USER ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart dune-weaver
  234. $USER ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop dune-weaver
  235. $USER ALL=(ALL) NOPASSWD: /usr/bin/systemctl start dune-weaver
  236. $USER ALL=(ALL) NOPASSWD: /usr/bin/systemctl poweroff
  237. $USER ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx
  238. EOF
  239. sudo chmod 0440 /etc/sudoers.d/dune-weaver
  240. print_success "Native deployment complete!"
  241. }
  242. # Install dw CLI command
  243. install_cli() {
  244. print_step "Installing 'dw' command..."
  245. # Copy dw script to /usr/local/bin
  246. sudo cp "$INSTALL_DIR/dw" /usr/local/bin/dw
  247. sudo chmod +x /usr/local/bin/dw
  248. print_success "'dw' command installed"
  249. }
  250. # Setup autohotspot
  251. setup_autohotspot() {
  252. print_step "Setting up autohotspot..."
  253. if [[ ! -f "$INSTALL_DIR/wifi/setup-wifi.sh" ]]; then
  254. print_warning "wifi/setup-wifi.sh not found, skipping autohotspot setup"
  255. return
  256. fi
  257. bash "$INSTALL_DIR/wifi/setup-wifi.sh"
  258. print_success "Autohotspot setup complete"
  259. }
  260. # Get IP address
  261. get_ip_address() {
  262. # Try multiple methods to get IP
  263. IP=$(hostname -I 2>/dev/null | awk '{print $1}')
  264. if [[ -z "$IP" ]]; then
  265. IP=$(ip route get 1 2>/dev/null | awk '{print $7}' | head -1)
  266. fi
  267. if [[ -z "$IP" ]]; then
  268. IP="<your-pi-ip>"
  269. fi
  270. echo "$IP"
  271. }
  272. # Print final instructions
  273. print_final_instructions() {
  274. IP=$(get_ip_address)
  275. HOSTNAME=$(hostname)
  276. echo ""
  277. echo -e "${GREEN}============================================${NC}"
  278. echo -e "${GREEN} Dune Weaver Setup Complete!${NC}"
  279. echo -e "${GREEN}============================================${NC}"
  280. echo ""
  281. echo -e "Access the web interface at:"
  282. echo -e " ${BLUE}http://$IP${NC}"
  283. echo -e " ${BLUE}http://$HOSTNAME.local${NC}"
  284. echo ""
  285. echo "Manage with the 'dw' command:"
  286. echo " dw logs View live logs"
  287. echo " dw restart Restart Dune Weaver"
  288. echo " dw update Pull latest and restart"
  289. echo " dw stop Stop Dune Weaver"
  290. echo " dw status Show status"
  291. echo " dw wifi help WiFi and hotspot management"
  292. echo " dw help Show all commands"
  293. echo ""
  294. if [[ "$SETUP_HOTSPOT" == "true" ]]; then
  295. echo -e "${BLUE}Autohotspot:${NC} If no known WiFi is found on boot,"
  296. echo "a 'Dune Weaver' hotspot will be created automatically."
  297. echo "Connect to it and open the app to configure WiFi."
  298. echo ""
  299. fi
  300. if [[ "$NEEDS_REBOOT" == "true" ]]; then
  301. print_warning "A reboot is recommended to apply WiFi fixes"
  302. read -p "Reboot now? (y/N) " -n 1 -r
  303. echo
  304. if [[ $REPLY =~ ^[Yy]$ ]]; then
  305. sudo reboot
  306. fi
  307. fi
  308. }
  309. # Main installation flow
  310. main() {
  311. echo -e "${GREEN}"
  312. echo " ____ __ __ "
  313. echo " | _ \ _ _ _ __ ___\ \ / /__ __ ___ _____ _ __ "
  314. echo " | | | | | | | '_ \ / _ \\ \ /\ / / _ \/ _\` \ \ / / _ \ '__|"
  315. echo " | |_| | |_| | | | | __/ \ V V / __/ (_| |\ V / __/ | "
  316. echo " |____/ \__,_|_| |_|\___| \_/\_/ \___|\__,_| \_/ \___|_| "
  317. echo -e "${NC}"
  318. echo "Raspberry Pi Setup Script"
  319. echo ""
  320. echo "Install directory: $INSTALL_DIR"
  321. echo ""
  322. # Run setup steps
  323. check_raspberry_pi
  324. install_system_deps
  325. install_nodejs
  326. ensure_repo
  327. update_system
  328. disable_wlan_powersave
  329. if [[ "$FIX_WIFI" == "true" ]]; then
  330. apply_wifi_fix
  331. fi
  332. if [[ "$SETUP_HOTSPOT" == "true" ]]; then
  333. setup_autohotspot
  334. fi
  335. deploy_native
  336. install_cli
  337. print_final_instructions
  338. }
  339. # Run main
  340. main