Mensajes Servidor → Cliente

Formato de los mensajes

Cada mensaje es un objeto JSON con una única clave de primer nivel. Esta clave codifica el tipo de evento y puede incluir una descripción legible separada por un guion:

"aa-dump all data"   →  tipo de evento = 2 primeros caracteres = "aa"
"ea"                 →  tipo de evento = "ea"
"d"                  →  tipo de evento = "d" (carácter único)

Los clientes deben comparar los 1 o 2 primeros caracteres de la clave, no la cadena completa, ya que la parte de descripción puede cambiar.

Todas las claves de eventos enviadas por el servidor están en minúsculas (ej. d, ea, ap, gc).


Índice de tipos de eventos

ClaveDescripción
dDump inicial completo (respuesta a DU)
aaDump completo de un módulo (módulo cargado/recargado)
apReemplazo completo de una propiedad
eaActualización de todos los valores de elementos de una propiedad
eeActualización de un solo valor de elemento
evActualización de un valor de elemento con sus restricciones
elCambio de la LOV local propia de un elemento
psActualización del estado y del estado activado de una propiedad
dmMódulo eliminado
dpPropiedad eliminada
gcLínea de cuadrícula creada
guLínea de cuadrícula actualizada
gdLínea de cuadrícula eliminada
grReinicio de la cuadrícula (todas las líneas borradas)
lcLOV creado o fusionado
luLOV reemplazado
ldLOV eliminado
fsPerfil guardado
flPerfil cargado
fcPerfil modificado (modificaciones no guardadas)
lEntrada de log
ucActualización de los datos del controlador
afArchivo añadido
dfArchivo eliminado
adCarpeta añadida
ddCarpeta eliminada
qaRespuesta a una consulta de módulo (mecanismo inter-módulo, no pensado para el cliente)
xxPong keepalive

d — Dump inicial completo

Enviado como respuesta a una petición DU. Contiene todo: todos los módulos, los logs, las listas de archivos y los datos del controlador. El detalle de las claves de controllerdata y de files está en Controlador, GlobalDatastore y archivos; el ejemplo siguiente solo muestra algunas.

{
  "d": {
    "grant-client": "1",
    "grant-server": "0",
    "serverlng": "en",
    "m": {
      "Focus": {
        "infos": { "modulelabel": "Focus", "description": "..." },
        "f": { "name": "default", "changed": false },
        "l": {
          "myLov": { "label": "My LOV", "type": "string", "values": { "a": "Option A" } }
        },
        "p": {
          "parameters": {
            "label": "Parameters",
            "order": "10",
            "level1": "Focus",
            "level2": "Config",
            "status": 0,
            "permission": 2,
            "enabled": true,
            "showElts": true,
            "hasGrid": false,
            "hasGraph": false,
            "rule": 0,
            "badge": false,
            "preicon1": "", "preicon2": "", "posticon1": "", "posticon2": "",
            "hasprofile": true,
            "freevalue": "",
            "e": {
              "iterations": {
                "type": "int",
                "label": "Iterations",
                "order": "10",
                "hint": "",
                "autoupdate": false,
                "badge": false,
                "directedit": false,
                "value": 5,
                "min": 1,
                "max": 20,
                "step": 1,
                "format": "",
                "slider": 0
              }
            }
          }
        }
      }
    },
    "files": {
      "folders": ["", "/Allsky", "/Allsky/archives"],
      "files": ["/image.jpeg"],
      "selectedfolder": "/home/user/ostmedia"
    },
    "logs": [
      { "d": "2024-01-01T12:00:00.000", "c": "Focus", "t": "Module loaded", "l": 1 }
    ],
    "controllerdata": {
      "profiles": {
        "Focus": ["default", "test"]
      },
      "currentconf": "default"
    },
    "lovs": {
      "sharedLov": { "label": "Shared LOV", "type": "string", "values": {} }
    }
  }
}
Abreviaturas del formato wire

