unfr0zen Download

Integrations

Integrations are chosen at install: tick them in the app, or pass them to the unfr0zen command-line tool. To change them, run the install again.

nestlocal replaces the thermostat's connection to Nest's cloud. Nest's own nlclient keeps running the screen and the heating, pointed at nestlocal on the unit instead of Nest's servers. The Nest and Google Home apps no longer control the thermostat; Home Assistant does, over your network. Remaining traffic to Nest's and Google's servers, NTP for example, stops with Block Nest and Google servers.

  • nestlocal. MQTT, Matter, Zigbee and Doom are served by nestlocal, which any of them installs on the thermostat.
  • Wi-Fi. MQTT and Matter use Wi-Fi, joined from the thermostat's Settings → Network. The network doesn't need internet access.
  • Generations. 1st, 2nd and 3rd generation. The 1st has MQTT, Matter over Wi-Fi and the external temperature: no Zigbee or Matter over Thread (its radio is on a UART), and no USB shell. The Nest Thermostat E is detected and refused.
  • Command line. On Linux and macOS, the app's executable run with arguments; Windows has the app only.
  • Linux. Run the app and CLI as your normal user, after the one-time USB permission setup. Run logs: ~/.local/share/unfr0zen/logs/, or $XDG_DATA_HOME/unfr0zen/logs/ when set.
  • Your own integration. The MQTT topics, Zigbee clusters and Matter endpoints are documented under Protocols.

The install replaces the thermostat's NEST APP settings entry with UNFR0ZEN. It shows Matter pairing, Zigbee pairing with a 30-second countdown, and Doom. An integration's entry appears only when it was installed.

The menu is linked into the unit's own nlclient; the original is kept at /etc/unfr0zen/nlclient.original across installs. Supported versions and undo: platform/common/nlclient/README.md.

MQTT

AppCLI
MQTT, under Patch → Integrations; Broker host[:port]--mqtt host[:port]
User, Password--mqtt-user USER, --mqtt-password PASSWORD
Encrypt the connection (TLS), CA certificate--mqtt-tls, --mqtt-ca FILE
Device name, Entity ID root, under Home Assistant--device-name NAME, --ha-entity-root ROOT

The thermostat connects over Wi-Fi to your MQTT broker (the Mosquitto add-on, for example); Home Assistant's MQTT integration discovers and controls it there. The broker is the only intermediary. Port 1883, or 8883 with TLS; a password needs a user; a CA certificate turns on TLS.

Names in Home Assistant

Home Assistant shows the thermostat as a device named Nest Thermostat, with entity IDs like climate.nestlocal_<serial>_thermostat. A device name and an entity ID root replace them:

  • Device name. Nest FamRm for example: one line of at most 32 bytes, the same as Matter's.
  • Entity ID root. nest_famrm for example: lowercase letters and digits, words joined by _, at most 64 characters. It gives climate.nest_famrm_thermostat, sensor.nest_famrm_current_temperature.
  • <serial> in either stands for the thermostat's 16-character serial, which counts towards the limit (lowercase in the root, kikoo_<serial>_lol for example).

Left empty, the thermostat keeps the names it has, so installing again for an update changes nothing. With a new root, Home Assistant (2025.10 or later) moves the thermostat's entities to the new IDs, with their history and what was set on them there (names, areas, icons); automations and dashboards need the new IDs. If Home Assistant isn't running when the thermostat connects after the install, the IDs change the next time it starts.

Entities

A climate entity with off, heat, cool, heat-cool, eco and fan modes, setpoints and range, and action, and beside it:

  • Eco and the eco temperatures
  • Humidity
  • Target humidity
  • Occupancy
  • °C/°F
  • Backplate temperature
  • Battery
  • Fan and its timer
  • Fan schedule: on/off, minutes per hour, start and end hours
  • Auto-Schedule
  • Home/Away Assist
  • Sunblock
  • Early-On
  • Eco heat and cool limits
  • Leaf, Early-On, Sunblock, safety shutoff and filter indicators
  • Heating, cooling and fan running
  • Each wired HVAC stage running
  • Time to temperature
  • Filter runtime
  • IP address
  • Wi-Fi signal
  • Clear schedule

