https://d226lax1qjow5r.cloudfront.net/blog/blogposts/home-surveillance-system-with-node-and-a-raspberry-pi/Blog_Home-Surveillance_Node-RaspberryPi_1200x600.png

ノードとRaspberry Piによるホーム監視システム

最終更新日 May 19, 2020

所要時間:26 分

ホーム監視システムを構築する方法を考えたことがあるだろうか?子供を監視したり、家の中で弱い立場の人を監視したり、あるいはホームセキュリティーシステムにするためでしょうか。このチュートリアルでは、家庭用監視システムを構築するための導入手順について説明します。

このチュートリアルでは、Raspberry Pi 4とRaspberry Pi Cameraモジュール、モーションセンサーを使って、小型で安価なホーム監視システムを構築します。ソフトウェア面では Video API(旧TokBox OpenTok)を使ってストリームを公開し Vonage Messages APIを使用し、動きが検知されたことをSMSでユーザーに通知する。

このチュートリアルで学ぶことのいくつかを紹介しよう:

前提条件

  • ラズベリーパイ4

  • Raspberry Pi カメラモジュール

  • モーションセンサー(HC-SR501 PIR)

  • TokBoxアカウント

  • Raspberry PiにインストールされたNodeとNPM

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.

Raspberry Piのインストールとセットアップ

ラズベリー・パイ財団は英国を拠点とする慈善団体で、世界中の人々がコンピューティングとデジタル技術の力を使って技術的な問題を解決し、創造的に自己表現できるよう支援している。

彼らのサイトには ステップバイステップガイドには、Raspberry Piデバイスの各パーツが何であるか、オペレーティング・システムのインストール方法、Raspberry Piの使い始め方についての素晴らしいステップ・バイ・ステップ・ガイドが掲載されている。その他にも、トラブルシューティングに役立つリソースや、興味のあるプロジェクトがたくさんあります。

カメラとモーションセンサーの設置

Raspberry Piカメラモジュールのインストール

このチュートリアルでは、Raspberry Pi 4と公式のRaspberry Pi Cameraモジュールを使用しますが、他のカメラを使用しても問題はありません。

下の写真は、この記事で使用したRaspberry Piとカメラモジュールです:

A Raspberry Pi with the Camera moduleA Raspberry Pi with the Camera module

カメラモジュールをリボンケーブルでRaspberry Piのカメラモジュールポートに接続します。下の写真は、カメラモジュールのリボンを取り付ける位置です:

Raspberry Pi with Camera Ribbon InstalledRaspberry Pi with Camera Ribbon Installed

SSHとカメラの有効化

セキュア・シェル (SSH)は、セキュアな接続とリモート・システムのコントロールを可能にするソフトウェア・パッケージである。このチュートリアルのRaspberry Piはヘッドレスモード、つまりモニター、キーボード、マウスなしで動作します。SSHを有効にすると、コンピューターや携帯電話でデバイスにリモート接続できるようになります。

SSHを有効にするには、Raspberry Piのターミナルで以下を実行する:

sudo raspi-config

下図のような画面が表示されます:

Raspberry Pi ConfigurationRaspberry Pi Configuration

オプション5を選択 Interfacing Options

  • 次のメニューから、オプション P1 を選択します。 Cameraを選択し Yes,

  • 続いて、オプションP2を選択する。 SSHを選択し、再度 Yes.

これでRaspberry PiのCameraモジュールとSSHが有効になりました。

モーションセンサーの取り付け

次のステップは、Raspberry Piとモーションセンサーを接続することです。このチュートリアルでは、HC-SR501 PIRモーションセンサーを使用していますが、他のモーションセンサーモジュールでも問題なく動作します。Raspberry Piへの配線は、各社の配線ガイドを参照してください。

まず、センサーを取り出し、3本のワイヤーを接続する。赤をライブ、青をGPIO、黒をグラウンドに使いました。この例のセンサーの場合、図のように1番目のピンがグラウンド、2番目のピンがGPIO、3番目のピンがライブです:

Example of Motion SensorExample of Motion Sensor

Raspberry Piの各ピンを説明するのに最適な例は、以下のサイトにあります。 ラズベリーパイのウェブサイト。この図は、GPIOピンのレイアウトを以下のように示しています:

Diagram of Raspberry Pi GPIO PinsDiagram of Raspberry Pi GPIO Pins

