install.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. #!/bin/bash
  2. # Dune Weaver Touch - One-Command Installer
  3. # This script sets up everything needed to run Dune Weaver Touch on boot
  4. set -e
  5. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  6. ACTUAL_USER="${SUDO_USER:-$USER}"
  7. USER_HOME=$(eval echo ~$ACTUAL_USER)
  8. # Detect Raspberry Pi model
  9. PI_MODEL=$(cat /proc/device-tree/model 2>/dev/null | tr -d '\0' || echo "unknown")
  10. IS_PI5=false
  11. if [[ "$PI_MODEL" == *"Pi 5"* ]]; then
  12. IS_PI5=true
  13. fi
  14. echo "🎯 Dune Weaver Touch - Complete Installation"
  15. echo "============================================="
  16. echo "App directory: $SCRIPT_DIR"
  17. echo "User: $ACTUAL_USER"
  18. echo "Detected: $PI_MODEL"
  19. echo ""
  20. # Check if running as root
  21. if [ "$EUID" -ne 0 ]; then
  22. echo "❌ This installer must be run with sudo privileges"
  23. echo ""
  24. echo "Usage: sudo ./install.sh"
  25. echo ""
  26. exit 1
  27. fi
  28. echo "🔧 Installing system components..."
  29. echo ""
  30. # Function to install system scripts
  31. install_scripts() {
  32. echo "📄 Installing system scripts..."
  33. local scripts=("screen-on" "screen-off" "touch-monitor")
  34. for script in "${scripts[@]}"; do
  35. local source_path="$SCRIPT_DIR/scripts/$script"
  36. local target_path="/usr/local/bin/$script"
  37. if [ -f "$source_path" ]; then
  38. cp "$source_path" "$target_path"
  39. chmod 755 "$target_path"
  40. chown root:root "$target_path"
  41. echo " ✅ $script → $target_path"
  42. else
  43. echo " ⚠️ $script not found at $source_path"
  44. fi
  45. done
  46. echo " 📄 System scripts installed"
  47. }
  48. # Function to setup systemd service
  49. setup_systemd() {
  50. echo "🚀 Setting up systemd service..."
  51. # Update paths in the service file
  52. sed "s|/home/pi/dune-weaver-touch|$SCRIPT_DIR|g" "$SCRIPT_DIR/dune-weaver-touch.service" > /tmp/dune-weaver-touch.service
  53. sed -i "s|User=pi|User=$ACTUAL_USER|g" /tmp/dune-weaver-touch.service
  54. sed -i "s|Group=pi|Group=$ACTUAL_USER|g" /tmp/dune-weaver-touch.service
  55. # Copy service file
  56. cp /tmp/dune-weaver-touch.service /etc/systemd/system/
  57. # Enable service
  58. systemctl daemon-reload
  59. systemctl enable dune-weaver-touch.service
  60. echo " 🚀 Systemd service installed and enabled"
  61. }
  62. # Function to configure boot settings for DSI display
  63. configure_boot_settings() {
  64. echo "🖥️ Configuring boot settings for DSI display..."
  65. local CONFIG_FILE="/boot/firmware/config.txt"
  66. # Fallback to old path if new path doesn't exist
  67. [ ! -f "$CONFIG_FILE" ] && CONFIG_FILE="/boot/config.txt"
  68. if [ ! -f "$CONFIG_FILE" ]; then
  69. echo " ⚠️ config.txt not found, skipping boot configuration"
  70. return
  71. fi
  72. # Backup config.txt
  73. cp "$CONFIG_FILE" "${CONFIG_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
  74. echo " ✅ Backed up config.txt"
  75. # Remove old/conflicting KMS settings
  76. sed -i '/dtoverlay=vc4-fkms-v3d/d' "$CONFIG_FILE"
  77. sed -i '/dtoverlay=vc4-xfkms-v3d/d' "$CONFIG_FILE"
  78. if [ "$IS_PI5" = true ]; then
  79. # Pi 5: KMS is enabled by default, gpu_mem is ignored (dedicated VRAM)
  80. echo " ℹ️ Pi 5 detected - KMS enabled by default, skipping vc4-kms-v3d overlay"
  81. echo " ℹ️ Pi 5 has dedicated VRAM, skipping gpu_mem setting"
  82. else
  83. # Pi 3/4: Add full KMS if not present
  84. if ! grep -q "dtoverlay=vc4-kms-v3d" "$CONFIG_FILE"; then
  85. # Find [all] section or add at end
  86. if grep -q "^\[all\]" "$CONFIG_FILE"; then
  87. sed -i '/^\[all\]/a dtoverlay=vc4-kms-v3d' "$CONFIG_FILE"
  88. else
  89. echo -e "\n[all]\ndtoverlay=vc4-kms-v3d" >> "$CONFIG_FILE"
  90. fi
  91. echo " ✅ Enabled full KMS (vc4-kms-v3d) for eglfs support"
  92. else
  93. echo " ℹ️ Full KMS already enabled"
  94. fi
  95. # Add GPU memory if not present (only for Pi 3/4 with shared memory)
  96. if ! grep -q "gpu_mem=" "$CONFIG_FILE"; then
  97. echo "gpu_mem=128" >> "$CONFIG_FILE"
  98. echo " ✅ Set GPU memory to 128MB"
  99. else
  100. echo " ℹ️ GPU memory already configured"
  101. fi
  102. fi
  103. # Disable splash screens for cleaner boot (all Pi models)
  104. if ! grep -q "disable_splash=1" "$CONFIG_FILE"; then
  105. echo "disable_splash=1" >> "$CONFIG_FILE"
  106. echo " ✅ Disabled rainbow splash"
  107. else
  108. echo " ℹ️ Rainbow splash already disabled"
  109. fi
  110. echo " 🖥️ Boot configuration updated"
  111. }
  112. # Function to setup touch rotation via udev rule
  113. setup_touch_rotation() {
  114. echo "👆 Setting up touchscreen rotation..."
  115. local UDEV_RULE_FILE="/etc/udev/rules.d/99-ft5x06-rotate.rules"
  116. # Create udev rule for FT5x06 touch controller (180° rotation)
  117. cat > "$UDEV_RULE_FILE" << 'EOF'
  118. # Rotate FT5x06 touchscreen 180 degrees using libinput calibration matrix
  119. # Matrix format: a b c d e f 0 0 1
  120. # For 180° rotation: -1 0 1 0 -1 1 0 0 1
  121. # This inverts both X and Y axes (equivalent to 180° rotation)
  122. SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="*generic ft5x06*", \
  123. ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 0 -1 1 0 0 1"
  124. EOF
  125. chmod 644 "$UDEV_RULE_FILE"
  126. echo " ✅ Touch rotation udev rule created: $UDEV_RULE_FILE"
  127. # Reload udev rules
  128. udevadm control --reload-rules
  129. udevadm trigger
  130. echo " ✅ Udev rules reloaded"
  131. echo " 👆 Touch rotation configured (180°)"
  132. }
  133. # Function to hide mouse cursor
  134. hide_mouse_cursor() {
  135. echo "🖱️ Configuring mouse cursor hiding..."
  136. # Install unclutter for hiding mouse cursor when idle
  137. echo " 📦 Installing unclutter..."
  138. apt install -y unclutter > /dev/null 2>&1
  139. # Create autostart directory if it doesn't exist
  140. local AUTOSTART_DIR="$USER_HOME/.config/autostart"
  141. mkdir -p "$AUTOSTART_DIR"
  142. chown -R "$ACTUAL_USER:$ACTUAL_USER" "$USER_HOME/.config"
  143. # Create unclutter autostart entry
  144. cat > "$AUTOSTART_DIR/unclutter.desktop" << 'EOF'
  145. [Desktop Entry]
  146. Type=Application
  147. Name=Unclutter
  148. Comment=Hide mouse cursor when idle
  149. Exec=unclutter -idle 0.1 -root
  150. Hidden=false
  151. NoDisplay=false
  152. X-GNOME-Autostart-enabled=true
  153. EOF
  154. chown "$ACTUAL_USER:$ACTUAL_USER" "$AUTOSTART_DIR/unclutter.desktop"
  155. echo " 🖱️ Mouse cursor hiding configured"
  156. }
  157. # Function to setup kiosk optimizations
  158. setup_kiosk_optimizations() {
  159. echo "🖥️ Setting up kiosk optimizations..."
  160. local CMDLINE_FILE="/boot/firmware/cmdline.txt"
  161. [ ! -f "$CMDLINE_FILE" ] && CMDLINE_FILE="/boot/cmdline.txt"
  162. # Determine DSI connector name based on Pi model
  163. # Pi 5 uses DSI-2 (separate DRM device), Pi 3/4 use DSI-1
  164. local DSI_CONNECTOR="DSI-1"
  165. if [ "$IS_PI5" = true ]; then
  166. DSI_CONNECTOR="DSI-2"
  167. echo " ℹ️ Pi 5 detected - using DSI-2 connector"
  168. fi
  169. # Configure cmdline.txt for display and boot
  170. if [ -f "$CMDLINE_FILE" ]; then
  171. cp "$CMDLINE_FILE" "${CMDLINE_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
  172. # Add video parameter for DSI display with rotation
  173. # Check for any existing DSI video configuration
  174. if ! grep -q "video=DSI-[0-9]:800x480@60,rotate=180" "$CMDLINE_FILE"; then
  175. sed -i "s/$/ video=${DSI_CONNECTOR}:800x480@60,rotate=180/" "$CMDLINE_FILE"
  176. echo " ✅ DSI display configuration added (${DSI_CONNECTOR}:800x480@60, rotated 180°)"
  177. else
  178. echo " ℹ️ DSI display configuration already present"
  179. fi
  180. # Add quiet splash for cleaner boot
  181. if ! grep -q "quiet splash" "$CMDLINE_FILE"; then
  182. sed -i 's/$/ quiet splash/' "$CMDLINE_FILE"
  183. echo " ✅ Boot splash enabled"
  184. else
  185. echo " ℹ️ Boot splash already enabled"
  186. fi
  187. fi
  188. echo " 🖥️ Kiosk optimizations applied"
  189. }
  190. # Function to setup console auto-login
  191. setup_console_autologin() {
  192. echo "🔑 Setting up console auto-login..."
  193. local OVERRIDE_DIR="/etc/systemd/system/getty@tty1.service.d"
  194. local OVERRIDE_FILE="$OVERRIDE_DIR/autologin.conf"
  195. # Create override directory
  196. mkdir -p "$OVERRIDE_DIR"
  197. # Create autologin override for getty@tty1
  198. cat > "$OVERRIDE_FILE" << EOF
  199. [Service]
  200. ExecStart=
  201. ExecStart=-/sbin/agetty --autologin $ACTUAL_USER --noclear %I \$TERM
  202. EOF
  203. chmod 644 "$OVERRIDE_FILE"
  204. echo " ✅ Getty autologin override created: $OVERRIDE_FILE"
  205. # Reload systemd to pick up changes
  206. systemctl daemon-reload
  207. echo " ✅ Systemd daemon reloaded"
  208. echo " 🔑 Console auto-login configured for user: $ACTUAL_USER"
  209. }
  210. # Function to setup Python virtual environment and install dependencies
  211. setup_python_environment() {
  212. echo "🐍 Setting up Python virtual environment..."
  213. # Install system Qt6 and PySide6 packages for full eglfs support
  214. echo " 📦 Installing system Qt6 and PySide6 packages..."
  215. apt update
  216. apt install -y \
  217. python3-pyside6.qtcore \
  218. python3-pyside6.qtgui \
  219. python3-pyside6.qtqml \
  220. python3-pyside6.qtquick \
  221. python3-pyside6.qtquickcontrols2 \
  222. python3-pyside6.qtquickwidgets \
  223. python3-pyside6.qtwebsockets \
  224. python3-pyside6.qtnetwork \
  225. qml6-module-qtquick \
  226. qml6-module-qtquick-controls \
  227. qml6-module-qtquick-layouts \
  228. qml6-module-qtquick-window \
  229. qml6-module-qtquick-dialogs \
  230. qml6-module-qt-labs-qmlmodels \
  231. qt6-virtualkeyboard-plugin \
  232. qml6-module-qtquick-virtualkeyboard \
  233. qt6-base-dev \
  234. qt6-declarative-dev \
  235. libqt6opengl6 \
  236. libqt6core5compat6 \
  237. libqt6network6 \
  238. libqt6websockets6 > /dev/null 2>&1
  239. echo " ✅ System Qt6/PySide6 packages installed"
  240. # Create virtual environment with system site packages
  241. if [ ! -d "$SCRIPT_DIR/venv" ]; then
  242. echo " 📦 Creating virtual environment with system site packages..."
  243. python3 -m venv --system-site-packages "$SCRIPT_DIR/venv" || {
  244. echo " ⚠️ Could not create virtual environment. Installing python3-venv..."
  245. apt install -y python3-venv python3-full
  246. python3 -m venv --system-site-packages "$SCRIPT_DIR/venv"
  247. }
  248. else
  249. echo " ℹ️ Virtual environment already exists"
  250. fi
  251. # Install non-Qt dependencies from requirements.txt
  252. echo " 📦 Installing Python dependencies..."
  253. "$SCRIPT_DIR/venv/bin/python" -m pip install --upgrade pip > /dev/null 2>&1
  254. "$SCRIPT_DIR/venv/bin/pip" install -r "$SCRIPT_DIR/requirements.txt" > /dev/null 2>&1
  255. # Change ownership to the actual user (not root)
  256. chown -R "$ACTUAL_USER:$ACTUAL_USER" "$SCRIPT_DIR/venv"
  257. echo " 🐍 Python virtual environment ready"
  258. }
  259. # Main installation process
  260. echo "Starting complete installation..."
  261. echo ""
  262. # Install everything
  263. setup_python_environment
  264. install_scripts
  265. setup_systemd
  266. configure_boot_settings
  267. setup_touch_rotation
  268. hide_mouse_cursor
  269. setup_kiosk_optimizations
  270. setup_console_autologin
  271. echo ""
  272. echo "🎉 Installation Complete!"
  273. echo "========================"
  274. echo ""
  275. echo "📟 Detected: $PI_MODEL"
  276. if [ "$IS_PI5" = true ]; then
  277. echo " └─ Using Pi 5 optimized settings (DSI-2, dedicated VRAM)"
  278. fi
  279. echo ""
  280. echo "✅ Python virtual environment created at: $SCRIPT_DIR/venv"
  281. echo "✅ System scripts installed in /usr/local/bin/"
  282. echo "✅ Systemd service configured for auto-start"
  283. echo "✅ Mouse cursor hiding configured (Qt + unclutter)"
  284. echo "✅ Kiosk optimizations applied"
  285. echo "✅ Console auto-login configured"
  286. echo ""
  287. echo "🔧 Service Management:"
  288. echo " Start now: sudo systemctl start dune-weaver-touch"
  289. echo " Stop: sudo systemctl stop dune-weaver-touch"
  290. echo " Status: sudo systemctl status dune-weaver-touch"
  291. echo " Logs: sudo journalctl -u dune-weaver-touch -f"
  292. echo ""
  293. echo "💡 To start the service now without rebooting:"
  294. echo " sudo systemctl start dune-weaver-touch"
  295. echo ""
  296. echo "🛠️ For development/testing (run manually):"
  297. echo " cd $SCRIPT_DIR"
  298. echo " ./run.sh"
  299. echo ""
  300. echo "⚙️ To change boot/login settings later:"
  301. echo " sudo ./configure-boot.sh"
  302. echo ""
  303. # Ask if user wants to start now
  304. read -p "🤔 Would you like to start the service now? (y/N): " -n 1 -r
  305. echo
  306. if [[ $REPLY =~ ^[Yy]$ ]]; then
  307. echo "🚀 Starting Dune Weaver Touch service..."
  308. systemctl start dune-weaver-touch
  309. sleep 2
  310. systemctl status dune-weaver-touch --no-pager -l
  311. echo ""
  312. echo "✅ Service started! Check the status above."
  313. fi
  314. echo ""
  315. echo "🚀 Next Steps:"
  316. echo " 1. ⚠️ REBOOT REQUIRED for config.txt changes to take effect"
  317. echo " 2. After reboot, the app will start automatically on boot via systemd service"
  318. echo " 3. Check the logs if you encounter any issues: sudo journalctl -u dune-weaver-touch -f"
  319. echo ""
  320. echo "🎯 Installation completed successfully!"