Files
ambilight-plasmoid/README.md
T
enne2 db47640846 Nome stabile della seriale via udev e note sull'indicatore di cattura
- udev/99-ambilight.rules: symlink /dev/ambilight ancorato alla porta USB fisica
  (il CH340 clone non ha iSerial, quindi by-id non e' univoco), ID_MM_DEVICE_IGNORE,
  TAG+=uaccess
- setup-udev.sh: rileva VID/PID/porta, installa la regola, verifica il symlink
- backend: fallback di porta (config -> /dev/ambilight -> /dev/ttyUSB0) e campo 'dev'
  nello stato D-Bus
- README: tabella dei percorsi, prove sull'indicatore di condivisione schermo e le
  tre alternative (portal, KWin ScreenShot2, kmsgrab)
2026-11-01 13:16:08 +01:00

144 lines
6.5 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ì |
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.
Le alternative per non averlo:
1. **KWin ScreenShot2** (nessun portal, nessun indicatore): 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`) da un servizio privilegiato con `CAP_SYS_ADMIN`:
nessun portal e nessun indicatore, ma cattura DRM grezza (piano/format legati alla
GPU) e un servizio di sistema: più fragile.
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).