Saltar al contenido principal

Remote Plugin

aviso

Por motivos técnicos, el código fuente completo de estos ejemplos no puede mostrarse aquí.
Visite nuestro repositorio de GitHub con más ejemplos y el código fuente completo.

El "optiMEAS Remote Plugin Module" es una herramienta muy flexible para conectar aplicaciones externas al sistema smartCORE, basada en protocolos de comunicación y tecnologías modernos. La comunicación subyacente se realiza mediante el protocolo UDP (User Datagram Protocol), conocido por su baja latencia y eficiencia, especialmente en aplicaciones en tiempo real. El módulo utiliza el formato MsgPack para la serialización y deserialización eficientes de datos, lo que permite una transmisión de datos compacta y rápida. La interfaz para la comunicación con el sistema smartCORE se realiza mediante IPC (comunicación entre procesos), y la configuración de los canales de productor y de consumidor puede adaptarse individualmente. Esto permite la integración y el control de software externo en tiempo real y facilita la ampliación flexible de los sistemas existentes. La documentación ofrece ejemplos detallados para facilitar el desarrollo de plugins propios, de modo que los requisitos específicos puedan implementarse de forma sencilla y eficiente. Gracias al empleo de estas tecnologías, el módulo ofrece una solución robusta y escalable para la comunicación entre smartCORE y procesos externos, ideal para aplicaciones en entornos industriales exigentes.

Notas sobre el desarrollo de scripts:

  • Si trabaja en Windows, asegúrese de que los scripts contengan solo \n, no \r\n

Tutoriales​

Desarrollo en un PC externo
Plugin sencillo de escritura de datos
Plugin de lectura y escritura de datos
[Avanzado] Instalación de nuevas bibliotecas de Python (p. ej., NumPy)

Configuración JSON​

Configuración de los parámetros de red​

Palabra claveExplicación
portPuerto UDP en el que escucha el plugin (por defecto: 61616)
localhostRestricción a la comunicación "solo localhost" (por defecto: true)

Configuración del control de procesos​

NombreExplicación
enableDetermina si el proceso debe iniciarse y supervisarse (por defecto: false)
logOutputIncorporar la salida (stdout y stderr) del proceso al archivo de registro de smartCORE (por defecto: true)
watchdogTimeoutTiempo máximo entre 2 mensajes IPC hasta el REINICIO del proceso
disableKillAllProcessesDesactivar la finalización de todos los procesos al iniciar o en caso de problemas (por defecto: false)
commandNombre (con ruta opcional) del proceso
argumentsArgumentos de línea de comandos del proceso

Configuración de los Producer Channels ( producerChannels )​

Palabra claveExplicación
nameNombre del canal
dataTypeTipo de datos del canal
physicalUnitUnidad del canal

Configuración del Consumer Channels ( consumerChannels )​

Palabra claveExplicación
nameNombre del canal que se va a leer

Configuración de ejemplo​

{
"module": "remote",
"factory": "remote",
"config": {
"port": 61616,
"localhost": true,
"process":
{
"enable": true,
"logOutput": false,
"watchdogTimeout": 60,
"disableKillAllProcesses": false,
"command": "i2c-sen5x-cpp",
"arguments": "--device-path=/dev/i2c-1 --interval=1"
},
"producerChannels": [
{
"name": "sen5x_pm1p0",
"dataType": "float",
"physicalUnit": "ug/m^3"
},
{
"name": "sen5x_pm2p5",
"dataType": "float",
"physicalUnit": "ug/m^3"
}
],
"consumerChannels": [
{
"name": "scd40_co2"
}
]
}
}

API/Protocolo​

El protocolo consta de una cabecera en su mayor parte estática, en la que se especifica un código de comando, y (si es necesario) una carga útil JSON.

Cabecera​

Metadatos de la cabecera​

