在宅勤務になったので、会社よりも自宅のCO2濃度をちゃんと観測しなきゃな、って思うようになりました。
CO2観測用のセンサは昔やったことあるしいけるやろ、ということで挑戦。
UART直結
今回はWio Nodeでなく、Raspberry Pi Zero W(以下RasPi ZW)でいきます。
RasPi ZWはUARTをふたつ持っていて、デフォルトだとフル機能UART(PL011)は内部でBluetoothインタフェイスに繋がっていてminiUARTがGPIO側に出てくるようです。
書いてあるとおりデフォルトではminiUARTがdisableなので、sudo raspi-config あたりで有効化させて繋げば一発で動く。高々9600bpsでフロー制御もないので、PL011にせずともminiUARTでちゃんと疎通します。
ここまでのことはぐぐったら沢山出てくる。
dev.classmethod.jp
I2C経由
BME280を使って温度湿度気圧を一緒に取りたいので、I2Cだけで疎通させてみました。Wio Nodeのときに買ったSC16IS750が余ってるので、今回も使います。
ざっと組むとこんな感じ。
デバドラで会話編(失敗)
で、SC16IS750との会話です。ぐぐると、LinuxカーネルにSC16IS7xxシリーズ向けI2Cドライバ実装が入っていて、Raspberry OSのDevice Treeにも存在してる。
www.raspberrypi.org
firmware/README at master · raspberrypi/firmware · GitHub
linux/sc16is7xx.c at master · torvalds/linux · GitHub
/boot/config.txtに dtoverlay=sc16is750-i2c って書いて再起動すると/dev/ttySC0が生えるので、これに対してコマンドを送れば出来そう。
注意事項としてはフォーラムやDeviceTree overlayに書いてあるとおり、SC16IS750チップのIRQとRasPi ZWのGPIOを繋ぐ必要があります。
ドライバ実装を見ると、データ読み込み実装sc16is7xx_handle_rxはチップからGPIO経由で割り込みが入ったときに動くのでIRQを繋がないと返事が取れない。
しかし、疎通失敗。しかも、最新のRaspberry Pi OSだとドライバ読ませた段階でI2C通信が死んでしまう。なぜだ???
ユーザランドで会話編
デバドラなんかうまくいかんのでユーザーランドでI2C喋ってなんとかすることに。
Python
取り敢えずPythonで書いたろうとぐぐって調べると、できかけの実装を見つけました。それを元にUART読み書きだけ追加で実装。
で、雑にMH-Z19Bと会話する。
from SC16IS750 import Serial s=Serial.Serial() s.write(b"\xff\x01\x86\x00\x00\x00\x00\x00\x79") while True: r = s.read() if r != None: break if len(r) >= 4 and r[0] == 0xff and r[1] == 0x86: print("co2:{}".format(r[2]*256 + r[3]))
Go
Goの実装はインターネット上では見つけられなかったので、勉強がてら前出のPython実装を移植してみました。
io.ReadWriteCloserの実装を書いて*1、既存のMH-Z19実装と組み合わせるとシュッと動いた。
conf := &sc16is7x0.Config{Address: 0x48, XtalFreq: 14745600, Baud: 9600} dev, _ := sc16is7x0.Open(conf) concentration, _ := z19.TakeReading(dev) fmt.Printf("co2=%d ppm\n", concentration)
*1:Goのinterfaceまわり、独特なんで書いて理解するのが一番だなという感想。