Novedad: el cortafuegos de IA supervisa cada módulo y explica cada incidente con palabras sencillas. Vea cómo funciona

API de firmware y ajustes de dispositivos

Suba firmware firmado, asígnelo, ejecute y dirija despliegues por oleadas, y lea y cambie los ajustes de dispositivos licenciados por REST: rutas, cuerpos y errores.

Esta página cubre dos familias de rutas: actualizaciones de firmware (OTA) y ajustes remotos de dispositivos. Cómo funcionan ambas para las personas se explica en Actualizaciones de firmware (OTA), Oleadas de despliegue de firmware y Ajustes remotos de dispositivos. Las rutas están bajo https://<your host>/tenant/<tenantId>.

Rutas de firmware

MétodoRutaPermisoFunción
GET/api/iot/ota/packagesiot_ota.readListar paquetes (status, title)
POST/api/iot/ota/packagesiot_ota.packages.manageSubir un paquete (multipart)
GET/api/iot/ota/packages/{packageId}iot_ota.readUn paquete con sus recuentos de actualizaciones
PATCH/api/iot/ota/packages/{packageId}iot_ota.packages.manageNotas de la versión, o estado DEPRECATED, READY de nuevo, REVOKED
DELETE/api/iot/ota/packages/{packageId}iot_ota.packages.manageEliminar un paquete no usado
GET, POST/api/iot/ota/assignmentslectura: iot_ota.read; asignar: iot_ota.assignListar o crear asignaciones
DELETE/api/iot/ota/assignments/{assignmentId}iot_ota.assignEliminar una asignación
GET/api/iot/ota/rolloutsiot_ota.readDespliegues por oleadas (packageId, status)
GET, POST/api/iot/ota/rollouts/{rolloutId}lectura; iot_ota.assignLectura; { "action": "pause" \| "resume" \| "abort" }
GET/api/iot/ota/statesiot_ota.readIntentos de actualización (packageId, state, limit hasta 500)
GET, POST/api/iot/ota/devices/{deviceId}lectura; iot_ota.assignLa actualización de un dispositivo; { "action": "retry" }
GET, PUT/api/iot/ota/settings/{profile\|device}/{id}lectura; iot_ota.assignAjustes OTA de un perfil, o la anulación de enlace medido de un dispositivo
GET, POST/api/iot/ota/signing-keyslectura; iot_ota.keys.manageListar o añadir claves públicas de firma
DELETE/api/iot/ota/signing-keys/{keyId}iot_ota.keys.manageRevocar una clave

Añadir y revocar claves de firma es un permiso de Propietario, así que una clave de API no puede hacerlo.

Subir un paquete

POST /api/iot/ota/packages acepta multipart/form-data con dos partes: file (la imagen) y meta (texto JSON). El checksum se comprueba antes de guardar nada, y la firma se verifica con tus claves registradas.

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."}'
Campo metaReglas
titleDe 1 a 128; letras, dígitos, ., _, +, -
versionDe 1 a 64; letras, dígitos, ., _, +, ~, -
checksumSHA-256 del archivo, 64 caracteres hexadecimales
signatureSchemeusign-ed25519 (una firma separada en signature), el esquema de arranque seguro de la familia de dispositivos para la que es el paquete, o none (solo donde el perfil permita imágenes sin firmar)
typeFIRMWARE o SOFTWARE
profileId, hardwareModels (hasta 50), minFromVersionA qué dispositivos se ajusta
releaseNoteshasta 4.000 caracteres

El tamaño máximo predeterminado es 64 MiB. La respuesta es 201 { "package": {...} }.

RechazoMensaje
400 file_missingAdjunta el archivo de firmware.
413 too_largeEl paquete es mayor de lo permitido.
413 quotaNo queda suficiente almacenamiento para este paquete.
422 checksum_mismatchEl SHA-256 del archivo subido no coincide con el indicado.
422La firma de la imagen no se verifica con ninguna clave registrada.
409 package_existsYa existe un paquete con este título y versión.

Asignar y desplegar

POST/tenant/{tenantId}/api/iot/ota/assignments

Asigna un paquete READY a un PROFILE o a un DEVICE (en targetId) o a un GROUP (deviceIds, hasta 5.000, o selector.profileId, ambos fijados ahora). dryRun: true devuelve los recuentos y no escribe nada. waves (de 1 a 20) despliega un perfil o grupo por oleadas; un dispositivo nunca se despliega por oleadas.

Cuerpo de la solicitud 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
        }
    ]
}

Ejemplo 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}]}'

Respuestas

201Creado
{
    "assignment": {
        "…": "…"
    },
    "preview": {
        "…": "…"
    },
    "result": {
        "…": "…"
    }
}
200OK
{
    "assignment": null,
    "preview": {
        "…": "…"
    }
}
409Conflicto
{
    "message": "Only a ready package can be assigned.",
    "code": "CONFLICT"
}

El size de una oleada es { "percent": 0–100 } o { "count": 1–100000 }; la última oleada toma el resto. soakMin de 0 a 10.080, minSuccessPct y maxFailurePct de 0 a 100, maxFailures opcional, maxDurationMin de 5 a 43.200.

