#!/bin/bash ####------------------- Pre-Flight Checks # Exit on error set -e # Check if the script is run as root if [[ $(id -u) -ne 0 ]]; then echo "Please run this script as root." exit 1 fi # Check if the working directory is 'client' and contains package.json if [[ ! -f "$(pwd)/package.json" ]]; then echo "Error: Please make sure the working directory is 'client' and contains package.json." exit 1 fi # Check to make sure the pi user exists if ! id "pi" &>/dev/null; then echo "Error: User pi does not exist." exit 1 fi ####------------------- Functions # Function to prompt user for input with a specific message and store the result in a variable prompt_user() { if [[ "$TEST_MODE" == "true" ]]; then echo "TESTING" # Use the pre-set value else read -p "$1: " input echo "$input" fi } # Function to prompt user for capabilities options and store the result in a variable prompt_capabilities() { if [[ "$TEST_MODE" == "true" ]]; then echo "radio" # Use the pre-set value else default_capabilities="radio" # Default value read -p "Select CLIENT_CAPABILITIES (comma-separated, default: $default_capabilities): " capabilities capabilities="${capabilities:-$default_capabilities}" # Use default value if input is empty echo "$capabilities" fi } # Function to prompt user for nearby systems details prompt_nearby_system() { if [[ "$TEST_MODE" == "true" ]]; then echo "\"TESTING-Node\": { \"frequencies\": [\"$(echo "155750000,154750000,156555550" | sed 's/,/","/g')\"], \"mode\": \"p25\", \"trunkFile\": \"testing_trunk.tsv\", \"whitelistFile\": \"testing_whitelist.tsv\" }," # Use the pre-set value else local system_name="" local frequencies="" local mode="" local trunk_file="" local whitelist_file="" read -p "Enter system name: " system_name read -p "Enter frequencies (comma-separated): " frequencies read -p "Enter mode (p25/nbfm): " mode if [[ "$mode" == "p25" ]]; then read -p "Enter trunk file: " trunk_file read -p "Enter whitelist file: " whitelist_file fi echo "\"$system_name\": { \"frequencies\": [\"$(echo "$frequencies" | sed 's/,/","/g')\"], \"mode\": \"$mode\", \"trunkFile\": \"$trunk_file\", \"whitelistFile\": \"$whitelist_file\" }," fi } # Check if test mode is enabled if [[ "$1" == "--test" ]]; then TEST_MODE="true" else TEST_MODE="false" fi # Install Node Repo # Get the CPU architecture cpu_arch=$(uname -m) # Print the CPU architecture for verification echo "Detected CPU Architecture: $cpu_arch" # Check if the architecture is ARMv6 if [[ "$cpu_arch" == "armv6"* ]]; then echo "----- CPU Architecture is ARMv6 or compatible. -----" echo "----- CPU Architectre is not compatible with dependencies of this project, please use a newer CPU architecture -----" exit fi curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash - # Update the system apt update apt upgrade -y # Install the necessary packages echo "Installing dependencies..." apt install -y \ nodejs \ libasound-dev \ portaudio19-dev \ libportaudio2 \ libpulse-dev \ pulseaudio \ apulse \ git \ ffmpeg \ python3 \ python3-pip echo "Setting up Pulse Audio" # Ensure pulse audio is running as system so the service can see the audio device systemctl --global disable pulseaudio.service pulseaudio.socket # Update the PulseAudio config to disable autospawning sed -i 's/autospawn = .*$/autospawn = no/' /etc/pulse/client.conf # Add the system PulseAudio service echo "[Unit] Description=PulseAudio system server [Service] Type=notify ExecStart=pulseaudio --daemonize=no --system --realtime --log-target=journal [Install] WantedBy=multi-user.target" >> /etc/systemd/system/PulseAudio.service # Add the root user to the pulse-access group usermod -aG pulse-access root usermod -aG pulse-access pi # Enable the PulseAudio service systemctl enable PulseAudio.service ####------------------- Install and setup node # Run npm install to install dependencies listed in package.json echo "Installing npm dependencies..." npm install # Get rid of PEP 668 rm -rf /usr/lib/python3.11/EMTERNALL-MANAGED # Not sure if this was an attrocious fat finger or if this is needed, doesn't throw an error, so... rm -rf /usr/lib/python3.11/EXTERNALLY-MANAGED # Getting the Python DAB echo "Installing PDAB and Dependencies" git clone -b DRBv3 https://git.vpn.cusano.net/logan/Python-Discord-Audio-Bot.git ./discordAudioBot/pdab pip3 install -r ./discordAudioBot/pdab/requirements.txt # Generate .env file echo "Creating the config .env file..." echo "# Client Config" > .env echo "CLIENT_NUID=0" >> .env client_name=$(prompt_user "Enter the name for this node") echo "CLIENT_NAME=$client_name" >> .env client_location=$(prompt_user "Enter the location of this node") echo "CLIENT_LOCATION=$client_location" >> .env client_capabilities=$(prompt_capabilities) echo "CLIENT_CAPABILITIES=$client_capabilities" >> .env # Server configuration (preset values) echo "" >> .env echo "# Configuration for the connection to the server" >> .env echo "SERVER_IP=vpn.cusano.net" >> .env echo "SERVER_PORT=3000" >> .env # OP25 configuration (preset values) echo "" >> .env echo "# Configuration for OP25" >> .env op25_full_path="$(pwd)/op25/op25/gr-op25_repeater/apps" # Update this with the actual path echo "OP25_FULL_PATH=$op25_full_path" >> .env # Core configuration (preset value) echo "" >> .env echo "# Core config, DO NOT TOUCH UNLESS YOU KNOW WHAT YOU ARE DOING" >> .env echo "CONFIG_PATH=./config/radioPresets.json" >> .env runuser -l pi -c 'python3 ./discordAudioBot/pdab/getDevices.py' audio_device_id=$(prompt_user "Enter the ID of the 'input' audio device you would like to use (most often 'default')") echo "AUDIO_DEVICE_ID=$audio_device_id" >> .env echo "PDAB_PORT=3110" >> .env echo "NODE_ENV=production" >> .env echo ".env file generated successfully." # Create a JSON object to store nearby systems systems_json="{" while true; do systems_json+="$(prompt_nearby_system)" read -p "Do you want to add another system? (yes/no): " choice if [[ "$choice" != "yes" ]]; then break fi done systems_json="${systems_json%,}" # Remove trailing comma systems_json+="}" # Append the created systems to the presets file mkdir -p ./config echo "$systems_json" >> "./config/radioPresets.json" echo "Systems added to radioPresets.json." # Create a systemd service file echo "Adding DRB Node service..." service_content="[Unit] Description=Discord-Radio-Bot_v3 After=syslog.target network.target nss-lookup.target network-online.target Requires=network-online.target [Service] User=1000 Group=1000 WorkingDirectory=$(pwd) ExecStart=/bin/bash -- serviceStart.sh RestartSec=5 Restart=on-failure [Install] WantedBy=multi-user.target" # Write the systemd service file echo "$service_content" > /etc/systemd/system/discord-radio-bot.service # Reload systemd daemon systemctl daemon-reload systemctl enable discord-radio-bot.service echo "\n\n\t\tDiscord Client Node install completed!\n\n" ####------------------- OP25 Installation # Clone OP25 from the git repository echo "Cloning OP25 from the git repository..." git clone -b gr310 https://github.com/boatbod/op25.git # Navigate to the OP25 directory ogPwd=$(pwd) cd op25 # Edit the startup script to use the active.cfg.json config file generated by the app echo "Editing startup script..." sed -i 's/p25_rtl_example.json/active.cfg.json/g' op25-multi_rx.sh # Move the startup script to the apps dir mv op25-multi_rx.sh op25/gr-op25_repeater/apps/ # Install the OP25 service echo "Adding OP25 service..." service_content="[Unit] Description=op25-multi_rx After=syslog.target network.target nss-lookup.target network-online.target Requires=network-online.target [Service] User=1000 Group=1000 WorkingDirectory=$(pwd)/op25/gr-op25_repeater/apps ExecStart=/bin/bash -- op25-multi_rx.sh RestartSec=5 Restart=on-failure [Install] WantedBy=multi-user.target" # Write the systemd service file echo "$service_content" > /etc/systemd/system/op25-multi_rx.service # Reload systemd daemon systemctl daemon-reload # Install OP25 using the provided installation script echo "Installing OP25..." ./install.sh echo "\n\n\t\tOP25 installation completed!\n\n" # Setting permissions on the directories created cd $ogPwd chown -R 1000:1000 ./* chown 1000:1000 .env echo "Permissions set on the client directory!" echo "\n\n\t\tNode installation Complete!" # Prompt the user for reboot confirmation read -p "This script has installed all required components for the DRB client. Are you okay with rebooting? If not, you will have to reboot later before running the applications to finish the installation. (Reboot?: y/n): " confirm # Convert user input to lowercase for case-insensitive comparison confirm="${confirm,,}" #echo "To configure the app, please go to http://$nodeIP:$nodePort" # TODO - uncomment when webapp is built echo "Thank you for joining the network!" if [[ "$confirm" == "y" && "$confirm" == "yes" ]]; then # Prompt user to press any key before rebooting read -rsp $'System will now reboot, press any key to continue or Ctrl+C to cancel...\n' -n1 key echo "Rebooting..." reboot else echo "Please restart your device to complete the installation" fi