Ein Befehl (ein RPC) fordert ein Gerät auf, etwas zu tun, und wartet, sofern er nicht einseitig ist, auf die Antwort des Geräts. Jeder Befehl wird als Anfrage mit einem Status gespeichert, sodass Sie ihn jetzt senden und das Ergebnis später abrufen können. Wie Befehle für Personen in der App funktionieren, steht unter Befehle an Geräte senden. Pfade liegen unter https://<your host>/tenant/<tenantId>.
In Entwicklung: Befehle an Geräte hinter einem Gateway (die untergeordneten Geräte eines Gateways) sind in Entwicklung. Senden Sie Befehle an Geräte, die sich selbstständig verbinden.
Routen
| Methode | Pfad | Berechtigung | Funktion |
|---|---|---|---|
| POST | /api/iot/devices/{deviceId}/rpc | iot_rpc.read plus die Stufe des Befehls | Einen Befehl senden |
| GET | /api/iot/devices/{deviceId}/rpc | iot_rpc.read | Der Befehlsverlauf des Geräts |
| GET | /api/iot/rpc/{rpcId} | iot_rpc.read | Ein Befehl mit seiner Antwort |
| POST | /api/iot/rpc/{rpcId}/cancel | iot_rpc.read plus die Stufe des Befehls | Einen wartenden oder gesendeten Befehl abbrechen |
| GET | /api/iot/devices/{deviceId}/rpc-commands | iot_rpc.send.basic | Die Befehle, die eine Dashboard-Steuerung an dieses Gerät senden darf |
| GET | /api/iot/rpc-commands/{profileId} | iot_rpc.read | Der Befehlskatalog eines Profils (?format=export für das Importformat) |
| POST | /api/iot/rpc-commands/{profileId} | iot_rpc.commands.manage | Einen Befehl zum Katalog hinzufügen |
| PUT | /api/iot/rpc-commands/{profileId} | iot_rpc.commands.manage | Den gesamten Katalog ersetzen |
| PATCH, DELETE | /api/iot/rpc-commands/{profileId}/{commandId} | iot_rpc.commands.manage | Einen Befehl ändern oder entfernen |
Wer was senden darf
Jeder Befehl im Katalog eines Profils hat eine Stufe. Die Stufe bestimmt die Berechtigung:
| Stufe | Berechtigung | Standardrolle | Kann ein API-Schlüssel sie besitzen? |
|---|---|---|---|
| basic | iot_rpc.send.basic | Benutzer | Ja |
| privileged | iot_rpc.send.privileged | Administrator | Ja |
| critical | iot_rpc.send.critical | Administrator | Ja |
| raw (eine Methode, die nicht im Katalog steht) | iot_rpc.send.raw | Eigentümer | Nein |
Ein API-Schlüssel kann daher nur Methoden senden, die im Befehlskatalog des Geräteprofils stehen.
Einen Befehl senden
POST/tenant/{tenantId}/api/iot/devices/{deviceId}/rpc
Felder: method (erforderlich, namespace.verb, bis zu 64 Zeichen), params (beliebiges JSON, höchstens 16 KiB), oneway, persistent, timeoutMs (1.000 bis 600.000; Standard ist der Wert des Katalogs oder des Profils, sonst 10.000), expiresInS (1 bis 604.800, für einen persistenten Befehl; Standard 86.400), wait, confirm, confirmText, source (api, console oder dashboard_control). Ein zweiseitiger, nicht persistenter Befehl mit einem Timeout von höchstens 30 Sekunden wartet auf sein Ende und antwortet mit 200; alles andere antwortet mit 202 und läuft weiter.
Anfragekörper application/json
{
"method": "pump.start",
"params": {
"speed": 80
},
"timeoutMs": 15000
}
Beispiel curl
curl -X POST 'https://<your-host>/tenant/{tenantId}/api/iot/devices/{deviceId}/rpc' \
-H 'Content-Type: application/json' \
-d '{"method":"pump.start","params":{"speed":80},"timeoutMs":15000}'
Antworten
200OK
{
"rpc": {
"rpcId": "c0de…",
"deviceId": "6f1c…",
"method": "pump.start",
"status": "SUCCESSFUL",
"outcome": null,
"response": {
"ok": true
},
"error": null,
"tier": "privileged",
"highImpact": false,
"source": "api",
"createdAt": "2026-11-09T09:00:00.000Z",
"completedAt": "2026-11-09T09:00:01.200Z",
"…": "…"
}
}
202Accepted
{
"rpc": {
"rpcId": "c0de…",
"status": "QUEUED",
"…": "…"
}
}
403Forbidden
{
"message": "You are not permitted to perform this action",
"code": "FORBIDDEN"
}
409Conflict
{
"message": "The device is disabled or quarantined; it takes no commands.",
"code": "CONFLICT",
"details": {
"reason": "device_not_active"
}
}
429Too Many Requests
{
"message": "Too many commands to this device; try again in a minute.",
"code": "RATE_LIMIT_EXCEEDED",
"details": {
"reason": "device_rate_limited"
}
}
- Einseitig (
oneway: true): Der Befehl gilt als erfolgreich, sobald er zugestellt ist; es wird keine Antwort erwartet. - Persistent (
persistent: true): Ist das Gerät offline, wartet der Befehl bis zuexpiresInSauf es und endet dann mitEXPIRED. - wait:
trueerzwingt das Warten (wird mit „A synchronous call waits at most 30 s; use wait: false for a longer timeout.“ abgelehnt, wenn der Befehl nicht in 30 s abgeschlossen werden kann);falseantwortet immer sofort mit202. - Folgenreiche Befehle benötigen
"confirm": truesowie die eingetippte Phrase inconfirmText, wenn der Katalogbefehl eine solche hat. Ohne diese Angaben: „This command needs confirm: true.“ Sie werden beim Senden und beim Abschluss ins Audit-Protokoll geschrieben und höchstens einmal gesendet.
Auf dieser Route gibt es keinen Idempotenzschlüssel: Jeder POST erzeugt einen neuen Befehl. Läuft Ihr Aufruf im Netzwerk in ein Timeout, lesen Sie den Verlauf des Geräts, bevor Sie erneut senden.
Status
QUEUED → SENT → DELIVERED → SUCCESSFUL, oder einer der Werte FAILED, TIMEOUT, EXPIRED, CANCELLED.
| Status | Bedeutung |
|---|---|
SUCCESSFUL | Die Antwort ist eingetroffen, oder ein einseitiger Befehl wurde zugestellt |
FAILED | Das Gerät hat ihn abgelehnt, oder er konnte nicht gesendet werden |
TIMEOUT | Keine Antwort rechtzeitig. Das Ergebnis ist unbekannt: Das Gerät könnte es ausgeführt haben. outcome ist unknown. |
EXPIRED | Er hat das Gerät vor Ablauf nie erreicht |
CANCELLED | Abgebrochen, während er wartete oder gesendet war |
outcome liefert Details: running (das Gerät hat einen länger laufenden Befehl angenommen), unknown (ein Timeout) oder late (eine Antwort kam nach dem Ende an). Ergebnisse werden standardmäßig 90 Tage aufbewahrt.
Ergebnisse abrufen
Fragen Sie GET /api/iot/rpc/{rpcId} ab, bis der Status endgültig ist, oder abonnieren Sie die Webhook-Ereignisse rpc.completed und rpc.failed und lesen Sie die Antwort, sobald eines eintrifft. Siehe die Webhook-Ereignisreferenz.
Verlauf eines Geräts, neueste zuerst:
GET /api/iot/devices/{deviceId}/rpc?status=FAILED&limit=50
Ohne page wird der Verlauf mit einem Cursor gelesen: status, method, from, to (Datumsangaben), limit (1 bis 100, Standard 25) und cursor. Die Antwort ist { "requests": [...], "nextCursor": "…" }; übergeben Sie nextCursor als cursor zurück, bis es null ist. Mit page (ab 0) folgt die Liste den üblichen Listenregeln: pageSize, search, sort (method, status, source, createdAt, completedAt), status und source als kommagetrennte Listen, createdFrom, createdTo; die Antwort ist { "requests": [...], "total": n }. Geheime Parameter werden in jeder Antwort maskiert.
Abbrechen
POST /api/iot/rpc/{rpcId}/cancel setzt einen QUEUED– oder SENT-Befehl auf CANCELLED und antwortet mit { "rpc": {...} }. Andere Status: 409 „Only a queued or sent request can be cancelled.“ Zum Abbrechen wird dieselbe Stufenberechtigung wie zum Senden benötigt. Ein Abbruch sendet keinen Webhook.
Grenzwerte
| Grenzwert | Standard |
|---|---|
| Befehle pro Gerät | 10 pro Minute (429, Retry-After: 60) |
| Befehle pro Organisation | 600 pro Minute (429 „Too many requests for your plan. Please upgrade or try again later.“) |
| Parameter | 16 KiB JSON |
| Aufbewahrte Antwort | 64 KiB |
| Befehle pro Profilkatalog | 200 |
Ablehnungen
| Status | details.reason | Meldung |
|---|---|---|
| 400 | bad_params | Die Parameter passen nicht zum Befehl. |
| 400 | wait_too_long | A synchronous call waits at most 30 s; use wait: false for a longer timeout. |
| 400 | confirm_required, confirm_text_mismatch | This command needs confirm: true. / Die eingegebene Bestätigung stimmt nicht überein. |
| 400 | method_refused | Werkseinstellungen zurücksetzen, Kopplung, WLAN vergessen und Abmeldung von der Cloud werden nie aus der Cloud gesendet. |
| 400 | payload_too_large | Die Anfrage ist größer, als das Gerät annimmt. |
| 403 | rpc_method_reserved | Die Methode gehört zu einem eigenen Modul (zum Beispiel Fernzugriff) und wird nur von diesem gesendet; details.owner nennt das Modul. |
| 404 | Gerät nicht gefunden. | |
| 409 | rpc_not_supported_by_profile | Das Geräteprofil spricht nur die Legacy-Topics, die kein RPC enthalten. |
| 409 | device_not_active | Das Gerät ist deaktiviert oder unter Quarantäne. |
| 409 | not_cancellable | Nur eine eingereihte oder gesendete Anfrage kann abgebrochen werden. |
| 429 | device_rate_limited | Zu viele Befehle an dieses Gerät; versuchen Sie es in einer Minute erneut. |
Der Befehlskatalog
Ein Katalogbefehl hat: method, label (bis zu 120), description, paramsSchema (bis zu 50 Felder, jeweils mit label, type von text, textarea, number, boolean, select, multi-select oder json sowie optional required, min, max, step, options), maskedParams (geheime Felder werden nie zurückgegeben), tier (basic, privileged, critical), highImpact, oneway, long, defaultTimeoutMs, persistentDefault, confirmText (nur bei High-Impact-Befehlen).
{
"method": "valve.set",
"label": "Set valve position",
"tier": "privileged",
"paramsSchema": { "position": { "label": "Position (%)", "type": "number", "min": 0, "max": 100, "required": true } }
}
GET ...?format=export gibt { "commands": [...] } ohne IDs zurück, die PUT wieder entgegennimmt, um einen Katalog in ein anderes Profil zu kopieren.

