alexCajas / EmbeddedMqttBroker

This is a Mqtt broker for embedded devices, developed in C++, FreeRTOS to use advanced multitasking capabilities, and arduino core. Tested in an Esp32 and esp8266.
https://github.com/alexCajas/EmbeddedMqttBroker
MIT License
71 stars 14 forks source link

Can't connect Android app as a client on a EmbeddedMqttBroker #16

Closed nachobgr closed 10 months ago

nachobgr commented 11 months ago

Hello! I'm working on a project where I have 6 clients (esp01) publishing, one broker (I need a microcontroller) and one client that is only suscribed (android app on a mobile phone).

I want to make a broker in a esp8266, esp32 or in a raspberry pi pico w. I started working with uMQTTBroker library [https://github.com/martin-ger/uMQTTBroker] but it has some issues with lwip variants which breaks with more than 5 clients and I couldn't fix it. I found EmbeddedMqttBroker really good but I don't no why I can connect the esp01 clients but no the app, while with uMQTTBroker it works. Another thing I would know is if you have an example of connecting a broker to another broker or connecting a client to two broker because I couldn't find the way to do it simultaneously.

I use this library for the android app: https://github.com/eclipse/paho.mqtt.java

alexCajas commented 11 months ago

Hi!, I use paho library to, but I don't have any trouble with that, I use this configuration for my android app:

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.mqttApp"
        minSdkVersion 29
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    namespace 'com.mqttApp'
}

dependencies {

    /*eclipse.paho.mqtt*/
    implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
    implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'androidx.work:work-runtime:2.5.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

There was a similar issue, but it was fixed. Can you descibe in more detail your issue?.

In the other hand, it is not possible to connect the same mqtt client object to two brokers, usually an mqtt client object is implemented using a tcp socket, this socket keep the conexion to only one ip and one port. But, in libraries like PubSubClient.h, you can set a callback function to process the incomming mqtt message, so, the closests you can get, is to use two mqtt clients to connect to differents brokers, and set the same callback function for both.

nachobgr commented 11 months ago

Thanks for the answer! Below I attach my configurations:

plugins {
    id 'com.android.application'
}

android {
    namespace 'com.example.pruebaaccesibilidad2'
    compileSdk 33

    defaultConfig {
        applicationId "com.example.pruebaaccesibilidad2"
        minSdk 24
        targetSdk 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.9.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
    implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
}

And this is the mqtt part in the app:

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

private MqttClient client;   //Cliente MQTT
conectarMQTT();

 //FUNCIONES MQTT
    @Override
    public void connectionLost(Throwable cause) {
        while (!client.isConnected()) {
            conectarMQTT();
        }
    }
    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {

    }
    public void conectarMQTT(){
        MemoryPersistence persistence = new MemoryPersistence();
        try {
            client = new MqttClient(BROKER_URL, Parametros.CLIENT_ID, persistence);
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setCleanSession(true);
            client.connect(connOpts);
            client.subscribe(Parametros.TOPIC + "/#");
            client.setCallback(this);

        } catch (MqttException e) {
            throw new RuntimeException(e);

        }
    }

What I want is to listen with the application, what are publishing other clients (they are already publishing on this broker) but I still couldn't suscribe the application (I can suscribe, for example, with mqtt-explorer).

alexCajas commented 11 months ago

I tried to use your paho version to connect to mosquitto broker, but it don't work, and wireshark never capture an mqtt packet sendded by andriod app, I don't now why it is happening, but if you change:

implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5' 

to

implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' 

probably works. Please, let me know if you can connect to broker affer this change!

nachobgr commented 11 months ago

I have my app working with mosquitto using the code I gave you before, the problem appears when I try to connect to this broker. I change the version of Paho but it still doesn't work.

alexCajas commented 10 months ago

Well, I can't reproduce your issue using 1.1.0 paho version, so, I will need more information, like wireshark captures and outputs of EmbeddedMqttBroker in verbose mode. Try with 1.1.0 paho version and this simple mqtt client app:


import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;

public class MainActivity extends AppCompatActivity {

    private MqttAndroidClient mqttAndroidClient;
    private final String brokerUri = "tcp://xxx.xxx.xxx.xxx:1883"; // url of broker

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button connectButton = findViewById(R.id.connectButton);

        connectButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                connectToBroker();
            }
        });

        setupMqttClient();
    }

    private void setupMqttClient() {

        String clientId = "clientId";
        mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), brokerUri, clientId);
    }

    private void connectToBroker() {
        MqttConnectOptions options = new MqttConnectOptions();
        options.setCleanSession(true);

        try {
            mqttAndroidClient.connect(options, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {

                    subscribeToTopic("tu/topic"); 
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {

                    exception.printStackTrace();
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    private void subscribeToTopic(String topic) {
        try {
            mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {

                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {

                    exception.printStackTrace();
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    private void setMqttCallback() {
        mqttAndroidClient.setCallback(new MqttCallback() {
            @Override
            public void connectionLost(Throwable cause) {

                cause.printStackTrace();
            }

            @Override
            public void messageArrived(String topic, org.eclipse.paho.client.mqttv3.MqttMessage message) throws Exception {

                String payload = new String(message.getPayload());

            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {

            }
        });
    }
}

Main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16dp"
    android:paddingTop="16dp"
    android:paddingRight="16dp"
    android:paddingBottom="16dp"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/connectButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Conectar a MQTT Broker"/>
</RelativeLayout>

Important, add to grandle this line:

implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

I don't have any issue using this, so I believe that are some wrong with your app configuration maybe?. Please, let me know if it works ;)

Leonidas00000 commented 10 months ago

Hello! I´m also working with nachobgr on this app, i tried to run the code u sent above but it´s still not working. I copied the part of the logcat where i can see the crash, maybe this can help to find the mistake. Thx for your time! _logcat___

FATAL EXCEPTION: main Process: com.example.pruebabroker, PID: 18172 java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/content/LocalBroadcastManager; at org.eclipse.paho.android.service.MqttAndroidClient.registerReceiver(MqttAndroidClient.java:450) at org.eclipse.paho.android.service.MqttAndroidClient.connect(MqttAndroidClient.java:428) at com.example.pruebabroker.MainActivity.connectToBroker(MainActivity.java:55) at com.example.pruebabroker.MainActivity.access$000(MainActivity.java:16) at com.example.pruebabroker.MainActivity$1.onClick(MainActivity.java:34) at android.view.View.performClick(View.java:7792) at android.widget.TextView.performClick(TextView.java:16112) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1202) at android.view.View.performClickInternal(View.java:7769) at android.view.View.access$3800(View.java:910) at android.view.View$PerformClick.run(View.java:30218) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135) Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.content.LocalBroadcastManager" on path: DexPathList[[zip file "/data/app/K5o5WwtKErcvQkTwI7b_Ag==/com.example.pruebabroker-PBpy71vgXKBR94CQcxjfGQ==/base.apk"],nativeLibraryDirectories=[/data/app/K5o5WwtKErcvQkTwI7b_Ag==/com.example.pruebabroker-PBpy71vgXKBR94CQcxjfGQ==/lib/arm64, /system/lib64, /system/system_ext/lib64]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259) at java.lang.ClassLoader.loadClass(ClassLoader.java:379) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) at org.eclipse.paho.android.service.MqttAndroidClient.registerReceiver(MqttAndroidClient.java:450)  at org.eclipse.paho.android.service.MqttAndroidClient.connect(MqttAndroidClient.java:428)  at com.example.pruebabroker.MainActivity.connectToBroker(MainActivity.java:55)  at com.example.pruebabroker.MainActivity.access$000(MainActivity.java:16)  at com.example.pruebabroker.MainActivity$1.onClick(MainActivity.java:34)  at android.view.View.performClick(View.java:7792)  at android.widget.TextView.performClick(TextView.java:16112)  at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1202)  at android.view.View.performClickInternal(View.java:7769)  at android.view.View.access$3800(View.java:910)  at android.view.View$PerformClick.run(View.java:30218)  at android.os.Handler.handleCallback(Handler.java:938)  at android.os.Handler.dispatchMessage(Handler.java:99)  at android.os.Looper.loopOnce(Looper.java:226)  at android.os.Looper.loop(Looper.java:313)  at android.app.ActivityThread.main(ActivityThread.java:8669)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)

alexCajas commented 10 months ago

you have issues with support.v4.content.LocalBroadCastManager class, it is used in paho library, but this class was deprecated in Androidx, There are differents solutions in web, but ususally people download paho library from github and changes to androidx manually: androidx.content.LocalBroadCastManager.

Good luck!