さくらのVPSのウェブサーバでIPv6の接続をうける | tech - 氾濫原 で、IPv6 アクセス環境がないと書いたが、スマフォで簡単に IPv6 接続できることを知った。

APN 設定

IIJ mio の場合、APN の設定で IPv4/IPv6を選ぶだけで優先的に v6 接続されるようになる。

全ホストの IPv6 対応

自力で確認できる環境が身近にあることがわかったので、このサーバでホストしているホストを IPv6 対応してみた (もとも IPv6 インターフェイスも listen してるので単に AAAA レコードをひけるようにしただけ)

ちゃんと接続されてるのか?

見た目が何も変わらないのが正しい状態なのだけど、IPv6 接続されてるのかよくわからないので、仕掛けをしてみた。

判定は単に REMOTE_ADDR を見て、IPv6 アドレスだったら IPv6 接続と判定する。: を含んでいたら IPv6 と判定するようにする。

このサイトの場合、ページ全体をキャッシュしているため、内容をIPv4/IPv6で出しわけると持つべきキャッシュが倍になってしまい現実的ではない。ということで、以下のようにした。

  • CSS で適当なところに content: attr(data-ip-info); と書いておく
  • JS で接続情報を取得するエンドポイントを叩き data-ip-info を埋める

ref

  1. トップ
  2. tech
  3. IPv6 対応にした

郑州炜盛电子科技 という会社の MH-Z19 という CO2 センサを買ってみました。Aliexpress で $22 ぐらいでした。

  • 非分散形赤外線吸収式
  • 電源は 3.6〜5V
  • インターフェイスは UART または PWM 3.3V
  • プリヒートは3分
  • 温度補正あり。精度は±50ppm + 5%

5V の電源と 3.3V のインターフェイスが必要ですね。

とりあえず動かしてグラフ化

Ruby 用のライブラリを書いて読みだして、GrowthForecast に投げてみました。Raspberry Pi 上で動かしています。シリアルは USB 経由で、PWM では GPIO 経由で読んでいます。

結構おもしろくて、人がいるかいないかはグラフから一目でわかるレベルです。換気するとそくざに値に反映されるのもおもしろいです。

Ruby 用のライブラリ

Ruby で読み出し用のライブラリを書いてみました。

Serial 経由の読みこみとPWM (Linux のみ。sys/class/gpio 経由) どちらとも実装してあります。

PWM

Serial は仕様書通りに書いただけですが、PWM はちょっと工夫がいるのと、データシートそのままだとちゃんと値がでず試行錯誤したのでメモしておきます。

/sys/class/gpio でのエッジトリガ

PWM はエッジトリガをしかけて時間をそこそこ正確に計測する必要があります。Linux の GPIO でやる方法がわからなかったので、ちょっと調べて以下のようにしました。

  • "/sys/class/gpio/gpio#{pin}/direction" を in に
  • "/sys/class/gpio/gpio#{pin}/edge" を both に
  • "/sys/class/gpio/gpio#{pin}/value" を開いて fd を取得
  • select でエッジを待つ
  • read で内容を読む
  • seek で戻す
  • select に戻る

select でブロックしてエッジが検出されると制御が戻ります。read したあと seek で戻さないと、次の select でブロックせずビジーループになってしまうようでした。

def self.trigger(pin, edge, timeout=nil, &block)
	self.direction(pin, :in)
	self.edge(pin, edge) #=> write "/sys/class/gpio/gpio#{pin}/edge"
	File.open("/sys/class/gpio/gpio#{pin}/value", "r") do |f|
		fds = [f]
		buf = " "
		while true
			rs, ws, es = IO.select(nil, nil, fds, timeout)
			if es
				f.sysread(1, buf)
				block.call(buf.to_i)
				f.sysseek(0)
			else
				break
			end
		end
	end
end

処理速度が不安でしたが、1ms 単位でとれれば十分なので Ruby + /sys/class/gpio でも十分でした。

PWM の場合の計算方法

データシートだと以下の計算式になっています。ここで th は PWM の high の時間、tl は low の時間、ppm は CO2 濃度です。

ppm = 2000 * (th - 2e-3) / ((th + tl) - 4e-3)

が、どうみてもデータシート通りの値がでてきませんでした。どうやら型番が一緒で、検出レンジが 0〜2000ppm のものと、0〜5000ppm のものがあるようで、2000 の部分を 5000 にするとうまく計算できました。

キャリブレーション

シリアル経由だと、ゼロ補正とスパン補正というのがあります。仕様書にどうやってキャリブレーションするか書いてないのですが、おそらく以下の手順です

  • CO2 がない環境 (窒素100%とか) でゼロキャリブレーション
  • 既知のCO2濃度の環境でスパンキャリブレーション (スパンキャリブレーション時に既知の濃度を渡します)

↑ の手順おそらく間違いなので以下の正しいと思われる手順を書きます。MH-Z19B のデータシートの手順です。

  • CO2 濃度が 400ppm の環境でゼロキャリブレーション
  • CO2 濃度は 2000ppm の環境でスパンキャリブレーション (1000ppm 以上の既知の濃度を使うこと)

まぁキャリブレーションは難しいのですが、一定期間内の最低値を外気のCO2濃度 (約400ppm) とみなしてときどき自動で補正していく方法もあるようです。

気象庁の二酸化炭素濃度のグラフを見る限り、近年は 400ppm 程度のようです。季節変動もみられますが、センサーの精度よりも小さいので無視できます。

二酸化炭素濃度の基準

ビル衛生管理上では 1000ppm を目安に換気せよと書いてあります。これは二酸化炭素の影響だけではなくて、これを目安として他の有害物質の滞留を防ぐという意味合いもあるみたいです。

また CO2 単体でも 2000ppm以上になると自覚できる症状が現れることがあるようです。

ref.

  1. トップ
  2. tech
  3. MH-Z19 という格安 CO2 センサを読んでみた