m = modules, p = properties, e = elements, l = globallovs, f = profile. Normalizar estas abreviaturas a sus nombres completos al almacenar internamente.


aa — Dump completo de un módulo (módulo cargado/recargado)

Enviado cuando un módulo se carga o recarga en tiempo de ejecución. Contiene el estado completo del módulo. La clave empieza por "aa".

{
  "aa-dump all data": {
    "Guider": {
      "infos": { "modulelabel": "Guider", "description": "..." },
      "f": { "name": "default", "changed": false },
      "l": {},
      "p": {
        "status": { ... }
      }
    }
  }
}

ap — Reemplazo completo de una propiedad

Reemplaza por completo una o varias propiedades. La clave empieza por "ap".

{
  "ap-dump all property data": {
    "Focus": {
      "p": {
        "parameters": {
          "label": "Parameters",
          "status": 0,
          "permission": 2,
          "enabled": true,
          "showElts": true,
          "hasGrid": false,
          "hasGraph": false,
          "rule": 0,
          "e": {
            "iterations": {
              "type": "int",
              "value": 7,
              "min": 1, "max": 20, "step": 1,
              "label": "Iterations", "order": "10", "hint": "",
              "autoupdate": false, "badge": false, "directedit": false,
              "format": "", "slider": 0
            }
          }
        }
      }
    }
  }
}

ea — Actualización de todos los valores de elementos (nivel propiedad)

El mensaje de actualización más común. Envía los valores actuales de todos los elementos de una propiedad. Solo contiene los valores — sin metadatos. La clave es exactamente "ea".

{
  "ea": {
    "Allsky": {
      "p": {
        "coming": {
          "e": {
            "sunrise": { "hh": 7, "mm": 6, "ss": 51 },
            "sunset":  { "hh": 21, "mm": 15, "ss": 1 }
          }
        }
      }
    }
  }
}

Para los tipos simples (int, float, bool, string, light), el valor es un escalar:

{
  "ea": {
    "Focus": {
      "p": {
        "parameters": {
          "e": {
            "iterations": 5,
            "exposure": 3.5,
            "active": true
          }
        }
      }
    }
  }
}

ee — Actualización de un solo valor de elemento

Actualiza el valor de un solo elemento. Mismo formato que ea pero para un solo elemento. La clave es exactamente "ee".

{
  "ee": {
    "Focus": {
      "p": {
        "parameters": {
          "e": {
            "iterations": 7
          }
        }
      }
    }
  }
}
ee solo tiene origen en el backend

ee solo se envía por iniciativa propia del backend (ej. un cambio de valor originado por un dispositivo, un sondeo interno) — nunca como respuesta directa a una escritura del cliente. Cualquier respuesta a un SV o SA iniciado por el cliente es siempre un ea de toda la propiedad, sin importar cuántos elementos hayan cambiado realmente.


ev — Actualización de un elemento con metadatos

Actualiza el valor de un elemento y sus restricciones (min, max, format). La clave empieza por "ev".

{
  "ev-set one element value/min/max/format ": {
    "Focus": {
      "p": {
        "parameters": {
          "e": {
            "temperature": {
              "value": 12.5,
              "min": -40.0,
              "max": 80.0,
              "format": "%.1f"
            }
          }
        }
      }
    }
  }
}

el — LOV local cambiada

Enviado cuando la lista de valores local propia de un elemento (listOfValues) se añade, actualiza o vacía por iniciativa propia del servidor — p. ej. los nombres de las posiciones de una rueda de filtros (re)leídos desde el dispositivo. La clave empieza por "el". Mismo formato de payload que ev (se incluyen el valor actual, las restricciones y listOfValues), pero a diferencia de ev esto nunca marca el perfil de una propiedad hasprofile como modificado (fc): una LOV local es decorativa, no un valor de perfil almacenado.

