Difference between revisions of "MQTT: Android Client Simple"

From OnnoWiki
Jump to navigation Jump to search
Line 6: Line 6:
  
 
Software used in this tutorial, be sure to have them installed:
 
Software used in this tutorial, be sure to have them installed:
-Android Studio
+
* Android Studio
-Python 2.7
+
* Python 2.7
  
 
Outline what I will be covering:
 
Outline what I will be covering:
1. Sorting out MQTT dependencies in Android Studio
+
# Sorting out MQTT dependencies in Android Studio
2. Setting up a cloud MQTT broker in CloudMQTT
+
# Setting up a cloud MQTT broker in CloudMQTT
3. Setting up a basic MQTT client and service in Android
+
# Setting up a basic MQTT client and service in Android
4. Setting up a mock data publisher with Python
+
# Setting up a mock data publisher with Python
5. Visualizing data with MPAndroidCharts library
+
# Visualizing data with MPAndroidCharts library
  
  
Line 25: Line 25:
 
According to official Paho Eclipse Github, we can install the library to our app using Maven, Gradle, or from source, but in this tutorial I will be using Gradle. So to sort out the dependency, simply add these lines to our build.gradle of our Android Studio project.
 
According to official Paho Eclipse Github, we can install the library to our app using Maven, Gradle, or from source, but in this tutorial I will be using Gradle. So to sort out the dependency, simply add these lines to our build.gradle of our Android Studio project.
  
repositories {
+
repositories {
    maven {
+
    maven {
        url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
+
        url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
    }
+
    }
}
+
}
 +
 
 
And in our build.gradle of our Android app.
 
And in our build.gradle of our Android app.
  
dependencies {
+
dependencies {
    compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
+
    compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
    compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
+
    compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}
+
}
 +
 
 
A notification will come up about our Gradle configuration being changed, if so click Sync Now. Oh, and please to have your internet on in this process or the Gradle sync will fail.
 
A notification will come up about our Gradle configuration being changed, if so click Sync Now. Oh, and please to have your internet on in this process or the Gradle sync will fail.
  
Line 44: Line 46:
 
There are a couple of cloud MQTT brokers that are available in the internet right now, like CloudMQTT and HiveMQ, but in this tutorial, I will teach how to set up a free private cloud MQTT broker using CloudMQTT. You can sign up for a free account at https://customer.cloudmqtt.com/login, just follow the instructions to sign up.
 
There are a couple of cloud MQTT brokers that are available in the internet right now, like CloudMQTT and HiveMQ, but in this tutorial, I will teach how to set up a free private cloud MQTT broker using CloudMQTT. You can sign up for a free account at https://customer.cloudmqtt.com/login, just follow the instructions to sign up.
  
cloudmqtt
+
cloudmqtt
  
 
Next, you will be redirected to the CloudMQTT instances page. Click the + Create button to create a new CloudMQTT instance. Now you would be in the Create new CloudMQTT instance page. Insert an instance name, choose any Data center available, and make sure for the “Plan” choose the “Cute Cat”, because we like free stuff.
 
Next, you will be redirected to the CloudMQTT instances page. Click the + Create button to create a new CloudMQTT instance. Now you would be in the Create new CloudMQTT instance page. Insert an instance name, choose any Data center available, and make sure for the “Plan” choose the “Cute Cat”, because we like free stuff.
  
instance
+
instance
  
 
In the next page, you can see your new created instance, click the details button of that instance. This is what you will see, (never mind the red scribbles):
 
In the next page, you can see your new created instance, click the details button of that instance. This is what you will see, (never mind the red scribbles):
  
account
+
account
  
 
Done! We have our own private cloud MQTT broker. Later we will use those credentials to connect our MQTT Android client to the broker.
 
Done! We have our own private cloud MQTT broker. Later we will use those credentials to connect our MQTT Android client to the broker.
Line 60: Line 62:
 
Before we code anything, we need to set up our AndroidManifest.xml file to let our app have permissions to access the Internet, access the network state, and let our app to stay alive as a service. Add these lines before the opening <application tag in our AndroidManifest.xml.
 
Before we code anything, we need to set up our AndroidManifest.xml file to let our app have permissions to access the Internet, access the network state, and let our app to stay alive as a service. Add these lines before the opening <application tag in our AndroidManifest.xml.
  
<uses-permission android:name="android.permission.INTERNET" />
+
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
+
<uses-permission android:name="android.permission.WAKE_LOCK"/>
 +
 
 
And register our MQTT Android Service in our app before the closing application tag using this piece of code:
 
And register our MQTT Android Service in our app before the closing application tag using this piece of code:
<service android:name="org.eclipse.paho.android.service.MqttService" />
+
 
 +
  <service android:name="org.eclipse.paho.android.service.MqttService" />
 +
 
 
So it should look like this: manifest Ok great, now lets begin to code shall we.
 
So it should look like this: manifest Ok great, now lets begin to code shall we.
  
Line 71: Line 76:
 
Add the following code inside our MqttHelper class, please adjust the credentials (serverUri, username, password) accordingly with your CloudMQTT instance from the previous step. Please note: the format of the server URI is tcp://server:port
 
Add the following code inside our MqttHelper class, please adjust the credentials (serverUri, username, password) accordingly with your CloudMQTT instance from the previous step. Please note: the format of the server URI is tcp://server:port
  
