BMP180を使ってみた

昨日今日と台風15号で日本は大荒れでした。

コロッケは買いに行かず、少し前にAmazonの中国発送商品で手に入れていたI2Cの気圧センサーのBosch社製BMP180の使ってみることにしました。

![61unNWeVL6L._SL1001_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/70185f9f-a060-2b1a-5510-56abe644e6c8.jpeg)

プラットフォームはFreeBSDはいまいろいろ立て込んでいるので、mruby on YABMの蟹さん(RTL8196C)にしました。

ネットを探すとライブラリや素のコードなどが見つかります。

これらはデータシートのサンプルシーケンスを元に作られています。

データーシートとネットのCコードなどを参考に作ってみました。符号ありのshortと無しのshortが混在していてちょっとはまりました。

https://github.com/yamori813/rtlbm-mruby/blob/master/samples/bmp180.rb

このコード実は問題があります。b4,b7が符号無しの32Bitなのですが、mrubyでは扱えません。b7が31ビットをオーバーしてしまうかはキャリフレーションデータに依存していて、モジュールによってはうまく動かない可能性があります。

![スクリーンショット 2019-09-08 22.30.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/2f687dd2-2249-f29c-00ce-f1fa9348c95e.png)

当初I2Cを実装した時に使った猛牛さんの有線ルーターを使っていたのですが、HomeSpotCubeに変更しました。このモジュールは後ろにスライドスイッチがあり、3種類の選択ができ、GPIOが2本出ています。下の写真の左がGPIOA2(2)で右がGPIOB3(11)です。

![写真（2019-09-11 13.31）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/31089891-53a3-fbb6-4892-7fffd8b009b1.jpeg)

スイッチを外してSDA,SCLにつないでみたのですが、うまく動きません。よくよく見ると以下のようになっています。

![GPIO_SWITCH.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/e3f57593-a9fd-ee6e-e0d0-229ab95bc24b.png)

BitbangでのI2CでGPIOを使う場合コンデンサーを外す必要があります。プルアップの抵抗はあっても動くことが多いです。ただI2Cのプルアップ抵抗は1K-10Kくらいで調整が必要な場合があるので、外した方がいいかもしれません。

私が作ったVM側のNETの処理とGPIOの処理がコンフリクトしていて、GPIO->NETで処理を叩くと動かないようです。いつか直します。

気圧計や温度計を室内に置いて観測する場合は置く場所も考える必要があります。気圧計は換気扇やドアの開け閉めなどの影響がありえますし、温度計は冷暖房の影響があります。人間の居住空間の温度を知る場合はこれを含めて測定することになりますが、気圧のために測定する場合は影響を排除すべきと考えられます。

蟹さんのネットワークは有線のEthernetですが、設置場所を自由にできるBluetoothやWifiは便利ですが、仕組みが複雑になります。またバッテリー駆動にすれば完全にどこにでも置けますが、電池切れを考慮する必要がありこれも悩ましいです。

本来気象観測は室外で行うべきなのでしょうが、外に置くには接続や電源や防水（完全な密閉じゃなく）などの問題を解決する必要があります。

BMP180のモジュールには3.3Vのレギュレーターが付いていましたが、供給電源が3.3Vなので外しました。

BMP180から得られるデータは現在地の気温と気圧だけです。気象庁などが発表している気圧は海面気圧になります。海面気圧を知るためには現在地の標高が必要で、現在地の標高を得るためには海面気圧が必要です。海面気圧を計算する式はデーターシートにもありますが、float無しに計算するのは難しいです。

