Diese Seite behandelt zwei Gruppen von Routen: Firmware-Updates (OTA) und Remote-Geräteeinstellungen. Wie beide für Anwender funktionieren, steht unter Firmware-Updates (OTA), Firmware-Rollout-Wellen und Remote-Geräteeinstellungen. Pfade beginnen mit https://<your host>/tenant/<tenantId>.
Firmware-Routen
| Methode | Pfad | Berechtigung | Funktion |
|---|---|---|---|
| GET | /api/iot/ota/packages | iot_ota.read | Pakete auflisten (status, title) |
| POST | /api/iot/ota/packages | iot_ota.packages.manage | Paket hochladen (multipart) |
| GET | /api/iot/ota/packages/{packageId} | iot_ota.read | Ein Paket mit seinen Update-Zählern |
| PATCH | /api/iot/ota/packages/{packageId} | iot_ota.packages.manage | Versionshinweise oder Status DEPRECATED, erneut READY, REVOKED |
| DELETE | /api/iot/ota/packages/{packageId} | iot_ota.packages.manage | Ein nicht verwendetes Paket löschen |
| GET, POST | /api/iot/ota/assignments | Lesen: iot_ota.read; zuweisen: iot_ota.assign | Zuweisungen auflisten oder anlegen |
| DELETE | /api/iot/ota/assignments/{assignmentId} | iot_ota.assign | Eine Zuweisung entfernen |
| GET | /api/iot/ota/rollouts | iot_ota.read | Rollouts in Wellen (packageId, status) |
| GET, POST | /api/iot/ota/rollouts/{rolloutId} | Lesen; iot_ota.assign | Lesen; { "action": "pause" \| "resume" \| "abort" } |
| GET | /api/iot/ota/states | iot_ota.read | Update-Versuche (packageId, state, limit bis 500) |
| GET, POST | /api/iot/ota/devices/{deviceId} | Lesen; iot_ota.assign | Das Update eines Geräts; { "action": "retry" } |
| GET, PUT | /api/iot/ota/settings/{profile\|device}/{id} | Lesen; iot_ota.assign | OTA-Einstellungen eines Profils oder die Ausnahme für getaktete Verbindungen eines Geräts |
| GET, POST | /api/iot/ota/signing-keys | Lesen; iot_ota.keys.manage | Signatur-Public-Keys auflisten oder hinzufügen |
| DELETE | /api/iot/ota/signing-keys/{keyId} | iot_ota.keys.manage | Einen Schlüssel widerrufen |
Signaturschlüssel hinzufügen und widerrufen ist eine Owner-Berechtigung, daher kann ein API-Schlüssel das nicht.
Ein Paket hochladen
POST /api/iot/ota/packages erwartet multipart/form-data mit zwei Teilen: file (das Image) und meta (JSON-Text). Die Prüfsumme wird geprüft, bevor etwas gespeichert wird, und die Signatur wird gegen Ihre registrierten Schlüssel verifiziert.
curl -s -X POST "https://$HOST/tenant/$TENANT/api/iot/ota/packages" \
-H "Authorization: Bearer $HERMETRY_KEY" \
-F "file=@router-fw-2.5.0.bin" \
-F 'meta={"title":"router-fw","version":"2.5.0","checksum":"<sha256 of the file>","signatureScheme":"usign-ed25519","signature":"<text of the .sig file>","profileId":"a1b2…","releaseNotes":"Fixes LTE reconnect."}'
Feld meta | Regeln |
|---|---|
title | 1 bis 128; Buchstaben, Ziffern, ., _, +, - |
version | 1 bis 64; Buchstaben, Ziffern, ., _, +, ~, - |
checksum | SHA-256 der Datei, 64 hexadezimale Zeichen |
signatureScheme | usign-ed25519 (eine losgelöste Signatur in signature), das Secure-Boot-Schema der Gerätefamilie, für die das Paket bestimmt ist, oder none (nur wenn das Profil unsignierte Images erlaubt) |
type | FIRMWARE oder SOFTWARE |
profileId, hardwareModels (bis 50), minFromVersion | Für welche Geräte es passt |
releaseNotes | bis 4.000 Zeichen |
Die maximale Standardgröße beträgt 64 MiB. Die Antwort ist 201 { "package": {...} }.
| Ablehnung | Meldung |
|---|---|
400 file_missing | Fügen Sie die Firmware-Datei an. |
413 too_large | Das Paket ist größer als erlaubt. |
413 quota | Für dieses Paket ist nicht genug Speicher frei. |
422 checksum_mismatch | Die SHA-256 der hochgeladenen Datei stimmt nicht mit der angegebenen überein. |
422 | Die Signatur des Images lässt sich mit keinem registrierten Schlüssel verifizieren. |
409 package_exists | Ein Paket mit diesem Titel und dieser Version existiert bereits. |
Zuweisen und ausrollen
POST/tenant/{tenantId}/api/iot/ota/assignments
Weist ein READY-Paket einem PROFILE oder einem DEVICE (in targetId) oder einer GROUP zu (deviceIds, bis 5.000, oder selector.profileId, beides wird jetzt eingefroren). dryRun: true liefert die Anzahlen und schreibt nichts. waves (1 bis 20) rollt ein Profil oder eine Gruppe in Wellen aus; ein einzelnes Gerät wird nie in Wellen ausgerollt.
Anfragetext application/json
{
"packageId": "f00d…",
"targetType": "PROFILE",
"targetId": "a1b2…",
"waves": [
{
"size": {
"percent": 5
},
"soakMin": 60,
"minSuccessPct": 95,
"maxFailurePct": 2,
"maxDurationMin": 1440
},
{
"size": {
"percent": 100
},
"soakMin": 0,
"minSuccessPct": 95,
"maxFailurePct": 2,
"maxDurationMin": 2880
}
]
}
Beispiel curl
curl -X POST 'https://<your-host>/tenant/{tenantId}/api/iot/ota/assignments' \
-H 'Content-Type: application/json' \
-d '{"packageId":"f00d…","targetType":"PROFILE","targetId":"a1b2…","waves":[{"size":{"percent":5},"soakMin":60,"minSuccessPct":95,"maxFailurePct":2,"maxDurationMin":1440},{"size":{"percent":100},"soakMin":0,"minSuccessPct":95,"maxFailurePct":2,"maxDurationMin":2880}]}'
Antworten
201Erstellt
{
"assignment": {
"…": "…"
},
"preview": {
"…": "…"
},
"result": {
"…": "…"
}
}
200OK
{
"assignment": null,
"preview": {
"…": "…"
}
}
409Konflikt
{
"message": "Only a ready package can be assigned.",
"code": "CONFLICT"
}
Die size einer Welle ist { "percent": 0–100 } oder { "count": 1–100000 }; die letzte Welle nimmt den Rest. soakMin 0 bis 10.080, minSuccessPct und maxFailurePct 0 bis 100, optional maxFailures, maxDurationMin 5 bis 43.200.
Rollout-Status: RUNNING, PAUSED, COMPLETED, ABORTED. Ein fehlgeschlagenes Gate pausiert den Rollout; resume setzt ihn fort, abort beendet ihn.
Update-Status
Das Update eines Geräts durchläuft QUEUED, INITIATED, WAITING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING und endet mit UPDATED, FAILED, TIMEOUT, ROLLED_BACK, SKIPPED oder CANCELLED. Nur FAILED, TIMEOUT und ROLLED_BACK können wiederholt werden ({ "action": "retry" }), bis zum Versuchslimit.
OTA-Einstellungen
PUT /api/iot/ota/settings/profile/{profileId} erwartet otaEnabled, allowMetered, allowUnsigned, downloadTimeoutMin (5 bis 1.440), updateTimeoutMin (2 bis 240), maxAttempts (1 bis 10); null setzt auf den Standard zurück. Für ein Gerät (/settings/device/{deviceId}) wird nur allowMetered übernommen: „Ein Gerät übernimmt nur die Einstellung für getaktete Verbindungen.“
Webhook-Ereignisse: ota.update.* und ota.rollout.*, siehe die Webhook-Ereignisreferenz.
Routen für Geräteeinstellungen
Remote-Einstellungen gelten für lizenzierte Geräte, deren Modell ein Einstellungsmanifest veröffentlicht.
| Methode | Pfad | Berechtigung | Funktion |
|---|---|---|---|
| GET | /api/iot/devices/{deviceId}/settings | iot_device_settings.read | Jeder Abschnitt: Soll- und Istwerte, Status, Drift |
| GET | /api/iot/devices/{deviceId}/settings/schema | .read | Das Manifest des Modells und der Firmware des Geräts |
| GET | /api/iot/devices/{deviceId}/settings/history | .read | Frühere Änderungen (section, page ab 0, sort=at:desc) |
| GET | /api/iot/devices/{deviceId}/settings/{section} | .read | Ein Abschnitt; ETag ist seine Revision |
| PUT | /api/iot/devices/{deviceId}/settings/{section} | .operate und die geänderten Klassen | Einen Abschnitt ersetzen: { values, confirm? } |
| PATCH | /api/iot/devices/{deviceId}/settings/{section} | .operate und die geänderten Klassen | Merge-Patch: { patch, confirm? } |
| POST | /api/iot/devices/{deviceId}/settings/{section}/reapply | .operate | Den Soll-Abschnitt erneut senden |
| GET | /api/iot/device-settings/models, /model-schema?model= | .read | Ihre Modelle und die Abschnitte eines Modells |
| GET, POST | /api/iot/device-settings/baselines | .read; .baselines.manage | Baselines auflisten oder anlegen |
| GET, PUT, DELETE | /api/iot/device-settings/baselines/{baselineId} | .read; .baselines.manage | Lesen, ersetzen, löschen |
| GET, POST | /api/iot/device-settings/jobs | .read; .jobs.manage | Massenjobs auflisten oder starten |
| GET | /api/iot/device-settings/jobs/{jobId}, .../targets | .read | Ein Job, seine Wellen und seine Geräte |
| POST | /api/iot/device-settings/jobs/{jobId}/pause, /resume, /cancel | .jobs.manage | Einen Job steuern |
Was ein Schreibvorgang ändern darf, hängt von der Klasse jeder geänderten Einstellung ab: Betriebseinstellungen benötigen iot_device_settings.operate, Konfigurationseinstellungen iot_device_settings.write, gefährliche Einstellungen iot_device_settings.dangerous.write (nur Owner, daher nie ein API-Schlüssel) und "confirm": true.
Einen Abschnitt ändern
GET /api/iot/devices/{deviceId}/settings/network → ETag: "7"
PATCH /api/iot/devices/{deviceId}/settings/network
If-Match: "7"
{ "patch": { "lte": { "apn": "iot.example" } } }
If-Matchist erforderlich: Ohne diesen Header antwortet die API mit428„If-Match is required: send the rev you read.“- Wurde ein Abschnitt seit dem Lesen geändert, antwortet die API mit
412„The section changed since it was read; read it again.“ (rev_mismatch). ?dryRun=trueprüft und listet auf, was sich ändern würde, und speichert nichts.- Ein Merge-Patch führt Objekte zusammen, löscht mit
nullund ersetzt Listen vollständig. - Schreibvorgänge sind auf 600 pro Organisation und Minute begrenzt.
- Geheimnisse werden nie zurückgegeben: Eine geheime Einstellung wird als
{ "set": true }gelesen.
Ein Gerät, das keine Einstellungen nach Abschnitt annimmt, antwortet mit 409 „This device does not take settings by section.“; eines, dessen Manifest noch nicht im Katalog ist, mit „The settings manifest of this device’s model and firmware is not in the catalog yet.“
Massenjobs
POST /api/iot/device-settings/jobs mit dem Header Idempotency-Key: name (bis zu 80), baselineId oder sections, selector (deviceIds, profileId oder models), optional waves ({ "percent": [1, 10, 100] } oder { "count": [...] }, bis zu 10), gates (minApplied, maxReverted als Anteile von 0 bis 1), onConflict (queue oder skip), offlineExpiryDays (1 bis 90), waveTimeoutMin (1 bis 1.440), confirm. Ein wiederholter Idempotency-Key liefert den ersten Job (200). ?dryRun=true liefert den Plan. Ablehnungen: 409 too_many_jobs; 422 confirm_required, invalid_sections, no_devices, too_many_devices; 403 class_forbidden.

