赤外線センサーの結果をRaspberryPi 3 Model B+からAWS IoT経由でQuickSightでグラフ化するまで(その2) | そう備忘録

赤外線センサーの結果をRaspberryPi 3 Model B+からAWS IoT経由でQuickSightでグラフ化するまで(その2)

はじめに

赤外線距離センサーでカウントした値をブラウザでグラフ形式で表示するまでを試してみた時の備忘録。

赤外線距離センサー、RaspberryPiの設定に関しては前回の記事を参照の事。

今回はPythonのプログラムの中身についての記事とする。

今回の記事の範囲

センサーからの値について

センサー(TSSP77038)のOUTをRaspberryPiのピン番号29(GPIO5)に接続しているのでGPIO5の値は

  • HIGH:赤外線で物体を未検知
  • LOW:赤外線で物体を検知

となっている。

GPIO5の推移図

GPIO5の値の推移・イメージ図

物体を検知するとGPIO5の値はLOWになる。

GPIO5を0.1秒間隔で監視して物体が横切り終わった時にカウントアップするロジックにした。

もちろん物体が横切り始めた瞬間を捉えてカウントアップしても問題ない。

0.1秒間隔としたのはそれほど早い速度で横切ることを想定していないのでこの値にしたが高速で横切る前提であれば監視間隔、方法、センサーを含めて見直した方が良いと思う。

プログラム

プログラムは以下の通り。

Pythonは経験が少ないので、しょぼいプログラムで恥ずかしいのだけれども誰かの参考になればと思いアップしておく。(RasPi-to-AWS-TSS77038.py)

# -*- coding utf-8 -*-
import paho.mqtt.client as mqtt # MQTT
import ssl
import json
import datetime as dt
from time import sleep
import RPi.GPIO as GPIO

port = 8883 #AWSのポート
cert = "./cert/xxxxx-certificate.pem.crt" #モノの証明書
key = "./cert/xxxxx-private.pem.key" #プライベートキー
rootCA = "./cert/xxxxx.pem" #Amazonルート証明書
endpoint = "xxxxx-ats.iot.ap-northeast-1.amazonaws.com" #AWSのエンドポイント
clientID = "RasPi01"
topic = "count/pub" # カウント数をRaspberryPi to AWS
terminalID = "SK-RPi001"
counter = 0

# ピンをGPIOの番号で指定
GPIO.setmode(GPIO.BCM)
# ピンの名前を変数として定義
TSS77038 = 5
# GPIOセットアップ
GPIO.setup(TSS77038, GPIO.IN)

#main
try:
    if __name__ == '__main__':
        print("RaspberryPi to AWS Start")
        client = mqtt.Client(clientID, protocol=mqtt.MQTTv311) #初期化
        client.tls_set(ca_certs=rootCA, # TLS通信のセット
                       certfile=cert,
                       keyfile=key,
                       cert_reqs=ssl.CERT_REQUIRED,
                       tls_version=ssl.PROTOCOL_TLSv1_2,
                       ciphers=None)
        client.connect(endpoint, port=port, keepalive=60) #AWS IoTに接続
        client.loop_start()                # ループスタート
        find_flg =0

        while True:
            # LOWからHIGHになる時にカウントアップしてAWSにPublish
            if GPIO.input(TSS77038) == GPIO.HIGH:
                if find_flg == 1: # 前回検知している
                    counter += 1
                    print("found",counter)
                    now = dt.datetime.now()
                    message = {"terminalId":terminalID, # JSON形式でメッセージをセット
                               "sk_date":"{0:%Y-%m-%d}".format(now),
                               "sk_time":"{0:%H:%M:%S}".format(now),
                               "microsecond":now.microsecond,
                               "counter":counter}
                    client.publish(topic, json.dumps(message)) #AWS IoTに送信(Publish)
                find_flg =0
            else:
                find_flg =1 # find
            sleep(0.1)
except KeyboardInterrupt:
    pass

client.disconnect()            # 停止時にdisconnect
GPIO.cleanup()

以下にプログラムの説明を簡単に書いておく。

必要なモジュールの読み込み

2~7行目のimportはMQTT、SSL、JSONなど必要なライブラリを読み込んでいる。

RPi.GPIOはRaspberry Pi のGPIO(General Purpose Input Output)ピンを操作する為のライブラリ。

初期値の設定

AWS接続時のポート番号

port = 8883 #AWSのポート

AWS IoT coreとの接続ポートは8883を使用する。

AWS IoT Core関連

cert = "./cert/xxxxx-certificate.pem.crt" #モノの証明書
key = "./cert/xxxxx-private.pem.key" #プライベートキー
rootCA = "./cert/xxxxx.pem" #Amazonルート証明書
endpoint = "xxxxx-ats.iot.ap-northeast-1.amazonaws.com" #AWSのエンドポイント

10~13行目はAWS IoT Coreでモノを登録して証明書を取得すると発行されるAWSのエンドポイントや各種証明書を指定している。

発行された証明書をプログラムのあるディレクトリ配下のcert以下に保存している。

なお、AWS IoT Coreの設定については次回以降の記事とする。

