Aus Linux-Magazin 04/2015

Raspberry Pi steuern mit Android

© ice, 123RF

Wer den Raspberry Pi über eine Android-App zum Tanz auffordern möchte, bringt am besten Websockets mit auf den Ball. Sie erleichtern die gepflegte Konversation mit dem graziösen Minirechner.

Ihre große Auswahl, allgemeine Verfügbarkeit und reichhaltige Ausstattung bei einem zugleich niedrigen Preis machen Kleincomputer mit relativ leistungsfähigen Mikroprozessoren zurzeit nicht nur bei Programmierern und Konstrukteuren beliebt, sondern auch bei Hobby-Entwicklern. Es gibt Minis in vielen Varianten, sie sind verfügbar und zugleich großzügig ausgestattet – und all das zum niedrigen Preis. Am bekanntesten ist der Raspberry Pi, zu nennen wären aber auch Cubietruck, Banana Pi, Beagle Bone oder Odroid C1.

Mittlerweile laufen auf diesen Plattformen dank schneller Prozessoren mit MMU-Einheiten komplette Desktop-Betriebssysteme wie Debian und Ubuntu. Sie ermöglichen zugleich den problemlosen und schnellen Zugriff auf Hardwarebusse über I2C, 1-Wire oder SPI. Dementsprechend entwickeln Benutzer der kleinen Einplatinencomputer bevorzugt Projekte, mit denen sie die beiden Welten Informatik und Elektronik miteinander kombinieren. Ihre Software liest eine Reihe externer Sensoren (Temperatur, Druck) aus, steuert Aktuatoren (Relais, Triac) und verbindet so Daten mit der realen Welt.

Während Hardwareplattformen wie etwa Beagle Bone Black oder Raspberry Pi weltweit an Bekanntheit gewinnen, wächst auch das Interesse an Projekten für die Heimautomatisierung. Dieser Bereich gilt vielen als Prüfstein dafür, ob Software und Hardware ideal zusammenarbeiten. Die Bedeutung schlägt sich unter anderem in einer rapide steigenden Anzahl an Fragen in thematisch verwandten Foren nieder. Eine oft und gern geführte Diskussion behandelt beispielsweise die Frage, wie sich das Entwicklerboard XYZ, das als Herz einer Heimautomatisierung fungiert, mit mobilen Geräten kontrollieren und steuern lässt.

Der vorliegende Artikel zeigt anhand zweier Beispielprojekte, wie sich auf dem Raspberry Pi ein Server betreiben lässt (Websockets Server), an den eine Clientanwendung (Websockets Client) asynchrone Broadcast-Benachrichtigungen schickt. Zu diesem Zweck kommt eine C-Implementierung des populären Websocket-Protokolls zum Einsatz, über das sich dank existierender Softwarebibliotheken auch ohne umfassendes Netzwerkwissen ein handlicher Kommunikationskanal aufbauen lässt.

Websockets

Bevor es daran geht, die Details zu implementieren, bedarf es einiger Kenntnisse zur Websockets-Technologie. Sie kommt zum Einsatz, wenn es darum geht, eine schnelle und leistungsfähige Zwei-Wege-Kommunikation zwischen Webanwendungen und Clients in Echtzeit zu realisieren. Das betrifft unter anderem Kommunikationsprogramme oder Multiplayer-Spiele. Der Grund: Das HTTP-Protokoll, das nach dem Frage-Antwort-Prinzip arbeitet, reicht schon seit geraumer Zeit für die Bedürfnisse vieler Anwendungen nicht mehr aus. Das gilt sowohl für die Ansprüche der Anwendungsentwickler als auch für die der Benutzer.

Anfangs versuchten die HTTP-Entwickler mit aktiven Abfragen gegenzusteuern und das Protokoll so zu erweitern, dass es den Eindruck von Asynchronität erzeugt. Die so genannte Polling-Methode trickst, indem sie Abfragen mehrfach an den Server sendet, um festzustellen, ob die Daten für den Client bereits ablesebereit sind. In der Praxis erwies sich diese Methode als wenig leistungsfähig, sie erzeugt ordentlich Traffic und belastet das Netz.

