Echo Spotとraspberry piでセキュリティーカメラを作る


Echo SpotやEcho Showの様にディスプレイを持つEchoは動画を再生させることが出来ます。

既にAlexa向けのカメラはUSでいっぱい発売されていますが、これを自作してみようと思います。
カメラはラズパイ純正のカメラを利用しています。

全体像はこんな感じ

完成品が動いてる所

Alexa Skill for camera

サンプルソース

Video Appで再生できる動画やオーディオ

ディスプレイ付Echoで使うdisplay templateの詳細については、この記事を見てください。
Echo Showの表示を試してみる

Supported Video Formats and Resolutions

Streaming format Accompanying audio format
HLS, MPEG-TS AAC
SmoothStreaming (SS), MP4, M4A AAC, Dolby, Dolby Digital Plus
  • httpsを利用して動画が配信されれなければならない
  • サポートしている拡張子:.mp4, .m3u8, .ts
  • 対応コーデック:MPEG4 または H.264
  • 推奨動画サイズ:640x480 または 1280x720
  • 最大動画サイズ:1280x720

この条件をみたすようにraspberry piをセットアップします。

ラズパイのセットアップ

ラズパイにカメラを繋いで、そこから配信することで、echoからその映像が見れるようにします。
こちらの記事にやり方が公開されていたので、そちらを参考にしました。

Raspberry Pi のカメラモジュールでハイビジョン撮影して iOS に streaming 配信する

ラズパイは「2017-11-29-raspbian-stretch.img」を使っています。

$ uname -a
Linux raspberrypi 4.9.59-v7+ #1047 SMP Sun Oct 29 12:19:23 GMT 2017 armv7l GNU/Linux

ffmpegのインストール

$ sudo su
$ cd /usr/src
$ git clone --depth 1 git://source.ffmpeg.org/ffmpeg.git
$ cd ffmpeg
$ ./configure
$ make -j4
$ make install

nginxのインストール

$ apt-get install nginx
$ nginx -v

nginx version: nginx/1.10.3

$ chown -R pi /var/www/html
$ chgrp -R pi /var/www/html

ここで問題となるのが、echoではhttpsでのアクセスを必要とするので、SSL証明書が必要になります。
ラズパイ自体がインターネットからアクセスできるのであれば、直接Let's Encryptの設定ができるのですが、今回は外部に公開していないので、別のサーバで発行してそれをコピーする方法でSSL証明書を作成しました。

また、証明書を発行する際にドメインも必要なので、AWSのRoute53でローカルのIPと紐付けたレコードを追加しています。

ec2上でSSL証明書を発行

$ sudo su
$ yum install nginx
$ service nginx start
$ wget https://dl.eff.org/certbot-auto
$ chmod a+x certbot-auto
$ ./certbot-auto --no-bootstrap certonly --webroot -w /usr/share/nginx/html -d <使うドメイン> --email <自分のメアド>

これで、etc/letsencrypt/live/<使うドメイン>/ の中に以下の証明書が作られるので、それを全部ラズパイにコピーします。

  • cert.pem
  • chain.pem
  • fullchain.pem
  • privkey.pem

ラズパイ側

$ mkdir /etc/nginx/certs
$ cd /etc/nginx/certs

ココに、作成したSSL証明書を置きます。

サンプルのソースをgitからcloneしてそれを使用します。

$ cd /opt
$ git clone [email protected]:sparkgene/echo-pi-camera.git
$ cp /opt/echo-pi-camera/nginx/stream.conf /etc/nginx/sites-available/stream.conf
$ ln -s  /etc/nginx/sites-available/stream.conf /etc/nginx/sites-enabled/stream.conf

/etc/nginx/sites-enabled/stream.conf に自分のドメインを書きます。

