5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

enebular InfoMotion でオムロン環境センサー (2JCIE-BL01) を可視化してみた。

Last updated at Posted at 2018-09-23

はじめに

enebular developer Meetuup Vol.3 で「enebular InfoMotion を使ってオムロン環境センサー (2JCIE-BL01) を可視化してみた。(仮)」というタイトルで LT する内容の記事です。

スクリーンショット 2018-09-23 20.26.56.png

Raspberry Piとオムロン環境センサーを使用して測定したデータを可視化する事例やハンズオンはいくつかあるが、データを Firebase へアップロードして、Firebase のデータを enebular InfoMotion で可視化してみた。

事前準備

  • Raspberry Pi
  • Raspberry Pi 3 Model B
  • Raspberry Pi 3 Model B+
  • Raspberry Pi Zero W
  • Raspberry Pi 2 Model B + Bluetooth 4.0 USBアダプタ(CSR V4.0、BT-Micro4 など)

 OS は "RASPBIAN STRETCH" Version:June 2018 (Release date:2018-06-27) を使用。

構成

スクリーンショット 2018-09-22 22.38.49.png

手順

Raspberry Pi

5分毎にデータをFirebaseへアップロードする場合 (Ambient のツールを流用しています)

# ライブラリをインストール
$ sudo apt-get install libglib2.0-dev
$ sudo pip3 install bluepy
$ sudo pip3 install pyrebase
# プログラムを実行
$ sudo nohup python3 omron_firebase.py < /dev/null &

omron_firebase.py プログラムは こちら

項目 設定値
config apiKey Firebase の apiKey を設定 (必須)
authDomain Firebase の authDomain を設定 (必須)
databaseURL Firebase の databaseURL を設定 (必須)
storageBucket Firebase の storageBucket を設定 (必須)
email Firebase の認証用 ID (必須)
password Firebase の認証用 Password (必須)
address オムロン環境センサーの BT アドレス (任意)
omron_firebase.py
# -*- coding: utf-8 -*-
#

from bluepy.btle import Peripheral, DefaultDelegate, Scanner, BTLEException, UUID
import bluepy.btle
import sys
import struct
from datetime import datetime
import argparse
import pyrebase

config = {
    "apiKey": "",
    "authDomain": "",
    "databaseURL": "",
    "storageBucket": ""
}
email = ''
password = ''
companyID = 'd502'  # OMRON company ID (Bluetooth SIG.)
address = 'FFA511nnnnnn'  # BT ADDRESS (replace nnnnnn to own device)

Debugging = False
def DBG(*args):
    if Debugging:
        msg = " ".join([str(a) for a in args])
        print(msg)
        sys.stdout.flush()

Verbose = True
def MSG(*args):
    if Verbose:
        msg = " ".join([str(a) for a in args])
        print(msg)
        sys.stdout.flush()

def send2firebase(dataRow):
    (temp, humid, light, uv, press, noise, accelX, accelY, accelZ, batt) = struct.unpack('<hhhhhhhhhB', bytes.fromhex(dataRow))
    MSG(temp/100, humid/100, light, uv/100, press/10, noise/100, (batt+100)/100)

    firebase = pyrebase.initialize_app(config)
    db = firebase.database()
    auth = firebase.auth()
    user = auth.sign_in_with_email_and_password(email, password)

    now = datetime.now()
    dt_s = now.strftime("%s") + str(int(now.microsecond/1000))
    data = {
        "timestamp": int(dt_s),
        "value": {
          "created": int(dt_s),
          "address": address,
          "battery": float((batt+100)/100),
          "temperature": float(temp/100),
          "humidity": float(humid/100),
          "light": float(light),
          "uv": float(uv/100),
          "pressure": float(press/10),
          "noise": float(noise/100)
        }
    }
    MSG(data)
    results = db.child("omron").child(address).push(data, user['idToken'])

class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)
        self.lastseq = None
        self.lasttime = datetime.fromtimestamp(0)

    def handleDiscovery(self, dev, isNewDev, isNewData):
            if isNewDev or isNewData:
                for (adtype, desc, value) in dev.getScanData():
                    if desc == 'Manufacturer' and value[0:4] == companyID:
                        delta = datetime.now() - self.lasttime
                        if value[4:6] != self.lastseq and delta.total_seconds() > 11:
                            self.lastseq = value[4:6]
                            self.lasttime = datetime.now()
                            send2firebase(value[6:])

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d',action='store_true', help='debug msg on')

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

    global Debugging
    Debugging = args.d
    bluepy.btle.Debugging = args.d

    scanner = Scanner().withDelegate(ScanDelegate())
    while True:
        try:
            scanner.scan(5.0)
        except BTLEException:
            MSG('BTLE Exception while scannning.')

