hiro が 2021年05月16日13時55分30秒 に編集
コメント無し
本文の変更
# 概要 obniz Board 1Y と BME680 を利用した簡単百葉箱です。 作成したコードはobnizのアプリとして公開していますのでセンサを用意すれば簡単に試すことが可能です。
# 材料 - obniz Boad 1Y - BME680
# デモ動画 @[youtube](https://youtu.be/-T9w0ey72g4)
## 今回使用したもの - [ BME680使用 温湿度・気圧・ガスセンサモジュールキット](https://akizukidenshi.com/catalog/g/gK-14469/) - [電池ボックス 単3×3本 リード線・フタ・スイッチ付](https://akizukidenshi.com/catalog/g/gP-02666/)
作者自宅で動いているシステムのグラフです。 https://ambidata.io/bd/board.html?id=25964
# 部品 | 部品 | 今回使用したもの | |:---:|:---| | obniz Boad 1Y | obniz Boad 1Y | | 環境センサ BOSCH BME680 | [BME680使用 温湿度・気圧・ガスセンサモジュールキット](https://akizukidenshi.com/catalog/g/gK-14469/) | | 電源 | [電池ボックス 単3×3本 リード線・フタ・スイッチ付](https://akizukidenshi.com/catalog/g/gP-02666/) | 電源はUSBでも動作します。 モバイルバッテリーを利用する場合、スリープ中に出力が停止するものがあるかもしれません。
秋月のBME680を利用すると、5Vを電源に使えるので、obnizから供給することが可能になります。 また、電源のIOの電圧を計測することで、電池の電圧が計測できます。
# 配線 | obniz | BME680 | |:---:|:---| | IO0 | GND | | IO1 | SDA | | IO2 | SCL | | IO3 | VIN |
# おおまかなシステムの流れ 1. obnizの電源が入る 1. クラウド実行(デバイスがオンライン時に実行)が呼び出される 1. センサ情報の取得 1. Ambientへ送信 1. スリープ移行 # インストール手順 1. Ambientでチャネルを作成して、チャネルIDとライトキーがわかるようにする 1. [アプリ](https://obniz.com/ja/webapp/4472)をインストールする 1. ambient_channel_id と ambient_write_key を設定する # 作成手順 1. BME680を組み立てる 1. 写真のようにIO0 - IO3 に接続
![センサ接続](https://camo.elchika.com/b5ae63a35e575c36c769c0c5f7e91118f18c0dbe/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f61333366626264392d356332332d343539372d396230352d3661356437613663646534352f65393139656537662d613335332d343466382d623936622d303136346461303938613433/)
1. 電源を入れて上記のインストールしたアプリが動作し、Ambientに情報が届いたら成功。インストールしたデバイスにログが記録されます。 ![実行ログ](https://camo.elchika.com/a2d28e9eeb34d739aea163f6bd2cb0ceee2d0e48/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f61333366626264392d356332332d343539372d396230352d3661356437613663646534352f37653336313535612d323133312d343965322d383231372d396333346434633066353037/)
# デモ 作者自宅で動いているシステムのグラフです。 https://ambidata.io/bd/board.html?id=25964
# ソースコード コンテストの応募要件なのでソースコードをそのまま貼ります。 obnizのサイトでもアプリとして[公開](https://obniz.com/ja/webapp/4472)しています。 下記ソースコードはそちらとは異なる可能性があります。
電池駆動させるために 1Y の deep sleep を利用しています。
```html:BME680_Ambient <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" /> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="https://unpkg.com/obniz@3.x/obniz.js" crossorigin="anonymous"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.10.1/qs.min.js" integrity="sha512-aTKlYRb1QfU1jlF3k+aS4AqTpnTXci4R79mkdie/bp6Xm51O5O3ESAYhvg6zoicj/PD6VYY0XrYwsWLcvGiKZQ==" crossorigin="anonymous"></script> <script src="https://unpkg.com/ambient-lib@1.0.3/lib/ambient-lib.js"></script> </head> <body> <div id="obniz-debug"></div> <script> var obniz = new Obniz("OBNIZ_ID_HERE"); var bme_addr = 0x77; var par_t1, par_t2, par_t3; var par_p1, par_p2, par_p3, par_p4, par_p5, par_p6, par_p7, par_p8, par_p9, par_p10; var par_h1, par_h2, par_h3, par_h4, par_h5, par_h6, par_h7; var par_g1, par_g2, par_g3, res_heat_range, res_heat_val, range_switching_error; function write(data) { obniz.i2c0.write(bme_addr, data); } async function read(reg_addr, num = 1) { write([reg_addr]); try { var ret = await obniz.i2c0.readWait(bme_addr, num); // console.log(`read(0x${reg_addr.toString(16)}[${num}]): ${ret}`); if (num == 1) return ret[0]; return ret; } catch (e) { console.error(e); } } async function loadCalibration() { all = await read(0x00, 0x100); par_t1 = (all[0xea] << 8) | all[0xe9]; par_t2 = _readSigned16((all[0x8b] << 8) | all[0x8a]); par_t3 = _readSigned8(all[0x8c]); par_p1 = (all[0x8f] << 8) | all[0x8e]; par_p2 = _readSigned16((all[0x91] << 8) | all[0x90]); par_p3 = _readSigned8(all[0x92]); par_p4 = _readSigned16((all[0x95] << 8) | all[0x94]); par_p5 = _readSigned16((all[0x97] << 8) | all[0x96]); par_p6 = _readSigned8(all[0x99]); par_p7 = _readSigned8(all[0x98]); par_p8 = _readSigned16((all[0x9d] << 8) | all[0x9c]); par_p9 = _readSigned16((all[0x9f] << 8) | all[0x9e]); par_p10 = all[0xa0]; par_h1 = (all[0xe3] << 4) | (all[0xe2] >> 4); par_h2 = (all[0xe1] << 4) | (all[0xe2] & 0xf); par_h3 = _readSigned8(all[0xe4]); par_h4 = _readSigned8(all[0xe5]); par_h5 = _readSigned8(all[0xe6]); par_h6 = all[0xe7]; par_h7 = _readSigned8(all[0xe8]); par_g1 = _readSigned8(all[0xed]); par_g2 = _readSigned16((all[0xec] << 8) | all[0xeb]); par_g3 = _readSigned8(all[0xee]); res_heat_range = (all[0x02] & 0x30) >> 4; res_heat_val = _readSigned8(all[0x00]); range_switching_error = (all[0x04] & 0xf0) >> 4; } function _readSigned16(value) { if (value >= 0x8000) { value = value - 0x10000; } return value; } function _readSigned8(value) { if (value >= 0x80) { value = value - 0x100; } return value; } async function getAllSensorValues(enableGas) { data = await read(0x1f, 8); d_gas = await read(0x2a, 2); var press_adc = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4); var temp_adc = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4); var hum_adc = (data[6] << 8) | data[7]; var gas_adc = (d_gas[0] << 2) | (d_gas[1] & 0xc0); var gas_range = d_gas[1] & 0x0f; var temp = calcTemperature(temp_adc); var temperature = temp[0]; var t_fine = temp[1]; var pressure = calcPressure(press_adc, t_fine); var humidity = calcHumidity(hum_adc, temperature); var gas = 0; if (enableGas) gas = calcGas(gas_adc, gas_range); return { temperature, humidity, pressure, gas }; } function calcTemperature(temp_adc) { var temp_comp, t_fine, var1, var2; var1 = (temp_adc / 16384.0 - par_t1 / 1024.0) * par_t2; var2 = (temp_adc / 131072.0 - par_t1 / 8192.0) * (temp_adc / 131072.0 - par_t1 / 8192.0) * (par_t3 * 16.0); t_fine = var1 + var2; temp_comp = t_fine / 5120.0; return [temp_comp, t_fine]; } function calcPressure(press_adc, t_fine) { var press_comp, var1, var2, var3; var1 = t_fine / 2.0 - 64000.0; var2 = var1 * var1 * (par_p6 / 131072.0); var2 = var2 + var1 * par_p5 * 2.0; var2 = var2 / 4.0 + par_p4 * 65536.0; var1 = ((par_p3 * var1 * var1) / 16384.0 + par_p2 * var1) / 524288.0; var1 = (1.0 + var1 / 32768.0) * par_p1; press_comp = 1048576.0 - press_adc; if (var1 != 0) { press_comp = ((press_comp - var2 / 4096.0) * 6250.0) / var1; var1 = (par_p9 * press_comp * press_comp) / 2147483648.0; var2 = press_comp * (par_p8 / 32768.0); var3 = (press_comp / 256.0) * (press_comp / 256.0) * (press_comp / 256.0) * (par_p10 / 131072.0); press_comp = press_comp + (var1 + var2 + var3 + par_p7 * 128.0) / 16.0; } else { press_comp = 0; } return press_comp / 100; // to hPa } function calcHumidity(hum_adc, temp_comp) { var hum_comp, var1, var2, var3, var4; var1 = hum_adc - (par_h1 * 16.0 + (par_h3 / 2.0) * temp_comp); var2 = var1 * ((par_h2 / 262144.0) * (1.0 + (par_h4 / 16384.0) * temp_comp + (par_h5 / 1048576.0) * temp_comp * temp_comp)); var3 = par_h6 / 16384.0; var4 = par_h7 / 2097152.0; hum_comp = var2 + (var3 + var4 * temp_comp) * var2 * var2; return hum_comp; } function calcGas(gas_adc, gas_range) { const const_array1 = [ 1, 1, 1, 11000000, 1, 0.99, 1125000, 0.992, 1, 115625, 0.998, 0.995, 11953.125, 0.99, 1, 1, ]; const const_array2 = [ 8000000, 4000000, 2000000, 499500.4995, 248262.1648, 63004.03226, 31281.28128, 7812.5, 3906.25, 976.5625, 488.28125, 244.140625, ]; var1 = (1340.0 + 5.0 * range_switching_error) * const_array1[gas_range]; gas_res = (var1 * const_array2[gas_range]) / (gas_adc - 512.0 + var1); return gas_res / 1000; // to kOhm } async function waitUntilMeasured(enableGas) { while (read(0x1d) & 0x20); if (enableGas) while (read(0x1d) & 0x40); } function calcWaitVal(dur) { var multi = 0; while (dur > 63) { dur /= 4; multi++; } if (multi > 3) return 0; return (multi << 6) | dur; } function calcResHeat(target_temp, amb_temp) { var1 = par_g1 / 16.0 + 49.0; var2 = (par_g2 / 32768.0) * 0.0005 + 0.00235; var3 = par_g3 / 1024.0; var4 = var1 * (1.0 + var2 * target_temp); var5 = var4 + var3 * amb_temp; res_heat = 3.4 * (var5 * (4.0 / (4.0 + res_heat_range)) * (1.0 / (1.0 + res_heat_val * 0.002)) - 25); return parseInt(res_heat); } async function setHeater(target_temp = 0, duration = 0) { obj = await getAllWait(false); amb_temp = obj.temperature; // 4. Set gas_wait_0<7:0> to 0x59 to select 100 ms heat up duration wait_val = calcWaitVal(duration); write([0x64, wait_val]); // 5. Set the corresponding heater set-point by writing the target heater resistance to res_heat_0<7:0> res_heat = calcResHeat(target_temp, amb_temp); write([0x5a, res_heat]); // 6. Set nb_conv<3:0> to 0x0 to select the previously defined heater settings // 7. Set run_gas_l to 1 to enable gas measurements write([0x71, 0x10]); } async function getAllWait(enableGas = true) { // force mode // 1. Set humidity oversampling to 1x by writing 0b001 to osrs_h<2:0> write([0x72, 0x01]); // 2. Set temperature oversampling to 2x by writing 0b010 to osrs_t<2:0> // 3. Set pressure oversampling to 16x by writing 0b101 to osrs_p<2:0> write([0x74, 0x54]); if (enableGas) { await setHeater(320, 150); } // 8. Set mode<1:0> to 0b01 to trigger a single measurement. write([0x74, 0x55]); await waitUntilMeasured(enableGas); val = await getAllSensorValues(enableGas); val.voltage = await obniz.ad3.getWait(); return val; } // called on online obniz.onconnect = async function () { // 電源設定 obniz.io3.drive("5v"); obniz.io3.output(true); // i2c var i2c = obniz.getFreeI2C(); await i2c.start({ mode: "master", gnd: 0, sda: 1, scl: 2, clock: 400000, pull: "5v", }); obniz.i2c0.onerror = function (err) { console.error(err); }; await obniz.wait(100); var chip_id = await read(0xd0); console.log(`chip_id: ${chip_id}`); await loadCalibration(); // センサが安定するまで何回か読み込む for (let step = 0; step < 5; step++) { await getAllWait(); } var val = await getAllWait(); obniz.i2c0.end(); console.log(val); console.log(`temperature: ${val.temperature} [degC]`); console.log(`pressure: ${val.pressure} [hPa]`); console.log(`humidity: ${val.humidity} [%]`); console.log(`gas: ${val.gas} [kOhm]`); console.log(`power voltage: ${val.voltage} [V]`); // Ambient const userconfig = Obniz.App.configs(); console.log(userconfig); const am = new Ambient( userconfig.ambient_channel_id, userconfig.ambient_write_key ); am.send( { d1: val.temperature, d2: val.pressure, d3: val.humidity, d4: val.gas, d5: val.voltage, }, function (response) { console.log(`Upload to Ambient: ${response.status}`); } ); obniz.display.print(`Temp: ${val.temperature.toPrecision(4)}`); obniz.display.print(`Press: ${val.pressure.toPrecision(6)}`); obniz.display.print(`Hum: ${val.humidity.toPrecision(4)}`); obniz.display.print(`Gas: ${val.gas.toPrecision(6)}`); obniz.display.print(`Volt: ${val.voltage.toPrecision(3)}`); await obniz.wait(2000); obniz.display.clear(); obniz.display.print("Good night."); await obniz.wait(1000); if (Obniz.App.isCloudRunning()) { Obniz.App.done({ status: "success", text: `TPHG: ${val.temperature.toPrecision( 4 )}, ${val.pressure.toPrecision(6)}, ${val.humidity.toPrecision( 4 )}, ${val.gas.toPrecision(4)}, Voltage: ${val.voltage.toPrecision(3)}`, }); } // sleep for 10 minutes // 6 timex x 24 hour = 144 times / day obniz.sleepMinute(10); }; </script> </body> </html> ```