diff --git a/lib/nerves_motd.ex b/lib/nerves_motd.ex index d62eef5..ac53547 100644 --- a/lib/nerves_motd.ex +++ b/lib/nerves_motd.ex @@ -84,6 +84,7 @@ defmodule NervesMOTD do [ [{"Uptime", uptime()}], [{"Clock", Utils.formatted_local_time()}], + temperature_row(), [], [firmware_cell(), applications_cell(apps)], [memory_usage_cell(), active_application_partition_cell()], @@ -108,6 +109,19 @@ defmodule NervesMOTD do [" ", format_cell(col0, 0), format_cell(col1, 1), "\n"] end + defp format_row(nil), do: [] + + @spec temperature_row() :: [cell()] | nil + defp temperature_row() do + case runtime_mod().cpu_temperature() do + {:ok, temperature_c} -> + [{"Temperature", :erlang.float_to_binary(temperature_c, decimals: 1)}] + + _ -> + nil + end + end + @spec format_cell(cell(), 0 | 1) :: IO.ANSI.ansidata() defp format_cell({label, value}, column_index) do [format_cell_label(label), " : ", format_cell_value(value, column_index, 24), :reset] diff --git a/lib/nerves_motd/runtime.ex b/lib/nerves_motd/runtime.ex index 70c96fd..f2920bc 100644 --- a/lib/nerves_motd/runtime.ex +++ b/lib/nerves_motd/runtime.ex @@ -1,6 +1,7 @@ defmodule NervesMOTD.Runtime do @moduledoc false @callback applications() :: %{started: [atom()], loaded: [atom()]} + @callback cpu_temperature() :: {:ok, float()} | :error @callback firmware_valid?() :: boolean() @callback load_average() :: [String.t()] @callback memory_stats() :: @@ -33,6 +34,21 @@ defmodule NervesMOTD.Runtime.Target do %{started: started, loaded: loaded} end + @impl NervesMOTD.Runtime + def cpu_temperature() do + # Read the file /sys/class/thermal/thermal_zone0/temp. The file content is + # an integer in millidegree Celsius, which looks like: + # + # 39008\n + + with {:ok, content} <- File.read("/sys/class/thermal/thermal_zone0/temp"), + {millidegree_c, _} <- Integer.parse(content) do + {:ok, millidegree_c / 1000} + else + _error -> :error + end + end + @impl NervesMOTD.Runtime def firmware_valid?() do Nerves.Runtime.firmware_valid?() diff --git a/test/nerves_motd_test.exs b/test/nerves_motd_test.exs index 2511b3c..39ad549 100644 --- a/test/nerves_motd_test.exs +++ b/test/nerves_motd_test.exs @@ -88,6 +88,22 @@ defmodule NervesMOTDTest do assert capture_motd() =~ ~r/Clock : \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \w{3}/ end + test "Temperature when available" do + NervesMOTD.MockRuntime + |> Mox.expect(:applications, 1, default_applications_code()) + |> Mox.expect(:cpu_temperature, 1, fn -> {:ok, 41.234} end) + + assert capture_motd() =~ ~r/Temperature : 41.2/ + end + + test "Temperature when unavailable" do + NervesMOTD.MockRuntime + |> Mox.expect(:applications, 1, default_applications_code()) + |> Mox.expect(:cpu_temperature, 1, fn -> :error end) + + refute capture_motd() =~ ~r/Temperature/ + end + test "Firmware when valid" do NervesMOTD.MockRuntime |> Mox.expect(:applications, 1, default_applications_code()) diff --git a/test/support/runtime.ex b/test/support/runtime.ex index 3989f2d..1a7fdfe 100644 --- a/test/support/runtime.ex +++ b/test/support/runtime.ex @@ -21,6 +21,9 @@ defmodule NervesMOTD.Runtime.Host do @impl NervesMOTD.Runtime def applications(), do: %{loaded: @apps, started: @apps} + @impl NervesMOTD.Runtime + def cpu_temperature(), do: {:ok, 41.234} + @impl NervesMOTD.Runtime def firmware_valid?(), do: true