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

Heimüberwachungssystem mit Node und einem Raspberry Pi

Zuletzt aktualisiert am May 19, 2020

Lesedauer: 40 Minuten

Haben Sie sich jemals gefragt, wie man ein Hausüberwachungssystem baut? Vielleicht, um Ihre Kinder zu überwachen, gefährdete Personen in ihrem Haus zu beaufsichtigen oder um Ihr eigenes Sicherheitssystem zu installieren? Diese Anleitung führt Sie durch den Einführungsprozess, um ein solches System zu bauen.

In diesem Tutorial bauen Sie ein kleines und günstiges Hausüberwachungssystem mit einem Raspberry Pi 4, einem Raspberry Pi Kameramodul und einem Bewegungssensor. Auf der Softwareseite wird Folgendes verwendet Vonage Video API (ehemals TokBox OpenTok) zur Veröffentlichung des Streams und Vonage Messages API um den Benutzer per SMS zu benachrichtigen, wenn eine Bewegung erkannt wird.

Hier sind einige der Dinge, die Sie in diesem Lernprogramm lernen werden:

Voraussetzungen

  • Raspberry Pi 4

  • Raspberry Pi Kameramodul

  • Bewegungssensor (HC-SR501 PIR)

  • TokBox Account

  • Node und NPM auf dem Raspberry Pi installiert

Vonage API-Konto

Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.

In diesem Lernprogramm wird auch eine virtuelle Telefonnummer verwendet. Um eine zu erwerben, gehen Sie zu Rufnummern > Rufnummern kaufen und suchen Sie nach einer Nummer, die Ihren Anforderungen entspricht.

Raspberry Pi Installation und Einrichtung

Die Raspberry Pi Foundation ist eine in Großbritannien ansässige Wohltätigkeitsorganisation, die es Menschen auf der ganzen Welt ermöglicht, technologische Probleme zu lösen und sich kreativ auszudrücken, indem sie die Leistungsfähigkeit von Computern und digitalen Technologien für ihre Arbeit nutzen.

Auf ihrer Website finden Sie eine großartige Schritt-für-Schritt-Anleitung die erklärt, was die einzelnen Teile des Raspberry Pi sind, wie man das Betriebssystem installiert und wie man mit dem Raspberry Pi anfängt. Es gibt auch viele andere Ressourcen, die Ihnen bei der Fehlerbehebung von Problemen helfen, und viele andere Projekte, die Sie interessieren könnten.

Installation von Kameras und Bewegungssensoren

Installation des Raspberry Pi Kameramoduls

In diesem Tutorial wird ein Raspberry Pi 4 und das offizielle Raspberry Pi-Kameramodul verwendet, obwohl es keine Probleme bei der Verwendung anderer Kameras geben sollte.

Das Foto unten zeigt den Raspberry Pi und ein Kameramodul, die in diesem Artikel verwendet werden:

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

Schließen Sie das Kameramodul über das Flachbandkabel an den Kameramodulanschluss des Raspberry Pi an. Das Foto unten zeigt, wo Sie das Flachbandkabel des Kameramoduls installieren sollten:

Raspberry Pi with Camera Ribbon InstalledRaspberry Pi with Camera Ribbon Installed

Aktivieren von SSH und Kamera

Sichere Shell (SSH) ist ein Softwarepaket, das eine sichere Verbindung und Kontrolle über ein entferntes System ermöglicht. Der Raspberry Pi wird in diesem Tutorial im Headless-Modus betrieben, d. h. ohne Monitor, Tastatur oder Maus. Wenn SSH aktiviert ist, können Sie von Ihrem Computer oder Telefon aus eine Fernverbindung zum Gerät herstellen.

Um SSH zu aktivieren, führen Sie im Terminal des Raspberry Pi Folgendes aus:

sudo raspi-config

Sie werden einen Bildschirm sehen, der dem unten abgebildeten ähnelt:

Raspberry Pi ConfigurationRaspberry Pi Configuration

