Raspberry Piと300円でIoTボタンを作ろう💪

# 概要

![シャッターボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294146/b239be14-e7e5-3464-7d12-0f01d63a23ee.jpeg)

100円ショップのダイソーでは、スマホのカメラのシャッターを遠隔操作するためのBluetoothカメラシャッターボタンが売っています。
これは**300円**ほどとお安く入手できるもので、なかなか面白いオモチャです。

今回はこのBluetoothボタンをIoTボタンとして転用してみることにします。
仕組みとしては、ボタンを押したらPythonとRaspberry Piでそのボタンの押下を検知し、任意のWEB APIにGETメソッドでコールすることで、自由に遊べるという感じ。

なお筆者は**トイレに行ったタイミング**でこのIoTボタンを押して、何時何分にトイレに行ったかデータをDBに記録しています。


# コード
[devinoue/300yen-iot-button](https://github.com/devinoue/300yen-iot-button)
GitHubにてコードを公開してます、スター:star:をよろしくお願いします！


## 環境
環境はRaspberry Piの使用を推奨。

- Raspberry Pi 3 Model B+
- Python 3.6
- pip 9.0.1 



# Bluetoothボタンの準備
まずリモートシャッターとRaspberry Piをペアリングをします。
リモートシャッターをONについて、Raspberry Piで以下のコマンドを実行します。

```
bluetoothctl
scan on
```

おそらく`[NEW] Device XX:XX:XX:XX:XX:XX AB Shutter3`という名前とMACアドレスが表示されるので、このMACアドレスでpairingと自動再接続されるようtrustを実行します。

```
pair XX:XX:XX:XX:XX:XX
trust XX:XX:XX:XX:XX:XX
```
成功したら終了しましょう。

```
exit
```



# 必要なモジュールのインストール
evdevというモジュールを使用しています。
以下のコマンドでインストールしてください。


```bash
sudo pip3 install evdev
```


# 実行

以下がコードのすべてです。evdevでキーの動作を検知しています。
長押し検知機能もあるので、**計4つのAPIエンドポイント**にコールすることができます。
標準出力にはレスポンスデータが表示されます。


```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Python IoT Button"""


import evdev
from evdev import InputDevice, categorize, ecodes
import datetime
from time import time, sleep
from urllib import request, error
import settings


# 送信先URL
# iOSボタンを押したとき
url_iOS_push = "https://postman-echo.com/get?from=ios_push"
# iOSボタンを長押ししたとき
url_iOS_hold = "https://postman-echo.com/get?from=ios_hold"

# Androidボタンを押したとき
url_Android_push="https://postman-echo.com/get?from=android_push"
# Androidボタンを長押ししたとき
url_Android_hold="https://postman-echo.com/get?from=android_push"

# ホールドされたとみなす時間(秒)
hold_time_sec = 0.5


def main():
    print("Waiting for device to become ready...")
    dev_path = ""
    while(True):
        devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
        for device in devices:
            if("Shutter" in device.name):
                dev_path = device.path
        if (dev_path == "") :
            sleep(1)
        else : break

    dev = InputDevice(dev_path)
    print("IoT Button is ready.")
    old = 0
    iOS_flag=0
    is_android = 0
    for event in dev.read_loop():
        if event.type == ecodes.EV_KEY:
            if event.value == 1:
                if event.code == 28:  # when android button pushed
                    is_android=1

            # key upが始まったら
            if event.value == 0:
                if iOS_flag==1 : 
                    iOS_flag=0
                    continue
                
                # 長押し終わり
                if old != 0 and time() - old > hold_time_sec:
                    if is_android :
                        ConnectServer(url_Android_hold,"Android hold")
                        is_android=0
                        iOS_flag=1
                    else:
                        ConnectServer(url_iOS_hold,"iOS hold")

                    old = 0
                    continue
                if is_android:
                    ConnectServer(url_Android_push,"Android push")
                    is_android=0
                    iOS_flag=1
                else:
                    ConnectServer(url_iOS_push,"iOS push")

            # 長押しスタート
            if event.value == 2 and old == 0:
                old = time()


def ConnectServer(url,style):
    req = request.Request(url)
    try:
        with request.urlopen(req) as res:
            print("Success : {} {}".format(style,res.read(100).decode('utf-8')))
    except error.HTTPError as err:
        print(err.code)
    except error.URLError as err:
        print(err.reason)


if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass
print("\n")


```


# 終わりに
Raspberry Piで楽々IoTボタンライフをお過ごしください

# 参照
[わずか300円でIoTボタンを作る方法](https://qiita.com/vimyum/items/8b7548ca8cf45383c5b0)
[Bluetoothシャットダウンボタンを作る #300円でIoTボタン](https://qiita.com/nori-dev-akg/items/96584d9591d329f9dcb2)