Tutorial: Erstellen Sie Ihr eigenes Smart TV mit RaspberryPi, NodeJS und Socket.io

Codementor Donald Derek ist Konferenzredner, Open-Source-Befürworter, Macher und Aktivist. Er organisiert, moderiert und betreut Startup-Events und hat auch persönlich mehrere Auszeichnungen für seine Projekte gewonnen, darunter n!mpein SoundCloud + Jamendo Music-Player mit einer mobilen Web-Remote-App und wegbringen, ein Tamagotchi-Spiel, das auf Ihren Foursquare-Checkins basiert. Derzeit ist er wissenschaftlicher Mitarbeiter am MIT Medienlabor – Reaktionsschnelle Umgebungen.

Donald hat auch die erstellt RaspberryPi-TV, in dem er uns ein Tutorial mitteilt, wie Sie damit Ihr eigenes Google TV erstellen können. Dieser Artikel wurde ursprünglich veröffentlicht in seinem Blog.


Hardware:

Software-Stack:

  • Raspbian – ein Fork von Debian, der für den Raspberry Pi entwickelt wurde
  • Node.js
    • Socket.io – um die Verbindung zwischen unserer Fernbedienung und unserem Fernseher über Websockets zu handhaben
    • Äußern – um einige grundlegende HTTP-Anfragen zu verarbeiten
    • Omxcontrol – ein einfaches Modul zur Steuerung des OMXPlayers, der der beste Videoplayer auf dem rPi ist
  • Chrom Browser
  • OMXPlayer
  • Youtube-dl – ein Skript, mit dem Sie YouTube-Videos herunterladen können
  • Quo.js – um Wischgesten in der mobilen Web-App zu verarbeiten
  • HTML5, CSS3-Übergänge, Javascript und Schnurrbart als Template-Engine
  • Youtube-API

Das Endergebnis

Raspberry Pi TV mit seiner speziellen Fernbedienung

Umriss

  • Installieren von Software und Paketen.
  • Einfacher Shellcode
  • Serverseitiges Scripting: Node.js, Express.js und Socket.io
  • Clientseitiges Scripting: Dashboard und mobile Remote-App

1. Installieren von Software und Paketen

Installation von Raspbian und Node.js

Folge dies Lernprogramm um Raspbian und Node.js auf Ihrem Raspberry Pi zu installieren

Chromium-Browser und Youtube-dl installieren

Bauen Sie ab Quelle oder verwenden Sie apt-get

sudo apt-get install chromium-browser

Für eine bessere Darstellung können Sie auch MC-Core-Fonts installieren

sudo apt-get install ttf-mscorefonts-installer

Installieren und aktualisieren Sie das Youtube-dl-Skript

sudo apt-get install youtube-dl 

sudo youtube-dl -U

Chromium auf dem RaspberryPi ist im Moment nicht hardwarebeschleunigt, daher ist das Streamen von Videos in den Browser eine schlechte Idee. Youtube-dl ist eine schnelle Alternative, das Video wird stattdessen im OMX-Player heruntergeladen und/oder gestreamt, der auf dem rPi hardwarebeschleunigt ist!

OMX-Player ist standardmäßig Raspbian OS installiert.

2. Grundlegender Shellcode

Wenn Sie sich über SSH mit Ihrem rPi verbinden, müssen Sie Ihre DISPLAY-Umgebungsvariablen aktualisieren, indem Sie sie ausgeben

export DISPLAY=:0.0

Die grafische Ausgabe dieser Sitzung zeigt nun auf das erste mit dem rPi verbundene Display. So überprüfen Sie alle Ihre Umgebungsvariablen:

env

Testen Sie Chromium im Kiosk-Modus:

chromium --kiosk 

Testen Sie Youtube-dl

youtube-dl youtube_video_url

Ich habe dem Youtube-dl-Befehl einige Argumente hinzugefügt

  • Der Standardname der heruntergeladenen Datei wurde geändert in: -o youtube ID [dot] Dateierweiterung
  • 720p-Modus erzwingen: -f /22/18
  • Sehen Sie sich die vollständige Liste der unterstützten YouTube-Formate an hier
youtube-dl -o "%(id)s.%(ext)s" -f /22/18 youtube_video_url

Versuchen Sie nach dem Herunterladen des Videos, es mit dem OMX-Player abzuspielen

omxplayer youtube_video_file

Viel Spaß beim Erkunden der Tastaturkürzel! Weitere Verknüpfungen können gefunden werden hier oder über das Hilfemenü im OMX-Player.

