Remote Plugin
Per motivi tecnici il codice sorgente completo di questi esempi non può essere visualizzato qui.
Visitare il nostro repository GitHub per ulteriori esempi e il codice sorgente completo.
L'"optiMEAS Remote Plugin Module" è uno strumento altamente flessibile per il collegamento di applicazioni esterne al sistema smartCORE, basato su moderni protocolli di comunicazione e tecnologie. La comunicazione sottostante avviene tramite il protocollo UDP (User Datagram Protocol), noto per la sua bassa latenza e la sua efficienza, in particolare nelle applicazioni in tempo reale. Il modulo utilizza il formato MsgPack per la serializzazione e la deserializzazione efficienti dei dati, consentendo una trasmissione dei dati compatta e rapida. L'interfaccia per la comunicazione con il sistema smartCORE avviene tramite IPC (comunicazione interprocesso), e la configurazione dei canali producer e consumer può essere adattata individualmente. Ciò consente l'integrazione e il controllo di software esterno in tempo reale e supporta l'estensione flessibile dei sistemi esistenti. La documentazione mette a disposizione esempi dettagliati per facilitare lo sviluppo di plug-in propri, in modo da poter implementare in modo semplice ed efficiente requisiti specifici. Grazie all'impiego di queste tecnologie, il modulo offre una soluzione robusta e scalabile per la comunicazione tra smartCORE e processi esterni, ideale per applicazioni in ambienti industriali impegnativi.
Note sullo sviluppo di script:
- Se si lavora su Windows, assicurarsi che gli script contengano solo
\ne non\r\n
Tutorial
Sviluppo su PC esterno
Semplice plug-in per la scrittura di dati
Plug-in per la lettura e la scrittura di dati
[Avanzato] Installazione di nuove librerie Python (ad es. NumPy)
Configurazione JSON
Configurazione dei parametri di rete
| Parola chiave | Spiegazione |
|---|---|
| port | Porta UDP su cui il plug-in è in ascolto (default: 61616) |
| localhost | Limitazione alla comunicazione "solo localhost" (default: true) |
Configurazione del controllo dei processi
| Nome | Spiegazione |
|---|---|
| enable | Stabilisce se il processo deve essere avviato e monitorato (default: false) |
| logOutput | Riporta l'output (stdout e stderr) del processo nel file di log di smartCORE (default: true) |
| watchdogTimeout | Tempo massimo tra 2 messaggi IPC prima del RESTART del processo |
| disableKillAllProcesses | Disattiva la terminazione di tutti i processi all'avvio o in caso di problemi (default: false) |
| command | Nome (con percorso opzionale) del processo |
| arguments | Argomenti della riga di comando per il processo |
Configurazione dei Producer Channel ( producerChannels )
| Parola chiave | Spiegazione |
|---|---|
| name | Nome del canale |
| dataType | Tipo di dati del canale |
| physicalUnit | Unità del canale |
Configurazione dei Consumer Channel ( consumerChannels )
| Parola chiave | Spiegazione |
|---|---|
| name | Nome del canale che deve essere letto |
Configurazione di esempio
{
"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/Protocollo
Il protocollo è costituito da un header in gran parte statico, in cui viene specificato un codice di comando, e (se necessario) da un payload JSON.
Header
Metadati dell'header
| Offset e tipo di dati | Nome | Descrizione |
|---|---|---|
| [0] uint32_t | magicToken | Riconoscimento del protocollo (fisso 0x45554C42) |
| [4] uint8_t | version | Versione del protocollo (attualmente sempre 1; aperta a estensioni) |
| [5] uint8_t | payloadType | Supporto e distinzione di diversi tipi di payload (qui attualmente sempre 2) |
| [6] uint16_t | reserved | Riservato per estensioni future (la dimensione dell'header deve essere divisibile per 4) |
| [8] uint64_t | senderPid | ID di processo del processo mittente |
| [16] uint64_t | senderTime_msSE | Istante in millisecondi in cui il pacchetto è stato inviato (a scopo diagnostico) |
| [24] uint16_t | group | Identificativo del servizio a cui era diretta la chiamata RPC o da cui proviene la risposta (qui fisso 1000) |
| [26] uint16_t | command | Numero della chiamata RPC (vedere la tabella seguente) |
Comandi
| N. comando | Denominazione | Spiegazione |
|---|---|---|
| 0 | LifeSignRequest | Interrogazione dello stato di smartCORE |
| 1 | LifeSignResponse | Risposta a LifeSignRequest |
| 100 | WriteSamplesByName | Invio di singoli campioni con nome del canale |
| 101 | ReadSamplesByNameRequest | Interrogazione di singoli canali tramite nome del canale |
| 102 | ReadSamplesByNameResponse | Risposta a ReadSamplesByNameRequest (valori misurati) |
| 200 | ChannelListRequest | Interrogazione dell'elenco dei canali (associazione nome del canale => indice) |
| 201 | ChannelListResponse | Risposta a ChannelListRequest (elenco dei canali) |
| 202 | WriteSamplesRequest | Invio di campioni (opzionalmente con timestamp) tramite indice |
| 203 | WriteSamplesResponse | Risposta opzionale a WriteSamplesRequest se è stato passato un token di conferma |
| 204 | ReadSamplesBegin | Attivazione dell'invio ciclico dei valori misurati da parte di smartCORE |
| 205 | ReadSamplesContent | Valori misurati dell'invio ciclico |
| 206 | ReadSamplesEnd | Disattivazione dell'invio ciclico |
| 300 | AlarmMessageRequest | Scrittura di un allarme nella centrale allarmi di smartCORE |
| 301 | AlarmMessageResponse | Conferma di AlarmMessageRequest |
Struttura del payload (contenuto JSON)
Comandi byName
Scrittura di valori in smartCORE
RPC: WriteSamplesByName (Client => smartCORE)
| Parametro | Descrizione |
|---|---|
| c | Array dei canali |
| n | Nome del canale |
| v | Valore misurato |
| t | Timestamp (opzionale) |
{
"c": [
{
"n": "sen5x_pm1p0",
"v": 1.0099999904632568,
"t": 1720074467000000
},
{
"n": "sen5x_pm2p5",
"v": 2.009999990463257,
"t": 1720074467000000
}
]
}
Lettura di valori da smartCORE (polling)
RPC: ReadSamplesByNameRequest (Client => smartCORE)
| Parametro | Descrizione |
|---|---|
| c | Array dei nomi dei canali |
{
"c": [
"sen5x_pm1p0",
"sen5x_pm2p5"
]
}
RPC: ReadSamplesByNameResponse (smartCORE => Client)
| Parametro | Descrizione |
|---|---|
| c | Array dei canali |
| n | Nome del canale |
| v | Valore misurato |
| t | Timestamp |
{
"c": [
{
"n": "sen5x_pm1p0",
"v": 1.0099999904632568,
"t": 1720074467000000
},
{
"n": "sen5x_pm2p5",
"v": 2.009999990463257,
"t": 1720074467000000
}
]
}
Comandi byIndex
Interrogazione dell'elenco dei canali
RPC: ChannelListRequest (Client => smartCORE)
Qui è possibile inviare una richiesta vuota per interrogare i nomi di tutti i canali. In alternativa è possibile richiedere anche solo i nomi di canali selezionati:
| Parametro | Descrizione |
|---|---|
| c | Array dei nomi dei canali |
| f | Richiesta di campi speciali, ad es. "d" (tipo di dati) [opzionale] |
{
"f": [
"d"
],
"c": [
"sen5x_pm1p0",
"sen5x_pm2p5"
]
}
RPC: ChannelListResponse (smartCORE => Client)
| Parametro | Descrizione |
|---|---|
| c | Array dei canali |
| n | Nome del canale |
| i | Indice del canale |
| w | Scrivibile (canale producer) [assente se false] |
| d | Tipo di dati (opzionale; se richiesto) |
{
"c": [
{
"n": "sen5x_pm1p0",
"i": 0,
"w": true,
"d": "float"
},
{
"n": "sen5x_pm2p5",
"i": 1,
"d": "int32"
}
]
}
Scrittura di valori in smartCORE
RPC: WriteSamplesRequest (Client => smartCORE)
Qui sono possibili tre payload:
- singoli campioni per canale
- più campioni con timestamp per canale
- campioni equidistanti per canale
| Parametro | Descrizione |
|---|---|
| a | Token per ricevere un pacchetto di acknowledge (opzionale) |
| c | Array dei canali |
| i | Indice del canale |
| v | Valore misurato |
| t | Timestamp (opzionale) |
| s | Differenza di tempo per campioni equidistanti |
Payload variante 1: singoli campioni per canale
{
"a": "xyz",
"t": 1720074467000000,
"c": [
{
"i": 0,
"v": 1.0099999904632568,
"t": 1720074467000000
},
{
"i": 1,
"v": 2.009999990463257,
}
]
}
Payload variante 2: più campioni con timestamp per canale
{
"a": "xyz",
"c": [
{
"i": 0,
"v": [
1,
2,
3
],
"t": [
1720074467000000,
1720074467000100,
1720074467000200
]
},
{
"i": 1,
"v": [
1,
2,
3
],
"t": 1720074467000000,
"s": 200
}
]
}
Payload variante 3: campioni equidistanti per canale
{
"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 => Client)
Se nel pacchetto di richiesta è stato indicato un token, smartCORE invia un pacchetto con il token come conferma.
| Parametro | Descrizione |
|---|---|
| a | Token dal pacchetto di richiesta |
{
"a": "xyz"
}
Lettura continua di valori da smartCORE
RPC: ReadSamplesBegin (Client => smartCORE)
| Parametro | Descrizione |
|---|---|
| t | Tempo in millisecondi tra due pacchetti (intervallo di invio) |
| n | Numero di campioni desiderato (numero di intervalli di consumo identici per intervallo di invio) |
| e | Equidistante (senza trasmissione dei timestamp) |
| c | Elenco degli indici dei canali |
{
"t": 100,
"n": 10,
"e": true,
"c": [
2,
5
]
}
RPC: ReadSamplesContent (smartCORE => Client)
| Parametro | Descrizione |
|---|---|
| x | indice progressivo del pacchetto dall'inizio (ad es. per rilevare la perdita di dati) |
| c | Array dei canali |
| i | Indice del canale |
| v | Valore misurato |
| t | Timestamp |
Note:
- Se sono disponibili meno campioni del numero desiderato, vengono trasmessi solo i campioni disponibili.
- Se non è disponibile alcun campione aggiornato, viene inviato solo l'"Last Value".
Payload variante 1: con timestamp ( 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
]
}
]
}
Payload variante 2: senza timestamp ( 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 (Client => smartCORE)
Richiesta vuota per disattivare la trasmissione.