{
  "spec_version": 1,
  "slug": "danfoss-ecl-comfort-310",
  "manufacturer": "Danfoss",
  "model": "ECL Comfort 296 / 310 (ECL 210 via RS-485)",
  "category": "HVAC controller",
  "supplier_url": "https://www.danfoss.com/en/products/dhs/electronic-controls/electronic-controllers-and-application-keys/ecl-comfort-controllers/",
  "default_configuration": {
    "protocol": "modbus_tcp",
    "port": 502,
    "unit_id": 1,
    "addressing": "one_based",
    "byte_order": "BigEndian",
    "word_order": "HighFirst"
  },
  "coils": [],
  "discrete_inputs": [],
  "input_registers": [],
  "holding_registers": [
    {
      "address": 35,
      "count": 1,
      "name": "ECL software version",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Two bytes: major.minor (257 = 0x0101 = version 1.01)."
    },
    {
      "address": 38,
      "count": 1,
      "name": "Modbus network address",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Valid range 1-247, factory default 1. A change takes effect immediately."
    },
    {
      "address": 1024,
      "count": 1,
      "name": "Sum alarms 17-32",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit field of alarms 17-32; bit set = alarm active."
    },
    {
      "address": 1025,
      "count": 1,
      "name": "Sum alarms 1-16",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit field of alarms 1-16; bit set = alarm active."
    },
    {
      "address": 2061,
      "count": 1,
      "name": "Application type number",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Application key the controller runs (e.g. 230, 266), which determines the sensor assignment."
    },
    {
      "address": 2062,
      "count": 1,
      "name": "Application type sub number",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Sub number of the installed application key. The guide reads the application name and version from PNU 2060-2063: 2060 = prefix (an ASCII letter, e.g. 65 = 'A'), 2061 = type number, 2062 = sub number, 2063 = version (major.minor in the two bytes)."
    },
    {
      "address": 2099,
      "count": 1,
      "name": "Production week and year",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "High byte = years since 2000, low byte = production week."
    },
    {
      "address": 4201,
      "count": 1,
      "name": "Circuit 1 mode",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Operating mode of circuit 1: 0 = manual operation, 1 = scheduled operation, 2 = constant comfort temperature, 3 = constant setback temperature, 4 = frost protection/standby, 5 = active cooling (A232 only). The guide places the circuit modes on PNU 4201-4206 (circuit 1-6) and states that manual mode applies to all circuits; it does not list a separate controller-wide mode PNU."
    },
    {
      "address": 4202,
      "count": 1,
      "name": "Circuit 2 mode",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Operating mode of circuit 2, same codes as circuit 1; circuit 3 mode is 4203, circuit 4 mode 4204, and so on up to circuit 6 at 4206."
    },
    {
      "address": 4211,
      "count": 1,
      "name": "Circuit 1 status",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Operating status of circuit 1: 0 = setback, 2 = pre-comfort, 3 = comfort, 5 = pre-setback, 6 and above = holiday states (see the guide's 'Mode and status' table). The operating status is read as 0 (setback) when the mode code is larger than 3."
    },
    {
      "address": 4212,
      "count": 1,
      "name": "Circuit 2 status",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Operating status of circuit 2, same codes as circuit 1; circuit 3 status is 4213, circuit 4 status 4214, and so on."
    },
    {
      "address": 10201,
      "count": 1,
      "name": "Raw sensor 1",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R",
      "description": "Uncorrected input value of hardware sensor input 1, before any application scaling."
    },
    {
      "address": 10202,
      "count": 1,
      "name": "Raw sensor 2",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 10203,
      "count": 1,
      "name": "Raw sensor 3",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 10204,
      "count": 1,
      "name": "Raw sensor 4",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 10399,
      "count": 1,
      "name": "SCADA timeout",
      "data_type": "UInt16",
      "units": "min",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "Minutes after which the SCADA overwrites below expire and the controller returns to its own values; 1-720."
    },
    {
      "address": 10400,
      "count": 1,
      "name": "SCADA outdoor temperature",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "RW",
      "description": "Outdoor temperature injected by SCADA; -60 to 60 °C. Must be written periodically, otherwise it expires after the SCADA timeout."
    },
    {
      "address": 10401,
      "count": 1,
      "name": "SCADA heat offset 1",
      "data_type": "Int16",
      "units": "K",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "RW",
      "description": "Parallel shift of heating circuit 1, -50 to 50 K; circuits 2-4 use 10402-10404. Must be written periodically."
    },
    {
      "address": 10405,
      "count": 1,
      "name": "SCADA boiler control 1",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "RW",
      "description": "DHW tank charging request: 0 = off, 1 = stop, 2 = start. Circuits 2-4 use 10406-10408."
    },
    {
      "address": 11175,
      "count": 1,
      "name": "Circuit 1 heat curve slope",
      "data_type": "Int16",
      "units": "",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Weather-compensation slope (heat curve); read-only per the guide, writable in some applications"
    },
    {
      "address": 11180,
      "count": 1,
      "name": "Circuit 1 comfort room setpoint",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "RW"
    },
    {
      "address": 11181,
      "count": 1,
      "name": "Circuit 1 saving room setpoint",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "RW"
    },
    {
      "address": 11190,
      "count": 1,
      "name": "Comfort DHW setpoint",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "RW"
    },
    {
      "address": 11191,
      "count": 1,
      "name": "Saving DHW setpoint",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "RW"
    },
    {
      "address": 11201,
      "count": 1,
      "name": "Circuit 1, sensor S1",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R",
      "description": "Measured value of the sensor the application assigns to S1 of circuit 1 (typically the flow temperature). Which physical sensor that is depends on the application key."
    },
    {
      "address": 11202,
      "count": 1,
      "name": "Circuit 1, sensor S2",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11203,
      "count": 1,
      "name": "Circuit 1, sensor S3",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11204,
      "count": 1,
      "name": "Circuit 1, sensor S4",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11205,
      "count": 1,
      "name": "Circuit 1, sensor S5",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11206,
      "count": 1,
      "name": "Circuit 1, sensor S6",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11207,
      "count": 1,
      "name": "Circuit 1, sensor S7",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11208,
      "count": 1,
      "name": "Circuit 1, sensor S8",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11209,
      "count": 1,
      "name": "Circuit 1, sensor S9",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11210,
      "count": 1,
      "name": "Circuit 1, sensor S10",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11251,
      "count": 1,
      "name": "Circuit 1, S1 sensor reference",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R",
      "description": "Desired value / setpoint used for sensor S1 of circuit 1."
    },
    {
      "address": 11252,
      "count": 1,
      "name": "Circuit 1, S2 sensor reference",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11253,
      "count": 1,
      "name": "Circuit 1, S3 sensor reference",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 11254,
      "count": 1,
      "name": "Circuit 1, S4 sensor reference",
      "data_type": "Int16",
      "units": "°C",
      "scale_factor": 0.01,
      "offset": 0,
      "access": "R"
    }
  ],
  "combined_registers": [],
  "notes": "Source: Danfoss Climate Solutions, \"ECL Comfort 210/296/310, communication description\" (operating guide AQ074886472234, English, 2026.05 edition). The ECL Comfort 296 and 310 are Modbus servers on TCP port 502 with default address 1 (range 1-247, settable in PNU 38); only public function codes 03 (read holding), 04 (read input) and 06 (write single) are supported, and the guide's own examples read both a setpoint and a sensor with function code 03, so the complete map is listed as holding registers, the ADU is limited to 240 bytes and a request may span at most 123 parameters. The register address is the PNU minus one (the guide's example: PNU 11180 is at address 11179), so the PNU numbers from the parameter list are used one_based here. Every value is a signed or unsigned 16-bit integer; the guide's Scale column is applied above (100 = 0.01, 10 = 0.1). The controller model is defined by the application key installed (PNU 2060-2063 report prefix, type number, sub number and version), and the application decides which sensor S1-S10 is what, which PNUs exist and whether a heat curve is present, so the sensor rows are intentionally described by their application-level names. PNU ranges: circuit modes 4201-4206 and circuit statuses 4211-4216 (circuit 1 = 4201/4211, as the guide's 'Mode and status' section states); the guide lists no controller-wide mode or status PNU, so none is included. Circuit 1 parameters are 11xxx, circuit 2 (DHW) 12xxx, and 1000 is added per further circuit. The circuit 1 heat curve slope (PNU 11175) uses the guide's scale 10 (= 1.0) and is listed as read-only, because the guide marks it read-only while some applications allow writing it. Reading non-existing parameters returns a Modbus exception instead of a value."
}
