Integrationen
ioBroker einrichten
Ein lokales JavaScript sendet Heartbeat und normalisierte Objektzustände.
Voraussetzungen
- ioBroker mit JavaScript-Adapter ab Version 7.9.0
- HomePulse-Standort mit ioBroker-Integration
- Standort-ID und API-Key
Schritt für Schritt
- Erzeuge die ioBroker-Integration in HomePulse. Direkt danach wird der vollständige Connector mit eingesetzter Standort-ID und API-Key einmalig angezeigt.
- Erstelle im JavaScript-Adapter ein neues Skript und füge den gesamten Connector-Code ein.
- Die Standardkonfiguration überwacht Admin-Verbindung, Update-Status, letzte Update-Prüfung und nur die Anzahl aktiver Socket-Clients.
- Ergänze bei Bedarf bewusst ausgewählte Datenpunkte in additionalStates.
- Starte das Skript und prüfe die Logeinträge ohne Ausgabe des Keys.
- Kontrolliere Heartbeat und Geräte unter HomePulse.
Beispielkonfiguration
// HomePulse Connector für ioBroker JavaScript-Adapter
// Benötigt ioBroker JavaScript-Adapter >= 7.9.0 (native Funktion httpPost).
const HOMEPULSE_URL = 'https://www.homepulse.at';
const SITE_ID = 'DEINE-STANDORT-GUID';
const API_KEY = 'hp_live_DEIN_EINMALIGER_KEY';
const CONNECTOR_VERSION = '1.1.0';
const CONNECTOR_STARTED_AT = Date.now();
const isTrue = value => value === true || value === 'true';
const connectedClientCount = value => {
if (Array.isArray(value)) return value.length;
const match = String(value || '').match(/^\[(\d+)\]/);
return match ? Number(match[1]) : 0;
};
const standardStates = [
{
id: 'admin.0.info.connection',
name: 'ioBroker Admin HTTP-Server',
type: 'service',
critical: true,
status: value => isTrue(value) ? 'online' : 'offline',
diagnostic: value => isTrue(value) ? 'HTTP-Server gestartet' : 'HTTP-Server nicht gestartet'
},
{
id: 'admin.0.info.newUpdates',
name: 'ioBroker Adapter-Updates',
type: 'service',
critical: false,
status: value => isTrue(value) ? 'warning' : 'online',
diagnostic: value => isTrue(value) ? 'Neue Adapter-Updates verfügbar' : 'Keine neuen Adapter-Updates gemeldet'
},
{
id: 'admin.0.info.updatesNumber',
name: 'Verfügbare ioBroker Updates',
type: 'service',
critical: false,
status: value => Number(value || 0) > 0 ? 'warning' : 'online',
diagnostic: value => `${Number(value || 0)} verfügbare Updates`
},
{
id: 'admin.0.info.lastUpdateCheck',
name: 'Letzte ioBroker Update-Prüfung',
type: 'sensor',
critical: false,
status: value => value ? 'online' : 'unknown',
diagnostic: value => value ? `Letzte Prüfung: ${String(value)}` : 'Noch keine Update-Prüfung gemeldet'
},
{
id: 'admin.0.info.connected',
name: 'ioBroker Admin-Verbindungen',
type: 'service',
critical: false,
status: value => value !== null && value !== undefined ? 'online' : 'unknown',
diagnostic: value => `Aktive Socket-Clients: ${connectedClientCount(value)}`
}
];
// Hier nur bewusst ausgewählte Healthcheck-Datenpunkte ergänzen.
const additionalStates = [
// {
// id: 'zigbee.0.sensor_bedroom.available',
// name: 'Zigbee Sensor Schlafzimmer',
// type: 'sensor',
// critical: false,
// status: value => isTrue(value) ? 'online' : 'offline',
// diagnostic: value => isTrue(value) ? 'Erreichbar' : 'Nicht erreichbar'
// }
];
function sourceVersion() {
const adminObject = getObject('system.adapter.admin.0');
const adminVersion = adminObject && adminObject.common && adminObject.common.version;
return adminVersion ? `admin-${adminVersion} / connector-${CONNECTOR_VERSION}` : `connector-${CONNECTOR_VERSION}`;
}
function stateTimestamp(state) {
const timestamp = state && Number(state.ts);
return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : null;
}
function createItem(definition) {
const state = getState(definition.id);
if (!state) {
return {
externalId: definition.id,
name: definition.name,
type: definition.type,
status: 'unknown',
lastSeenUtc: null,
diagnostic: 'Datenpunkt in ioBroker nicht gefunden',
isCritical: definition.critical
};
}
return {
externalId: definition.id,
name: definition.name,
type: definition.type,
status: definition.status(state.val),
lastSeenUtc: stateTimestamp(state),
diagnostic: definition.diagnostic(state.val),
isCritical: definition.critical
};
}
async function post(path, body) {
return new Promise((resolve, reject) => {
httpPost(
`${HOMEPULSE_URL}/api/ingest/iobroker/${path}`,
body,
{
timeout: 15000,
headers: {
'Content-Type': 'application/json',
'X-HomePulse-Key': API_KEY,
'Idempotency-Key': `iob-${path}-${Date.now()}`
}
},
(error, response) => {
if (error) {
reject(new Error(`HomePulse ${path}: ${error.message || error}`));
return;
}
if (!response || response.statusCode < 200 || response.statusCode >= 300) {
reject(new Error(`HomePulse ${path}: HTTP ${response ? response.statusCode : 'ohne Antwort'}`));
return;
}
try {
const data = typeof response.data === 'string' ? JSON.parse(response.data) : response.data;
resolve(data || { status: 'accepted' });
} catch {
resolve({ status: 'accepted' });
}
}
);
});
}
async function heartbeat() {
return post('heartbeat', {
apiVersion: '2026-08-01',
siteId: SITE_ID,
source: 'iobroker',
sourceVersion: sourceVersion(),
sentAtUtc: new Date().toISOString(),
status: 'online',
uptimeSeconds: Math.floor((Date.now() - CONNECTOR_STARTED_AT) / 1000)
});
}
async function snapshot() {
const items = [...standardStates, ...additionalStates].map(createItem);
return post('snapshot', {
apiVersion: '2026-08-01',
siteId: SITE_ID,
source: 'iobroker',
sourceVersion: sourceVersion(),
sentAtUtc: new Date().toISOString(),
eventId: `iob-snapshot-${Date.now()}`,
isFullSnapshot: true,
items
});
}
async function run(label, action) {
try {
const result = await action();
log(`HomePulse ${label}: ${result && result.status ? result.status : 'accepted'}`, 'info');
} catch (error) {
log(`HomePulse ${label} fehlgeschlagen: ${error.message}`, 'error');
}
}
schedule('*/1 * * * *', () => run('Heartbeat', heartbeat));
schedule('*/5 * * * *', () => run('Snapshot', snapshot));
run('Heartbeat', heartbeat);
run('Snapshot', snapshot);
Testschritt
Skript manuell starten und im ioBroker-Log ausschließlich HTTP-Status/Fehlercode kontrollieren.
Erwartetes Ergebnis
Heartbeat erscheint binnen einer Minute; die ausgewählten Zustände erscheinen unter Geräte & Entitäten.
Fehlerbehebung
- httpPost fehlt: JavaScript-Adapter auf mindestens Version 7.9.0 aktualisieren.
- 403/401: API-Key und Integration prüfen; bei einem offengelegten Key zuerst rotieren.
- Falscher Status: Mapping im items-Block an die Bedeutung des Datenpunkts anpassen.
Sicherheitshinweise
- Das Skript und den darin enthaltenen API-Key nur für Administratoren zugänglich machen.
- newsFeed, updatesList und Namen verbundener Admin-Clients werden aus Gründen der Datenminimierung nicht übertragen.
- Keine kompletten Objektbäume oder personenbezogenen Werte übertragen.
- Skriptlogs dürfen Header und Body mit Key nicht ausgeben.