public class MqttHelper {
+
public class MqttHelper {
    public MqttAndroidClient mqttAndroidClient;
+
    public MqttAndroidClient mqttAndroidClient;
 
+
    final String serverUri = "tcp://m12.cloudmqtt.com:11111";
+
    final String serverUri = "tcp://m12.cloudmqtt.com:11111";  
 
+
    final String clientId = "ExampleAndroidClient";
+
    final String clientId = "ExampleAndroidClient";
    final String subscriptionTopic = "sensor/+";
+
    final String subscriptionTopic = "sensor/+";  
 
+
    final String username = "xxxxxxx";
+
    final String username = "xxxxxxx";
    final String password = "yyyyyyyyyy";
+
    final String password = "yyyyyyyyyy";
 
+
    public MqttHelper(Context context){
+
    public MqttHelper(Context context){
        mqttAndroidClient = new MqttAndroidClient(context, serverUri, clientId);
+
        mqttAndroidClient = new MqttAndroidClient(context, serverUri, clientId);
        mqttAndroidClient.setCallback(new MqttCallbackExtended() {
+
        mqttAndroidClient.setCallback(new MqttCallbackExtended() {
            @Override
 
            public void connectComplete(boolean b, String s) {
 
                Log.w("mqtt", s);
 
            }
 
 
 
            @Override
 
            public void connectionLost(Throwable throwable) {
 
 
 
            }
 
 
 
            @Override
 
            public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
 
                Log.w("Mqtt", mqttMessage.toString());
 
            }
 
 
 
            @Override
 
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
 
 
 
            }
 
        });
 
        connect();
 
    }
 
 
 
    public void setCallback(MqttCallbackExtended callback) {
 
        mqttAndroidClient.setCallback(callback);
 
    }
 
 
 
    private void connect(){
 
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
 
        mqttConnectOptions.setAutomaticReconnect(true);
 
        mqttConnectOptions.setCleanSession(false);
 
        mqttConnectOptions.setUserName(username);
 
        mqttConnectOptions.setPassword(password.toCharArray());
 
 
 
        try {
 
 
 
            mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
 
                @Override
 
                public void onSuccess(IMqttToken asyncActionToken) {
 
 
 
                    DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
 
                    disconnectedBufferOptions.setBufferEnabled(true);
 
                    disconnectedBufferOptions.setBufferSize(100);
 
                    disconnectedBufferOptions.setPersistBuffer(false);
 
                    disconnectedBufferOptions.setDeleteOldestMessages(false);
 
                    mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
 
                    subscribeToTopic();
 
                }
 
 
 
                @Override
 
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
 
                    Log.w("Mqtt", "Failed to connect to: " + serverUri + exception.toString());
 
                }
 
            });
 
 
 
 
 
        } catch (MqttException ex){
 
            ex.printStackTrace();
 
        }
 
    }
 
 
 
 
 
    private void subscribeToTopic() {
 
        try {
 
            mqttAndroidClient.subscribe(subscriptionTopic, 0, null, new IMqttActionListener() {
 
                @Override
 
                public void onSuccess(IMqttToken asyncActionToken) {
 
                    Log.w("Mqtt","Subscribed!");
 
                }
 
 
 
                @Override
 
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
 
                    Log.w("Mqtt", "Subscribed fail!");
 
                }
 
            });
 
 
 
        } catch (MqttException ex) {
 
            System.err.println("Exception whilst subscribing");
 
            ex.printStackTrace();
 
        }
 
    }
 
}
 
Now go to our activity_main.xml or any other activity you may have created, and you may see the Hello World text view which is added by default by Android Studio, let’s give it an ID so we can access it in our Java code, here I give it an ID dataReceived.
 
 
 
id
 
 
 
So our MainActivity java class should look like this, let Android Studio resolve the imports if needed.
 
 
 
public class MainActivity extends AppCompatActivity {
 
    MqttHelper mqttHelper;
 
 
 
    TextView dataReceived;
 
 
 
    @Override
 
 
 
    protected void onCreate(Bundle savedInstanceState) {
 
        super.onCreate(savedInstanceState);
 
        setContentView(R.layout.activity_main);
 
 
 
        dataReceived = (TextView) findViewById(R.id.dataReceived);
 
 
 
        startMqtt();
 
    }
 
 
 
    private void startMqtt(){
 
        mqttHelper = new MqttHelper(getApplicationContext());
 
        mqttHelper.setCallback(new MqttCallbackExtended() {
 
 
             @Override
 
             @Override
 
             public void connectComplete(boolean b, String s) {
 
             public void connectComplete(boolean b, String s) {
 
+
                Log.w("mqtt", s);
             }
+
             }  
 
+
 
             @Override
 
             @Override
             public void connectionLost(Throwable throwable) {
+
             public void connectionLost(Throwable throwable) {  
 
+
 
             }
 
             }
 
+
 
             @Override
 
             @Override
 
             public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
 
             public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
                 Log.w("Debug",mqttMessage.toString());
+
                 Log.w("Mqtt", mqttMessage.toString());
                dataReceived.setText(mqttMessage.toString());
 
 
             }
 
             }
 
+
 
             @Override
 
             @Override
             public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
+
             public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {  
 
+
 
             }
 
             }
 
         });
 
         });
 +
        connect();
 +
    }
 +
 +
    public void setCallback(MqttCallbackExtended callback) {
 +
        mqttAndroidClient.setCallback(callback);
 
     }
 
     }
 +
 +
    private void connect(){
 +
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
 +
        mqttConnectOptions.setAutomaticReconnect(true);
 +
        mqttConnectOptions.setCleanSession(false);
 +
        mqttConnectOptions.setUserName(username);
 +
        mqttConnectOptions.setPassword(password.toCharArray());
 +
 +
        try {
 +
 +
            mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
 +
                @Override
 +
                public void onSuccess(IMqttToken asyncActionToken) {
 +
 +
                    DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
 +
                    disconnectedBufferOptions.setBufferEnabled(true);
 +
                    disconnectedBufferOptions.setBufferSize(100);
 +
                    disconnectedBufferOptions.setPersistBuffer(false);
 +
                    disconnectedBufferOptions.setDeleteOldestMessages(false);
 +
                    mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
 +
                    subscribeToTopic();
 +
                }
 +
 +
                @Override
 +
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
 +
                    Log.w("Mqtt", "Failed to connect to: " + serverUri + exception.toString());
 +
                }
 +
            });
 +
 +
        } catch (MqttException ex){
 +
            ex.printStackTrace();
 +
        }
 +
    }
 +
 +
 +
    private void subscribeToTopic() {
 +
        try {
 +
            mqttAndroidClient.subscribe(subscriptionTopic, 0, null, new IMqttActionListener() {
 +
                @Override
 +
                public void onSuccess(IMqttToken asyncActionToken) {
 +
                    Log.w("Mqtt","Subscribed!");
 +
                }
 +
 +
                @Override
 +
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
 +
                    Log.w("Mqtt", "Subscribed fail!");
 +
                }
 +
            });
 +
 +
        } catch (MqttException ex) {
 +
            System.err.println("Exception whilst subscribing");
 +
            ex.printStackTrace();
 +
        }
 +
    }
 +
}
 +
 +
