Protocols
What nestlocal, the service unfr0zen installs on the thermostat, speaks on MQTT, Zigbee and Matter: enough to write an integration for any home automation system. To set the integrations up with Home Assistant, see Integrations.
All three protocols read the same state and run the same commands, though raw/, eco_mode, fan_timer_end, rssi, local_ip, hot_water_boiling_state and heatpump_ready are MQTT's alone, and Matter takes neither the weather nor the time. A command changes the unit's settings; the state then shows what the unit did, not what was asked. A setpoint the unit adjusts or refuses comes back as the unit has it.
Conventions
- Temperatures are °C on every protocol, whatever the unit displays. MQTT carries degrees; Zigbee and Matter carry hundredths of a degree (
2150is 21.5 °C). - Temperatures read as the display shows them: to 0.5 °C, or, when the unit displays °F, to the whole °F converted back to °C. The
raw/MQTT topics keep the unit's exact values. - Setpoints written are rounded to 0.5 °C. The unit keeps a range's low and high at least 1.5 °C apart.
- The equipment decides what is offered. Cooling, the fan, an air filter, a humidifier and so on appear only when the unit's wiring has them (
can_heat,can_cool,has_fan,has_air_filter,has_humidifier,has_dehumidifier,has_hot_water_control), and each HVAC stage when its wire is (has_x2_heat,has_x3_heat,has_aux_heat,has_alt_heat,has_x2_alt_heat,has_emer_heat,has_x2_cool,has_x3_cool), the first heat or cool stage beside any other of its kind. A Heat Link model installed with the Works With Nest boiler option (which needs Zigbee or Thread) offers heat with nothing on W1, though the unit'scan_heatinraw/sharedstays false. - Nothing is offered before the unit has reported its settings to nestlocal, a few seconds after it starts.
- The serial is the unit's serial number, which is also its hostname.
MQTT
nestlocal is an MQTT 3.1.1 client of your broker: tcp:// or mqtt:// in the clear, ssl://, tls:// or mqtts:// over TLS. WebSockets are not supported.
| Connection | Value |
|---|---|
| Client ID | nestlocal-<serial> |
| Session | Clean session |
| Keepalive | 3600 s, so the broker drops the connection after 90 minutes without a packet. The unit sleeps, and its pings with it; left alone it wakes about every 30 minutes, and a wake pings the broker when nothing went to it for 10 minutes. |
| Will | offline on nestlocal/<serial>/availability, retained, QoS 1 |
| Subscriptions | nestlocal/<serial>/set/# and homeassistant/status, QoS 1 |
| Reconnect | Every 10 s while the broker cannot be reached. Publishes made while disconnected are dropped; on each connection the whole state is published again. |
Every topic starts with nestlocal/<serial>/.
| Topic | Direction | Payload |
|---|---|---|
availability | out, retained, QoS 1 | online while the broker has nestlocal and the unit has called in within 5 minutes; offline otherwise. |
state | out, retained | One JSON object every entity reads: MQTT state. Published again on every change. |
raw/<bucket> | out, retained | One of the unit's settings buckets (device, shared, schedule, structure, …), whole, as JSON, with the unit's own field names and exact values. |
set/<command> | in | A command: MQTT commands. |
update | out, retained | unfr0zen's versions, as Home Assistant's update entity reads them: installed_version, latest_version (the last release a check found, kept across restarts; null until one has answered; the installed version when that is a later build), release_url and in_progress. |
set/update | in | install: install the latest release, on a 3rd generation unit; or an http:// or https:// URL: install the bundle there, for a unit that can't reach GitHub. Either way the unit checks the bundle against its manifest and unfr0zen's release key, refuses a version older than the one it runs, installs it, and restarts. |
time/request | out | Empty: the unit asks for the time. See Weather & clock. |
Outgoing publishes are QoS 0 unless stated, and the empty discovery configs of a root change are QoS 1. Incoming ones may be QoS 0 or 1.
Watch everything, and set a temperature:
mosquitto_sub -h broker.lan -t 'nestlocal/#' -v
mosquitto_pub -h broker.lan -t 'nestlocal/<serial>/set/target' -m 21.5
Home Assistant discovery
nestlocal publishes retained discovery configs to homeassistant/<component>/nestlocal_<serial in lowercase>/<key>/config on each connection, again when a config changes (equipment, firmware version, °C/°F) and whenever online arrives on homeassistant/status.
- Removal. An entity the equipment stops offering during a connection gets an empty retained payload.
- Names. Each config's
default_entity_idis<component>.<root>_<key>, the rootnestlocal_<serial in lowercase>unless the install named another, and its device is named Nest Thermostat unless named otherwise;unique_idand the device's identifier keepnestlocal_<serial in lowercase>. - A new root. When the root changes, nestlocal publishes an empty retained payload to every config, waits 2 seconds, and publishes them again: Home Assistant restores each removed entity under its new
default_entity_id. It does so once more at the nextonlineonhomeassistant/status, for a Home Assistant that wasn't running the first time. - Without Home Assistant. Every config reads
stateand names itsavailabilitytopic, so a system that isn't Home Assistant can ignore discovery and use the topics above.
Components: one climate (key thermostat), and sensor, binary_sensor, switch, number, select and button entities whose key is the state field they read or the command they send (sensor hvac_action reads action).
MQTT commands
Publish to nestlocal/<serial>/set/<command>, and watch state for the result.
- Payload. Plain text, surrounding whitespace ignored.
- On/off.
ON,OFF,true,false,1or0, in any case, as are theONandOFFofhot_water_boostandfilter_reset. Other words are case-sensitive. - Errors. A payload out of range or unknown, or a command for a bucket the unit hasn't reported, is logged on the unit and ignored: there is no error topic.
- Retain. Don't retain commands, the weather's aside (
set/outdoor_temperature,set/outdoor_humidity,set/weather): nestlocal gets every retained one again each time it connects.
| Command | Payload | Effect |
|---|---|---|
mode | off heat cool heat_cool | System mode. heat_cool is the unit's range mode. |
target | °C, 4.5–35 | The setpoint in heat or cool. |
target_low, target_high | °C, 4.5–35 | The range's setpoints in heat_cool. |
preset | eco none (or empty) | Eco on, or back to the schedule. |
fan_mode | on auto | on runs the fan for the fan timer duration (15 min if unset); auto stops the timer. |
fan_timer_duration | whole minutes, 15–1440 | How long fan_mode on runs the fan. |
fan_schedule | on/off (with a fan) | On: the fan runs on its schedule, the run time of every hour from the start hour to the end hour, every day. Off: only for the fan timer and heating or cooling. The unit's screen shows the schedule but can't change it. |
fan_schedule_minutes | 15 30 45 60 | Minutes of each hour the fan schedule runs the fan; 60 is always on. |
fan_schedule_start, fan_schedule_end | hour, 0–23 or 07:00 | When the fan schedule starts and ends each day; the same start and end run it all day. |
away_temperature_low | °C, 4.5–21 | Eco heating temperature. |
away_temperature_high | °C, 24–32 | Eco cooling temperature. |
away_temperature_low_enabled, away_temperature_high_enabled | on/off | Whether eco heats, or cools, at all. |
learning_mode | on/off | Auto-Schedule. |
auto_away_enable | on/off | Home/Away Assist. |
sunlight_correction_enabled | on/off | Sunblock. |
preconditioning_enabled | on/off | Early-On. |
target_humidity | %, 10–60 | Target humidity (with a humidifier or dehumidifier). |
target_humidity_enabled | on/off | Humidity control. |
hot_water_boost | off, 30, 60 or 120 minutes; ON is 30 (with hot water control) | Starts or cancels a hot water boost. The unit ends it by itself when the time is up. |
hot_water_schedule | on/off (with hot water control) | On: hot water follows its schedule. Off: the unit's hot water mode is off. |
temperature_scale | C F | What the unit displays. Every protocol stays in °C. |
filter_reminder_enabled | on/off | Filter reminder (with an air filter): whether the unit reminds to change the filter. |
filter_reset | anything but OFF, which does nothing | The air filter was changed: the unit zeroes its runtime and clears the reminder. |
clear_schedule | anything | Empties every day of the unit's schedule and turns Auto-Schedule off: the unit then holds whatever setpoint it is given. |
external_temperature | °C, −30–60 | A reading for the unit to regulate from, with the external temperature option. Available on gen 1 and gen 2 (reviewed 5.9.4-5 firmware) and gen 3. Counts for 30 minutes; the first after nestlocal starts also selects the sensor. On gen 2, selection waits for native sample acceptance. Refused without the option. |
outdoor_temperature | °C, −60–60 | Outdoor temperature for the unit's weather. Not a setting: kept in memory only. |
outdoor_humidity | %, 0–100 | Outdoor humidity. The unit shows no weather until it has both. |
weather | JSON | Conditions and forecast: Weather & clock. |
time | seconds since 1970 | The answer to time/request. |
raw/<bucket> | JSON object | Merged into the unit's <bucket> bucket, top-level fields replaced. For anything the commands don't cover. |
raw/ writes go to the unit unchecked, with Nest's own field names: read the matching raw/<bucket> topic first. Only the unit's own buckets (<bucket>.<serial>) already reported can be written; structure is keyed by its own id, so set/raw/structure is refused.MQTT state
The state topic's JSON. A number or string the unit hasn't reported is null, and a bool false. mode and action read off, fan_mode auto, preset none, hot_water_boost off and hot_water_schedule true.
| Field | Type | Meaning |
|---|---|---|
mode | string | off, heat, cool or heat_cool. |
target, target_low, target_high | °C | Setpoints. In heat_cool the range applies; otherwise target. |
current_temperature | °C | Room temperature. |
current_humidity | % | Room humidity. |
action | string | What the system is doing: off, heating, cooling, fan or idle. |
heating, cooling, fan_running | bool | action is heating or cooling (any stage, aux or emergency heat included; so false in off); the fan is on, in any mode. |
heat_stage_1, heat_stage_2, heat_stage_3, aux_heat, alt_heat, alt_heat_stage_2, emergency_heat, cool_stage_1, cool_stage_2, cool_stage_3 | bool | The HVAC stage's relay is on (W1, W2, W3, aux, alt heat and its second stage, emergency heat; Y1, Y2, Y3): false unless action is the stage's heating or cooling. Each has a binary_sensor when the wiring has it (see above). |
fan_mode | string | on while the fan timer runs, else auto. |
fan_timer_end | RFC 3339 | When the fan timer ends, or null. |
fan_timer_duration | string | Minutes, as text ("15"). Absent until the unit has one. |
fan_schedule | bool | The fan runs on its schedule. |
fan_schedule_minutes | string | The schedule's minutes per hour, as text ("30"). Absent until the unit has one. |
fan_schedule_start, fan_schedule_end | string | The schedule's start and end, "HH:MM". Absent until the unit has them. |
preset | string | eco or none. |
eco_mode | string | The unit's own: schedule, manual-eco (set by hand or a command) or auto-eco (Home/Away Assist). <nil> until reported. |
away_temperature_low, away_temperature_high | °C | Eco temperatures, always within the commands' ranges (4.5–21 and 24–32 °C): the unit's 40, 70 and 90 °F limits read as the nearest bound. |
occupancy | bool | true for 15 minutes after the unit's motion sensor last saw someone (its RealTimeOccupancy events, read from nlclient's event log as they happen). |
time_to_target | RFC 3339 | When the unit expects to reach the setpoint, or null. |
backplate_temperature | °C | The backplate's own sensor, exact. |
battery_level | V | The display's battery voltage. |
rssi | number | Wi-Fi signal. |
local_ip | string | The unit's IP address. |
current_version | string | Nest firmware version. |
external_temperature | °C or null | The latest reading while it counts. With the external temperature option only. |
temperature_source | string | external or backplate: what the unit regulates from. With the external temperature option only. |
temperature_scale | string | C or F: what the unit displays. |
target_humidity | % | Target humidity. |
filter_runtime_sec, filter_runtime_h | s, h | Air filter runtime; filter_runtime_h to 0.1 h, absent until the unit reports a runtime. |
learning_mode, auto_away_enable, sunlight_correction_enabled, preconditioning_enabled, away_temperature_low_enabled, away_temperature_high_enabled, target_humidity_enabled, filter_reminder_enabled | bool | The settings of the same-named commands. |
leaf | bool | The Leaf shows. |
preconditioning_active, sunlight_correction_active | bool | Early-On, Sunblock acting now. |
hvac_safety_shutoff_active | bool | The unit's safety temperature shutoff tripped. |
filter_replacement_needed | bool | Filter reminder due. |
hot_water_active, hot_water_boiling_state | bool | Hot water (with hot water control). |
hot_water_boost | string | off, or the shortest of 30, 60 and 120 covering the minutes left. |
hot_water_schedule | bool | Hot water follows its schedule rather than being off. |
humidifier_state, dehumidifier_state | bool | Running. |
heatpump_ready | bool | The unit's heat pump readiness flag. |
Weather & clock
The unit's weather screen and its clock came from Google. Over MQTT, anything can supply them; the Home Assistant blueprints on the Integrations page are one implementation.
Weather. Publish set/outdoor_temperature and set/outdoor_humidity; without both the unit shows no weather. Retain them so a restarted nestlocal gets them back, as the Home Assistant blueprint does. Optionally publish set/weather, retained too, as JSON in Home Assistant's own names:
{
"condition": "partlycloudy",
"next_rising": "2026-10-31T07:12:00+00:00",
"next_setting": "2026-10-31T17:40:00+00:00",
"hourly": [{"datetime": "2026-10-30T15:00:00+00:00", "temperature": 12.5, "humidity": 70}],
"daily": [{"datetime": "2026-10-31T00:00:00+00:00", "temperature": 14, "templow": 6, "humidity": 65}]
}
- Every field is optional, and each publish replaces the last, so a field left out is cleared. Times are ISO 8601 with an offset; temperatures °C.
conditionis a Home Assistant weather condition:sunny,clear-night,partlycloudy,cloudy,fog,rainy,pouring,lightning,lightning-rainy,snowy,snowy-rainy,hail,windy-variant. Others show the unit's default image.next_risingandnext_settingtogether choose the day or night image; one alone is ignored.hourly: up to 48 hours.daily: up to 6 days. A twice-daily list (day and night halves, each withis_daytime) is folded into days, the night's temperature as the low.
Clock. nestlocal sets the unit's clock from NTP. Over MQTT it also asks, whether or not NTP works: it publishes an empty message on time/request on each connection and every minute until answered, then every 6 hours. Answer on set/time with the current time in seconds since 1970 (decimals allowed; a value under 1,000,000,000 is refused). An answer more than 5 seconds after the request is ignored.
mosquitto_sub -h broker.lan -t 'nestlocal/+/time/request' -v | while read -r topic _; do
mosquitto_pub -h broker.lan -t "${topic%/time/request}/set/time" -m "$(date +%s)"
done
Zigbee
The thermostat is a Zigbee 3.0 router on the Home Automation profile (0x0104), in standard ZCL clusters, plus one manufacturer-specific cluster, Weather, for what Zigbee has no standard for. Zigbee2MQTT has a ready-made converter, which is also a working reference for a converter or quirk elsewhere.
| Network | Value |
|---|---|
| Joining | Active scan of channels 11–26; joins, as a router, the network permitting joins with the best link quality (Zigbee PRO stack profile only). |
| Security | The Zigbee 3.0 global key (ZigBeeAlliance09) bootstraps joining. The thermostat obtains the encrypted network key and requests an individual trust-centre link key for authenticated router notifications. No install code. |
| Rejoin | The network is kept on the unit and in the radio: restarts don't need pairing again. |
| Manufacturer code | 0x10D6 (Nest Labs): the ZDO node descriptor's, and the code in the Weather cluster's frames |
| Basic: ManufacturerName | Google Nest |
| Basic: ModelIdentifier | 2nd generation: Nest Learning Thermostat (gen2); 3rd generation: Nest Learning Thermostat |
| Basic: HWVersion | 2 or 3, matching the thermostat generation |
Basic: SWBuildID (0x4000) | Nest firmware version |
| Basic: PowerSource | 0x81: mains (the HVAC's 24 V) with battery backup |
Reports
The thermostat reports every change, and everything every 10 minutes (the first 10 s after joining), to the coordinator (0x0000), endpoint 1. OutdoorTemperature and endpoint 5's seconds left trigger no report of their own: they go out with the next one. It does so whatever bindings and reporting configuration exist: Configure Reporting is accepted and changes nothing. Bind and configure reporting anyway if your stack expects it; the converter does.
Reported attributes: Thermostat 0x0000–0x0002, 0x0011–0x0014, 0x001B, 0x001C, 0x0025, 0x0029; Power Configuration 0x0020; 0x0000 of Fan Control, Thermostat UI Configuration, Relative Humidity and Temperature Measurement; PresentValue (0x0055) of Analog Output, Analog Input, Binary Input and Binary Output.
Commands
Read Attributes, Write Attributes (with and without response), Configure Reporting and Discover Attributes are answered.
- Writes. A write is a command (see MQTT commands, with the same ranges, but 9–32 °C for the occupied setpoints): out of range gives
INVALID_VALUE, read-onlyREAD_ONLY, the wrong typeINVALID_DATA_TYPE, an attribute the cluster lacksUNSUPPORTED_ATTRIBUTE. - Reads with no value yet. A read of an attribute with no value yet gives ZCL's "none" for its type (
0x8000for LocalTemperature, OutdoorTemperature and MeasuredValue,0xFFFFfor humidity,0xFFfor battery voltage). - Defaults. Occupied and unoccupied setpoints read defaults instead (cooling 2400 and 3200, heating 2000 and 900), the fan timer 15, the fan schedule's run time 60, its start and end 0, and the target humidity 35.
- Manufacturer-specific frames. Served for the Weather cluster with Nest Labs' code; any other gets
UNSUP_MANUF_*_COMMAND.
Time
Endpoint 1 is a Time cluster (0x000A) client: 10 s after joining, then every 6 hours, the thermostat reads Time (0x0000, UTCTime) from the coordinator's endpoint 1 and sets its clock from it when the two differ by more than 2 s; a read that brings no time is retried every minute. Zigbee2MQTT and ZHA answer it by themselves. An answer is trusted only within 5 s of the request.
Zigbee endpoints
Each endpoint has a fixed number, present when the unit's equipment, as of nestlocal's start, calls for it.
| Endpoint | Device type | Server clusters | What |
|---|---|---|---|
| 1 | Thermostat 0x0301 | Basic, Power Configuration, Identify, Thermostat, Thermostat UI Configuration, Relative Humidity, Weather (0xFC00), Fan Control (with a fan). Client: Time | The thermostat |
| 2 | Temperature Sensor 0x0302 | Temperature Measurement | Backplate temperature |
| 3 | Level Controllable Output 0x0003 | Analog Output | Fan timer duration, minutes, 15–1440 (with a fan) |
| 4 | Level Controllable Output 0x0003 | Analog Output | Target humidity, %, 10–60 (with a humidifier or dehumidifier) |
| 5 | Simple Sensor 0x000C | Analog Input | Time to temperature, seconds left (0: none) |
| 6 | Simple Sensor 0x000C | Analog Input | Filter runtime, hours (with an air filter); writing 0 resets it |
| 7 | Level Controllable Output 0x0003 | Analog Output | Fan schedule run time, minutes per hour: 15, 30, 45 or 60 (with a fan) |
| 8 | Level Controllable Output 0x0003 | Analog Output | Fan schedule start, hour of the day, 0–23 (with a fan) |
| 9 | Level Controllable Output 0x0003 | Analog Output | Fan schedule end, hour of the day, 0–23; the start's runs it all day (with a fan) |
| 10 | On/Off Output 0x0002 | Binary Output | Auto-Schedule |
| 11 | On/Off Output 0x0002 | Binary Output | Home/Away Assist |
| 12 | On/Off Output 0x0002 | Binary Output | Sunblock |
| 13 | On/Off Output 0x0002 | Binary Output | Early-On |
| 14 | On/Off Output 0x0002 | Binary Output | Eco heat limit (can heat) |
| 15 | On/Off Output 0x0002 | Binary Output | Eco cool limit (can cool) |
| 16 | On/Off Output 0x0002 | Binary Output | Humidity control (with a humidifier or dehumidifier) |
| 17 | On/Off Output 0x0002 | Binary Output | Hot water boost, 30 minutes when on (with hot water control) |
| 18 | On/Off Output 0x0002 | Binary Output | Hot water schedule (with hot water control) |
| 19 | On/Off Output 0x0002 | Binary Output | Filter reminder (with an air filter) |
| 20 | Simple Sensor 0x000C | Binary Input | Leaf |
| 21 | Simple Sensor 0x000C | Binary Input | Early-On active |
| 22 | Simple Sensor 0x000C | Binary Input | Sunblock active |
| 23 | Simple Sensor 0x000C | Binary Input | Safety shutoff |
| 24 | Simple Sensor 0x000C | Binary Input | Filter replacement (with an air filter) |
| 25 | Simple Sensor 0x000C | Binary Input | Hot water (with hot water control) |
| 26 | Simple Sensor 0x000C | Binary Input | Humidifier (with a humidifier) |
| 27 | Simple Sensor 0x000C | Binary Input | Dehumidifier (with a dehumidifier) |
| 28 | Simple Sensor 0x000C | Binary Input | Temperature source (with the external temperature option): true while the unit regulates from the external temperature, MQTT's temperature_source external. Read-only. |
| 29 | On/Off Output 0x0002 | Binary Output | Fan schedule (with a fan) |
| 30 | Simple Sensor 0x000C | Binary Input | Heat stage 1 (with any other heat stage below) |
| 31 | Simple Sensor 0x000C | Binary Input | Heat stage 2 (W2 wired) |
| 32 | Simple Sensor 0x000C | Binary Input | Heat stage 3 (W3 wired) |
| 33 | Simple Sensor 0x000C | Binary Input | Aux heat (aux heat wired) |
| 34 | Simple Sensor 0x000C | Binary Input | Alt heat (alt heat wired) |
| 35 | Simple Sensor 0x000C | Binary Input | Alt heat stage 2 (a second alt heat stage wired) |
| 36 | Simple Sensor 0x000C | Binary Input | Emergency heat (emergency heat wired) |
| 37 | Simple Sensor 0x000C | Binary Input | Cool stage 1 (with another cool stage) |
| 38 | Simple Sensor 0x000C | Binary Input | Cool stage 2 (Y2 wired) |
| 39 | Simple Sensor 0x000C | Binary Input | Cool stage 3 (Y3 wired) |
Thermostat cluster (0x0201), endpoint 1
| Attribute | Type | Access | Meaning |
|---|---|---|---|
0x0000 LocalTemperature | int16 | read | Room temperature |
0x0001 OutdoorTemperature | int16 | read | The last set/outdoor_temperature over MQTT, or the Weather cluster's |
0x0002 Occupancy | map8 | read | Bit 0 set for 15 minutes after the motion sensor last saw someone, as MQTT's occupancy |
0x0003–0x0006, 0x0015–0x0018 | int16 | read | Setpoint limits: 900 (9 °C) and 3200 (32 °C) |
0x0011 OccupiedCoolingSetpoint | int16 | read, write | target_high in auto, else target |
0x0012 OccupiedHeatingSetpoint | int16 | read, write | target_low in auto, else target |
0x0013 UnoccupiedCoolingSetpoint | int16 | read, write | Eco cooling temperature, 24–32 °C |
0x0014 UnoccupiedHeatingSetpoint | int16 | read, write | Eco heating temperature, 4.5–21 °C |
0x0019 MinSetpointDeadBand | int8 | read | 15 (1.5 °C) |
0x001B ControlSequenceOfOperation | enum8 | read | 0x00 cooling only, 0x02 heating only, 0x04 both, or neither reported yet |
0x001C SystemMode | enum8 | read, write | 0x00 off, 0x01 auto (heat_cool), 0x03 cool, 0x04 heat |
0x0025 ThermostatProgrammingOperationMode | map8 | read, write | 0x04 (economy) in eco, 0x01 (schedule) otherwise. Writing bit 2 sets or clears eco. |
0x0029 ThermostatRunningState | map16 | read | Bit 0 heating, bit 1 cooling, bit 2 fan, bit 3 heat stage 2, bit 4 cool stage 2 (beside bit 0 or 1) |
Commands: SetpointRaiseLower (0x00; mode 0 heat, 1 cool, 2 both; amount int8 in 0.1 °C, clamped to the limits; in heat or cool, a mode naming only the other side does nothing) and ClearWeeklySchedule (0x03; as clear_schedule).
Other clusters
| Cluster | Attribute | Meaning |
|---|---|---|
Identify 0x0003 | 0x0000 IdentifyTime, uint16 | Always 0. Writes and commands 0x00, 0x01 succeed and do nothing. |
Power Configuration 0x0001 | 0x0020 BatteryVoltage, uint8 | Display battery, in 100 mV |
Fan Control 0x0202 | 0x0000 FanMode, enum8, read/write | 0x04 on (fan timer running), 0x05 auto. Writing 0x00 also means auto. |
Fan Control 0x0202 | 0x0001 FanModeSequence | 0x04: on/auto |
Thermostat UI Configuration 0x0204 | 0x0000 TemperatureDisplayMode, enum8, read/write | 0 °C, 1 °F |
Thermostat UI Configuration 0x0204 | 0x0001 KeypadLockout | Always 0, read-only |
Relative Humidity 0x0405 | 0x0000 MeasuredValue, uint16 | Room humidity, 0.01 %; min/max 0/10000 |
Temperature Measurement 0x0402 | 0x0000 MeasuredValue, int16 | Backplate temperature; min/max −2000/6000 |
Analog Output 0x000D | 0x0055 PresentValue, single, read/write | Value, rounded on write. Also Description 0x001C, Min/MaxPresentValue 0x0045/0x0041, EngineeringUnits 0x0075 (71 hours, 72 minutes, 98 percent). |
Analog Input 0x000C | 0x0055 PresentValue, single | Value. EngineeringUnits 73 seconds, 71 hours. Writing 0 to the filter runtime (endpoint 6) says the filter was changed, as filter_reset; any other write is refused. |
Binary Input 0x000F | 0x0055 PresentValue, bool | The state. Description 0x001C is its name, as in the table above; endpoint 28's reads External temperature in use. |
Binary Output 0x0010 | 0x0055 PresentValue, bool, read/write | The setting. Description 0x001C is its name, as in the table above. |
Weather cluster (0xFC00, manufacturer-specific), endpoint 1
What the thermostat used to get from Google: MQTT's set/outdoor_temperature, set/outdoor_humidity and set/weather as attributes, all read/write, written by the coordinator with manufacturer code 0x10D6 in the frame and kept in memory until written again.
- None. Each kind of value has one "none":
0x8000for an int16,0xFFfor a uint8,0xFFFFFFFFfor a UTCTime (seconds since 2000-01-01 UTC), the empty string for the condition. - Range. Any int16 outside −60 to 60 °C, or uint8 above 100, gets
INVALID_VALUE. - Forecast slots. The forecast is in slots, hour hh (0–23, in hex: hour 23's time is
0x1170) at0x1hhfand day dd (0–5) at0x2ddf, f the field; a slot whose time is none is left out of the forecast, so write every slot. - Frame size. A frame holds about 12 attributes (4 hours, or 3 days); Zigbee2MQTT's converter does the splitting, from the weather blueprint for Zigbee.
| Attribute | Type | Meaning |
|---|---|---|
0x0000 | int16 | Outdoor temperature, 0.01 °C, −60 to 60 °C; also Thermostat's OutdoorTemperature |
0x0001 | uint8 | Outdoor humidity, % |
0x0002 | string | Condition, Home Assistant's name (sunny, partlycloudy, rainy, …), for the screen's image |
0x0003, 0x0004 | UTCTime | Next sunrise and sunset, as sun.sun's next_rising and next_setting |
0x0005 | int16 | External temperature, 0.01 °C, −30 to 60 °C: MQTT's set/external_temperature. Reads back the reading while it counts. Refused without the external temperature option. |
0x1hh0, 0x2dd0 | UTCTime | The hour's time; the day's date |
0x1hh1, 0x2dd1 | int16 | The hour's temperature; the day's high |
0x1hh2, 0x2dd2 | uint8 | Humidity, % |
0x2dd3 | int16 | The day's low |
Matter
A Matter node on UDP port 5540, over Wi-Fi and, with Thread support, Thread. Any Matter controller commissions it over IP or, on a 3rd generation with the supported Bluetooth firmware, Bluetooth, with the pairing code from Integrations; the discriminator is 512 with the default code, and a custom code sets its top 4 bits, the rest zero.
On the thermostat, UNFR0ZEN → Matter → Enable pairing → Forget and pair confirms removal of every existing Matter fabric and its sessions before a fresh pairing window opens. Failed re-pairing does not restore the removed controllers. Wi-Fi and Zigbee settings are retained.
| Basic Information | Value |
|---|---|
| VendorID, ProductID | 0xFFF1, 0x8001 (Matter test IDs, test attestation: controllers must accept uncertified devices) |
| VendorName, ProductName | Google Nest, Nest Learning Thermostat |
| HardwareVersion, SoftwareVersion | 3, 1 on every unit: Matter doesn't tell the generations apart |
| SerialNumber | The unit's serial |
| NodeLabel | The device name an install gives (--device-name), set when it changes, ConfigurationVersion bumped with it; otherwise what a controller wrote, empty at first. The commissioning advertisement's DN is the device name, Nest Thermostat unless named |
| SoftwareVersionString | Nest firmware version |
| Endpoint | Device type | Clusters | What |
|---|---|---|---|
| 1 | Thermostat | Identify, Thermostat, Relative Humidity Measurement, Thermostat User Interface Configuration | The thermostat; °C/°F |
| 2 | Temperature Sensor | Identify, Temperature Measurement, Fixed Label | Backplate temperature |
| 3 | Power Source | Power Source (battery), Fixed Label | Battery: BatVoltage in mV, BatChargeLevel |
| 4 | Fan | Identify, Fan Control, Fixed Label | FanModeSequence Off/High: FanMode High (or On) runs the fan timer, Off stops it, others are refused. PercentSetting above 0 acts as High; 0 or null as Off. PercentCurrent is 100 while the fan runs, else 0 (with a fan) |
| 5 | Mode Select | Mode Select, Fixed Label | Fan timer duration: modes 0–7 are 15, 30, 45, 60, 120, 240, 480, 720 min; CurrentMode is the nearest to the unit's duration (with a fan) |
| 6 | Mode Select | Mode Select, Fixed Label | External temperature, with the external temperature option: modes 0–60 are 5–35 °C by half degrees. ChangeToMode is a new reading, MQTT's set/external_temperature, also to the mode it is already in. CurrentMode reads 30 (20 °C) while there is no reading. |
| 7 | Mode Select | Mode Select, Fixed Label | Temperature source, with the external temperature option: mode 0 backplate, mode 1 external, MQTT's temperature_source. ChangeToMode to the current mode succeeds; to the other fails with INVALID_ACTION. |
| 10… | On/Off Plug-in Unit | Identify, On/Off, Fixed Label | The switches: On, Off, Toggle |
| 40–42 | Mode Select | Mode Select, Fixed Label | The fan schedule (with a fan): 40 its run time, modes 0–3 are 15, 30, 45, 60 min per hour (CurrentMode the nearest); 41 and 42 its start and end, modes 0–23 are the hours |
Switches are numbered from 10 in this order, skipping those the equipment lacks: Auto-Schedule, Home/Away Assist, Sunblock, Early-On, Eco heat limit (can heat), Eco cool limit (can cool), Humidity control (with a humidifier or dehumidifier), Hot water boost, 30 minutes when on, and Hot water schedule (with hot water control), Filter reminder and Filter reset (with an air filter; Filter reset always reads off, and turning it on resets the filter as filter_reset), and last, Fan schedule (with a fan).
The numbers therefore differ between units: identify each by its Fixed Label, ha_entitylabel, whose value is the name above. Endpoints 2–7 are labelled Backplate temperature, Battery, Fan, Fan timer duration, External temperature and Temperature source; 40–42 Fan schedule run time, Fan schedule start and Fan schedule end.
The equipment is read once, at start, as on Zigbee.
Thermostat cluster
- Features: Heating, Cooling, AutoMode, Occupancy, Presets. What the unit can do is in ControlSequenceOfOperation (read-only): heating only, cooling only, or cooling and heating.
- SystemMode: Off, Heat, Cool, Auto (
heat_cool). A mode the equipment can't do is refused with a constraint error. - Occupied setpoints: the range in Auto; otherwise either one sets the single target. Limits 9–32 °C, dead band 1.5 °C. In Auto, a write closer than the dead band to the other setpoint is refused with a constraint error.
- Unoccupied setpoints are the eco temperatures. Writes: heating 9–21 °C, cooling 24–32 °C. Matter refuses the 4.5–9 °C that MQTT and Zigbee accept, but reads it, there and in the preset, when set that way.
- Occupancy (as MQTT's
occupancy), OutdoorTemperature (from MQTT or Zigbee's Weather cluster; subscribers get it with the next other change), ThermostatRunningState (heat, cool, fan, heat stage 2, cool stage 2). - Presets: one, handle
eco(the eco temperatures). SetActivePresetRequest withecoturns eco on, with null back to the schedule. ActivePresetHandle isecoor null. - Commands: SetpointRaiseLower and SetActivePresetRequest. No weekly schedule. SetpointRaiseLower stops at the limits and the dead band; outside Auto it moves the target whichever side it names.
Not on Matter: the indicators (Leaf, Early-On and Sunblock active, safety shutoff, filter replacement, hot water, humidifier and dehumidifier running), which of the other HVAC stages runs (W3, aux, alt and emergency heat, Y3), the target humidity, time to temperature, filter runtime, clearing the schedule, and sending the weather or the time: OutdoorTemperature only reads what MQTT or Zigbee supplied. Use MQTT or Zigbee for those.