Englisch version   English version


  Diese Version ist veraltet. Die neue Version befindet sich hier: UrsAI2UDP


Version Anpassungen
1 (2018-01-27) Initiale Version
2 (2018-12-08) Seit Dezember 2018 gab es Probleme mit Netzwerkzugriffen. Diese Zugriffe müssen nun in separaten Threads ausgeführt werden. Die Komponente wurde entsprechend umgeschrieben.
Zusätzlich wurde die Eigenschaft InitErr eingeführt, über die Fehler bei der Initialisierung der Komponente abgerufen werden können.
3 (2019-01-11) Leider hatte die Version 2 ein paar Probleme. Die Version 3 ist neu strukturiert. Sie ist leider nicht kompatibel mit der vorhergehenden Version. Zum Update deshalb die unten aufgeführten Migrationshinweise beachten.
Die alte Version 2 ist hier archiviert.
3.1 (2019-04-29) Die neue Eigenschaft BinaryMode erlaubt das Übertragen von binären Daten. Diese Version ist kompatibel mit der Version 3.0. Beim Hochladen bleiben die bestehenden Verknüpfungen der Blöcke erhalten.
3.2 (2020-02-17) - DropSentToYourself wurde nach Start des Listeners nicht weitergereicht.
- Die Bestimmung der Local-Host-IP per Enumration über die Netzwerkinterfaces führt zu Problemen bei Endgeräten, die mehr als ein Interface besitzen. DropSentToYourself hat nicht funktioniert. DropSentToYourself vergleicht nun die Absender-Adresse mit allen vorhandenen NIC-Adressen. LocalHost ist nun die Adresse, mit der das Internet erreicht wird (google.com, 8.8.8.8).

Motivation

Für ein Projekt sollte eine Android-App entwickelt werden, die mit einem ESP8266(-Projekt) kommuniziert. Zur App-Entwicklung sollte wegen der einfachen Handhabung der MIT App Inventor 2 benutzt werden.

Die IP-Adressen der verfügbaren ESP8266-Geräte sollten im Projekt nicht fest vorgegeben werden. Die App soll selbst ermitteln, welche Geräte gerade aktiv sind und unter welchen Adressen sie angesprochen werden können.

Zur Erledigung dieser Aufgabe (Name Service) bietet sich die Nutzung der Broadcast-Funktion von UDP an. Man sendet einfach an einen vorher vereinbarten Port ein Broadcast-Datagramm an alle im lokalen Netzwerk vorhandenen Geräte mit der Aufforderung, die eigenen Verbindungsdaten zurück zu liefern. Die Geräte, die auf dem vereinbarten Port lauschen, senden daraufhin ihre IP und ggf. weitere Daten an den Absender zurück. Der Absender sammelt die Antworten auf und kennt damit alle aktiven Geräte. Da die Paket-Übermittlung bei UDP nicht garantiert ist, empfiehlt es sich, diesen Vorgang zu wiederholen und die Vereinigungsmenge der Antworten zu nutzen.

Um gezielt die Geräte eines Projekts ansprechen zu können, vereinbart man entweder unterschiedliche Ports oder man gibt eine Geräte-Kennung in der Antwort mit. Der Empfänger filtert dann diejenigen Geräte heraus, die ihn interessieren.

Nun kommt die Krux. Der App Inventor hat kein eingebautes UDP und ich habe auch keine funktionierende Erweiterung (Extension) gefunden. Also selber machen.

Hinweis:

Die Extension klappt einwandfrei, wenn sich Smartphone und Gegenstation im gleichen (lokalen) Netzwerk befinden. Ist das Smartphone nur per Mobilfunknetz verbunden, ist es i.d.R. nicht erreichbar. Der Grund ist, dass das Smartphone nicht direkt mit dem Internet verbunden ist, sondern nur mit dem lokalen Netzwerk des Mobilfunkanbieters.

Mobilfunk-Verbindung

Ein Gerät im eigenen LAN kann man von außerhalb per Port-Weiterleitung (port porwarding) am eigenen Router erreichen (ggf. via DDNS). Den Router des Providers wird man nicht beeinflussen können. Also senden vom Smartphone an ein Gerät im LAN funktioniert, umgekehrt geht es nicht.

Das gleiche gilt übrigens auch für TCP. Wenn das Smartphone nur mit dem Mobilfunknetz verbunden ist, kann die Verbindung kann nur vom Smartphone aus aufgebaut werden. Das Gerät im LAN muss als Server agieren, wartet also auf eine eingehende Verbindungsanforderung. Das Smartphone agiert als Client, initiiert den Verbindungsaufbau. Ist die Verbindung einmal eingerichtet, haben sich die Router intern über Adressen und Ports abgestimmt. Der Datentransfer ist dann in beide Richtungen möglich.

