イベント風景の自動Tweetとパラパラ漫画をつくろう from 長野

こんにちは！[IoTLT Advent Calendar 2019](https://qiita.com/advent-calendar/2019/iotlt_neo) 19日目担当の[chinoppy](https://twitter.com/chinoppy0727)です！

今回は、長野版IoT縛りの勉強会時に使用した、イベント風景自動Tweet/その写真を使って作ったパラパラ漫画と、構築したシステムについて紹介しますー

[長野版IoT縛りの勉強会 IoTLT長野 vol.2](https://iotlt.connpass.com/event/122650/)

# めざすもの

## イベント風景自動Tweet

<blockquote class="twitter-tweet">
<a href="https://twitter.com/glnagano/status/1119473436122734592">
</blockquote>

##  パラパラ漫画

撮影間隔が30分だったので、ちょっと物足りないですが・・・

![ezgif.com-video-to-gif_001.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52947/20c15be0-1d73-cbba-0f6d-b67faaed9410.gif)

# システム構築

## つかったもの

### ハード

- Raspberry Pi 3 Model B
  - OS：raspbian
- [Raspberry Pi Camera Module V2 カメラモジュール](https://www.amazon.co.jp/dp/B01ER2SKFS)
- [SORACOM SIM、USBドングル AK-020](https://www.amazon.co.jp/dp/B01G1GSYHW)

![IMG_20191217_130411.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52947/1acb42ff-494d-9c07-42c0-369954604d96.jpeg)

### クラウド

- SORACOM
  - SORACOM Beam
- AWS
  - IoT Core
  - Lambda
  - STS
  - S3

## 構成

![スクリーンショット 2019-12-15 17.14.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52947/83dbf629-b73f-747d-7266-e020be9b3546.png)

## 処理内容

1. Raspberry Piで写真撮影
2. SORACOM経由でIoT Coreへトークンの取得リクエストをする
3. STS経由でトークンを取得し、Raspberry Piへ送る
4. 2で取得したトークンを使用して、S3へアップロード
5. S3のTriggerでLambdaを実行し、Tweetする！

※ちなみに、今回、SORACOMを使用して、IoT Core経由でトークンを取得するようにしていますが、、、
※Raspberry Pi側にAWSのセキュリティ情報（シークレットキーなど）を保持させても問題ない環境でWifiが利用可能であれば、
※2、3は不要で、直接、S3へアップロードするのが楽かと思います！

## 環境構築

### 【Raspberry Pi】

ソースの詳細はこちら

https://github.com/peacemaker07/iot_making_for_raspberry_pi

※READMEなどちゃんと整備できていなくてすみません。。。

主になるソースはこちら

https://github.com/peacemaker07/iot_making_for_raspberry_pi/blob/master/main_camera.py

#### 前提

- OSはインストールしてあり、SSHで接続できる
- カメラは接続済み
- USBドングルにSOARCOMのSIMがはいっていて、SORACOMへ接続済み
  - 参考 : [SORACOM Airの設定](http://chinoppy.hatenablog.com/entry/2018/05/05/182930?_ga=2.245904263.2070522560.1576380651-424856074.1572872237#SORACOM-Air%E3%81%AE%E8%A8%AD%E5%AE%9A)

#### Raspberry Piで写真撮影

この部分で、撮影タイミングの場合は撮影し、撮影タイミングではない場合は処理終了

```python:main_camera.py
・・・
    # カメラ撮影
    camera_obj = Camera(camera_shadow)
    if not camera_obj.is_shooting():
        return
    camera_obj.shooting()
・・・
```

撮影時に使用するライブラリは[picamera](https://picamera.readthedocs.io/en/release-1.13/)し、撮影してます

```python:utils/camera.py
from picamera import PiCamera
・・・
     def _shooting(self):
・・・
        camera = PiCamera()

・・・
        # プレビュー開始
        camera.start_preview()

        # Camera warm-up time
        time.sleep(5)

        # 撮影
        camera.capture(image_path, quality=self.shadow.quality)

        # プレビュー終了しカメラクローズ
        camera.stop_preview()
        camera.close()
・・・
```

#### SORACOM経由でIoT Coreへトークンの取得リクエストをする

トークンの取得のリクエストと、取得はここで行っています

```python:main_camera.py
・・・
    # tokenの取得要求
    msg_token_req = MsgTokenReq(imsi=imsi)

    # token取得するためsubscribe実行
    result_sub = tasks_mqtt.run_subscribe_by_mqtt.delay(host, port, msg_token_req.get_sub_topic())
    time.sleep(2)

    try:
        mqtt_client = CommMqtt(host, port)
        mqtt_client.connect()

        result = mqtt_client.publish(msg_token_req)

        mqtt_client.disconnect()
    except:
        print("error")

    while not result_sub.ready():
        time.sleep(1)

    value = redis_client.get('token')
・・・
```

SORACOM→IoT Core→Lambda→STS の戻りを待たないといけないので、[celery](https://celery.readthedocs.io/en/latest/)を使用して待ち、取得したトークンをredis経由で取得します。

#### S3へアップロード

アップロードはこの部分で行っています

```python:main_camera.py
・・・
    # 撮影画像をS3へputする
    send_images_data = SendImagesData(imsi, camera_obj)
    # TODO S3 bucket名を可変にする
    comm_aws_s3 = CommAwsS3('sample-iot-making-dev', [send_images_data])
    ok_list, ng_list = comm_aws_s3.put_s3(payload_str)
・・・
```

取得したトークンを使用して、アップロードしてます

#### 定期的に実行

今回は、cronを使用しています
※リポジトリをpiユーザのホームディレクトリにした場合です

```
$ cd /home/pi/iot_making_for_raspberry_pi

# ライブラリインストール
$ pip3 install -r requirements.txt

# cron
$ crontab -e


*/10 * * * * python3 ~/iot_making_for_raspberry_pi/main_camera.py
```

### 【AWS】

[severless framework](https://serverless.com/)を使って構築しました

ソースの詳細はこちら

https://github.com/peacemaker07/iot_making_for_sls

※こちらもREADMEなど整備できていなくすみません。。。

READMEのInstall部分、Usageの「deploy」を行い環境を構築
これで構成図のAWS部分は完成

#### その他：IoT Coreでモノの登録を行う

デバイス証明書（あとにでてくるSORACOMでも使用）とShadowの機能を使うため、モノの登録を行います

こちらを参照に、モノの名前は「SIMのIMSI」

https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/register-device.html

#### IoT CoreのShadowを使う

設定値をShadowに持たせることにより、クラウドから設定を変更することができるようになります

IoT Coreのモノの中にある「シャドウ」に以下を登録

```
{
  "desired": {
    "sensor": {
      "interval": 10
    },
    "camera": {
      "quality": 10,
      "shoot_timing": 1,
      "resolution_width": 800,
      "resolution_height": 600,
      "tmp_dir": "/tmp",
      "is_shooting": true,
      "is_change_status": true
    }
  },
  "reported": {
    "sensor": {
      "interval": 10
    },
    "camera": {
      "resolution_width": 800,
      "is_shooting": true,
      "resolution_height": 600,
      "tmp_dir": "/tmp",
      "shoot_timing": 1,
      "quality": 10,
      "is_change_status": true
    }
  }
}
```

- desired
  - デバイスへ要求する値
- reported
  - デバイスの状態

「shoot_timing」を変更すると撮影タイミングを変えられます
ただし、Raspberry Pi側のcronでの実行間隔に依存します。。。

##### 例）

- cronが10分毎
  - ⇒shoot_timing=1 だと10分毎に撮影
  - ⇒shoot_timing=3 だと30分毎に撮影

#### S3のTriggerでLambdaを実行し、Tweetする！

S3へ画像がputされたときに、Lambdaを起動するようにしています

```yaml:serverless.yml
・・・
  #
  # S3 TriggerでLambdaを起動
  # https://serverless.com/framework/docs/providers/aws/events/s3/
  #
  notification_twitter:
    handler: handler.notification_twitter
    role: S3TriggerRoleForLambda
    events:
      - s3:
          bucket: ${file(./serverless.env.yml):NAME_PREFIX}-iot-making-${opt:stage}
          event: s3:ObjectCreated:*
          rules:
            - suffix: .jpg
          existing: true
・・・
```

Lambdaはこちら

https://github.com/peacemaker07/iot_making_for_sls/blob/master/handler/notification_twitter.py

「event」内にbucket、objキーの情報があるので、S3から取得しTweetしてます

### 【SORACOM】

#### 前提

- Webのコンソールは使用できる状態
- 使用するSIMは登録済み

#### SORACOM経由でIoT Coreへトークンの取得リクエストをする

この部分でBeamを使用するため、設定を行います

なのですが、まず、IoT Coreで取得したデバイス証明書の登録をします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52947/5e9287db-1c1c-3cb0-07e1-9475f289b8f2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52947/14d2d291-48fd-6cab-95a4-598e5761cd88.png)

「X.509証明書」を選択し必須項目を入力して登録

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52947/db60fe13-caa7-0b78-784b-605a2e42e3e7.png)

Beamの設定をします

- ホスト名は、IoT Coreのカスタムエンドポイントを入力
- 認証情報は、先ほど登録した二章情報を選択し設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52947/d9f5eab0-0aa5-58f7-e980-b88b690da32d.png)


撮影に関しては、これで設定完了しTweetできるようになりました👏

# パラパラ漫画について

こちらは、S3へ保存された写真をダウンロードして、iMovieで動画にしましたｗ

AWS CLIを使用すると簡単にダウンロードできます

```bash
$ aws s3 cp --recursive --exclude '*' --include 'camera_20190420*' s3://[bucket名]/[IMSI]/camera/ ./ --profile [pfofile名]
```

こんなかたちにすると、正規表現でダウンロードできるので楽です！

# 課題

- Raspberry Pi部分：S3へ画像送信時、bucket名が固定となっている
- ツイートの内容はコードを修正しないといけない。。。
- 送信間隔がcronでの間隔単位でしか設定できない。。。

別のイベントでも重宝してます👍