Now go to our activity_main.xml or any other activity you may have created, and you may see the Hello World text view which is added by default by Android Studio, let’s give it an ID so we can access it in our Java code, here I give it an ID dataReceived.
 +
 +
id
 +
 +
So our MainActivity java class should look like this, let Android Studio resolve the imports if needed.
 +
 +
public class MainActivity extends AppCompatActivity {
 +
    MqttHelper mqttHelper;
 +
 +
    TextView dataReceived;
 +
 +
    @Override
 +
 +
    protected void onCreate(Bundle savedInstanceState) {
 +
          super.onCreate(savedInstanceState);
 +
          setContentView(R.layout.activity_main); 
 +
 +
          dataReceived = (TextView) findViewById(R.id.dataReceived);
 +
 +
          startMqtt();
 +
    }
 +
 +
    private void startMqtt(){
 +
          mqttHelper = new MqttHelper(getApplicationContext());
 +
          mqttHelper.setCallback(new MqttCallbackExtended() {
 +
              @Override
 +
              public void connectComplete(boolean b, String s) {
 +
 +
              }
 +
 +
              @Override
 +
              public void connectionLost(Throwable throwable) {
 +
 +
              }
 +
 
 +
              @Override
 +
              public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
 +
                  Log.w("Debug",mqttMessage.toString());
 +
                  dataReceived.setText(mqttMessage.toString());
 +
              }
 +
 +
              @Override
 +
              public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
 +
 +
              }
 +
          });
 +
      }
 +
 
So what we do here is set the callback functions for the MQTT client, the only callback function we need right now is the messageArrived function which is called every time the MQTT client receives a message. Whenever a message is received, it will set the text of our TextView in our activity according to the message received.
 
So what we do here is set the callback functions for the MQTT client, the only callback function we need right now is the messageArrived function which is called every time the MQTT client receives a message. Whenever a message is received, it will set the text of our TextView in our activity according to the message received.
  
Line 220: Line 226:
 
Go back to your CloudMQTT instance and open the Websocket UI. In the topic input, enter the topic set in our app, in my case is “sensor/+”. If you have done your research about MQTT, you may recall that the “+” sign is a wildcard which simply means “any subtopic”. So let’s try sending data with the “sensor/temp” topic.
 
Go back to your CloudMQTT instance and open the Websocket UI. In the topic input, enter the topic set in our app, in my case is “sensor/+”. If you have done your research about MQTT, you may recall that the “+” sign is a wildcard which simply means “any subtopic”. So let’s try sending data with the “sensor/temp” topic.
  
send
+
send
  
 
And in our app:
 
And in our app:
  
Screenshot_2017-05-11-05-35-49-859_com.frost.mqtttutorial
+
Screenshot_2017-05-11-05-35-49-859_com.frost.mqtttutorial
  
 
Magic! It’s like our computer and phones are telepathic right now!
 
Magic! It’s like our computer and phones are telepathic right now!
Line 240: Line 246:
 
First you will need to install the paho.mqtt client library in python.
 
First you will need to install the paho.mqtt client library in python.
  
pip install paho-mqtt
+
pip install paho-mqtt
  
 
And the code:
 
And the code:
  
import json
+
import json
import paho.mqtt.client as mqtt
+
import paho.mqtt.client as mqtt
import random
+
import random
import time
+
import time
import threading
+
import threading
import sys
+
import sys
 