Download

Das ZIP-Archiv UrsAI2UDPv3.2 zum Download. Das Archiv enthält den Quellcode, das kompilierte Binary zum Upload in den App Inventor und eine Beispiel-Anwendung.

Migration von der Version 2 zur Version 3

Die wesentlichen Unterschiede sind:

  • Die Methoden Xmit und StartListening sind nun Funktionen, die einen Rückgabewert liefern, der angibt, ob die Methode erfolgreich ausgeführt wurde.
  • Die Ereignisse XmitError und RcvError entfallen dafür. Bei der App-Entwicklung war es schwierig, diese mit der Aktion in Verbindung zu bringen.
  • Die Namen einiger Funktionen und Funktionsparameter wurden an die gebräuchlichen Bezeichnungen angepasst.

Am besten geht man bei der Migration eines bestehenden Projekts wie folgt vor:

  • Sichern des bestehen Projekts ("Save project as ..." im Projekt-Menü von App Inventor).
  • Importieren der neuen Version der Extension (zusätzlich zu der alten!).
  • Im App Inventor Designer: Eine neue Instanz der Extension auf den Screen ziehen.
  • Im Block-Editor die betroffen Blöcke an den neuen Extension-Block umhängen. Dabei auf Warnungen und Fehler achten!
  • Am besten an dieser Stelle eine weitere Sicherung erstellen.
  • Im Designer: Die Instanz der alten Extension-Version und die alte Extension löschen.
  • Im Block-Editor nachschauen, ob noch alles korrekt ist.

Verwendung

Datagramme versenden

Block Funktion Anmerkung
Xmit Der Block Xmit versendet Datagramme an den angegebenen Remote-Endpunkt (RemoteIP:RemotePort). Dabei wird der lokale Endpunkt 0.0.0.0:LocalPort verwandt, d.h. der Dienstanbieter wählt das passende Netzwerk-Interface aus.

Beim Parameter RemoteIP können sowohl Unicast- als auch Broadcast-Adressen angegeben werden.

Für den Parameter LocalPort sind auch die Angabe 0 oder negative Werte erlaubt. In diesem Fall sucht der Dienstanbieter einen zufälligen freien Port aus.

Message enthält entweder die Nachricht als Text (BinaryMode = false) oder codierte Binärwerte (BinaryMode = true, s. unten).

Der Rückgabewert bedeutet:
Wert Bedeutung
0 Versand erfolgreich.
1 Angabe zu RemoteIP kann nicht in eine IPv4-Adresse umgewandelt werden.
2 Unter der Angabe LocalPort kann kein Socket angelegt werden. Port-Nummer ist nicht frei oder > 65535.
3 Fehler beim Versenden.
4 String kann nicht konvertiert werden (nur, wenn BinaryMode = true).
Ein Android-Device hat zu einer Zeit i.d.R. maximal nur ein aktives Netzwerk-Interface. Dies ist entweder die mobile Datenverbindung oder das WLAN.


Zu UDP-Adress-Schemata siehe UdpClient: Aufs Bit geschaut / Adressierungsschemata

Zu Endpunkten in Java UdpClient: Aufs Bit geschaut / Java


Eine typische Verwendung zeigt dieser Block:
Datagramme versenden

Will man Binärdaten übertragen, muss BinaryMode auf true gesetzt werden und die Werte codiert als String im Parameter Message übergeben werden. Um z.B. drei Byte mit den HEX-Werten 33 48 DF zu versenden, könnte dies durch die Angabe "0x33,0x48,0xDF" geschehen. Details: s.u.
Last Error Über die Eigenschaft LastErrorMessage kann ein (englischer) Text abgerufen werden, der den zuletzt aufgetretenen Fehler näher beschreibt.  
BinaryMode Wenn BinaryMode auf true gesetzt wird, wird der Inhalt von Message nicht direkt gesendet, sondern in ein Byte-Array übersetzt. Auswirkung: s.u.


Datagramme empfangen

Block Funktion Anmerkung
StartListening StartListening startet das "Lauschen" auf Datagramme, die an den angegebenen Port gesendet werden (UDP-Server).

Der Rückgabewert bedeutet:
Wert Bedeutung
0 Start erfolgreich.
1 Mit der Angabe Port kann kein Socket angelegt werden. Port-Nummer ist nicht frei, < 1 oder > 65535.
2 Startvorgang bevor vorhergehender Start abgeschlossen wurde.

