{
  "spec_version": 1,
  "slug": "zehnder-comfoconnect-pro",
  "manufacturer": "Zehnder",
  "model": "ComfoConnect PRO gateway for ComfoAir Q / Flex",
  "category": "HVAC controller",
  "supplier_url": "https://www.zehnder-systems.com/en/indoor-ventilation/products/comfoconnect-pro",
  "default_configuration": {
    "protocol": "modbus_tcp",
    "port": 502,
    "unit_id": 1,
    "addressing": "zero_based",
    "byte_order": "BigEndian",
    "word_order": "HighFirst"
  },
  "coils": [
    {
      "address": 1,
      "count": 1,
      "name": "Reset errors",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Coil 0x0001; writing true resets the active alarms, the coil resets itself."
    },
    {
      "address": 6,
      "count": 1,
      "name": "Auto mode",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Coil 0x0006, automatic ventilation demand control on/off."
    },
    {
      "address": 7,
      "count": 1,
      "name": "Boost",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Coil 0x0007, start a temporary boost; the unit clears it when the boost time has elapsed."
    },
    {
      "address": 8,
      "count": 1,
      "name": "Away function",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Coil 0x0008, reduced ventilation while absent."
    },
    {
      "address": 9,
      "count": 1,
      "name": "ComfoCool",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Coil 0x0009, cooling module on/off."
    }
  ],
  "discrete_inputs": [
    {
      "address": 1,
      "count": 1,
      "name": "Error flag",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Discrete input 0x0001, 0 = ok."
    },
    {
      "address": 4,
      "count": 1,
      "name": "Filter dirty",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Discrete input 0x0004, filter change required."
    }
  ],
  "input_registers": [
    {
      "address": 1,
      "count": 1,
      "name": "Connection state",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x0001. 30 = the detected ventilation unit is not a ComfoAir Q, 40 = ComfoAir Q version not compatible, 50 = no ventilation unit detected."
    },
    {
      "address": 2,
      "count": 1,
      "name": "Active error 1",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x0002; error code of the first active alarm, slots 2-6 hold alarms 1-5."
    },
    {
      "address": 3,
      "count": 1,
      "name": "Active error 2",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 4,
      "count": 1,
      "name": "Active error 3",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 5,
      "count": 1,
      "name": "Active error 4",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 6,
      "count": 1,
      "name": "Active error 5",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 7,
      "count": 1,
      "name": "Air flow",
      "data_type": "UInt16",
      "units": "m³/h",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x0007, current ventilation air flow."
    },
    {
      "address": 8,
      "count": 1,
      "name": "Room temperature",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x0008."
    },
    {
      "address": 9,
      "count": 1,
      "name": "Extract temperature",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x0009, air drawn from the rooms as it enters the unit."
    },
    {
      "address": 10,
      "count": 1,
      "name": "Exhaust temperature",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x000A, air blown outside."
    },
    {
      "address": 11,
      "count": 1,
      "name": "Outdoor temperature",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x000B."
    },
    {
      "address": 12,
      "count": 1,
      "name": "Supply temperature",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x000C, air blown into the rooms."
    },
    {
      "address": 13,
      "count": 1,
      "name": "Room humidity",
      "data_type": "UInt16",
      "units": "%",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x000D."
    },
    {
      "address": 14,
      "count": 1,
      "name": "Extract humidity",
      "data_type": "UInt16",
      "units": "%",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x000E."
    },
    {
      "address": 15,
      "count": 1,
      "name": "Exhaust humidity",
      "data_type": "UInt16",
      "units": "%",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x000F."
    },
    {
      "address": 16,
      "count": 1,
      "name": "Outdoor humidity",
      "data_type": "UInt16",
      "units": "%",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x0010."
    },
    {
      "address": 17,
      "count": 1,
      "name": "Supply humidity",
      "data_type": "UInt16",
      "units": "%",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x0011."
    },
    {
      "address": 18,
      "count": 1,
      "name": "CO2 sensor zone 1",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x0012; zones 2-8 follow at 0x0013-0x0019. A zone reading 0 has no sensor."
    },
    {
      "address": 19,
      "count": 1,
      "name": "CO2 sensor zone 2",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 20,
      "count": 1,
      "name": "CO2 sensor zone 3",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 21,
      "count": 1,
      "name": "CO2 sensor zone 4",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 22,
      "count": 1,
      "name": "CO2 sensor zone 5",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 23,
      "count": 1,
      "name": "CO2 sensor zone 6",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 24,
      "count": 1,
      "name": "CO2 sensor zone 7",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 25,
      "count": 1,
      "name": "CO2 sensor zone 8",
      "data_type": "UInt16",
      "units": "ppm",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 26,
      "count": 1,
      "name": "Filter days remaining",
      "data_type": "UInt16",
      "units": "d",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Input register 0x001A, days until the next filter change."
    }
  ],
  "holding_registers": [
    {
      "address": 1,
      "count": 1,
      "name": "Ventilation preset",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Holding register 0x0001: 0 = low, 1 = medium, 2 = high, 3 = maximum."
    },
    {
      "address": 2,
      "count": 1,
      "name": "Temperature profile",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Holding register 0x0002: 0 = normal, 1 = cold, 2 = warm. Only used in the adaptive and fixed modes."
    },
    {
      "address": 3,
      "count": 1,
      "name": "Temperature profile mode",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Holding register 0x0003: 0 = adaptive, 1 = fixed, 2 = external setpoint."
    },
    {
      "address": 4,
      "count": 1,
      "name": "External setpoint",
      "data_type": "UInt16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "RW",
      "description": "Holding register 0x0004, supply air temperature setpoint for the external setpoint mode."
    },
    {
      "address": 5,
      "count": 1,
      "name": "Boost time",
      "data_type": "UInt16",
      "units": "s",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Holding register 0x0005, boost duration in whole seconds; 65535 means 24 hours."
    }
  ],
  "combined_registers": [],
  "notes": "Source: Zehnder, \"ComfoConnect PRO - Installer manual\", document ComfoConnectPro_Modbus_Installation (revision 137/140), chapter 'ComfoAirQ/Flex exposed interface' and the ComfoConnect PRO Modbus TCP/RTU installation section; the register layout matches the comfoconnect-pro-modbus library, which is built against revision 140. The ComfoConnect PRO (product number 30006323) is a gateway on port 502 that exposes the ComfoAir Q or ComfoAir Flex connected over ComfoNet; Modbus TCP and Modbus RTU are alternative settings (default slave ID 1, range 1-247; RTU is 8 data bits with even parity and 1 stop bit, or 2 stop bits without parity). Addresses are PDU addresses starting at zero, so 0x0007 is wire address 7. Temperatures carry one decimal (raw x0.1), humidities and CO2 are whole numbers, air flow is in m3/h, and the error slots hold alarm codes. The gateway reports no serial number, model or firmware version, and the ventilation unit cannot be switched off or put into standby over Modbus. Auto mode, boost and the ventilation preset are also changed by the unit itself (for example when a boost ends), so poll the settings as often as the readings."
}
