Skip to content

ENS160

ScioSense ENS160 digital metal-oxide multi-gas sensor (TVOC, eCO2, AQI-UBA).

Live catalog

Prefer labwired_describe with the catalog id over guessing pins or addresses.

Status at a glance

Aspect Status
Catalog id ens160
Bus I²C
Address 0x52 (0x53 with MISO/ADDR high)
Source configs/devices/ens160.yaml (declarative, no Rust model)
Datasheet ScioSense ENS160 datasheet v1.3 (SC-001224-DS-9), §16 Registers
Tier smoke-proven (register-level tests: crates/core/tests/everyday_sensor_set.rs)

Pins / attachment

Pin / net Role
SDA I²C SDA
SCL I²C SCL
VDD/GND Power (digital twin)

Support matrix

Behavior Status Notes
PART_ID 0x0160 (little-endian) ✅ Reads 0x60, 0x01
OPMODE (IDLE at power-on, STANDARD 0x02, RESET 0xF0) ✅ RESET returns OPMODE to IDLE only
DATA_AQI 0x21 / DATA_TVOC 0x22 / DATA_ECO2 0x24 ✅ Live in STANDARD only; defaults until then, last value held after
DEVICE_STATUS STATAS / NEWDAT ⚠️ NEWDAT has no published cadence; ready at every poll
DEVICE_STATUS VALIDITY ⚠️ Host-driven validity channel (warm-up / start-up)
TEMP_IN / RH_IN → DATA_T / DATA_RH ✅ Copied; compensation itself not modelled
MOx algorithm, COMMAND / GPR, DATA_MISR, INTn ❌ Not modelled

Stimulus

Host inputs: tvoc (ppb), eco2 (ppm), aqi (1..5), validity (0..3).

How to run

  1. Place the part and an MCU in Playground, or add it to a system YAML:
    external_devices:
      - id: "ens160"
        type: "ens160"
        connection: "i2c0"   # the bus id your chip system uses
    
  2. Agent: labwired_list → labwired_describe id=ens160 → wire → labwired_validate → labwired_run / labwired_verify.
  3. Register-level smoke: cargo test -p labwired-core --test everyday_sensor_set — PART_ID, OPMODE = IDLE, then STANDARD with AQI 2 / 100 ppb / 600 ppm. The same file's negative control proves the check fails against a part that answers only 0x00 or only 0xFF.

Limitations

  • The three outputs are independent host channels; ScioSense's TrueVOC algorithm that relates them is not modelled.
  • DATA_TVOC is at 0x22 (datasheet Table 16); 0x26 is reserved.
  • Warm-up (3 min) and initial start-up (1 h) are posed by the host through validity, not timed.

See the YAML header for the full datasheet trace and every named approximation.