setup-pi.sh 10 KB

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