Search
  • Riya Manchanda

How to Establish Connection between An Arduino and An Android App using AT Commands




Internet of Things projects are increasingly popular these days and people are constantly developing new and innovative applications of this concept. One of the most commonly used appliance in small-scale Internet of Things projects is the Arduino microcontroller.


As part of my high school Personal Project, I developed an Android application which I linked to a physical set-up including an Arduino and a gas sensor. The purpose of this system was to detect domestic gas leakages and notify the user of potential hazards.


In order to do this, I wanted to explore the world of web servers and experiment with it a little bit. So I tried to figure out whether my Arduino can connect with the web server without the Http Protocol, using AT commands. In this tutorial I will describe how exactly I did it.


Table of Contents:

  1. Equipment Used

  2. Introducing ThingSpeak

  3. WiFi Module and Serial Communication

  4. AT Commands

  5. Setting up a Basic Android App

  6. Establishing the Connection

  7. Updating the Data


1. Equipment Used


The following is the hardware that I use in this tutorial:

  • Mq-2 Gas Sensor

  • Arduino Uno Rev 3

  • ESP8266 Wifi Module

  • USB AB Cable

  • Breadboard

  • Jumper Wires

The following is the software that I use in this tutorial:

  • Android Studio

  • Arduino

  • Google Chrome (for ThingSpeak)



2. Introducing ThingSpeak


So the first step toward communication between your Arduino and Android Application, is to set up a channel on a web server where our data will be stored. For this tutorial I will be using the ThingSpeak web service. ThingSpeak is an open-source web application and API written in Ruby, which focuses mainly toward Internet of Things projects and storing/retrieving data over the Internet or Local Networks. It is great for beginners and hobbyists who are only just getting started with programming.


First things first, I will go ahead and set up a channel on ThingSpeak. You can do this simply by signing up and clicking on the New Channel button on your account page. Then you can add basic details for the Channel like this:



Once you are done with that, you will be directed to your Channel's page and there you will see a blank 'visualisation' of your data field. It should look somewhat like this:



Great job! You now have a web server channel where you can save your gas reading details! Once that is done, we can now move onto our Arduino.



4. WiFi Module and Serial Communication


In order to communicate with the web, we obviously need a network connection. For this purpose, I will be using the ESP8266 WiFi module and I will be connecting it to my Arduino through jumper cables, in order to establish serial communication between my microcontroller and the wifi module using the Arduino's TX and RX ports. Serial Communication is when a device sends data bit-by-bit through a particular port.


You can go ahead and make the connections as follows. Make sure that you connect TX-RX and RX-TX of your Arduino and ESP8266:



At this point I would like to point out that I have seen in some cases where the TX and RX ports do not work. The reasons behind this are unclear, but in this case we use custom TX and RX ports on of digital pins using a library called 'Software Serial'. These custom ports are also going to beneficial when we want to send commands to our ESP8266 through software. So you can go ahead and install that library in your Arduino. Once you are done, we can enter the following code to create our ports:



#include <SoftwareSerial.h>
SoftwareSerial esp8266(2, 3) // 2 is RX and 3 is TX

void setup()
{
    Serial.begin(9600);
    esp8266.begin(115200);
}

void loop() 
{
    // code here
}


We can now connect the TX and RX from the WiFi module to ports 1 and 0 respectively. Good going! We have now successfully connect our WiFi module to our Arduino. For the sake of this tutorial, I will quickly also add the code for receiving sensor input into my Arduino:



#include <SoftwareSerial.h>
SoftwareSerial esp8266(2, 3) // 2 is RX and 3 is TX

int sensor = A5 // this analog pin to which my sensor is connected

void setup()
{
    pinMode(sensor, INPUT)

    Serial.begin(9600);
    esp8266.begin(115200);
}

void loop() 
{
    int sensorValue = analogReader(sensor);

    delay(2000);
}


I will not be going into how you can connect a sensor to your Arduino, for more information on that you can read up here. Once you are done connecting your Input device, make sure it is powered on and operational before moving on to the next steps.



5. AT Commands


It is now time to move onto the software side of things. So let us open up the Arduino application and connect our microcontroller to our devices. Firstly, we might want to check whether our WiFi module is successfully communication with our Arduino. For that, I will open up a blank file and open up the Tools > Serial Monitor. To test the connection, I will simply enter 'AT' into the window. With a successful connection, a response of 'OK' should appear below.