Estados de despliegue: RUNNING, PAUSED, COMPLETED, ABORTED. Una comprobación fallida pausa el despliegue; resume lo continúa, abort lo termina.

Estados de actualización

La actualización de un dispositivo pasa por QUEUED, INITIATED, WAITING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING y termina en UPDATED, FAILED, TIMEOUT, ROLLED_BACK, SKIPPED o CANCELLED. Solo FAILED, TIMEOUT y ROLLED_BACK pueden reintentarse ({ "action": "retry" }), hasta el límite de intentos.

Ajustes OTA

PUT /api/iot/ota/settings/profile/{profileId} acepta otaEnabled, allowMetered, allowUnsigned, downloadTimeoutMin (de 5 a 1.440), updateTimeoutMin (de 2 a 240), maxAttempts (de 1 a 10); null vuelve al valor predeterminado. Para un dispositivo (/settings/device/{deviceId}) solo se acepta allowMetered: «Un dispositivo solo acepta el ajuste de enlace medido.»

Eventos de webhook: ota.update.* y ota.rollout.*, consulta la Referencia de eventos de webhook.

Rutas de ajustes de dispositivos

Los ajustes remotos son para dispositivos con licencia cuyo modelo publica un manifiesto de ajustes.

MétodoRutaPermisoFunción
GET/api/iot/devices/{deviceId}/settingsiot_device_settings.readTodas las secciones: valores deseados e informados, estado, desviación
GET/api/iot/devices/{deviceId}/settings/schema.readEl manifiesto del modelo y firmware del dispositivo
GET/api/iot/devices/{deviceId}/settings/history.readCambios anteriores (section, page desde 0, sort=at:desc)
GET/api/iot/devices/{deviceId}/settings/{section}.readUna sección; ETag es su revisión
PUT/api/iot/devices/{deviceId}/settings/{section}.operate y las clases modificadasReemplaza una sección: { values, confirm? }
PATCH/api/iot/devices/{deviceId}/settings/{section}.operate y las clases modificadasParche de fusión: { patch, confirm? }
POST/api/iot/devices/{deviceId}/settings/{section}/reapply.operateVuelve a enviar la sección deseada
GET/api/iot/device-settings/models, /model-schema?model=.readTus modelos y las secciones de un modelo
GET, POST/api/iot/device-settings/baselines.read; .baselines.manageListar o crear líneas base
GET, PUT, DELETE/api/iot/device-settings/baselines/{baselineId}.read; .baselines.manageLeer, reemplazar, eliminar
GET, POST/api/iot/device-settings/jobs.read; .jobs.manageListar o iniciar trabajos masivos
GET/api/iot/device-settings/jobs/{jobId}, .../targets.readUn trabajo, sus oleadas y sus dispositivos
POST/api/iot/device-settings/jobs/{jobId}/pause, /resume, /cancel.jobs.manageDirigir un trabajo

Lo que una escritura puede cambiar depende de la clase de cada ajuste modificado: los ajustes de operación requieren iot_device_settings.operate, los ajustes de configuración iot_device_settings.write, los ajustes peligrosos iot_device_settings.dangerous.write (solo el Propietario, nunca una clave de API) y "confirm": true.

Cambiar una sección

GET  /api/iot/devices/{deviceId}/settings/network        → ETag: "7"
PATCH /api/iot/devices/{deviceId}/settings/network
If-Match: "7"
{ "patch": { "lte": { "apn": "iot.example" } } }
  • Se requiere If-Match: sin él, 428 «If-Match is required: send the rev you read.»
  • Una sección cambiada desde que la leyó: 412 «The section changed since it was read; read it again.» (rev_mismatch).
  • ?dryRun=true valida y lista lo que cambiaría, y no guarda nada.
  • Un merge patch fusiona objetos, elimina con null y reemplaza las listas completas.
  • Las escrituras están limitadas a 600 por organización y por minuto.
  • Los secretos nunca se devuelven: un ajuste secreto se lee como { "set": true }.

Un dispositivo que no acepta ajustes por sección responde 409 «This device does not take settings by section.»; uno cuyo manifiesto no está aún en el catálogo, «The settings manifest of this device’s model and firmware is not in the catalog yet.»

Trabajos masivos

POST /api/iot/device-settings/jobs con la cabecera Idempotency-Key: name (hasta 80), baselineId o sections, selector (deviceIds, profileId o models), waves opcional ({ "percent": [1, 10, 100] } o { "count": [...] }, hasta 10), gates (minApplied, maxReverted como fracciones de 0 a 1), onConflict (queue o skip), offlineExpiryDays (de 1 a 90), waveTimeoutMin (de 1 a 1,440), confirm. Una Idempotency-Key repetida responde con el primer trabajo (200). ?dryRun=true responde con el plan. Rechazos: 409 too_many_jobs; 422 confirm_required, invalid_sections, no_devices, too_many_devices; 403 class_forbidden.