Files
ambilight-plasmoid/README.md
T
enne2 47b5c09fa1 kmsgrab e ScreenShot2: esiti sperimentali documentati
- kmsgrab non praticabile: piano primario AR30 con modifier AMD DCC/tiled, ffmpeg
  rifiuta il framebuffer prima di applicare format/modifier
- KWin ScreenShot2: NoAuthorized anche con desktop entry system-wide
- indicatore del vassoio identificato come SNI di xdg-desktop-portal-kde
  (titolo 'Trasmissione dello schermo')
- backend kmsgrab comunque implementato e selezionabile (capture=kmsgrab)
- setup-kmsgrab.sh: installa via pkexec una copia di ffmpeg con cap_sys_admin+ep
2026-11-01 13:22:03 +01:00

160 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ambilight-plasmoid
Ambilight per KDE Plasma 6: cattura il bordo superiore dello schermo su **Wayland**
(portal ScreenCast + PipeWire), calcola il colore medio di 47 zone e pilota una
striscia **WS2812B** collegata a un **ESP8266 (Wemos D1 mini)** con firmware
**Adalight** via seriale. Il controllo sta in un **plasmoide nel vassoio di sistema**,
con popup per luminosità, contrasto, saturazione e banda campionata.
```
schermo ──portal──▶ ambilightd ──Adalight/seriale──▶ ESP8266 ──▶ striscia
▲
│ D-Bus org.enne2.Ambilight
│
ambilight-ctl ◀── plasmoide (Plasma 6, QML)
```
## Componenti
| File | Ruolo |
|---|---|
| `backend/ambicapture.py` | negoziazione ScreenCast portal + pipeline GStreamer (`pipewiresrc`) |
| `backend/ambilightd.py` | demone: cattura, calcolo zone, luminosità/contrasto/saturazione, invio Adalight, servizio D-Bus |
| `backend/ambilight-ctl` | CLI che parla col demone e stampa JSON (usata dal plasmoide) |
| `backend/ambilight.service` | unit `systemd --user` (avvio automatico al login) |
| `package/org.enne2.ambilight/` | plasmoide Plasma 6 (icona nel vassoio + popup con slider) |
| `install.sh` / `uninstall.sh` | installazione e rimozione, senza root |
## Hardware
- ESP8266 Wemos D1 mini (clone), firmware **Adalight-FastLED** con `PIN_DATA 5` (= D1/GPIO5),
`Num_Leds` = dimensione buffer (256): il numero reale di LED lo decide il software che invia i frame.
- Striscia WS2812B **47 LED** sul solo bordo superiore.
- Cablaggio: `D1 → 470 Ω → DIN`, alimentatore 5 V separato (~60 mA/LED), **massa comune**,
1000 µF sull'alimentazione; level shifter 74AHCT125 se il filo dati è lungo.
## Installazione
```sh
./install.sh # backend + servizio utente + plasmoide
```
Al primo avvio il desktop chiede il permesso di **condividere lo schermo**: va concesso
una volta (viene memorizzato in `~/.cache/ambilight/restore_token`).
Il plasmoide appare nel vassoio come **Ambilight** (icona TV); clic per il popup.
## Uso da terminale
```sh
ambilight-ctl state # JSON con tutto lo stato
ambilight-ctl start | stop | toggle
ambilight-ctl set brightness 0.8 # brightness|contrast|saturation|band|reverse|leds
ambilight-ctl get fps
systemctl --user status ambilight.service
```
## Configurazione
`~/.config/ambilight/config.json` (scritto dal demone a ogni modifica):
| chiave | range | default | note |
|---|---|---|---|
| `brightness` | 0.05 – 2.0 | 1.0 | moltiplicatore |
| `contrast` | 0.5 – 2.0 | 1.0 | pivot sul grigio 128 |
| `saturation` | 0.0 – 2.0 | 1.0 | 0 = bianco e nero |
| `band` | 0.02 – 0.5 | 0.12 | frazione di altezza campionata |
| `reverse` | bool | true | LED 0 sul lato destro (verificato a schermo) |
| `leds` | 1 – 256 | 47 | LED della striscia |
| `port`, `baud` | – | `/dev/ttyUSB0`, 115200 | seriale |
| `side` | top/bottom | top | bordo campionato |
| `auto_start` | bool | true | streaming attivo all'avvio del demone |
## Prestazioni misurate
- 47 LED, Adalight a 115200: ~**78 fps** (limite teorico della seriale per 147 byte/frame).
- Cattura: portal + PipeWire, pipeline ridotta a `47×4 × 72` px RGB → costo CPU trascurabile.
## Nome stabile del dispositivo seriale
La scheda (CH340, `1a86:7523`) **non espone un iSerial**: verificato con
`cat /sys/bus/usb/devices/1-2/serial` → vuoto. Di conseguenza:
| percorso | valore su questa macchina | unico? |
|---|---|---|
| `/dev/ttyUSB0` | assegnato in ordine di enumerazione | no |
| `/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0` | derivato da `ID_SERIAL=1a86_USB_Serial` | **no** (due cloni identici collidono) |
| `/dev/serial/by-path/pci-0000:65:00.3-usb-0:2:1.0-port0` | legato alla porta USB fisica | sì |
| `/dev/ambilight` (regola udev) | symlink creato da noi | sì |
> **Su questa macchina la regola NON è installata**: scelta esplicita dell'utente di
> lasciare `ttyUSB0` come assegnato dal kernel. I file restano nel repo come opzione.
Installa la regola (richiede sudo, una volta):
```sh
sudo ./setup-udev.sh /dev/ttyUSB0 # rileva la porta fisica e scrive /etc/udev/rules.d/99-ambilight.rules
ambilight-ctl set port /dev/ambilight
systemctl --user restart ambilight.service
```
La regola aggancia `KERNELS=="<porta>"` + VID/PID (non il numero `ttyUSB`), crea
`/dev/ambilight`, aggiunge `ID_MM_DEVICE_IGNORE` (ModemManager smette di sondare la
porta) e `TAG+="uaccess"` (accesso ACL all'utente attivo). Se sposti la scheda su
un'altra porta USB il nome non segue: rilancia `setup-udev.sh`.
Il demone comunque ripiega su `/dev/ambilight` e poi `/dev/ttyUSB0` se il percorso
configurato non esiste, e riporta il dispositivo realmente aperto nel campo `dev`
di `ambilight-ctl state`.
## L'indicatore di condivisione schermo nel vassoio
Con la cattura via **portal ScreenCast**, KDE mostra nel vassoio un **pallino rosso**
finché la sessione di condivisione è attiva. Verificato su questa macchina:
- compare/scompare insieme allo streaming (diff di due screenshot: cambia solo quella
regione del vassoio, ~1.500 px in 172x22);
- **non** è un plasmoide di sistema (`/usr/share/plasma/plasmoids` non contiene nulla
di simile) e **non** compare in `knownItems`/`extraItems` del vassoio, quindi non
esiste la voce "Configure System Tray → Entries" per nasconderlo: è un indicatore
di stato del shell, per scelta di KDE.
**Il pallino è uno StatusNotifierItem pubblicato da `xdg-desktop-portal-kde`** (titolo
"Trasmissione dello schermo"): quindi è un elemento del vassoio con visibilità
configurabile da *Configura il vassoio di sistema → Voci* (impostandolo su "Sempre
nascosto" sparisce dal pannello e resta nel popup espanso).
Le alternative per non averlo:
1. **KWin ScreenShot2** (nessun portal, nessun indicatore) — **rifiutato su questa
macchina**: testato sia con `.desktop` utente sia con entry system-wide in
`/usr/local/share/applications` (`Exec=/usr/bin/python3`, `X-KDE-DBUS-Restricted-Interfaces=org.kde.KWin.ScreenShot2`,
`kbuildsycoca6`): la risposta resta `org.kde.KWin.ScreenShot2.Error.NoAuthorized`. KWin autorizza solo i
processi con un `.desktop` che dichiara `X-KDE-DBUS-Restricted-Interfaces=org.kde.KWin.ScreenShot2`.
Provato con un `.desktop` utente (`Exec=/usr/bin/python3` e `python3.14`) + `kbuildsycoca6`:
risponde ancora `org.kde.KWin.ScreenShot2.Error.NoAuthorized`. Non provato l'entry
in `/usr/local/share/applications` (richiede sudo). Se funziona, la cattura è un
`CaptureArea` della sola fascia (nessun indicatore, ma costo CPU per frame).
2. **kmsgrab** (`ffmpeg -f kmsgrab`) con `CAP_SYS_ADMIN`: **provato e non praticabile su
questa macchina** (Radeon 780M + KWin). Il piano primario è `plane-3` (id 206),
`crtc-0`, `fb=463`, `format=AR30` (`0x30335241`) con `modifier=0x200000010437b04`
(AMD DCC/tiled): ffmpeg risponde `Framebuffer pixel format 30335241 is not a known
supported format` e fallisce **prima** di applicare `-format`/`-format_modifier`
(provati `bgr0`, `rgb0`, `0rgb`, `bgra`, `x2rgb10le`, `-format_modifier 0`,
`-plane_id 206`). Anche superando il controllo, il layout tiled/DCC richiederebbe
un import GBM/EGL o VAAPI, che kmsgrab non fa.
3. Tenere il portal: costo GPU minimo, ~78 fps, indicatore visibile.
## Note
- Il firmware Adalight manda `Ada\n` una volta al secondo quando non riceve frame: è
l'heartbeat del protocollo, non un errore.
- Il demone tiene la seriale in esclusiva: Prismatik (o altri programmi Adalight) vanno chiusi.
- `ModemManager` su Fedora può contendere `/dev/ttyUSB0`: se la porta risulta occupata
serve una regola udev con `ID_MM_DEVICE_IGNORE`.
## Licenza
GPL-3.0-or-later (come i componenti KDE con cui interagisce).