{
  "el-element's own local lov changed": {
    "Sequencer": {
      "p": {
        "sequence": {
          "e": {
            "filter": {
              "value": 1,
              "listOfValues": { "1": "Luminance", "2": "Red", "3": "Green", "4": "Blue" }
            }
          }
        }
      }
    }
  }
}

ps — Actualización del estado de una propiedad

Actualiza únicamente los campos status y enabled de una propiedad. La clave empieza por "ps".

{
  "ps-only property state": {
    "Focus": {
      "p": {
        "autofocus": {
          "status": 2,
          "enabled": true
        }
      }
    }
  }
}

Valores de estado: 0 Reposo · 1 OK · 2 Ocupado · 3 Error


dm — Módulo eliminado

Enviado cuando un módulo se descarga. El cliente debe eliminar todos los datos de ese módulo. La clave empieza por "dm".

{
  "dm-delete/remove module": {
    "Focus": {}
  }
}

dp — Propiedad eliminada

Enviado cuando una propiedad se elimina de un módulo. La clave empieza por "dp".

{
  "dp-delete/remove property": {
    "Focus": {
      "p": {
        "oldProperty": ""
      }
    }
  }
}

gc — Línea de cuadrícula creada

Enviado tras añadir una nueva línea en una propiedad de tipo cuadrícula. La clave empieza por "gc".

{
  "gc-grid new line ": {
    "Sequencer": {
      "p": {
        "sequence": {
          "i": 3,
          "values": {
            "target": "M31",
            "exposure": 120,
            "count": 10
          }
        }
      }
    }
  }
}

i es el índice de la línea recién creada. values es un objeto indexado por nombre de elemento.


gu — Línea de cuadrícula actualizada

Enviado cuando se modifica una línea existente de la cuadrícula. La clave empieza por "gu".

{
  "gu-grid update line": {
    "Sequencer": {
      "p": {
        "sequence": {
          "i": 1,
          "values": {
            "target": "M42",
            "exposure": 60,
            "count": 20
          }
        }
      }
    }
  }
}

gd — Línea de cuadrícula eliminada

Enviado cuando se elimina una línea de la cuadrícula. La clave empieza por "gd".

{
  "gd-grid delete line": {
    "Sequencer": {
      "p": {
        "sequence": {
          "i": 0
        }
      }
    }
  }
}

i es el índice (base cero) de la línea eliminada. Las líneas siguientes se desplazan una posición hacia arriba.


gr — Reinicio de la cuadrícula

Borra la totalidad de la cuadrícula de una propiedad. La clave empieza por "gr".

{
  "gr-grid reset": {
    "Sequencer": {
      "p": {
        "sequence": {}
      }
    }
  }
}

lc / lu / ld — Eventos LOV

lc — LOV creado/fusionado (clave empieza por "lc"):

LOV de módulo:

{
  "lc-lov create": {
    "Focus": {
      "l": {
        "myLov": {
          "label": "My LOV",
          "type": "string",
          "values": { "a": "Option A", "b": "Option B" }
        }
      }
    }
  }
}

LOV del controlador (sin envoltura de módulo, usa la clave lovs):

{
  "lc-lov create": {
    "lovs": {
      "sharedLov": {
        "label": "Shared LOV",
        "type": "string",
        "values": { "x": "Value X" }
      }
    }
  }
}

lu — LOV reemplazado (mismo formato que lc, reemplazo completo).

ld — LOV eliminado (clave empieza por "ld"):

{
  "ld-lov delete": {
    "lovs": {
      "sharedLov": {}
    }
  }
}

fs / fl / fc — Eventos de perfil

Enviados cuando un perfil se guarda, carga o modifica.

{
  "fs-profile saved": {
    "Focus": {
      "f": { "name": "myProfile", "changed": false }
    }
  }
}
Prefijo de claveEvento
fsPerfil guardado
flPerfil cargado
fcPerfil con modificaciones no guardadas

