11
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Elixir × Nerves で MH-Z19 を動かす

Last updated at Posted at 2021-05-15

はじめに

Elixir で CO2センサー MHZ19 の読み取り方を書いたものが見つからなかったため,この記事を書くことにした.

使用するもの

前提

  • Nervesが入っている
  • mh-z19 が配線されている

本編

ライブラリのインストール

  • mh-z19 は UART通信を用いるので,Circuits.UART(ドキュメント) を使う.

まずは mix.exs に追加したあと,mix deps.get する.

defp deps do
    [
      # ....
      {:circuits_uart, "~> 1.3"}
    ]
  end

コード

[mh-z19 データシート](https://www.winsen-sensor.com/d/files/PDF/Infrared Gas Sensor/NDIR CO2 SENSOR/MH-Z19 CO2 Ver1.0.pdf) に従って,後々使いやすいように(?) GenServerの形で実装する.

init

  • UART の GenServer (このGenServerとは別) を起動して,pid を状態としてを持っておく.
  • UART GenServer の "ttyAMA0" インタフェースを開く.このとき,データシートに従って baud_rate 等のパラメタを設定しておく.

handle_call

GenServer へ :read の呼び出しが来たときに,センサーの読み取り値を返す.

  • センサーの値を読み取るコマンド @sensor_read_commandwrite してあげる.
  • read_uart を呼び出して,帰ってきた値を読む.
    • read_uart では,結果を含む返信を読むまでループして,結果を返すか,結果が得られなければ {:error, reason} を返す.(reasonCircuits.UART のエラーを含む)

measure

値を読むためのメソッド.使うときはこれを呼べば良い.

defmodule WarblerUi.Sensors.Mhz19 do
  use GenServer, restart: :permanent

  alias Circuits.UART

  @baud_rate 9600
  @sensor_read_command <<0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79>>

  def init(_opts) do
    {:ok, uart_pid} = UART.start_link()

    :ok =
      UART.open(uart_pid, "ttyAMA0",
        speed: @baud_rate,
        data_bits: 8,
        stop_bits: 1,
        parity: :none,
        active: false
      )

    {:ok, uart_pid}
  end

  def handle_call(:read, _from, uart_pid) do
    :ok = UART.write(uart_pid, @sensor_read_command)
    read_uart(uart_pid)
  end

  defp read_uart(uart_pid) do
    case UART.read(uart_pid) do
      {:ok, <<255, 134, higher_bits, lower_bits, _, _, _, _>>} ->
        decoded_data = higher_bits * 256 + lower_bits
        {:reply, {:ok, decoded_data}, uart_pid}

      {:error, reason} ->
        {:reply, {:error, reason}, uart_pid}

      _ ->
        read_uart(uart_pid)
    end
  end

  def measure(pid) do
    GenServer.call(pid, :read)
  end
end

使い方

Nerves のコンソールを ssh nerves.local して開き,こんな感じで実行すれば,CO2 濃度がわかる.

alias WarblerUi.Sensors.Mhz19
{:ok, mhz19_pid} = GenServer.start_link(Mhz19, {})
{:ok, co2} = Mhz19.measure(mhz19_pid)

あとがき

現在は Phoenix フレームワークを使って,センサーの値を liveview で表示したりしようとしています.
気が向いたらそれについても書くかもしれません.

また,Elixir, Nerves を始めて間もなく,初めての記事なので,間違い等あるかもしれないです.
見つけた場合は指摘していただければ幸いです.

11
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?