diff --git a/AGENTS.md b/AGENTS.md index faf9a81..802bec9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,6 +10,7 @@ This repo is a single Python script (`luz-musica.py`) that: - System dependency: `playerctl` must be installed and your player must expose MPRIS metadata. - Python deps: `requests`, `Pillow`. - Run: `python3 luz-musica.py` +- Service install: `make install-service` creates and starts a `systemd --user` unit on Ubuntu. ## Dependencies @@ -27,6 +28,12 @@ Create a venv and install Python deps: Then run: - `python luz-musica.py` +## Ubuntu service +- The service is installed as `~/.config/systemd/user/music-light.service`. +- The service loads optional environment overrides from `~/.config/music-light/env`. +- Use `make status-service`, `make logs-service`, `make restart-service`, and `make uninstall-service`. +- Keep it as a user service because `playerctl` needs access to the logged-in desktop user's MPRIS session. + ## Configuration Edit constants at the top of `luz-musica.py`: - `HA_URL`, `HA_TOKEN`, `LIGHT_ENTITY` diff --git a/Makefile b/Makefile index 06c8d4f..cddf710 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,12 @@ PY ?= python3 VENV ?= .venv +SERVICE_NAME ?= music-light.service +SYSTEMD_USER_DIR ?= $(HOME)/.config/systemd/user +SERVICE_FILE := $(SYSTEMD_USER_DIR)/$(SERVICE_NAME) +CONFIG_DIR ?= $(HOME)/.config/music-light +ENV_FILE ?= $(CONFIG_DIR)/env -.PHONY: venv deps run +.PHONY: venv deps run service-env install-service uninstall-service start-service stop-service restart-service status-service logs-service venv: $(PY) -m venv $(VENV) @@ -13,3 +18,32 @@ deps: venv run: deps $(VENV)/bin/python luz-musica.py +service-env: + install -d $(CONFIG_DIR) + test -f $(ENV_FILE) || install -m 600 music-light.env.example $(ENV_FILE) + +install-service: deps service-env + install -d $(SYSTEMD_USER_DIR) + printf '%s\n' '[Unit]' 'Description=Music Light album-art color sync' 'After=graphical-session.target' 'Wants=graphical-session.target' '' '[Service]' 'Type=simple' 'WorkingDirectory=$(CURDIR)' 'Environment=PYTHONUNBUFFERED=1' 'Environment=PLAYERCTL_BIN=/usr/bin/playerctl' 'EnvironmentFile=-%h/.config/music-light/env' 'ExecStart=$(abspath $(VENV))/bin/python $(CURDIR)/luz-musica.py' 'Restart=always' 'RestartSec=5' '' '[Install]' 'WantedBy=default.target' > $(SERVICE_FILE) + systemctl --user daemon-reload + systemctl --user enable --now $(SERVICE_NAME) + +uninstall-service: + systemctl --user disable --now $(SERVICE_NAME) || true + rm -f $(SERVICE_FILE) + systemctl --user daemon-reload + +start-service: + systemctl --user start $(SERVICE_NAME) + +stop-service: + systemctl --user stop $(SERVICE_NAME) + +restart-service: + systemctl --user restart $(SERVICE_NAME) + +status-service: + systemctl --user status $(SERVICE_NAME) + +logs-service: + journalctl --user -u $(SERVICE_NAME) -f diff --git a/README.md b/README.md index 66065ee..d732e26 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ pip install -r requirements.txt ## Configuration -Edit the constants at the top of `luz-musica.py`: +For local runs, edit the constants at the top of `luz-musica.py` or export environment variables: - `HA_URL` - `HA_TOKEN` @@ -56,8 +56,49 @@ Or use the Makefile: make run ``` +## Ubuntu User Service + +Install and start the script as a `systemd --user` service: + +```bash +make install-service +``` + +The install target: + +- creates `.venv` and installs `requirements.txt` +- copies `music-light.env.example` to `~/.config/music-light/env` if it does not exist +- writes `~/.config/systemd/user/music-light.service` +- enables and starts the service + +Edit the service environment file with your Home Assistant settings: + +```bash +nano ~/.config/music-light/env +make restart-service +``` + +Manage the service with: + +```bash +make status-service +make logs-service +make restart-service +make stop-service +make start-service +``` + +Remove the service: + +```bash +make uninstall-service +``` + +This is installed as a user service because `playerctl` needs access to the desktop user's MPRIS session. + ## Troubleshooting - If nothing is playing, or `playerctl` cannot read metadata, the loop sleeps and retries. - If `mpris:artUrl` is missing, the script logs it and waits for the next track change. - If Home Assistant is unreachable or returns an error, the script logs the exception and retries. +- If the service cannot see the media player, make sure it is running under the same logged-in desktop user. diff --git a/luz-musica.py b/luz-musica.py index e228651..93bf128 100644 --- a/luz-musica.py +++ b/luz-musica.py @@ -12,9 +12,12 @@ from urllib.parse import parse_qs, urlparse import requests from PIL import Image -HA_URL = "http://127.0.0.1:8123" -HA_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkZjM1MmRhNjg1ZWM0MGJiYTc4YTZlNWY3ZmQ0YTA1YSIsImlhdCI6MTc3NjI4MTI0MiwiZXhwIjoyMDkxNjQxMjQyfQ.rR0Kfwk5Smr06_9KJSDn3YPXiRlokEZZFiAa_naNs78" -LIGHT_ENTITY = "light.luzsala_luz_sala" +HA_URL = os.environ.get("HA_URL", "http://127.0.0.1:8123") +HA_TOKEN = os.environ.get( + "HA_TOKEN", + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkZjM1MmRhNjg1ZWM0MGJiYTc4YTZlNWY3ZmQ0YTA1YSIsImlhdCI6MTc3NjI4MTI0MiwiZXhwIjoyMDkxNjQxMjQyfQ.rR0Kfwk5Smr06_9KJSDn3YPXiRlokEZZFiAa_naNs78", +) +LIGHT_ENTITY = os.environ.get("LIGHT_ENTITY", "light.luzsala_luz_sala") # Ajustes visuais BRIGHTNESS_PCT = 70 diff --git a/music-light.env.example b/music-light.env.example new file mode 100644 index 0000000..2cef63e --- /dev/null +++ b/music-light.env.example @@ -0,0 +1,5 @@ +# Uncomment and edit these values to override the defaults from luz-musica.py. +# HA_URL=http://127.0.0.1:8123 +# HA_TOKEN=replace-with-your-home-assistant-token +# LIGHT_ENTITY=light.luzsala_luz_sala +# PLAYERCTL_BIN=/usr/bin/playerctl