TI社のSensorTagで測った温度、湿度、気圧、照度、バッテリーレベルをBluetooth Low Energy(BLE)でRaspberry Pi3(RPi3)に送り、RPi3からAmbientに送ってデーターをグラフ化しました。

2017/6/1追記。「SensorTagはアドバタイズ状態で2分間放っておくとスリープモードに入って通信できなくなるので、長期間測定する端末としては使いにくい」と書きましたが、接続したままにすればスリープモードには入らないので、長期間測定する端末としても問題なく使えることが分かりました。詳しくは「SensorTagで温度、湿度などを測りRaspberry Pi3経由でAmbientに送ってグラフ化する」をご覧ください。

SensorTag

SensorTagは通信モジュールの異なる3種類のデバイスがあります。今回使ったのは「マルチスタンダード SensorTag」というもので、BLEで通信します。センサーとしては周囲および表面の温度センサー、湿度センサー、気圧センサー、周辺光センサー、加速度センサー、ジャイロスコープ、コンパス、磁気センサーが搭載されています。

SensorTagは2分間放っておくとスリープモードに入ります。省電力設計なのですが、再度電源ボタンを押さないと通信できなくなるので、どこかに設置して長期間気温などを測定する端末としては使いにくい仕様です。

(最初の版で「3分放っておくと」と書きましたが、TIの資料を再度調べたところ「アドバタイズが始まってから2分」で低消費電力モードに入るとのことでした)

今回はこの使いにくい仕様には目をつぶり、SensorTagからRPi3を経由してAmbientにデーターを送るテストをおこないました。

Raspberry Pi3(RPi3)のPythonでAmbientに中継する

「マルチスタンダード SensorTag」はBLEで通信します。そこでゲートウェイとしてRaspberry Pi3(RPi3)を使い、RPi3からBLEでSensorTagのデーターを取得し、Ambientに送りました。

プログラムはPythonで書きました。ライブラリーとしてbluepyを使いました。まずbluepyをRPiにインストールします。

pi$ sudo apt-get install python-pip libglib2.0-dev
pi$ git clone https://github.com/IanHarvey/bluepy.git
pi$ cd bluepy
pi$ python3 setup.py build
pi$ sudo python3 setup.py install

次にAmbientのPythonライブラリーもインストールします。

pi$ sudo pip3 install git+https://github.com/TakehikoShimojima/ambient-python-lib.git

SensorTagからデーターを取得するPythonプログラムは大まかには次のような流れになっています。

  • BLEデバイスをスキャンする
  • スキャンできたデバイスから、SensorTagを探す
    (SensorTagはローカルネームが’CC2650 SensorTag’になっている)
  • SensorTagに接続する
    (SensorTagクラスのインスタンスを作ると接続してくれる)
  • 温度、湿度、気圧、照度、バッテリーセンサーを有効化する
  • 温度、湿度、気圧、照度、バッテリーの値を読む
  • センサーを無効化する
  • 読んだ値をAmbientに送信する
  • 5秒ごとに上記の動作を繰り返す

このプログラムを動かすと、SensorTagのデーターがAmbientに送信され、グラフ化されるのが確認できました。

pi$ sudo python3 st2ambient.py
scanning tag
found SensorTag, addr = 24:71:89:bc:63:84
{'d4': 81, 'd5': 336.32, 'd2': 45.806884765625, 'd1': 25.1875, 'd3': 1016.45}
200

Ambientの画面上では次のように表示されます。

プログラムを最後に掲載します。今回はSensorTagからRPi3を経由してAmbientにデーターを送るテストということで、SensorTagがスリープモードに入った場合は手動で電源ボタンを押して再起動する必要がありますし、Pythonプログラムは複数のSensorTagがある場合を考慮していません。これらは次の課題です。

# -*- coding: utf-8 -*-
# while True:
#     SensorTagをスキャンし、見つけたデバイスに接続し、
#     温度、湿度、気圧、照度、バッテリーレベルを取得し、Ambientに送信
#
import bluepy
import time
import sys
import argparse
import ambient

def main():
    channelId = チャネルID
    writeKey = 'ライトキー'

    parser = argparse.ArgumentParser()
    parser.add_argument('-i',action='store',type=float, default=120.0, help='scan interval')
    parser.add_argument('-t',action='store',type=float, default=5.0, help='scan time out')

    arg = parser.parse_args(sys.argv[1:])

    scanner = bluepy.btle.Scanner(0)
    am = ambient.Ambient(channelId, writeKey)

    while True:
        dev = None
        print('scanning tag...')
        devices = scanner.scan(arg.t)  # BLEをスキャンする
        for d in devices:
            for (sdid, desc, val) in d.getScanData():
                if sdid == 9 and val == 'CC2650 SensorTag': # ローカルネームが'CC2650 SensorTag'のものを探す
                    dev = d
                    print('found SensorTag, addr = %s' % dev.addr)
        sys.stdout.flush()

        if dev is not None:
            tag = bluepy.sensortag.SensorTag(dev.addr) # 見つけたデバイスに接続する

            tag.IRtemperature.enable()
            tag.humidity.enable()
            tag.barometer.enable()
            tag.battery.enable()
            tag.lightmeter.enable()

            # Some sensors (e.g., temperature, accelerometer) need some time for initialization.
            # Not waiting here after enabling a sensor, the first read value might be empty or incorrect.
            time.sleep(1.0)

            data = {}
            data['d1'] = tag.IRtemperature.read()[0]  # set ambient temperature to d1
            data['d2'] = tag.humidity.read()[1]  # set humidity to d2
            data['d3'] = tag.barometer.read()[1]  # set barometer to d3
            data['d5'] = tag.lightmeter.read()  # set light to d5
            data['d4'] = tag.battery.read()  # set battery level to d4

            tag.IRtemperature.disable()
            tag.humidity.disable()
            tag.barometer.disable()
            tag.battery.disable()
            tag.lightmeter.disable()

            print(data)
            r = am.send(data)
            print(r.status_code)
            sys.stdout.flush()

            time.sleep(arg.i)
            # tag.waitForNotifications(arg.t)

            tag.disconnect()
            del tag

if __name__ == "__main__":
    main()