Wählen Sie Option 5 - Interfacing Options

  • Wählen Sie im nächsten Menü die Option P1 für Cameraund wählen Sie dann Yes,

  • Wählen Sie anschließend Option P2 für SSH, wählen Sie erneut Yes.

Sie haben nun das Kameramodul und SSH auf Ihrem Raspberry Pi aktiviert.

Installieren des Bewegungssensors

Der nächste Schritt besteht darin, den Raspberry Pi mit einem Bewegungssensor zu verbinden. In diesem Tutorial wird der HC-SR501 PIR-Bewegungssensor verwendet, aber auch andere Bewegungssensormodule sollten problemlos funktionieren. Bitte beachten Sie die entsprechenden Anleitungen für die Verkabelung mit Ihrem Raspberry Pi.

Nehmen Sie zunächst den Sensor und schließen Sie drei Drähte daran an. Ich habe rot für die Spannung, blau für den GPIO und schwarz für die Masse verwendet. Für den Sensor in diesem Beispiel ist der erste Pin Masse, der zweite GPIO und der dritte live, wie gezeigt:

Example of Motion SensorExample of Motion Sensor

Ein gutes Beispiel für die Beschreibung der einzelnen Pins des Raspberry Pi finden Sie auf Die Raspberry Pi Website. Das Diagramm veranschaulicht die Anordnung der GPIO-Pins, wie unten dargestellt:

Diagram of Raspberry Pi GPIO PinsDiagram of Raspberry Pi GPIO Pins

Der letzte Teil ist der Anschluss der Drähte an den Raspberry Pi. Das stromführende (rote) Kabel muss mit einem der Pins des Pi verbunden werden. 5V power Pin des Pi angeschlossen werden, im obigen Diagramm habe ich Pin 2 verwendet. Das Erdungskabel (schwarz) muss mit einem der Pins des Pi verbunden werden. GND Pins des Pi verbunden werden, wie im Diagramm dargestellt, habe ich Pin 6 verwendet. Das letzte zu verbindende Kabel ist das GPIO-Kabel (blau), das an einen der GPIO Pins. In diesem Beispiel habe ich Pin 12 verwendet, der mit "GPIO 18" bezeichnet ist.

Die endgültige Verkabelung ist unten dargestellt:

Sensor Writing Part 2Sensor Writing Part 2

Testen der Bewegungserkennung

Jetzt ist die gesamte Hardware installiert und konfiguriert, und es ist an der Zeit, den Code für das Projekt zu erstellen. Zunächst muss jedoch ein Node-Projekt erstellt werden, um die Bewegungserkennung zu testen und sich auf das Projekt vorzubereiten. In diesem Projekt werden Sie den gesamten Code für die Bewegungserkennung und das Video-Streaming schreiben. Um ein neues Node-Projekt zu erstellen, legen Sie ein neues Verzeichnis an, wechseln Sie in dieses Verzeichnis und führen Sie npm init. Mit den unten aufgeführten Befehlen führen Sie alle drei Schritte aus:

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

Folgen Sie den Anweisungen, legen Sie einen Namen für das Projekt fest und belassen Sie die restlichen Eingaben als Standard.

Die folgenden Befehle erstellen ein neues index.jsan, in dem der Großteil des Codes gespeichert wird, und installieren ein neues Paket namens onoff das die Steuerung der GPIO-Pins ermöglicht:

touch index.js npm install onoff

Kopieren Sie in Ihre neue index.js Datei kopieren Sie den folgenden Code, der den GPIO-Pin 18 ausliest, um zu alarmieren, wenn eine Bewegung erkannt wurde, oder um zu alarmieren, wenn die Bewegung gestoppt wurde.

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');
    }
});

Zeit zu prüfen, ob der obige Code und die Installation des Weg- und/oder Geschwindigkeitsgebers erfolgreich waren. Ausführen:

node index.js

Winken Sie mit der Hand vor dem Bewegungssensor und beobachten Sie das Terminal, um zu sehen, dass "Motion Detected!" ausgegeben wird. Einige Sekunden später sehen Sie die Ausgabe "Bewegung gestoppt".

