# Préparation de l'image RPI videopi ## Raspi OS et SSH 1. Télécharger l'image disque version "Legacy" lite : https://downloads.raspberrypi.org/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2022-09-26/2022-09-22-raspios-buster-armhf-lite.img.xz 2. Flasher l'image sur une carte SD : `xzcat 2022-09-22-raspios-buster-armhf-lite.img.xz | sudo dd of=/dev/mmcblkp0 bs=128K oflag=dsync status=progress && sync` 3. Monter la carte SD et ajouter un fichier nommé `ssh` sur la partition `/boot` pour activer le serveur SSH; `touch boot/ssh` (https://linuxhint.com/rasperberry_pi_wifi_wpa_supplicant/) 5. Toujours sur la partition `/boot`, créer un fichier nommé `wpa_supplicant.conf` pour configurer la connexion wifi. Le contenu de celui-ci : ``` ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 country=FR network={ ssid="BLAH" # Nom du réseau auquel on se connecte #scan_ssid=1 # Décommenter si le réseau est caché psk="BLAH" # Mot de passe wifi # Pour accélérer la découverte et la connexion du point d'accès wifi, # on peut spécifier les fréquences à balayer en fonction du canal utilisé par ce dernier. # https://w1.fi/cgit/hostap/tree/wpa_supplicant/wpa_supplicant.conf#n910 # Wifi 2.4 Ghz : https://fr.wikipedia.org/wiki/Liste_des_canaux_Wi-Fi#Bande_2,4_GHz # scan_freq=2412 2437 2462 # See nmcli 802-11-wireless.channel # https://developer-old.gnome.org/NetworkManager/stable/settings-802-11-wireless.html # Wifi 5ghz : https://fr.wikipedia.org/wiki/Liste_des_canaux_Wi-Fi#Liste_des_canaux_dans_la_bande_des_5_GHz # scan_freq= 5805 } ``` 4. Insérer la carte dans le RPI et démarrer le système. 5. Se connecter via SSH. 6. Adduser pil ### Options du pilote brcmfmac pour le wifi intégré des rpi 3+/4 Voir ici : [https://wiki.arthus.net/?Rpi_wifi_-_BCM4345_and_CTRL-EVENT-ASSOC-REJECT](https://wiki.arthus.net/?Rpi_wifi_-_BCM4345_and_CTRL-EVENT-ASSOC-REJECT) ``` echo 'options brcmfmac roamoff=1 feature_disable=0x82000' | sudo tee /etc/modprobe.d/brcmfmac.conf ``` ## Modification de config.txt Ajouter les lignes suivantes au fichier `/boot/config.txt` : ``` #hdmi_force_hotplug=1 #hdmi_drive=2 # Forcer HDMI Full HD hdmi_group=1 hdmi_mode=16 # fullHD@60 [all] # Désactivation du bluetooth dtoverlay=disable-bt max_framebuffers=2 # Désactiver le logo éclair et l'arc en ciel au démarrage boot_delay=1 avoid_warnings=1 disable_splash=1 ``` ### Activation du pilote GPU libre pour le décodage vidéo matériel Ajouter à '/boot/config.txt' : ``` dtoverlay=vc4-kms-v3d ``` #### Utilisation gpu ``` vcgencmd get_mem ``` Where type is: * arm: total memory assigned to arm * gpu: total memory assigned to gpu * malloc_total: total memory assigned to gpu malloc heap * malloc: free gpu memory in malloc heap * reloc_total: total memory assigned to gpu relocatable heap * reloc: free gpu memory in relocatable heap ### Overclocking ``` # SD card reader OC (expect 20% rio improvement) # https://www.pidramble.com/wiki/benchmarks/microsd-cards # Samsung Pro/Evo+ is recommended # default value : 50 # value needs to be an int divisor of core_freq # NEEDS A UHS-1/Class10 SD CARD ! # dtparam=sd_overclock=84 # to check value in os : cat /sys/kernel/debug/mmc0/ios [pi4] # Run as fast as firmware / board allows arm_boost=1 dtoverlay=disable-bt dtoverlay=vc4-kms-v3d max_framebuffers=2 # Apply to rpi3, rpi3+, cm3 [pi3] # Safe OC values # gpu_freq : Sets core_freq, h264_freq, isp_freq, v3d_freq and hevc_freq together # default values : # arm_freq 1200 # gpu_freq 400 # sdram_freq 450 arm_freq=1300 gpu_freq=462 sdram_freq=500 over_voltage=3 dtparam=sd_overclock=66 # Disable bluetooth dtoverlay=disable-bt #dtoverlay=disable-wifi # Enable DRM VC4 V3D driver dtoverlay=vc4-kms-v3d max_framebuffers=2 gpu_mem=64 # Override OC values for 3+ models [pi3+] # Defaults values : # arm_freq 1400 # core_freq 400 # gpu_freq 400 # sdram_freq 500 arm_freq=1500 sdram_freq=550 [pi1] # Defaults values : # arm_freq 700 # core_freq 250 # sdram_freq 400 arm_freq=950 core_freq=300 sdram_freq=500 over_voltage=6 gpu_mem=128 [all] # Forcer HDMI Full HD hdmi_group=1 hdmi_mode=16 # fullHD@60 # Désactiver le logo éclair et l'arc en ciel au démarrage boot_delay=1 avoid_warnings=1 disable_splash=1 ``` ## Configuration du Wifi ``` echo -e " ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\n update_config=1\n country=FR\n \n network={\n ssid="BLAH" # Nom du réseau auquel on se connecte\n #scan_ssid=1 # hidden ssid \n psk="BLAH" # Mot de passe wifi\n # Specify 2.4 or 5G freq\n # https://w1.fi/cgit/hostap/tree/wpa_supplicant/wpa_supplicant.conf#n910\n # https://fr.wikipedia.org/wiki/Liste_des_canaux_Wi-Fi#Bande_2,4_GHz # scan_freq=2412 2437 2462\n # See nmcli 802-11-wireless.channel\n # https://developer-old.gnome.org/NetworkManager/stable/settings-802-11-wireless.html\n # scan_freq= 5805\n }\n" | sudo tee -a /etc/wpa_supplicant/wpa_supplicant.conf ``` ## Limiter le nombre de paquets installés par APT ``` echo -e 'APT::Install-Suggests "0";\nAPT::Install-Recommends "0";' | sudo tee -a /etc/apt/apt.conf.d/80noclutter ``` ## Rendre le démarrage du RPI complètement silencieux (écran noir) ### cmdline.txt Editer le fichier `/boot/cmdline.txt` et ajouter les options suivantes à la fin de la première ligne: ``` console=tty3 loglevel=3 vt.global_cursor_default=0 logo.nologo quiet consoleblank=1 ``` ### Login silencieux Lancer les commandes suivantes : * `echo "" | sudo tee /etc/issue` * `echo "" | sudo tee /etc/motd` * `touch ~/.hushlogin` Editer le fichier `/etc/systemd/system/getty@tty1.service.d/autologin.conf` et remplacer le contenu par : ``` [Service] ExecStart= ExecStart=-/sbin/agetty --skip-login --noclear --noissue --login-options "-f pil" %I $TERM ``` Editer le fichier `/etc/rc.local` et ajouter la ligne suivante juste avant "exit 0" : `setterm -term linux -blank 1 >/dev/tty1` ## Connexion automatique au démarrage Lancer la commande `raspi-config`, puis aller dans "1 System Options", "S5 Boot / Auto login", "B2 Console Auto Login". ## Installation des logiciels nécessaires ``` sudo apt-get update # min sudo apt-get install vlc vlc-plugin-base python3-minimal python3-pip nginx file lua5.2 python pip install flask flask-httpauth waitress toml werkzeug ffmpeg ffmpegthumbnailer # build # sudo apt-get install vlc git dkms firmware-realtek firmware-iwlwifi firmware-ipw2x00 firmware-atheros raspberrypi-kernel-headers build-essential va-driver-all va-driver vdpau-driver-all ``` ### SSH : identification par clés Sur le serveur régie, générer les clés publiques/privées avec : ``` # générer une clé sans mot de passe, adapter le nom du fichier ssh-keygen -t ed25519 -f ~/.ssh/videopiX -N "" # copier sur le client rpi en adaptant l'IP SSH_AUTH_SOCK="" ssh-copy-id -i .ssh/videopiX.pub pi@$IP ``` Désactiver la connexion par login/mdp : ``` echo "PasswordAuthentication no ChallengeResponseAuthentication no UsePAM no" | sudo tee -a /etc/ssh/sshd_config ``` Sur le serveur régie, éditer le fichier `~/.ssh/config` et ajouter à la fin : ``` # VideoPi Host 10.42.0.142 IdentityFile ~/.ssh/ User pi Host 10.42.0.135 IdentityFile ~/.ssh/rpi3 User pi ``` ## Sudoers : commandes systèmes sans mot de passe `/etc/sudoers.d/010_pilpil_nopasswd.conf` : ``` Cmnd_Alias PILPIL=/usr/sbin/reboot, /usr/sbin/poweroff, /usr/bin/tee pil ALL=(ALL) NOPASSWD: PILPIL ``` ## Systemd Unit : démarrage automatique des services ## VLC Créer le fichier `.config/systemd/user/vlc.service` contenant: ``` [Unit] Description=VLC http service [Service] WorkingDirectory=/home/pil/ ExecStart=/usr/bin/cvlc --quiet -I http --no-osd --http-password=secret --file-caching=5000 Restart=always [Install] WantedBy=multi-user.target ``` Puis lancer les commandes : ``` systemctl --user daemon-reload systemctl --user enable vlc systemctl --user start vlc ``` ## pilpil Créer le fichier `.config/systemd/user/pilpil.service` contenant: ``` [Unit] Description=Pilpil Command Server After=network.target [Service] WorkingDirectory=/home/pil/pilpil-client #ExecStart=/home/pil/pilpil-client/app.py ExecStart=/home/pil/.local/bin/waitress-serve --listen=127.0.0.1:5000 app:app Restart=always [Install] WantedBy=multi-user.target ``` Puis lancer les commandes : ``` systemctl --user daemon-reload systemctl --user enable pilpil systemctl --user start pilpil ``` ## Configuration du serveur régie ### Linux : network-manager cli ``` hotspot() { SSID="omen" PASSWD="EpQmSmXH123" #Intel IFW="wlo1" #Brostrend #IFW="wlp0s20f0u1" #Band (bg = 2.4Ghz, a= 5Ghz) BAND="bg" #HIDE="802-11-wireless.hidden false" CHAN="802-11-wireless.channel 1" if [ "$1" == "off" ];then nmcli radio wifi off nmcli con delete $SSID else if [ "$1" == "wlp0s20f0u1" ];then IFW="wlp0s20f0u1" # IFW="wlp0s20f0u2u4" # BAND="a" # CHAN="802-11-wireless.channel 161" fi nmcli con delete $SSID nmcli con add type wifi ifname $IFW con-name $SSID autoconnect no ssid $SSID nmcli con modify $SSID 802-11-wireless.mode ap 802-11-wireless.band $BAND $CHAN ipv4.method shared nmcli con modify $SSID wifi-sec.key-mgmt wpa-psk nmcli con modify $SSID 802-11-wireless-security.proto rsn nmcli con modify $SSID 802-11-wireless-security.pairwise ccmp nmcli con modify $SSID wifi-sec.psk $PASSWD nmcli radio wifi on nmcli con up $SSID fi } ``` #### Changer la plage d'IP du hotspot Une fois la connexion créée, éditer `/etc/NetworkManager/system-connections/$SSID.nmconnection` et ajouter une directive `address1` à la section "[ipv4]": ``` [ipv4] method=shared address1=192.168.125.1/24,192.168.125.1 ``` puis redémarrer networkmanager : ``` sudo systemctl restart NetworkManager ``` #### Supprimer baux dhcp ``` sudo rm /var/lib/NetworkManager/*.leases ``` `sudo rm /var/lib/NetworkManager/dnsmasq-wlo1.leases` ### IP fixes des clients #### Bail dhcp permanent `sudo nano /etc/NetworkManager/dnsmasq-shared.d/wlo1.conf` ``` log-queries log-facility=/var/log/dnsmasq.log #rpi1 dhcp-host=00:e0:4c:18:0a:fa,rpi1,10.42.0.142 #rpi3 dhcp-host=b8:27:eb:12:55:31,rpi3,10.42.0.135 ``` #### WPA supplicant ### Windows setup #### Hotspot : netsh ``` netsh wlan set hostednetwork mode=allow ssid=Hotspot key=ZiZiPass netsh wlan start hostednetwork ``` #### Dependencies 1. Install wsl/msys2 ; [https://learn.microsoft.com/fr-fr/windows/wsl/install]/[https://www.msys2.org/] 2. Install openssh, rsync, python-pip : ``` pacman -S openssh rsync python-pip ``` 3. Install python deps : ``` pip install flask waitress toml ``` 4. Start app with `flask run` ### Win/Linux install With Docker-compose / Docker desktop: ``` docker-compose -f docker-compose.yml up ``` ### Firewall : port 67 Ouvrir port 67 pour le DHCP ## Imaging the OS ### From Sd to image `dd bs=256K if=/dev/sda of=BLAH.img status=progress oflag=dsync` ### Shrink image `sudo pishrink.sh -sZpa BLAH.img` ### From image to sd `xzcat 2022-07-19-videopi.img.xz | sudo dd of=/dev/sda bs=128K oflag=dsync status=progress && sync` ### Regenerate SSH hostkeys on first start `sudo ln -s /lib/systemd/system/regenerate_ssh_host_keys.service /mount_point/etc/systemd/system/multi-user.target.wants/regenerate_ssh_host_keys.service` ### (Optional) Resize FS to fill SD card Use `raspi-config` to resize the file system; "Advanced options" > "Expand Filesystem" ## Installation * Install python 3.10 * Use pip to install flask, waitress : ``` pip install flask waitress toml ``` ## Other : ### VLC : local jquery and flowplayer libs #### Jquery Récupérer les librairies jquery sur le system de fichier local dans '/usr/share/vlc/lua/http/js' : ``` sudo mkdir -p /usr/share/vlc/lua/http/js/ajax/libs/jquery/1.6.1/ sudo mkdir -p /usr/share/vlc/lua/http/js/ajax/libs/jqueryui/1.8.13/ sudo wget -P /usr/share/vlc/lua/http/js/ajax/libs/jquery/1.6.1/ https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js sudo wget -P /usr/share/vlc/lua/http/js/ajax/libs/jqueryui/1.8.13/ https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js ``` Remplacer les liens d'importation dans '/usr/share/vlc/lua/http/index.html', l.40-41 : ```html ``` #### Flowplayer ``` sudo mkdir -p /usr/share/vlc/lua/http/js/swf sudo wget -P /usr/share/vlc/lua/http/js/ https://releases.flowplayer.org/js/flowplayer-3.2.6.min.js sudo wget -P /usr/share/vlc/lua/http/js/swf https://releases.flowplayer.org/swf/flowplayer-3.2.7.swf ``` Remplacer les liens d'importation dans '/usr/share/vlc/lua/http/index.html', l.211-213 : ```js $.getScript('./js/flowplayer-3.2.6.min.js', function(data, textStatus){ $('#player').empty(); flowplayer("player", "./js/swf/flowplayer-3.2.7.swf"); ``` ### VLC http LUA : ajouter des méthodes On modifie le fichier [`httprequests.lua`](https://code.videolan.org/videolan/vlc/-/blob/master/share/lua/intf/modules/httprequests.lua) : `/usr/lib/arm-linux-gnueabihf/vlc/lua/intf/modules/httprequests.lua` Pour être sur d'avoir la bonne version, `apt-get source vlc-plugin-base` après avoir décommenté la ligne pour les sources dans `/etc/apt/sources.list`. Puis `tar -xvf vlc_3.0.17.4.orig.tar.xz vlc-3.0.17.4/share/lua/intf/modules/httprequests.lua`. On compile avec luac en faisant attention à bien utiliser la bonne version de luac ( 5.2 avec VLC-3.0.17.4 au 09-2022 ) : ``` file /usr/lib/arm-linux-gnueabihf/vlc/lua/intf/modules/httprequests.luac luac.out: Lua bytecode, version 5.2 luac -v Lua 5.2 Copyright (C) 1994-2021 Lua.org, PUC-Rio ``` * Ajout ligne 131 : ```lua elseif command == "pl_move" then vlc.playlist.move( id, tonumber(val) or -1 ) ``` * Compilation : ``` luac -o /usr/lib/arm-linux-gnueabihf/vlc/lua/intf/modules/httprequests.luac vlc-3.0.17.4/share/lua/intf/modules/httprequests.lua ``` [https://salsa.debian.org/multimedia-team/vlc](https://salsa.debian.org/multimedia-team/vlc) #### pl_move : Usage Sample playlist : ``` ``` ``` # Move id 3 after id 5 10.42.0.135:8080/requests/status.xml?command=pl_move&id=3&val=5 ``` ``` # Make id 4 first item in list 10.42.0.135:8080/requests/status.xml?command=pl_move&id=4&val=1 Make an array from new playlist, then loop other that from the end ``` ### Certbot, Nginx, Waitress https://dev.to/thetrebelcc/how-to-run-a-flask-app-over-https-using-waitress-and-nginx-2020-235c ``` sudo apt-get install nginx ``` /etc/nginx/sites-available/default : ``` # Cmd server server { listen 8888 ssl; ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; location / { client_max_body_size 100M; # Max http_upload size proxy_pass http://127.0.0.1:5000; proxy_set_header X-Real-IP $remote_addr; } } # VLC server server { listen 8887 ssl; ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; location / { proxy_pass http://127.0.0.1:5001; proxy_set_header X-Real-IP $remote_addr; } } ``` openssl : ``` openssl req -new -newkey rsa:4096 -days 1825 -nodes -x509 -subj "/C=/ST=Denial/L=/O=/CN=10.42.0.135" -addext "subjectAltName=10.42.0.135" -keyout "/etc/ssl/private/nginx-selfsigned.key" -out "/etc/ssl/certs/nginx-selfsigned.crt" ``` #### Fix nginx startup fail if /var/log/nginx doesn't exists In '/etc/nginx/mklogdir.sh' : ```bash #!/bin/bash if [[ ! -d /var/log/nginx ]] then mkdir /var/log/nginx systemctl restart nginx fi ``` then `sudo chmod +x /etc/nginx/mklogdir.sh`. After that, edit the nginx service unit to add a `ExecStartPre` directive to run the script : ``` sudo systemctl edit --full nginx.service [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/etc/nginx/mklogdir.sh # Add this line ``` ### Bash script ```bash #!/bin/bash PASSWD="secret" ADDRESSES=("10.42.0.1" "10.42.0.135" "10.42.0.142") #ADDRESSES1=("10.42.0.1" "10.42.0.135") #ADDRESSES2=("10.42.0.142") for ADDR in ${ADDRESSES[@]} do echo "Sending command $1 and $2 to $ADDR..." echo -e "$PASSWD\n$1\n$2" | nc "$ADDR" 9999 -w 5 & # echo -e "$PASSWD\n$1\n$2" | nc "$ADDR" 9999 -w 5 | sed '/Welcome/d;/VLC/d;/Password/d;' & # echo -e "$PASSWD\n$1\n$2" | nc "$ADDR" 9999 > /dev/null & done sleep 0.5 for ADDR in ${ADDRESSES[@]} do echo "Sending command $3 and $4 to $ADDR..." echo -e "$PASSWD\n$3\n$4" | nc "$ADDR" 9999 > /dev/null & done ``` #### DKMS install All modules on all kernels : ``` ls /lib/modules | \ sudo xargs -n1 /usr/lib/dkms/dkms_autoinstaller start ``` Specific module on specific kernel : ``` sudo dkms build -m rtl8821cu -v 5.12.0 -k $kernel_version # rtl8192eu/1.0 sudo dkms install -m rtl8821cu -v 5.12.0 -k $kernel_version # rtl8192eu/1.0 # The module should loaded automatically but just if needed... sudo modprobe 8821cu # 8192eu ``` ## Udev & systemd - Running a graphic environment when a USB device is plugged in ## Summary : At a GNU/Linux console prompt, no GUI. When a USB device of type [HID](https://en.wikipedia.org/wiki/Human_interface_device) (keyboard/mouse mainly) is plugged in, we want the X server to start and launch VLC's graphical interface, fullscreen, no borders. When this device is removed, VLC is shut down and the X server too, and we end up back at the console prompt. ### Proposed solution: 1. [Udev](https://wiki.archlinux.org/title/Udev) rules are triggered when the USB device is plugged/unplugged to create a file in '/tmp' named '.vlc_gui'. 2. A systemd [user](https://wiki.archlinux.org/title/Systemd/User) service starts a script on startup. 3. This script uses [inotifywait](https://man.archlinux.org/man/inotifywait.1) to monitor a file's creation/deletion in the '/tmp' folder, and act accordingly; 4. Start/close a minimal graphical environment with [openbox](http://openbox.org/) running [VLC](https://videolan.org). ## 1. Udev configuration ### Run script on USB HID (mouse/kb) connect We want a rule that triggers when a device has SUBSYSTEM=="usb" and DRIVER=="usbhid". In '/etc/udev/rules.d/01-vlc_gui.rules' : ``` # On plug ACTION=="add" SUBSYSTEM=="usb", DRIVER=="usbhid", RUN+="/usr/bin/touch /tmp/.vlc_gui" # On un-plug ACTION=="remove" SUBSYSTEM=="usb", RUN+="/usr/bin/rm -f /tmp/.vlc_gui" ``` The rules above create a '.vlc_gui' file in '/tmp' when a usbhid device is plugged in, and removes it when unplugged. ### Change read permissions on tty7 By default, permissions on '/dev/tty*' are 0620 (`crw--w----`). So members of group `tty` can write, but not read to ttys. This will be a problem for the X server, so we need to change those permissions to have read writes for our group too. Let's change the permissions on the tty that we need to 0660 (`crw-rw----`) so that we can run our X session on it. Inspect how udev sees your TTY (tty7 here): `udevadm info --attribute-walk --path=/sys/class/tty/tty7` ``` looking at device '/devices/virtual/tty/tty7': KERNEL=="tty7" SUBSYSTEM=="tty" DRIVER=="" ATTR{power/control}=="auto" ATTR{power/runtime_active_time}=="0" ATTR{power/runtime_status}=="unsupported" ATTR{power/runtime_suspended_time}=="0 ``` So we want a rule that matches 'KERNEL=="tty7"' and 'SUBSYSTEM=="tty"' and set it to mode '0660': `SUBSYSTEM=="tty", KERNEL=="tty7", MODE:="0660"` Notice the [immutable operator](https://www.freedesktop.org/software/systemd/man/udev.html#Operators) ":=" for "MODE"; it makes shure this won't be changed by another rule. [Udev rules order read](https://forums.opensuse.org/t/udev-rules-priority-disallow-change-by-other-rules-with-operator/100210) Test which rules are triggered by a specific device with : `udevadm test /class/tty/tty7` Reload and apply the new rules with : ``` udevadm control --reload-rules udevadm trigger ``` Of course, don't forget to add your user to the 'tty' group : `sudo adduser USERNAME tty` On some system, you might have to use usermod : `sudo usermod -a -G tty USERNAME` then log out/in and check with `groups` that 'tty' appears in the listed groups. ## 2. Systemd user unit We can create [user units](https://wiki.archlinux.org/title/systemd/User) in '~/.config/systemd/user/', e.g : `nano ~/.config/systemd/user/vlc_gui.service` ```yaml [Unit] Description=VLC GUI launcher service [Service] # %h specifier resolves to user home (~ equivalent) ExecStart="%h"/vlc_gui.sh Restart=always [Install] WantedBy=default.target ``` Reload the units with `systemctl --user daemon-reload` and start/enable the service with `systemctl --user start vlc_gui.service` / `systemctl --user enable vlc_gui.service`. More about systemd specifiers: [https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers](https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers) ### Starting a user unit as root If running [systemd version >= 248 (2021-03)](https://github.com/systemd/systemd/blob/28795f2c138203fb700fc394f0937708af886116/NEWS#L2809), you can [start a user unit as root](https://www.freedesktop.org/software/systemd/man/systemctl.html#-M), i.e ; using `sudo systemctl` or in a root shell, with e.g: `sudo systemctl --user --machine USERNAME@ start foo.service` On prior versions, you have to use either `su - USERNAME -c 'systemctl --user start foo.service'` or `runuser -l USERNAME -c 'systemctl --user start foo.service'` instead. ## 3. inotifywait : watch for a file's creation/deletion ### Install the tool : `sudo apt-get install inotify-tools` ### Create the script : In '~/vlc_gui.sh' : ```bash #!/usr/bin/env bash inotifywait -m /tmp -e create -e delete | while read directory action file; do if [[ "$file" == ".vlc_gui" ]]; then if [[ "$action" == "CREATE" ]]; then echo "Starting VLC GUI." # Start X environment on tty7 DISPLAY=:0 startx -- vt7 & elif [[ "$action" == "DELETE" ]]; then echo "Killing VLC GUI" pkill vlc fi fi done ``` Don't forget to set execution bit : `sudo chmod +x ~/vlc_gui.sh` ## 4. Minimal X environment & Launching VLC Install the following packages : `sudo apt-get install -y --no-install-recommends --no-install-suggests xinit xserver-xorg xserver-xorg-core xserver-xorg-input-evdev xserver-xorg-input-kbd openbox feh` ### Xinit config We start the X environment with `startx`, which sources "~/.xinitrc". Let's start openbox session there. `cp /etc/X11/xinit/xinitrc ~/.xinitrc` Then in "~/.xinitrc" : ```bash #!/bin/sh # /etc/X11/xinit/xinitrc # # global xinitrc file, used by all X sessions started by xinit (startx) # invoke global X session script . /etc/X11/Xsession exec openbox-session ``` Set execution bit : `sudo chmod +x ~/.xinitrc` ### Openbox configuration Now Openbox config files are in '~/.config/openbox' and there are two of them : #### autostart.sh In '~/.config/openbox/autostart.sh' : ```bash #!/bin/bash # Exit openbox when VLC is closed vlc --vout=gles2 && openbox --exit # on rpi with 3d kms driver, can be --vout=drm_vout ``` Set execution bit : `sudo chmod +x ~/.config/openbox/autostart.sh` #### rc.xml `cp /etc/xdg/openbox/rc.xml ~/.config/openbox/` We want the VLC gui launching fullscreen, with no window decoration. In openbox's [](http://openbox.org/wiki/Help:Applications) section of '~/.config/openbox/rc.xml', l.656, add: ```markup no yes ``` ## Troubleshooting ### Udev rules You can increase udev's log verbosity with `sudo udevadm control --log-priority=debug` then run `journalctl -f` to see if an error message comes up when plugging/unplugging the USB HID. ### Xserver You can see what's going on by launching `journalctl -f` in a SSH session, then plug/unplug the USB HID. If you encounter an error with the X server complaining about permission to tty7 like this ``` (EE) xf86OpenConsole: Cannot open virtual console 7 (Permission denied) ``` try rebooting. ### Slow mouse cursor If you experience laggy mouse cursor movements, you can try adding `usbhid.mousepoll=0` to '/boot/cmdline.txt'. Other values you might want to try are : | value | speed | | :-: | :-: | | 0 | device request | | X | 1000/X Hz | source: [https://peppe8o.com/fixing-slow-mouse-with-raspberry-pi-os/](https://peppe8o.com/fixing-slow-mouse-with-raspberry-pi-os/) ## Systemd unit : run unit every X seconds with timer /etc/systemd/system/nvlc.service /etc/systemd/system/nvlc.timer In '.config/systemd/user/nvlc.service' : ``` [Unit] Description=VLC Ncurse UI service [Service] Type=oneshot #User=pil WorkingDirectory=/home/pil/ ExecStart=/home/pil/vlc_gui.sh #ExecStart=/usr/bin/nvlc -I ncurses --no-osd --file-caching=5000 [Install] WantedBy=default.target ``` In '.config/systemd/user/nvlc.timer' : ```[Unit] Description=NVLC test [Timer] OnUnitActiveSec=10s OnBootSec=10s [Install] WantedBy=timers.target ``` then to start timer : ``` systemctl --user start nvlc.timer ``` list timers : ``` systemctl --user list-timers --all ``` ## Timedate To sync time/date , add dns to '/etc/resolv.conf', then ``` sudo timedatectl ``` systemd unit : ``` systemctl status systemd-timesyncd ```