+
mqttc = mqtt.Client("client1", clean_session=False)
+
mqttc = mqtt.Client("client1", clean_session=False)
mqttc.username_pw_set("#User", "#password")
+
mqttc.username_pw_set("#User", "#password")
mqttc.connect("#Server", #port, 60)
+
mqttc.connect("#Server", #port, 60)
 
+
 
+
def pub():
def pub():
+
    mqttc.publish("sensor/temp", payload=random.normalvariate(30, 0.5), qos=0)
    mqttc.publish("sensor/temp", payload=random.normalvariate(30, 0.5), qos=0)
+
    threading.Timer(1, pub).start()
    threading.Timer(1, pub).start()
 
  
 
pub()
 
pub()
Line 273: Line 278:
 
In our project’s build.gradle below the previous MQTT dependency, add `
 
In our project’s build.gradle below the previous MQTT dependency, add `
  
maven { url "https://jitpack.io" }
+
maven { url "https://jitpack.io" }
 +
 
 
So now it should look like:
 
So now it should look like:
  
maven {
+
maven {
    url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
+
    url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
}
+
}
maven { url "https://jitpack.io" }
+
maven { url "https://jitpack.io" }
 +
 
 
and our app’s build.gradle add it below our MQTT dependency too:
 
and our app’s build.gradle add it below our MQTT dependency too:
  
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
+
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
 +
 
 
so now it should look like:
 
so now it should look like:
  
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
+
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
+
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
+
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
 +
 
 
Okay gradle, Sync Now!!
 
Okay gradle, Sync Now!!
  
 
Now add a new Java Class in our helpers package named ChartHelper​, with the following code inside:
 
Now add a new Java Class in our helpers package named ChartHelper​, with the following code inside:
  
public class ChartHelper implements OnChartValueSelectedListener {
+
public class ChartHelper implements OnChartValueSelectedListener {
 
+
    private LineChart mChart;
+
    private LineChart mChart;  
 
+
    public ChartHelper(LineChart chart) {
+
    public ChartHelper(LineChart chart) {
        mChart = chart;
+
        mChart = chart;
        mChart.setOnChartValueSelectedListener(this);
+
        mChart.setOnChartValueSelectedListener(this);
 
+
        // no description text
+
        // no description text
        mChart.setNoDataText("You need to provide data for the chart.");
+
        mChart.setNoDataText("You need to provide data for the chart.");
 
+
        // enable touch gestures
+
        // enable touch gestures
        mChart.setTouchEnabled(true);
+
        mChart.setTouchEnabled(true);
 
+
        // enable scaling and dragging
+
        // enable scaling and dragging
        mChart.setDragEnabled(true);
+
        mChart.setDragEnabled(true);
        mChart.setScaleEnabled(true);
+
        mChart.setScaleEnabled(true);
        mChart.setDrawGridBackground(false);
+
        mChart.setDrawGridBackground(false);
 
+
        // if disabled, scaling can be done on x- and y-axis separately
+
        // if disabled, scaling can be done on x- and y-axis separately
        mChart.setPinchZoom(true);
+
        mChart.setPinchZoom(true);
 
+
        // set an alternative background color
+
        // set an alternative background color
        mChart.setBackgroundColor(Color.WHITE);
+
        mChart.setBackgroundColor(Color.WHITE);
        mChart.setBorderColor(Color.rgb(67,164,34));
+
        mChart.setBorderColor(Color.rgb(67,164,34));
 
+
 
+
        LineData data = new LineData();
+
        LineData data = new LineData();
        data.setValueTextColor(Color.WHITE);
+
        data.setValueTextColor(Color.WHITE);
 
+
        // add empty data
+
        // add empty data
        mChart.setData(data);
+
        mChart.setData(data);  
 
+
        // get the legend (only possible after setting data)
+
        // get the legend (only possible after setting data)
        Legend l = mChart.getLegend();
+
        Legend l = mChart.getLegend();
 
+
        // modify the legend ...
+
        // modify the legend ...
        // l.setPosition(LegendPosition.LEFT_OF_CHART);
+
        // l.setPosition(LegendPosition.LEFT_OF_CHART);
        l.setForm(Legend.LegendForm.LINE);
+
        l.setForm(Legend.LegendForm.LINE);
        l.setTypeface(Typeface.MONOSPACE);
+
        l.setTypeface(Typeface.MONOSPACE);
        l.setTextColor(Color.rgb(67, 164, 34));
+
        l.setTextColor(Color.rgb(67, 164, 34));  
 
+
        XAxis xl = mChart.getXAxis();
+
        XAxis xl = mChart.getXAxis();
        xl.setTypeface(Typeface.MONOSPACE);
+
        xl.setTypeface(Typeface.MONOSPACE);
        xl.setTextColor(Color.rgb(67, 164, 34));
+
        xl.setTextColor(Color.rgb(67, 164, 34));
        xl.setDrawGridLines(false);
+
        xl.setDrawGridLines(false);
        xl.setAvoidFirstLastClipping(true);
+
        xl.setAvoidFirstLastClipping(true);
        xl.setEnabled(true);
+
        xl.setEnabled(true);
 
+
        YAxis leftAxis = mChart.getAxisLeft();
+
        YAxis leftAxis = mChart.getAxisLeft();
        leftAxis.setTypeface(Typeface.MONOSPACE);
+
        leftAxis.setTypeface(Typeface.MONOSPACE);
        leftAxis.setTextColor(Color.rgb(67, 164, 34));
+
        leftAxis.setTextColor(Color.rgb(67, 164, 34));
 
+
        leftAxis.setDrawGridLines(true);
+
        leftAxis.setDrawGridLines(true);
 
+
        YAxis rightAxis = mChart.getAxisRight();
+
        YAxis rightAxis = mChart.getAxisRight();
        rightAxis.setEnabled(false);
+
        rightAxis.setEnabled(false);  
 
+
    }
+
    }
 
+
    public void setChart(LineChart chart){ this.mChart = chart; }
+
    public void setChart(LineChart chart){ this.mChart = chart; }
 
+
    public void addEntry(float value) {
+
    public void addEntry(float value) {  
 
+
        LineData data = mChart.getData();
+
        LineData data = mChart.getData();
 
+
        if (data != null){
+
        if (data != null){
 +
 +
            ILineDataSet set = data.getDataSetByIndex(0);
 +
            // set.addEntry(...); // can be called as well
 +
 +
            if (set == null) {
 +
                set = createSet();
 +
                data.addDataSet(set);
 +
            }
 +
 +
            data.addEntry(new Entry(set.getEntryCount(),value),0);
 +
            Log.w("chart", set.getEntryForIndex(set.getEntryCount()-1).toString());
 +
 +
            data.notifyDataChanged();
 +
 +
            // let the chart know it's data has changed
 +
            mChart.notifyDataSetChanged();
 +
 +
            // limit the number of visible entries
 +
            mChart.setVisibleXRangeMaximum(10);
 +
            // mChart.setVisibleYRange(30, AxisDependency.LEFT);
 +
 +
            // move to the latest entry
 +
            mChart.moveViewTo(set.getEntryCount()-1, data.getYMax(), YAxis.AxisDependency.LEFT);
 +
 +
            // this automatically refreshes the chart (calls invalidate())
 +
            // mChart.moveViewTo(data.getXValCount()-7, 55f,
 +
            // AxisDependency.LEFT);
 +
        }
 +
    }
 +
 +
    private LineDataSet createSet() {
 +
        LineDataSet set = new LineDataSet(null, "Data");
 +
        set.setAxisDependency(YAxis.AxisDependency.LEFT);
 +
        set.setColor(Color.rgb(67, 164, 34));
 +
        //set.setCircleColor(Color.WHITE);
 +
        set.setLineWidth(2f);
 +
        //set.setCircleRadius(4f);
 +
        set.setFillAlpha(65);
 +
        set.setFillColor(Color.rgb(67, 164, 34));
 +
        set.setHighLightColor(Color.rgb(67, 164, 34));
 +
        set.setValueTextColor(Color.rgb(67, 164, 34));
 +
        set.setValueTextSize(9f);
 +
        set.setDrawValues(false);
 +
        return set;
 +
    }
 +
 +
    @Override
 +
    public void onValueSelected(Entry e, Highlight h) {
 +
        Log.i("Entry selected", e.toString());
 +
    }
 +
 +
    @Override
 +
    public void onNothingSelected(){
 +
        Log.i("Nothing selected", "Nothing selected.");
 +
    }
  
            ILineDataSet set = data.getDataSetByIndex(0);
+
}
            // set.addEntry(...); // can be called as well
 
  
            if (set == null) {
 
                set = createSet();
 
                data.addDataSet(set);
 
            }
 
 
            data.addEntry(new Entry(set.getEntryCount(),value),0);
 
            Log.w("chart", set.getEntryForIndex(set.getEntryCount()-1).toString());
 
 
            data.notifyDataChanged();
 
 
            // let the chart know it's data has changed
 
            mChart.notifyDataSetChanged();
 
 
            // limit the number of visible entries
 
            mChart.setVisibleXRangeMaximum(10);
 
            // mChart.setVisibleYRange(30, AxisDependency.LEFT);
 
 
            // move to the latest entry
 
            mChart.moveViewTo(set.getEntryCount()-1, data.getYMax(), YAxis.AxisDependency.LEFT);
 
 
            // this automatically refreshes the chart (calls invalidate())
 
            // mChart.moveViewTo(data.getXValCount()-7, 55f,
 
            // AxisDependency.LEFT);
 
        }
 
    }
 
 
    private LineDataSet createSet() {
 
        LineDataSet set = new LineDataSet(null, "Data");
 
        set.setAxisDependency(YAxis.AxisDependency.LEFT);
 
        set.setColor(Color.rgb(67, 164, 34));
 
        //set.setCircleColor(Color.WHITE);
 
        set.setLineWidth(2f);
 
        //set.setCircleRadius(4f);
 
        set.setFillAlpha(65);
 
        set.setFillColor(Color.rgb(67, 164, 34));
 
        set.setHighLightColor(Color.rgb(67, 164, 34));
 
        set.setValueTextColor(Color.rgb(67, 164, 34));
 
        set.setValueTextSize(9f);
 
        set.setDrawValues(false);
 
        return set;
 
    }
 
 
    @Override
 
    public void onValueSelected(Entry e, Highlight h) {
 
        Log.i("Entry selected", e.toString());
 
    }
 
 
    @Override
 
    public void onNothingSelected(){
 
        Log.i("Nothing selected", "Nothing selected.");
 
    }
 
 
}
 
 
Ok so let Android Studio resolve the imports for you.
 
Ok so let Android Studio resolve the imports for you.
  
 
Now add the chart layout to our activity_main.xml, by using the text editor. Add the below code under our <TextView layout:
 
Now add the chart layout to our activity_main.xml, by using the text editor. Add the below code under our <TextView layout:
  
<com.github.mikephil.charting.charts.LineChart
+
<com.github.mikephil.charting.charts.LineChart
        android:id="@+id/chart"
+
        android:id="@+id/chart"
        android:layout_width="match_parent"
+
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
+
        android:layout_height="match_parent" />
 +
 
 
Go back to the Design editor, and rearrange the layouts accordingly (or maybe any other way you want).
 
Go back to the Design editor, and rearrange the layouts accordingly (or maybe any other way you want).
  
layout.JPG
+
layout.JPG
  
 
So as we can see, our chart is a Line Chart with an ID chart​, which we’ll reference in our Java code. Okay, so we want this chart to update in real time when ever a new data arrives from our MQTT Publisher.
 
So as we can see, our chart is a Line Chart with an ID chart​, which we’ll reference in our Java code. Okay, so we want this chart to update in real time when ever a new data arrives from our MQTT Publisher.
Line 432: Line 443:
 
Now let’s modify our MainActivity.java, first import our ChartHelper​:
 
Now let’s modify our MainActivity.java, first import our ChartHelper​:
  
import helpers.ChartHelper;
+
import helpers.ChartHelper;
 +
 
 
and declare a ChartHelper and LineChart object below our MqttHelper object declaration.
 
and declare a ChartHelper and LineChart object below our MqttHelper object declaration.
  
ChartHelper mChart;
+
ChartHelper mChart;
LineChart chart;
+
LineChart chart;
 +
 
 
Below our dataReceived initialization in the onCreate function, initialize our chart​ and our ChartHelper​
 
Below our dataReceived initialization in the onCreate function, initialize our chart​ and our ChartHelper​
  
chart = (LineChart) findViewById(R.id.chart);
+
chart = (LineChart) findViewById(R.id.chart);
mChart = new ChartHelper(chart);
+
mChart = new ChartHelper(chart);
 +
 
 
And in our Mqtt callback, add the below line in our messageArrived function:
 
And in our Mqtt callback, add the below line in our messageArrived function:
  
mChart.addEntry(Float.valueOf(mqttMessage.toString()));
+
mChart.addEntry(Float.valueOf(mqttMessage.toString()));
 +
 
 
So all in all, our code will look like this:
 
So all in all, our code will look like this:
 +
 +
import helpers.ChartHelper;
 +
import helpers.MqttHelper;
 +
 +
public class MainActivity extends AppCompatActivity {
 +
 +
    MqttHelper mqttHelper;
 +
    ChartHelper mChart;
 +
    LineChart chart;
 +
 +
    TextView dataReceived;
 +
 +
    @Override
 +
 +
    protected void onCreate(Bundle savedInstanceState) {
 +
        super.onCreate(savedInstanceState);
 +
        setContentView(R.layout.activity_main);
 +
 +
        dataReceived = (TextView) findViewById(R.id.dataReceived);
 +
        chart = (LineChart) findViewById(R.id.chart);
 +
        mChart = new ChartHelper(chart);
 +
 +
        startMqtt();
 +
    }
 +
 +
    private void startMqtt(){
 +
        mqttHelper = new MqttHelper(getApplicationContext());
 +
        mqttHelper.mqttAndroidClient.setCallback(new MqttCallbackExtended() {
 +
            @Override
 +
            public void connectComplete(boolean b, String s) {
 +
                Log.w("Debug","Connected");
 +
            }
 +
 +
            @Override
 +
            public void connectionLost(Throwable throwable) {
 +
 +
            }
 +
 +
            @Override
 +
            public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
 +
                Log.w("Debug",mqttMessage.toString());
 +
                dataReceived.setText(mqttMessage.toString());
 +
                mChart.addEntry(Float.valueOf(mqttMessage.toString()));
 +
            }
 +
 +
            @Override
 +
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
 +
 +
            }
 +
        });
 +
    }
 +
}
  