if __name__ == "__main__":
    main()

一括でCSVファイルのデータをFirebaseへアップロードする場合 (オムロンのサンプルプログラムが出力するCSVファイルを使用)

# ライブラリをインストール
$ sudo apt-get install python-bluez
$ sudo pip3 install pyrebase
# プログラムを実行
$ python3 omron_csv_firebase.py ./log/env_sensor_log.csv

omron_csv_firebase.py プログラムは こちら

項目 設定値
config apiKey Firebase の apiKey を設定 (必須)
authDomain Firebase の authDomain を設定 (必須)
databaseURL Firebase の databaseURL を設定 (必須)
storageBucket Firebase の storageBucket を設定 (必須)
email Firebase の認証用 ID (必須)
password Firebase の認証用 Password (必須)
omron_csv_firebase.py
import sys
import csv
from datetime import datetime
import pyrebase

config = {
    "apiKey": "",
    "authDomain": "",
    "databaseURL": "",
    "storageBucket": ""
}
email = ''
password = ''

arguments = sys.argv

if len(arguments) == 1:
  print ("Usage: python omron_csv_firebase.py CSV_FILE")
  sys.exit()

csvfile = arguments[1]

def main():
    firebase = pyrebase.initialize_app(config)
    db = firebase.database()
    auth = firebase.auth()
    user = auth.sign_in_with_email_and_password(email, password)

    ##  CSV_FILE format
    ##  Time,Gateway,Address,Type,RSSI (dBm),Distance (m),Sequence No.,Battery (mV),Temperature (degC),Humidity (%%RH),Light (lx),UV Index,Pressure (hPa),Noise (dB),Discomfort Index,Heat Stroke Risk,Accel.X (mg),Accel.Y (mg),Accel.Z (mg)
    ##  2018-09-17 00:04:53.831591,raspberrypi,FFA511nnnnnn,EP,-66,1.77188476275,69,2830.0,22.68,82.6,0,0.01,996.3,34.64,71.4,23.37,0.0,0.0,0.0

    f = open(csvfile, 'r')
    reader = csv.reader(f)

    for row in reader:
      if row[0] == 'Time':
        continue
      dt = datetime.strptime(row[0][0:19], '%Y-%m-%d %H:%M:%S')
      dt_s = dt.strftime('%s') + row[0][20:23]

      data = {
        "timestamp": int(dt_s),
        "value": {
          "created": int(dt_s),
          "address": row[2],
          "rssi": float(row[4]),
          "distance": float(row[5]),
          "battery": float(row[7]),
          "temperature": float(row[8]),
          "humidity": float(row[9]),
          "light": float(row[10]),
          "uv": float(row[11]),
          "pressure": float(row[12]),
          "noise": float(row[13]),
          "di": float(row[14]),
          "heat": float(row[15])
        }
      }
##      print (data)
      results = db.child("omron").child(row[2]).push(data, user['idToken'])

    f.close()
    return
 
if __name__ == "__main__":
    main()

※ pyrebase をインストールした後、プログラムを実行すると「ImportError: cannot import name 'opentype' 」エラーが出力されるので、google-auth-oauthlib をアップグレードする。

$ sudo pip3 install --upgrade google-auth-oauthlib

Firebase

omron → BT アドレス (FFA511nnnnnn) 配下にデータが格納される。データ構造は以下。

第一階層 第二階層
timestamp タイムスタンプ Unixtime (ミリ秒)
value address オムロン環境センサーの BT アドレス
battery バッテリー電圧 (mV)
created タイムスタンプ Unixtime (ミリ秒)
di 不快指数
distance 距離 (m)
heat 熱中症警戒度
humidity 湿度 (%)
light 照度 (Lm)
noise 騒音 (dBm)
pressure 気圧 (hPa)
rssi 電波強度 (dBm)
temperature 気温 (℃)
uv UV Index

Firebase_2.png

InfoType

InfoMotion 作成の前に InfoType 作成を実施する必要があるが、InfoType 作成には InfoMotion Tool を導入する必要があるため、今回はサンプルで用意されている linechart をダウンロードして使用することにした。
(参考) https://docs.enebular.com/ja/infomotion/infomotiontool
(参考) https://docs.enebular.com/ja/infomotion/SampleInfoTypes.html

enebular_linechart.png

InfoMotion

InfoType と DataSource を指定して InfoMotion ダッシュボードを作成する。(参考)

TYPE に linechart を指定する。
DATASOURCE に Firebase DataSource を指定する。
Label に address データキーを指定する。
Value に 上記の第二階層のデータキーを指定する。(気温であれば temperature を指定する。)

enebular_add_graph_3.png

enebular_add_graph_2.png

結果

enebular.png

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?