Testen der Kamera

Geben Sie in der Befehlszeile Ihres Raspberry Pi den folgenden Befehl ein, um ein Standfoto der Kameraansicht aufzunehmen.

HINWEIS Wenn Sie sich als ein anderer als der Standardbenutzer angemeldet haben piersetzen Sie pi durch Ihren Benutzernamen.

raspistill -o /home/pi/cam.jpg

Wenn Sie im Verzeichnis /home/pi/ sehen Sie jetzt cam.jpg. Wenn Sie es öffnen, sehen Sie ein Foto der aktuellen Kameraansicht Ihres Raspberry Pi.

Knotenpunkt und NPM

node --version npm --version

Sowohl Node als auch NPM müssen installiert sein und die richtige Version haben. Gehen Sie zu nodejs.orgund laden Sie die richtige Version herunter und installieren Sie sie, falls Sie sie noch nicht haben.

Unser CLI

Richten Sie Ihr Vonage CLI mithilfe diese Anleitung. Sie benötigen nur die Installation und Einrichten Ihrer Konfiguration Schritt.

Git (optional)

Sie können git verwenden, um die Demo-Anwendung von GitHub klonen.

Für diejenigen, die sich mit Git-Befehlen nicht auskennen, habe ich eine Lösung parat.

Folgen Sie dieser Anleitung zur Installation von Git.

Einen Mysql-Server installieren

Führen Sie auf dem Raspberry Pi den folgenden Befehl aus, um den MySQL-Datenbankserver zu installieren:

sudo apt install mariadb-server

Standardmäßig wird der MySQL-Server mit dem Benutzer root Benutzer kein Passwort hat. Sie müssen dies korrigieren, um sicherzustellen, dass die Datenbank nicht unsicher ist. Führen Sie auf dem Pi den folgenden Befehl aus und folgen Sie den Anweisungen.

sudo mysql_secure_installation

Nachdem das root Passwort des Benutzers festgelegt ist, ist es an der Zeit, eine Datenbank und einen Benutzer für den Zugriff auf diese Datenbank zu erstellen. Verbinden Sie sich mit dem MySQL-Server:

sudo mysql -u root -p

Führen Sie nun die folgenden SQL-Abfragen aus, um einen neuen Benutzer zu erstellen und diesem Benutzer einige Rechte für eine neue Datenbank zu gewähren:

-- 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;

Ihr Raspberry Pi ist nun eingerichtet und bereit für den Code-Teil des Tutorials.

Erstellung der Anwendung

Installieren eines SSL-Zertifikats

Wechseln Sie im Terminal Ihres Raspberry Pi in das Verzeichnis mit Ihrem Projektpfad und führen Sie den folgenden Befehl aus, um ein selbstsigniertes SSL-Zertifikat zu generieren. Vonage Video API erfordert HTTPS für den Zugriff, daher ist ein SSL-Zertifikat erforderlich, auch wenn es selbstsigniert ist. Führen Sie den folgenden Befehl aus, um Ihre SSL-Zertifikate zu generieren.

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

Es werden zwei Dateien erstellt, key.pem und cert.pemVerschieben Sie diese an einen Ort, auf den Ihr Code zugreifen kann. In diesem Tutorial befinden sie sich im Projektverzeichnis.

Der Webserver

Express ist ein minimalistisches und flexibles Node.js-Framework für Webanwendungen, das eine Reihe von robusten Funktionen für Web- und mobile Anwendungen bietet.

Express ist ein sehr leichtgewichtiges, flexibles Node.js-Framework, das Sie für dieses Projekt benötigen. Zur Bereitstellung von Endpunkten für den Zugriff auf Ihren Video-Stream.

Installieren Sie Express mit dem folgenden Befehl in Ihrer Anwendung:

npm install express --save

Am Anfang der Datei index.js Datei müssen Sie die Pakete https, fs und express. Nehmen Sie die folgenden Änderungen vor:

+ 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');
    }
});

Sie brauchen den else Teil der Bewegungserkennung für dieses Lernprogramm nicht. Entfernen Sie also auch diesen Teil, wie oben gezeigt.

Sie benötigen einen Webserver, um über das Netzwerk oder das Internet auf Ihren Video-Stream zuzugreifen. Es ist an der Zeit, eine Methode zu erstellen, um einen neuen Server mit einem Beispiel-Endpunkt zu initiieren. Oben pir.watch(function(err, value) { hinzufügen

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;
  });
}

Es wird nun eine Möglichkeit benötigt, auf diese Funktion zuzugreifen, und zwar unterhalb der Funktion startServer() {} einen Aufruf der Funktion wie gezeigt einfügen:

startServer();

Um zu testen, ob dies funktioniert, führen Sie in Ihrem Terminal aus:

node index.js

Anmerkung: Wenn Sie mit Ihrem Raspberry Pi über SSH oder Tastatur/TV verbunden sind, geben Sie im Terminal: ifconfig ein, um die lokale IP-Adresse Ihres Raspberry Pi herauszufinden.

Wenn Sie die IP-Adresse Ihres Raspberry Pi in Ihrem Browser aufrufen: https://<ip address>:3000/ wird zurückgegeben

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

Installieren von Sequelize

Sequelize ist eine leistungsstarke Bibliothek für Node, die das Abfragen einer Datenbank erleichtert. Es ist ein Object-Relational Mapper (ORM), der Objekte auf die Datenbankschemata abbildet. Sequelize deckt verschiedene Protokolle wie Postgres, MySQL, MariaDB, SQLite und Microsoft SQL Server ab. In diesem Tutorial wird MariaDB Server verwendet, da dies der SQL Server ist, der auf dem Raspberry Pi verfügbar ist.

# 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

Erstellen Sie in Ihrem Projektverzeichnis eine neue Datei .envund aktualisieren Sie die nachstehenden Werte mit den korrekten Anmeldeinformationen für Ihre Datenbank.

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

Innerhalb des Verzeichnisses config Verzeichnis wird eine neue Datei mit dem Namen config.js. In dieser Datei werden die Datenbankeinstellungen des Projekts gespeichert, und da es sich um Javascript handelt, kann es auf die .env Datei zugreifen:

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
  },
}

Jetzt in models/index.jssuchen und ersetzen:

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

Zurück in Ihrer Haupt index.js Datei, importieren Sie die models/index.js Datei für Ihre Anwendung, um auf Ihre Datenbankmodelle zuzugreifen:

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

Erzeugen und Ausführen einer Migration

Wenn eine Vonage Video-Sitzung erstellt wird, wird eine Sitzungs-ID zurückgegeben. Diese Sitzungs-ID muss irgendwo gespeichert werden, damit Sie sich aus der Ferne mit ihr verbinden können. Dies geschieht am besten in einer Datenbanktabelle. Führen Sie mit der kürzlich installierten Sequelize CLI den folgenden Befehl aus. Es wird eine neue Tabelle mit dem Namen Session erstellt, die zwei neue Spalten enthält:

  • sessionId (eine Zeichenkette),

  • aktiv (ein boolescher Wert).

# 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

Nach erfolgreicher Ausführung dieses Befehls werden zwei neue Dateien erstellt, und zwar:

  • models/session.js

  • migrations/<timestamp>-Session.js

Das neue Modell, session.jsdefiniert, was die Datenbank in Bezug auf Spaltennamen, Datentypen und andere Dinge erwartet.

Die neue Migrationsdatei legt fest, was nach erfolgreicher Migration in die Datenbank übernommen werden soll. In diesem Fall erstellt sie eine neue Datenbanktabelle namens sessions mit fünf neuen Spalten:

  • id

  • sessionId

  • aktiv

  • createdAt

  • updatedAt

Führen Sie diese Migration mit dem Sequelize CLI-Befehl mit den Parametern db:migrate:

sequelize db:migrate

Die Ausgabe ist dieselbe wie im folgenden Beispiel:

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

Sie haben nun eine neue Datenbanktabelle, die Sie später zum Speichern der Sitzungs-ID verwenden werden.

Vonage Video

Sie sind dabei, zwei Bibliotheken zu installieren, die das Projekt benötigt: Vonage Video (früher TokBox OpenTok) und Puppeteer.

Vonage Video (ehemals TokBox OpenTok) ist ein Dienst, der interaktive Live-Videositzungen für Menschen auf der ganzen Welt anbietet. Die Vonage Video API (ehemals TokBox OpenTok) nutzt den WebRTC-Industriestandard. Sie ermöglicht es Menschen, individuelle Videoerlebnisse auf Milliarden von Geräten zu schaffen, egal ob es sich um Mobil-, Web- oder Desktop-Anwendungen handelt.

Puppeteer ist eine Node-Bibliothek, die eine Methode zur programmatischen Steuerung von Chrome oder Chromium bietet. Standardmäßig läuft Puppeteer in einem Headless-Modus, kann aber auch in einem Nicht-Headless-Modus von Chrome oder Chromium laufen. Ein Headless-Browser ist ein Browser ohne grafische Benutzeroberfläche (z. B. ohne Monitor, den der Benutzer sehen kann).

Installieren Sie diese beiden Bibliotheken, indem Sie den folgenden Befehl ausführen:

npm install opentok puppeteer

Kopieren Sie die Ergänzungen zu dem Code in Ihrem index.js wie unten gezeigt. Dieser Code importiert drei Bibliotheken in Ihr Projekt.

  • OpenTok (zum Veröffentlichen/Abonnieren von Videostreams mit Vonage Video)

  • Puppeteer (Für Ihren Raspberry Pi, um einen Browser im Headless-Modus zu öffnen und den Stream zu veröffentlichen)

  • DotEnv (Für den Zugriff auf die .env-Variablen)

Ein OpenTok-Objekt wird mit Ihrem Vonage-API-Schlüssel und geheimen .env-Variablen initialisiert, die Sie noch hinzufügen müssen.

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,
+ );

Sie benötigen Ihren Vonage Video API-Schlüssel und Ihr API-Geheimnis. Sie finden diese, indem Sie sich bei Ihrem Vonage Video Video API Account.

Als nächstes erstellen Sie ein neues Projekt. Sobald es erstellt ist, sehen Sie das Dashboard Ihres Projekts, das den API-Schlüssel und das API-Geheimnis enthält.

Innerhalb Ihrer .env Datei fügen Sie die Vonage Video-Anmeldedaten wie folgt hinzu (Aktualisierung der Werte in < und > mit Ihren Anmeldedaten):

VONAGE_VIDEO_API_KEY= VONAGE_VIDEO_API_SECRET=

Erstellen einer Vonage Video-Sitzung

In Ihrer index.js Datei finden Sie den Teil des Codes, der das OpenTok-Objekt initialisiert, und fügen Sie drei Variablen namens:

  • canCreateSessionlegt fest, ob Ihr Projekt eine Sitzung erstellen kann oder nicht (wenn bereits eine Sitzung aktiv ist)

  • sessionist die Variable, die das aktuelle Sitzungsobjekt enthält

  • url ist die Variable, die die aktuelle URL der Sitzung enthält (in diesem Fall eine 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;

Es ist an der Zeit, eine Sitzung zu erstellen und die zurückgegebene Sitzungs-ID in der Datenbank zu speichern, damit sie verwendet werden kann, wenn der Benutzer auf den Link klickt, um den veröffentlichten Stream anzuzeigen. Kopieren Sie den nachstehenden Code, um die Funktionen hinzuzufügen, die dies ermöglichen:

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;
    });
}