import helpers.ChartHelper;
 
import helpers.MqttHelper;
 
 
public class MainActivity extends AppCompatActivity {
 
 
    MqttHelper mqttHelper;
 
    ChartHelper mChart;
 
    LineChart chart;
 
 
    TextView dataReceived;
 
 
    @Override
 
 
    protected void onCreate(Bundle savedInstanceState) {
 
        super.onCreate(savedInstanceState);
 
        setContentView(R.layout.activity_main);
 
 
        dataReceived = (TextView) findViewById(R.id.dataReceived);
 
        chart = (LineChart) findViewById(R.id.chart);
 
        mChart = new ChartHelper(chart);
 
 
        startMqtt();
 
    }
 
 
    private void startMqtt(){
 
        mqttHelper = new MqttHelper(getApplicationContext());
 
        mqttHelper.mqttAndroidClient.setCallback(new MqttCallbackExtended() {
 
            @Override
 
            public void connectComplete(boolean b, String s) {
 
                Log.w("Debug","Connected");
 
            }
 
 
            @Override
 
            public void connectionLost(Throwable throwable) {
 
 
            }
 
 
            @Override
 
            public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
 
                Log.w("Debug",mqttMessage.toString());
 
                dataReceived.setText(mqttMessage.toString());
 
                mChart.addEntry(Float.valueOf(mqttMessage.toString()));
 
            }
 
 
            @Override
 
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
 
 
            }
 
        });
 
    }
 
}
 
 
Now run our app.
 
