Skip to main content

Remote Plugin

warning

For technical reasons, the complete source code of these examples cannot be displayed here.
Please visit our Github repository for more examples and full source code.

The "optiMEAS Remote Plugin Module" is a highly flexible tool for connecting external applications to the smartCORE system, based on modern communication protocols and technologies. The underlying communication takes place via the UDP protocol (User Datagram Protocol), which is known for its low latency and efficiency, especially in real-time applications. The module uses the MsgPack format for efficient serialization and deserialization of data, enabling compact and fast data transmission. The interface for communication with the smartCORE system is via IPC (inter-process communication), whereby the configuration of producer and consumer channels can be individually adapted. This enables the integration and control of external software in real time and supports the flexible expansion of existing systems. The documentation provides detailed examples to facilitate the development of your own plug-ins, allowing specific requirements to be implemented easily and efficiently. By using these technologies, the module provides a robust and scalable solution for communication between smartCORE and external processes, ideal for applications in demanding industrial environments.

Notes on script development:

  • If you are working on Windows, make sure that scripts only contain \n, not \r\n

Tutorials

Development on external PC Simple data-write plugin Data read and write plugin [Advanced] Installation of new Python libraries (e.g. NumPy)

JSON configuration

Configuration of the network parameters

KeywordExplanation
portUDP port on which the plugin listens (default: 61616)
localhostRestriction to "localhost only" communication (default: true)

Configuration of the process control

NameExplanation
enableDefines whether the process should be started and monitored (default: false)
logOutputTransfer output (stdout & stderr) of the process to the smartCORE log file (default: true)
watchdogTimeoutMaximum time between 2x IPC messages until RESTART of the process
disableKillAllProcessesDisable all processes at startup or in case of problems (default: false)
commandName (with optional path) of the process
argumentsCommand line arguments for the process

Configuration of the producer channels ( producerChannels )

keywordexplanation
nameName of the channel
dataTypeData type of the channel
physicalUnitUnit of the channel

Configuration of the consumer channel ( consumerChannels )

KeywordExplanation
nameName of the channel to be read

Example configuration

{
"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": "µg/m³"
},
{
"name": "sen5x_pm2p5",
"dataType": "float",
"physicalUnit": "µg/m³"
}
],
"consumerChannels": [
{
"name": "scd40_co2"
}
]
}
}

API/Protocol

The protocol consists of a mostly static header, in which a command code is specified, and (if necessary) a JSON payload.

Header metadata

Offset and data typeNameDescription
[0] uint32_tmagicTokenRecognition of the protocol (fixed 0x45554C42)
[4] uint8_tversionProtocol version (currently always 1; open for extensions)
[5] uint8_tpayloadTypeSupport and differentiation of different payload types (currently always 2)
[6] uint16_treservedReserved for later extensions (header size should be divisible by 4)
8] uint64_tsenderPidProcess ID of the sending process
[16] uint64_tsenderTime_msSETime in milliseconds when the packet was sent (for diagnostic purposes)
[24] uint16_tgroupIdentifier of the service to which the RPC call was sent or from which the response came (here fixed at 1000)
[26] uint16_tcommandNumber of the RPC call (see following table)

Commands

Command-NoNameExplanation
0LifeSignRequestsmartCORE Status Request
1LifeSignResponseResponse to LifeSignRequest
100WriteSamplesByNameSend individual samples with channel name
101ReadSamplesByNameRequestQuery individual channels by channel name
102ReadSamplesByNameResponseResponse to ReadSamplesByNameRequest (measured values)
200ChannelListRequestQuery channel list (assignment of channel name => index)
201ChannelListResponseResponse to ChannelListRequest (channel list)
202WriteSamplesRequestSend samples (optionally with timestamp) via index
203WriteSamplesResponseOptional response to WriteSamplesRequest if a token was passed for confirmation
204ReadSamplesBeginSwitching on the cyclical sending of measured values by the smartCORE
205ReadSamplesContentMeasured values of the cyclical transmission
206ReadSamplesEndSwitch off cyclical transmission
300AlarmMessageRequestWriting an alarm to the smartCORE alarm center
301AlarmMessageResponseConfirmation of AlarmMessageRequest

Payload structure (JSON content)

byName Commands

Write values in smartCORE

RPC: WriteSamplesByName (Client => smartCORE)

ParametersDescription
cArray of channels
nchannel name
vMeasured value
tTime Stamp (optional)
{
"c": [
{
"n": "sen5x_pm1p0",
"v": 1.0099999904632568,
"t": 1720074467000000
},
{
"n": "sen5x_pm2p5",
"v": 2.009999990463257,
"t": 1720074467000000
}
]
}
Read values from smartCORE (polling)

RPC: ReadSamplesByNameRequest (Client => smartCORE)

ParametersDescription
cArray of channel names
{
"c": [
"sen5x_pm1p0",
"sen5x_pm2p5"
]
}

RPC: ReadSamplesByNameResponse (smartCORE => Client)

ParametersDescription
cArray of channels
nchannel name
vMeasured value
tTime Stamp
{
"c": [
{
"n": "sen5x_pm1p0",
"v": 1.0099999904632568,
"t": 1720074467000000
},
{
"n": "sen5x_pm2p5",
"v": 2.009999990463257,
"t": 1720074467000000
}
]
}

byIndex Commands

Query channel list

RPC: ChannelListRequest (Client => smartCORE)

An empty request can be sent here to request the names of all channels. Alternatively, only selected channel names can be requested:

ParametersDescription
cArray of channel names
fRequest special fields such as "d" (data type) [optional]
{
"f": [
"d"
],
"c": [
"sen5x_pm1p0",
"sen5x_pm2p5"
]
}

RPC: ChannelListResponse (smartCORE => Client)

ParametersDescription
cArray of channels
nchannel name
iIndex of the channel
wWritable (producer channel) [not available if false]
dData type (optional; if requested)
{
"c": [
{
"n": "sen5x_pm1p0",
"i": 0,
"w": true,
"d": "float"
},
{
"n": "sen5x_pm2p5",
"i": 1,
"d": "int32"
}
]
}
Write values in smartCORE

RPC: WriteSamplesRequest (Client => smartCORE)

There are three possible payloads here:

  • single samples per channel
  • Multiple samples with time stamps per channel
  • Equidistant samples per channel
ParametersDescription
aToken to receive acknowledge packet (optional)
cArray of channels
ichannel index
vMeasured value
tTime stamp (optional)
sDifferent time for equidistant samples

Payload variant 1: individual samples per channel

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

Payload variant 2: Multiple samples with time stamp per channel

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

Payload variant 3: Equidistant samples per channel

{
"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)

If a token was specified in the request packet, the smartCORE sends a packet with the token for confirmation.

ParametersDescription
aToken from the request packet
{
"a": "xyz"
}
Read continuous values from smartCORE

RPC: ReadSamplesBegin (Client => smartCORE)

ParametersDescription
tTime in milliseconds between two packets (sending interval)
nDesired number of samples (number of identical consumption intervals per transmission interval)
eEquidistant (without transmission of the time stamp)
cList of channel indices
{
"t": 100,
"n": 10,
"e": true,
"c": [
2,
5
]
}

RPC: ReadSamplesContent (smartCORE => Client)

ParametersDescription
xConsecutive packet index since start (e.g. to determine data loss)
cArray of channels
iChannel index
vMeasured value
ttime stamp

Notes:

  • If fewer than the desired number of samples are available, only the available samples are transmitted.
  • If no current sample is available, only the "Last Value" is sent.

Payload variant 1: with time stamp ( 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 variant 2: without time stamp ( 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)

Empty request to switch off the transmission.