Der Session Watcher-Teil des Projekts muss aktualisiert werden, um festzustellen, ob canCreateSession wahr ist. Wenn dies der Fall ist, setzen Sie es auf false (damit keine anderen Streams erstellt werden, während dieser aktiv ist), dann erstellen Sie die Sitzung, indem Sie die zuvor zum Projekt hinzugefügte Methode createSession. Dies geschieht durch Aktualisierung des folgenden Codes:

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

+       createSession();
    }
});

Erstellen eines Verlegers und Abonnenten

Es wird ein neues Verzeichnis benötigt, das die Vorderseiten für den Pi enthält, um seinen Stream zu veröffentlichen, und für den Client (Sie), um einen Stream zu abonnieren. Erstellen Sie ein neues public Verzeichnis mit dem zugehörigen css, js, und config Verzeichnissen mit den folgenden Befehlen:

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

Sie werden ein gewisses Styling für Ihre Seite brauchen, das der Kunde sieht, also erstellen Sie eine neue app.css Datei innerhalb von public/css/ und kopieren Sie den unten stehenden Code in diese Datei. Das unten stehende CSS sorgt dafür, dass die Größe des Inhalts 100 % beträgt, die Hintergrundfarbe grau ist und der Videostream für maximale Sichtbarkeit im Vollbildmodus angezeigt wird.

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;
}

Als nächstes müssen Sie eine neue Javascript-Datei erstellen, die auf der Client-Seite (also in Ihrem Browser als Teilnehmer) verwendet wird. Diese Datei initialisiert eine Vonage Video Sitzung, holt die Sitzungsdetails vom Backend mit einer GET Anfrage und wenn die Route /serve ist, wird sie den Stream veröffentlichen, wenn der URL-Pfad /client lautet, abonniert sie den aktuell aktiven Video-Stream. Unter public/js/ erstellen Sie eine neue app.js Datei und kopieren Sie den folgenden Code hinein:

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} );
}

Zwei neue HTML Dateien werden für diese beiden neuen Endpunkte benötigt /serve und /clientDiese nutzen die clientseitige Javascript-Bibliothek von Vonage Video, um aktive Sitzungen zu veröffentlichen oder zu abonnieren.

Erstellen Sie eine neue server.html Datei innerhalb des Verzeichnisses public/ Verzeichnis eine neue Datei mit folgendem Inhalt:

<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>

Für den /client Endpunkt, erstellen Sie eine neue client.html Datei innerhalb des Verzeichnisses public/ Verzeichnis und kopieren Sie den folgenden Code:

<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>

Sie haben die Endpunkte noch nicht in Ihrem Backend-Code definiert (index.js), also wird es Zeit, diese zu erstellen! Suchen Sie den ursprünglichen Endpunkt, den Sie erstellt haben:

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

Ersetzen Sie ihn durch den folgenden Code:

// 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,
  }));
});

Wenn Sie im obigen Code genau hinsehen, verwenden Sie eine neue Bibliothek namens path. Deshalb muss am Anfang der index.js Datei den Pfad wie unten gezeigt ein:

const path = require('path');

Es passiert nichts, bis Sie die Anzeige auf dem Raspberry Pi veröffentlichen.

Innerhalb von .env eine weitere Variable einfügen (60000 Millisekunden entsprechen 60 Sekunden):

VIDEO_SESSION_DURATION=60000

Zurück im Inneren index.js Funktionalität hinzufügen, die den Stream schließt, wenn die Funktion closeSession() aufgerufen wird:

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
    });
  }
}

Jetzt ist es an der Zeit, die Veröffentlichung des Streams im Headless-Modus zu erstellen. Die folgende Funktion führt alle folgenden Schritte im Headless-Modus aus:

  • Erzeugt eine neue Browser-Instanz,

  • Öffnet eine neue Seite/Registerkarte,

  • Setzt die Berechtigungen für die Kamera und das Mikrofon im Browser außer Kraft,

  • Leitet die Seite an den /serve Endpunkt zur Veröffentlichung des Video-Streams,

  • Erstellt einen neuen Timer, der den Video-Stream nach einer bestimmten Zeitspanne stoppt,

  • Erzeugt einen weiteren Timer, um einen Puffer zwischen dem Ende des Streams und dem Beginn eines weiteren zu schaffen