Now run our app.
  
Line 505: Line 521:
 
Thank you, you’ve reached the end! If you had a wonderful time finishing this tutorial, please await for more tutorials from me.
 
Thank you, you’ve reached the end! If you had a wonderful time finishing this tutorial, please await for more tutorials from me.
  
https://github.com/wildan2711/mqtt-android-tutorial
+
https://github.com/wildan2711/mqtt-android-tutorial
  
 
Wildan Maulana Syahidillah
 
Wildan Maulana Syahidillah

Revision as of 19:50, 30 March 2022

MQTT is one of the popular data communication or messaging protocols that are becoming widely used for machine-to-machine (M2M) communication, or the computer network trend that is popularly coined as “Internet of Things”. MQTT (Message Queue Transport Telemetry) is a messaging protocol with a publish-subscribe pattern, one of the messaging protocol regarded as “light-weight”, which is important for the Internet of Things architecture, because it heavily involves low-powered devices, such as sensor nodes, microcontrollers, and the like.

One of the many uses of the MQTT protocol is to send sensor data from embedded devices. Sometimes we want those data to be sent to our smartphones which could help us monitor some important things from afar, and that’s what I’ll be showing you here in this tutorial, specifically using the Android OS.

If you’re too busy or too lazy to be reading this tutorial, you can get the full code in my Github page.

Software used in this tutorial, be sure to have them installed:

  • Android Studio
  • Python 2.7

Outline what I will be covering:

  1. Sorting out MQTT dependencies in Android Studio
  2. Setting up a cloud MQTT broker in CloudMQTT
  3. Setting up a basic MQTT client and service in Android
  4. Setting up a mock data publisher with Python
  5. Visualizing data with MPAndroidCharts library


You may skip some steps if you think you know what you’re doing. I’ve structured this tutorial as modular as possible so you can replace any of the steps with your own way.

1. Dependecies

First we need to sort out dependencies which are libraries needed to setup an MQTT client and service in an Android app. We will be using the Paho MQTT Client and Android Service provided by Eclipse.

According to official Paho Eclipse Github, we can install the library to our app using Maven, Gradle, or from source, but in this tutorial I will be using Gradle. So to sort out the dependency, simply add these lines to our build.gradle of our Android Studio project.

repositories {
    maven {
        url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
    }
}

And in our build.gradle of our Android app.

dependencies {
    compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
    compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}

A notification will come up about our Gradle configuration being changed, if so click Sync Now. Oh, and please to have your internet on in this process or the Gradle sync will fail.

Well that’s it, eventually Gradle will converge our Android app with the Paho MQTT Client and Android Service libraries.

2. Setting up cloud MQTT broker with CloudMQTT

There are a couple of cloud MQTT brokers that are available in the internet right now, like CloudMQTT and HiveMQ, but in this tutorial, I will teach how to set up a free private cloud MQTT broker using CloudMQTT. You can sign up for a free account at https://customer.cloudmqtt.com/login, just follow the instructions to sign up.

cloudmqtt

Next, you will be redirected to the CloudMQTT instances page. Click the + Create button to create a new CloudMQTT instance. Now you would be in the Create new CloudMQTT instance page. Insert an instance name, choose any Data center available, and make sure for the “Plan” choose the “Cute Cat”, because we like free stuff.

instance

In the next page, you can see your new created instance, click the details button of that instance. This is what you will see, (never mind the red scribbles):

account

Done! We have our own private cloud MQTT broker. Later we will use those credentials to connect our MQTT Android client to the broker.

3. Setting up MQTT Client and Service

Before we code anything, we need to set up our AndroidManifest.xml file to let our app have permissions to access the Internet, access the network state, and let our app to stay alive as a service. Add these lines before the opening <application tag in our AndroidManifest.xml.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

And register our MQTT Android Service in our app before the closing application tag using this piece of code:

 <service android:name="org.eclipse.paho.android.service.MqttService" />

So it should look like this: manifest Ok great, now lets begin to code shall we.

So first, lets create a new package called helpers in our app, which will contain our MQTT helper class. Then create a new Java Class inside that package called MQTTHelper.

