SensorTagとEdisonで室温計を作ったった

記事タイトルとURLをコピーする

竹永です。最近実家でにゃんこ共をモフってきました。ふひ…ふひひ…。

なんとなくの思いつきで、社内にいっぱいあるSensorTagと、社内にいっぱいあったはずのIntel Edisonを使って、社内にこっそりと温度計をばらまきます。

レシピ

CC2650STK

センサーにはCC2650STK(SensorTag)を使います。CC2650というマイコンに温度や湿度や加速度やマイクなどなどのセンサーを10種類ほど搭載した、赤くてちっこいやつです。

Bluetooth Low Energy(BLE)・ZigBee・6LoWPANを使って外部と通信することが可能なので、IoTの検証にはもってこいです。

ボタン型電池1つで(中身のファームウェアと周辺ハードウェアにもよりますが)かなりの長期間動作し続けることができます。

CC-DEVPACK-DEBUGを使うと中身を書き換えることができます。
デフォルトのファームウェアでは弄くれないマイクとかを使うのであれば買いましょう。

今回はデフォルトのファームウェアを使います。

Intel Edison

組み込みLinuxと普通のIntel CPUが入ったRas○berry ○iっぽい何かです。何を作るかはアナタ次第。
社内に落ちていたのはArduino互換ボードがくっついてる、Intel Edison Kit for Arduinoです。

Edison本体はSDカード大のちっこいボードですが、5GHzのWi-FiとつながったりBluetoothを使えたりと、なかなか使い勝手のいい代物です。
Edison本体

Edisonのファームウェアバージョンは2.1を使います。

SensorTagのセットアップ

箱を開けたら赤いカバーに包まれた本体が出てきます。
本体の下のビニールを引っこ抜いたら準備完了です。

ぶちょおにお願いしてSensorTagのいろいろ書き換えられる「CC-DEVPACK-DEBUG」を買ってもらいましたが、いろいろ書いているうちに心がポッキリいったのでファームウェア書き換えはもうやりません。

使い勝手は良いです。はい。

Edisonのいろいろセットアップ

まずはEdisonの初期設定ですが、公式のマニュアルを参考にします。稀に良く色々なことに失敗しますが、抜き差ししてればきっといつかできます。
Step5は飛ばしていただいても結構です。Arduinoに用は無い。

次にopkgの設定を行います。かなり適当に言えばyumっぽいアレです。 Edison用のリポジトリを作ってくれた方の説明を参考に設定ファイルを書きます。

まずはEdisonにログインします。
シリアルコンソールでもSSHでも、お好みの方法で大丈夫です。

ログインしたらファイルを開いて、

# vi /etc/opkg/base-feeds.conf

下記をコピペして保存します(viの使い方はお察しください)

src/gz all http://repo.opkg.net/edison/repo/all
src/gz edison http://repo.opkg.net/edison/repo/edison
src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32

リポジトリの最新情報をダウンロードします。

# opkg update

次に、Edisonはデフォルト状態だとBluetoothが無効になっているので有効にします。

# rfkill unblock bluetooth

これでパッケージインストールし放題、無線飛ばし放題です。

ググると出てくる罠

ちなみに下記コマンドを打たせている一部情報がありますが、打ったらダメです。

# opkg upgrade

もう打ってしまった方は初期設定からやり直しましょう。再起動するとかなりの確率でいろいろな不具合が出てきます。

そして公式の説明には下記のように太字で書いてあります。

Do not run "opkg upgrade", that will overfill your rootfs and is not an intended use case for this repo.」("opkg upgrade" は実行しないでね。rootfsが溢れるし、upgradeはこのリポジトリの意図した使い方じゃないよ。)

詳しいことはこっちですが、簡単に書くと↓のような流れでぶっ壊れます。

  1. opkg upgrade 中に /boot あたりの空き容量が足りなくなる
  2. 一部パッケージのアップデートに失敗する
  3. アップデートされたパッケージと他パッケージとの間でバージョンの不整合が発生する
  4. 一部デーモンが起動しなくなる

ユースケースによってはこの問題に引っかからずに済みますが、今回は別です。

パッケージのインストール

さて、リポジトリの設定が終わったので、パッケージのインストールに取り掛かります。

まずは下記のパッケージをインストール・アップグレードして…

# opkg install systemd-dev
# opkg upgrade nodejs

作業用のディレクトリを作って…

# mkdir sensortag
# cd sensortag

SensorTag周りで手抜きをするためにNode.jsのライブラリをインストールします。

# npm install sensortag async

これでSensorTagと戯れることが出来るようになります。

なお、Edisonのバージョンアップで動かなくなっても怒らないでください…。
結構頻繁に前のやり方が通用しなくなります。

コードの本体をつっこむ

コードづくりに入っていきます。 SensorTag複数台となると少し面倒ですが、SensorTag 1台だけであれば簡単です。

1つ前の手順でインストールしたNode.js用ライブラリである node-sensortag ですが、READMEがかなり丁寧に書かれています。

とりあえずEdison上でエディターを開いて、READMEとサンプルコードを参考に下のようなコードを書きました。 ファイル名は sensor.js にしてます。

// 使うライブラリを require する
var Util = require('util');
var Async = require('async');
var SensorTag = require('sensortag');

// SensorTagを見つけた時の処理
function onDiscover(sensorTag) {
  Util.log('Discovered: ' + sensorTag);

  // 切断された時の処理
  sensorTag.on('disconnect', function() {
    Util.log('Disconnected: ' + sensorTag);
  });

  // 接続する
  sensorTag.connectAndSetUp(function(error) {
    if (error) {
      util.log('Connection error:', error);
    } else {
      // 接続できたら準備
      prepareSensor(sensorTag);
    }
  });
};

