Apr 7

MQTT Service with MQTTCallback innerclass to handle messages

package com.simonecaruso.mqtt.service;
 
import org.eclipse.paho.client.mqttv3.IMqttAsyncClient;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
 
import com.simonecaruso.mqtt.FullscreenActivityTest;
 
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
 
public class MQTTService extends Service {
 
    private static final String TAG = "MQTTService";
    private static boolean hasWifi = false;
    private static boolean hasMmobile = false;
    private Thread thread;
    private ConnectivityManager mConnMan;
    private volatile IMqttAsyncClient mqttClient;
    private String deviceId; 
 
    class MQTTBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            IMqttToken token;
            boolean hasConnectivity = false;
            boolean hasChanged = false;
            NetworkInfo infos[] = mConnMan.getAllNetworkInfo();
 
            for (int i = 0; i < infos.length; i++){
                if (infos[i].getTypeName().equalsIgnoreCase("MOBILE")){
                    if((infos[i].isConnected() != hasMmobile)){
                        hasChanged = true;
                        hasMmobile = infos[i].isConnected();
                    }
                    Log.d(TAG, infos[i].getTypeName() + " is " + infos[i].isConnected());
                } else if ( infos[i].getTypeName().equalsIgnoreCase("WIFI") ){ 
                    if((infos[i].isConnected() != hasWifi)){
                        hasChanged = true;
                        hasWifi = infos[i].isConnected();
                    }
                    Log.d(TAG, infos[i].getTypeName() + " is " + infos[i].isConnected());
                }
            }
 
            hasConnectivity = hasMmobile || hasWifi;
            Log.v(TAG, "hasConn: " + hasConnectivity + " hasChange: " + hasChanged + " - "+(mqttClient == null || !mqttClient.isConnected()));
            if (hasConnectivity && hasChanged && (mqttClient == null || !mqttClient.isConnected())) {
                doConnect();
            } else if (!hasConnectivity && mqttClient != null && mqttClient.isConnected()) {
                Log.d(TAG, "doDisconnect()");
                try {
                    token = mqttClient.disconnect();
                    token.waitForCompletion(1000);
                } catch (MqttException e) {
                    e.printStackTrace();
                }
            }
        }
    };
 
    public class MQTTBinder extends Binder {
        public MQTTService getService(){
        	return MQTTService.this;
        }
    }
 
    @Override
    public void onCreate() {
        IntentFilter intentf = new IntentFilter();
        setClientID();
        intentf.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(new MQTTBroadcastReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        mConnMan = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
    }
 
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        Log.d(TAG, "onConfigurationChanged()");
        android.os.Debug.waitForDebugger();
        super.onConfigurationChanged(newConfig);
 
    }
 
    private void setClientID(){
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        WifiInfo wInfo = wifiManager.getConnectionInfo();
        deviceId = wInfo.getMacAddress();
        if(deviceId == null){
            deviceId = MqttAsyncClient.generateClientId();
        }
    }
 
    private void doConnect(){
        Log.d(TAG, "doConnect()");
        IMqttToken token;
        MqttConnectOptions options = new MqttConnectOptions();
        options.setCleanSession(true);
        try {
            mqttClient = new MqttAsyncClient("tcp://mqtt.example.com:1883", deviceId, new MemoryPersistence());
            token = mqttClient.connect();
            token.waitForCompletion(3500);
            mqttClient.setCallback(new MqttEventCallback());
            token = mqttClient.subscribe("testtopic", 0);
            token.waitForCompletion(5000);
        } catch (MqttSecurityException e) {
            e.printStackTrace();
        } catch (MqttException e) {
            switch (e.getReasonCode()) {
            case MqttException.REASON_CODE_BROKER_UNAVAILABLE:
            case MqttException.REASON_CODE_CLIENT_TIMEOUT:
            case MqttException.REASON_CODE_CONNECTION_LOST:
            case MqttException.REASON_CODE_SERVER_CONNECT_ERROR:
                Log.v(TAG, "c" +e.getMessage());
                e.printStackTrace();
                break;
            case MqttException.REASON_CODE_FAILED_AUTHENTICATION:
                Intent i = new Intent("RAISEALLARM");
                i.putExtra("ALLARM", e);
                Log.e(TAG, "b"+ e.getMessage());
                break;
            default:
                Log.e(TAG, "a" + e.getMessage());
            }
        }
    }
 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v(TAG, "onStartCommand()");
        return START_STICKY;
    }
 
    private class MqttEventCallback implements MqttCallback {
 
        @Override
        public void connectionLost(Throwable arg0) {
 
 
        }
 
        @Override
        public void deliveryComplete(IMqttDeliveryToken arg0) {
 
        }
 
        @Override
        @SuppressLint("NewApi")
        public void messageArrived(String topic, final MqttMessage msg) throws Exception {
        	Log.i(TAG, "Message arrived from topic" + topic);
        	Handler h = new Handler(getMainLooper());
        	h.post(new Runnable() {
        		@Override
        		public void run() {
        		    Intent launchA = new Intent(MQTTService.this, FullscreenActivityTest.class);
        		    launchA.putExtra("message", msg.getPayload());
        		    //TODO write somethinkg that has some sense
        		    if(Build.VERSION.SDK_INT >= 11){
        		        launchA.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_REORDER_TO_FRONT|Intent.FLAG_ACTIVITY_NO_ANIMATION);
        		    } /*else {
        		        launchA.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        		    }*/
        		    startActivity(launchA);
        			Toast.makeText(getApplicationContext(), "MQTT Message:\n" + new String(msg.getPayload()), Toast.LENGTH_SHORT).show();
        		}
        	});
        }
    }
 
    public String getThread(){
        return Long.valueOf(thread.getId()).toString();
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind called");
        return null;
    }
 
}

13 comments so far...

  • sks Said on April 18th, 2015 at 18:17:

    I tried couple of examples for Android. Most of them did not work for me. Samples were working are too complicated. I got scared when I saw them. This is really really fantastic. Simple and works like a charm. Thank you very much!!!! Saved my days…

  • Pixel Said on May 12th, 2015 at 12:59:

    Thank you very much

    Almost four weeks, I tried to find a way to keep MQTT service running even if the app closed so the widget can be updated, the paho sample seemed to not work when the activity shut down.

    but yours is very simple, clear and exactly perfect thank you!

  • dk Said on May 27th, 2015 at 07:05:

    I get the below error when i try to run this code from my application. I added this service into android manifest file and started my application. It throws the below error. Can you help?

    D/MQTTService﹕ WIFI is true
    V/MQTTService﹕ hasConn: true hasChange: true – true
    D/MQTTService﹕ doConnect()
    V/MQTTService﹕ cTimed out waiting for a response from the server
    W/System.err﹕ at org.eclipse.paho.client.mqttv3.internal.Token.waitForCompletion(Token.java:112)
    W/System.err﹕ at org.eclipse.paho.client.mqttv3.MqttToken.waitForCompletion(MqttToken.java:67)
    W/System.err﹕ at com.trimble.fsm.fieldmaster.service.MQTTService.doConnect(MQTTService.java:124)
    W/System.err﹕ at com.trimble.fsm.fieldmaster.service.MQTTService.access$400(MQTTService.java:34)
    W/System.err﹕ at com.trimble.fsm.fieldmaster.service.MQTTService$MQTTBroadcastReceiver.onReceive(MQTTService.java:71)

  • Pixel Said on June 1st, 2015 at 12:02:

    @dk I’m newbie but it seems your error related to the server (time out waiting for response), try other server: iot.eclipse.org OR test.mosquitto.org and see..
    Make sure that your server is working, if so you may need to increase the time out.

  • Nnadi Ugwumsinachi Said on October 29th, 2015 at 06:51:

    Nice code but you didn’t specify the permissions for the Android manifest.. Sorry am still new to this..

  • Geurt Lagemaat Said on February 1st, 2016 at 21:43:

    Great, works really well, thanks!

  • Shibin Said on February 13th, 2016 at 04:10:

    Ohh.. this what exactly I need. You are a genius bro

  • BM Said on February 18th, 2016 at 17:18:

    Same story as the rest :P New to Android development and struggling to get an MQTT app of the ground. this example is the closest I’ve come to understanding how the Paho library works, But still cant seem to get it to work properly. Followed this example and trying to connect to mosquittos test broker and keep getting this:

    D/MQTTService: MOBILE is true
    D/MQTTService: WIFI is false
    V/MQTTService: hasConn: true hasChange: true – true
    D/MQTTService: doConnect()
    E/MQTTService: aMqttException

    I monitored my network traffic and it isn’t even trying to send any data to the server. Not to sure what I’m doing wrong

  • BM Said on February 18th, 2016 at 17:27:

    Lol i’m a noob, didnt add permission INTERNET, works now thank you for an awesome example

  • BeeGee Said on May 3rd, 2016 at 15:01:

    Great code snippet, got it to work without problems.
    Do you have a code snippet for publishing a message with MQTT as well?

  • BeeGee Said on May 3rd, 2016 at 16:16:

    Never mind, found a solution to put into my main appby using your code and change it to publishing:
    public void doPublish(String topic, String payload){
    if (BuildConfig.DEBUG) Log.d(DEBUG_LOG_TAG, “doPublish()”);
    if (MQTTService.mqttClient == null) { // If service is not (yet) active, don’t publish
    return;
    }
    IMqttToken token;
    try {
    byte[] encodedPayload;
    encodedPayload = payload.getBytes(“UTF-8”);
    MqttMessage message = new MqttMessage(encodedPayload);
    token = MQTTService.mqttClient.publish(topic, message);
    token.waitForCompletion(5000);
    } catch (MqttSecurityException | UnsupportedEncodingException e) {
    e.printStackTrace();
    } catch (MqttException e) {
    switch (e.getReasonCode()) {
    case MqttException.REASON_CODE_BROKER_UNAVAILABLE:
    case MqttException.REASON_CODE_CLIENT_TIMEOUT:
    case MqttException.REASON_CODE_CONNECTION_LOST:
    case MqttException.REASON_CODE_SERVER_CONNECT_ERROR:
    if (BuildConfig.DEBUG) Log.d(DEBUG_LOG_TAG, “c” +e.getMessage());
    e.printStackTrace();
    break;
    case MqttException.REASON_CODE_FAILED_AUTHENTICATION:
    Intent i = new Intent(“RAISEALLARM”);
    i.putExtra(“ALLARM”, e);
    if (BuildConfig.DEBUG) Log.d(DEBUG_LOG_TAG, “b”+ e.getMessage());
    break;
    default:
    if (BuildConfig.DEBUG) Log.d(DEBUG_LOG_TAG, “a” + e.getMessage());
    }
    }
    }

  • Dhina Said on August 24th, 2016 at 07:26:

    How to stop receiving messaging temperarily

  • Pratibha Said on September 14th, 2016 at 09:44:

    Its very very helpful thank you!

leave a reply