unfr0zen Download

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 (2150 is 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's can_heat in raw/shared stays 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.

ConnectionValue
Client IDnestlocal-<serial>
SessionClean session
Keepalive3600 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.
Willoffline on nestlocal/<serial>/availability, retained, QoS 1
Subscriptionsnestlocal/<serial>/set/# and homeassistant/status, QoS 1
ReconnectEvery 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>/.

TopicDirectionPayload
availabilityout, retained, QoS 1online while the broker has nestlocal and the unit has called in within 5 minutes; offline otherwise.
stateout, retainedOne JSON object every entity reads: MQTT state. Published again on every change.
raw/<bucket>out, retainedOne 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>inA command: MQTT commands.
updateout, retainedunfr0zen'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/updateininstall: 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/requestoutEmpty: 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_id is <component>.<root>_<key>, the root nestlocal_<serial in lowercase> unless the install named another, and its device is named Nest Thermostat unless named otherwise; unique_id and the device's identifier keep nestlocal_<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 next online on homeassistant/status, for a Home Assistant that wasn't running the first time.
  • Without Home Assistant. Every config reads state and names its availability topic, 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, 1 or 0, in any case, as are the ON and OFF of hot_water_boost and filter_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.
CommandPayloadEffect
modeoff heat cool heat_coolSystem mode. heat_cool is the unit's range mode.
target°C, 4.5–35The setpoint in heat or cool.
target_low, target_high°C, 4.5–35The range's setpoints in heat_cool.
preseteco none (or empty)Eco on, or back to the schedule.
fan_modeon autoon runs the fan for the fan timer duration (15 min if unset); auto stops the timer.
fan_timer_durationwhole minutes, 15–1440How long fan_mode on runs the fan.
fan_scheduleon/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_minutes15 30 45 60Minutes of each hour the fan schedule runs the fan; 60 is always on.
fan_schedule_start, fan_schedule_endhour, 0–23 or 07:00When the fan schedule starts and ends each day; the same start and end run it all day.
away_temperature_low°C, 4.5–21Eco heating temperature.
away_temperature_high°C, 24–32Eco cooling temperature.
away_temperature_low_enabled, away_temperature_high_enabledon/offWhether eco heats, or cools, at all.
learning_modeon/offAuto-Schedule.
auto_away_enableon/offHome/Away Assist.
sunlight_correction_enabledon/offSunblock.
preconditioning_enabledon/offEarly-On.
target_humidity%, 10–60Target humidity (with a humidifier or dehumidifier).
target_humidity_enabledon/offHumidity control.
hot_water_boostoff, 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_scheduleon/off (with hot water control)On: hot water follows its schedule. Off: the unit's hot water mode is off.
temperature_scaleC FWhat the unit displays. Every protocol stays in °C.
filter_reminder_enabledon/offFilter reminder (with an air filter): whether the unit reminds to change the filter.
filter_resetanything but OFF, which does nothingThe air filter was changed: the unit zeroes its runtime and clears the reminder.
clear_scheduleanythingEmpties 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–60A 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–60Outdoor temperature for the unit's weather. Not a setting: kept in memory only.
outdoor_humidity%, 0–100Outdoor humidity. The unit shows no weather until it has both.
weatherJSONConditions and forecast: Weather & clock.
timeseconds since 1970The answer to time/request.
raw/<bucket>JSON objectMerged 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.

FieldTypeMeaning
modestringoff, heat, cool or heat_cool.
target, target_low, target_high°CSetpoints. In heat_cool the range applies; otherwise target.
current_temperature°CRoom temperature.
current_humidity%Room humidity.
actionstringWhat the system is doing: off, heating, cooling, fan or idle.
heating, cooling, fan_runningboolaction 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_3boolThe 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_modestringon while the fan timer runs, else auto.
fan_timer_endRFC 3339When the fan timer ends, or null.
fan_timer_durationstringMinutes, as text ("15"). Absent until the unit has one.
fan_scheduleboolThe fan runs on its schedule.
fan_schedule_minutesstringThe schedule's minutes per hour, as text ("30"). Absent until the unit has one.
fan_schedule_start, fan_schedule_endstringThe schedule's start and end, "HH:MM". Absent until the unit has them.
presetstringeco or none.
eco_modestringThe 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°CEco 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.
occupancybooltrue 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_targetRFC 3339When the unit expects to reach the setpoint, or null.
backplate_temperature°CThe backplate's own sensor, exact.
battery_levelVThe display's battery voltage.
rssinumberWi-Fi signal.
local_ipstringThe unit's IP address.
current_versionstringNest firmware version.
external_temperature°C or nullThe latest reading while it counts. With the external temperature option only.
temperature_sourcestringexternal or backplate: what the unit regulates from. With the external temperature option only.
temperature_scalestringC or F: what the unit displays.
target_humidity%Target humidity.
filter_runtime_sec, filter_runtime_hs, hAir 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_enabledboolThe settings of the same-named commands.
leafboolThe Leaf shows.
preconditioning_active, sunlight_correction_activeboolEarly-On, Sunblock acting now.
hvac_safety_shutoff_activeboolThe unit's safety temperature shutoff tripped.
filter_replacement_neededboolFilter reminder due.
hot_water_active, hot_water_boiling_stateboolHot water (with hot water control).
hot_water_booststringoff, or the shortest of 30, 60 and 120 covering the minutes left.
hot_water_scheduleboolHot water follows its schedule rather than being off.
humidifier_state, dehumidifier_stateboolRunning.
heatpump_readyboolThe 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.
  • condition is 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_rising and next_setting together 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 with is_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.

NetworkValue
JoiningActive scan of channels 11–26; joins, as a router, the network permitting joins with the best link quality (Zigbee PRO stack profile only).
SecurityThe 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.
RejoinThe network is kept on the unit and in the radio: restarts don't need pairing again.
Manufacturer code0x10D6 (Nest Labs): the ZDO node descriptor's, and the code in the Weather cluster's frames
Basic: ManufacturerNameGoogle Nest
Basic: ModelIdentifier2nd generation: Nest Learning Thermostat (gen2); 3rd generation: Nest Learning Thermostat
Basic: HWVersion2 or 3, matching the thermostat generation
Basic: SWBuildID (0x4000)Nest firmware version
Basic: PowerSource0x81: 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-only READ_ONLY, the wrong type INVALID_DATA_TYPE, an attribute the cluster lacks UNSUPPORTED_ATTRIBUTE.
  • Reads with no value yet. A read of an attribute with no value yet gives ZCL's "none" for its type (0x8000 for LocalTemperature, OutdoorTemperature and MeasuredValue, 0xFFFF for humidity, 0xFF for 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.

EndpointDevice typeServer clustersWhat
1Thermostat 0x0301Basic, Power Configuration, Identify, Thermostat, Thermostat UI Configuration, Relative Humidity, Weather (0xFC00), Fan Control (with a fan). Client: TimeThe thermostat
2Temperature Sensor 0x0302Temperature MeasurementBackplate temperature
3Level Controllable Output 0x0003Analog OutputFan timer duration, minutes, 15–1440 (with a fan)
4Level Controllable Output 0x0003Analog OutputTarget humidity, %, 10–60 (with a humidifier or dehumidifier)
5Simple Sensor 0x000CAnalog InputTime to temperature, seconds left (0: none)
6Simple Sensor 0x000CAnalog InputFilter runtime, hours (with an air filter); writing 0 resets it
7Level Controllable Output 0x0003Analog OutputFan schedule run time, minutes per hour: 15, 30, 45 or 60 (with a fan)
8Level Controllable Output 0x0003Analog OutputFan schedule start, hour of the day, 0–23 (with a fan)
9Level Controllable Output 0x0003Analog OutputFan schedule end, hour of the day, 0–23; the start's runs it all day (with a fan)
10On/Off Output 0x0002Binary OutputAuto-Schedule
11On/Off Output 0x0002Binary OutputHome/Away Assist
12On/Off Output 0x0002Binary OutputSunblock
13On/Off Output 0x0002Binary OutputEarly-On
14On/Off Output 0x0002Binary OutputEco heat limit (can heat)
15On/Off Output 0x0002Binary OutputEco cool limit (can cool)
16On/Off Output 0x0002Binary OutputHumidity control (with a humidifier or dehumidifier)
17On/Off Output 0x0002Binary OutputHot water boost, 30 minutes when on (with hot water control)
18On/Off Output 0x0002Binary OutputHot water schedule (with hot water control)
19On/Off Output 0x0002Binary OutputFilter reminder (with an air filter)
20Simple Sensor 0x000CBinary InputLeaf
21Simple Sensor 0x000CBinary InputEarly-On active
22Simple Sensor 0x000CBinary InputSunblock active
23Simple Sensor 0x000CBinary InputSafety shutoff
24Simple Sensor 0x000CBinary InputFilter replacement (with an air filter)
25Simple Sensor 0x000CBinary InputHot water (with hot water control)
26Simple Sensor 0x000CBinary InputHumidifier (with a humidifier)
27Simple Sensor 0x000CBinary InputDehumidifier (with a dehumidifier)
28Simple Sensor 0x000CBinary InputTemperature source (with the external temperature option): true while the unit regulates from the external temperature, MQTT's temperature_source external. Read-only.
29On/Off Output 0x0002Binary OutputFan schedule (with a fan)
30Simple Sensor 0x000CBinary InputHeat stage 1 (with any other heat stage below)
31Simple Sensor 0x000CBinary InputHeat stage 2 (W2 wired)
32Simple Sensor 0x000CBinary InputHeat stage 3 (W3 wired)
33Simple Sensor 0x000CBinary InputAux heat (aux heat wired)
34Simple Sensor 0x000CBinary InputAlt heat (alt heat wired)
35Simple Sensor 0x000CBinary InputAlt heat stage 2 (a second alt heat stage wired)
36Simple Sensor 0x000CBinary InputEmergency heat (emergency heat wired)
37Simple Sensor 0x000CBinary InputCool stage 1 (with another cool stage)
38Simple Sensor 0x000CBinary InputCool stage 2 (Y2 wired)
39Simple Sensor 0x000CBinary InputCool stage 3 (Y3 wired)

Thermostat cluster (0x0201), endpoint 1

AttributeTypeAccessMeaning
0x0000 LocalTemperatureint16readRoom temperature
0x0001 OutdoorTemperatureint16readThe last set/outdoor_temperature over MQTT, or the Weather cluster's
0x0002 Occupancymap8readBit 0 set for 15 minutes after the motion sensor last saw someone, as MQTT's occupancy
0x0003–0x0006, 0x0015–0x0018int16readSetpoint limits: 900 (9 °C) and 3200 (32 °C)
0x0011 OccupiedCoolingSetpointint16read, writetarget_high in auto, else target
0x0012 OccupiedHeatingSetpointint16read, writetarget_low in auto, else target
0x0013 UnoccupiedCoolingSetpointint16read, writeEco cooling temperature, 24–32 °C
0x0014 UnoccupiedHeatingSetpointint16read, writeEco heating temperature, 4.5–21 °C
0x0019 MinSetpointDeadBandint8read15 (1.5 °C)
0x001B ControlSequenceOfOperationenum8read0x00 cooling only, 0x02 heating only, 0x04 both, or neither reported yet
0x001C SystemModeenum8read, write0x00 off, 0x01 auto (heat_cool), 0x03 cool, 0x04 heat
0x0025 ThermostatProgrammingOperationModemap8read, write0x04 (economy) in eco, 0x01 (schedule) otherwise. Writing bit 2 sets or clears eco.
0x0029 ThermostatRunningStatemap16readBit 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

ClusterAttributeMeaning
Identify 0x00030x0000 IdentifyTime, uint16Always 0. Writes and commands 0x00, 0x01 succeed and do nothing.
Power Configuration 0x00010x0020 BatteryVoltage, uint8Display battery, in 100 mV
Fan Control 0x02020x0000 FanMode, enum8, read/write0x04 on (fan timer running), 0x05 auto. Writing 0x00 also means auto.
Fan Control 0x02020x0001 FanModeSequence0x04: on/auto
Thermostat UI Configuration 0x02040x0000 TemperatureDisplayMode, enum8, read/write0 °C, 1 °F
Thermostat UI Configuration 0x02040x0001 KeypadLockoutAlways 0, read-only
Relative Humidity 0x04050x0000 MeasuredValue, uint16Room humidity, 0.01 %; min/max 0/10000
Temperature Measurement 0x04020x0000 MeasuredValue, int16Backplate temperature; min/max −2000/6000
Analog Output 0x000D0x0055 PresentValue, single, read/writeValue, rounded on write. Also Description 0x001C, Min/MaxPresentValue 0x0045/0x0041, EngineeringUnits 0x0075 (71 hours, 72 minutes, 98 percent).
Analog Input 0x000C0x0055 PresentValue, singleValue. 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 0x000F0x0055 PresentValue, boolThe state. Description 0x001C is its name, as in the table above; endpoint 28's reads External temperature in use.
Binary Output 0x00100x0055 PresentValue, bool, read/writeThe 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": 0x8000 for an int16, 0xFF for a uint8, 0xFFFFFFFF for 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) at 0x1hhf and day dd (0–5) at 0x2ddf, 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.
AttributeTypeMeaning
0x0000int16Outdoor temperature, 0.01 °C, −60 to 60 °C; also Thermostat's OutdoorTemperature
0x0001uint8Outdoor humidity, %
0x0002stringCondition, Home Assistant's name (sunny, partlycloudy, rainy, …), for the screen's image
0x0003, 0x0004UTCTimeNext sunrise and sunset, as sun.sun's next_rising and next_setting
0x0005int16External 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, 0x2dd0UTCTimeThe hour's time; the day's date
0x1hh1, 0x2dd1int16The hour's temperature; the day's high
0x1hh2, 0x2dd2uint8Humidity, %
0x2dd3int16The 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 InformationValue
VendorID, ProductID0xFFF1, 0x8001 (Matter test IDs, test attestation: controllers must accept uncertified devices)
VendorName, ProductNameGoogle Nest, Nest Learning Thermostat
HardwareVersion, SoftwareVersion3, 1 on every unit: Matter doesn't tell the generations apart
SerialNumberThe unit's serial
NodeLabelThe 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
SoftwareVersionStringNest firmware version
EndpointDevice typeClustersWhat
1ThermostatIdentify, Thermostat, Relative Humidity Measurement, Thermostat User Interface ConfigurationThe thermostat; °C/°F
2Temperature SensorIdentify, Temperature Measurement, Fixed LabelBackplate temperature
3Power SourcePower Source (battery), Fixed LabelBattery: BatVoltage in mV, BatChargeLevel
4FanIdentify, Fan Control, Fixed LabelFanModeSequence 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)
5Mode SelectMode Select, Fixed LabelFan 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)
6Mode SelectMode Select, Fixed LabelExternal 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.
7Mode SelectMode Select, Fixed LabelTemperature 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 UnitIdentify, On/Off, Fixed LabelThe switches: On, Off, Toggle
40–42Mode SelectMode Select, Fixed LabelThe 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 with eco turns eco on, with null back to the schedule. ActivePresetHandle is eco or 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.