Add the following code inside our MqttHelper class, please adjust the credentials (serverUri, username, password) accordingly with your CloudMQTT instance from the previous step. Please note: the format of the server URI is tcp://server:port

public class MqttHelper {
    public MqttAndroidClient mqttAndroidClient;

    final String serverUri = "tcp://m12.cloudmqtt.com:11111"; 

    final String clientId = "ExampleAndroidClient";
    final String subscriptionTopic = "sensor/+"; 

    final String username = "xxxxxxx";
    final String password = "yyyyyyyyyy";

    public MqttHelper(Context context){
        mqttAndroidClient = new MqttAndroidClient(context, serverUri, clientId);
        mqttAndroidClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean b, String s) {
                Log.w("mqtt", s);
            } 

            @Override
            public void connectionLost(Throwable throwable) { 

            }

            @Override
            public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
                Log.w("Mqtt", mqttMessage.toString());
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { 

            }
        });
        connect();
    }

    public void setCallback(MqttCallbackExtended callback) {
        mqttAndroidClient.setCallback(callback);
    }

    private void connect(){
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setAutomaticReconnect(true);
        mqttConnectOptions.setCleanSession(false);
        mqttConnectOptions.setUserName(username);
        mqttConnectOptions.setPassword(password.toCharArray());

        try {

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

                    DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
                    disconnectedBufferOptions.setBufferEnabled(true);
                    disconnectedBufferOptions.setBufferSize(100);
                    disconnectedBufferOptions.setPersistBuffer(false);
                    disconnectedBufferOptions.setDeleteOldestMessages(false);
                    mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
                    subscribeToTopic();
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.w("Mqtt", "Failed to connect to: " + serverUri + exception.toString());
                }
            });
        } catch (MqttException ex){
            ex.printStackTrace();
        }
    }


    private void subscribeToTopic() {
        try {
            mqttAndroidClient.subscribe(subscriptionTopic, 0, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.w("Mqtt","Subscribed!");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.w("Mqtt", "Subscribed fail!");
                }
            }); 

        } catch (MqttException ex) {
            System.err.println("Exception whilst subscribing");
            ex.printStackTrace();
        }
    }
}

Now go to our activity_main.xml or any other activity you may have created, and you may see the Hello World text view which is added by default by Android Studio, let’s give it an ID so we can access it in our Java code, here I give it an ID dataReceived.

id

So our MainActivity java class should look like this, let Android Studio resolve the imports if needed.

public class MainActivity extends AppCompatActivity {
    MqttHelper mqttHelper; 

    TextView dataReceived;

    @Override

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

         dataReceived = (TextView) findViewById(R.id.dataReceived); 

         startMqtt();
    }

    private void startMqtt(){
         mqttHelper = new MqttHelper(getApplicationContext());
         mqttHelper.setCallback(new MqttCallbackExtended() {
             @Override
             public void connectComplete(boolean b, String s) { 

             }

             @Override
             public void connectionLost(Throwable throwable) { 

             }
 
             @Override
             public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
                 Log.w("Debug",mqttMessage.toString());
                 dataReceived.setText(mqttMessage.toString());
             }

             @Override
             public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

             }
         });
     }

So what we do here is set the callback functions for the MQTT client, the only callback function we need right now is the messageArrived function which is called every time the MQTT client receives a message. Whenever a message is received, it will set the text of our TextView in our activity according to the message received.

Now let’s try to send some data to our app.

Go back to your CloudMQTT instance and open the Websocket UI. In the topic input, enter the topic set in our app, in my case is “sensor/+”. If you have done your research about MQTT, you may recall that the “+” sign is a wildcard which simply means “any subtopic”. So let’s try sending data with the “sensor/temp” topic.

send

And in our app:

Screenshot_2017-05-11-05-35-49-859_com.frost.mqtttutorial

Magic! It’s like our computer and phones are telepathic right now!

Well, so far, our Android Project structure will look like this:

structure

4. Setting up a mock data publisher with python

So now since we can be sure that our Android App can communicate using the MQTT Protocol, we can use any device with any programming language to communicate our app with the MQTT Protocol, be it your own web server, your Arduino temperature monitoring device, or even your very own smart underwear! All you need is an MQTT broker, which we have covered in step 2.

Here I will show you an example of that case, by making a mock data publisher using python 2.7.

First you will need to install the paho.mqtt client library in python.

pip install paho-mqtt

And the code:

import json
import paho.mqtt.client as mqtt
import random
import time
import threading
import sys

