ラズパイとAWS IoTを使った見守りシステム自作で学んだこと（９）S3にuploadした映像の確認用web page

[（６）稿目](https://qiita.com/nsaito9628/items/8126fda477d61d542414)でuploadしたmp4ファイルの表示部になります。

mp4ファイルを確認する為のweb page Projectの構成と、ラズパイでイベント録画してS3にuploadした後にmp4ファイルを処理するLambda関数を説明します。

## web page Projectの構成
web page Projectの[リポジトリー内格納場所](https://github.com/nsaito9628/Monitoring-system-with-Raspberry-Pi-and-AWS)は/Monitoring-system-with-Raspberry-Pi-and-AWS/templateになります。

CloudFrontオリジン(兼mp4のupload先)として構築した[S3バケット](https://qiita.com/nsaito9628/items/312112486ce61ba396ae#origins3bucket)のrootにはindex.htmlが配置されます。このindex.htmlがCloudFrontにDefault Rootとして登録されていてCloudFrontDomainを叩くと表示されます。

以下はset_parameters.pyでモノの名前を入力後に出力したindex.htmlの一部です。
```html:index.html
<!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>My Place Watching Over Site</title>
        <meta name="viewport" content="width=device-width">
        <link href="https://fonts.googleapis.com/earlyaccess/nicomoji.css" rel="stylesheet">
        <link href="https://fonts.googleapis.com/css?family=M+PLUS+Rounded+1c" rel="stylesheet">
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body>
        <div class="container">
            <header>
                <h1>My Place Watching Over Site</h1>
            </header>

            <section class="information">
                <h1>Event records from catbed1 to catbed4</h1>
            </section>
        </div>    <div class="box1">
                <div class="section2">
        <h2>catbed1</h2>
        <img src="img/place1.jpg" width="500">
        <ol>
            <li><a href="Place1/place1-1.html" target="_blank">latest</a></li>
            <li><a href="Place1/place1-2.html" target="_blank">1 time ago</a></li>
                ・
                ・
                ・
            <li><a href="Place2/place2-11.html" target="_blank">10 times ago</a></li>
            <li><a href="Place2/place2-12.html" target="_blank">11 times ago</a></li>  
        </ol>
    </div>
    </div>
```

webブラウザーで表示される外観は以下のようになります。

<img width= 1500 src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565396/8d42f5d1-39e1-3cf1-50ac-e68838fe430f.png>

一つ階層を下がると、ラズパイ設置場所Place1からPlace4の映像を仕分けする為のプレフィクスが用意されていて、各プレフィックスにはindex.htmlに紐づいた過去１２回分のmp4ファイルを表示するhtmlファイルが格納されています。

後述するmp4ファイル名変更をするLambda関数は./functionに格納されます。

ページレイアウト用のCSSは./cssに、web pageに表示する場所の写真は./imgに格納されます。

表示する場所の写真を変更する場合はフォルダー内の写真を上書きします。

```sh
/neko-mimamori
┣ index.html
┣ /Place1
┃ ┣ 01.mp4
┃ ┣ Place1.html
┃ ┣ 02.mp4
┃ ┣ Place1-2.html
・　　・
・　　・
┃ ┣ 12.mp4
┃ ┗ Place1-12.html
・　　・
┣ /Place4
・　　・
・　　・
・　　・
┣ /function
┃ ┗ app.py
┣ /img
┃ ┣ place1.jpg
┃ ┣ place2.jpg
┃ ┣ place3.jpg
┃ ┗ place4.jpg
┣ /css
```

## Lambda関数によるmp4ファイル名変更と移動

html中のmp4ファイル名は固定（下のPlace1.htmlの場合だと01.mp4に固定）されているため、新たなファイルがuploadされた場合はファイル名をhtmlに合わせて書き換える必要があります。

```html:/Place1/place1-1.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>catbedNo1</title>
</head>
<body>
    <h1>catbed1 latest</h1>
    <video src="01.mp4" autoplay muted loop playsinline controls width=1024 height=768></video>
</body>
```

このファイル名更新作業をLambda関数で行います。

#### シーケンス図
mp4がS3のrootにuploadされると[Lambda関数が発火](https://qiita.com/nsaito9628/items/312112486ce61ba396ae#lambdafunction)して、まず最初に連番ファイル名になっている既存のmp4ファイルの番号を一つずつ繰り下げます。最後に、uploadされたmp4ファイルを01.mp4にリネームします。

下図のような動作になります。

<img width= 1200 src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565396/328c7fba-402b-dced-f44c-d2e6e7eb6333.png>

#### Lambda関数

このmp4ファイル名変更シーケンスを実行するLambda関数です。
S3Bucket名は環境変数として読み込みます。
```python:app.py
import boto3
import os

s3 = boto3.client('s3')
ORG_BACKET = os.environ['ORG_BACKET']
```
deploy_fileはmp4表示用htmlに書かれているファイル名を降順に格納したリストです。Lambdaが発火したら古い順にファイル名を更新して01.mp4をあける必要があるからです。
```python
PLACE1 = "Place1"
PLACE2 = "Place2" 
PLACE3 = "Place3" 
PLACE4 = "Place4" 

deploy_file = ["12.mp4",
                "11.mp4",
                "10.mp4",
                "09.mp4",
                "08.mp4",
                "07.mp4",
                "06.mp4",
                "05.mp4",
                "04.mp4",
                "03.mp4",
                "02.mp4",
                "01.mp4"]
```
古い順にファイルをリネームします。[バージョニング](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/Versioning.html)設定をしていない場合、元の12.mp4は上書きされると消えます。
```python
def modify_fname(filename, prefix):
    for i in range(len(deploy_file)):
        try:
            if deploy_file[i] == '01.mp4':
                s3.copy_object(Bucket=ORG_BACKET, 
                                Key=prefix+deploy_file[i],
                                CopySource={'Bucket': ORG_BACKET, 
                                            'Key': filename})
                s3.delete_object(Bucket=ORG_BACKET, 
                                Key=filename)
                break
            else:                    
                s3.copy_object(Bucket=ORG_BACKET, 
                                Key=prefix+deploy_file[i], 
                                CopySource={'Bucket': ORG_BACKET, 
                                            'Key': prefix+deploy_file[i+1]})
        except Exception as e:
            pass
    return
```
s3:ObjectCreatedのevent引数からuploadファイル名を抽出し、ファイル名に含まれるPlace番号が振り分け先プレフィックスになります。
```python
def lambda_handler(event, context):
    
    for rec in event['Records']:
        filename = (rec['s3']['object']['key'])

        if PLACE1 in filename: prefix = PLACE1 + "/"
        if PLACE2 in filename: prefix = PLACE2 + "/"
        if PLACE3 in filename: prefix = PLACE3 + "/"
        if PLACE4 in filename: prefix = PLACE4 + "/"

        modify_fname(filename, prefix)

    return
```

## Projectの実装
[（８）template.yamlで定義するAWSリソースの説明とsam deploy](https://qiita.com/nsaito9628/items/312112486ce61ba396ae)で説明したAWSリソースを全て実装した後に/Monitoring-system-with-Raspberry-Pi-and-AWS/templateの中身を作成したS3Bucketにuploadします。

これまでの設定例と同じくBucket名をneko-mimamoriとします。
モノの名前の登録と同様にここではawscliを利用してS3にuploadします。
```sh
BUCKET_NAME="neko-mimamori"

/usr/local/bin/aws s3 cp ./index.html s3://${BUCKET_NAME}
/usr/local/bin/aws s3 cp ./css/ s3://${BUCKET_NAME}/css --recursive
/usr/local/bin/aws s3 cp ./Place1/ s3://${BUCKET_NAME}/Place1 --recursive
/usr/local/bin/aws s3 cp ./Place2/ s3://${BUCKET_NAME}/Place2 --recursive
/usr/local/bin/aws s3 cp ./Place3/ s3://${BUCKET_NAME}/Place3 --recursive
/usr/local/bin/aws s3 cp ./Place4/ s3://${BUCKET_NAME}/Place4 --recursive
/usr/local/bin/aws s3 cp ./img/ s3://${BUCKET_NAME}/img --recursive
```

リポジトリー中のshellscriptではBUCKET_NAMEをiot_prov_configから読み込むので１行目だけ下記のように置き換えます。
```sh:mimamori-project-deploy.sh
BUCKET_NAME=$(cat ../../cert/iot_prov_config | grep S3BUCKET | awk -F'=' '{print $2}')
　　　　　　　　　　　　　　　　　　　　・
　　　　　　　　　　　　　　　　　　　　・
　　　　　　　　　　　　　　　　　　　　・
``` 
S3Bucketにuploadが完了しているのを確認できました。
<img width= 1200 src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565396/90f45c86-7c5c-18cf-54a6-a26d4da4ddbd.png>

## 次回
恐らく、本業でも趣味でもwebの仕組みを作られてる方が見たら「どうしてこうなった、、、、、」と言うかそっ閉じしたくなるような内容だったと思います。お付き合い頂きありがとうございました。

今後の課題として簡単なSPAづくりをJavaScriptのフレームワーク使って挑戦したいと思います。Amplifyも。

次回最終回、[(10)cliでラズパイ環境とAWSリソースを構築](https://qiita.com/nsaito9628/items/0339662ed04ba56bbb44)に続きます。