最後に、Raspberry Piにワイヤーを接続する。ライブ(赤)ワイヤーはPiのピンの1つに接続する必要があります。 5V powerアース(黒)線はPiのピンの1つに接続する必要がある。 GND上の図を参考に、私は6番ピンを使いました。最後に接続するワイヤーはGPIO(青)ワイヤーで、ピンの1つに接続する必要がある。 GPIOピンに接続する必要がある。この例では、"GPIO 18 "と書かれた12番ピンを使用した。

最終的な配線のセットアップを以下に示す:

Sensor Writing Part 2Sensor Writing Part 2

動作検知のテスト

これですべてのハードウェアのインストールと設定が完了し、いよいよプロジェクトのコードをビルドする時が来た。しかし、最初にNodeプロジェクトを作成し、モーションテストを行い、プロジェクトの準備をする必要があります。このプロジェクトで、モーション検出とビデオストリーミングのコードをすべて記述します。新しいNodeプロジェクトを作成するには、新しいディレクトリを作成し、そのディレクトリに移動して npm init.以下のコマンドを実行することで、これら3つのすべてを行うことができます:

mkdir /home/pi/pi-cam/ cd /home/pi/pi-cam/ npm init

要求された指示に従って、プロジェクトの名前を設定し、残りの入力はデフォルトのままにしておきます。

以下のコマンドは index.jsという新しいパッケージをインストールします。 onoffという新しいパッケージをインストールします:

touch index.js npm install onoff

新しい index.jsこのコードは、GPIOピン18を読み込んで、動きが検出されたら警告を発し、動きが止まったら警告を発します。

const gpio = require('onoff').Gpio;
const pir = new gpio(18, 'in', 'both');

pir.watch(function(err, value) {
    if (value == 1) {
        console.log('Motion Detected!')
    } else {
        console.log('Motion Stopped');
    }
});

上記のコードとモーションセンサーの取り付けが成功したかどうかをチェックする時間です。実行する:

node index.js

モーションセンサーの前で手を振り、ターミナルで「Motion Detected!数秒後、"Motion stopped "と出力されます。

カメラのテスト

Raspberry Piのコマンドラインで以下のコマンドを入力し、カメラの映像を静止画として撮影する。

注意デフォルト以外のユーザーでログインした場合は pi以外のユーザーでログインした場合は piをユーザー名に置き換えてください。

raspistill -o /home/pi/cam.jpg

ディレクトリを見ると /home/pi/を見ると cam.jpg.これを開くと、Raspberry Piの現在のカメラビューの写真が表示されます。

ノードとNPM

node --version npm --version

NodeとNPMの両方が正しいバージョンでインストールされている必要があります。 nodejs.orgにアクセスしてください。にアクセスし、正しいバージョンをダウンロードしてインストールしてください。

私たちのCLI

を使用してVonage CLIをセットアップします。 このガイド.必要なのは インストール設定の設定のステップだけです。

Git(オプション)

gitを使って デモ・アプリケーションをGitHubからクローンできます。

gitコマンドが苦手な方もご心配なく。

この を参照してください。.

Mysqlサーバーのインストール

Raspberry Pi上で以下のコマンドを実行し、MySQLデータベースサーバーをインストールする:

sudo apt install mariadb-server

デフォルトでは、MySQL サーバは rootユーザがパスワードなしでインストールされます。データベースが安全でないことを確認するために、これを修正する必要がある。Piで以下のコマンドを実行し、指示に従ってください。

sudo mysql_secure_installation

これで rootユーザーのパスワードが設定できたので、次はデータベースとそのデータベースにアクセスするユーザーを作成する番だ。MySQL サーバに接続する:

sudo mysql -u root -p

次に以下のSQLクエリーを実行して、新しいユーザーを作成し、そのユーザーに新しいデータベース上でいくつかの権限を付与する:

-- Creates the database with the name picam
CREATE DATABASE picam;
-- Creates a new database user "camuser" with a password "securemypass" and grants them access to picam
GRANT ALL PRIVILEGES ON picam.* TO `camuser`@localhost IDENTIFIED BY "securemypass";
-- Flushes these updates to the database
FLUSH PRIVILEGES;

これであなたのRaspberry Piはセットアップされ、このチュートリアルのコードパートの準備が整いました。

アプリケーションの構築

SSL証明書のインストール

Raspberry Piのターミナルで、ディレクトリをプロジェクトのパスに変更し、以下のコマンドを実行して自己署名SSL証明書を生成します。Video API へのアクセスには HTTPS が必要なため、自己署名であっても SSL 証明書が必要です。以下のコマンドを実行して、SSL証明書を生成してください。

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

