Files
public-scripts/ioBroker-Skripte/AWTRIX Now Playing Sonos/ioBroker_awtrix_sonos_NowPlaying.js
2025-10-27 12:27:16 +01:00

140 lines
4.0 KiB
JavaScript
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.
/******************************************************
* AWTRIX NowPlaying Sonos → AWTRIX Custom App
* Version 0.0.1
* Autor: Mike
* Zweck: Zeigt "🎵 Künstler — Titel (Album)" auf der AWTRIX
* Trigger: Änderungen an Sonos-Datenpunkten (Titel/Artist/Album)
******************************************************/
/*********** Einstellungen ***********/
const MQTT_INSTANCE = "mqtt.0";
const AWTRIX_PREFIX = "awtrix"; // Dein Prefix
const APP_NAME = "NowPlaying";
const LIFETIME_SEC = 600; // Eintrag läuft ab, wenn kein Refresh kommt
const KEEPALIVE_SEC = 10; // alle x Sekunden Refresh solange Titel vorhanden
const FORCE_SWITCH = false; // bei jedem Refresh auf App schalten (falls viele Apps)
/* Anzeige */
const ICON_MUSIC = 29944;
const COLOR_RGB = [255, 255, 255];
const TEXT_CASE = 2;
/* Sonos-Datenpunkte (ggf. anpassen) */
const DP = {
title: "sonos.0.root.192_168_178_75.current_title",
artist: "sonos.0.root.192_168_178_75.current_artist",
album: "sonos.0.root.192_168_178_75.current_album"
};
/*************************************/
/*********** Helpers ***********/
function readVal(id) {
const st = getState(id);
return st ? (st.val ?? "") : "";
}
function buildText(artist, title, album) {
let base = "";
if (artist && title) base = `${artist}${title}`;
else if (title) base = title;
else if (artist) base = artist;
if (base && album) base += ` (${album})`;
if (!base) base = "—";
return `🎵 ${base}`;
}
function sendMQTT(topic, payloadObj) {
// ioBroker als Broker → sendMessage2Client
sendTo(MQTT_INSTANCE, "sendMessage2Client", {
topic,
message: JSON.stringify(payloadObj),
retain: false,
qos: 0
});
}
function publishCustom(text) {
const payload = {
name: APP_NAME,
text,
icon: ICON_MUSIC,
color: COLOR_RGB,
textCase: TEXT_CASE,
lifetime: LIFETIME_SEC
};
sendMQTT(`${AWTRIX_PREFIX}/custom/${APP_NAME}`, payload);
if (FORCE_SWITCH) sendMQTT(`${AWTRIX_PREFIX}/switch`, { name: APP_NAME });
}
function removeApp() {
sendMQTT(`${AWTRIX_PREFIX}/custom/${APP_NAME}`, { name: APP_NAME, lifetime: 1 });
log("🛑 NowPlaying entfernt (keine Titelinfos)");
}
/*********** Kernlogik ***********/
let currentSig = ""; // artist|title|album
let keepAliveTmr = null; // setInterval-Handle
let debounceTmr = null;
function stopKeepAlive() {
if (keepAliveTmr) {
clearInterval(keepAliveTmr);
keepAliveTmr = null;
}
}
function startKeepAlive(text) {
stopKeepAlive();
// Erster Push sofort (sichtbar machen) …
publishCustom(text);
// … und dann regelmäßig solange Titel vorhanden ist
keepAliveTmr = setInterval(() => {
// Wenn Titel leer geworden ist, sofort stoppen und App entfernen
const t = String(readVal(DP.title)).trim();
if (!t) {
stopKeepAlive();
currentSig = "";
removeApp();
return;
}
publishCustom(text);
}, KEEPALIVE_SEC * 1000);
}
function updateAwtrix() {
const title = String(readVal(DP.title)).trim();
const artist = String(readVal(DP.artist)).trim();
const album = String(readVal(DP.album)).trim();
// Kein Lied → alles aus
if (!title && !artist && !album) {
stopKeepAlive();
if (currentSig) removeApp();
currentSig = "";
return;
}
const text = buildText(artist, title, album);
const sig = `${artist}|${title}|${album}`;
// Neuer/anderer Track → Keep-Alive neu starten
if (sig !== currentSig) {
currentSig = sig;
log(`🎧 NowPlaying → ${text}`);
startKeepAlive(text);
} else {
// Gleicher Track: nichts weiter Keep-Alive tickt von selbst
}
}
/*********** Trigger & Initiallauf ***********/
function scheduleUpdate() {
if (debounceTmr) clearTimeout(debounceTmr);
debounceTmr = setTimeout(updateAwtrix, 200);
}
on({ id: [DP.title, DP.artist, DP.album], change: "ne" }, scheduleUpdate);
// Beim Start einmal versuchen
setTimeout(updateAwtrix, 1500);