ソラカメを使ったデモアプリを作ってみた①前編 ソラカメのEventから検知画像を取り出す

<h1>やったこと

会社の有志メンバーにて、ソラカメを使ったデモ（お魚検知アプリ）をAWSで作ってみようというプロジェクトを実施したのだが、なんとか出来上がったのでアウトプットしとく。
作ったのはソラカメで家の水槽を撮影し、指定した時間に検知された魚の数とその瞬間の画像を表示できるようにするもの。
企画部門のメンバーだけでやったので、純粋なエンジニアはゼロ。コーディングはChatGPTくんやBardさんに手伝ってもらいながら作りあげた。

作ったシステムの全容（アーキテクチャ）は以下の通り。
大まかなフローとしては、

:::note info
1. WebUIから日時を指定
2. 対象日時の画像をソラカメに取りに行く
3. 画像データをAWS Rekognitionでラベル検知
4. 指定時間内で一番多く魚を検知した画像をSNSで通知
:::

といった感じ。全てAWSのマネージドを使った完全サーバレス構成で作ってみた。
私は主に2と3のバックエンドの部分を担当したので、その周辺で気づいたことをメモ。

![スクリーンショット 2023-12-30 14.17.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68086/062a1bb7-ec46-6eb8-a640-16156027bf4a.png)

<h1>開発環境

今回は複数人で開発したため、開発環境はCloud9、言語はPython3.11.4に統一した。
これは開発開始時点でLambdaのPythonのバージョン最新が3.11だったため。
Cloud9の環境構築は以下な感じ。
- とりあえず以下のURLとかを参考にマネージメントコンソールからCloud9の環境を作成する
　https://www.fabrica-com.co.jp/techblog/technology/4807/
- 上記の手順に従い、Cloud9の環境を構築。変更したのは、上記URLにあるようにEBSのボリュームを少し追加したところだけ。
- 以下のURLの手順を参考に、Cloud9環境へPythonをインストールする.
　https://dev.classmethod.jp/articles/build-a-python-development-environment-with-cloud9/
- Pythonインストール時に起きたこと
openssl1.1.1がない　→  openssl1.0.2のアンインストール　→ openssl1.1.1のインストール

<h1>ソラカメからEvent画像を取り出す

最初にやったのはソラカメでモーション検知した画像を取り出し、一旦S３へアップするという部分。
ソラカメでは、録画している映像に対してモーション検知（動体を検知）した場合に動画が12秒保存される。
このデータがEventとして保存され、APIにてそのEventデータを取り出すことができる。
今回利用したAPIは以下の「ソラカメ対応カメラのイベント一覧を取得する」もの。

<font color="red">GET /sora_cam/devices/{DEVICEID}/events</font>

実際にこのAPIを使って画像データを取得するためのURLを取り出すPythonコードは以下。
APIに渡すパラメータとしては、
limit : 1回のリクエストで取得するデータの最大値（今回は大きめの100とした）
from : イベント取得の開始時間（UNIX時間　ミリ秒）
to : イベント取得の終了時間（UNIX時間　ミリ秒）

この部分に関するTipsも記載しておく。
* 入力時間→UNiX時間の変換が必要
* <INS>ソラカメのモーション検知Eventは、一度取得されると5分間は次の検知をしない→1時間で最大12件</INS>
* モーションタグをONにしていると、検知したところに緑枠がつく（オリジナル画像がほしい場合はOFFにする必要あり）

```
def get_url_list(api_key: str, token: str, limit_num, ftime, ttime) -> None:
  headers = {
    'Content-Type': 'application/json',
    'X-Soracom-API-Key': api_key,
    'X-Soracom-Token': token,
  }  
  params = {
    "limit": limit_num,
    "from": ftime,
    "to": ttime
  }  
  resp = requests.get(
    f'{SORACOM_ENDPOINT}/sora_cam/devices/{DEVICEID}/events',
    headers=headers,
    params=params
  )                                                                                           
  data = json.loads(resp.text)
    image_urls = []
  for event in data:
    image_urls.append(event['eventInfo']['atomEventV1']['picture'])
  list_count = len(image_urls)
  print("リストの個数: {}".format(list_count))
  return image_urls
</conde>
```
上記関数でEvent画像のURLを取得できたので、このURLから画像をダウンロードし、S3にアップロードするところまでを最初のLambda関数として処理させた。
一応S3にアップするまでのところの関数は以下の通り。

```
def put_images(image_urls, bucket):
  #s3clientの設定                                                                                                                  
  s3 = boto3.client("s3")

  for data in image_urls:
    response = requests.get(data)
    image = response.content
    #　画像ファイル名を抽出                                                                                                        
    filename = re.findall(r"/([^/]+.jpg)?(?=\?|$)", data)[0]
    folder_name = "withlight"
    s3.put_object(Bucket=bucket, Key=f"{folder_name}/{filename}", Body=image)  
    print(filename)
```

このコードをLambda関数にしてデプロイし、前半の処理は終了。
後半（Rekognitionによる魚検知）に続く。