Retour aux mises à jour
New releaseJul 14, 2026

phone-deck v3.0.1

Console de contrôle auto-hébergée et bureau à distance pour postes de travail Linux via Tailscale, avec streaming WebRTC, contrôle vocal avec LLM local, macros de scène, entrée virtuelle, transfert de fichiers et télémétrie système en direct.

Partager

phone-deck

Transformez un téléphone Android de rechange (ou tout appareil avec un navigateur) en un panneau de contrôle auto-hébergé et en bureau à distance pour votre station de travail Linux — via votre réseau privé Tailscale, sans applications tierces.

Tout a commencé par « que faire d'un vieux téléphone ? » et est devenu un plan de contrôle pour une configuration Hyprland : contrôle des fenêtres/espaces de travail, macros de scène, routeur vocal push-to-talk avec un assistant LLM local, contrôles contextuels dans l'application, streaming audio + écran bidirectionnel, un bureau à distance tactile, un clavier/souris virtuel, transfert de fichiers + partage téléphone→PC, et télémétrie en direct — le tout servi comme une PWA installée avec un aspect terminal phosphor.

Note sur la portabilité. Ceci a été construit pour une configuration spécifique : Linux basé sur Arch (Garuda) + Hyprland + PipeWire + NVIDIA + Tailscale, avec les dotfiles end-4 / illogical-impulse. L'architecture est générique, mais plusieurs intégrations sont spécifiques à l'environnement (noms de moniteurs, liaisons d'espaces de travail, chemin du thème matugen, cpupower/nvidia-smi). Considérez-le comme une référence de travail à adapter, pas un package clé en main.


Fonctionnalités

L'UI est une application web sombre, paysage, à onglets (synchronisée avec le thème de votre bureau) :

OngletCe qu'il fait
EspacesGrille d'espaces de travail en direct par écran (taper pour changer), liste des fenêtres en direct (taper pour focaliser), bascule DPMS par écran + luminosité ddcutil
DistantPavé tactile à l'écran (glisser/taper/deux doigts) + clavier virtuel avec modificateurs et combinaisons, via un périphérique uinput du noyau
ModesMacros de scène en un tap — lancer/fermer/agencer des dispositions d'applications complètes sur plusieurs écrans (ex. « Travail » / « Loisirs »)
VoixRouteur vocal push-to-talk (faster-whisper, CPU) : voies de mot-clé — macro (exécuter un mode/une commande), type (dicter), input (phrase → combinaison de touches) — avec confirmation avant exécution, plus « friday », un répondeur LLM local en lecture seule (Ollama + Qwen) avec recherche web auto-hébergée et connaissance de l'état système en direct
AudioSourdine micro/haut-parleur, volume, sélecteurs de périphériques de sortie et d'entrée, transport playerctl + couverture d'album (suit le lecteur MPRIS actif)
StreamAudio WebRTC bidirectionnel (PC↔téléphone, avec micro du téléphone et sortie téléphone uniquement) + vidéo d'écran, et taper pour contrôler l'écran streamé = un véritable bureau à distance
SystèmeBascule du mode de performance, changement de thème en direct, statut Tailscale, principaux processus (taper pour tuer), verrouillage, redémarrage de NetworkManager, mise en veille/redémarrage/extinction
FichiersCapture d'écran d'un moniteur → visualisation/téléchargement sur le téléphone ; déposer un fichier téléphone→PC
ConfigModifier la configuration commands.json / modes.json (et voix/contexte) depuis le téléphone (validé JSON)

Toujours présent, au-dessus des onglets — une bande contextuelle qui affiche ce qui se passe en ce moment : un appel actif (sourdine / aller à), média en cours de lecture + transport, et contrôles de clavier dans l'application pour l'application focalisée (YouTube / Brave / Teams), fournis sans voler le focus.

Deux autres, au-delà des onglets :

  • Envoyer au Rig — la PWA s'enregistre comme cible de partage Android : partagez une image, du texte ou un lien depuis n'importe quelle application de votre téléphone et ils atterrissent sur le rig — les images sauvegardées dans un répertoire drop et placées dans le presse-papier sous forme de PNG prêt à coller, le texte dans le presse-papier, un lien nu ouvert.
  • Cogitateur Ambiant — après quelques minutes d'inactivité, le panneau devient un tableau de bord phosphor : télémétrie à cadran avec maintien de pic (« était-ce au maximum pendant mon absence ? »), horloge, lecture en cours.

Plus : connexion par code PIN numérique, verrouillage de l'écran, PWA plein écran paysage, et verrouillage par force brute sur la connexion.


Architecture

   téléphone / ordinateur portable (PWA navigateur)
            │  HTTPS + WSS  (Tailscale uniquement)
            ▼
   tailscale serve  ──►  Application web FastAPI   ── Socket Unix ──►  deckd
   (certificat TLS réel)       (exécutée en tant que votre utilisateur)   (noms d'actions)   (exécutée en tant que root)
                              │                                  │
              hyprctl · pactl · ddcutil · grim ·          liste d'autorisation fixe
              wf-recorder · uinput · WebRTC               de commandes privilégiées
                                                          (cpupower, nvidia-smi,
                                                           systemctl, …)

Deux processus :

  • app/ — l'application web s'exécute en tant que votre utilisateur normal. Elle fait tout ce qui ne nécessite pas root : contrôle Hyprland, audio, luminosité, capture d'écran, entrée virtuelle, streaming WebRTC, transfert de fichiers.
  • deckd/ — un petit assistant root (stdlib uniquement, aucune dépendance) pour les quelques actions privilégiées. L'application web ne lui envoie jamais de chaînes shell — seulement des noms d'actions d'une liste d'autorisation fixe (governor_performance, gpu_power_limit, suspend, …), validée dans deckd/actions.py avant toute exécution. Même si l'application web était complètement compromise, le rayon d'impact est exactement les actions autorisées, sans injection d'arguments. Le socket est root:<groupe> mode 0660.

Modèle de sécurité

  • Accessible uniquement à l'intérieur de votre tailnet — tailscale serve l'expose sur votre nom MagicDNS avec un vrai certificat Let's Encrypt ; il ne se lie jamais à 0.0.0.0.
  • Connexion JWT (PIN → cookie signé), avec verrouillage à backoff exponentiel après échecs répétés.
  • Les actions privilégiées sont isolées derrière le démon assistant autorisé.
  • Les téléchargements sont nettoyés de leur nom de base (impossible de sortir du répertoire drop).

L'application web peut exécuter vos commandes shell configurées et injecter des entrées en tant que votre utilisateur — c'est, par conception, une télécommande pour votre machine. Gardez-la sur votre tailnet, derrière le PIN, et ne l'exposez pas publiquement.


Prérequis

  • Linux avec Hyprland (wlroots), PipeWire (avec compatibilité pactl/PulseAudio)
  • Python ≥ 3.11 et uv
  • Tailscale (avec certificats HTTPS activés pour votre tailnet)
  • Outils CLI utilisés par diverses fonctionnalités (installez ce que vous voulez utiliser) : hyprctl, pactl / pw-record / pw-play, playerctl, ddcutil, wf-recorder, grim, cpupower, nvidia-smi, kitty (ou votre terminal)
  • Votre utilisateur dans le groupe input (pour /dev/uinput) et le groupe i2c (pour ddcutil)
  • aiortc + PyAV (installés via uv) pour le streaming audio/vidéo

Installation

git clone <votre-url-de-repo> phone-deck
cd phone-deck
uv sync                          # crée .venv et installe les dépendances
uv run python -m app.set_pin     # définissez votre PIN de déverrouillage

1. L'assistant root (deckd)

Modifiez systemd/deckd.service d'abord — définissez les chemins et DECK_SOCKET_GROUP à un groupe auquel votre utilisateur appartient (généralement votre groupe principal) :

sudo cp systemd/deckd.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now deckd

Catégories