// SensorTagの準備
function prepareSensor(sensorTag) {
  Async.series([
    function(callback) {
      // 温度センサーの有効化
      Util.log('enableIrTemperature');
      sensorTag.enableIrTemperature(callback);
    },
    function(callback) {
      // 値が取れるまでちょっと時間が掛かるので待つ
      setTimeout(callback, 2000);
    },
    function(callback) {
      // 10秒毎に readSensorsValue を呼び出すようにする
      setInterval(
        function() { readSensorsValue(sensorTag); },
        10000
      );
      callback();
    }
  ]);
}

// センサーの値を読み取る
function readSensorsValue(sensorTag) {
  Util.log('Reading sensors value: ' + sensorTag)
  sensorData = {}

  Async.series([
    function(callback) {
      // 温度センサーの値を読み取って sensorData に格納
      sensorTag.readIrTemperature(function(error, objTemp, ambTemp) {
        sensorData.ambTemp = ambTemp;
        callback();
      });
    },
    function(callback) {
      // 集めたセンサーの値をコンソールに出力
      Util.log(sensorData)
      callback();
    }
  ]);
}

// SensorTagの検索開始
Util.log("discoverAll");
SensorTag.discoverAll(onDiscover);

コードの概要は↓のような感じです。

  • SensorTagを探す
  • 見つけたら接続する
  • 接続できたら温度センサーを有効にする
  • 10秒ごとに値を取得して出力する

ということで、コードの作成終了です。

温度を測ってみる

作ったコードを実行します。

# node sensor.js

実行したらSensorTagの電源を入れます(厳密には電源入りっぱなしだけど気にしない)
SensorTagの緑LEDがなんかチカチカしてたら電源が入ってます。

SensorTagとEdisonが接続されたら、下記のような感じにコンソールに出力されます。
ambTempに格納されているのが室温です。

18 Feb 10:40:13 - discoverAll
18 Feb 10:40:20 - Discovered: {"id":"xxxxxxxxxxxx","type":"cc2650"}
18 Feb 10:40:22 - enableIrTemperature
18 Feb 10:40:34 - Reading sensors value: {"id":"xxxxxxxxxxxx","type":"cc2650"}
18 Feb 10:40:34 - { ambTemp: 25.90625 }
18 Feb 10:40:44 - Reading sensors value: {"id":"xxxxxxxxxxxx","type":"cc2650"}
18 Feb 10:40:44 - { ambTemp: 25.9375 }
...

ね?簡単でしょう?

湿度も測りたいんだけど?

そんなこともあろうかと処理を増やしやすい(個人比)コードにしてます。

まずは prepareSensor を下記のように書き換えて、湿度センサーを有効化します。

function prepareSensor(sensorTag) {
  Async.series([
    function(callback) {
      // 温度センサーの有効化
      Util.log('enableIrTemperature');
      sensorTag.enableIrTemperature(callback);
    },
/** 追加した場所はここから **/
    function(callback) {
      // 湿度センサーの有効化
      Util.log('enableHumidity');
      sensorTag.enableHumidity(callback);
    },
/** ここまで **/
    function(callback) {
      // 値が取れるまでちょっと時間が掛かるので待つ
      setTimeout(callback, 2000);
    },
    function(callback) {
      // 10秒毎に readSensorsValue を呼び出すようにする
      setInterval(
        function() { readSensorsValue(sensorTag); },
        10000
      );
      callback();
    }
  ]);
}

次に readSensorsValue を書き換えて、湿度センサーの値を読み取るようにします。

function readSensorsValue(sensorTag) {
  Util.log('Reading sensors value: ' + sensorTag)
  sensorData = {}

  Async.series([
    function(callback) {
      // 温度センサーの値を読み取って sensorData に格納
      sensorTag.readIrTemperature(function(error, objTemp, ambTemp) {
        sensorData.ambTemp = ambTemp;
        callback();
      });
    },
/** ここから **/
    function(callback) {
      // 湿度センサーの値を読み取って sensorData に格納
      sensorTag.readHumidity(function(error, temperature, humidity) {
        sensorData.humidity = humidity;
        callback();
      });
    },
/** ここまで **/
    function(callback) {
      // 集めたセンサーの値をコンソールに出力
      Util.log(sensorData)
      callback();
    }
  ]);
}

これでコードいじりは終わりです。
先ほどと同じように node sensor.js を実行すると、下記のようになります。

18 Feb 18:31:15 - discoverAll
18 Feb 18:31:15 - Discovered: {"id":"xxxxxxxxxxxx","type":"cc2650"}
18 Feb 18:31:21 - enableIrTemperature
18 Feb 18:31:22 - enableHumidity
18 Feb 18:31:35 - Reading sensors value: {"id":"xxxxxxxxxxxx","type":"cc2650"}
18 Feb 18:31:35 - { ambTemp: 22.09375, humidity: 65.850830078125 }
18 Feb 18:31:45 - Reading sensors value: {"id":"xxxxxxxxxxxx","type":"cc2650"}
18 Feb 18:31:45 - { ambTemp: 22.15625, humidity: 65.68603515625 }
...

humidity の値が(相対)湿度です。とっても簡単ですね。

おわり

温湿度計のような何かが完成しました。わほーい。

上記のコードだと取得した情報がコンソールに垂れ流しですが、コンソール出力の代わりにデータベースなどなどに格納すれば一日の記録をとってグラフを描画することも難しくはありません。

思い思いに値を格納したりいじくり回したりして、SensorTagから取った値を活用してみてはいかがでしょうか?

次回はAWSのサービスを使って可視化してみます。
乞うご期待?

おまけ

余談ですが私がいじくり回した結果、下のようなものができあがりました(ドヤァ
社内温度計