Next step would be to connect our ESP8266 to our local WiFi. For this, enter the following commands into the serial monitor:


AT + CWMODE = 1
AT + CWJAP = "your wifi name", "your wifi password"

And voila! Just like that, your ESP8266 and thus your Arduino is not connected to your local WiFi. Moving on, the next step would be establish a connection with our ThingSpeak channel. For this we enter the following commands into the serial monitor:


AT + CIPMUX = 0
AT + CIPSTART = "TCP", "api.thingspeak.com", 80

Here we connect to the ThingSpeak API through port 80. Now we send or 'write' data to our channel using our Write API Key. You can access this on your ThingSpeak channel. Once you have it, you can enter the following code:


AT + CIPSEND = 51
GET /update?api_key={your write api key}&field1={data value}
AT + CIPCLOSE

Bravo! Just like that, we have sent our first data value to our ThingSpeak channel. You can now view this data point on the visualisation of your data field.


At this point you must be wondering about the inefficiency of what we just did in terms of constantly sending data to ThingSpeak. Well, your spidey-senses are right! What we need to do now is do all of the above but through code in our Arduino. We're gonna split these commands into two categories: ones which we only need to run once as set up, and the ones which we need to run every time we wish to send sensor data to our web server. So we will basically be sending all the above commands to our software serial port as follows:



#include <SoftwareSerial.h>
SoftwareSerial esp8266(2, 3) // 2 is RX and 3 is TX

int sensor = A5 // this analog pin to which my sensor is connected

void setup()
{
    pinMode(sensor, INPUT)

    Serial.begin(9600);
    esp8266.begin(115200);
    
    delay(2000)
    
    esp8266.println("AT+CWMODE=1")
    delay(2000)
    
    esp8266.println("AT+CWJAP=\"WIFI name\", \"WIFI password\"")
    delay(5000)
    
}

void loop() 
{
    int sensorValue = analogReader(sensor);

    esp8266.println("AT+CIPMUX=0")
    delay(2000);
    
    esp8266.println("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80")
    delay(2000);
    
    esp8266.println("AT+CIPSEND=51")
    delay(2000);
    
    esp8266.println("GET /update?api_key={your api key}&field1="+String(sensorValue))
    delay(2000);
    
    esp8266.println("AT+CIPCLOSE");
    delay(2000);

}
    

Eureka! Now our Arduino is capable of sending over sensor data every few seconds to our ThingSpeak channel. Notice that we are adding a delay of 2 seconds after each AT command, this we are doing to ensure the commands do not overlap and ensure smooth and orderly execution. We have also used our sensorValue variable to send sensor input to ThingSpeak instead of hardcoding any data. Just like that, we are successfully sending sensor data to be stored in our database every 5 seconds. And our Arduino part is done! Time to use this data in our Android app.



6. Connecting to an Android App


Great going! We are very close to achieving our goal. However, we still need to work on our Android Application and allow it to fetch data which is now stored in our ThingSpeak database. So I am going to go ahead open up Android Studio, and set up a very basic application in Kotlin.


For fetching or 'getting' data from ThingSpeak, I will be using the Volley library in Kotlin application. In order to use this library, I will first add it as a dependency in the build.gradle file of my Android project by entering the following code as below:



implementation 'com.android.volley:volley:1.1.1'


Now let's get back to our MainActivity.kt file. We will now create a function which contains a get request to fetch data from ThingSpeak. Before that, we need to import Volley and a few support tools into the file:



import com.android.volley.toolbox.Volley
import com.android.volley.toolbox.StringRequest
import com.android.volley.Response
import com.android.volley.Request


Once we have added this and synchronised our build, we are equipped to use Volley in our project. For the next step, you will need your Read API Key from your ThingSpeak channel.

We also need to understand how our fetch request will work. So we are going to create a StringRequest, which will take four parameters: type of request, url of our channel, a response listener (in this case which tells the function what to do with the data received), and an error listener/handler. By default, we will be receiving our data in the form of a JSONObject. Now we are all ready to create our fetch request function inside our MainActivity class:



fun getRequest() {
    
    val stringRequest = StringRequest(
    
        Request.Method.GET,
            "https://api.thingspeak.com/channels/{your-channel-id}/fields/1.json?api_key={your-api-key}&results=2",
            
        Response.Listener { responseString -> 
            val newSensorReading = responseString
        },
            
        Response.ErrorListener { volleyError -> 
            val errorMessage = volleyError.message
        }
   )

}
            

Here we have created a basic fetch request. To execute this, we need to add it to the Volley newRequestQueue:



Volley.newRequestQueue(this).add(stringRequest)


Great! Now it is time for us to call our function inside of the onCreate function:



override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(findViewById(R.id.toolbar))

    getRequest()
}


Awesome. However, this will throw an error right now, since we have not yet been granted permission to use the user's Internet. For that, let us go ahead and add the following line of code in our AndroidManifest.xml file:



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


Great, now it should work. But right now there is no way yet for us to check what data we have received from our ThingSpeak channel. So for this, I am going to create a textview within a liner layout in my activity_main.xml by dragging and dropping on the story board. After that, as part of our Response Listener, I am going to set our fetched value in the string request as the text for our textview:



fun getRequest() {
    
    val stringRequest = StringRequest(
    
        Request.Method.GET,
            "https://api.thingspeak.com/channels/{your-channel-id}/fields/1.json?api_key={your-api-key}&results=2",
            
        Response.Listener { responseString -> 
            val newSensorReading = responseString
        
            textView.text = newSensorReading
        },
            
        Response.ErrorListener { volleyError -> 
            val errorMessage = volleyError.message
        
            textView.text = errorMessage
        }
   )

}
    

To access my textview, I also need to import my main activity file:



import kotlinx.android.synthetic.main.activity_main.*


We should now try to run this code on a simulator and check whether the output is as desired. If you have done that, you will notice that although you do get the fetched value as you wanted, it is not exactly in the format you wanted. The format would look something very ambiguous like this right now:



And that is clearly not what we desire, we do not require all of the additional information provided to us. We simply want to display the number which is our gas reading value. So, in our Response Listener, let us go ahead and write the code to extract the data from this JSONObject:



fun getRequest() {
    
    val stringRequest = StringRequest(
    
        Request.Method.GET,
            "https://api.thingspeak.com/channels/{your-channel-id}/fields/1.json?api_key={your-api-key}&results=2",
            
        Response.Listener { responseString -> 
            
            val jsonArray = JSONObject(responseString).getJSONArray("feeds")
            val feeds = jsonArray.getJSONObject(0)
            val sensorReading = feeds.getString("field1")

        
            textView.text = sensorReading
        },
            
        Response.ErrorListener { volleyError -> 
            val errorMessage = volleyError.message
        
            textView.text = errorMessage
        }
   )

}
  

There we go! Now we see a nice clean sensor reading on our screen as below:



The last thing that we will discuss today, is how do we get this sensor value which is displayed on our app to be updated periodically? Say, every 5 seconds? For this we will create a Runnable object which executes tasks every 5 seconds using a Handler and Looper. And instead of running our getRequest function directly in our onCreate function, we will call it inside our handled task. This will look something like this:



lateinit var mainHandler: Handler

private val updateTextTask = object : Runnable {
    override fun run() {
        getRequest()
        mainHandler.postDelayed(this, 5000) 
    }
}
    

Now we create a Handler in our onCreate function and call this updateTextTask in our onCreate function like this:



override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(findViewById(R.id.toolbar))

    mainHandler = Handler(Looper.getMainLooper())
    mainHandler.post(updateTextTask)
}


For the above code to work properly, we also need to import Handler and Looper into our project, so let us do that:



import android.os.Handler
import android.os.Looper


And voila! There we go! Now our data values keep updating every 5 seconds. Congratulations, we have successfully managed to input sensor data into our Arduino, send it to a web server, and then display this data on an Android Application.



Conclusion

Wow, that was pretty exciting, no? You can now transfer data between any Android application and any physical device that you make using an Arduino Board and WiFi Module, that opens up quite a few new doors for you to explore. I would like to once again extend my heartfelt gratitude to all of you who made it through the entire post and I sincerely hope you learnt something beneficial. If you did so, don't forget to drop your likes and comments so I know that I should keep going! Before I sign off, always remember, Science (especially Computer Science) is all about experimentation, so never be afraid of trying out new ways of doing things.


Until Next Time ~

143 views0 comments