Schick! Lassen Sie uns diesen Prozess mit Node.js automatisieren

3. Serverseitiges Scripting: Node.js, Express.js und Socket.io

Der Quellcode soll für den Workshop einfach sein. Hier ist die Projektdateihierarchie:

  • Öffentlichkeit
    • js
    • css
    • Bilder
    • Schriftarten
    • index.html
    • entfernt.html
  • app.js
  • Paket.json

Paket.json – Eine JSON-Datei, die von npm benötigt wird, um Abhängigkeiten automatisch zu installieren und andere Metadaten zu Ihrem Projekt zu speichern.

{
    "name": "RasPi.TV",
    "version": "0.0.1",
    "private": false,
    "scripts": {
        "start": "node app.js"
    },
    "dependencies": {
    "express": "3.1.1",
    "socket.io":"0.9.14",
    "omxcontrol":"*"
    }
}

Geben Sie in Ihrem Terminal den folgenden Befehl ein, um die Abhängigkeiten zu installieren:

npm install

Beachten Sie, dass ein Ordner namens _ node_modules _ wird in Ihrem Projektverzeichnis erstellt, wenn Sie gerne Git verwenden, vergessen Sie nicht, eine zu erstellen .gitignorieren Datei und schreibe einfach hinein „ node_modules “, ignoriert dies, dass der Ordner node_modules zu Ihrem Git-Projekt hinzugefügt wird

Erstellen Sie die Datei app.js und beginnen Sie mit der Erstellung unseres grundlegenden HTTP-Servers mit Express.js (v3.xx).

var express = require('express')
  , app = express()  
  , server = require('http').createServer(app)
  , path = require('path')


app.set('port', process.env.TEST_PORT || 8080);
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(path.join(__dirname, 'public')));


app.get('/', function (req, res) {
  res.sendfile(__dirname + '/public/index.html');
});

app.get('/remote', function (req, res) {
  res.sendfile(__dirname + '/public/remote.html');
});

server.listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

Dies ist eine grundlegende Express-HTTP-Serverkonfiguration. Um es auszuprobieren, müssen zuerst statische Dateien erstellt werden: index.html und remote.html im öffentlichen Verzeichnis. Schreiben Sie Ihre bevorzugten „Hello, World“-Nachrichten in diese Seiten, gehen Sie dann zurück zu Ihrem Terminal und führen Sie sie aus

node app.js

oder

npm start

Funktioniert nur, wenn Sie das folgende Snippet zu Ihrer Datei „package.json“ hinzugefügt haben

...
"scripts": {
        "start": "node app.js"
    },
...

Bei Server-Init erhalten Sie dies auf Ihrer Standardausgabe Express-Server, der Port 8080 überwacht
Um Ihre statischen Seiten zu testen, führen Sie diese Anwendung im Hintergrund aus, indem Sie hinzufügen &.

node app.js &

Nun, dies ist die primitivste Art, eine Node.js-App im Hintergrund zu starten, während Sie Node.js lernen, könnten Sie auf einige Module stoßen, die Prozesse für Sie daemonisieren können, genau wie PM2

Jetzt haben wir einen einfachen Node.js-Webserver, der statische Dateien bereitstellen kann. Lassen Sie uns Chromium im –kiosk-Modus öffnen und die Seiten testen.

chromium --kiosk 

Integration von Socket.io

Als AJAX zum ersten Mal auftauchte, spürten Old-School-Entwickler seine Magie, aber sie sind auf viele Probleme gestoßen, weil verschiedene Browser asynchrone Javascript- und XML-Anforderungen verarbeiten. jQuery kam mit der Lösung und stellte eine minimale und plattformübergreifende Abstraktion für XHR bereit. Socket.io macht dasselbe, aber für Web-Sockets und kann auf andere bidirektionale Web-Protokolle zurückgreifen, wenn der Browser des Clients noch keine Web-Sockets unterstützt.

Um Echtzeit-Konnektivität auf jedem Browser bereitzustellen, wählt Socket.io zur Laufzeit den leistungsfähigsten Transport aus, ohne die API zu beeinträchtigen. Natürlich werden einige der folgenden Technologien sowohl Ihr Netzwerk als auch Ihren Server beeinträchtigen, insbesondere das Adobe® Flash® Socket-Fallback, es sollte wirklich deaktiviert oder veraltet sein.

  1. WebSocket
  2. Adobe® Flash®-Socket
  3. AJAX lange Abfrage
  4. AJAX Multipart-Streaming
  5. Für immer Iframe
  6. JSONP-Abfrage