Desplazamiento y tipo de datosNombreDescripción
[0] uint32_tmagicTokenReconocimiento del protocolo (fijo 0x45554C42)
[4] uint8_tversionVersión del protocolo (actualmente siempre 1; abierta a ampliaciones)
[5] uint8_tpayloadTypeCompatibilidad y distinción de distintos tipos de carga útil (aquí actualmente siempre 2)
[6] uint16_treservedReservado para ampliaciones futuras (el tamaño de la cabecera debe ser divisible por 4)
[8] uint64_tsenderPidID del proceso emisor
[16] uint64_tsenderTime_msSEInstante en milisegundos en que se envió el paquete (con fines de diagnóstico)
[24] uint16_tgroupIdentificador del servicio al que iba dirigida la llamada RPC o del que procede la respuesta (aquí fijo 1000)
[26] uint16_tcommandNúmero de la llamada RPC (véase la tabla siguiente)

Comandos​

N.º de comandoDenominaciónExplicación
0LifeSignRequestConsulta del estado de smartCORE
1LifeSignResponseRespuesta a LifeSignRequest
100WriteSamplesByNameEnviar muestras individuales con el nombre del canal
101ReadSamplesByNameRequestConsulta de canales individuales mediante nombres de canal
102ReadSamplesByNameResponseRespuesta a ReadSamplesByNameRequest (valores medidos)
200ChannelListRequestConsulta de la lista de canales (asignación nombre de canal => índice)
201ChannelListResponseRespuesta a ChannelListRequest (lista de canales)
202WriteSamplesRequestEnviar muestras (opcionalmente con marca de tiempo) mediante índice
203WriteSamplesResponseRespuesta opcional a WriteSamplesRequest si se ha pasado un token de confirmación
204ReadSamplesBeginActivación del envío cíclico de valores medidos por parte de smartCORE
205ReadSamplesContentValores medidos del envío cíclico
206ReadSamplesEndDesactivación del envío cíclico
300AlarmMessageRequestEscritura de una alarma en la central de alarmas de smartCORE
301AlarmMessageResponseConfirmación de AlarmMessageRequest

Estructura de la carga útil (contenido JSON)​

Comandos byName​

Escribir valores en smartCORE​

RPC: WriteSamplesByName (Cliente => smartCORE)

ParámetroDescripción
cArray de canales
nNombre del canal
vValor medido
tMarca de tiempo (opcional)
{
"c": [
{
"n": "sen5x_pm1p0",
"v": 1.0099999904632568,
"t": 1720074467000000
},
{
"n": "sen5x_pm2p5",
"v": 2.009999990463257,
"t": 1720074467000000
}
]
}
Leer valores de smartCORE (polling)​

RPC: ReadSamplesByNameRequest (Cliente => smartCORE)

ParámetroDescripción
cArray de nombres de canal
{
"c": [
"sen5x_pm1p0",
"sen5x_pm2p5"
]
}

RPC: ReadSamplesByNameResponse (smartCORE => Cliente)

ParámetroDescripción
cArray de canales
nNombre del canal
vValor medido
tMarca de tiempo
{
"c": [
{
"n": "sen5x_pm1p0",
"v": 1.0099999904632568,
"t": 1720074467000000
},
{
"n": "sen5x_pm2p5",
"v": 2.009999990463257,
"t": 1720074467000000
}
]
}

Comandos byIndex​

Consultar la lista de canales​

RPC: ChannelListRequest (Cliente => smartCORE)

Aquí se puede enviar una solicitud vacía para consultar los nombres de todos los canales. Alternativamente, también pueden consultarse solo nombres de canal seleccionados:

ParámetroDescripción
cArray de nombres de canal
fConsulta de campos especiales, p. ej. "d" (tipo de datos) [opcional]
{
"f": [
"d"
],
"c": [
"sen5x_pm1p0",
"sen5x_pm2p5"
]
}

RPC: ChannelListResponse (smartCORE => Cliente)