Kopieren Sie den folgenden Code in Ihre index.js Datei:

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);
}

Es ist an der Zeit, die Funktion zu nutzen, die Sie gerade in Ihr Projekt eingefügt haben. startPublish() zu Ihrem Code hinzu:

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

Sie sind fast so weit, dass Sie Ihren Code testen können! Sie haben neue Endpunkte erstellt, die entweder als Herausgeber oder als Abonnent des Videos zugänglich sind. Als Nächstes benötigen Sie eine URL für den Zugriff auf den Stream, wenn Sie sich an einem anderen Ort befinden.

Ngrok

Wenn Sie sich außerhalb des Netzwerks, mit dem der Raspberry Pi verbunden ist, mit dem Kamera-Stream verbinden möchten, müssen Sie Ihren Webserver mit dem Internet verbinden. Es ist an der Zeit, Folgendes zu installieren und zu verwenden Ngrok.

Wenn Sie den folgenden Befehl ausführen, wird Ngrok nur lokal für das Projekt installiert:

npm install ngrok

Sie müssen nun die Verwendung von Ngrok in Ihr Projekt implementieren. Also am Anfang der index.js Datei fügen Sie das ngrok Paket ein:

const ngrok = require('ngrok');

Nun müssen Sie eine Funktion erstellen, die eine Verbindung zu Ngrok herstellt. Wenn sie erfolgreich ist, speichert sie die zurückgegebene URL in einer Datei public/config/config.txt die in der in den vorherigen Schritten erstellten Datei abgerufen wird public/client.html. In Ihrer index.js Datei fügen Sie Folgendes hinzu:

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!');
  });
}

Nachdem dies alles konfiguriert wurde, können Sie Ngrok aufrufen, indem Sie die connectNgrok() Funktion wie unten gezeigt:

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

+   connectNgrok();

  return true;
});

Jetzt können Sie Ihren Stream testen. Führen Sie den folgenden Befehl im Raspberry Pi Terminal aus:

node index.js

Winken Sie nach etwa 10 Sekunden (damit sich der Dienst initialisieren kann) mit der Hand vor dem Bewegungssensor. Wenn Sie erfolgreich waren, sehen Sie eine Motion Detected! Ausgabe in Ihrem Terminalfenster. Gehen Sie nun zu der Datei auf Ihrem Raspberry pi public/config/config.txt, kopieren Sie diese URL und fügen Sie sie in Ihren Browser ein. Fügen Sie /client an das Ende der URL an. Bei mir war das https://gregdev.eu.ngrok.io/client. Ihr Browser zeigt nun den veröffentlichten Stream von Ihrem Raspberry Pi an, der eine Chromium-Browser-Instanz ohne Kopf geöffnet und zu seiner lokalen IP navigiert hat: https://localhost/serve.

Installieren von Vonage-Nachrichten

Um die neue Vonage Messages API zu nutzen, die SMS-Nachrichten sendet, sobald eine Bewegung erkannt wird, müssen Sie die Beta-Version unseres Node SDK installieren. Führen Sie den folgenden Befehl aus:

npm install @vonage/server-sdk

Für die Messages API müssen Sie eine Applikation auf dem Vonage Developer Portal erstellen und eine zugehörige a private.key die beim Erstellen der Anwendung generiert wird. Wenn Sie den folgenden Befehl ausführen, wird die Anwendung erstellt, die Webhooks werden festgelegt (die im Moment nicht erforderlich sind, also lassen Sie sie in Anführungszeichen) und schließlich wird eine Schlüsseldatei namens 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

Nachdem Sie nun die Anwendung erstellt haben, müssen Sie einige Umgebungsvariablen setzen. Sie finden Ihre API key und API secret auf dem Vonage Entwickler Dashboard.

