Files
public-scripts/ioBroker-Skripte/AWTRIX Now Playing Sonos/ioBroker_awtrix_sonos_NowPlaying.js

154 lines
4.4 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.2
* Autor: Mike
* Zweck: Zeigt "🎵 Künstler — Titel (Album)" auf der AWTRIX
* Trigger: Änderungen an Sonos-Datenpunkten (Titel/Artist/Album/State)
******************************************************/
/*********** 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",
stateSimple: "sonos.0.root.192_168_178_75.state_simple" // true = spielt, false = kein Playback
};
/*************************************/
/*********** Helpers ***********/
function readVal(id) {
const st = getState(id);
return st ? (st.val ?? "") : "";
}
function readBool(id) {
const st = getState(id);
return st ? !!st.val : false;
}
function isPlaying() {
// state_simple ist bereits Boolean: true = Wiedergabe
return readBool(DP.stateSimple);
}
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) {
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 (kein Playback)");
}
/*********** 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 UND Playback aktiv
keepAliveTmr = setInterval(() => {
const t = String(readVal(DP.title)).trim();
const playing = isPlaying();
// Wenn kein Titel oder nicht mehr playing → sofort stoppen und App entfernen
if (!t || !playing) {
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();
const playing = isPlaying();
// Kein Lied ODER Player nicht im Play-Status → alles aus
if ((!title && !artist && !album) || !playing) {
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);
}
}
/*********** Trigger & Initiallauf ***********/
function scheduleUpdate() {
if (debounceTmr) clearTimeout(debounceTmr);
debounceTmr = setTimeout(updateAwtrix, 200);
}
// Triggert jetzt auch auf state_simple
on({ id: [DP.title, DP.artist, DP.album, DP.stateSimple], change: "ne" }, scheduleUpdate);
// Beim Start einmal versuchen
setTimeout(updateAwtrix, 1500);