@mcm1957 Das wäre super, wenn der alte Adapter neues Leben eingeflösst bekäme, aber ich weiß selbst wie wertvoll Zeit ist...
Ich habe mir vorübergehend, solange bis jemand mit Ahnung etwas besseres baut, folgendes Script gebaut:
// 🛠️ Konfiguration
const userPath = '0_userdata.0.Lokal.Statistics.PiHole';
const piholeUrl = 'https://MEINPIHOLE';
const password = 'AUS DER OBERFLÄCHE'; // App-Passwort, nicht GUI-Passwort
const debug = getState("0_userdata.0.Global.Debug")?.val || false;
const sillydebug = getState("0_userdata.0.Global.SillyDebug")?.val || false;
// 📊 Datenpunkte mit Beschreibung für den ioBroker
const datapoints = {
total: 'Anzahl aller angefragen Domains',
blocked: 'Zahl der blockierten Domains',
percent_blocked: 'Blockierte Domains in %',
unique_domains: 'Eindeutige Domains',
queries_forwarded: 'Weitergeleitete Anfragen',
queries_cached: 'Gecachte Anfragen',
};
// 🔁 Axios einbinden (funktioniert ab js-controller 3.x)
const axios = require('axios').default;
// Hilfsfunktion für Logs, gibt nur aus wenn SillyDebug=true ist
function debugLog(msg) {
const sillyDebug = getState('0_userdata.0.Global.SillyDebug')?.val || false;
if (sillyDebug) {
log(msg);
}
}
// Hauptfunktion: Authentifizieren, Daten holen und Datenpunkte schreiben
async function loginAndFetchPiHole() {
if (debug) console.log('🔐 Authentifiziere Pi-hole…');
try {
// Login an Pi-hole API, um Session-ID und CSRF-Token zu erhalten
const authResponse = await axios.post(
`${piholeUrl}/api/auth`,
{ password: password },
{ httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }) }
);
// Session-Daten extrahieren
const { sid, csrf } = authResponse.data.session || {};
if (!sid || !csrf) throw new Error('SID oder CSRF fehlt in Antwort');
if (debug) console.log('✅ Authentifizierung erfolgreich');
// Zusammenfassung der Pi-hole Statistiken abfragen
const summaryResponse = await axios.get(
`${piholeUrl}/api/stats/summary`,
{
headers: {
Cookie: `sid=${sid}`,
'x-csrf-token': csrf
},
httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }),
}
);
const data = summaryResponse.data;
debugLog('Pi-hole API Rohdaten: ' + JSON.stringify(data));
// Datenpunkte erstellen und mit Werten aus Pi-hole füllen
for (const key in datapoints) {
const dp = `${userPath}.${key}`;
await createStateAsync(dp, 0, { name: datapoints[key], type: 'number', read: true, write: false });
// Wert je Datenpunkt aus der API Antwort zuordnen
let value = 0;
switch (key) {
case 'total': value = data.queries.total; break;
case 'blocked': value = data.queries.blocked; break;
case 'percent_blocked': value = Math.round(data.queries.percent_blocked); break;
case 'unique_domains': value = data.queries.unique_domains; break;
case 'queries_forwarded': value = data.queries.forwarded; break;
case 'queries_cached': value = data.queries.cached; break;
default: value = 666;
}
debugLog(`${dp}: ${value}`);
setState(dp, value || 0, true);
}
if (debug) console.log('✅ Pi-hole Daten aktualisiert');
} catch (err) {
log('❌ Fehler bei Pi-hole API Zugriff: ' + err.message, 'error');
}
}
// ⏰ Intervall: alle 5 Minuten ausführen
schedule('*/5 * * * *', loginAndFetchPiHole);
// Direkt beim Start einmal ausführen
loginAndFetchPiHole();
Ich will hier keine Grundsatzdiskussion über Arten der Programmierung oder gar die Adapterentwicklung in Frage stellen. Das Script läuft bei mir, wenn es jemanden hilft, gut, wenn nicht, auch gut.
CU