Hallo,
diese Kommunikation (z.B zwischen Pi und einer Android App) erledige ich in meinen Projekten meist über MQTT.
Ich kann dir gerne ein Minimalbeispiel zur Verfügung stellen, da ich aus diversen Androidprojekten bereits Klassen habe, die genau dieses Problem lösen und die ich immer wieder verwende. Zunächst gibt es bei MQTT einen Server (MQTT-Broker). MQTT-Clients verbinden sich mit dem MQTT-Broker und können dann auf beliebigen Topics eigene Nachrichten veröffentlichen. Andere MQTT-Clients können das jeweilige Topic abonnieren und erhalten dann die entsprechende Nachricht. Auf diese Weise kannst du unter beliebig vielen Geräten ganz einfach kommunizieren.
In deinem Fall wäre der Pi sowohl MQTT-Broker als auch MQTT-Client.
Auf dem Pi kannst du den MQTT Broker und den Client mit einem Befehl installieren
sudo apt-get install mosquitto mosquitto-clients
Der Broker läuft jetzt auf Port 1883 und wartet darauf, dass Clients sich verbinden.
Der Pi kann nun als Client eigene Nachrichten veröffentlichen, z.B auf dem Topic "sensors/batterylife" die Nachricht "81 %"
mosquitto_pub -t 'sensors/batterylife' -m '81%'
Die Nachrichten kannst du dann mit einer MQTT-Bibliothek in der Programmiersprache deiner Wahl auf einem beliebigen Gerät im Netzwerk empfangen und verarbeiten.
Hier ein minimales funktionierendes Beispiel für Android:
Zuerst im neuen Androidprojekt die MQTT Bibliothek als gradle-Dependency zur build.gradle hinzufügen:
dependencies {
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.1'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}
Die App braucht 3 Berechtigungen und der Service muss im Manifest eingetragen werden - das sieht dann in einem frischen Projekt so aus:
(AndroidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="apps.vsum.dev.mqttexample">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="org.eclipse.paho.android.service.MqttService" />
</application>
</manifest>
Display More
Mit folgender Klasse (MQTTHelper.java) wird die Verbindung zum MQTT-Broker aufgebaut:
import android.content.Context;
import android.util.Log;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import java.util.ArrayList;
public class MqttHelper {
private MqttAndroidClient mqttAndroidClient;
private ArrayList<String> topics;
public MqttHelper(Context context, String brokerHostname, String brokerPort, ArrayList<String> topics){
this.topics = topics;
String serverSocket = "tcp://" + brokerHostname + ":" + brokerPort;
mqttAndroidClient = new MqttAndroidClient(context, serverSocket, MqttClient.generateClientId());
connect();
}
// connect to MQTT broker
private void connect(){
// define MQTT options
final MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setAutomaticReconnect(true);
mqttConnectOptions.setCleanSession(false);
mqttConnectOptions.setConnectionTimeout(3);
try {
// try to connect to MQTT broker
mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
final DisconnectedBufferOptions options = new DisconnectedBufferOptions();
options.setBufferEnabled(true);
options.setBufferSize(100);
options.setPersistBuffer(false);
options.setDeleteOldestMessages(false);
mqttAndroidClient.setBufferOpts(options);
// subscribe topics again on reconnect
for (String topic : topics){
subscribeToTopic(topic);
}
}
// on connection failure
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.i(this.getClass().getSimpleName(),"Could not connect to MQTT broker");
}
});
} catch (Exception e){
Log.i(this.getClass().getSimpleName(),"Could not connect to MQTT broker");
}
}
// subscribe to topic
public void subscribeToTopic(final String topic) {
try {
// subscribe topic from argument
mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.i(this.getClass().getSimpleName(),"Subscribed to " + topic);
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.i(this.getClass().getSimpleName(),"Could not subscribe to " + topic);
}
});
} catch (MqttException ex) {
Log.i(this.getClass().getSimpleName(),"Error while subscribing " + topic);
}
}
// set callback method
public void setCallback(MqttCallbackExtended callback) {
mqttAndroidClient.setCallback(callback);
}
}
Display More
In deiner MainActivity kannst du jetzt mit der Helper-Klasse ganz einfach Topics abonnieren (subscribe) und die Nachrichten auswerten:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
MqttHelper mqttHelper;
ArrayList<String> topics;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// define topics to subscribe
topics = new ArrayList<String>();
topics.add("sensors/batterylife");
topics.add("sensors/speed");
// start mqtt client
startMqtt("192.168.4.15", "1883");
}
private void startMqtt(String brokerHostname, String brokerPort){
mqttHelper = new MqttHelper(getApplicationContext(),brokerHostname, brokerPort, topics);
mqttHelper.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean b, String s) {
// subscribe topics when connected to broker
for (String topic : topics) {
mqttHelper.subscribeToTopic(topic);
}
}
@Override
public void connectionLost(Throwable throwable) {
}
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
// mqtt message has arrived
onMessageArrived(topic, mqttMessage.toString());
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
}
});
}
private void onMessageArrived(String topic, String message) {
Log.i(topic, message);
}
}
Display More
Wann immer der Pi eine Nachricht veröffentlicht, landest du in der letzten Methode onMessageArrived() und kannst das Topic und die Nachricht auslesen.
Die App kann auch eigene Nachrichten veröffentlichen, welche dann der Pi abonniert. Du kannst also in beide Richtungen kommunizieren.