l — Entrada de log

Enviado para cada mensaje de log generado por el servidor. La clave es exactamente "l".

{
  "l": {
    "d": "2024-01-01T12:00:00.000",
    "c": "Focus",
    "t": "Autofocus completed successfully",
    "l": 1
  }
}
CampoDescripción
dFecha/hora ISO 8601 con milisegundos
cContexto/origen (nombre del módulo o "WS")
tTexto del mensaje (traducido al idioma del cliente)
lNivel: 0 Debug · 1 Info · 2 Advertencia · 3 Error · 4 Crítico

uc — Actualización de los datos del controlador

Enviado cuando cambian los datos globales del controlador: perfiles, configuraciones, drivers INDI activos, listas de archivos (files, folders), carga del sistema (systemwatcher, cada 10 s por defecto). La clave empieza por "uc". Las claves posibles se describen en Controlador, GlobalDatastore y archivos.

{
  "uc-update controller data": {
    "profiles": {
      "Focus": ["default", "highres"],
      "Guider": ["default"]
    }
  }
}

El payload es {"clave": valor} donde valor puede ser una cadena, un array o un objeto. Cada mensaje lleva una sola clave, y su valor reemplaza por completo al anterior.


af / df / ad / dd — Eventos de archivo y de carpeta

Enviado a todos los clientes cuando cambia el contenido de la carpeta de archivos vigilada (ver Sistema de archivos). A diferencia de los demás mensajes, el valor es una cadena simple: la ruta afectada, sin envolver en un objeto ni en un array — el servidor solo reporta una ruta por mensaje.

{ "af": "/Allsky/image_001.jpeg" }
{ "df": "/Allsky/old_image.jpeg" }
ClaveSignificado
afArchivo añadido a la carpeta seleccionada
dfArchivo eliminado de la carpeta seleccionada
adSubcarpeta añadida en cualquier parte del webroot
ddSubcarpeta eliminada de cualquier parte del webroot

af/df solo conciernen a la carpeta actualmente seleccionada vía FS — no se notifica nada sobre el contenido de otras carpetas. ad/dd son globales: se disparan para todo el árbol del webroot, sea cual sea la carpeta actualmente seleccionada. Ver Sistema de archivos para el panorama completo.


qa — Respuesta a una consulta de módulo

Comunicación inter-módulo, no una funcionalidad de cliente

Ver la nota sobre QY: este mecanismo existe principalmente para que un módulo consulte a otro internamente. Documentado aquí por exhaustividad, no como funcionalidad pensada para el cliente.

Respuesta a una consulta QY. QY/qa es un mecanismo genérico de consulta/respuesta propio de cada módulo: un cliente (u otro módulo, internamente) hace a un módulo una pregunta con nombre y parámetros, y recibe una respuesta con nombre a cambio. Qué nombres de consulta entiende realmente un módulo, y la forma de su respuesta, depende enteramente de ese módulo — el protocolo solo define el sobre, no el contenido.

{
  "qa-query answer": {
    "Sequencer": {
      "q": {
        "query": "profileduration",
        "result": { "seconds": 3600 }
      }
    }
  }
}

result es lo que el módulo devolvió para esa consulta — su forma depende enteramente de query. Un módulo sin un caso que coincida con el nombre de query solicitado devuelve silenciosamente un result vacío.

Todavía poco que ver

Hoy solo el módulo Sequencer implementa una respuesta real (profileduration), usada internamente por el módulo Planner en lugar de por ningún flujo de cliente documentado. Ningún otro módulo incluido responde de forma significativa a ningún nombre de consulta por ahora — el mecanismo existe y está completamente cableado, pero de momento hay poco que consultar en la práctica.


xx — Pong keepalive

Enviado por el servidor en respuesta a un heartbeat de cliente (XX). Sin payload útil; los clientes pueden ignorarlo.

{ "xx": {} }