server {
  listen 443 ssl;
  server_name <自分のドメイン>;

ラズパイにアクセスできるネットワーク上から実際にドメイン指定でアクセスできるかを確認します。

$ curl -I https://<自分のドメイン>/

HTTP/1.1 200 OK
Server: nginx/1.10.3
Date: Wed, 21 Mar 2018 07:10:09 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Wed, 21 Mar 2018 05:26:01 GMT
Connection: keep-alive
ETag: "5ab1ece9-264"
Accept-Ranges: bytes

これで、動画を配信する準備はできました。

Alexa Skillの作成

Alexa Skillはカスタムスキルを利用しますが、まだecho spotはまだ日本語対応していないので、US英語向けのSkillとして作成します。

skillの作成ではask cliを使っいますので、事前にAWSのクレデンシャルの登録をします。
ask cliで必要な権限は以下で公開されているので、この権限を持つアクセスキーを作成して、プロファイルを作成します。
https://developer.amazon.com/ja/docs/smapi/set-up-credentials-for-an-amazon-web-services-account.html

作業は、PC上で行ないます。

$ aws credential -p ask-cli

次にask cliをインストールしていなければ、インストールして初期設定を済ませます。

$ npm install -g ask-cli
$ ask init
$ ask init -l

  Profile              Associated AWS Profile
  [default]                 ** NULL **
  [us-alexa]                "ask-cli"

プロフィル名は適宜自分の環境に合わせて下さい。

サンプルソースをコピーます。

$ git clone [email protected]:sparkgene/echo-pi-camera.git
$ cd echo-pi-camera/echo-pi-camera

lambda/custom/lambda_function.py に映像のURLが書かれているので自分の環境に合わせて書き換えて下さい。

VIDEO_URL = "https://<自分のドメイン>/stream.m3u8"

askコマンドで、デプロイします。

$ ask deploy -p us-alexa
-------------------- Create Skill Project --------------------
Profile for the deployment: [us-alexa]
Skill Id: amzn1.ask.skill.
Skill deployment finished.
Model deployment finished.
Lambda deployment finished.
Your skill is now deployed and enabled in the development stage.
Try invoking the skill by saying “Alexa, open {your_skill_invocation_name}” or simulate an invocation via the `ask simulate` command.

完了すると、skillとlambdaファンクションが作られます。
lambdaファンクションで、runtimeが nodejs になってしまうのが原因わからないのですが(誰か教えて)、これをpython 3.6に変えます。

ラズパイ上で配信を開始

$ cd /opt/echo-pi-camera
$ sh ./stream.sh

ffmpeg version git-2018-03-21-7e0dc72 Copyright (c) 2000-2018 the FFmpeg developers
  built with gcc 6.3.0 (Raspbian 6.3.0-18+rpi1) 20170516
  configuration:
  libavutil      56. 11.100 / 56. 11.100
  libavcodec     58. 14.100 / 58. 14.100
  libavformat    58. 10.100 / 58. 10.100
  libavdevice    58.  2.100 / 58.  2.100
  libavfilter     7. 13.100 /  7. 13.100
  libswscale      5.  0.102 /  5.  0.102
  libswresample   3.  0.101 /  3.  0.101
Input #0, h264, from 'pipe:':
  Duration: N/A, bitrate: N/A
    Stream #0:0: Video: h264 (High), yuv420p(progressive), 720x404, 25 fps, 25 tbr, 1200k tbn, 50 tbc
[stream_segment,ssegment @ 0x2b7b310] Opening '/var/www/html/segments/00000000.ts' for writing
Output #0, stream_segment,ssegment, to '/var/www/html/segments/%08d.ts':
  Metadata:
    encoder         : Lavf58.10.100
    Stream #0:0: Video: h264 (High), yuv420p(progressive), 720x404, q=2-31, 25 fps, 25 tbr, 90k tbn, 25 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
[stream_segment,ssegment @ 0x2b7b310] Timestamps are unset in a packet for stream 0. This is deprecated and will stop working in the future. Fix your code to set the timestamps properly
[stream_segment,ssegment @ 0x2b7b310] Opening '/var/www/html/stream.m3u8.tmp' for writing
[stream_segment,ssegment @ 0x2b7b310] Opening '/var/www/html/segments/00000001.ts' for writing
[stream_segment,ssegment @ 0x2b7b310] Opening '/var/www/html/stream.m3u8.tmp' for writing
[stream_segment,ssegment @ 0x2b7b310] Opening '/var/www/html/segments/00000002.ts' for writing

配信が始まっている状態で、echoに対して alexa, open pi camera と話しかけると、映像が表示されます。

こんな感じのアクセスログが残ってました。

192.168.3.32 - - [21/Mar/2018:09:20:37 +0000] "GET /stream.m3u8 HTTP/1.1" 200 275 "-" "Dalvik/2.1.0 (Linux; U; Android 5.1.1; AEORK Build/LVY48F)"
192.168.3.32 - - [21/Mar/2018:09:20:37 +0000] "GET /00000003.ts HTTP/1.1" 200 389536 "-" "Dalvik/2.1.0 (Linux; U; Android 5.1.1; AEORK Build/LVY48F)"
192.168.3.32 - - [21/Mar/2018:09:20:37 +0000] "GET /00000004.ts HTTP/1.1" 200 392356 "-" "Dalvik/2.1.0 (Linux; U; Android 5.1.1; AEORK Build/LVY48F)"
192.168.3.32 - - [21/Mar/2018:09:20:38 +0000] "GET /00000005.ts HTTP/1.1" 200 217140 "-" "Dalvik/2.1.0 (Linux; U; Android 5.1.1; AEORK Build/LVY48F)"
192.168.3.32 - - [21/Mar/2018:09:20:38 +0000] "GET /00000003.ts HTTP/1.1" 200 389536 "-" "Dalvik/2.1.0 (Linux; U; Android 5.1.1; AEORK Build/LVY48F)"

ffmpegのオプションで -segment_time 2-segment_list_size 5 を指定してるから、 stream.m3u8 に2秒のtsファイルが最大5個として順次書き換えられていきます。echo側からの読み込みは stream.m3u8 の先頭に書かれているtsファイルを順次読み込んでいくので、その分の遅延が発生します(最大、10秒ぐらい)。
これをもっとリアルタイムにするには、もっとチューニングが必要そうな感じですね。

Smart Home Skill

今回はカスタムSkillとして作成しましたが、実際はSmartHome Skillでも作れるので、自然な発話で考えると、SmartHome Skillの方が良いのかなと思います。
https://developer.amazon.com/docs/device-apis/alexa-camerastreamcontroller.html
今度は、SmartHome版にもチャレンジしようと思います。

参考にしたサイト

https://qiita.com/UedaTakeyuki/items/dbb466fd47fa32a57a4c
https://www.ffmpeg.org/ffmpeg-formats.html#segment_002c-stream_005fsegment_002c-ssegment
https://qiita.com/MashMorgan/items/56498f276c54406b1928