Skip to content

Multi Command Sensors

WeSpeakEnglish edited this page Sep 25, 2026 · 1 revision

Multi-Command Sensors

Some sensors don't stream data on their own. They must be woken up, configured, and then polled — often with a different reply format for each command. The commands array handles this.

When to use it

  • The sensor needs an initialisation sequence (e.g. Sensirion SCD30, SEN63C, SCD41).
  • Data must be requested with a command and read back.
  • Different commands return different frame formats.
  • The sensor sits behind a bridge (e.g. I²C-to-USB) that needs its own protocol.

Command object

Field Required Type Description
command yes string Hex bytes to send, e.g. "1B 41 6B 57 00 52 03 53"
repeat no number 0 = run once during init; ≥ 1 = run N times per measurement cycle
postDelay_ms no number Wait this long after sending before the next step
frame no object How to detect this command's reply (same as top-level frame)
checksum no object How to validate the reply
data no object Signals to extract from the reply
id no number Only used by child sensors to override a parent command — see Inheritance

Extra keys such as _comment inside a command are a handy way to document each step.

Execution flow

Connect
  │
  ├─ Init phase: every command with repeat: 0, in order, once
  │
  └─ Measurement loop (while connected):
        every command with repeat ≥ 1, in order,
        each sent `repeat` times, waiting postDelay_ms after each
Disconnect
  └─ stop_command (if defined)
  • A command without frame/data is just sent (e.g. a configuration write).
  • A command with frame/checksum/data has its reply parsed; any command's data can feed the charts.

start_command and stop_command

Classic mode Multi-command mode
start_command Sent after connect Ignored — use a repeat: 0 command instead
stop_command Sent on disconnect Sent on disconnect

Skeleton

Command bytes, frame length and expressions below are placeholders — replace them with values from your sensor's datasheet.

{
  "name": "My Polled Sensor",
  "port": { "baudRate": 115200, "dataBits": 8, "stopBits": 1, "parity": "none" },
  "stop_command": "7E 00 01 00 FE 7E",
  "commands": [
    {
      "_comment": "start measurement (once)",
      "command": "7E 00 00 02 01 03 F9 7E",
      "repeat": 0,
      "postDelay_ms": 1000
    },
    {
      "_comment": "read measured values (every cycle)",
      "command": "7E 00 03 00 FC 7E",
      "repeat": 1,
      "postDelay_ms": 1000,
      "frame": { "startByte": "0x7E", "endByte": "0x7E", "length": 10,
                 "stuffing": [["7D 5E", "0x7E"], ["7D 5D", "0x7D"]] },
      "checksum": { "eval": "...", "compare": "..." },
      "data": {
        "PM2.5": { "value": "...", "unit": "μg/m³" }
      }
    }
  ]
}

For a fully annotated walkthrough — protocol, frames, checksum and how each byte maps to the JSON — see SEN5x UART Protocol. For more complete working examples, look at Sensirion SPS30, Sensirion SCD41 via KEL I2C to UART and Sensirion SEN55 UART in sensors.json.

Tips

  • Give the sensor enough time: check the datasheet's execution time for each command and set postDelay_ms accordingly.
  • The first reading after starting a measurement is often invalid; a repeat: 0 "priming" read can discard it.
  • Checksums can include extra validity checks — the SCD41 config, for example, returns 1 only if every CRC-8 matches, and compares against "1".

Clone this wiki locally