😺

Go言語によるRaspberry, MH-Z19B, DHT22を利用した環境測定

2024/12/16に公開

はじめに

前回の記事ではCO2濃度だけだったのですが、手持ちのセンサーを追加して気温と湿度も測定できるよう拡張しました。

環境設定

  • 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 get go.bug.st/serial
  • DHT22用ライブラリ
$ go get github.com/MichaelS11/go-dht

機器の接続

接続図

※図ではRasberry Pi3となっていますが、実際にテストしたのはPi4です。

プログラム説明

  1. main()
    • mainで1分おきにループしてCO2測定処理、温度・湿度測定処理を呼出し、結果をログ出力します
  2. getMH_Z19B()
    • シリアル通信でCO2濃度を取得しています
    • 本来readできるデータのサイズは9バイトなのですが、結構なタイミングで先頭部分が欠落します。欲しいデータは3バイト目と4バイト目なので、ここが欠落した場合は5回リトライして、だめならあきらめます
  3. getDHT22()
    • DHT22との通信は専用の単線式デジタル通信なので、すべてモジュールにおまかせです。

プログラム

package main

import (
	"errors"
	"log"
	"time"

	"go.bug.st/serial"

	"github.com/MichaelS11/go-dht"
)

func main() {
	for range time.Tick(time.Minute*1) {
		co2Conc, err1 := getMH_Z19B()
		if err1!=nil {
			log.Println("getDHT22 error:",err1)
		}
		temperatur, humidity, err2 := getDHT22()
		if err2!=nil {
			log.Println("getDHT22 error:",err2)
		}
		log.Printf("Tmp:%4.1f, Hum:%.1f %%, CO2:%4d ppm", temperatur, humidity, co2Conc)
	}
}

func getMH_Z19B() (int, error) {
	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("Z19B serial port open error:",err)
		return 0,err
	}
	defer port.Close()

	buf := make([]byte, 128)

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

	for i:=0; i<5; i++ {
		_, errW := port.Write(readCmd)
		if errW != nil {
			log.Println("Z19B serial port write error:",err)
			continue
		}

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

		if nRead>=7 {
			co2conc := int(buf[nRead-7])*256 + int(buf[nRead-6])
			return co2conc,nil
		} else {
			//log.Println("Z19B serial port read size error:",nRead)
			continue
		}
	}
	return 0,errors.New("MH_Z19B error")
}

func getDHT22() (float64,float64,error) {
	err := dht.HostInit()
	if err != nil {
		log.Println("HosiInit error:", err)
		return 0.0,0.0,err
	}

	dht, err := dht.NewDHT("GPIO18", dht.Celsius, "")
	if err != nil {
		log.Println("NewDHT error:", err)
		return 0.0,0.0,err
	}

	humidity, temperature, err := dht.ReadRetry(11)
	if err != nil {
		log.Println("Read error:", err)
		return 0.0,0.0,err
	}

	return temperature, humidity, nil
}

最後に

Discussion