[以前試したMPL115A2](https://qiita.com/yamori813/items/a4d1ba76033016c4ed7d)より数値はいい感じなのですが、昨日動かしていたら6時間くらいで止まってしまっていたので、ちょっといじってみてしばらく様子を見てみたいと思います。

いろいろ試したところ、i2cを読む前に毎回GPIOとi2cの初期化を行うと安定しました。しかしたまにデータが読めない時があるので、読んだ値が0の時は、アップしないようにしました。

どうも蟹さんのGPIOはマルチプレックスになってる機能との兼ね合いで、信号線のドライブ能力に差があるように思われます。つなぐところによって挙動が変わります。

気温や気圧以外に湿度や照度や風速・風向や騒音や地震や落雷や雨量や二酸化炭素濃度などを調べられるウエザーステーション自作したい。以前湿度計モジュールを買ったら、1年くらいで壊れてしまって、作るんだったら長く使えるものにしたい。

![スクリーンショット 2019-09-12 10.25.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/3a29a0e9-2569-3a92-88ee-ad51a28806ef.png)

その後結構安定している。昔はバリゴのアナログ気圧計が欲しかったけど、これの方が良い気がする。気圧は時間経過を確認できるのが大切だ。

例えばバリゴの気圧計が2万円として、電気代を換算すると1kWhが20円として、100kWhになる。もちろん気圧計は1kWhなんて使わなくてそれの1000分の1として1000x100時間でぼぼ10年。もう少ししっかり調べたほうがいいかもしれないが、そんな数字もあるかもしれない。

MATLABで過去一週間の最高気温をグラフにしてみました。

```MATLAB
% Last week max temputure

readChannelID = ;
readAPIKey = "";

day = datetime('now') - 7;

for c = 1:7
    
    startdaystr = datestr(day,'mmm dd, yyyy 00:00:00');
    enddaystr = datestr(day + 1,'mmm dd, yyyy 00:00:00');
    [a,b] = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields',1,'DateRange', [datetime(startdaystr),datetime(enddaystr)]);

    [m, n] = max(a);
    [x, y] = min(a);

    t(c) = day;
    v(c) = m;
    day = day + 1
end

bar(t, v, 'r');
```

![スクリーンショット 2019-09-23 15.56.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/dd242dbf-e947-272b-4db3-e659b64f9a70.png)

タイムゾーンの対応がなんかおかしい気がします。

直近のアクセス間隔をグラフにしてみました。

```MATLAB
readChannelID = ;
readAPIKey = '';

t1 = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'NumPoints',4320, 'OutputFormat','table');

[m,n] = size(t1);
for c = 1:m - 1
    d = seconds(t1.Timestamps(c+1) - t1.Timestamps(c));
    s(c) = d(1); 
end

%A = accumarray(s,1);
ma = max(s);
for c = 1:ma
    t(c) = c;
    v(c) = 0;
end

for c = 1:m - 1
    v(s(c)) = v(s(c)) + 1;
end

plot(t, v, 'LineStyle','--','LineWidth',2,'Color','green','Marker','s')
```

最高気温の方は配列でデータを読み込んでいますが、こちらはテーブルで読み込んでいます。

なぜか10秒台ピークが二つあります。もしI2Cでデータが取れない場合は20秒以降になるはずで謎です。

![スクリーンショット 2019-09-23 15.58.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/528badbb-b84d-fafa-fd0c-83a663ea2029.png)

最高気温と最低気温をグラフにしてみました。最低気温と最高気温を積み上げて、最低気温を白にして消しています。最低気温がマイナスだと正しく表示できません。^ ^;

```MATLAB
% Last week max and min temputure

readChannelID = ;
readAPIKey = "";

day = datetime('now') - 7;

for c = 1:7
    
    startdaystr = datestr(day,'mmm dd, yyyy 00:00:00');
    enddaystr = datestr(day + 1,'mmm dd, yyyy 00:00:00');
    [a,b] = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields',1,'DateRange', [datetime(startdaystr),datetime(enddaystr)]);

    [m, n] = max(a);
    [x, y] = min(a);

    t(c) = day;
    vmax(c) = m - x
    vmin(c) = x
    day = day + 1
end

C = vertcat(vmin, vmax);

H = bar(t, C, 'stacked');

set(H(1),{'FaceColor'},{[1 1 1]});
set(H(1),{'EdgeColor'},{[1 1 1]});
set(H(1),{'LineWidth'},{1});
```

![スクリーンショット 2019-09-23 21.10.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/4872de99-6b6f-33be-eac4-2a44c00c0c33.png)

最高気温と最低気温の時間のグラフを作ってみました。

```MATLAB
readChannelID = ;
readAPIKey = "";

day = datetime('now') - 14;

for c = 1:14
    
    startdaystr = datestr(day,'mmm dd, yyyy 00:00:00');
    enddaystr = datestr(day + 1,'mmm dd, yyyy 00:00:00');
    [a,b] = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields',1,'DateRange', [datetime(startdaystr),datetime(enddaystr)]);

    [m, n] = max(a);
    [x, y] = min(a);

    t(c) = day;
    tmax(c) = hour(b(n)) + minute(b(n)) / 60;
    tmin(c) = hour(b(y)) + minute(b(y)) / 60;
    day = day + 1
end

plot(t, tmax,'LineStyle','none','Marker','o');
hold on
plot(t, tmin,'LineStyle','none','Marker','x');
hold off
```

![スクリーンショット 2019-10-02 10.34.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/e9b2beed-008b-5631-fdc9-a7dfc340d4d4.png)

海面更正気圧もグラフにしてみました。zが測定地の標高(m)です。

```MATLAB
readChannelID = ;
readAPIKey = "";

z = 45;

day = datetime('now');

nowhourstr = datestr(day,'mmm dd, yyyy hh:00:00');

lasthour = 48;

for c = 1:lasthour
    
    [a,b] = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields',[1 2],'DateRange', [datetime(nowhourstr)+hours(c-lasthour),datetime(nowhourstr)+hours(c-lasthour+1)]);
    x = filloutliers(a(:,1),'linear');
    y = filloutliers(a(:,2),'linear');
    tav = mean(x);
    pav = mean(y);
    t(c) = datetime(nowhourstr)+hours(c-lasthour);
    vsea(c) = pav * (1 - 0.0065 * z /(tav + 0.0065 * z + 273.15))^-5.257;
end

H = line(t, vsea);
```

filloutliers()で異常値を省いています。

![スクリーンショット 2019-10-11 9.26.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/6c7818fb-6b84-96ad-053b-a831bc7e333b.png)