{
  "spec_version": 1,
  "slug": "senseair-s8",
  "manufacturer": "SenseAir",
  "model": "S8 / S8 LP CO2 sensor module",
  "category": "Sensor",
  "supplier_url": "https://senseair.com/product/s8/",
  "default_configuration": {
    "protocol": "modbus_tcp",
    "port": 502,
    "unit_id": 254,
    "addressing": "zero_based",
    "byte_order": "BigEndian",
    "word_order": "HighFirst",
    "native_interface": "rs485",
    "serial": {
      "parity": "None",
      "baud_rate": 9600,
      "data_bits": 8,
      "stop_bits": 1
    }
  },
  "coils": [],
  "discrete_inputs": [],
  "input_registers": [
    {
      "address": 0,
      "count": 1,
      "name": "Meter status",
      "data_type": "Binary",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit 1 fatal error, bit 2 offset regulation error, bit 3 algorithm error, bit 4 output error, bit 5 self diagnostics, bit 6 out of range, bit 7 memory error."
    },
    {
      "address": 1,
      "count": 1,
      "name": "Alarm status",
      "data_type": "Binary",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "All bits reserved on the S8."
    },
    {
      "address": 2,
      "count": 1,
      "name": "Output status",
      "data_type": "Binary",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit 1 alarm output status (inverted, open collector), bit 2 PWM output status (1 = full output)."
    },
    {
      "address": 3,
      "count": 1,
      "name": "CO2 concentration",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Filtered CO2 value. Some S8 variants divide the reading by 10."
    },
    {
      "address": 21,
      "count": 1,
      "name": "PWM output 2",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 25,
      "count": 1,
      "name": "Sensor type ID, high",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Sensor type ID is 3 bytes: low byte of 25 plus 26."
    },
    {
      "address": 26,
      "count": 1,
      "name": "Sensor type ID, low",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 27,
      "count": 1,
      "name": "Memory map version",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 28,
      "count": 1,
      "name": "Firmware version",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "High byte main revision, low byte sub revision."
    },
    {
      "address": 29,
      "count": 1,
      "name": "Sensor ID, high",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Sensor ID is the 4-byte serial number in 29 and 30."
    },
    {
      "address": 30,
      "count": 1,
      "name": "Sensor ID, low",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    }
  ],
  "holding_registers": [
    {
      "address": 0,
      "count": 1,
      "name": "Acknowledgement register",
      "data_type": "Binary",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Bit 6 CO2 background calibration performed, bit 7 CO2 zero calibration performed."
    },
    {
      "address": 1,
      "count": 1,
      "name": "Special command register",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "W",
      "description": "0x06 = start CO2 background calibration, 0x07 = start CO2 zero calibration."
    },
    {
      "address": 31,
      "count": 1,
      "name": "ABC period",
      "data_type": "UInt16",
      "units": "h",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Automatic baseline correction period in hours; 0 suspends ABC."
    }
  ],
  "combined_registers": [],
  "notes": "RS-485/CMOS serial sensor: reach it through a Modbus RTU-to-TCP gateway using the factory serial settings above (9600 bps, 8 data bits, no parity; the sensor transmits two stop bits and accepts one or two). Source: SenseAir 'Modbus on SenseAir S8', document TDE2067 rev. 4 (2020-04-21), tables 3 and 4 and appendix A. The document states that the register address is the register number minus one, so addresses here are zero based. unit_id 254 is the 'any sensor' address that every example frame in TDE2067 uses; it is not a factory value. The sensor's individual slave address is stored in its EEPROM and can be set to 1-247, so change unit_id to the address your sensor is configured with. Only 6 registers can be read in one request."
}