Daher haben W3C und IETF im Dezember 2011 einen neuen Standard entwickelt, um die eingetretenen Probleme zu lösen. So entstand das Websocket-Protokoll, das den Zwei-Wege-Austausch der Daten über eine TCP-Verbindung abwickelt. Der Standard verwendet zunächst das übliche TCP-Protokoll, fängt aber die Verbindung zwischen Server und Client im Zuge der typischen HTTP-Transaktion ab und bittet darum, das Protokoll zu ändern und zu aktualisieren, wie es die Abbildung 1 darstellt.

Abbildung 1: Ablauf eines Handshake beim Websocket-Protokoll.

Abbildung 1: Ablauf eines Handshake beim Websocket-Protokoll.

Zu den wesentlichen Vorteilen des Websocket-Protokolls zählen unter anderem:

  • Es erlaubt Client-Server-Architekturen, die das Netz nur wenig belasten. Unter anderem fällt dadurch das bislang genutzte Polling weg.
  • Asynchrone Broadcast-Benachrichtigungen lassen sich einfach implementieren.
  • Das Format der hochgeladenen Daten lässt sich beliebig wählen, es darf sich beispielsweise um Json- und XML-Dateien oder einfache Textmitteilungen handeln.
  • Für die verschiedenen Dateitypen kommen getrennte und optimierte Übertragungskanäle zum Einsatz, etwa für Text- und Binärdateien.
  • Es beherrscht chiffrierte Verbindungen.
  • Zahlreiche Bibliotheken unterstützen das Websocket-Protokoll, und es existieren Bindings für die bekanntesten Programmiersprachen, wozu beispielsweise Java, Javascript, aber auch C# oder PHP gehören.
  • Das Protokoll lässt sich einfach und schnell implementieren. In den meisten Fällen liefern die Bibliotheken dem Programmierer einen hohen Grad an Abstraktion. Der erspart es ihm zum Beispiel, Details darüber zu kennen, wie er Data Frames bauen, formatierten und versenden muss.
  • Die meisten bekannten Internetbrowser unterstützen Websockets.

Ursprünglich sollten sich Websockets vor allem um die Kommunikation von Internetbrowsern mit Internetdiensten kümmern. Sie zogen jedoch recht schnell in andere Lösungen ein, die aufgrund ihrer Architektur eine einfache und leistungsfähige Kommunikation zwischen Client und Server erfordern. In dem folgenden Beispiel sollen Websockets den Einplatinencomputer Raspberry Pi mit Android-Mobilgeräten verbinden.

Doppelter Spaß

Der Artikel zeigt gleich zwei Anwendungen (Abbildung 2). Websockets Server dient als einfacher Echo-Server, während die Clientanwendung Websockets Client auf Android läuft, die Daten als einfache Json-Objekte an den Server sendet und solche von diesem empfängt.

Abbildung 2: Der Raspberry Pi arbeitet als Websocket-Server und erledigt im Artikel gleich zwei Aufgaben. Zum einen dient er als einfacher Echo-Server, zum anderen schickt er eine Nachricht an das Smartphone, sobald jemand einen USB-Stick anstöpselt.

Abbildung 2: Der Raspberry Pi arbeitet als Websocket-Server und erledigt im Artikel gleich zwei Aufgaben. Zum einen dient er als einfacher Echo-Server, zum anderen schickt er eine Nachricht an das Smartphone, sobald jemand einen USB-Stick anstöpselt.

Neben der Echo-Funktion implementiert der Code auch die Möglichkeit, asynchrone Broadcast-Meldungen an alle an den Server angeschlossenen Clients zu versenden. Um nicht einen weiteren Artikel zum GPIO-Monitoring abzuliefern, sollen die Server- und Client-Anwendung asynchrone D-Bus-Signale austauschen, die im Beispiel der Udisks-Daemon erzeugt. Konkret hat der Server eine Nachricht an die Clientanwendung auf dem Android-Gerät zu senden, sobald ein User einen USB-Stick an den Raspberry Pi steckt. Die erscheint dann auf dem Android-Gerät, Abbildung 2 zeigt schematisch, wie das aussehen soll.