Um Socket.io zu integrieren, fügen wir Folgendes hinzu app.js Datei:

var express = require('express')
  , app = express()  
  , server = require('http').createServer(app)
  , path = require('path')
  , io = require('socket.io').listen(server)
  , spawn = require('child_process').spawn

und um die Protokolle zu minimieren, fügen Sie Folgendes hinzu:

//Socket.io Config
io.set('log level', 1);

Denken Sie bei der Entwicklung mit socket.io immer an eine einfache Chat-Anwendung. Ich habe eine einfache Chat-Web-App hinzugefügt, die mit Node.js und Socket.io erstellt wurde ein Github-Repo für dieses Tutorial!

Unser Socket.io-Server ist bereit, aber er tut noch nichts. Als nächstes implementieren wir, wie wir Nachrichten und Ereignisse verarbeiten, die vom Client an den Server gesendet werden.

Serverseitige Socket.io-Integration unten:

io.sockets.on('connection', function (socket) {
    socket.emit('message', { message: 'welcome to the chat' });
    socket.on('send', function (data) {
        
        io.sockets.emit('message', data);
    });
});

Jetzt sendet unser Server die Nachricht „message“, wenn ein neuer Client verbunden wird, und wartet auf einen Ereignisnamen „send“, um die Daten zu verarbeiten und an alle verbundenen Clients zurückzusenden

In unserem Fall haben wir zwei Arten von Clients: Das rPi-Display (das Fernsehgerät) und die mobile Web-App (die Fernbedienung).

var ss;

io.sockets.on('connection', function (socket) {

 socket.on("screen", function(data){
   socket.type = "screen";
   
   ss = socket;
   console.log("Screen ready...");
 });

 socket.on("remote", function(data){
   socket.type = "remote";
   console.log("Remote ready...");
   if(ss != undefined){
      console.log("Synced...");
   }
 });
)};

Clientseitige Web-Socket-Implementierung

Fügen Sie Folgendes zu remote.html hinzu:

<script src="/socket.io/socket.io.js"> </script>
<script>
  
      
      var socket = io.connect('http://raspberrypi.local:8080');
  socket.on('connect', function(data){
      socket.emit('screen');
  });
</script>

Fügen Sie Folgendes hinzu index.html:

<script src="/socket.io/socket.io.js"> </script>
<script>
  
      
      var socket = io.connect('http://raspberrypi.local:8080');
  socket.on('connect', function(data){
    socket.emit('screen');
  });
</script>

Ausführen von Shellcode von Node.js

Node.js ermöglicht es uns, Systembefehle innerhalb der gegebenen Berechtigungen eines untergeordneten Prozesses auszuführen. Dazu gehört die Möglichkeit, Argumente an den Befehl zu übergeben und sogar die Ergebnisse eines Befehls an einen anderen weiterzuleiten, ähnlich wie bei UNIX.

Eine Möglichkeit, Shell-Befehle von Node.js auszuführen Kindprozess

spawn('echo',['foobar']);

Wenn Sie die Antwort jedoch an einen anderen Aufruf weiterleiten möchten, sollten Sie die folgende Rückruffunktion für die Funktion bereitstellen:


function run_shell(cmd, args, cb, end) {
    var spawn = require('child_process').spawn,
        child = spawn(cmd, args),
        me = this;
    child.stdout.on('data', function (buffer) { cb(me, buffer) });
    child.stdout.on('end', end);
}

Hinzufügen von OMXControl – dem OMX-Player-Controller für Node.js

Tolle Sachen findet man auf npm: OMXControl-Modul ermöglicht es Ihnen, den OMX-Player über HTTP zu steuern.
Benötigen Sie dieses Modul intp Ihrer Hauptprojektdatei.

var omx = require('omxcontrol');


app.use(omx());

Das OMXControl-Modul erstellt die folgenden Routen zur Steuerung der Videowiedergabe:

/omx/start/:filename
/omx/pause
/omx/quit

Alles zusammenfügen

Unsere weiterentwickelte app.js-Datei



var express = require('express')
  , app = express()  
  , server = require('http').createServer(app)
  , path = require('path')
  , io = require('socket.io').listen(server)
  , spawn = require('child_process').spawn
  , omx = require('omxcontrol');


app.set('port', process.env.TEST_PORT || 8080);
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(path.join(__dirname, 'public')));
app.use(omx());