つのファイルが作成される、 key.pemcert.pemこれらをコードがアクセスできる場所に移動します。このチュートリアルでは、これらはプロジェクト・ディレクトリにあります。

ウェブサーバー

Expressは、ウェブアプリケーションとモバイルアプリケーションのための堅牢な機能セットを提供する、最小で柔軟なNode.jsウェブアプリケーションフレームワークです。

Expressは非常に軽量で柔軟なNode.jsフレームワークで、このプロジェクトで必要なものだ。ビデオ・ストリームにアクセスするためのエンドポイントを提供します。

以下のコマンドでExpressをアプリケーションにインストールする:

npm install express --save

ファイルの先頭で index.jsファイルの先頭に、パッケージ https, fsexpress.以下のように変更してください:

+ const express = require('express');
+ const https = require('https');
+ const fs = require('fs');
const gpio = require('onoff').Gpio;

+ const app = express();
const pir = new gpio(18, 'in', 'both');

pir.watch(function(err, value) {
    if (value == 1) {
        console.log('Motion Detected!')
-    } else {
-        console.log('Motion Stopped');
    }
});

このチュートリアルでは elseこのチュートリアルでは動き検出の部分は必要ありません。ですから、上の図のようにその部分も削除してください。

ネットワークやインターネット経由でビデオストリームにアクセスするには、ウェブサーバーが必要です。エンドポイントの例を使って、新しいサーバーを開始するメソッドを作成しましょう。上記 pir.watch(function(err, value) {追加

async function startServer() {
  const port = 3000;

  app.get('/', (req, res) => {
    res.json({ message: 'Welcome to your webserver!' });
  });

  const httpServer = https.createServer({
    // The key.pem and cert.pem files were created by you in the previous step, if the files are not stored in the project root directory
    // make sure to update the two lines below with their correct paths.
    key: fs.readFileSync('./key.pem'),
    cert: fs.readFileSync('./cert.pem'),
    // Update this passphrase with what ever passphrase you entered when generating your SSL certificate.
    passphrase: 'testpass',
  }, app);

  httpServer.listen(port, (err) => {
    if (err) {
      return console.log(`Unable to start server: ${err}`);
    }

    return true;
  });
}

この関数にアクセスする方法が必要になった。 startServer() {}の下に、この関数への呼び出しを追加します:

startServer();

これが機能しているかテストするには、ターミナルで以下を実行する:

node index.js

注意SSHまたはキーボード/tvでRaspberry Piに接続している場合は、ターミナルで次のように入力します: ifconfigと入力すると、Raspberry PiのローカルIPアドレスが表示されます。

ブラウザでRaspberry PiのIPアドレスにアクセスします: https://<ip address>:3000/を返します。

{"message":"Welcome to your webserver!"}

Sequelizeのインストール

シーケライズはデータベースのクエリを簡単にするNode用の強力なライブラリだ。オブジェクトリレーショナルマッパー(ORM)であり、オブジェクトをデータベーススキーマにマッピングする。SequelizeはPostgres、MySQL、MariaDB、SQLite、Microsoft SQL Serverなど様々なプロトコルに対応しています。このチュートリアルでは、Raspberry Piで利用可能なSQLサーバーであるMariaDBサーバーを使用します。

# DotEnv is used to access your .env variables # Sequelize is an ORM for your DATABASE # mysql2 is what you're using as a database. Sequelize needs to know this. npm install --save dotenv sequelize mysql2 # Sequelize-cli allows you to generate models, migrations and run these migrations. npm install -g sequelize-cli # Initializes Sequelize into the project, creating the relevant files and directories sequelize init

プロジェクト・ディレクトリ内に、新しいファイル .envを作成し、以下の値をデータベースの正しい認証情報で更新します。

DB_NAME= DB_USERNAME= DB_PASSWORD= DB_HOST=127.0.0.1 DB_PORT=3306

ディレクトリ内に configディレクトリ内に config.js.このファイルにはプロジェクトのデータベース設定が保存されます。 .envファイルにアクセスできます:

require('dotenv').config();

module.exports = {
  development: {
    database: process.env.DB_NAME,
    username: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD,
    host: process.env.DB_HOST,
    port: process.env.DB_PORT,
    dialect: 'mysql',
    operatorsAliases: false
  },
}

では models/index.jsで、検索と置換を行う:

- const config = require(__dirname + '/../config/config.json')[env];
+ const config = require(__dirname + '/../config/config.js')[env];

メインファイルの index.jsファイルをインポートします。 models/index.jsファイルをインポートしてください:

const db = require('./models/index');

移行の生成と実行

Vonage Videoセッションが作成されると、セッションIDが返されます。このセッションIDは、リモートで接続するためにどこかに保存する必要があります。これを行う最良の方法は、データベースのテーブルです。最近インストールしたSequelize CLIを使って、以下のコマンドを実行してください。Sessionという新しいテーブルが作成され、2つの新しいカラムが追加されます:

  • sessionId (これは文字列である)、

  • アクティブ(ブール値)。

# Generate yourself a Session model, this is going to be used to store the sessionId of the video feed sequelize model:generate --name Session --attributes sessionId:string,active:boolean

このコマンドが成功すると、2つの新しいファイルが作成される:

  • models/session.js

  • migrations/<timestamp>-Session.js

新しいモデル session.js新しいモデルは、カラム名やデータ型など、データベースが期待するものを定義します。

新しい migrations ファイルは、移行が成功したときにデータベースに永続化されるものを定義します。この例では sessionsという新しいデータベーステーブルを作成します:

  • アイドル

  • セッションID

  • アクティブ

  • 作成日時

  • 更新日時

Sequelize CLIコマンドを使用して、パラメータを指定してこのマイグレーションを実行します。 db:migrate:

sequelize db:migrate

出力は以下の例と同じになる:

== 20200504091741-create-session: migrating =======
== 20200504091741-create-session: migrated (0.051s)

これで、後でセッションIDを格納するために使う新しいデータベーステーブルができました。

ビデオ

プロジェクトが必要とする2つのライブラリ、Vonage Video(旧TokBox OpenTok)とPuppeteerをインストールするところだ。

Vonage Video (旧TokBox OpenTok)は、世界中の人々にインタラクティブなライブ・ビデオ・セッションを提供するサービスです。Vonage Video API(旧TokBox OpenTok)はWebRTC業界標準を使用しています。これにより、モバイル、ウェブ、デスクトップアプリケーションを問わず、何十億ものデバイスでカスタムビデオ体験を作成することができます。

Puppeteerは、ChromeやChromiumをプログラムで制御する方法を提供するNodeライブラリです。デフォルトでは、Puppeteerはヘッドレスモードで動作しますが、ChromeやChromiumの非ヘッドレスモードで動作させることもできます。ヘッドレス・ブラウザとは、グラフィカル・ユーザー・インターフェイスを持たないブラウザのことである。

以下のコマンドを実行して、これら2つのライブラリをインストールする:

npm install opentok puppeteer

に追加したコードをコピーする。 index.jsのコードにコピーする。このコードは3つのライブラリをプロジェクトにインポートします。

  • OpenTok (Vonage Videoでビデオストリームを公開/購読する)

  • Puppeteer (Raspberry Piでヘッドレスモードでブラウザを開き、ストリームを公開する)

  • DotEnv (env変数にアクセスする)

OpenTok オブジェクトは、Vonage API Key と、まだ追加していない Secret .env 変数を使って初期化されます。

const gpio = require('onoff').Gpio;
+ const OpenTok = require('opentok');
+ const puppeteer = require('puppeteer');
+ const dotenv = require('dotenv');

const app = express();
const pir = new gpio(23, 'in', 'both');

+ dotenv.config();

+ const opentok = new OpenTok(
+   process.env.VONAGE_VIDEO_API_KEY,
+   process.env.VONAGE_VIDEO_API_SECRET,
+ );

Video APIキーとAPIシークレットが必要です。これらは Video API アカウントにログインしてください。.

次に、新規プロジェクトを作成する。プロジェクトが作成されると、APIキーとAPIシークレットを含むプロジェクトのダッシュボードが表示されます。

ファイル内に .envファイルにVonage Videoの認証情報を追加します。 <>をあなたの認証情報で更新してください):

VONAGE_VIDEO_API_KEY= VONAGE_VIDEO_API_SECRET=

Vonageビデオセッションの作成

ファイルの中で index.jsファイルで、OpenTok オブジェクトを初期化している部分を見つけて、3つの変数を追加します:

  • canCreateSessionプロジェクトがセッションを作成できるかどうかを決定します。

  • sessionは、現在のセッション・オブジェクトを保持する変数である。

  • urlはセッションの現在のURL(この場合はNgrokのURL)を保持する変数です。

const opentok = new OpenTok(
  process.env.VONAGE_VIDEO_API_KEY,
  process.env.VONAGE_VIDEO_API_SECRET,
);

+ let canCreateSession = true;
+ let session = null;
+ let url = null;

セッションを作成し、返されたセッションIDをデータベースに保存して、ユーザーがリンクをクリックして公開ストリームを表示するときに使用します。以下のコードをコピーして、これを実現する関数を追加してください:

async function createSession() {
  opentok.createSession({ mediaMode: 'routed' }, (error, session) => {
    if (error) {
      console.log(`Error creating session:${error}`);

      return null;
    }

    createSessionEntry(session.sessionId);

    return null;
  });
}

function createSessionEntry(newSessionId) {
  db.Session
    .create({
      sessionId: newSessionId,
      active: true,
    })
    .then((sessionRow) => {
      session = sessionRow;

      return sessionRow.id;
    });
}

がtrueかどうかを判断するために、プロジェクトのセッションウォッチャー部分を更新する必要があります。 canCreateSessionもしそうなら、それをfalseに設定し(このストリームがアクティブな間は、他のストリームが作成されないようにする)、プロジェクトに追加したメソッドを呼び出してセッションを作成します。 createSession.これは、以下のコードを更新することで行われる:

pir.watch(function(err, value) {
-    if (value == 1) {
+    if (value === 1 && canCreateSession === true) {
+       canCreateSession = false;
        console.log('Motion Detected!');

+       createSession();
    }
});

発行者および購読者の作成

Piがストリームを公開し、クライアント(あなた)がストリームを購読するための、フロントページを保持する新しいディレクトリが必要です。新しい publicディレクトリを作成する。 css, jsconfigディレクトリを以下のコマンドで作成する:

mkdir public mkdir public/css mkdir public/js mkdir public/config

クライアントが見るページにはスタイリングが必要なので、新しい app.cssファイルを作成し public/css/を作成し、以下のコードをこのファイルにコピーしてください。以下のCSSは、コンテンツのサイズが高さ100%であること、背景色が灰色であること、ビデオストリームがフルスクリーンであることを保証します。

body, html {
    background-color: gray;
    height: 100%;
}

#videos {
    position: relative;
    width: 100%;
    height: 100%;
    margin-left: auto;
    margin-right: auto;
}

#subscriber {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 10;
}