Das Hauptfenster der Anwendung Websockets Client zeigt Abbildung 3. Das Interface besteht aus drei Feldern vom Typ »EditBox« . Über sie gibt der Nutzer Parameter wie die IP-Adresse, die Nummer des Ports und ein Timeout in Millisekunden ein. Ein Druck auf den »Connect« -Button verbindet ihn mit dem Raspberry Pi. Über das »EditBox« -Feld im unteren Teil des Bildschirms schickt er Befehle an den Server. Alle so verschickten Botschaften erscheinen im mittleren Bereich des Bildschirms.

Abbildung 3: Die Benutzeroberfläche der Client-anwendung Websockets Client.

Abbildung 3: Die Benutzeroberfläche der Client-anwendung Websockets Client.

Obwohl die Internetanwendung auf einem Raspberry Pi entwickelt und getestet wurde, können Leser, die keinen ARM-Rechner besitzen, sie auch auf ihrem Linux-Rechner übersetzen und testen [1]. Auf Github wartet die aktuelle Version des Quellcodes für den Server [2] und den Client [3].

Websockets Server

C-Programmierer, in dieser Sprache ist Websockets Server geschrieben, greifen wahlweise auf Lösungen wie die Libwebsocket [4], Wslay [5] oder die Websocket-Implementierung No-Poll [6] zurück. Für die Bibliothek Libwebsocket spricht, dass ihre Verfasser damit werben, dass sie die CPU und den Arbeitsspeicher nur minimal beansprucht, was für die schwachen Einplatinencomputer wesentlich ist.

Zunächst installiert der Entwickler die Debian-Variante Raspian über eine SD-Karte auf dem Raspberry Pi und bringt die Installation über

sudo apt-get update
sudo apt-get upgrade

auf den neuesten Stand. Anleitungen dazu, wie das funktioniert, warten mittlerweile im Dutzend im Internet, etwa unter [7]. Im nächsten Schritt installiert der Entwickler die Komponenten, die er braucht, um die Libwebsocket für die Serveranwendung Websockets Server zu übersetzen:

sudo apt-get install cmake git libssl-dev libglib2.0-dev libjansson4 libjansson-dev

Anschließend lädt er den Quellcode herunter und kompiliert die Bibliothek Libwebsocket. Wie das geht, zeigt Listing 1.

Listing 1

Libwebsocket übersetzen

01 cd $HOME
02 git clone https://github.com/lukasz-skalski/libwebsockets.git
03 cd libwebsockets
04 mkdir build
05 cd build
06 cmake -DLWS_IPV6=OFF -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
07 make
08 sudo make install

Nun gilt es, die wesentlichen Bestandteile von Websockets Server aus dem Repository zu holen und zu kompilieren, was Listing 2 vorführt.

Listing 2

WebSocketsServer kompilieren

01 cd $HOME
02 git clone https://github.com/lukasz-skalski/WebSocketsServer.git
03 cd WebSocketsServer
04 mkdir build && cd build
05 cmake -DCMAKE_BUILD_TYPE=Debug ../
06 make

Abbildung 4 zeigt schematisch, wie die Serveranwendung tickt. Sie macht klar, dass sich der Quellcode von Websockets Server grob in fünf funktionale Blöcke unterteilen lässt. Die Hauptschleife »main()« des Programms beginnt damit, den Server zu initialisieren. Dieser Vorgang findet in zwei Etappen statt, wobei die Bibliothek Libwebsocket dem Programmierer das erwähnte High-Level-API anbietet.

Abbildung 4: Beim Initialisieren erzeugt die Anwendung den Websocket-Kontext und registriert sich bei D-Bus. Das Hauptprogramm etabliert dann zwei Callback-Funktionen für D-Bus und die Libwebsocket.

Abbildung 4: Beim Initialisieren erzeugt die Anwendung den Websocket-Kontext und registriert sich bei D-Bus. Das Hauptprogramm etabliert dann zwei Callback-Funktionen für D-Bus und die Libwebsocket.

