🐱

Go言語によるRaspberry PiとMH-Z19Bを利用したCO2濃度検出

2024/12/14に公開

はじめに

Raspberry Pi4-BとMH-Z19Bを使って部屋のCO2濃度を計測して遊んでいたのですが、これ計測結果をDBにためたり、濃度が一定値を超えるとメールしたりしたいなぁと感じました。普通はPythonでやるのでしょうが、Python嫌い苦手なので大好きなGoで書きました。

環境設定

Goのインストール

$ wget https://go.dev/dl/go1.23.4.linux-arm64.tar.gz
$ sudo tar -C /usr/local -xzf go1.23.4.linux-arm64.tar.gz
$ rm go1.23.4.linux-arm64.tar.gz 

シリアル通信用のライブラリ取得(go mod initはよしなに)

$ go get go.bug.st/serial

go-serial

Rapsberry Pi4-Bのシリアルポート設定

/dev/serial0がBluetoothに割り当てられている場合、ソフトウェアシリアルポートが適用されてCPU負荷の影響を受けてREADの際に先頭バイト(0xff)を取りこぼすケースがあったのでシリアルポートの設定を行った。

  1. /boot/firmware/config.txtの確認
    • 以下の行によりbluetoothが無効になっていることを確認
dtoverlay=disable-bt
  1. raspi-configで以下を設定



プログラムソース

package main

import (
  "fmt"
  "log"
  "os"

  "go.bug.st/serial"
)

func main() {
  mode := &serial.Mode{
    BaudRate: 9600,
    DataBits: 8,
    Parity:   serial.NoParity,
    StopBits: serial.OneStopBit,
  }
  port, err := serial.Open("/dev/serial0", mode)
  if err != nil {
    log.Println("serial port open error:",err)
    os.Exit(1)
  }
  defer port.Close()

  buf := make([]byte, 128)

  readCmd := []byte{0xff, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}

  _, errW := port.Write(readCmd)
  if errW != nil {
    log.Println("serial port write error:",err)
    os.Exit(2)
  }

  nRead, errRead := port.Read(buf)
  if errRead != nil {
    log.Println("serial port read error:",err)
    os.Exit(3)
  }

  if nRead!=9 {
    log.Println("serial port does't work. data size::",nRead)
    os.Exit(4)
  }

  co2conc := int(buf[2])*256 + int(buf[3])

  fmt.Println("CO2:", co2conc, "ppm")
}


プログラム説明

  1. シリアル通信のモード設定
  2. ポートは"dev/serial0"を使用
  3. MH-Z19Bの読み込みコマンドを送信する(データシート参照)
  4. 9バイトの計測結果からCO2濃度を取得(データシート参照)
  5. 結果を焼くなり、煮るなり好きなように

MH-Z19Bデータシート

実行結果

$ go build main.go
$ sudo ./main
CO2: 1294 ppm

最後に

「なんでPythonでやらないの?馬鹿なの」という声が聞こえてきそうですが、Goが好きなんです。Rob PikeとRuss CoxがMy Heroなんです。
実はBME280という温度/湿度を取得できるセンサも所持しているので、これもなんとかRaspiにつないで温度/湿度/CO2濃度を記録できるようにしたいと思っています。

Discussion