Raspberry Pi Camera with enebular

# Raspberry Pi Camera with enebular

## はじめに

この記事では、デバイスで定期的にカメラを撮像し、S3へ格納するフローを作成していきます。  
~~Raspberry Pi 4で遊んで見たかっただけ~~
もしかしたら養殖支援システムで使うかもしれないので、その勉強用とメモです。

## 準備
- デバイス
  - [Raspberry Pi 4](https://jp.rs-online.com/web/p/processor-microcontroller-development-kits/1822096)
  - [Raspberry Pi Camera Module V2](https://jp.rs-online.com/web/p/video-modules/9132664/)
- OSセットアップ
  - [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) (今回はRaspbian Buster 2019-09-26を利用)
- [AWS アカウント](https://aws.amazon.com/jp/console/)
  - A.IoT Core でThingsを作成できる、IAM と Credential情報(enebular-agentで使用)
  - B.enebularのフローデプロイで使用するConnection用 IAM と Credential情報 (後述)
  - C.フローの処理の中でS3バケットへ格納ための IAM と Credential情報 (後述)

## 権限設定

カメラデバイスを有効にする

```
$ sudo raspi-config 
```

↓


```
┌─────────┤ Raspberry Pi Software Configuration Tool (raspi-config) 
│　〜 中略 〜
│  5 Interfacing Options  Configure connections to peripherals              
```

↓

```
┌─────────┤ Raspberry Pi Software Configuration Tool (raspi-config) 
│  P1 Camera      Enable/Disable connection to the Raspberry Pi Camera         
```

↓

```
          ┌──────────────────────────────────────────────────────────┐
          │                                                          │ 
          │ Would you like the camera interface to be enabled?       │ 
          │               <Yes>                  <No>                │ 
          │                                                          │ 
          └──────────────────────────────────────────────────────────┘ 
```
`<Yes>` を選択

## enebular-agentインストール

Raspberry Piにログインして enbular-agentを[インストール手順](https://docs.enebular.com/ja/EnebularAgent/Installation.html)に従ってインストールします。

```
$ wget -qO- https://enebular.com/agent-install | \
  sudo -E bash -s -- \
  --aws-iot-thing-name=enebular-agent-my-camera \
  --aws-access-key-id=AKIA**************** \
  --aws-secret-access-key=**************************************** \
  --aws-iot-region=ap-northeast-1 \
  --user=pi \
  --remote-maintenance-user-password=enebular
```
<details><summary>インストール時のログ</summary><div>

```
=================================================================================================================
 enebular-agent installation:
   - Device name:         tomono-pi4-suisui
   - System:              Linux 4.19.75-v7l+ armv7l GNU/Linux
   - Install user:        pi
   - Install destination: /home/pi/enebular-runtime-agent
   - Agent port:          awsiot
   - Agent version:       latest-release

... (省略)...

=================================================================================================================
 enebular-agent has been successfully installed ✔
   - Version: 2.9.1
   - Location: /home/pi/enebular-runtime-agent
   - User: pi
   - Service name: enebular-agent-pi

 AWS IoT Thing enebular-agent-my-camera has been created.
 enebular-agent is running as a system service.
 To check the status of agent, run the following command on the target device:
   sudo journalctl -ex -u enebular-agent-pi.service
=================================================================================================================
See details in full install log file: /tmp/enebular-agent-install-log.orIrop
```
</div></details>

## Connection を作成

続いて、enebularからデプロイするための[AWS IoT CoreへのConnection](https://docs.enebular.com/ja/deploy/deployflow/awsiot/makeawsiotconnection)を作成します。

空のフローの状態で、Deploy ができることを確認しておきます。

<img width="1127" alt="128_flow-my-camera___enebular.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540750/2a0bd651-a21f-e75d-1544-fc4bde80d228.png">


<!--
上記手順が完了すると、以下の情報が手に入っています。

- `arn:aws:iam::************:role/enebular_status_push_role` (Connection情報①)
- `arn:aws:iam::************:policy/EnebularPassRole` (Connection情報②)
- `****iot.ap-northeast-1.amazonaws.com` Connection情報③
-->

## Flow を作成

以下のnodeモジュールをenebularフローエディタ上の`admin`タブからインストールします。
- `node-red-contrib-camerapi`
- `node-red-contrib-aws`

次に、ノードを以下のように配置して接続していきます。  
また、適宜デバッグ出力ノードを入れます。

- ノード設定
  1. 入力 - `inject` : 定期実行
  2. その他 - `exec` : ホスト名取得
  3. 機能 - `switch` : 実行環境判定
  4. Raspberry Pi - `camerapi takephoto` : 撮影
  5. 機能 - `function` ：S3オブジェクト情報へ変換
  6. AWS - `AWS S3` : S3 PutObject

各ノードを以下の設定をしていきます。
なお、特に記載していないものはデフォルトのままです。


### 1. 定期実行

| 設定  | 設定値 |
|-------|--------|
| Node-RED起動の {N} 秒後、以下を行う | チェック
| {N} 秒後 | 0.1 |
| 繰り返し | 指定した時間間隔 |
| 時間間隔 | 1 |
| 時間間隔 | 分 |

### 2. ホスト名取得

| 設定  | 設定値 |
|-------|--------|
| コマンド | hostname |
| 引数 msg.payload | チェックを外す |

### 3.実行環境判定

ここで、実行ホスト名による分岐を行います。
この処理が無いと、enebularをホスティングしているサーバーで定期的に実行され 空(0バイト)の画像がS3バケットに格納されてしまいます。
条件1にこのフローがエッジデバイス上で実行されている場合の条件を、
条件2でサーバーで動いている場合に分けます。

次に注意するポイントとして、一つ前の「ホスト名取得」の実行結果msg.payloadに改行コードが入っています。
単純な文字列比較(`==`)の場合`\`をエスケープしてくれる(改行コードを入れられないという制約がある)ため、JSONataの`$trim`関数で改行コードを除いて比較を行います。

| 設定  | 設定値 |
|-------|--------|
| 条件1 | JSONata式 : `$trim(payload)="{Raspberry Piのホスト名}"` |
| 条件2 | その他 |
| 終了条件 | 最初に合致した条件で終了 |

### 4. 撮影

| 設定  | 設定値 |
|-------|--------|
| File Mode | Buffered Mode |
| Image Resolution | 320x240 (※任意の値に設定してください) |

今回は解像度について、アップロードのテストのため最小の解像度を選択しています。
ファイルサイズと予算にあった設定を行ってください。

### 5. S3オブジェクトへ変換

S3バケットへ格納するキー名(Key)と中身(Body)を設定します。

```javascript
const now = new Date();
const filename = ('0000' + (1900 + now.getYear())).slice(-4) + 
  ('00' + (1 + now.getMonth())).slice(-2) + 
  ('00' + now.getDate()).slice(-2) +
  ('00' + now.getHours()).slice(-2) + 
  ('00' + now.getMinutes()).slice(-2) + 
  ('00' + now.getSeconds()).slice(-2) + 
  '.jpg';

msg = msg || {};
msg.Key = 'test/' + filename;
msg.Body = msg.payload;

return msg;
```

### 6. S3 PutObject

あらかじめS3バケットの `PutObject` の権限を持ったIAMユーザー(準備.C)のCredential情報を入力していきます。
また、S3には格納用のS3バケットを作成しておきます。
- AWS設定

| 設定  | 設定値 |
|-------|--------|
| Region | ap-northeast-1 (※任意のリージョンを設定) |
| Access Id | AKIA************* |
| Secret Key | ************ |

| 設定  | 設定値 |
|-------|--------|
| Operation | PutObject |
| Bucket | {バケット名} |
| Key | test/dummy |

<img width="800" alt="enebular_Flow_Editor.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540750/79f92585-7891-24bd-ac12-e762f62f4777.png">

## 実行結果

期待通り、1分置きに画像が格納されている。

<img width="1210" alt="S3_Management_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540750/c8f612e9-eeff-a8f6-5c39-5b129c574134.png">

撮影した画像の結果

![20191222185258.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540750/677fc00c-0bbc-aee4-e66a-8b310d7402ab.jpeg)

## まとめ
細かいハマりポイントを除けば比較的簡単に環境を構築できました。
エッジ側で機械学習したモデルを使って処理させたりしたら、面白いことできそう。