mqttc = mqtt.Client("client1", clean_session=False)
mqttc.username_pw_set("#User", "#password")
mqttc.connect("#Server", #port, 60)

def pub():
    mqttc.publish("sensor/temp", payload=random.normalvariate(30, 0.5), qos=0)
    threading.Timer(1, pub).start()

pub() Please change the credentials accordingly with your CloudMQTT Instance (the hash tagged words). This piece of code will periodically (every 1 second) publish a random number somewhere around 30.

After running the above python code, you will see that your app will show a different number every second, which means the code works.

5. Visualizing data with MPAndroidCharts library

Usually for sensor data monitoring, just showing the raw data may look ugly, like your sister HAH (sorry bad joke), and that is why it may be a good idea to visualize our data using charts. Here I will use one of the most popular chart libraries available for Android, when I mean popular, I mean “the first search result on Google” popular. Try googling “android chart”, and you will find MPAndroidChart as the first result (not the ads, psst).

First things first, dependencies dependencies…

In our project’s build.gradle below the previous MQTT dependency, add `

maven { url "https://jitpack.io" }

So now it should look like:

maven {
    url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
}
maven { url "https://jitpack.io" }

and our app’s build.gradle add it below our MQTT dependency too:

compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'

so now it should look like:

compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'

Okay gradle, Sync Now!!

Now add a new Java Class in our helpers package named ChartHelper​, with the following code inside:

public class ChartHelper implements OnChartValueSelectedListener {

    private LineChart mChart; 

    public ChartHelper(LineChart chart) {
        mChart = chart;
        mChart.setOnChartValueSelectedListener(this);

        // no description text
        mChart.setNoDataText("You need to provide data for the chart.");

        // enable touch gestures
        mChart.setTouchEnabled(true);

        // enable scaling and dragging
        mChart.setDragEnabled(true);
        mChart.setScaleEnabled(true);
        mChart.setDrawGridBackground(false);

        // if disabled, scaling can be done on x- and y-axis separately
        mChart.setPinchZoom(true);

        // set an alternative background color
        mChart.setBackgroundColor(Color.WHITE);
        mChart.setBorderColor(Color.rgb(67,164,34));


        LineData data = new LineData();
        data.setValueTextColor(Color.WHITE);

        // add empty data
        mChart.setData(data); 

        // get the legend (only possible after setting data)
        Legend l = mChart.getLegend();

        // modify the legend ...
        // l.setPosition(LegendPosition.LEFT_OF_CHART);
        l.setForm(Legend.LegendForm.LINE);
        l.setTypeface(Typeface.MONOSPACE);
        l.setTextColor(Color.rgb(67, 164, 34)); 

        XAxis xl = mChart.getXAxis();
        xl.setTypeface(Typeface.MONOSPACE);
        xl.setTextColor(Color.rgb(67, 164, 34));
        xl.setDrawGridLines(false);
        xl.setAvoidFirstLastClipping(true);
        xl.setEnabled(true);

        YAxis leftAxis = mChart.getAxisLeft();
        leftAxis.setTypeface(Typeface.MONOSPACE);
        leftAxis.setTextColor(Color.rgb(67, 164, 34));

        leftAxis.setDrawGridLines(true);

        YAxis rightAxis = mChart.getAxisRight();
        rightAxis.setEnabled(false); 

    }

    public void setChart(LineChart chart){ this.mChart = chart; }

    public void addEntry(float value) { 

        LineData data = mChart.getData();

        if (data != null){

            ILineDataSet set = data.getDataSetByIndex(0);
            // set.addEntry(...); // can be called as well

            if (set == null) {
                set = createSet();
                data.addDataSet(set);
            }

            data.addEntry(new Entry(set.getEntryCount(),value),0);
            Log.w("chart", set.getEntryForIndex(set.getEntryCount()-1).toString());

            data.notifyDataChanged();

            // let the chart know it's data has changed
            mChart.notifyDataSetChanged();

            // limit the number of visible entries
            mChart.setVisibleXRangeMaximum(10);
            // mChart.setVisibleYRange(30, AxisDependency.LEFT);

            // move to the latest entry
            mChart.moveViewTo(set.getEntryCount()-1, data.getYMax(), YAxis.AxisDependency.LEFT);

            // this automatically refreshes the chart (calls invalidate())
            // mChart.moveViewTo(data.getXValCount()-7, 55f,
            // AxisDependency.LEFT);
        }
    } 

    private LineDataSet createSet() {
        LineDataSet set = new LineDataSet(null, "Data");
        set.setAxisDependency(YAxis.AxisDependency.LEFT);
        set.setColor(Color.rgb(67, 164, 34));
        //set.setCircleColor(Color.WHITE);
        set.setLineWidth(2f);
        //set.setCircleRadius(4f);
        set.setFillAlpha(65);
        set.setFillColor(Color.rgb(67, 164, 34));
        set.setHighLightColor(Color.rgb(67, 164, 34));
        set.setValueTextColor(Color.rgb(67, 164, 34));
        set.setValueTextSize(9f);
        set.setDrawValues(false);
        return set;
    }

    @Override
    public void onValueSelected(Entry e, Highlight h) {
        Log.i("Entry selected", e.toString());
    }

    @Override
    public void onNothingSelected(){
        Log.i("Nothing selected", "Nothing selected.");
    }
}

Ok so let Android Studio resolve the imports for you.

Now add the chart layout to our activity_main.xml, by using the text editor. Add the below code under our <TextView layout:

<com.github.mikephil.charting.charts.LineChart
        android:id="@+id/chart"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

Go back to the Design editor, and rearrange the layouts accordingly (or maybe any other way you want).

layout.JPG

So as we can see, our chart is a Line Chart with an ID chart​, which we’ll reference in our Java code. Okay, so we want this chart to update in real time when ever a new data arrives from our MQTT Publisher.

Now let’s modify our MainActivity.java, first import our ChartHelper​:

import helpers.ChartHelper;

and declare a ChartHelper and LineChart object below our MqttHelper object declaration.

ChartHelper mChart;
LineChart chart;

Below our dataReceived initialization in the onCreate function, initialize our chart​ and our ChartHelper​

chart = (LineChart) findViewById(R.id.chart);
mChart = new ChartHelper(chart);

And in our Mqtt callback, add the below line in our messageArrived function:

mChart.addEntry(Float.valueOf(mqttMessage.toString()));

So all in all, our code will look like this:

import helpers.ChartHelper;
import helpers.MqttHelper;

public class MainActivity extends AppCompatActivity {

    MqttHelper mqttHelper;
    ChartHelper mChart;
    LineChart chart;

    TextView dataReceived;

    @Override

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

        dataReceived = (TextView) findViewById(R.id.dataReceived);
        chart = (LineChart) findViewById(R.id.chart);
        mChart = new ChartHelper(chart);

        startMqtt();
    }

    private void startMqtt(){
        mqttHelper = new MqttHelper(getApplicationContext());
        mqttHelper.mqttAndroidClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean b, String s) {
                Log.w("Debug","Connected");
            }

            @Override
            public void connectionLost(Throwable throwable) {

            }

            @Override
            public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
                Log.w("Debug",mqttMessage.toString());
                dataReceived.setText(mqttMessage.toString());
                mChart.addEntry(Float.valueOf(mqttMessage.toString()));
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

            }
        });
    }
} 

Now run our app.

Screenshot_2017-05-11-09-33-31-128_com.frost.mqtttutorial

Holy crap it moves! Feel like a magician now?

Thank you, you’ve reached the end! If you had a wonderful time finishing this tutorial, please await for more tutorials from me.

https://github.com/wildan2711/mqtt-android-tutorial

Wildan Maulana Syahidillah


Referensi