TL;DR
In meinem Repository findet ihr ein kleines Beispiel, wie ihr Daten von der Homematic REST API abrufen könnt.
Verwendete Hardware
- Homematic Geräte
- Homematic IP WLAN Access Point
- Homematic IP Access Point (kabelgebunden)
- Homematic IP Set mit 3 Heizkörperthermostaten
- Homematic IP Steckdose
- Homematic IP Fensterkontakt
- Homematic IP Wandthermostat
Vorwort
Nutzt ihr für Homematic keine CCU und habt nur einen Access Point gibt es lediglich die Möglichkeit per App eure Umgebung zu steuern und Informationen anzuzueigen.
Diese App zieht sich jedoch auch nur die Informationen aus der Homematic Cloud. Ich zeige euch in diesem Beitrag, wie ihr euch an diesen Endpunkt verbinden könnt. Die Informationen, die ich über diesen Endpunkt erhalte zeige ich mir daheim auf einem Dashboard an. Es ist zum Beispiel möglich die IST-Temperatur von Heizungsthermostat (etrv-2) anzeigen zu lassen – dieses Feature bietet die Homematic APP leider nicht.
Anmelden an der Schnittstelle
Die Anmeldung erfolgt in 5 Schritten
- REST URL herausfinden
- Request eine Verbindung aufzubauen
- Blaue Taste auf dem Access Point drücken (Bestätigen des Requests)
- Access Token beantragen
- Access Token bestätigen
Nachdem diese Schritt ausgeführt wurden wird dieser Account in der Homematic App in der „Benutzerübersicht“ (Einstellungen -> Benutzerverwaltung -> Benutzerübersicht) angezeigt. Ich werde euch diesen Vorgang Schritt für Schritt zeigen. In meinem Repository ist alles in einem Prozess (installer.js) enthalten. Leider kann ich nicht genau sagen, wie viel Zeit ihr zwischen den Schritten habt bevor die Daten des letzten Schrittes von der Homematic API verworfen werden.
BITTE BEACHTET, DASS IDs UND ANDERE SENSITIVE DATEN ENTFERNT WERDEN. FÜR MEIN BEISPIEL NUTZE ICH DIE ACCESS POINT ID (SGTIN) 3014F211A000215BE9A5ABCD und PIN 1234. DIESE ENTSPRICHT NATÜRLICH NICHT MEINER RICHTIGEN ID.
REST URL herausfinden
Ich bin ebenfalls neu im dem Thema Homematic. Es scheint, als ob der Endpunkt je nach Kunde unterschiedlich ist. Nach Ausführungen des folgenden Codes sollte in der Console eure REST Url stehen.
const axios = require('axios');
const os = require('os');
//EDIT your settings!
const ID = "3014F211A000215BE9A5ABCD";
const LOOKUP_URL = "https://lookup.homematic.com:48335/getHost";
const LOOKUP_JSON = {
"clientCharacteristics": {
"apiVersion": "12",
"applicationIdentifier": "homematicip-python",
"applicationVersion": "1.0",
"deviceManufacturer": "none",
"deviceType": "Computer",
"language": "en",
"osType": os.type(),
"osVersion": os.release()
},
"id": ID
}
var main = (async () => {
//getting your rest url
console.log("Starting getting your rest url...")
var response = null;
try {
response = await axios.default.post(LOOKUP_URL, LOOKUP_JSON);
console.log(response.data.urlREST);
} catch (error) {
console.error("Something went wrong! Maybe your SGTIN is incorrect!");
console.error(error.response.data);
return;
}
})();
Antwort vom Server
{
"urlREST": "https://srz22.homematic.com:6969",
"urlWebSocket": "wss://srz22.homematic.com:8888",
"apiVersion": "12",
"primaryAccessPointId": "3014F211A000215BE9A5ABCD",
"requestingAccessPointId": "3014F211A000215BE9A5ABCD"
}
Connection Request abschicken
Im letzten Schritt haben wir den Endpunkt ermittelt. Diesen Endpunkt nutzten wir im weiteren Verlauf für unsere Requests. Als nächstes schicken wir einen Connection Request ab. Dieser dient lediglich dazu die Authorisierung zu starten. Im korrekten Fall bekommen wir lediglich einen Status Code 200 von der Schnittstelle zurück – kein Inhalt im Body oder Ähnliches.
Falls ihr einen Pin eingerichtet habt muss diese nun ebenfalls mitgeschickt werden. Weiterhin brauchen wir einen gehashten Wert der an Hand eurer SGTIN ermittelt wird. Bitte die REST_URL mit eurer Rest Url ersetzen!
Dieser Request generiert eine zufällige UUID. Diese brauchen wir für die nächsten Schritte ebenfalls. Kopiert euch die UUID aus der Console.
const axios = require('axios');
const crypto = require('crypto');
const HASH = crypto.createHash('sha512');
//EDIT your settings!
const ID = "xxx";
const PIN = "xxx";
const DEVICE_NAME = "my-api-user";
const REST_URL = "https://srz22.homematic.com:6969";
const UUID = crypto.randomUUID();
console.log("Used UUID=" + UUID);
const CLIENTAUTH = HASH.update(ID + 'jiLpVitHvWnIGD1yo7MA', 'utf-8').digest('hex').toUpperCase();
var data = { "deviceId": UUID, "deviceName": DEVICE_NAME, "sgtin": ID }
var headers = {
"content-type": "application/json",
"accept": "application/json",
"VERSION": "12",
"CLIENTAUTH": CLIENTAUTH,
"PIN": PIN
}
var main = (async () => {
console.log("Sending connection request ...");
try {
response = await axios.default.post(REST_URL + "/hmip/auth/connectionRequest", data, { headers: headers });
} catch (error) {
console.error(error);
return;
}
console.log("Connection request was successfully sent!");
})();
Connection Request bestätigen
Dieser Schritt dient der Bestätigung des Requestes und das wir die genutzte SGTIN wirklich „besitzen“. Wir führen die Überprüfung in einer Schleife aus und fragen jede Sekunde beim Server nach, ob die blaue Taste auf dem Access Point zur Bestätigung gedrück wurde. Dies ist nötig um den Request zu quittieren. Identifiziert wird dieser Request durch die im letzten Schritt genutzte UUID. Daher muss diese aus der Console kopiert und in dieses Script eingetragen werden. Das Script wartet lediglich auf einen HTTP Status 200 vom Server – dies signalisiert, dass die blaue Taste gedrückt wurde.
const axios = require('axios');
const crypto = require('crypto');
const HASH = crypto.createHash('sha512');
const ID = "3014F211A000215BE9A5ABCD";
const PIN = "1234";
const UUID = "UUID-FROM-LAST-STEP";
const REST_URL = "https://srz36.homematic.com:6969";
const CLIENTAUTH = HASH.update(ID + 'jiLpVitHvWnIGD1yo7MA', 'utf-8').digest('hex').toUpperCase();
statusCode = 0;
var data = { "deviceId": UUID }
var headers = {
"content-type": "application/json",
"accept": "application/json",
"VERSION": "12",
"CLIENTAUTH": CLIENTAUTH,
"PIN": PIN
}
var main = (async () => {
while (statusCode != 200) {
console.log("Please press your blue button on the access point!")
try {
response = await axios.default.post(REST_URL + "/hmip/auth/isRequestAcknowledged", data, { headers: headers });
statusCode = response.status;
} catch (error) {
//silence
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
console.log("Button press recordnized! Move on to next step...");
})();
Auth Token abholen
Durch das Bestätigen unserer UUID im letzten Schritt können wir nun mit dieser unseren Auth Token abholen, den wir dann für die Abfrage der eigentlichen Daten der Schnittstelle brauchen. Diesen solltet ihr kopieren und verwahren. Verliert ihr diesen müsst ihr die Prozedur erneut durchführen.
const axios = require('axios');
const crypto = require('crypto');
const HASH = crypto.createHash('sha512');
const ID = "3014F211A000215BE9A5ABCD";
const PIN = "1234";
const UUID = "UUID-FROM-LAST-STEP";
const REST_URL = "https://srz36.homematic.com:6969";
const CLIENTAUTH = HASH.update(ID + 'jiLpVitHvWnIGD1yo7MA', 'utf-8').digest('hex').toUpperCase();
var data = { "deviceId": UUID }
var headers = {
"content-type": "application/json",
"accept": "application/json",
"VERSION": "12",
"CLIENTAUTH": CLIENTAUTH,
"PIN": PIN
}
var main = (async () => {
//get request authToken!
console.log("Getting authToken ...");
try {
response = await axios.default.post(REST_URL + "/hmip/auth/requestAuthToken", data, { headers: headers });
} catch (error) {
console.error(error.response.data);
return;
}
const authToken = response.data.authToken;
console.log("authToken=" + authToken);
})();
Auth Token bestätigen
Der letzte Schritt ist die Bestätigung des Tokens. Diesen senden wir an die Schnittstelle und er wird für uns registriert. Nach diesem Schritt sollte dieser Token in der Homematic App wie im Intro beschrieben sichtbar sein. Die Schnittstelle schickt uns eine clientId zurück. Im Momenet weiß ich noch nicht genau für was diese gebraucht wird. Kopiert und sichert euch diese ebenfalls.
const axios = require('axios');
const crypto = require('crypto');
const HASH = crypto.createHash('sha512');
const ID = "3014F211A000215BE9A5ABCD";
const PIN = "1234";
const UUID = "UUID-FROM-LAST-STEP";
const REST_URL = "https://srz36.homematic.com:6969";
const AUTH_TOKEN = "AUTH-TOKEN-LAST-STEP";
const CLIENTAUTH = HASH.update(ID + 'jiLpVitHvWnIGD1yo7MA', 'utf-8').digest('hex').toUpperCase();
var data = { "deviceId": UUID }
var headers = {
"content-type": "application/json",
"accept": "application/json",
"VERSION": "12",
"CLIENTAUTH": CLIENTAUTH,
"PIN": PIN
}
var main = (async () => {
//confirm authToken!
console.log("Confirming authToken ...");
var data = { "deviceId": UUID, "authToken": AUTH_TOKEN }
try {
response = await axios.default.post(REST_URL + "/hmip/auth/confirmAuthToken", data, { headers: headers });
} catch (error) {
handleError(error);
return;
}
const clientId = response.data.clientId;
console.log("clientId="+clientId);
})();
Daten der Homematic API abrufen
Die Daten werden über einen einzigen Endpunkt abgerufen. Dieser gibt uns alle verfügbaren Daten zurück. In diesem Request sind grundlegende Konfigurationen, Gruppen, Geräte und Clients (haben wir in Kapital 1 einen erstellt).
Beispiel zur Aufgabe der IST-Temperatur, SOLL-Temperatur, Ventilstellung usw.
const axios = require('axios');
const crypto = require('crypto');
const os = require('os');
const HASH = crypto.createHash('sha512');
//EDIT your settings!
const ID = "3014F211A000215BE9A5ABCD";
const REST_URL = "https://srz36.homematic.com:6969";
const AUTH_TOKEN = "YOUR-AUTH-TOKEN";
const CLIENT_AUTH = HASH.update(ID + 'jiLpVitHvWnIGD1yo7MA', 'utf-8').digest('hex').toUpperCase();
const data = {
"clientCharacteristics": {
"apiVersion": "12",
"applicationIdentifier": "hmip-server",
"applicationVersion": "1.0",
"deviceManufacturer": "none",
"deviceType": "Computer",
"language": "en",
"osType": os.type(),
"osVersion": os.version()
}
}
const headers = {
"VERSION": "12",
"Content-Type": "application/json",
"CLIENTAUTH": CLIENT_AUTH,
"AUTHTOKEN": AUTH_TOKEN
}
var main = (async () => {
try {
const response = await axios.default.post(REST_URL + "/hmip/home/getCurrentState", data, { headers: headers });
for(const [deviceId, device] of Object.entries(response.data.devices)){
if(device.type == "HEATING_THERMOSTAT"){
console.log(device.functionalChannels['1']);
}
}
} catch (error) {
console.error(error);
return;
}
})();
Ausgabe in der Console zeigt eine IST-Temperatur von 18,3°, eine SOLL-Temperatur von 22° und eine Ventilstellung von 83% geöffnet.
{
"label": "",
"deviceId": "3014F711A000395FXXXXXXXX",
"index": 1,
"groupIndex": 1,
"functionalChannelType" : "HEATING_THERMOSTAT_CHANNEL",
"groups": [
"3e492eb7-XXXX-4c9a-b235-XXXXXXXXXXXX",
"62783cae-XXXX-49a9-b84e-XXXXXXXXXXXX"
],
"channelRole": "HEATING_CONTROLLER",
"temperatureOffset": 0,
"valvePosition": 0.83,
"setPointTemperature": 22,
"valveState": "ADAPTION_DONE",
"valveActualTemperature": 18.3
}