Japanese Stable CLIP を試してみた

node.js でセンサー(i2c)の値を取得する

その1

その2


python を使ってセンサーの値を取得することができたので、次は node.js を使ってセンサーの値を取得します。物理的な接続はできていて、python での値の取得もできている、という前提です。


i2c デバイスファイルの権限変更

まず、root 権限でなくても i2c デバイスの読み書きができるようにします。スクリプトを sudo したりしなくてはならなくて不便なので、ユーザーに権限を付与します。

まず、デバイスファイルの権限を確認します。

  1. $ ls -l /dev/i2c-*
  2. crw-rw---- 1 root i2c 89, 0 9 15 23:17 /dev/i2c-0
  3. crw-rw---- 1 root i2c 89, 1 9 15 23:17 /dev/i2c-1
所有権はユーザーが "root"、グループは "i2c" になっています。なので、ユーザーを i2c グループに追加すればよさそうです。
  1. $ sudo gpasswd -a **** i2c
****は実際のユーザー名に置き換えてください。これで再ログインすれば、前回のスクリプトも sudo を付けずに実行することが可能になります。

node.js インストール

armbian の場合、apt でも node.js をインストールできますが、npm のバージョンが古いのか、 python2.7 に依存しています。そのためだけに大量の関連パッケージをインストールするのももったいないので、nodebrew を使ってインストールすることにします。

まず nodebrew のダウンロード。

  1. $ curl -L git.io/nodebrew | perl - setup
  2. % Total % Received % Xferd Average Speed Time Time Time Current
  3. Dload Upload Total Spent Left Speed
  4. 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
  5. 0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0
  6. 0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0
  7. 100 24634 100 24634 0 0 13886 0 0:00:01 0:00:01 --:--:-- 13886
  8. Fetching nodebrew...
  9. Installed nodebrew in $HOME/.nodebrew
  10.  
  11. ========================================
  12. Export a path to nodebrew:
  13.  
  14. export PATH=$HOME/.nodebrew/current/bin:$PATH
  15. ========================================
コマンドの出力にあるとおり、.bashrc などに export で始まる行を追加して、nodebrew をダウンロードしたディレクトリをパスに追加します。
nodebrew を使って、最新版の node.js をインストールします。
  1. $ nodebrew install-binary stable
  2. Fetching: https://nodejs.org/dist/v14.11.0/node-v14.11.0-linux-armv7l.tar.gz
  3. ################################################################################################################# 100.0%
  4. Installed successfully
nodebrew はインストール済みの node.js のバージョンを切り替えて使用することができます。そのため、インストールしたうえで、どのバージョンを使用するか指定する必要があります。インストールしただけだと、以下のように「v14.11.0」がインストールされていますが、「current: none」とあるように、使用するバージョンが指定されていない状態になります。
  1. $ nodebrew list
  2. v14.11.0
  3.  
  4. current: none
なので、使用するバージョンを指定します。
  1. $ nodebrew use v14.11.0
  2. use v14.11.0
無事、current に使用するバージョンが表示されました。
  1. $ nodebrew list
  2. v14.11.0
  3.  
  4. current: v14.11.0
ついでに、TypeScript を使うことにします。
  1. $ mkdir builders_flash
  2. $ cd builders_flash
  3. $ npm init -y
  4. $ npm i -D typescript @types/node
  5. $ npx tsc --init
センサーの読み書きに使う i2c-bus ライブラリもインストールします。
  1. $ npm i i2c-bus -s


コーディング

TypeScript は初めて使うので、いろいろと試行錯誤しましたが、結果的にはこんな感じのスクリプトになりました。途中の複雑な計算は、BME280 のデータシートに記載されている計算式ほぼそのまま (のつもり) です。