Phase 1

Um den Server zu initialisieren, ergänzt der Entwickler im ersten Schritt die Felder der Struct »lws_context_creation_info« und ruft dann die Funktion »libwebsocket_create_context()« auf, wie Listing 3 in Zeile 30 zeigt. Dank der gewählten Parameter erzeugt diese »socket« und »handler« auf der Struktur, über die der Entwickler die Verbindung steuert. Das schließt bereits die erste Etappe der Initialisierung ab. Die erforderliche Minimalkonfiguration der Struct »lws_context_creation_info« stellt Listing 3 ab Zeile 16 dar.

Listing 3

WebSocketsServer.c (Phase 1, Auszug)

01 [...]
02 static struct libwebsocket_protocols protocols[] = {
03   {
04     "my_protocol",                   /* protocol name */
05     my_callback,                     /* callback */
06     sizeof(struct per_session_data)  /* max frame size / rx buffer */
07   },
08   {
09     NULL, NULL, 0
10   }
11 };
12 [...]
13
14 struct lws_context_creation_info info;
15 [...]
16 memset (&info, 0, sizeof info);
17 info.port = 8080;
18 info.iface = NULL;
19 info.protocols = protocols;
20 info.extensions = libwebsocket_get_internal_extensions();
21 info.gid = -1;
22 info.uid = -1;
23 info.options = 0;
24 info.ssl_cert_filepath = NULL;
25 info.ssl_private_key_filepath = NULL;
26 [...]
27
28 static struct libwebsocket_context *context;
29
30 context = libwebsocket_create_context (&info);
31 if (context == NULL)
32   {
33     print_log (LOG_ERR, "(main) libwebsocket context init failed\n");
34     goto out;
35   }
36 [...]

Für die simpelste Version eines Servers, der die Kommunikation mit dem Mobilgerät ermöglicht, braucht die Struct »lws_context_creation_info« die Nummer des Ports, auf dem der Server Verbindungen entgegennimmt (»info.port« ), sowie eine Info zu dem verwendeten Protokoll (»info.protocols« ). Letztere verweist auf eine Struktur vom Typ »libwebsocket_protocols« , die das implementierte Protokoll definiert und beschreibt.

Eine Beispieldefinition für das Protokoll »my_protocol« und die zugehörige Callback-Funktion »my_callback()« liefert Listing 3 in den Zeilen 2 bis 11. Sie kümmert sich darum, Verbindungen herzustellen und abzuschließen sowie Daten zu lesen und aufzuzeichnen.

Phase 2

In der zweiten Etappe initialisiert der Code den D-Bus-Systembus. Er soll dafür sorgen, dass der Server asynchrone Nachrichten an die angeschlossenen Clients sendet, und funktioniert unabhängig von der Websocket-Kommunikation. Dazu ruft das Programm die Funktion »g_bus_get_sync()« der Glib-Bibliothek auf und verbindet sich in den Zeilen 16 bis 21 von Listing 4 mit einem ausgewählten Systembus.

Listing 4

WebSocketsServer.c (Phase 2, Auszug)

01 [...]
02 g_dbus_connection_signal_subscribe (connection,
03                                     "org.freedesktop.UDisks",
04                                     NULL,
05                                     "DeviceAdded",
06                                     NULL,
07                                     NULL,
08                                     G_DBUS_SIGNAL_FLAGS_NONE,
09                                     dbus_notification_callback,
10                                     NULL,
11                                     NULL);
12 [...]
13
14 GDBusConnection *connection = NULL;
15
16 connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
17 if (connection == NULL)
18   {
19     printf ("Can't connect to system bus: %s\n", error->message);
20     g_error_free (error);
21   }
22 [...]

Ist dieser Initialisierungsschritt erst mal geglückt, abonniert das Programm, wie in Abbildung 4 dargestellt, Benachrichtigungen über Systemereignisse, die D-Bus involvieren, etwa beim Anschluss des USB-Sticks an den entsprechenden USB-Port. Dazu muss das Programm zunächst den Daemon, der D-Bus verwaltet, darüber informieren, von welchen Systemereignissen es erfahren möchte.

