NervesTime (nerves_time v0.4.11)

Copy Markdown View Source

Keep time in sync on Nerves devices

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.

Nearly all configuration is via the application config (config.exs). The following keys are available:

  • :servers - a list of NTP servers for time synchronization. Specifying an empty list turns off NTP
  • :time_file - a file path for tracking the time. It allows the system to start with a reasonable time quickly on boot and before the Internet is available for NTP to work.
  • :earliest_time - times before this are considered invalid and adjusted
  • :latest_time - times after this are considered invalid and adjusted
  • :ntpd - the absolute path to the Busybox ntpd. This only needs to be set if your system does not provide ntpd in the $PATH.
  • :await_initialization_timeout - Timeout to await a successful system time initialization on startup before continuing asynchronously. Set in milliseconds. Defaults to 0.

Summary

Types

NTP daemon event names emitted to subscribers.

Metadata reported by the NTP helper script for a synchronization event.

Current NTP synchronization state.

Functions

Return the current NTP servers

Manually restart the NTP daemon

Set the list of NTP servers

Set the system time

Subscribe a process to NTP daemon events.

Return the current NTP synchronization status.

Check whether NTP is synchronized with the configured NTP servers

Unsubscribe a process from NTP daemon events.

Types

ntpd_event()

@type ntpd_event() ::
  :sync_status | :sync_acquired | :sync_updated | :sync_lost | :clock_step

NTP daemon event names emitted to subscribers.

ntpd_event_report()

@type ntpd_event_report() :: %{
  freq_drift_ppm: integer(),
  offset: float(),
  stratum: integer(),
  poll_interval: integer()
}

Metadata reported by the NTP helper script for a synchronization event.

sync_status()

@type sync_status() :: %{
  synchronized?: boolean(),
  last_sync_report: ntpd_event_report() | nil,
  sync_acquired_at: DateTime.t() | nil,
  last_sync_at: DateTime.t() | nil
}

Current NTP synchronization state.

Functions

ntp_servers()

@spec ntp_servers() :: [String.t()] | {:error, term()}

Return the current NTP servers

restart_ntpd()

@spec restart_ntpd() :: :ok | {:error, term()}

Manually restart the NTP daemon

This is normally not necessary since NervesTime handles restarting it automatically. An example of a reason to call this function is if you know when the Internet becomes available. For this case, calling restart_ntp will cancel ntpd's internal timeouts and cause it to immediately send time requests. If using NTP Pool, be sure not to violate its terms of service by calling this function too frequently.

set_ntp_servers(servers)

@spec set_ntp_servers([String.t()]) :: :ok

Set the list of NTP servers

Use this function to replace the list of NTP servers that are queried for time. It is also possible to set this list in your config.exs by doing something like the following:

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

NervesTime uses NTP Pool by default. To disable this and configure servers solely at runtime, specify an empty list in config.exs:

config :nerves_time, :servers, []

set_system_time(time)

@spec set_system_time(NaiveDateTime.t()) :: :ok | :error

Set the system time

subscribe(pid \\ self())

@spec subscribe(pid()) :: :ok

Subscribe a process to NTP daemon events.

Subscribers receive messages in the form:

{:nerves_time, event, report}

Where event is one of:

  • :sync_status
  • :sync_acquired
  • :sync_updated
  • :sync_lost
  • :clock_step

:sync_status is sent immediately when subscribing so new subscribers can observe the current synchronization state without replaying old events.

sync_status()

@spec sync_status() :: sync_status()

Return the current NTP synchronization status.

synchronized?()

@spec synchronized?() :: boolean()

Check whether NTP is synchronized with the configured NTP servers

It's possible that the time is already set correctly when this returns false. NervesTime decides that NTP is synchronized when ntpd sends a notification that the device's clock stratum is 4 or less. Clock adjustments occur before this, though.

Once NTP is synchronized, it will remain that way until the nerves_time application is restarted.

unsubscribe(pid \\ self())

@spec unsubscribe(pid()) :: :ok

Unsubscribe a process from NTP daemon events.