Nervesでtarget(Raspberry Pi等)で動かすときはこっち、host(macOS等)で動かすときはそっち


(この記事は、「#NervesJP Advent Calendar 2019」の7日目です)
昨日はYoosukeさんの「Nerves と GraphQLsever の組み合わせを考える「ポエム」」です!こちらもぜひぜひ!

はじめに

ちょっとだけ困ったことの具体例

  • Nervesから動かしていることをアピールするために "I use Nerves. I like it!" を差し込みたいとします
lib/weather/forecast.ex
defmodule Weather.Forecast do
  def run({city, name}) do
    description =
      "http://weather.livedoor.com/forecast/webservice/json/v1?city=#{city}"
      |> HTTPoison.get!()
      |> Map.get(:body)
      |> Poison.decode!()
      |> Map.get("description")
      |> Map.get("text")
      |> String.split()
      |> Enum.reduce_while("#{name}\n", fn s, acc ->
        if String.length(acc <> "#{s}\n") < 140 - String.length(i_use_nerves()),
          do: {:cont, acc <> "#{s}\n"},
          else: {:halt, acc}
      end)
      |> Kernel.<>(i_use_nerves())
  end

  def run do
    cities() |> Enum.random() |> run
  end

  defp i_use_nerves do
    "I use Nerves. I like it!"
  end
  • こう書くと、microSDカードに焼き込んでNervesで動かしいているときは問題ないのですが、開発の途中にhost(macOS等)で動かしているときは、 "I use Nerves. I like it!" といれたくありません
  • 結局最後は、Nervesで動かすのですから、そんな些細なこと気にしなくてもいいのかもしれません
  • このままの状態で、Twitterに投稿するまでをテストしたいときには、"I use Nerves. I like it!" が入ってしまうので、ちょっとだけうそつきになります
  • なにかコンパイルスイッチというかそういうもので、 target(Raspberry Pi等)で動かすときはこっち、host(macOS等)で動かすときはそっち ができないものかと調べてみました

Mix.target() => (使えません)

  • mix nerves.new hello_nerves したときにできる config/config.exsMix.target()なる記述がありました
config/config.exs
if Mix.target() != :host do
  import_config "target.exs"
end
  • これを使って、
lib/weather/forecast.ex
  defp i_use_nerves do
    if Mix.target() != :host do
      "I use Nerves. I like it!"
    else
      ""
    end
  end
  • なんてやると動くのかなと最初はおもいました
  • しかしこれをmicroSDカードに焼き込んでRaspberry Pi2で動かしてみても動きません
  • Mix.target()なんて使えないよ的なエラーがでます

解決策

lib/weather/forecast.ex
  defp i_use_nerves do
    if Application.get_env(:hello_nerves, :target) != :host do
      "I use Nerves. I like it!"
    else
      ""
    end
  end
  • 他にもいい方法があるのかもしれません
  • ここで得た知識はjbernardo95/cronexNervesアプリケーションで使おうとしたときに、Mix.env が使えないよ的なエラーに遭遇したことがありましてそのエラーを調査する際にどこかで聞いた話だなとピンときました

if(condition, clauses) のconditionを != じゃなくて == で書きたい

  • 2019/12/22 追記
  • if Application.get_env(:hello_nerves, :target) != :host の部分
  • Nerves on Raspberry Pi 2で動かしてみました
iex> Application.get_env(:hello_nerves, :target)
:rpi2
  • MIX_TARGETに設定したTargets TAGが返ってくるようです
  • if Application.get_env(:hello_nerves, :target) == :rpi2 と書けないわけではないですが、他のTargetでも動かすことを考える(もっていないけど)と、!= の書き方のほうがいいかなあとおもっています

まとめ

  • Leap before you look

次回

次回はpojiroさんの「作って学ぶNerves、BBBでCO2計測」です!こちらも是非どうぞ~