StopListening stoppt den Server. Ein mehrfaches Aufrufen von StopListening ist unkritisch.
Zu Endpunkten in Java UdpClient: Aufs Bit geschaut / Java


Eine typische Verwendung zeigt dieser Block:
Listener starten
Last Error Über die Eigenschaft LastErrorMessage kann ein (englischer) Text abgerufen werden, der den zuletzt aufgetretenen Fehler näher beschreibt.  
Server Start/Stop Passend dazu gibt es das Ereignis ServerStarted mit LocalIP und LocalPort als Empfangsadresse und das Ereignis ServerStopped.  
IsRunning Über die Eigenschaft isRunning kann abgefragt werden, ob der Server aktuell aktiv ist.  
Datagramm empfangen Wenn Daten empfangen werden, wird das Ereignis DataReceived ausgelöst.

Data enthält die Datagramm-Daten RemoteIP und RemotePort die Absender-Adresse.
 
DropSentToYourself Die Eigenschaft DropSentToYourself steuert das Verhalten beim Empfang Broadcast-Datagrammen. Der Block ist standardmäßig so eingestellt, dass Nachrichten ignoriert werden, die von der eigenen IP versandt wurden. Sollen diese dennoch empfangen werden, ist DropSentToYourself auf false zu setzen.

Diese Eigenschaft kann auch im Designer eigestellt werden.
Die Voreinstellung ist true.
BinaryMode Wenn BinaryMode auf true gesetzt wird, wird das empfangene Paket in einen String mit einer Folge von Dezimalzahlen übersetzt. Auswirkung: s.u.

Binärdaten

BinaryMode

Wenn BinaryMode auf true gesetzt ist, akzeptiert Xmit eine Zeichenfolge mit codierten Bytes, die durch ein Komma (’,’) oder ein Semikolon (';') voneinander getrennt sind.

Jedes Byte kann als „0xff“ oder „0xFF“ oder „0Xff“ oder „0XFF“ oder „#ff“ oder „#FF“ für HEX-Input oder „255“ für dezimalen Input oder „0377“ für den Oktal-Input codiert sein.

Man kann die Formate mischen: "0xFF;255,#ff" ist gültig.

Man kann auch Leerzeichen vor und nach der Zahl einfügen: „0xFF;  255,  #ff ”ist ebenfalls gültig.

Ein nachfolgendes Komma oder Semikolon wird ignoriert: "0xFF; 255, #ff" und "0xFF; 255, #ff;" sind identisch.

Wenn BinaryMode auf true gesetzt ist, wird das empfangene Paket in eine durch Semikola getrennte Zeichenfolge von Dezimalzahlen übersetzt, z.B. "123;33;0;44". Man kann String.Split verwenden, um eine Liste der Bytes abzurufen.

Die Eigenschaft BinaryMode kann im Entwurfsfenster oder per Code festgelegt werden. Der Standardwert ist false.

BinaryMode

Es gibt einen neuen Rückkehrcode: 4. Er bedeutet "Eingabe kann nicht konvertiert werden". Nichts wird gesendet.

Für die Konvertierung wird dieser Algorithmus verwandt:
1) Ersetzen aller Kommas durch Semikolons
2) splitten der Zeichenfolge per Semikolons
3) führende und nachfolgende Leerzeichen löschen
4) Konvertierung in Integer mit Integer.decode ()
5) auf Werte <0 oder> 255 prüfen.

Diverses

Block Funktion Anmerkung
LocalHost LocalHost ruft die lokale IP-Adresse ab (in der Android-Umgebung ist diese i.d.R. eindeutig). Dies ist die Adresse, mit der das Internet erreicht werden kann.

Ist kein Netzwerk erreichbar, wird der bei Default angegebene Wert zurück geliefert.
Eine typische Verwendung zeigt dieser Block:
LocalHost

Beispiel

Screenshot   Designer

Die Blöcke im Beispiel sind nicht schwer zu verstehen. Den größten Bereich nimmt die Überprüfung valider Eingaben ein.

Werkzeuge

Für die Erstellung eigener Extensions habe ich einige Tipps zusammengestellt: AI2 FAQ: Extensions entwickeln.

Die Entwicklung der Erweiterungen erfolgt mit Java. Ein Tutorial über Datagramme findet man in der Oracle Java Dokumentation. Dort findet man auch Informationen zur verwendeten Klasse DatagramSocket.