#publisher {
    position: absolute;
    width: 360px;
    height: 240px;
    bottom: 10px;
    left: 10px;
    z-index: 100;
    border: 3px solid white;
    border-radius: 3px;
}

次に、クライアント側で使用される新しい javascript ファイルを作成する必要があります。このファイルは、Vonage Video セッションを初期化し、GET リクエストでバックエンドからセッションの詳細を取得します。 /serveであれば、ストリームを公開します。 /clientであれば、現在アクティブな Video ストリームを購読します。で public/js/に新しい app.jsファイルを作成し、そこに以下のコードをコピーします:

let apiKey;
let sessionId;
let token;
let isPublisher = false;
let isSubscriber = false;
let url = '';

// Handling all of our errors here by alerting them
function handleError(error) {
  if (error) {
    console.log(error.message);
  }
}

function initializeSession() {
  const session = OT.initSession(apiKey, sessionId);

  // Subscribe to a newly created stream
  if (isSubscriber === true) {
    session.on('streamCreated', (event) => {
      session.subscribe(event.stream, 'subscriber', {
        insertMode: 'append',
        width: '100%',
        height: '100%',
      }, handleError);
    });
  }

  if (isPublisher === true) {
    // Create a publisher
    let publisher = OT.initPublisher('publisher', {
      insertMode: 'append',
      width: '100%',
      height: '100%',
    }, handleError);
  }

  // Connect to the session
  session.connect(token, (error) => {
    // If the connection is successful, publish to the session
    if (error) {
      handleError(error);
    } else if (isPublisher === true) {
      session.publish(publisher, handleError);
    }
  });
}

