nerves_time

CircleCI Hex version

`NervesTime` keeps the system clock on Nerves devices in sync when connected to the network and close to in sync when disconnected. It's especially useful for devices lacking a Battery-backed real-time clock and will advance the clock at startup to a reasonable guess.

Installation

First add `nerves_time` to your project's dependencies:

def deps do
  [
    {:nerves_time, "~> 0.3.0"}
  ]
end

Ensure that your `vm.args` allows for timewarps. If it doesn't, `nerves_time` will update the OS system time, but Erlang's system time will lag. The following line should be in the beginning or middle of the `vm.args` file:

+C multi_time_warp

If you're using one of the official Nerves Systems, then this is all that's needed. `nerves_time` requires Busybox's `ntpd` and `date` applets to be enabled. If you haven't explicitly disabled the, they're probably enabled.

Configuration

`nerves_time` uses ntp.pool.org for time synchronization. Please see their terms of use before tweaking `nerves_time`. Alternative NTP servers can be specified using the `config.exs`:

# config/config.exs

config :nerves_time, :servers, [
    "0.pool.ntp.org",
    "1.pool.ntp.org",
    "2.pool.ntp.org",
    "3.pool.ntp.org"
  ]

It's also possible to configure NTP servers at runtime. See `NervesTime.set_ntp_servers/1`.

`nerves_time` also has a concept of a valid time range. This minimizes time errors on systems without clocks or Internet connections or that may have some issue that causes a very wrong time value. The default valid time range is hardcoded and moves forward each release. It is not the build timestamp since that results in non-reproducible builds. Applications can override the valid range via the application config:

# config/config.exs

config :nerves_time, earliest_time: ~N[2019-10-04 00:00:00], latest_time: ~N[2022-01-01 00:00:00]

Algorithm

Here's the basic idea behind `nerves_time`:

  • If the clock hasn't been set or is invalid, set it to the earliest valid time known to `nerves_time`. This is either set in the application config or defaulted to a reasonable value that likely moves forward a little each `nerves_time` release.
  • Check for `~/.nerves_time`. If it exists, advance the clock to it's last modification time.
  • Run Busybox `ntpd` to synchronize time using the NTP protocol.
  • Update `~/.nerves_time` periodically and on graceful power downs. This is currently only done at around 11 minute intervals to avoid needless exercising of Flash-based memory.

To check the NTP synchronization status, call `NervesTime.synchronized?/0`.

Credits and license

This project started as a fork of nerves_ntp by Marcin Operacz and Wojciech Mandrysz. It has quite a few changes from since when they worked on the project, but some of their code still exists. Both their project and this one are covered by the Apache-2.0 license.