setup-pi.sh 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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-docker Use Python venv instead of Docker
  15. # --no-wifi-fix Skip WiFi stability fix
  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. USE_DOCKER=true
  27. FIX_WIFI=true # Applied by default for stability
  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-docker)
  34. USE_DOCKER=false
  35. shift
  36. ;;
  37. --no-wifi-fix)
  38. FIX_WIFI=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-docker Use Python venv instead of Docker"
  52. echo " --no-wifi-fix Skip WiFi stability fix (applied by default)"
  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. # Check if running on Raspberry Pi
  77. check_raspberry_pi() {
  78. print_step "Checking system compatibility..."
  79. if [[ ! -f /proc/device-tree/model ]]; then
  80. print_warning "Could not detect Raspberry Pi model. Continuing anyway..."
  81. return
  82. fi
  83. MODEL=$(tr -d '\0' < /proc/device-tree/model)
  84. echo "Detected: $MODEL"
  85. # Check for 64-bit OS
  86. ARCH=$(uname -m)
  87. if [[ "$ARCH" != "aarch64" && "$ARCH" != "arm64" ]]; then
  88. print_error "64-bit OS required. Detected: $ARCH"
  89. echo "Please reinstall Raspberry Pi OS (64-bit) using Raspberry Pi Imager"
  90. exit 1
  91. fi
  92. print_success "64-bit OS detected ($ARCH)"
  93. }
  94. # Disable WLAN power save
  95. disable_wlan_powersave() {
  96. print_step "Disabling WLAN power save for better stability..."
  97. # Check if already disabled
  98. if iwconfig wlan0 2>/dev/null | grep -q "Power Management:off"; then
  99. echo "WLAN power save already disabled"
  100. return
  101. fi
  102. # Create config to persist across reboots
  103. sudo tee /etc/NetworkManager/conf.d/wifi-powersave-off.conf > /dev/null << 'EOF'
  104. [connection]
  105. wifi.powersave = 2
  106. EOF
  107. # Also try immediate disable
  108. sudo iwconfig wlan0 power off 2>/dev/null || true
  109. print_success "WLAN power save disabled"
  110. }
  111. # Apply WiFi stability fix
  112. apply_wifi_fix() {
  113. print_step "Applying WiFi stability fix..."
  114. CMDLINE_FILE="/boot/firmware/cmdline.txt"
  115. if [[ ! -f "$CMDLINE_FILE" ]]; then
  116. CMDLINE_FILE="/boot/cmdline.txt"
  117. fi
  118. if [[ ! -f "$CMDLINE_FILE" ]]; then
  119. print_warning "Could not find cmdline.txt, skipping WiFi fix"
  120. return
  121. fi
  122. # Check if fix already applied
  123. if grep -q "brcmfmac.feature_disable=0x82000" "$CMDLINE_FILE"; then
  124. echo "WiFi fix already applied"
  125. return
  126. fi
  127. # Backup and apply fix
  128. sudo cp "$CMDLINE_FILE" "${CMDLINE_FILE}.backup"
  129. sudo sed -i 's/$/ brcmfmac.feature_disable=0x82000/' "$CMDLINE_FILE"
  130. print_success "WiFi fix applied. A reboot is recommended after setup."
  131. NEEDS_REBOOT=true
  132. }
  133. # Update system packages
  134. update_system() {
  135. print_step "Updating system packages..."
  136. sudo apt update
  137. sudo apt full-upgrade -y
  138. print_success "System updated"
  139. }
  140. # Install Docker
  141. install_docker() {
  142. print_step "Installing Docker..."
  143. if command -v docker &> /dev/null; then
  144. echo "Docker already installed: $(docker --version)"
  145. else
  146. curl -fsSL https://get.docker.com -o /tmp/get-docker.sh
  147. sudo sh /tmp/get-docker.sh
  148. rm /tmp/get-docker.sh
  149. print_success "Docker installed"
  150. fi
  151. # Add user to docker group
  152. if ! groups $USER | grep -q docker; then
  153. print_step "Adding $USER to docker group..."
  154. sudo usermod -aG docker $USER
  155. DOCKER_GROUP_ADDED=true
  156. print_warning "You'll need to log out and back in for docker group changes to take effect"
  157. fi
  158. }
  159. # Install Python dependencies (non-Docker)
  160. install_python_deps() {
  161. print_step "Installing Python dependencies..."
  162. # Install system packages
  163. sudo apt install -y python3-venv python3-pip git
  164. print_success "Python dependencies installed"
  165. }
  166. # Verify we're in the dune-weaver directory
  167. ensure_repo() {
  168. print_step "Setting up dune-weaver repository..."
  169. # Check if we're already in the dune-weaver directory
  170. if [[ -f "docker-compose.yml" ]] && [[ -f "main.py" ]]; then
  171. INSTALL_DIR="$(pwd)"
  172. print_success "Using existing repo at $INSTALL_DIR"
  173. return
  174. fi
  175. # Check if repo exists in home directory
  176. if [[ -d "$INSTALL_DIR" ]] && [[ -f "$INSTALL_DIR/main.py" ]]; then
  177. print_success "Found existing repo at $INSTALL_DIR"
  178. cd "$INSTALL_DIR"
  179. echo "Pulling latest changes..."
  180. git pull
  181. return
  182. fi
  183. # Clone the repository
  184. print_step "Cloning dune-weaver repository..."
  185. git clone "$REPO_URL" --single-branch "$INSTALL_DIR"
  186. cd "$INSTALL_DIR"
  187. print_success "Cloned to $INSTALL_DIR"
  188. }
  189. # Install dw CLI command
  190. install_cli() {
  191. print_step "Installing 'dw' command..."
  192. # Copy dw script to /usr/local/bin
  193. sudo cp "$INSTALL_DIR/dw" /usr/local/bin/dw
  194. sudo chmod +x /usr/local/bin/dw
  195. print_success "'dw' command installed"
  196. }
  197. # Deploy with Docker
  198. deploy_docker() {
  199. print_step "Deploying Dune Weaver with Docker Compose..."
  200. cd "$INSTALL_DIR"
  201. sudo docker compose up -d --quiet-pull
  202. print_success "Docker deployment complete!"
  203. }
  204. # Deploy with Python venv
  205. deploy_python() {
  206. print_step "Setting up Python virtual environment..."
  207. cd "$INSTALL_DIR"
  208. # Create venv
  209. python3 -m venv .venv
  210. source .venv/bin/activate
  211. # Install dependencies
  212. print_step "Installing Python packages..."
  213. pip install --upgrade pip
  214. pip install -r requirements.txt
  215. # Create systemd service
  216. print_step "Creating systemd service..."
  217. sudo tee /etc/systemd/system/dune-weaver.service > /dev/null << EOF
  218. [Unit]
  219. Description=Dune Weaver Backend
  220. After=network.target
  221. [Service]
  222. ExecStart=$INSTALL_DIR/.venv/bin/python $INSTALL_DIR/main.py
  223. WorkingDirectory=$INSTALL_DIR
  224. Restart=always
  225. User=$USER
  226. Environment=PYTHONUNBUFFERED=1
  227. [Install]
  228. WantedBy=multi-user.target
  229. EOF
  230. # Enable and start service
  231. sudo systemctl daemon-reload
  232. sudo systemctl enable dune-weaver
  233. sudo systemctl start dune-weaver
  234. print_success "Python deployment complete!"
  235. }
  236. # Get IP address
  237. get_ip_address() {
  238. # Try multiple methods to get IP
  239. IP=$(hostname -I 2>/dev/null | awk '{print $1}')
  240. if [[ -z "$IP" ]]; then
  241. IP=$(ip route get 1 2>/dev/null | awk '{print $7}' | head -1)
  242. fi
  243. if [[ -z "$IP" ]]; then
  244. IP="<your-pi-ip>"
  245. fi
  246. echo "$IP"
  247. }
  248. # Print final instructions
  249. print_final_instructions() {
  250. IP=$(get_ip_address)
  251. HOSTNAME=$(hostname)
  252. echo ""
  253. echo -e "${GREEN}============================================${NC}"
  254. echo -e "${GREEN} Dune Weaver Setup Complete!${NC}"
  255. echo -e "${GREEN}============================================${NC}"
  256. echo ""
  257. echo -e "Access the web interface at:"
  258. echo -e " ${BLUE}http://$IP:8080${NC}"
  259. echo -e " ${BLUE}http://$HOSTNAME.local:8080${NC}"
  260. echo ""
  261. echo "Manage with the 'dw' command:"
  262. echo " dw logs View live logs"
  263. echo " dw restart Restart Dune Weaver"
  264. echo " dw update Pull latest and restart"
  265. echo " dw stop Stop Dune Weaver"
  266. echo " dw status Show status"
  267. echo " dw help Show all commands"
  268. echo ""
  269. if [[ "$DOCKER_GROUP_ADDED" == "true" ]]; then
  270. print_warning "Please log out and back in for docker group changes to take effect"
  271. fi
  272. if [[ "$NEEDS_REBOOT" == "true" ]]; then
  273. print_warning "A reboot is recommended to apply WiFi fixes"
  274. read -p "Reboot now? (y/N) " -n 1 -r
  275. echo
  276. if [[ $REPLY =~ ^[Yy]$ ]]; then
  277. sudo reboot
  278. fi
  279. fi
  280. }
  281. # Main installation flow
  282. main() {
  283. echo -e "${GREEN}"
  284. echo " ____ __ __ "
  285. echo " | _ \ _ _ _ __ ___\ \ / /__ __ ___ _____ _ __ "
  286. echo " | | | | | | | '_ \ / _ \\ \ /\ / / _ \/ _\` \ \ / / _ \ '__|"
  287. echo " | |_| | |_| | | | | __/ \ V V / __/ (_| |\ V / __/ | "
  288. echo " |____/ \__,_|_| |_|\___| \_/\_/ \___|\__,_| \_/ \___|_| "
  289. echo -e "${NC}"
  290. echo "Raspberry Pi Setup Script"
  291. echo ""
  292. # Detect deployment method
  293. if [[ "$USE_DOCKER" == "true" ]]; then
  294. echo "Deployment method: Docker (recommended)"
  295. else
  296. echo "Deployment method: Python virtual environment"
  297. fi
  298. echo "Install directory: $INSTALL_DIR"
  299. echo ""
  300. # Run setup steps
  301. check_raspberry_pi
  302. ensure_repo
  303. update_system
  304. disable_wlan_powersave
  305. if [[ "$FIX_WIFI" == "true" ]]; then
  306. apply_wifi_fix
  307. fi
  308. if [[ "$USE_DOCKER" == "true" ]]; then
  309. install_docker
  310. deploy_docker
  311. else
  312. install_python_deps
  313. deploy_python
  314. fi
  315. install_cli
  316. print_final_instructions
  317. }
  318. # Run main
  319. main