Diesen Subscription genannten Prozess setzt die Anwendung Websockets Server über die Funktion »g_dbus_connection_signal_subscribe()« (Zeilen 2 bis 11 in Listing 4) um, die ebenfalls die Bibliothek Glib bereitstellt. Die Beispiel-Subskription reagiert dabei auf ein »DeviceAdded« -Signal, das Udisks verschickt, sobald jemand einen USB-Stick an den Raspberry stöpselt.

D-Bus kümmert sich um die Interprozesskommunikation (IPC, [8]) auf fast allen Linux-Distributionen. Damit das Programm über die Funktion »g_dbus_connection_signal_subscribe()« auch das richtige Signal registriert, muss der Entwickler zuvor die Daten analysieren, die das Tool »dbus-monitor« zurückgibt. Eine Liste aller Signale, die über D-Bus wandern, zeigt auf dem Raspberry Pi:

dbus-monitor --system

Wer einen beliebigen Massenspeicher an den USB-Port anschließt, sollte die Informationen sehen, die »udisks« ausgibt (siehe Listing 5).

Listing 5

D-Bus-Ausgabe (Auszug)

01 [...]
02 signal sender=:1.6 -> dest=(null destination) serial=81 path=/org/freedesktop/UDisks; interface=org.freedesktop.UDisks; member=DeviceAdded
03    object path "/org/freedesktop/UDisks/devices/sda"
04 signal sender=:1.6 -> dest=(null destination) serial=83 path=/org/freedesktop/UDisks; interface=org.freedesktop.UDisks; member=DeviceAdded
05    object path "/org/freedesktop/UDisks/devices/sda1"
06 [...]

In der Nomenklatur des D-Bus-Projekts trägt Udisks den Interfacenamen »org.freedesktop.UDisks« und lautet der Signalname »DeviceAdded« . Diese Informationen benötigt die Serverfunktion »g_dbus_connection_signal_subscribe()« , um die USB-Ansteck-Aktionen eindeutig zu identifizieren.

Die Funktion aus Zeile 2 in Listing 4 muss auch den Namen der Callback-Funktion kennen, die sie auslösen soll, wenn sie das »DeviceAdded« -Signal erkennt. Der Name ist »dbus_notification_callback()« .

Main Loop

Damit schließt das Programm die Phasen der Initialisierung und Subskription ab und etabliert zwei Callbacks: »my_callback()« und »dbus_notification_callback()« . Mit ihrer Hilfe reicht es bestimmte Ereignisse über D-Bus an die Mobilgeräte weiter.

Die While-Schleife aus Listing 6 wartet auf anstehende Ereignisse. Ihre Hauptaufgabe besteht darin, die Funktion »libwebsocket_service()« im Auge zu behalten, sie akzeptiert Verbindungen und löst die zuvor definierte Callback-Funktion aus, wenn der Server Daten von Clients empfängt. In diesem Fall tritt die Funktion »g_main_context_iteration()« in Aktion. Sie iteriert einmal über Glibs Hauptschleife, um zu prüfen, ob D-Bus-Benachrichtigungen warten.

Listing 6

while()-Schleife

01 [...]
02 while (cnt >= 0 && !exit_loop) {
03
04   cnt = libwebsocket_service (context, 10);
05
06   if (send_notification) {
07     libwebsocket_callback_on_writable_all_protocol (&protocols[0]);
08     send_notification = FALSE;
09   }
10
11   g_main_context_iteration (NULL, FALSE);
12 }
13 [...]

Schließt also jemand den USB-Stick an den Raspberry Pi, setzt D-Bus das Signal »DeviceAdded« ab, woraufhin die Funktion »dbus_notification_callback()« das Flag »send_notification« setzt, was wiederum »libwebsocket_callback_on_writable_all_protocol()« auf den Plan ruft. Die Funktion löst die zuvor definierte Callback-Funktion »my_callback()« aus, die nun Broadcast-Nachrichten an alle angeschlossenen Clients verschickt.

