pilpil-setup/prepa_rpios.md

26 KiB

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/)
  4. 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
}
  1. Insérer la carte dans le RPI et démarrer le système.
  2. Se connecter via SSH.
  3. 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

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 <type>

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
  1. Install python deps :
pip install flask waitress toml
  1. 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 :

		<script type="text/javascript" src="./js/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
		<script type="text/javascript" src="./js/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"></script>

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 :

			$.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 : /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 :
    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

pl_move : Usage

Sample playlist :

<leaf duration="8"   id="3"  ro="rw" uri="file:///home/pi/sangliers_1080.mp4" name="sangliers_1080.mp4"/>
<leaf duration="23"  id="4"  ro="rw" uri="file:///home/pi/tst1.mp4" name="tst1.mp4"/>
<leaf duration="227" id="5"  ro="rw" uri="file:///home/pi/tst.mp4" name="tst.mp4"/>
<leaf duration="8"   id="6"  ro="rw" uri="file:///home/pi/sangliers_1080.mp4" name="sangliers_1080.mp4"/>
<leaf duration="23"  id="7"  ro="rw" uri="file:///home/pi/tst1.mp4" name="tst1.mp4"/>
<leaf duration="227" id="8"  ro="rw" uri="file:///home/pi/tst.mp4" name="tst.mp4"/>
# Move id 3 after id 5
10.42.0.135:8080/requests/status.xml?command=pl_move&id=3&val=5
<node name="Playlist" ro="ro" id="1">
    <leaf duration="23" id="4" ro="rw" uri="file:///home/pi/tst1.mp4" name="tst1.mp4"/>
    <leaf duration="227" id="5" ro="rw" uri="file:///home/pi/tst.mp4" name="tst.mp4"/>
    <leaf duration="8" id="3" ro="rw" uri="file:///home/pi/sangliers_1080.mp4" name="sangliers_1080.mp4"/>
    <leaf duration="8" id="6" ro="rw" uri="file:///home/pi/sangliers_1080.mp4" name="sangliers_1080.mp4"/>
    <leaf duration="23" id="7" ro="rw" uri="file:///home/pi/tst1.mp4" name="tst1.mp4"/>
    <leaf duration="227" id="8" ro="rw" uri="file:///home/pi/tst.mp4" name="tst.mp4"/>
</node>
# 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' :

#!/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

#!/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 (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 rules are triggered when the USB device is plugged/unplugged to create a file in '/tmp' named '.vlc_gui'.
  2. A systemd user service starts a script on startup.
  3. This script uses inotifywait to monitor a file's creation/deletion in the '/tmp' folder, and act accordingly;
  4. Start/close a minimal graphical environment with openbox running VLC.

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 ":=" for "MODE"; it makes shure this won't be changed by another rule.

Udev rules order read

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 in '~/.config/systemd/user/', e.g :

nano ~/.config/systemd/user/vlc_gui.service

[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

Starting a user unit as root

If running systemd version >= 248 (2021-03), you can start a user unit as root, 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' :

#!/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" :

#!/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' :

#!/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 <applications> section of '~/.config/openbox/rc.xml', l.656, add:

    <application name="vlc" role="vlc-main">
        <decor>no</decor>
        <maximized>yes</maximized>
    </application>

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/

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' :

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