Client IDとtopic

clientID = "RasPi01"

Client IDはAWS側でポリシーを設定して(詳しくは次回以降の記事とする)特定のClient IDだけコネクトを許す設定ができる。

プログラム側では、

client = mqtt.Client(clientID, protocol=mqtt.MQTTv311) #初期化

の様に初期化の時にclient IDを指定する。

もちろんポリシーの設定次第ではClient IDは不要になるのだが、今回は指定した。

topic = "count/pub" # カウント数をRaspberryPi to AWS

topicはMQTTプロトコル(MQTTについては前回の記事を参照)でメッセージをパブリッシュ(送信)、サブスクライブ(受信)する時に仕分ける為のキー。

“/”(スラッシュ)で階層構造を設定する事ができる。

またサブスクライブでは”#”(シャープ記号)でワイルドカード指定が可能。

今回はcount/pubを指定したが、例えば複数のRaspberryPiで様々な機器のカウント数をパブリッシュする時に、それぞれの機器で、

count/pub1

count/pub2

count/pub3

のtopicでパブリッシュして個別にサブスクライブするのであればcount/pub1、2、3を指定、一括でサブスクライブするならcount/#や#などの指定ができる。

2019/07/13追記

尚、topicは本番環境ではTopicデザインホワイトペーパ(Designing MQTT Topics for AWS IoT Core)を読んでからデザインする事をおすすめする。

connectとpublish

37~38行目でコネクトしてループをスタートしている。

client.connect(endpoint, port=port, keepalive=60) #AWS IoTに接続00
client.loop_start()                # ループスタート

実際にpublish(送信)するのは53行目

client.publish(topic, json.dumps(message)) #AWS IoTに送信(Publish)

最後に61行目でdisconnectしている

client.disconnect()            # 停止時にdisconnect

GPIO関連の設定

# ピンをGPIOの番号で指定
GPIO.setmode(GPIO.BCM)
# ピンの名前を変数として定義
TSS77038 = 5
# SPI通信用の入出力を定義
GPIO.setup(TSS77038, GPIO.IN)

19~24行目でGPIOの5をIN(入力)として定義している。

MQTTの初期化

client = mqtt.Client(clientID, protocol=mqtt.MQTTv311) #初期化
client.tls_set(ca_certs=rootCA, # TLS通信のセット
certfile=cert,
keyfile=key,
cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLSv1_2,
ciphers=None)

30~36行目では初期化した後、TLS通信する為のセットを行いAWS IoT Coreの設定で発行される各種証明書を指定してる。

上記の設定はpaho MQTTのサイトを参考にさせてもらった。

ループ

While True:
  ・
  ・
    sleep(0.1)
except KeyboardInterrupt:
    pass
GPIO.cleanup()

0.1秒間隔でwhile内の処理を無限ループで実行する。

プログラムはCtrl+Cキーを押して終了する。

また終了時にGPIOをクリーンアップしている。

これを実行しないと次回にプログラムを起動した時に前回のGPIOの値が残っていて誤動作する事があるので念の為。

条件文

if GPIO.input(TSS77038) == GPIO.HIGH:
    if find_flg == 1: # 前回検知している

43~44行目で前回物体を検知していて今回未検知の時(前述のGPIO5の推移(イメージ図)を参照)にパブリッシュする。

メッセージの作成

message = {"terminalId":terminalID, # JSON形式でメッセージをセット
"sk_date":"{0:%Y-%m-%d}".format(now),
"sk_time":"{0:%H:%M:%S}".format(now),
"microsecond":now.microsecond,
"counter":counter}

48~52行目でJSON形式のメッセージを作成する。

端末ID(ClientIDとは別)、日付、時刻、ミリ秒、カウント数をセットしている。

ここでちょっとハマったのがJSONの項目名のネーミングルール。

dateは予約後になっているだろうと想像してsk-dateとしたのだが”-“(ハイフン)は項目名としては許可されていないのでAWS IoT Coreにはパブリッシュできたのだが、その先のAWS Analyticsでエラーになってしまった。

なまじAWS IoT Coreでは通ってしまったので原因が判明するまでちょっとハマった。

結局”_”(アンダーバー)にしたらAWS Analyticsもあっさり通った。

動画

ブログと同内容を動画で説明しているので興味がある方はご確認ください。

つづく

今回はこれで終了。

次回以降にAWS IoT Coreの設定、AWS Analytics、AWS QuickSightの設定を行う

souichirou

やった事を忘れない為の備忘録 同じような事をやりたい人の参考になればと思ってブログにしてます。 主にレゴ、AWS(Amazon Web Services)、WordPress、Deep Learning、RaspberryPiに関するブログを書いています。 仕事では工場に協働ロボットの導入や中小企業へのAI/IoT導入のアドバイザーをやっています。 2019年7月にJDLA(一般社団法人 日本デイープラーニング協会)Deep Learning for GENERALに合格しました。 質問は記事一番下にあるコメントかメニュー上部の問い合わせからお願いします。

おすすめ

質問やコメントや励ましの言葉などを残す

名前、メール、サイト欄は任意です。
またメールアドレスは公開されません。