Rückruf erwünscht

Bleibt noch die Funktion »my_callback()« zu erklären, die den Server mit den Clients verbindet, eine vereinfachte Variante liefert Listing 7. Weil die Bibliothek Libwebsocket dem Programmierer ein High-Level-Interface liefert, das die Details zur Verbindungsaufnahme vor ihm verbirgt, reagiert er in seinem Programm lediglich auf bestimmte Ereignisse.

Listing 7

my_callback()

01 [...]
02 my_callback ()
03 {
04   struct per_session_data *psd = (struct per_session_data*) user;
05   int nbytes;
06
07   switch (reason)
08     {
09       case LWS_CALLBACK_ESTABLISHED:
10         /* connection established */
11       break;
12
13       case LWS_CALLBACK_CLOSED:
14         /* connection closed */
15       break;
16
17       case LWS_CALLBACK_SERVER_WRITEABLE:
18         nbytes = libwebsocket_write(/* data to write */);
19         print_log ("%d bytes written\n", nbytes);
20       break;
21
22       case LWS_CALLBACK_RECEIVE:
23         print_log ("received %d bytes\n", (int) len);
24         psd->len = prepare_reply (wsi, in, &psd->buf[PADDING]);
25         if (psd->len > 0)
26           libwebsocket_callback_on_writable (context, wsi);
27       break;
28     }
29   return 0;
30 }
31 [...]

Die Funktion »my_callback()« kennt insgesamt vier Grundereignisse, die alle mit dem Präfix »LWS_CALLBACK_« beginnen. Über sie lässt sich sowohl eine Verbindung herstellen (Zeile 9) als auch schließen (Zeile 13), lassen sich Daten versenden (Zeile 17) und empfangen (Zeile 22).

Erhält die Serveranwendung in ihrer Funktion als Echo-Server Daten, bereitet sie mit Hilfe von »prepare_reply()« eine Antwort für die Clientanwendung vor. Diese erfolgt in Form eines Json-Objektes:

{
  "Type":    "standard",
  "Message": "Hello"
}

Das schickt sie an den Client zurück, die Funktion »libwebsocket_callback_on_writable()« hilft. Für die asynchronen D-Bus-Benachrichtigungen, die den Client über einen angesteckten USB-Stick informieren, sieht das Json-Objekt so aus:

{
  "Type":    "notification",
  "Message": "[Udisks] DeviceAdded"
}

Fehlt also noch der Code für die Client-Seite der Anwendung.

Websockets Client

Für die Android-Anwendung Websockets Client erwies sich die Wahl einer Bibliothek, die mit Websockets umgehen kann, als weniger trivial. Viele Projekte und Bibliotheken, die dem Programmierer die Arbeit mit Websockets erleichtern, sind in Java geschrieben, zu nennen wären Java Websocket [9] oder Projekt Autobahn Android [10]. Für das Linux-Magazin griff der Autor zur Bibliothek Secure Websocket [11], einem Klon des Projekts Autobahn Android.

Der wesentliche Code zur Anwendung findet sich in der Datei »ActivityMain.java« . Er definiert unter anderem die Funktionen »wsConnect()« und »wsDisconnect()« , welche die Verbindungen zum Server herstellen und schließen. Die Hauptklasse der Anwendung – »ActivityMain« – implementiert das Interface »Websocket.WebSocketConnectionObserver« und überschreibt die Methoden, die Tabelle 1 auflistet. Eine gekürzte und vereinfachte Version des Programms Websockets Client zeigt Listing 8.

Tabelle 1

Methoden in ActivityMain

Methodenname

Beschreibung

onOpen()

Websocket-Verbindung wurde etabliert

onClose()

Websocket-Verbindung wurde geschlossen

onTextMessage()

Textnachricht wurde empfangen

onRawTextMessage()

Raw-Textnachricht wurde empfangen

onBinaryMessage()

Binärdatei wurde empfangen

