Si7021を使ってみた。

インフルエンザの流行も始まっているようなので、おうちの湿度を計ってみることにしました。蟹さんのBMP180につないであったモジュールに湿度センサーのSi7021もつないでみました。

購入したモジュールはレギュレーターとN-MOSFETを使ったレベル変換が実装されていますが3.3Vで使うので外します。

![写真（2019-12-21 8.25）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/9d6b239d-8f82-e59f-fff2-4ccd46f9b4f0.jpeg)

となってたところを、部品がセンサーなのでヒートガンは使わず、表面実装部品取り外し用の低温ハンダを使って剥がして

![写真（2019-12-21 9.46）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/5bdc06a5-b25a-ce8d-1600-53212c2529a0.jpeg)

こんな風に直結してみました。結構てこづりました。多分外さなくても動くと思いますが、不安定になると嫌なので、外しました。

![写真（2019-12-22 11.07）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/fe0755a9-f1dd-84cb-8275-224cea36faa0.jpeg)

mrubyコードはこんな感じにしてみました。

```ruby
SIADDR = 0x40

class SI7021
  def init yabm
    @y = yabm
  end

  def getRevition
    @y.i2cwrites(SIADDR, [0x84, 0xb8], 0)
    delay(@y, 1)
    siarr = @y.i2creads(SIADDR, 1)
    return siarr[0]
  end

  def getCelsiusHundredths
    @y.i2cwrites(SIADDR, [0xf3], 1)
    while 1 do
      siarr = @y.i2creads(SIADDR, 2)
      if siarr != nil then
        break
      end
    end
    tempcode = (siarr[0] << 8) | siarr[1]
    t = (tempcode * 17572) / 65536 - 4685
    return t

  end

  def getHumidityPercent
    @y.i2cwrites(SIADDR, [0xf5], 1)
    while 1 do
      siarr = @y.i2creads(SIADDR, 2)
      if siarr != nil then
        break
      end
    end
    rhcode = (siarr[0] << 8) | siarr[1]
    rh = (125 * rhcode) / 65536 - 6
    return rh
  end
end
```

蟹さんはfloatが使えないので100倍の整数演算で処理しています。

![math-20200111-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/f84adf4b-7a54-14e6-88d7-2ead640215ed.png)
![math-20200111-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/5e038ce8-a641-294b-642e-aa0063efd6de.png)
![math-20200111-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/f92c64a8-89a1-aa62-2af5-f358dc070d47.png)


Si7021からの湿度と温度の拾い方は2種類あり、ストレッチクロックを使った方法とReadのACKを確認する方法です。

ストレッチクロックの実装も入れてみたのですが、うまく値が拾えなかったので、ACKの方で実装してみました。

リピーテッドスタートのサポートのためmruby-yabmのi2cwritesに引数を追加したのとi2creadsを追加しました。

いつものようにThingSpeakに投げてInternet of Testしてみます。

![スクリーンショット 2019-12-22 11.43.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/cd24ae8f-5693-d4f3-96df-2a13de0c9e64.png)

Field 3がSi7021の気温でField 4が湿度です。

BMP180の温度と近いし、湿度も気象庁の観測データと近いので、おそらく大きな間違いはないと思います。

ちょっと不安定なようですが、様子を見て対策を考えたいと思います。

SILICON LABSのチップの仕様はなんだか不思議な感じがします。

Revision拾うところもdelayを入れないと拾えなかったり、湿度を3バイトで拾ってchecksumを計算するとあってるのですが、なぜか温度の数字が異常値になります。

あまりエラーが多いので、前回の値と差が大きい場合はエラーとして前回の値を使うようにしました。エラーを別のフィールドでビットフィールドでアップして、エラーレートの確認ができるようにもしました。いろいろいじっていたら、上のグラフとは逆に、湿度より温度の方がエラーが多くなりました。:(

```ruby
    sh = si.getHumidityPercent
    if count == 0 || (lastsh - sh).abs < 10 then
      shstr = sh.to_s
      lastsh = sh
    else
      shstr = lastsh.to_s
      error = error | (1 << 2)
    end
```

もともとSi7021には10Kのプルアップ抵抗がI2Cに入っていたのですが、これを外して、BMP180の方の4.7Kだけにしました。この構成でブレッドボードはエラーありながらも動いていたのですが、ユニバーサル基板に配線して移したらまったく動かなくなりました。BMP180の4.7Kも外して、7.5Kでプルアップしたところ、安定しました。I2Cデバイスを複数つなぐときにはプルアップ抵抗に注意が必要です。

![写真（2019-12-26 14.45） #2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/93c99b20-bb72-cbe8-17b4-84e7ea843413.jpeg)


いろいろ試行錯誤してi2cchkという関数を追加して、ACKが返ってくるまでビジーループするようにしたところエラーはほぼなくなり安定しました。

![スクリーンショット 2020-01-09 17.40.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/90794dde-a403-f588-c536-706b07c48bf3.png)

BMP180と温度が0.4度くらい違いますが、傾向はほぼ一致しています。

以前秋月でHDC1000を使ったモジュールを購入して試していたら、値が非常に高いままになって、じきにまったく値が拾えなくなってしまいました。このモジュールはネットに経年劣化で異常値になるという報告がありました。

湿度は気温や気圧に比べると炊事などの生活環境からの影響を受けやすいようです。


2020/01/16に再起動しました。

![スクリーンショット 2020-01-18 8.52.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/4f118025-0a5f-4dd5-447e-f79410389d3d.png)

ThingSpeakのログ

```
2020-01-16 20:04:22 JST,43763,20646,7.8,1015.83,8.21,76,0,,,,
2020-01-16 20:04:44 JST,43764,20647,7.8,1015.85,8.20,76,0,,,,
2020-01-16 20:05:14 JST,43765,20648,7.8,1015.85,8.20,76,15,,,,
2020-01-16 20:05:38 JST,43766,20649,7.8,1015.85,8.20,76,7,,,,
2020-01-16 20:06:09 JST,43767,20650,7.8,1015.85,8.20,76,7,,,,
2020-01-16 20:52:04 JST,43768,0,7.7,-1215.57,2.56,78,0,,,,
2020-01-16 20:52:41 JST,43769,1,7.7,-1215.51,2.56,77,4,,,,
2020-01-16 20:53:05 JST,43770,2,7.7,-1215.51,2.56,77,7,,,,
...
2020-01-16 21:00:20 JST,43789,21,7.7,-1215.36,2.56,77,4,,,,
2020-01-16 21:02:32 JST,43790,22,7.7,-1215.36,2.56,77,7,,,,
2020-01-16 21:27:12 JST,43791,0,7.7,1015.98,8.10,78,0,,,,
2020-01-16 21:27:35 JST,43792,1,7.7,1015.95,8.04,78,0,,,,
2020-01-16 21:27:58 JST,43793,2,7.7,1015.96,8.06,78,0,,,,
```

2回再起動しています。

ちょうどこの時間帯にfreebsdworkshopのストリーミングを見ていました。

![filename-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/1680a705-2d8e-ea3f-7254-5e0b731bc4d6.png)

どうもネットワーク負荷につられて落ちた可能性があるようです。接続先がSwitchなのでトラフィックがそのまま蟹さんに入った可能性はなくて、経路上の混雑につられて可能性があります。同時間帯にBCM/mipsのモジュールには問題が起きていません。

一回目の再起動の前にもセンサー値の異常があったようです。

あと今のロジックは前回値と差を元に判定しているので、再起動後の初回にエラー値があるとそれ以降おかしくなります。これは対策を考える必要があります。

BMP180の気圧とSi7021の気温が異常値で、BMP180の気温とSi7021の湿度は正常値に見えます。謎です。

初めの再起動が46分、二回目が25分くらい間があいています。Watchdogは5分くらいでかかるようにしてたはずなので、それではなさそうですし、ネットワークアクセス失敗は20秒間隔が10回で200秒で再起動なので、それでもなさそうなので、想定外の状態になっています。


ネットワーク負荷を上げると再現できそうということはわかりました。

2010/1/20 突然全く動作しなくなり、調べてみたらプルアップ抵抗を変えたところ、直りました。元は7.5Kとしていたのですが10Kにしました。ついでにプルアップ抵抗を変更できるようにしてみました。

![写真（2020-01-20 18.33） #2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/e5fd5f1b-3d56-19ab-d438-18606d9816a4.jpeg)

個体差があるかもしれませんが、Si7021はアクセスタイミングに微妙なさじ加減が必要な気がします。