Die VONAGE_APPLICATION_PRIVATE_KEY_PATH ist der Speicherort der Datei, die Sie mit dem vorherigen Befehl erzeugt haben. Bei diesem Projekt wurde sie im Projektverzeichnis gespeichert, also zum Beispiel: /home/pi/pi-cam/my_messages_app.key

Die VONAGE_BRAND_NAME wird in diesem Projekt nicht verwendet, aber für die Messages API ist es erforderlich, eine zu haben, ich habe es einfach gehalten HomeCam

Schließlich ist der TO_NUMBER ist der Empfänger, der die SMS-Benachrichtigung erhält.

VONAGE_API_KEY= VONAGE_API_SECRET= VONAGE_APPLICATION_PRIVATE_KEY_PATH= VONAGE_BRAND_NAME=HomeCam TO_NUMBER=

Am Anfang Ihrer index.js Datei importieren Sie das Vonage-Paket:

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

Um das Vonage-Objekt zu erstellen, das für die API-Anfragen verwendet wird, fügen Sie unter der Definition des OpenTok-Objekts Folgendes hinzu:

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,
});

Fügen Sie innerhalb und am Ende Ihrer connectNgrok() Funktion fügen Sie eine Funktionalität hinzu, die Ihre Vonage-Anwendung mit Webhooks aktualisiert, um eingehende Nachrichten und den Nachrichtenstatus mit der richtigen URL (der Ngrok-URL) zu verarbeiten:

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);
  }
});

Versenden einer SMS

Die Benachrichtigungsmethode der Wahl für dieses Tutorial ist SMS, die über die Messages API gesendet wird. Die Vonage-Bibliothek wurde bereits in diesem Projekt installiert, so dass sie nicht konfiguriert werden muss. In der Datei index.js Datei fügen Sie eine neue Funktion namens sendSMS()Diese nimmt die URL und die Nummer an, unter der die SMS empfangen werden soll. Anschließend sendet sie über die Messages API eine SMS-Benachrichtigung, dass die Kamera eine Bewegung erkannt hat.

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 },
  );
}

Rufen Sie nun die sendSMS() Funktion durch Hinzufügen auf:

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

Das war's dann auch schon! Alles, was Sie jetzt noch tun müssen, ist, sich per SSH in Ihren Raspberry Pi einzuwählen und den Server in Ihrem Projektverzeichnis zu starten:

node index.js

Ihr Server läuft jetzt, und Ihr Raspberry Pi soll Bewegungen erkennen, was er dann wie folgt tun wird:

  • Starten Sie eine OpenTok-Sitzung,

  • Speichern Sie die Sitzungs-ID in der Datenbank,

  • Senden Sie eine SMS mit einem Link zum Stream an eine von Ihnen festgelegte Telefonnummer,

  • Starten Sie einen Veröffentlichungsstrom vom Raspberry Pi.

Sie haben sich nun in kurzer Zeit ein Hausüberwachungssystem aufgebaut, auf das Sie überall auf der Welt zugreifen können!

Den fertigen Code für dieses Tutorial finden Sie im GitHub-Repository.

Im Folgenden finden Sie einige weitere Tutorials, die wir zur Implementierung der Vonage Video API in Projekte geschrieben haben:

Vergessen Sie nicht, wenn Sie Fragen, Ratschläge oder Ideen haben, die Sie mit der Community teilen möchten, dann können Sie sich gerne in unserem Slack-Arbeitsbereich der Gemeinschaft. Ich würde mich freuen, von allen zu hören, die dieses Tutorial umgesetzt haben und wie ihr Projekt funktioniert.

Teilen Sie:

https://a.storyblok.com/f/270183/250x250/b052219541/greg-holmes.png
Greg HolmesVonage Ehemalige

Ehemaliger Ausbilder für Entwickler @Vonage. Kommt von einem PHP-Hintergrund, ist aber nicht auf eine Sprache beschränkt. Ein begeisterter Gamer und Raspberry-Pi-Enthusiast. Oft beim Bouldern in Kletterhallen anzutreffen.