Die komplette Anwendung lässt sich aus dem Github-Repository holen oder von der DELUG-DVD herunterladen und über Androids Buildsystem Gradle mit dem Befehl aus Listing 9 übersetzen. Dazu braucht der Smartphone-Besitzer das passende Android-SDK für sein Smartphone sowie die richtigen Plattform-Tools für die vom Handy verwendete Android-Version [12].

Listing 9

Websockets Client übersetzen

01 git clone https://github.com/lukasz-skalski/WebSocketsClient.git
02 cd WebSocketsClient/
03 export ANDROID_HOME=/path/to/sdk/
04 ./gradlew build

Zum Schluss des Bauprozesses befinden sich im Ordner »$HOME/WebSocketsClient/app/build/outputs/apk« die installierbaren APK-Dateien. Wer sich das Bauen ersparen möchte, kann auch die fertige APK-Datei aus der Github-Paketquelle verwenden.

Listing 8

ActivityMain.java (vereinfachter Auszug)

01 [...]
02 public class ActivityMain extends Activity implements WebSocket.WebSocketConnectionObserver {
03
04   private volatile boolean isConnected = false;
05   private WebSocketConnection wsConnection;
06   private WebSocketOptions wsOptions;
07
08   @Override
09   protected void onCreate (Bundle savedInstanceState) {
10
11     super.onCreate (savedInstanceState);
12     setContentView (R.layout.activity_main);
13
14     connectButton.setOnClickListener (new View.OnClickListener() {
15       @Override
16       public void onClick(View v) {
17         wsConnect());
18       }
19     });
20
21     cmdInput.setOnEditorActionListener (new EditText.OnEditorActionListener() {
22       @Override
23       public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
24         if (actionId == EditorInfo.IME_ACTION_DONE) {
25           wsSend();
26           return true;
27         }
28         return false;
29       }
30     });
31   }
32
33   boolean wsConnect() {
34
35     this.wsConnection = new WebSocketConnection();
36     this.wsOptions = new WebSocketOptions();
37
38     wsConnection.connect(wsURI, this, wsOptions);
39   }
40
41   void wsDisconnect() {
42     wsConnection.disconnect();
43   }
44
45   void wsSend() {
46
47     /* send message to the server */
48     wsConnection.sendTextMessage(cmdInput.getText().toString());
49     appendText(cmdOutput, "[CLIENT] " + cmdInput.getText().toString()  + "\n", Color.RED);
50   }
51
52   @Override
53   public void onOpen() {
54     this.isConnected = true;
55   }
56
57   @Override
58   public void onClose (WebSocketCloseNotification code, String reason){
59     this.isConnected = false;
60   }
61
62   @Override
63   public void onTextMessage (String payload) {
64
65     JSONObject jsonObj = new JSONObject(payload);
66
67     if ((jsonObj.has(TAG_JSON_TYPE)) && (jsonObj.has(TAG_JSON_MSG))) {
68
69       if (jsonObj.getString(TAG_JSON_TYPE).equals("notification")) {
70
71         /* show notification */
72
73       } else if (jsonObj.getString(TAG_JSON_TYPE).equals("standard")) {
74
75         appendText(cmdOutput, "[SERVER]" + jsonObj.getString(TAG_JSON_MSG)+"\n",Color.RED);
76
77       } else {
78
79         Log.e (TAG_LOG, "Received invalid JSON from server");
80
81       }
82     }
83   }
84
85   @Override
86   public void onRawTextMessage (byte[] payload) {
87     Log.wtf (TAG_LOG, "We didn't expect 'RawTextMessage'");
88   }
89
90   @Override
91   public void onBinaryMessage (byte[] payload) {
92     Log.wtf (TAG_LOG, "We didn't expect 'BinaryMessage'");
93   }
94 [...]

Der Server auf dem Raspberry Pi lässt sich einfach starten. Wer die angebotenen Grundfunktionen bereits kennt, aktiviert ihn einfach über den Befehl:

./WebSocketsServer --port=8080

Wer sich jetzt für weitere Details zu den Möglichkeiten der Libwebsocket interessiert, studiert am besten die Dokumentation [13].

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 7 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben