All notable changes to nest_gen2. Versions follow Semantic Versioning:
while the version is 0.x, a minor release (0.1 → 0.2) may change the API.
0.6.6 (2026-11-01)
NestGen2.Text: fix an app crashing when it rendered text while another process's render was slow. A caller now waits its turn instead of giving up after 30 s; each render still stops at 20 s with{:error, :timeout}, now set bytext_render_ms.
0.6.5 (2026-10-30)
- Deep sleep: fix the Nest staying awake for good after one refused suspend. The SDK's own once-a-second idle check fell into step with the 8 s retry and was always waiting when the SDK looked for anything to handle first, so it refused every attempt. That check no longer counts.
NestGen2.DisplayandNestGen2.Text: fix apps crashing when drawing or rendering text took more than 5 s while the Nest was busy. Display calls now wait up to 30 s; a render that takes over 20 s returns{:error, :timeout}and restarts the renderer, so its late reply can't be taken for the next text's.examples/sdk_test: an app that shows every event the SDK sends, for checking a Nest and an SDK build.deploy_app.shstops when it can't reach the Nest (for example while it is in deep sleep) instead of carrying on as if no SDK were installed.
0.6.4 (2026-10-28) — use 0.6.5: can stay awake for good after one refused suspend
- Deep sleep: fix 0.6.2 and 0.6.3 never suspending, so the Nest drained its battery on its base until it restarted. Every message from the base is a wake-up event, and the base answers the sleep notice, so the wake-up count taken before the notice was always out of date and the kernel refused every suspend. The SDK now takes the count 250 ms after the notice, once the base has gone quiet, as Nest's own sleep daemon does.
- The Hex package also has the
NestGen2.Display30 s call timeout listed under 0.6.5.
0.6.3 (2026-10-28) — use 0.6.4: never suspends on the Nest
- Deep sleep: fix a press that reached the SDK in the few milliseconds before it read the wake-up count being left unhandled until the next wake (up to 270 s). If anything is already waiting to be handled at that point, the SDK handles it first and tries to sleep again shortly after.
- No compiler warning in
NestGen2.Displayon newer Elixir versions.
0.6.2 (2026-10-28) — use 0.6.4: never suspends on the Nest
- Deep sleep: fix a press or motion in the moment the Nest goes to sleep
being missed, so it slept on for up to 270 s. Before suspending, the SDK now
uses the kernel's
wakeup_counthandshake (as Nest's own sleep daemon does): any wake-up event after it decided to sleep cancels the suspend. - Deep sleep: fix the light thresholds in the sleep notice (
b9). The SDK sent the room temperature there, which the base takes as "wake the display when the light goes above this", so in a bright room it could wake straight away. They are now setlight_wake_jump_pct(at leastlight_wake_min_deltacounts) either side of the room's light, and off without:lightinwake_sources. - Deep sleep: the base's wake mask (
a4) followswake_sources: someone near wakes the display only with:motion, a change in light only with:light. The temperature and humidity wakes are off, so the base no longer wakes the display every 30 s on cold mornings at all. docs/backplate.md: the wake mask and wake reason bits, and the light thresholds, named from Nest's own software.
0.6.1 (2026-10-26)
- Watch-only viewer:
config :nest_gen2, host_viewer_controls: falseshows the screen with no buttons and refuses every press, turn and climate change, for putting an app's screen on a public website. Its replies may be cached for a second by a CDN in front. See "Showing it publicly" indocs/host.md. - The viewer encodes the screen only when it changes, instead of on every fetch.
0.6.0 (2026-10-21)
- Host mode (
config :nest_gen2, target: :host): run an app on a computer instead of the Nest, unchanged, to develop and test screens without deploying. The SDK touches no hardware: the screen is drawn in memory, the climate is a steady simulated reading, and deep sleep, the clock and Wi-Fi are left alone. Seedocs/host.md. NestGen2.Host.Viewer: on the host, the screen in a browser at http://localhost:4000, with the ring turned by mouse wheel, drag or arrow keys, and buttons for a press, double click, long press and someone walking past. Uses OTP's own:inets; no new dependencies.NestGen2.Host:turn/1,step/1,click/0,double_click/0,long_press/0,motion/1,climate/2andscreenshot/0, producing the same events as the hardware.mix nest_gen2.hostbuilds the text renderer for the computer and checks for the fonts (copied from your own Nest; they aren't shipped).NestGen2.Display.snapshot/0(on the Nest too): what the screen shows.NestGen2.Image.to_png/1.NestGen2.Dial.turn/1,press/1andstep/0.- Text fonts are found in
font_dir(default the Nest's/nestlabs/share/fonts).
0.5.1 (2026-10-15)
- Deep sleep: the sleep notice's low-temperature threshold (
c2) is now 5 °C instead of Nest's 16.48 °C. Below the threshold the base woke the display every 30 s (wake reason0x0004), so on a cold morning the Nest barely slept; with 5 °C it sleeps the full 270 s. docs/power.md: why the Nest drains its battery on its base unless it deep-sleeps, what the SDK does about it, and what an app should do.docs/backplate.md: the backplate's hardware and serial protocol (frames, start-up, keep-alive, the sleep protocol and every known message), from our captures and the cuckoo-nest project's research, with each fact's source and credits.
0.5.0 (2026-10-14)
- Deep sleep (
deep_sleepconfig /NestGen2.Power.set_deep_sleep/1, off by default): 10 s after the screen goes dark the whole system suspends to RAM, as Nest's own software does, and wakes on the button, on the base (motion), or after at most 270 s. It tells the base first (the sleep notice Nest's client sends, with the planned seconds) and repeats Nest's wake-up exchange afterwards. Without it the Nest drains its battery even on its stand, which supplies only about 120 mA; with it, the battery charges (measured +290 mV/h against -70 mV/h). - The base's wake reason (0x0014) is decoded and traced.
0.4.0 (2026-10-14)
NestGen2.Gestureand the:gesturetopic::click,:double_clickand:long_pressfrom the button, withbutton_double_click_ms(default 300,nilfor none) andbutton_long_press_ms(default 800).:button:down/:upare unchanged.
0.3.0 (2026-10-13)
NestGen2.Storage: per-app settings in flash (put/3,get/3,delete/2,keys/1,dir/1), written so a power cut mid-write can't corrupt them (temporary file, flush, rename, previous value kept as a fallback), stored as readable text with a checksum.platform/storage.sh: list, read, write and delete an app's stored values from your computer.NestGen2.Wifi.save/2: save a network without switching to it, e.g. a phone hotspot before taking the Nest somewhere new.
0.2.5 (2026-10-12)
- Backplate framing moves from C to Elixir.
bplinkis now a byte pipe (it sets the serial line up and sends the BREAK, nothing else) speaking{packet, 2}, andNestGen2.Backplate.Framefinds, checks and builds frames with binary pattern matching: partial frames are kept for the next chunk, noise and bad checksums are skipped. Checked against traffic captured from Nest's own firmware: the same frames found, and the head's frames re-encoded byte for byte. No API change; the trace keeps its format.
0.2.4 (2026-10-12)
- Fix: the screen went dark after 10 minutes and only a press brought it back, even
with an idle timeout of
:infinity. That was the Linux console, not the SDK: it blanks the framebuffer after 10 minutes without keyboard input, and on the Nest only the button counts as a keyboard (not the dial or the motion sensor).NestGen2.Displaynow turns console blanking off at start, and un-blanks the screen wheneverNestGen2.Powerwakes it.
0.2.3 (2026-10-10)
- Backplate restarts are counted (
NestGen2.Backplate.status/0gainsrestarts) instead of logged: after the first wake-up, each restart and its chatter ("BRK", the firmware banner, "sense", and "HVAC power lost", which a base with no heating system wired to it prints) no longer reach the log. A loose head unit on its base restarts it now and then; the SDK wakes it again within about 2 seconds. - The optional backplate trace (
trace_file) is capped at 256 KB (trace_max_bytes), the older part kept as<file>.1. It lives in/tmp, which is RAM: uncapped, it grew about 7 MB a day and ran the Nest out of memory overnight, which resets the board ("Global Cold Reset").
0.2.2 (2026-10-04)
- Install guide and scripts. docs/install.md goes from a 2nd-gen
Nest flashed with No Longer Evil to foxbus and then your own app.
platform/install.sh <nest-address>installs the platform (SSH key, a prebuilt runtime bundle with a checked sha256, Wi-Fi, boot script with the original kept asrcS.stock) and--checkreports what's running;platform/uninstall.shrestores the original. examples/hello_nest: the smallest useful app, as a starting point.- The Hex description, README and package links say it's for a Wi-Fi-connected Nest rooted with No Longer Evil, and link to the install guide and NLE's rooting instructions.
deploy_app.shinstalls the SDK with the app on the first deploy to a Nest, and with--sdkreplaces a different version; it removes an updated library's old.beamfiles.app_watchdog.shwaits quietly until the app has been deployed.host_env.shworks with OTP 26 / Elixir 1.17 from mise or asdf, anddeploy_app.shstops early with what to install if the toolchain is wrong.- Platform:
wifi.sh add SSIDsaves another network over SSH (the password is asked for without echo, and only the derived key is stored), so a phone hotspot can be set up before taking the Nest somewhere new. - Platform:
app_watchdog.shkeeps the previous run's log as<app>.log.1. - Platform: at boot,
wifi.sh takeoverno longer hands Wi-Fi back to Nest's connection manager when the gateway is slow to answer (which, with Nest's software stopped, left the Nest offline until the next reboot); it keeps retrying. The old behaviour iswifi.sh trial. The Wi-Fi log moves to<install>/wifi.logso it survives a reboot.
0.2.1 (2026-10-03)
- The backplate is woken the way Nest's own client does it, each time the link opens: a serial BREAK, then answering its 0x0004 hello (echoed as 0x8f) and its start-up queries. After a reset or a power loss the backplate otherwise stays silent (no motion, light or climate readings, and the green LED flashing) until the stock firmware runs.
- If no backplate message arrives for 15 s, the handshake runs again (at most once a minute).
bplinkacceptsbrk(flush, then a 100 ms BREAK).
0.2.0 (2026-10-03)
NestGen2.Wifi: status, scan, connect (with automatic fall-back to the previous network and nothing saved on failure), saved networks, forget;:wifievents. Passwords are stored as the derived WPA key.NestGen2.version/0.- Platform:
entropyd, started from rcS, keeps the kernel's entropy pool topped up. Without it OpenSSL blocks on/dev/randomat the first TLS connection and stalls the whole VM. evwatchexits when its port closes instead of lingering until the next input event.- Platform: Wi-Fi from boot (
wifi.sh takeoverin rcS), andwifi.sh guard, which restartswpa_supplicantfrom the saved configuration after 3 minutes without the gateway. platform/mix26: runmixwith the Nest's toolchain regardless of the shell's version manager.
0.1.0 (2026-10-02)
First release.
Head unit
NestGen2.Display: page-flipped drawing on the round 320×320 screen (set_background/1with an image or a hex colour drawn as the visible disc,put_image/3,fill_rect/5,put_text/4,present/0).NestGen2.Text: text rendered on the device from its own fonts (no font files shipped).NestGen2.Dial: rotation (7800 counts per turn), steps with Nest's click, and press.NestGen2.Backlight,NestGen2.Piezo,NestGen2.Power(sleep after idle; wake on dial, button, motion or a flicker in room light;keep_awake/1holds that keep the screen on, released explicitly or when the holder exits).
Backplate
- Keep-alive that stops the backplate power-cycling the head unit.
NestGen2.Motion,NestGen2.Climate,NestGen2.Battery,NestGen2.Light, and events (:motion,:light,:climate,:battery).
System
NestGen2.Network: DNS without Nest's connection manager.NestGen2.Clock: SNTP sync of UTC, saved to the RTC. Takes four samples per server and trusts the shortest round trip (rejecting any over 500 ms), first sync 30 s after start.- Platform:
app_watchdog.sh(one watchdog per app; the VM records its own pid),deploy_app.sh(deploy an app without the SDK, checking the SDK version on the device), Wi-Fi without connmand (platform/wifi).
Known limitations
- If the backplate is reset (or loses power while the head unit stays up) it stops reporting and periodically power-cycles the head unit. Booting the stock firmware once brings it back; the SDK cannot yet do this itself.