app.get('/', function (req, res) {
  res.sendfile(__dirname + '/public/index.html');
});

app.get('/remote', function (req, res) {
  res.sendfile(__dirname + '/public/remote.html');
});


io.set('log level', 1);

server.listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});


function run_shell(cmd, args, cb, end) {
    var spawn = require('child_process').spawn,
        child = spawn(cmd, args),
        me = this;
    child.stdout.on('data', function (buffer) { cb(me, buffer) });
    child.stdout.on('end', end);
}


var ss;

io.sockets.on('connection', function (socket) {

 socket.on("screen", function(data){
   socket.type = "screen";
   ss = socket;
   console.log("Screen ready...");
 });
 socket.on("remote", function(data){
   socket.type = "remote";
   console.log("Remote ready...");
 });

 socket.on("controll", function(data){
    console.log(data);
   if(socket.type === "remote"){

     if(data.action === "tap"){
         if(ss != undefined){
            ss.emit("controlling", {action:"enter"}); 
            }
     }
     else if(data.action === "swipeLeft"){
      if(ss != undefined){
          ss.emit("controlling", {action:"goLeft"}); 
          }
     }
     else if(data.action === "swipeRight"){
       if(ss != undefined){
           ss.emit("controlling", {action:"goRight"}); 
           }
     }
   }
 });

 socket.on("video", function(data){

    if( data.action === "play"){
    var id = data.video_id,
         url = "http://www.youtube.com/watch?v="+id;

    var runShell = new run_shell('youtube-dl',['-o','%(id)s.%(ext)s','-f','/18/22',url],
        function (me, buffer) { 
            me.stdout += buffer.toString();
            socket.emit("loading",{output: me.stdout});
            console.log(me.stdout)
         },
        function () { 
            
            omx.start(id+'.mp4');
        });
    }    

 });
});

4. Clientseitiges Scripting: Dashboard und mobile Remote-App

Raspberry Pi TV-Bildschirm-Frontend

Eine detaillierte Beschreibung, wie ich das Front-End erstellt habe, ist in diesem Tutorial nicht möglich, ich möchte jedoch auf einige Tipps hinweisen, die ich bei der Durchführung dieses Projekts entdeckt habe.

Beim Entwerfen für den 10-Fuß-Bildschirm gibt es einige Designtipps zu beachten, Google hat eine nette Reihe dieser Tricks zusammengestellt Entwicklerseite

Himbeer-Pi-Fernbedienung

Anstatt eine klassische Fernbedienung voller Tasten zu kreieren, habe ich mich entschieden zu geben Quo.js Probieren Sie es aus, es ist eine fantastische js-Bibliothek für plattformübergreifende Wischgesten!

$$(".r-container").swipeLeft(function(){
socket.emit('control',{action:"swipeLeft"}); 
});

Hier ist ein Beispiel dafür, wie ich die Nachricht „Control“ mit der Datenaktion an den Server zurücksende: swipeLeft

Der Server verarbeitet diese Nachricht, indem er sie an den Bildschirm sendet, der Bildschirmclient verarbeitet diese Nachricht, indem er das ausgewählte Quadrat zur nächsten App verschiebt (Watch, Listen, Play).

Ich habe auch eine Liste von Meta-Tricks zusammengestellt, die Ihre mobile iPhone-Web-App wie eine native aussehen lassen, mit einem netten Symbol und einem Begrüßungsbildschirm.
Fügen Sie einfach Folgendes zu Ihren HTML--Blöcken hinzu

<link rel="apple-touch-icon" href="images/custom_icon.png"/>
<link rel="apple-touch-startup-image" href="images/startup.png">
<meta name="viewport" content="width=device-width initial-scale=1, maximum-scale=1, user-scalable=no" />
<meta name="apple-mobile-web-app-title" content="Remote">
<meta name="apple-mobile-web-app-capable" content="yes">

Besonderer Dank

Dieser Workshop wurde am gegeben Lamba Labs Beirut Erster Hackerspace Schauen Sie sich nach einer Reihe von Blitzvorträgen die Präsentation an hier Wenn Sie das Tutorial umgehen und in die lustigen Sachen einsteigen möchten, können Sie den Code jederzeit forken GitHub

Auch dieser Workshop wird von betrieben GDG Beirut und die Idee wurde während einer gebacken Blitz sprechen die ich bei der gegeben habe Google IO Extend Beirut 2013

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *