Solving timekeeping issues on an offline Nest thermostat

The issue

Some time ago I received a smart Nest thermostat as part of a promotional offer. I wasn't very keen on the idea of having something like a thermostat phoning home to a centralised server in the "cloud", but it was a good deal and the Nest does still offer some benefits over a traditional dumb thermostat even when it has no access to the internet. I have a good number of reasons for wanting to keep the thermostat disconnected from the internet and I will not go into them here as that is not the point of this article.

There is one downside to keeping the Nest disconnected though; it's not very good at keeping track of the date and time. In fact, it's quite bad at it actually, I'd see it reset to January the 1st 1970 every few days or weeks. As a result, this messes up your heating schedule and you might find yourself being in a cold house when you'd expect it to be warm, or the thermostat might instruct your heating to turn on in the middle of the night wasting unnecessary energy and money.

Looking into Nest traffic

The behaviour as described above indicates that the Nest lacks a proper RTC, or realtime clock. Searching on the internet on several occasions did not yield me many useful results, it appears that most users of the thermostat do not suffer from this problem. This led me to believe that the thermostat relies on some sort of network service to periodically query the time and adjust itself. I suspected it was using the well-established NTP protocol for this, and set out investigate.

As I have OpenWRT running on my router, I added a firewall rule to block all traffic going from the LAN to the WAN for the MAC address of the Nest. I used LuCI for doing this but you can also use uci over ssh if you prefer. You can find out the MAC address of your Nest before connecting it to a network by going into Settings > Technical Info and scrolling all the way down until you see it listed.

After this, I felt comfortable configuring the thermostat to connect to my WiFi AP and to inspect the traffic it would generate. For this I am using tcpdump on the router and examining the capture files with Wireshark on my desktop.

When I did this I noticed I made a small mistake, I blocked the wrong MAC address from accessing the internet and my Nest did in fact phone home. While being connected for less than 5 minutes, it submitted some sort of statistical data to the Nest servers and pulled in a firmware update. I had no way of preventing this update after it was pulled in, though I don't mind that as much as the statistics it managed to send off. So, make sure you block the right MAC address or just even pull the cable to your modem entirely if you want to be on the safe side.

After quickly correcting my firewall rule, I noticed the Nest was not too happy with the connection. It'd try to connect and upon finding that the internet wasn't accessible it'd disassociate from the AP again. The new firmware it pulled in is more tolerant of the restricted network capabilities, it stays connected to the WiFi AP without much complaining. Looks like my little mistake did end up benefitting me after all.

On to addressing the issue at hand, which is timekeeping. I noticed some very convenient behaviour in the traffic I analysed. The Nest does indeed rely on NTP for keeping time, and it actually tries to query your network's gateway for it first! In my case that meant it was trying to connect to an NTP server on my router which I did not have running. After a few failed attempts, it resolves time.nest.com and queries that instead.

The solution

At this point there are three possible approaches I can think of to give the Nest the time information it seeks:

  1. Host an NTP daemon on the router
  2. Redirect DNS queries for time.nest.com to a machine within my LAN that has an NTP daemon running
  3. Explicitely allow NTP requests to access the internet

I decided to go for option 1 as it seemed the simplest and most direct way of remedying the timekeeping issues whilst keeping all control.

For OpenWRT there are various ways to host an NTP daemon, but the quickest way to accomplish this without pulling in any extra packages is to use the ntpd that is compiled into busybox. Instructions on how to do this may be a little unclear online as it seems to be a recent inclusion into OpenWRT, but it is in fact very simple.

Connect to your OpenWRT/LEDE router over ssh and open up /etc/config/system in your favourite editor. There will be a section describing the NTP configuration:

config timeserver 'ntp'
    list server '0.openwrt.pool.ntp.org'
    list server '1.openwrt.pool.ntp.org'
    list server '2.openwrt.pool.ntp.org'
    list server '3.openwrt.pool.ntp.org'
    option enabled '1'

After these existing options defining the nameservers and enabling the client, add the following line:

    option enable_server '1'

Save the file, exit, and run /etc/init.d/sysntpd reload. You're done! At this point you can verify that the ntp daemon is up and running by issuing netstat -l; it should now show that there's a service listening to the NTP port. Further traffic analysis of the Nest shows me that the Nest is indeed getting an NTP response from my router and that it doesn't bother to query time.nest.com after that.

social