setup-pi.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. #!/bin/bash
  2. #
  3. # Dune Weaver Raspberry Pi Setup Script
  4. #
  5. # One-command setup for deploying Dune Weaver on Raspberry Pi
  6. # Usage: curl -fsSL https://raw.githubusercontent.com/tuanchris/dune-weaver/main/scripts/setup-pi.sh | bash
  7. #
  8. # Or with options:
  9. # bash setup-pi.sh --no-docker # Use Python venv instead of Docker
  10. # bash setup-pi.sh --no-wifi-fix # Skip WiFi stability fix
  11. # bash setup-pi.sh --help # Show help
  12. #
  13. set -e
  14. # Colors for output
  15. RED='\033[0;31m'
  16. GREEN='\033[0;32m'
  17. YELLOW='\033[1;33m'
  18. BLUE='\033[0;34m'
  19. NC='\033[0m' # No Color
  20. # Default options
  21. USE_DOCKER=true
  22. FIX_WIFI=true # Applied by default for stability
  23. INSTALL_DIR="$HOME/dune-weaver"
  24. REPO_URL="https://github.com/tuanchris/dune-weaver"
  25. # Parse arguments
  26. while [[ $# -gt 0 ]]; do
  27. case $1 in
  28. --no-docker)
  29. USE_DOCKER=false
  30. shift
  31. ;;
  32. --no-wifi-fix)
  33. FIX_WIFI=false
  34. shift
  35. ;;
  36. --install-dir)
  37. INSTALL_DIR="$2"
  38. shift 2
  39. ;;
  40. --help|-h)
  41. echo "Dune Weaver Raspberry Pi Setup Script"
  42. echo ""
  43. echo "Usage: $0 [OPTIONS]"
  44. echo ""
  45. echo "Options:"
  46. echo " --no-docker Use Python venv instead of Docker (for Pi Zero 2W)"
  47. echo " --no-wifi-fix Skip WiFi stability fix (applied by default)"
  48. echo " --install-dir Custom installation directory (default: ~/dune-weaver)"
  49. echo " --help, -h Show this help message"
  50. echo ""
  51. echo "Examples:"
  52. echo " $0 # Standard Docker installation + WiFi fix"
  53. echo " $0 --no-docker # Python venv installation + WiFi fix"
  54. echo " $0 --no-wifi-fix # Docker without WiFi fix"
  55. exit 0
  56. ;;
  57. *)
  58. echo -e "${RED}Unknown option: $1${NC}"
  59. echo "Use --help for usage information"
  60. exit 1
  61. ;;
  62. esac
  63. done
  64. # Helper functions
  65. print_step() {
  66. echo -e "\n${BLUE}==>${NC} ${GREEN}$1${NC}"
  67. }
  68. print_warning() {
  69. echo -e "${YELLOW}Warning:${NC} $1"
  70. }
  71. print_error() {
  72. echo -e "${RED}Error:${NC} $1"
  73. }
  74. print_success() {
  75. echo -e "${GREEN}$1${NC}"
  76. }
  77. # Check if running on Raspberry Pi
  78. check_raspberry_pi() {
  79. print_step "Checking system compatibility..."
  80. if [[ ! -f /proc/device-tree/model ]]; then
  81. print_warning "Could not detect Raspberry Pi model. Continuing anyway..."
  82. return
  83. fi
  84. MODEL=$(cat /proc/device-tree/model)
  85. echo "Detected: $MODEL"
  86. # Check for 64-bit OS
  87. ARCH=$(uname -m)
  88. if [[ "$ARCH" != "aarch64" && "$ARCH" != "arm64" ]]; then
  89. print_error "64-bit OS required. Detected: $ARCH"
  90. echo "Please reinstall Raspberry Pi OS (64-bit) using Raspberry Pi Imager"
  91. exit 1
  92. fi
  93. print_success "64-bit OS detected ($ARCH)"
  94. }
  95. # Disable WLAN power save
  96. disable_wlan_powersave() {
  97. print_step "Disabling WLAN power save for better stability..."
  98. # Check if already disabled
  99. if iwconfig wlan0 2>/dev/null | grep -q "Power Management:off"; then
  100. echo "WLAN power save already disabled"
  101. return
  102. fi
  103. # Create config to persist across reboots
  104. sudo tee /etc/NetworkManager/conf.d/wifi-powersave-off.conf > /dev/null << 'EOF'
  105. [connection]
  106. wifi.powersave = 2
  107. EOF
  108. # Also try immediate disable
  109. sudo iwconfig wlan0 power off 2>/dev/null || true
  110. print_success "WLAN power save disabled"
  111. }
  112. # Apply WiFi stability fix
  113. apply_wifi_fix() {
  114. print_step "Applying WiFi stability fix..."
  115. CMDLINE_FILE="/boot/firmware/cmdline.txt"
  116. if [[ ! -f "$CMDLINE_FILE" ]]; then
  117. CMDLINE_FILE="/boot/cmdline.txt"
  118. fi
  119. if [[ ! -f "$CMDLINE_FILE" ]]; then
  120. print_warning "Could not find cmdline.txt, skipping WiFi fix"
  121. return
  122. fi
  123. # Check if fix already applied
  124. if grep -q "brcmfmac.feature_disable=0x82000" "$CMDLINE_FILE"; then
  125. echo "WiFi fix already applied"
  126. return
  127. fi
  128. # Backup and apply fix
  129. sudo cp "$CMDLINE_FILE" "${CMDLINE_FILE}.backup"
  130. sudo sed -i 's/$/ brcmfmac.feature_disable=0x82000/' "$CMDLINE_FILE"
  131. print_success "WiFi fix applied. A reboot is recommended after setup."
  132. NEEDS_REBOOT=true
  133. }
  134. # Update system packages
  135. update_system() {
  136. print_step "Updating system packages..."
  137. sudo apt update
  138. sudo apt full-upgrade -y
  139. print_success "System updated"
  140. }
  141. # Install Docker
  142. install_docker() {
  143. print_step "Installing Docker..."
  144. if command -v docker &> /dev/null; then
  145. echo "Docker already installed: $(docker --version)"
  146. else
  147. curl -fsSL https://get.docker.com -o /tmp/get-docker.sh
  148. sudo sh /tmp/get-docker.sh
  149. rm /tmp/get-docker.sh
  150. print_success "Docker installed"
  151. fi
  152. # Add user to docker group
  153. if ! groups $USER | grep -q docker; then
  154. print_step "Adding $USER to docker group..."
  155. sudo usermod -aG docker $USER
  156. DOCKER_GROUP_ADDED=true
  157. print_warning "You'll need to log out and back in for docker group changes to take effect"
  158. fi
  159. }
  160. # Install Python dependencies (non-Docker)
  161. install_python_deps() {
  162. print_step "Installing Python dependencies..."
  163. # Install system packages
  164. sudo apt install -y python3-venv python3-pip git
  165. print_success "Python dependencies installed"
  166. }
  167. # Clone repository
  168. clone_repo() {
  169. print_step "Cloning Dune Weaver repository..."
  170. if [[ -d "$INSTALL_DIR" ]]; then
  171. echo "Directory $INSTALL_DIR already exists"
  172. read -p "Update existing installation? (y/N) " -n 1 -r
  173. echo
  174. if [[ $REPLY =~ ^[Yy]$ ]]; then
  175. cd "$INSTALL_DIR"
  176. git pull
  177. else
  178. print_error "Installation cancelled"
  179. exit 1
  180. fi
  181. else
  182. git clone "$REPO_URL" --single-branch "$INSTALL_DIR"
  183. fi
  184. cd "$INSTALL_DIR"
  185. print_success "Repository ready at $INSTALL_DIR"
  186. }
  187. # Deploy with Docker
  188. deploy_docker() {
  189. print_step "Deploying Dune Weaver with Docker Compose..."
  190. cd "$INSTALL_DIR"
  191. # Use newgrp to apply docker group if just added, otherwise use sudo
  192. if [[ "$DOCKER_GROUP_ADDED" == "true" ]]; then
  193. echo "Starting Docker containers (using sudo since group not yet active)..."
  194. sudo docker compose up -d
  195. else
  196. docker compose up -d
  197. fi
  198. print_success "Docker deployment complete!"
  199. }
  200. # Deploy with Python venv
  201. deploy_python() {
  202. print_step "Setting up Python virtual environment..."
  203. cd "$INSTALL_DIR"
  204. # Create venv
  205. python3 -m venv .venv
  206. source .venv/bin/activate
  207. # Install dependencies
  208. print_step "Installing Python packages..."
  209. pip install --upgrade pip
  210. pip install -r requirements.txt
  211. # Create systemd service
  212. print_step "Creating systemd service..."
  213. sudo tee /etc/systemd/system/dune-weaver.service > /dev/null << EOF
  214. [Unit]
  215. Description=Dune Weaver Backend
  216. After=network.target
  217. [Service]
  218. ExecStart=$INSTALL_DIR/.venv/bin/python $INSTALL_DIR/main.py
  219. WorkingDirectory=$INSTALL_DIR
  220. Restart=always
  221. User=$USER
  222. Environment=PYTHONUNBUFFERED=1
  223. [Install]
  224. WantedBy=multi-user.target
  225. EOF
  226. # Enable and start service
  227. sudo systemctl daemon-reload
  228. sudo systemctl enable dune-weaver
  229. sudo systemctl start dune-weaver
  230. print_success "Python deployment complete!"
  231. }
  232. # Get IP address
  233. get_ip_address() {
  234. # Try multiple methods to get IP
  235. IP=$(hostname -I 2>/dev/null | awk '{print $1}')
  236. if [[ -z "$IP" ]]; then
  237. IP=$(ip route get 1 2>/dev/null | awk '{print $7}' | head -1)
  238. fi
  239. if [[ -z "$IP" ]]; then
  240. IP="<your-pi-ip>"
  241. fi
  242. echo "$IP"
  243. }
  244. # Print final instructions
  245. print_final_instructions() {
  246. IP=$(get_ip_address)
  247. HOSTNAME=$(hostname)
  248. echo ""
  249. echo -e "${GREEN}============================================${NC}"
  250. echo -e "${GREEN} Dune Weaver Setup Complete!${NC}"
  251. echo -e "${GREEN}============================================${NC}"
  252. echo ""
  253. echo -e "Access the web interface at:"
  254. echo -e " ${BLUE}http://$IP:8080${NC}"
  255. echo -e " ${BLUE}http://$HOSTNAME.local:8080${NC}"
  256. echo ""
  257. if [[ "$USE_DOCKER" == "true" ]]; then
  258. echo "Useful commands:"
  259. echo " View logs: cd $INSTALL_DIR && docker compose logs -f"
  260. echo " Restart: cd $INSTALL_DIR && docker compose restart"
  261. echo " Update: cd $INSTALL_DIR && git pull && docker compose pull && docker compose up -d"
  262. echo " Stop: cd $INSTALL_DIR && docker compose down"
  263. else
  264. echo "Useful commands:"
  265. echo " View logs: sudo journalctl -u dune-weaver -f"
  266. echo " Restart: sudo systemctl restart dune-weaver"
  267. echo " Status: sudo systemctl status dune-weaver"
  268. echo " Stop: sudo systemctl stop dune-weaver"
  269. fi
  270. echo ""
  271. if [[ "$DOCKER_GROUP_ADDED" == "true" ]]; then
  272. print_warning "Please log out and back in for docker group changes to take effect"
  273. fi
  274. if [[ "$NEEDS_REBOOT" == "true" ]]; then
  275. print_warning "A reboot is recommended to apply WiFi fixes"
  276. read -p "Reboot now? (y/N) " -n 1 -r
  277. echo
  278. if [[ $REPLY =~ ^[Yy]$ ]]; then
  279. sudo reboot
  280. fi
  281. fi
  282. }
  283. # Main installation flow
  284. main() {
  285. echo -e "${GREEN}"
  286. echo " ____ __ __ "
  287. echo " | _ \ _ _ _ __ ___\ \ / /__ __ ___ _____ _ __ "
  288. echo " | | | | | | | '_ \ / _ \\ \ /\ / / _ \/ _\` \ \ / / _ \ '__|"
  289. echo " | |_| | |_| | | | | __/ \ V V / __/ (_| |\ V / __/ | "
  290. echo " |____/ \__,_|_| |_|\___| \_/\_/ \___|\__,_| \_/ \___|_| "
  291. echo -e "${NC}"
  292. echo "Raspberry Pi Setup Script"
  293. echo ""
  294. # Detect deployment method
  295. if [[ "$USE_DOCKER" == "true" ]]; then
  296. echo "Deployment method: Docker (recommended)"
  297. else
  298. echo "Deployment method: Python virtual environment"
  299. fi
  300. echo "Install directory: $INSTALL_DIR"
  301. echo ""
  302. # Run setup steps
  303. check_raspberry_pi
  304. update_system
  305. disable_wlan_powersave
  306. if [[ "$FIX_WIFI" == "true" ]]; then
  307. apply_wifi_fix
  308. fi
  309. clone_repo
  310. if [[ "$USE_DOCKER" == "true" ]]; then
  311. install_docker
  312. deploy_docker
  313. else
  314. install_python_deps
  315. deploy_python
  316. fi
  317. print_final_instructions
  318. }
  319. # Run main
  320. main