Ventanas de mantenimiento
Una ventana de mantenimiento evita que los comandos disruptivos, como un reinicio, se inicien en el momento equivocado. Esta guía explica cómo configurar una y ver cómo un comando espera a que se abra. El razonamiento de fondo está en Ventanas de mantenimiento.
Las ventanas se gestionan en la API GraphQL de gestión de dispositivos, en
https://<your-host>/api/device-management/graphql. Los comandos se emiten como se describe en
Enviar un comando, contra la API de entrega de comandos.
Crear una ventana
Una ventana es una zona horaria más de 1 a 56 franjas semanales. slots es una cadena JSON.
Cada franja tiene un day (MONDAY a SUNDAY), un start (HH:MM de 24 horas, hora de reloj en
esa zona) y una durationMinutes (de 1 a 10080, tiempo transcurrido).
mutation {
createMaintenanceWindow(request: {
token: "weekend-night",
name: "Weekend night",
timezone: "Europe/Berlin",
slots: "[{\"day\":\"SATURDAY\",\"start\":\"22:00\",\"durationMinutes\":240}]"
}) {
token timezone slots
}
}
Local y los nombres de zona desconocidos se rechazan. Una franja puede cruzar la medianoche, así que
el ejemplo anterior está abierto de las 22:00 a las 02:00 en la noche del sábado al domingo. Para
comprobar qué hará una ventana, pregunta cuándo se abre:
query {
maintenanceWindowOpening(token: "weekend-night", at: "2026-11-02T12:00:00Z") {
found openNow dispatchAfter closes
}
}
dispatchAfter es el instante por el que preguntaste si la ventana está abierta; en caso contrario,
la próxima apertura. Omite at para usar el momento actual.
Asignarla a un tipo de dispositivo
Un tipo de dispositivo tiene como máximo una ventana. Todos los dispositivos de ese tipo la siguen.
mutation {
updateDeviceType(token: "pump-controller", request: {
maintenanceWindowToken: "weekend-night"
}) {
token
maintenanceWindow { token }
}
}
Envía null o un valor vacío para desvincularla. Un tipo de dispositivo sin ventana envía todos los
comandos de inmediato, como antes.
Marcar un comando como DISRUPTIVE
Solo esperan los comandos declarados con impacto DISRUPTIVE o DESTRUCTIVE. Defínelo en la
definición del comando y después publica el perfil; la compuerta lee el vocabulario publicado.
mutation {
createCommandDefinition(request: {
token: "pump-reboot",
deviceProfileToken: "pump-profile",
commandKey: "reboot",
impact: "DISRUPTIVE"
}) { token impact }
}
impact es NORMAL si se omite. Add LwM2M standard commands, en la consola, crea
lwm2m.reboot como DISRUPTIVE. Las definiciones declaradas antes no cambian. Un comando cuya clave
no esté declarada con alguno de estos impactos, incluido un lwm2m.execute sin procesar, nunca se
retiene.
Enviar un comando y verlo esperar
Envía el comando como de costumbre. Si la ventana está cerrada, el comando se acepta y espera. Si la ventana está abierta, el comando se envía de inmediato, pero solo hasta que la ventana se cierre.
mutation {
createCommand(request: {
token: "reboot-pump-7",
deviceToken: "pump-007",
name: "reboot"
}) {
command { token status dispatchAfter maintenanceWindowToken }
rejection { code reason }
}
}
El comando permanece en QUEUED, dispatchAfter es la próxima apertura y maintenanceWindowToken
es weekend-night. Cuando la ventana se abre, se envía como cualquier otro comando, también a un
dispositivo dormido que despierte más tarde. Los comandos en espera cuentan para el techo de comandos
sin entregar del inquilino y pueden cancelarse, uno a uno o como lote, como cualquier comando en
cola. El campo waiting del registro de un lote indica cuántos miembros quedaron retenidos para una
ventana.
Para ver qué ocurriría sin enviar nada, consulta commandDispatchSchedule con los tokens de los
dispositivos, la clave del comando y un expiresAt opcional.
La ventana controla solo el inicio. Un comando ya iniciado dentro de la ventana termina cuando termine.
Cuando la ventana se abre demasiado tarde: WINDOW_AFTER_EXPIRY
Un comando caduca a los siete días salvo que indiques expiresAt. Si la próxima apertura es posterior,
el encolado se rechaza con el código WINDOW_AFTER_EXPIRY, porque aceptarlo solo acabaría en
EXPIRED. En un lote es un rechazo por dispositivo, y se rechaza todo el lote salvo que se indique
allowPartial. Tal como está, no tiene sentido reintentarlo. Para solucionarlo, haz una de estas
cosas:
- indica un
expiresAtposterior, de modo que el comando sobreviva a la espera; - añade franjas a la ventana o adelanta la próxima, para que se abra antes de que el comando caduque.
Editar o eliminar una ventana
updateMaintenanceWindow es una actualización parcial: omite un campo para dejarlo como está.
mutation {
updateMaintenanceWindow(token: "weekend-night", request: {
slots: "[{\"day\":\"SATURDAY\",\"start\":\"23:00\",\"durationMinutes\":180}]"
}) { token slots }
}
Los comandos que ya esperan siguen el nuevo calendario en aproximadamente un minuto, porque la entrega de comandos lo consulta periódicamente en lugar de recibir un aviso. No esperes que el cambio sea instantáneo.
deleteMaintenanceWindow se rechaza mientras algún tipo de dispositivo use la ventana; desvincúlala
primero. Desvincular una ventana de un tipo no libera los comandos que ya esperan por ella: siguen
esperando a que se abra, o a que se elimine la propia ventana, lo que los libera. Si un dispositivo
está desconectado durante toda una apertura, su comando pasa a la siguiente apertura en lugar de
enviarse cuando el dispositivo vuelva.
Límites
- Una ventana pertenece a un tipo de dispositivo. No hay ventana por grupo, por dispositivo ni predeterminada del inquilino, ni ventanas de bloqueo o festivos.
- El control de las actualizaciones por aire no está construido.
- Si no se puede alcanzar la gestión de dispositivos al encolar, el comando se rechaza en lugar de enviarse sin control.
El contador command_delivery_window_restamps_total cuenta los comandos cuya retención se movió por
una edición, una eliminación o una ventana que se cerró de nuevo antes de que volviera el
dispositivo.