キャストした釣り竿の「引き」をセンサーで検知し、一定の敷居値を超えた場合に、LINEにメッセージを通知する内容を実装しましたので、まとめてみました。
加速度センサーの実装
基本的な機器の実装と、加速度の取得は、以下の記事を参考にしてください。今回はx,y,z軸への移動距離を「振動のふり幅」とするので、取得した値のうち、Acceloretor値を使用します。 camelrush.hatenablog.com
システム構成図
今回の構成図は以下の通りです。MobilePC上でグラフを表示しつつ、スマホ(SmartPhone)のLINEにAPI通知をPushメッセージを通知します。
LINE「Messaging API」の使用
LINEのAPIのうち、今回は「Messaging API」を使用します。作成したチャネルのエントリポイント(WebHook)に対して、JSON形式でHTTPリクエストをPOSTすると、あらかじめチャネルを登録しているユーザに対してメッセージを発信することができます(発信先は、Toパラメータで個別指定ができますが、今回はブロードキャスト(全体)発信とします)詳細の仕様は以下に書かれています。
Messaging APIリファレンス | LINE Developers
LINEアカウントがあれば、LINE Developersにログインすることで、フリープランのAPIチャネルを使用することができます。
- LINE Developers サイト developers.line.biz
※アカウントの登録方法、チャネルの作成方法は省略します。
プログラム
RaspberryPiには、以下のPythonプログラムを配置します。
- mqttAccelerometer.py
from devices.accelerometer import AccelerometerMPU6050 as MPU6050 import paho.mqtt.client import ssl import asyncio import json import time import datetime import requests import random # Mqtt Define AWSIoT_ENDPOINT = "[AWS IoT Entry Point]" MQTT_PORT = 8883 MQTT_TOPIC_PUB = "mqttAccelerometer" MQTT_ROOTCA = "./awscert/AmazonRootCA1.pem" MQTT_CERT = "./awscert/xxxxxxxxxxx-certificate.pem.crt" MQTT_PRIKEY = "./awscert/xxxxxxxxxxx-private.pem.key" LINE_THRESHOLD = 5 MSG_LIST = ['ヒットしてない!?', '来てる来てるw', 'Fish on!', 'Gone!'] def mqtt_connect(client, userdata, flags, respons_code): print('mqtt connected.') # Entry Mqtt Subscribe. client.subscribe(MQTT_TOPIC_SUB) print('subscribe topic : ' + MQTT_TOPIC_SUB) def mqtt_message(client, userdata, msg): # Get Received Json Data json_dict = json.loads(msg.payload) # if use ... json_dict['xxx'] def line_post(asum,tmstr): access_token = [LINE API Access Token] headers = {'Authorization': 'Bearer {}'.format(access_token)} uri = "https://api.line.me/v2/bot/message/broadcast" msg = random.choice(MSG_LIST) + "\n" + tmstr + "(" + asum + ")" print(msg) item_data = { "messages":[ { "type":"text", "text":msg } ] } r_post = requests.post(uri, headers=headers, json=item_data) print(r_post) # Publish Loop async def pub_loop(): acmeter = MPU6050() sendtime = time.time() while True: # get Sensor data temp = acmeter.get_temp() ax, ay, az = acmeter.get_accel() gx, gy, gz = acmeter.get_gyro() tm = datetime.datetime.now() asum = abs(ax)+abs(ay)+abs(az) print('ax:{0:> .6f} ,ay:{1:> .6f} ,az:{2:> .6f} ,asum:{3:> .6f}'.format(ax,ay,az,asum)) json_msg = json.dumps({"dt":tm.strftime('%Y-%m-%d %H:%M:%S.%f'),"ax":ax,"ay":ay,"az":az,"asum":asum,"threshold":LINE_THRESHOLD,"gx":gx,"gy":gy,"gz":gz,"temp":temp}) # Line Message Send if (asum > LINE_THRESHOLD): if (time.time() - sendtime) > 1: sendtime = time.time() line_post('G:{0:>.2f}'.format(asum), tm.strftime('%H時').lstrip("0") + tm.strftime('%M分').lstrip("0") + tm.strftime('%S秒').lstrip("0")) # mqtt Publish client.publish(MQTT_TOPIC_PUB ,json_msg) time.sleep(0.01) # Main Procedure if __name__ == '__main__': # Mqtt Client Initialize client = paho.mqtt.client.Client() client.on_connect = mqtt_connect client.on_message = mqtt_message client.tls_set(MQTT_ROOTCA, certfile=MQTT_CERT, keyfile=MQTT_PRIKEY, cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None) # Connect To Mqtt Broker(aws) client.connect(AWSIoT_ENDPOINT, port=MQTT_PORT, keepalive=60) # Start Mqtt Subscribe client.loop_start() # Start Publish Loop loop = asyncio.get_event_loop() loop.run_until_complete(pub_loop())
加速度センサー「MPU6050」を制御する処理は、以下のとおりとなります。
- devices/accelerometer.py
from abc import ABCMeta import smbus import math from time import sleep # MPU6050 Register Map DEV_ADDR = 0x68 ACCEL_XOUT = 0x3b ACCEL_YOUT = 0x3d ACCEL_ZOUT = 0x3f TEMP_OUT = 0x41 GYRO_XOUT = 0x43 GYRO_YOUT = 0x45 GYRO_ZOUT = 0x47 PWR_MGMT_1 = 0x6b PWR_MGMT_2 = 0x6c class AbstractAccelerometer(metaclass=ABCMeta): def __init__(self ,devadr): self._devadr = devadr self._bus = smbus.SMBus(1) acc_conf = self._bus.read_byte_data(self._devadr ,0x1C) acc_conf = acc_conf | 0x18 self._bus.write_byte_data(self._devadr, 0x1C, acc_conf) def startup(self ,pwr_mgmt_adr): self._bus.write_byte_data(self._devadr, pwr_mgmt_adr, 0) def _read_word(self ,adr): high = self._bus.read_byte_data(self._devadr, adr) low = self._bus.read_byte_data(self._devadr, adr+1) val = (high << 8) + low return val def read_word_sensor(self ,adr): val = self._read_word(adr) if (val >= 0x8000): # minus return -((65535 - val) + 1) else: # plus return val class AccelerometerMPU6050(AbstractAccelerometer): def __init__(self): super().__init__(DEV_ADDR) super().startup(PWR_MGMT_1) def get_temp(self): temp = super().read_word_sensor(TEMP_OUT) x = temp / 340 + 36.53 # data sheet(register map)記載の計算式. return x def get_gyro(self): x = super().read_word_sensor(GYRO_XOUT)/ 131.0 y = super().read_word_sensor(GYRO_YOUT)/ 131.0 z = super().read_word_sensor(GYRO_ZOUT)/ 131.0 return [x, y, z] def get_accel(self): #x = super().read_word_sensor(ACCEL_XOUT)/ 16384.0 #y = super().read_word_sensor(ACCEL_YOUT)/ 16384.0 #z = super().read_word_sensor(ACCEL_ZOUT)/ 16384.0 x = super().read_word_sensor(ACCEL_XOUT)/ 2048.0 y = super().read_word_sensor(ACCEL_YOUT)/ 2048.0 z = super().read_word_sensor(ACCEL_ZOUT)/ 2048.0 return [x, y, z]
結果
以下のとおり、加速度センサーのふり幅(水色)が敷居値(灰色:5.0G)を超えた場合だけ、LINEに通知が送られてきました。
べからず
LINE API は、フリープランのうちは、60メッセージ/日、合計でも1.000メッセージが上限であり、それ以上を送ると通知してくれなくなります。センサーの通知メッセージをノーウエイトで送るとあっという間に上限に達し「429 Too Many Requests」を応答するようになりますので、注意してください。