function setDetails(details) {
  apiKey = details.apiKey;
  sessionId = details.sessionId;
  token = details.token;

  initializeSession();
}

async function getDetails(publisher, subscriber, url) {
  const request = await fetch(url);
  const response = await request.json();

  if (publisher === true) {
    isPublisher = true;
  }

  if (subscriber === true) {
    isSubscriber = true;
  }

  setDetails(response);
}

function fetchUrl() {
  return fetch('/config/config.txt')
   .then( r => r.text() )
   .then( t => { url = t} );
}

この2つの新しい HTMLファイルが必要である。 /serve/clientこれらは、Vonage Video クライアント側 javascript ライブラリを使用して、現在のアクティブなセッションを公開または購読します。

新しい server.htmlファイルを作成する。 public/ディレクトリの中に新しいファイルを作成する:

<html>
<head>
    <link type="text/css" rel="stylesheet" href="/css/app.css">
    <script src="https://static.opentok.com/v2/js/opentok.min.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
    <h1>Publisher view</h1>
    <div id="videos">
        <div id="publisher"></div>
    </div>

    <script type="text/javascript" src="/js/app.js"></script>
    <script type="text/javascript">
        getDetails(true, false, 'https://localhost:3000/get-details');
    </script>
</body>
</html>

エンドポイントには /clientエンドポイント用に client.htmlファイルを public/ディレクトリ内に新しいファイルを作成し、以下のコードをコピーする:

<html>
<head>
    <link type="text/css" rel="stylesheet" href="/css/app.css">
    <script src="https://static.opentok.com/v2/js/opentok.min.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
    <h1>Subscriber view</h1>
    <div>
        <button onclick="getDetails(false, true, url + 'get-details')">Watch Video Stream</button>
    </div>
    <div id="videos">
        <div id="subscriber"></div>
    </div>


    <script type="text/javascript" src="/js/app.js"></script>
</body>
</html>

バックエンドのコード(index.js)にまだエンドポイントが定義されていません!作成したオリジナルのエンドポイントを見つけてください:

app.get('/', (req, res) => {
  res.json({ message: 'Welcome to your webserver!' });
});

これを次のコードに置き換える:

// Adds the public directory to a publicly accessible directory within our new web server
app.use(express.static(path.join(`${__dirname}/public`)));
// Creates a new endpoint `/serve` as a GET request, which provides the contents of `/public/server.html` to the users browser
app.get('/serve', (req, res) => {
  res.sendFile(path.join(`${__dirname}/public/server.html`));
});

// Creates a new endpoint `/client` as a GET request, which provides the contents of `/public/client.html` to the users browser
app.get('/client', (req, res) => {
  res.sendFile(path.join(`${__dirname}/public/client.html`));
});

// Creates a new endpoint `/get-details` as a GET request, which returns a JSON response containing the active Vonage Video session, the API Key and a generated Token for the client to access the stream with.
app.get('/get-details', (req, res) => {
  db.Session.findAll({
    limit: 1,
    where: {
      active: true,
    },
    order: [['createdAt', 'DESC']],
  }).then((entries) => res.json({
    sessionId: entries[0].sessionId,
    token: opentok.generateToken(entries[0].sessionId),
    apiKey: process.env.VONAGE_VIDEO_API_KEY,
  }));
});

上のコードを注意深く見ると、新しいライブラリ path.そのため index.jsファイルの先頭に、以下のようにパスをインクルードする:

const path = require('path');

Raspberry Piのディスプレイを公開するまで何も起こらない。

内部 .envに別の変数を追加する(60000ミリ秒は60秒に相当):

VIDEO_SESSION_DURATION=60000

内部に戻る index.js関数が呼び出されたときにストリームを閉じる機能を追加する。 closeSession()が呼び出されたときにストリームを閉じる機能を追加する:

async function closeSession(currentPage, currentBrowser) {
  console.log('Time limit expired. Closing stream');
  await currentPage.close();
  await currentBrowser.close();

  if (session !== null) {
    session.update({
      active: false
    });
  }
}

さて、次はヘッドレスモードでストリームのパブリッシングを作成する番だ。以下の関数は、すべてヘッドレスモードで以下のことを行う:

  • 新しいブラウザのインスタンスを作成します、

  • 新しいページ/タブを開きます、

  • ブラウザのカメラとマイクのパーミッションを上書きします、

  • ビデオストリームを公開する /serveエンドポイントに誘導し、Video ストリームを公開します、

  • 一定時間後にビデオストリームを停止する新しいタイマーを作成する、

  • ストリームが終了し、別のストリームが開始できるようになるまでの間にバッファを提供するために、別のタイマーを作成する。

以下のコードを index.jsファイルにコピーしてください:

async function startPublish() {
  // Create a new browser using puppeteer
  const browser = await puppeteer.launch({
    headless: true,
    executablePath: 'chromium-browser',
    ignoreHTTPSErrors: true,
    args: [
      '--ignore-certificate-errors',
      '--use-fake-ui-for-media-stream',
      '--no-user-gesture-required',
      '--autoplay-policy=no-user-gesture-required',
      '--allow-http-screen-capture',
      '--enable-experimental-web-platform-features',
      '--auto-select-desktop-capture-source=Entire screen',
    ],
  });

  // Creates a new page for the browser
  const page = await browser.newPage();

  const context = browser.defaultBrowserContext();
  await context.overridePermissions('https://localhost:3000', ['camera', 'microphone']);

  await page.goto('https://localhost:3000/serve');

  let sessionDuration = parseInt(process.env.VIDEO_SESSION_DURATION);
  let sessionExpiration = sessionDuration + 10000;

  // Closes the video session / browser instance when the predetermined time has expired
  setTimeout(closeSession, sessionDuration, page, browser);

  // Provides a buffer between the previous stream closing and when the next can start if motion is detected
  setTimeout(() => { canCreateSession = true; }, sessionExpiration);
}

今プロジェクトに入れた関数を使う時が来た。 startPublish()を追加してください:

createSessionEntry(session.sessionId);
+ startPublish();

もう少しで、コードをテストできる段階になります!新しいエンドポイントを作成し、Video のパブリッシャーまたはサブスクライバーとしてアクセスできるようにしました。次に、遠隔地にいる場合にストリームにアクセスするための URL を用意します。

ングロク

リモートでカメラのストリームに接続したい場合は、ネットワークの外で、Raspberry Piが接続している、インターネットにWebサーバーを公開する必要があります。次に Ngrok.

以下のコマンドを実行すると、Ngrokはプロジェクトのローカルにのみインストールされます:

npm install ngrok

Ngrokの使い方をプロジェクトに実装する必要がある。そこで index.jsファイルの先頭に ngrokパッケージをインクルードします:

const ngrok = require('ngrok');

次に、Ngrokに接続する関数を作成する必要があります。成功したら、返されたURLをファイルに保存します。 public/config/config.txtに保存します。 public/client.html.あなたの index.jsファイルに以下を追加してください:

async function connectNgrok() {
  let url = await ngrok.connect({
    proto: 'http',
    addr: 'https://localhost:3000',
    region: 'eu',
    // The below examples are if you have a paid subscription with Ngrok where you can specify which subdomain
    //to use and add the location of your configPath. For me, it was gregdev which results in
    //https://gregdev.eu.ngrok.io, a reserved subdomain
    // subdomain: 'gregdev',
    // configPath: '/home/pi/.ngrok2/ngrok.yml',
    onStatusChange: (status) => { console.log(`Ngrok Status Update:${status}`); },
    onLogEvent: (data) => { console.log(data); },
  });

  fs.writeFile('public/config/config.txt', url, (err) => {
    if (err) throw err;
    console.log('The file has been saved!');
  });
}

これですべての設定が完了した。 connectNgrok()関数を呼び出します:

httpServer.listen(port, (err) => {
  if (err) {
    return console.log(`Unable to start server: ${err}`);
  }

+   connectNgrok();

  return true;
});

これでストリームをテストできます。Raspberry Piのターミナルで以下を実行してください:

node index.js

約10秒後(サービスが初期化されるため)、モーションセンサーの前で手を振ってください。成功すれば Motion Detected!が出力されます。次に、Raspberry piのファイルにアクセスします。 public/config/config.txtこのURLをコピーし、ブラウザに貼り付けます。URLの末尾に /clientをURLの最後に追加してください。私の場合、これは https://gregdev.eu.ngrok.io/client.あなたのブラウザは、ヘッドレスChromiumブラウザインスタンスを開き、ローカルIPに移動したRaspberry piからの公開ストリームを表示します: https://localhost/serve.

Vonageメッセージのインストール

動きが検出されるたびにSMSメッセージを送信する新しいVonage Messages APIを使用するには、Node SDKのベータ版をインストールする必要があります。以下のコマンドを実行してください:

npm install @vonage/server-sdk

Messages APIを使用するには、Vonage Developerポータルでアプリケーションを作成し、アプリケーション作成時に生成される付属の private.keyが必要です。以下のコマンドを実行するとアプリケーションが作成され、Webhooks が設定され(今は必要ないので引用符で囲んだままにしておく)、最後にキーファイル private.key.

vonage apps:create "My Messages App" --messages-inbound-url=https://example.com/webhooks/inbound-message --messages-status-url=https://example.com/webhooks/message-status

アプリケーションを作成したので、いくつかの環境変数を設定する必要があります。環境変数には API keyAPI secretVonage Developer Dashboard.

は、前のコマンドで生成したファイルの場所である。 VONAGE_APPLICATION_PRIVATE_KEY_PATHは前のコマンドで生成したファイルの場所です。このプロジェクトではプロジェクト・ディレクトリに保存されていたので、例えば /home/pi/pi-cam/my_messages_app.key

このプロジェクトでは VONAGE_BRAND_NAMEはこのプロジェクトでは使われないが、Messages APIを使う際にはセットする必要がある。 HomeCam

最後に TO_NUMBERはSMS通知を受け取る受信者である。

VONAGE_API_KEY= VONAGE_API_SECRET= VONAGE_APPLICATION_PRIVATE_KEY_PATH= VONAGE_BRAND_NAME=HomeCam TO_NUMBER=

あなたの index.jsファイルをインポートしてください:

const Vonage = require('@vonage/server-sdk');

API リクエストに使う Vonage オブジェクトを作成するには、OpenTok オブジェクトの定義の下に以下を追加します:

const vonage = new Vonage({
  apiKey: process.env.VONAGE_API_KEY,
  apiSecret: process.env.VONAGE_API_SECRET,
  applicationId: process.env.VONAGE_APPLICATION_ID,
  privateKey: process.env.VONAGE_APPLICATION_PRIVATE_KEY_PATH,
});

関数の内部と最後に connectNgrok()関数の内部と最後に、インバウンドメッセージとメッセージステータスを正しいURL(Ngrok URL)で処理するためのWebhookでVonageアプリケーションを更新する機能を追加します:

vonage.applications.update(process.env.VONAGE_APPLICATION_ID, {
  name: process.env.VONAGE_BRAND_NAME,
  capabilities: {
    messages: {
      webhooks: {
        inbound_url: {
          address: `${url}/webhooks/inbound-message`,
          http_method: 'POST',
        },
        status_url: {
          address: `${url}/webhooks/message-status`,
          http_method: 'POST',
        },
      },
    },
  },
},
(error, result) => {
  if (error) {
    console.error(error);
  } else {
    console.log(result);
  }
});

SMSの送信

このチュートリアルで選択する通知方法は、Messages API経由で送信されるSMSです。Vonageライブラリはすでにこのプロジェクトにインストールされているので、設定する必要はない。プロジェクトの index.jsという関数を追加します。 sendSMS()この関数はURLとSMSを受け取る番号を受け取ります。そして、Messages APIを使用して、カメラが動きを検出したというSMS通知を送信します。

function sendSMS() {
  const message = {
    content: {
      type: 'text',
      text: `Motion has been detected on your camera, please view the link here: ${url}/client`,
    },
  };

  vonage.channel.send(
    { type: 'sms', number: process.env.TO_NUMBER },
    { type: 'sms', number: process.env.VONAGE_BRAND_NAME },
    message,
    (err, data) => { console.log(data.message_uuid); },
    { useBasicAuth: true },
  );
}

次に sendSMS()関数を呼び出す:

createSessionEntry(session.sessionId);
+ sendSMS();

これで完了です!あとはRaspberry PiにSSH接続して、プロジェクト・ディレクトリ内のサーバーを起動するだけです:

node index.js

これでサーバーは起動し、Raspberry Piは動きを検知する:

  • OpenTok セッションを開始します、

  • セッションIDをデータベースに保存する、

  • あらかじめ設定した電話番号に、ストリームへのリンクを記載したSMSを送信します、

  • Raspberry piからパブリッシング・ストリームを開始する。

これで、世界中どこからでもアクセスできる家庭用監視システムを短期間で構築したことになる!

このチュートリアルの完成したコードは GitHub リポジトリ.

以下は、Vonage Video APIをプロジェクトに実装するために私たちが書いた他のチュートリアルです:

コミュニティで共有したい質問、アドバイス、アイデアなどがありましたら、お気軽に私たちの コミュニティSlackワークスペース.このチュートリアルを実施した方、あなたのプロジェクトがどのように機能しているか、ぜひお返事をお待ちしています。

シェア:

https://a.storyblok.com/f/270183/250x250/b052219541/greg-holmes.png
Greg Holmesヴォネージの卒業生

元Vonage開発者エデュケーター。PHPのバックグラウンドを持つが、一つの言語に縛られることはない。熱心なゲーマーでRaspberry pi愛好家。屋内クライミング施設でボルダリングをしていることが多い。