ParámetroDescripción
cArray de canales
nNombre del canal
iÍndice del canal
wEscribible (canal Producer) [si es false, no está presente]
dTipo de datos (opcional; si se ha solicitado)
{
"c": [
{
"n": "sen5x_pm1p0",
"i": 0,
"w": true,
"d": "float"
},
{
"n": "sen5x_pm2p5",
"i": 1,
"d": "int32"
}
]
}
Escribir valores en smartCORE​

RPC: WriteSamplesRequest (Cliente => smartCORE)

Aquí hay tres cargas útiles posibles:

  • muestras individuales por canal
  • varias muestras con marca de tiempo por canal
  • muestras equidistantes por canal
ParámetroDescripción
aToken para recibir un paquete de confirmación (Acknowledge) (opcional)
cArray de canales
iÍndice del canal
vValor medido
tMarca de tiempo (opcional)
sDiferencia de tiempo en muestras equidistantes

Variante de carga útil 1: muestras individuales por canal

{
"a": "xyz",
"t": 1720074467000000,
"c": [
{
"i": 0,
"v": 1.0099999904632568,
"t": 1720074467000000
},
{
"i": 1,
"v": 2.009999990463257,
}
]
}

Variante de carga útil 2: varias muestras con marca de tiempo por canal

{
"a": "xyz",
"c": [
{
"i": 0,
"v": [
1,
2,
3
],
"t": [
1720074467000000,
1720074467000100,
1720074467000200
]
},
{
"i": 1,
"v": [
1,
2,
3
],
"t": 1720074467000000,
"s": 200
}
]
}

Variante de carga útil 3: muestras equidistantes por canal

{
"a": "xyz",
"t": 1720074467000000,
"s": 200,
"c": [
{
"i": 0,
"v": [
1,
2,
3
],
"t": 1720074467000000,
"s": 200
},
{
"i": 1,
"v": [
1,
2,
3
]
}
]
}

RPC: WriteSamplesResponse (smartCORE => Cliente)

Si en el paquete de solicitud se indicó un token, smartCORE envía un paquete con el token como confirmación.

ParámetroDescripción
aToken del paquete de solicitud
{
"a": "xyz"
}
Leer valores de smartCORE de forma continua​

RPC: ReadSamplesBegin (Cliente => smartCORE)

ParámetroDescripción
tTiempo en milisegundos entre dos paquetes (intervalo de envío)
nNúmero deseado de muestras (número de intervalos de consumo idénticos por intervalo de envío)
eEquidistante (sin transmisión de las marcas de tiempo)
cLista de índices de canal
{
"t": 100,
"n": 10,
"e": true,
"c": [
2,
5
]
}

RPC: ReadSamplesContent (smartCORE => Cliente)

ParámetroDescripción
xíndice de paquete correlativo desde el inicio (p. ej., para detectar pérdida de datos)
cArray de canales
iÍndice del canal
vValor medido
tMarca de tiempo

Notas:

  • Si hay disponibles menos muestras que el número deseado, solo se transmiten las muestras disponibles.
  • Si no hay ninguna muestra actual disponible, solo se envía el "Last Value" (último valor).

Variante de carga útil 1: con marca de tiempo ( e = "false")

{
"x": 123,
"c": [
{
"i": 2,
"v": [
1.0099999904632568,
5.009999990463257,
6.009999990463257
],
"t": [
1720074467000000,
1720074467000100,
1720074467000200
]
},
{
"i": 5,
"v": [
1.0099999904632568,
5.009999990463257,
6.009999990463257
],
"t": [
1720074467000000,
1720074467000100,
1720074467000200
]
}
]
}

Variante de carga útil 2: sin marca de tiempo ( e = "true")

{
"x": 123,
"t": 1720074467000000,
"s": 100,
"c": [
{
"i": 2,
"v": [
1.0099999904632568,
5.0099999904632568,
6.0099999904632568
]
},
{
"i": 5,
"v": [
1.0099999904632568,
5.0099999904632568,
6.0099999904632568
]
}
]
}

RPC: ReadSamplesEnd (Cliente => smartCORE)

Solicitud vacía para desactivar la transmisión.