With the equipment for them:

  • Filter reminder and its reset
  • Hot water state, schedule and boost
  • Humidifier and dehumidifier state
  • Humidity control

Updates

An unfr0zen update entity shows the version the thermostat runs and, when it can reach GitHub, the latest release, checked every 6 hours. On a 3rd generation unit Install downloads that release's bundle, checks it against its manifest and unfr0zen's release key, installs it and restarts the thermostat. Only official releases install, and never one older than the installed version, unless Allow unsigned updates was on when the unit was patched. 1st and 2nd generation units show the versions; update them with the app. An install that fails says why in the thermostat's log and leaves it running; one that does not come back after the restart is fixed by patching it again with the app over USB.

A thermostat that can't reach GitHub installs a release's bundle (unfr0zen-diamond3-<version>.tgz, from the release's assets) from your own network: put it on any web server the thermostat reaches and publish its URL, for example from a Home Assistant script:

action: mqtt.publish
data:
  topic: nestlocal/<serial>/set/update
  payload: http://nas.lan/unfr0zen-diamond3-v0.5.0.tgz

Weather and clock

Two Home Assistant blueprints replace what Google supplied. Both need MQTT; on Zigbee, see Zigbee.

Weather

Sends outdoor temperature, humidity, conditions and forecast every 15 minutes, when Home Assistant starts, and when the weather entity comes back from unavailable or unknown.

Import it, create an automation, pick the thermostat and a weather entity. Outdoor sensors are optional; °F is converted to °C.

Import the weather blueprint

Clock

On a network without NTP access, Home Assistant answers the thermostat's time requests.

Import it and create an automation; no settings, answers every thermostat.

Import the clock blueprint

Matter

AppCLI
Matter, under Patch → Integrations--matter
Pairing code--matter-code CODE
Device name, under Home Assistant--device-name NAME

Works alone or beside MQTT; needs Wi-Fi. The device name, shared with MQTT, is the name controllers show: Matter's node label, at most 32 bytes, <serial> standing for the serial. An install that gives a new one sets it; a name changed in the controller stays until then.

Pairing

Pairing code 0347-100-5534, or one of your own with a valid check digit; --matter-code turns on Matter. The first pairing window opens by itself: UNFR0ZEN → Matter shows Ready to pair with the QR and code, then Paired.

  1. Home Assistant: Settings → Devices & services → Add integration → Matter.
  2. Add the device with the pairing code, or scan the QR shown on the thermostat.
nestlocal uses the Matter test vendor ID (0xFFF1) and test attestation, so controllers treat it as uncertified. Home Assistant's Matter server accepts it only with its test-net DCL option on.

Enable pairing → Forget and pair forgets every Matter controller before opening a new window. This cannot be undone, even if the new pairing fails; Wi-Fi and Zigbee settings are kept.

Entities

Home Assistant gets the thermostat (modes, setpoints and range, action, eco as a preset, humidity, outdoor temperature), occupancy, °C/°F, backplate temperature, battery, fan and its timer, the fan schedule's run time, start and end, and switches for Auto-Schedule, Home/Away Assist, Sunblock, Early-On, the eco limits and, with a humidifier or dehumidifier, humidity control, and with hot water control, Hot water boost (30 minutes when on) and Hot water schedule, and with an air filter, the filter reminder and a Filter reset switch that resets the filter when turned on, and with a fan, the fan schedule. The other MQTT entities aren't offered over Matter.

Bluetooth commissioning

3rd generation units with the supported DA14580 Bluetooth firmware also pair over Bluetooth; nestlocal loads the unit's own radio firmware into RAM, the stock image unchanged. Bluetooth advertises only while the pairing window is open; traffic goes over Wi-Fi or Thread. The thermostat's own Bluetooth is turned off for it: real Nest Temperature Sensors stop working, and the Nest app cannot pair with it over Bluetooth. Other units pair over IP.

Sleep

Experimental. The thermostat sleeps between Matter messages and wakes for a controller's: unicast UDP to port 5540, and on the 3rd generation also a DNS-SD lookup of the unit and an IPv6 neighbour solicitation for its addresses. nestlocal adds these to the wake patterns Nest's sleep daemon gives the Wi-Fi chip. The 2nd generation's chip lets no multicast through while the unit sleeps, so it answers lookups when it wakes on its own. Each wake reports to the controllers' subscriptions, which they keep through its sleep. It stays awake while commissioning. With more fabrics than the chip has room for, lookups of other Matter devices wake it too.

Matter over Thread

AppCLI
Thread support, under Matter--matter-thread

The thermostat joins a Thread mesh as a router and serves Matter over it, beside Wi-Fi; the commissioner supplies the credentials. Needs Matter. Takes the radio from Nest's Thread firmware (Heat Link), so not with Zigbee. On the 2nd generation nestlocal flashes a Thread image and keeps the unit awake while Thread runs. Design and device details: platform/common/radio/thread/README.md.

Zigbee

AppCLI
Zigbee, under Patch → Integrations--zigbee

A Zigbee router on the thermostat's own 802.15.4 radio, alone or beside MQTT and Matter. On first start nestlocal replaces Nest's Thread firmware (Heat Link) with its own; installing again without Zigbee puts Nest's back. Transmit power is Nest's -15 dBm.

Heat Link models

A 3rd generation Heat Link model (Display-3.x, Display-5.x) on firmware 6.4-8 can stop on H71 or H74 once the Heat Link can't connect. With Zigbee or Thread, Works With Nest boiler (--wwn-boiler) sets the unit up as heating a Works With Nest boiler: it keeps heating through W1 with its safety temperature and real backplate sensors, and Zigbee, Matter and MQTT offer heat. Off unless chosen; installing again without it takes it back. While set: Safety Temp shows a notice (its values stay in force), Heating Equipment does nothing, Pro Setup's boiler pages go nowhere, and with nothing on W1 the boiler has to be driven from the setpoint, with a relay from Home Assistant for example.

Coordinators

Any Zigbee 3.0 coordinator works: standard clusters, so ZHA needs no quirk (its switches need zha 0.0.61, June 2025, or later). Zigbee2MQTT with the converter is recommended: it names every entity and carries the weather.

  1. Zigbee2MQTT 2.12.1 or later: copy nest-learning-thermostat.mjs to data/external_converters/ and restart Zigbee2MQTT.
  2. Permit join on the coordinator. The thermostat joins the strongest network permitting joins, on any channel, and keeps it across restarts.
  3. After updating the converter, re-interview the device to refresh its generation-specific model, then Reconfigure it so Home Assistant gets the new entities.

The switches are Binary Output clusters, so ZHA names them. A thermostat paired on an older release has to be paired again in ZHA, or re-interviewed in Zigbee2MQTT with the updated converter; delete the old switch entities.

Entities, clock and weather

With the converter, Home Assistant gets the MQTT entities under the same names, minus IP address and Wi-Fi signal; temperature and HVAC action sit on the climate entity. The clock comes from the coordinator's Time cluster, no blueprint needed. The weather has a Zigbee2MQTT blueprint: import it, create an automation, pick the thermostat, the base topic (default zigbee2mqtt) and a weather entity. Outdoor sensors are optional; °F is converted to °C. Nothing needs Wi-Fi.

Import the weather blueprint for Zigbee

Joining and moving networks

On a coordinator with per-device keys, a router needs its own trust-centre link key to help others join. If the thermostat still has only the global key, enable pairing again.

To move networks: UNFR0ZEN → Zigbee → Enable pairing. The thermostat leaves its network, forgets its credentials and looks for one permitting joins for 30 seconds; on timeout it stays off any network until pairing is enabled again or nestlocal restarts.

Sleep

The radio routes while the thermostat sleeps and wakes it for a message, on the 2nd generation's kernel and the 3rd generation's 5.8 to 6.1 kernels; on others, messages wait until the unit wakes. The 2nd generation doesn't sleep with a USB cable connected.

External temperature

AppCLI
External temperature, under Patch → Integrations--external-temperature

A thermometer of yours regulates the heating in place of the thermostat's own sensor. Every generation, with MQTT, Matter or Zigbee. nestlocal presents a virtual Nest Temperature Sensor (gen 1 and 2: local sensor input, on Nest firmware 5.9.4-5; gen 3: Bluetooth). Send readings and the thermostat regulates from them; stop, and it goes back to its own sensor.

  • One sensor. Only one external temperature is supported for now.
  • Named after the thermostat's room. The sensor takes the thermostat's room, so the Sensors menu lists it under that room's name, Living room for example. It cannot be renamed on its own yet.
  • On 3rd generation, Bluetooth is turned off. The thermostat no longer hears real Nest Temperature Sensors, and the Nest app cannot pair with it over Bluetooth.

Setting it up in Home Assistant

Install with the option and your integration, then import that integration's blueprint and create an automation. Each sends the reading on change, every 10 minutes and when Home Assistant starts; °F is converted to °C; nothing is sent while the thermometer is unavailable.

MQTT. Import external-temperature-mqtt.yaml, create an automation from it, and pick the thermostat (its MQTT device) and your room temperature sensor. It publishes each reading to nestlocal/<serial>/set/external_temperature.

Import the external temperature blueprint for MQTT

Zigbee2MQTT. Use the converter from Zigbee. After updating it, re-interview the thermostat, then Reconfigure it, so Home Assistant gets Temperature source. Import external-temperature-zigbee.yaml, create an automation from it, and pick the thermostat, the Zigbee2MQTT base topic (default zigbee2mqtt) and your room temperature sensor. It publishes {"external_temperature": 21.5} to <base topic>/<IEEE address>/set. There is no blueprint for ZHA: the reading is attribute 0x0005 of the manufacturer-specific cluster 0xFC00 (see Protocols).

Import the external temperature blueprint for Zigbee2MQTT

Matter. The thermostat's Matter device gets an External temperature select offering 5 to 35 °C in half degrees. Import external-temperature-matter.yaml, create an automation from it, and pick that select and your room temperature sensor. Readings are rounded to the nearest half degree. Choosing the same temperature again counts as a new reading.

Import the external temperature blueprint for Matter

How it behaves

  • The sensor appears in the Sensors menu when the thermostat starts. The thermostat uses its own sensor until the first reading arrives.
  • A reading counts for 30 minutes, repeated to the thermostat every minute. About 11.5 minutes after it lapses, the thermostat goes back to its own sensor until the next reading.
  • Choosing the backplate in the Sensors menu lasts until the thermostat restarts. After a restart, the next reading switches it back to the external temperature.
  • Home Assistant shows External temperature, the reading while it counts, and Temperature source, external or backplate. Zigbee2MQTT shows Temperature source only. On Matter both are selects: Temperature source shows the source, and choosing the other one is refused.
  • Installing again without the option removes the sensor from the thermostat, its Sensors menu entry included, and undoes the gen 1 and 2 input patch or restores the gen 3 Bluetooth setting.

Other options

The app's Patch page takes you through Connect, Integrations, Features and Review. Works With Nest boiler (with Zigbee or Thread), Block Nest and Google servers, the time server, SSH, the USB console, Doom and Dark theme are on Features; Device, Entry point, Backplate simulator and Allow unsigned updates under Developer options on Review, which also offers a NAND backup before the patch.

AppCLIWhat it does
Block Nest and Google servers--block-cloudResolves Nest's and Google's servers to nowhere, and checks for the internet at Cloudflare. Turns on the custom NTP server.
Custom NTP server; Time server under Block Nest and Google servers--ntp-server [HOST]Sets the firmware's time server to HOST instead of time.nest.com (default pool.ntp.org). nestlocal's own clock check stays on pool.ntp.org.
SSH--sshRuns an SSH server on the unit (dropbear on the 1st and 2nd generation, host keys kept in system-config).
Your key, under SSH--ssh-public-key FILERequires --ssh. Adds one OpenSSH public key to root's authorized keys without replacing existing keys. Use an ECDSA key with the 3rd generation's stock OpenSSH 6.0; Ed25519 is supported by the 2nd generation's dropbear. Supply a public .pub file, never a private key.
USB console--usb-shellRoot shell on the unit's USB serial port. On the 2nd generation it installs a kernel with a USB serial port, booted ahead of the stock one, which stays as the fallback.
Allow password login, turned off--ssh-key-onlyRequires --ssh-public-key. SSH takes the key only: root's password is refused over SSH.
Root password--root-password PASSWORDFor SSH and the USB shell (default unfr0zen).
Backplate simulator (1H1C)--backplate-sim1H1C with a simulated temperature, for testing off the wall.
Allow unsigned updates--allow-unsigned-updatesThe unit installs updates that unfr0zen's release key does not sign, such as your own builds, and older versions than the one it runs. Off, it installs only official releases, never going back.
Not available--nand-image FILE1st or 2nd generation: patches a raw NAND image (2112-byte pages) in place instead of a unit.
Entry point--entry-point ENTRY_POINT3rd generation: how its boot ROM is entered for recovery: auto (default) tries the official loader, then CVE-2017-7932, then CVE-2017-7936; or official-loader, cve-2017-7932, cve-2017-7936. It applies to a patch, backup, restore and booting the application, in the app and the CLI.
Device--device diamond|j49|diamond3The generation (1st, 2nd, 3rd) to expect instead of the one identified on USB. The app applies it to a patch only.
Dark theme--dark-theme2nd generation, Nest firmware 5.9.4-5: shows the settings screens in the 3rd generation's dark colours, and the boot logo on black. The app offers it when a 2nd generation is connected. A run without it brings back the light colours.
Works With Nest boiler--wwn-boilerNeeds Zigbee or Thread. See Zigbee.
Rescueunfr0zen bootBoots the application firmware from any mode: a 3rd generation through recovery U-Boot, a 1st or 2nd generation by restarting the flasher an interrupted run left on USB.
Not availableunfr0zen uboot3rd generation: loads recovery U-Boot and leaves it at its prompt.
Serial consoleNot availableA terminal on a patched unit's USB root shell.
Offered at startunfr0zen updateInstalls the latest release.

Every CLI option: unfr0zen --help.

Backup & restore

AppCLI
Back up unitunfr0zen backup [OUT]
Not availableunfr0zen verify IMAGE
Restore to unit, Restore from fileunfr0zen restore IMAGE
  • Backup. The whole NAND as an image with a .sha256 beside it. On the 3rd generation: 512 MiB, ECC-corrected, with a .bad list of its bad and unreadable blocks. On the 1st and 2nd: raw pages with OOB, unclean blocks read until two reads agree. Nothing is written during a backup.
  • Resume. unfr0zen backup OUT with the same OUT resumes an interrupted backup; the app, and a run without OUT, start a new file.
  • Restore. Verifies the image against the .sha256, asks, then writes it back. On the 1st and 2nd generation the factory-bad blocks must match the chip's, only differing blocks are rewritten, and an interrupted restore is run again.

Doom

AppCLI
Doom, under Patch → Features--doom

Installs Doom with the shareware episode (DOOM1.WAD v1.9, included). Start it from UNFR0ZEN → Doom → Play.

  • You walk forward all along. Turn the ring to steer, press it to fire. Doors and switches open as you walk into them.
  • In menus, the ring moves and a press selects.
  • Hold the ring for 3 seconds to quit back to the thermostat.
  • Sound comes from the piezo: the PC speaker effects and each song's highest note.