src/bme280.ts

  1. const DEVICE_NUMBER = 0;
  2. //const TARGET_IC_ADDR = 0x23;
  3. const TARGET_IC_ADDR = 0x76;
  4.  
  5. function getShort(data: any, index: number): number
  6. {
  7. return (data[index + 1] << 8) + data[index]
  8. }
  9.  
  10. function getUShort(data: any, index: number): number
  11. {
  12. return (data[index + 1] << 8) + data[index]
  13. }
  14.  
  15. function getChar(data: any, index: number): number
  16. {
  17. let result: number = data[index];
  18. if(result > 127)
  19. {
  20. result = result - 256;
  21. }
  22. return result
  23. }
  24.  
  25. function getUChar(data: any, index: number): number
  26. {
  27. let result: number = data[index] & 0xFE;
  28. return result;
  29. }
  30.  
  31. function sleep(msec: number)
  32. {
  33. return new Promise(function(resolve) {
  34. setTimeout(function() {resolve()}, msec);
  35. })
  36. }
  37.  
  38. function readBME280(): void
  39. {
  40. const REG_DATA = 0xF7;
  41. const REG_CONTROL = 0xF4;
  42. const REG_CONFIG = 0xF5;
  43.  
  44. const REG_CONTROL_HUM = 0xF2;
  45. const REG_HUM_MSB = 0xFD;
  46. const REG_HUM_LSB = 0xFE;
  47.  
  48. const OVERSAMPLE_TEMP = 2;
  49. const OVERSAMPLE_PRES = 2;
  50. const MODE = 1;
  51.  
  52. const OVERSAMPLE_HUM = 2;
  53.  
  54. var i2c = require('i2c-bus');
  55. var i2c1 = i2c.openSync(DEVICE_NUMBER);
  56.  
  57. // write param
  58. i2c1.writeByteSync(TARGET_IC_ADDR, REG_CONTROL_HUM, OVERSAMPLE_HUM);
  59. const control = OVERSAMPLE_TEMP << 5 | OVERSAMPLE_PRES << 2 | MODE;
  60. i2c1.writeByteSync(TARGET_IC_ADDR, REG_CONTROL, control);
  61.  
  62. var cal1 = Buffer.alloc(24);
  63. var cal2 = Buffer.alloc(1);
  64. var cal3 = Buffer.alloc(7);
  65.  
  66. i2c1.readI2cBlockSync(TARGET_IC_ADDR, 0x88, cal1.length, cal1);
  67. i2c1.readI2cBlockSync(TARGET_IC_ADDR, 0xA1, cal2.length, cal2);
  68. i2c1.readI2cBlockSync(TARGET_IC_ADDR, 0xE1, cal3.length, cal3);
  69.  
  70. const dig_T1 = getUShort(cal1, 0);
  71. const dig_T2 = getShort(cal1, 2);
  72. const dig_T3 = getShort(cal1, 4);
  73.  
  74. const dig_P1 = getUShort(cal1, 6);
  75. const dig_P2 = getShort(cal1, 8);
  76. const dig_P3 = getShort(cal1, 10);
  77. const dig_P4 = getShort(cal1, 12);
  78. const dig_P5 = getShort(cal1, 14);
  79. const dig_P6 = getShort(cal1, 16);
  80. const dig_P7 = getShort(cal1, 18);
  81. const dig_P8 = getShort(cal1, 20);
  82. const dig_P9 = getShort(cal1, 22);
  83.  
  84. const dig_H1 = getUChar(cal2, 0);
  85. const dig_H2 = getShort(cal3, 0);
  86. const dig_H3 = getUChar(cal3, 2);
  87.  
  88. let dig_H4 = getUChar(cal3, 3);
  89. dig_H4 = (dig_H4 << 24) >> 20;
  90. dig_H4 = dig_H4 | (getChar(cal3, 4) & 0x0F)
  91.  
  92. let dig_H5 = getChar(cal3, 5);
  93. dig_H5 = (dig_H5 << 24) >> 20;
  94. dig_H5 = dig_H5 | (getUChar(cal3, 4) >> 4 & 0x0F)
  95.  
  96. const dig_H6 = getChar(cal3, 6)
  97.  
  98. // Wait
  99. const wait_time = 1.25 + (2.3 * OVERSAMPLE_TEMP) + ((2.3 * OVERSAMPLE_PRES) + 0.575) + ((2.3 * OVERSAMPLE_HUM) + 0.575);
  100. sleep(wait_time / 1000);
  101.  
  102. // Read temperature/pressure/humidity
  103. var data = Buffer.alloc(8);
  104. i2c1.readI2cBlockSync(TARGET_IC_ADDR, 0xF7, data.length, data);
  105. const pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
  106. const temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
  107. const hum_raw = (data[6] << 8) | data[7]
  108.  
  109. // Refine tempreture
  110. let var1 = (((temp_raw >> 3) - (dig_T1 << 1)) * (dig_T2)) >> 11;
  111. let var2 = (((((temp_raw>>4) - (dig_T1)) * ((temp_raw>>4) - (dig_T1))) >> 12) * (dig_T3)) >> 14;
  112. let t_fine = var1+var2;
  113. let temperature = ((t_fine * 5) + 128) >> 8;
  114.  
  115. // Refine pressure and adjust for temperature
  116. let pressure = 0;
  117. var1 = t_fine / 2.0 - 64000.0;
  118. var2 = var1 * var1 * dig_P6 / 32768.0;
  119. var2 = var2 + var1 * dig_P5 * 2.0;
  120. var2 = var2 / 4.0 + dig_P4 * 65536.0;
  121. var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0;
  122. var1 = (1.0 + var1 / 32768.0) * dig_P1;
  123. if(var1 == 0)
  124. {
  125. pressure = 0;
  126. } else {
  127. pressure = 1048576.0 - pres_raw;
  128. pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1;
  129. var1 = dig_P9 * pressure * pressure / 2147483648.0;
  130. var2 = pressure * dig_P8 / 32768.0;
  131. pressure = pressure + (var1 + var2 + dig_P7) / 16.0;
  132. }
  133.  
  134. // Refine humidity
  135. let humidity = t_fine - 76800.0;
  136. humidity = (hum_raw - (dig_H4 * 64.0 + dig_H5 / 16384.0 * humidity)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * humidity * (1.0 + dig_H3 / 67108864.0 * humidity)));
  137. humidity = humidity * (1.0 - dig_H1 * humidity / 524288.0);
  138. if(humidity > 100)
  139. {
  140. humidity = 100;
  141. } else if(humidity < 0)
  142. {
  143. humidity = 0;
  144. }
  145.  
  146. console.log(temperature / 100.0, pressure / 100.0, humidity);
  147. }
  148.  
  149. readBME280();
今頃気が付きましたが、getShort と getUShort 関数が同じになってますね・・・あと、BH1750FVI の値を取得するのを忘れてました。とはいえ、この状態で実行すると、
  1. $ npx ts-node src/bb.ts
  2. 25.8 1088.2437277298607 49.58872975883544
と、値が取得できました。

コメント