Cette page couvre deux familles de routes : les mises à jour du firmware (OTA) et les réglages à distance des appareils. Leur fonctionnement pour les utilisateurs est décrit dans Mises à jour du firmware (OTA), Vagues de déploiement du firmware et Réglages à distance des appareils. Les chemins sont sous https://<your host>/tenant/<tenantId>.
Routes du firmware
| Méthode | Chemin | Permission | Action |
|---|---|---|---|
| GET | /api/iot/ota/packages | iot_ota.read | Lister les paquets (status, title) |
| POST | /api/iot/ota/packages | iot_ota.packages.manage | Téléverser un paquet (multipart) |
| GET | /api/iot/ota/packages/{packageId} | iot_ota.read | Un paquet avec ses compteurs de mises à jour |
| PATCH | /api/iot/ota/packages/{packageId} | iot_ota.packages.manage | Notes de version, ou statut DEPRECATED, READY à nouveau, REVOKED |
| DELETE | /api/iot/ota/packages/{packageId} | iot_ota.packages.manage | Supprimer un paquet inutilisé |
| GET, POST | /api/iot/ota/assignments | lecture : iot_ota.read ; affectation : iot_ota.assign | Lister ou créer des affectations |
| DELETE | /api/iot/ota/assignments/{assignmentId} | iot_ota.assign | Retirer une affectation |
| GET | /api/iot/ota/rollouts | iot_ota.read | Déploiements par vagues (packageId, status) |
| GET, POST | /api/iot/ota/rollouts/{rolloutId} | lecture ; iot_ota.assign | Lecture ; { "action": "pause" \| "resume" \| "abort" } |
| GET | /api/iot/ota/states | iot_ota.read | Tentatives de mise à jour (packageId, state, limit jusqu’à 500) |
| GET, POST | /api/iot/ota/devices/{deviceId} | lecture ; iot_ota.assign | Mise à jour d’un appareil ; { "action": "retry" } |
| GET, PUT | /api/iot/ota/settings/{profile\|device}/{id} | lecture ; iot_ota.assign | Réglages OTA d’un profil, ou exception de liaison limitée d’un appareil |
| GET, POST | /api/iot/ota/signing-keys | lecture ; iot_ota.keys.manage | Lister ou ajouter des clés publiques de signature |
| DELETE | /api/iot/ota/signing-keys/{keyId} | iot_ota.keys.manage | Révoquer une clé |
L’ajout et la révocation des clés de signature sont réservés au propriétaire, une clé API ne peut donc pas les effectuer.
Téléverser un paquet
POST /api/iot/ota/packages accepte multipart/form-data avec deux parties : file (l’image) et meta (texte JSON). La somme de contrôle est vérifiée avant tout stockage, et la signature est vérifiée par rapport à vos clés enregistrées.
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."}'
Champ meta | Règles |
|---|---|
title | 1 à 128 ; lettres, chiffres, ., _, +, - |
version | 1 à 64 ; lettres, chiffres, ., _, +, ~, - |
checksum | SHA-256 du fichier, 64 caractères hexadécimaux |
signatureScheme | usign-ed25519 (une signature détachée dans signature), le schéma de démarrage sécurisé de la famille d’appareils visée par le paquet, ou none (uniquement si le profil autorise les images non signées) |
type | FIRMWARE ou SOFTWARE |
profileId, hardwareModels (jusqu’à 50), minFromVersion | Appareils concernés |
releaseNotes | jusqu’à 4 000 caractères |
La taille maximale par défaut est de 64 MiB. La réponse est 201 { "package": {...} }.
| Refus | Message |
|---|---|
400 file_missing | Joignez le fichier du firmware. |
413 too_large | Le paquet dépasse la taille autorisée. |
413 quota | Espace de stockage insuffisant pour ce paquet. |
422 checksum_mismatch | Le SHA-256 du fichier téléversé ne correspond pas à celui fourni. |
422 | La signature de l’image ne se vérifie pas avec une clé enregistrée. |
409 package_exists | Un paquet avec ce titre et cette version existe déjà. |
Affecter et déployer
POST/tenant/{tenantId}/api/iot/ota/assignments
Affecter un paquet READY à un PROFILE ou à un DEVICE (dans targetId) ou à un GROUP (deviceIds, jusqu’à 5 000, ou selector.profileId, figés immédiatement). dryRun: true renvoie les comptages sans rien écrire. waves (1 à 20) déploie un profil ou un groupe par vagues ; un appareil seul n’est jamais déployé par vagues.
Corps de la requête 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
}
]
}
Exemple 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}]}'
Réponses
201Créé
{
"assignment": {
"…": "…"
},
"preview": {
"…": "…"
},
"result": {
"…": "…"
}
}
200OK
{
"assignment": null,
"preview": {
"…": "…"
}
}
409Conflit
{
"message": "Only a ready package can be assigned.",
"code": "CONFLICT"
}
La size d’une vague est { "percent": 0–100 } ou { "count": 1–100000 } ; la dernière vague prend le reste. soakMin de 0 à 10 080, minSuccessPct et maxFailurePct de 0 à 100, maxFailures facultatif, maxDurationMin de 5 à 43 200.
Statuts de déploiement : RUNNING, PAUSED, COMPLETED, ABORTED. Un contrôle échoué met le déploiement en pause ; resume le reprend, abort le termine.
Statuts de mise à jour
La mise à jour d’un appareil passe par QUEUED, INITIATED, WAITING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING et se termine par UPDATED, FAILED, TIMEOUT, ROLLED_BACK, SKIPPED ou CANCELLED. Seuls FAILED, TIMEOUT et ROLLED_BACK peuvent être relancés ({ "action": "retry" }), jusqu’à la limite de tentatives.
Réglages OTA
PUT /api/iot/ota/settings/profile/{profileId} accepte otaEnabled, allowMetered, allowUnsigned, downloadTimeoutMin (5 à 1 440), updateTimeoutMin (2 à 240), maxAttempts (1 à 10) ; null rétablit la valeur par défaut. Pour un appareil (/settings/device/{deviceId}), seul allowMetered est accepté : « Un appareil ne prend que le réglage de liaison limitée. »
Événements webhook : ota.update.* et ota.rollout.*, voir la Référence des événements webhook.
Routes des réglages d’appareil
Les réglages à distance concernent les appareils sous licence dont le modèle publie un manifeste de réglages.
| Méthode | Chemin | Permission | Action |
|---|---|---|---|
| GET | /api/iot/devices/{deviceId}/settings | iot_device_settings.read | Toutes les sections : valeurs souhaitées et remontées, état, dérive |
| GET | /api/iot/devices/{deviceId}/settings/schema | .read | Le manifeste du modèle et du firmware de l’appareil |
| GET | /api/iot/devices/{deviceId}/settings/history | .read | Modifications passées (section, page à partir de 0, sort=at:desc) |
| GET | /api/iot/devices/{deviceId}/settings/{section} | .read | Une section ; ETag correspond à sa révision |
| PUT | /api/iot/devices/{deviceId}/settings/{section} | .operate et les classes modifiées | Remplacer une section : { values, confirm? } |
| PATCH | /api/iot/devices/{deviceId}/settings/{section} | .operate et les classes modifiées | Patch de fusion : { patch, confirm? } |
| POST | /api/iot/devices/{deviceId}/settings/{section}/reapply | .operate | Renvoyer la section souhaitée |
| GET | /api/iot/device-settings/models, /model-schema?model= | .read | Vos modèles et les sections d’un modèle |
| GET, POST | /api/iot/device-settings/baselines | .read ; .baselines.manage | Lister ou créer des lignes de base |
| GET, PUT, DELETE | /api/iot/device-settings/baselines/{baselineId} | .read; .baselines.manage | Lire, remplacer, supprimer |
| GET, POST | /api/iot/device-settings/jobs | .read; .jobs.manage | Lister ou lancer des tâches en masse |
| GET | /api/iot/device-settings/jobs/{jobId}, .../targets | .read | Une tâche, ses vagues et ses appareils |
| POST | /api/iot/device-settings/jobs/{jobId}/pause, /resume, /cancel | .jobs.manage | Piloter une tâche |
Ce qu’une écriture peut modifier dépend de la classe de chaque réglage modifié : les réglages de fonctionnement exigent iot_device_settings.operate, les réglages de configuration iot_device_settings.write, les réglages dangereux iot_device_settings.dangerous.write (propriétaire uniquement, jamais une clé d’API) et "confirm": true.
Modifier une section
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-Matchest obligatoire : sans lui,428« If-Match is required: send the rev you read. »- Une section modifiée depuis votre lecture :
412« The section changed since it was read; read it again. » (rev_mismatch). ?dryRun=truevalide et liste ce qui serait modifié, sans rien enregistrer.- Un merge patch fusionne les objets, supprime avec
nullet remplace les listes entières. - Les écritures sont limitées à 600 par organisation et par minute.
- Les secrets ne sont jamais renvoyés : un réglage secret se lit comme
{ "set": true }.
Un appareil qui ne prend pas les réglages par section répond 409 « This device does not take settings by section. » ; un appareil dont le manifeste n’est pas encore dans le catalogue, « The settings manifest of this device’s model and firmware is not in the catalog yet. »
Tâches en masse
POST /api/iot/device-settings/jobs avec l’en-tête Idempotency-Key : name (80 caractères au maximum), baselineId ou sections, selector (deviceIds, profileId ou models), waves facultatif ({ "percent": [1, 10, 100] } ou { "count": [...] }, jusqu’à 10), gates (minApplied, maxReverted sous forme de fractions de 0 à 1), onConflict (queue ou skip), offlineExpiryDays (1 à 90), waveTimeoutMin (1 à 1 440), confirm. Un Idempotency-Key répété renvoie la première tâche (200). ?dryRun=true renvoie le plan. Refus : 409 too_many_jobs ; 422 confirm_required, invalid_sections, no_devices, too_many_devices ; 403 class_forbidden.

