# Управление яркостью внешнего монитора через Waybar (DDC/CI)

## Что в итоге

— яркость отображается в Waybar (%)
— колесо мыши меняет яркость с шагом 2%
— UI обновляется мгновенно
— реальные команды в монитор идут аккуратно (без лагов и ошибок)
— всё работает без sudo

---

# 1. Установка

```bash
sudo apt-get install ddcutil
```

---

# 2. Доступ к I²C (чтобы не нужен был sudo)

```bash
sudo groupadd i2c
sudo usermod -aG i2c $USER
```

udev правило:

```bash
sudo vim /etc/udev/rules.d/45-i2c.rules
```

```
KERNEL=="i2c-[0-9]*", GROUP="i2c", MODE="0660"
```

Применить:

```bash
sudo udevadm control --reload-rules
sudo udevadm trigger
```

Перелогиниться.

Проверка:

```bash
ls -l /dev/i2c-*
```

Должно быть `root i2c`.

---

# 3. Структура скриптов

```bash
~/.config/waybar/scripts/
```

Создать папку:

```bash
mkdir -p ~/.config/waybar/scripts
```

---

# 4. brightness-get.sh (для Waybar)

```bash
#!/bin/bash

state="$HOME/.cache/brightness-state"
[ -f "$state" ] || echo 50 > "$state"

val=$(cat "$state" 2>/dev/null)
echo "{\"text\":\"${val}%\",\"percentage\":$val}"
```

---

# 5. brightness-set.sh (обработка scroll)

```bash
#!/bin/bash

step=2
state="$HOME/.cache/brightness-state"
target="$HOME/.cache/brightness-target"
lock="/tmp/brightness-ui.lock"

mkdir -p "$HOME/.cache"
[ -f "$state" ] || echo 50 > "$state"

exec 9>"$lock"
flock -x 9

current=$(cat "$state")
case "$current" in ''|*[!0-9]*) current=50 ;; esac

case "$1" in
  up)   new=$((current + step)) ;;
  down) new=$((current - step)) ;;
  *) exit 1 ;;
esac

[ "$new" -gt 100 ] && new=100
[ "$new" -lt 0 ] && new=0

echo "$new" > "$state"
echo "$new" > "$target"

pkill -RTMIN+8 waybar >/dev/null 2>&1
```

---

# 6. brightness-worker.sh (реальная установка)

```bash
#!/bin/bash

target="$HOME/.cache/brightness-target"
sent="$HOME/.cache/brightness-sent"
lock="/tmp/ddcutil.lock"

mkdir -p "$HOME/.cache"
[ -f "$target" ] || echo 50 > "$target"
[ -f "$sent" ] || echo -1 > "$sent"

while true; do
  want=$(cat "$target")
  last=$(cat "$sent")

  case "$want" in ''|*[!0-9]*) sleep 0.15; continue ;; esac
  case "$last" in ''|*[^0-9-]*) last=-1 ;; esac

  if [ "$want" != "$last" ]; then
    if flock -w 2 8; then
      if ddcutil setvcp 10 "$want" >/dev/null 2>&1; then
        echo "$want" > "$sent"
      fi
    fi 8>"$lock"
  fi

  sleep 0.15
done
```

---

# 7. brightness-init.sh (синхронизация при старте)

```bash
#!/bin/bash

val=$(ddcutil getvcp 10 2>/dev/null | sed -n 's/.*current value = *\([0-9]\+\).*/\1/p')
[ -n "$val" ] || val=50

mkdir -p "$HOME/.cache"
echo "$val" > "$HOME/.cache/brightness-state"
echo "$val" > "$HOME/.cache/brightness-target"
echo "$val" > "$HOME/.cache/brightness-sent"

pkill -RTMIN+8 waybar >/dev/null 2>&1
```

---

# 8. Права

```bash
chmod +x ~/.config/waybar/scripts/*
```

---

# 9. Конфиг Waybar

Добавить модуль:

```json
"custom/brightness": {
  "exec": "/home/axawys/.config/waybar/scripts/brightness-get.sh",
  "return-type": "json",
  "signal": 8,
  "exec-on-event": true,
  "smooth-scrolling-threshold": 0.5,
  "on-scroll-up": "/home/axawys/.config/waybar/scripts/brightness-set.sh up",
  "on-scroll-down": "/home/axawys/.config/waybar/scripts/brightness-set.sh down"
}
```

И в `modules-right`:

```json
"custom/brightness",
```

---

# 10. systemd user service (воркер)

```bash
mkdir -p ~/.config/systemd/user
nvim ~/.config/systemd/user/brightness-worker.service
```

```ini
[Unit]
Description=Brightness worker for ddcutil

[Service]
ExecStart=/home/axawys/.config/waybar/scripts/brightness-worker.sh
Restart=always
RestartSec=1

[Install]
WantedBy=default.target
```

Запуск:

```bash
systemctl --user daemon-reload
systemctl --user enable --now brightness-worker.service
```

---

# 11. niri автозапуск

```kdl
spawn-sh-at-startup "~/.config/waybar/scripts/brightness-init.sh"
spawn-at-startup "waybar"
```

---

# Архитектура (ключевая идея)

— Waybar читает **локальное состояние**
— scroll → мгновенно меняет UI
— worker → асинхронно применяет в монитор
— ddcutil не перегружается

---

# Результат

— плавный UX
— нет ошибок `ddcutil`
— нет лагов
— корректная архитектура под Wayland

