Mobile App communication with Inverter through Bluetooth

With Internet of Things (IoT) adoption, OEMs are building connected products. The first step to build connected ecosystem is to enable wireless communication on edge devices. The objective of this blog is to help how to use the Bluetooth technologies to communicate with devices wirelessly.

Problem

We are working with leading solar inverter manufacturer. They have requirement to monitor power generation, storage and consumption of remotely deployed rooftop solar panels. As remote location does not have GSM connectivity, it’s always challenge to retrive data. Considering scale and low cost business model, Bluetooth technology was clear choice solution.

Solution

We have build Mobile app that interact with Inverter over Bluetooth. Providing reliable and cost effective solution to the end user is main motto behind this. User has to pair with Inverter and click few buttons to retrive data. The same data would be uploaded to cloud when Mobile comes in wi-fi or data coverage.

package com.example.bluetoothconnection; 
import android.support.v7.app.ActionBarActivity; 
import android.os.Bundle; 
public class MainActivity extends ActionBarActivity 
{ 
         @Override protected void onCreate(Bundle savedInstanceState) 
          {         
                super.onCreate(savedInstanceState);   
                setContentView(R.layout.activity_main); 
          }
 }

Source 1. Starting code

The first programming step is to create a new Android Application Project in Android Studio. Doing so will generate code similar to that in Source 1. The first thing the program should do is determine if the Android device supports Bluetooth. To do this, create a BluetoothAdapter object using the function getDefaultAdapter(). If this returns null, then the Android device does not support Bluetooth. Source 2 shows how to do this. Add this code to OnCreate().

package com.example.bluetoothconnection; 
import android.support.v7.app.ActionBarActivity; 
import android.os.Bundle; 
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
if (mBluetoothAdapter == null) 
{ 
         // Device does not support Bluetooth
 }

Source 2. Determine if Android supports Bluetooth

If getDefaultAdapter does not return null, then the Android supports Bluetooth. The next step is to determine if Bluetooth is enabled, and if it is not enabled, to enable it. Source 3 accomplishes this task, checking if the BluetoothAdapter is enabled and reacting accordingly. Add it after Source 2.

if (!mBluetoothAdapter.isEnabled()) 
{ 
   Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);                                                               startActivityForResult(enableBtIntent, 1);
 } 

Source 3. Turn on Bluetooth if disabled

Next, the program has to retrieve the actual Bluetooth device it will communicate with, in this case the microcontroller’s Bluetooth module. The BluetoothAdapter’s getBondedDevices() function will do this. This function puts all of the microcontroller’s currently-paired devices into a storage structure called a “Set”. Since only the microcontroller’s Bluetooth module is paired with the Android (which was done at the beginning of these instructions), only this device will be in the Set. Assign this device to a BluetoothDevice variable. Source 4 demonstrates these steps. Add it after Source 3

Set pairedDevices = mBluetoothAdapter.getBondedDevices();
 if (pairedDevices.size() > 0) 
{ 
        for (BluetoothDevice device : pairedDevices) 
       { 
            mDevice = device; 
        } 
}

Source 4. Get the Bluetooth module device

At this point, the Android has the microcontroller’s Bluetooth module stored in a BluetoothDevice object. The next objective is to form the connection between the Android and the microcontroller’s . This work should take place in separate thread. This is because forming a connection can block a thread for a significant amount of time. Up until now, all of the program’s code has been written in the main thread, or “user interface thread” (UI thread). The UI thread should never be blocked. Therefore, create a new thread class where the connection will form. Source 6 shows the code to accomplish this. Add it as an inner class of the main class.

private class ConnectThread extends Thread 
{ 
    private final BluetoothSocket mmSocket; 
    private final BluetoothDevice mmDevice;
    private static final UUID MY_UUID =   UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); 
      public ConnectThread(BluetoothDevice device) 
      { 
            BluetoothSocket tmp = null; mmDevice = device;
            try 
            {
                 tmp = device. createRfcommSocketToServiceRecord(MY_UUID); 
             } 
             catch (IOException e) 
             {
                  e.printStackTrace
              } 
              mmSocket = tmp;
        } 

        public void run() 
        {  
            mBluetoothAdapter.cancelDiscovery(); 
                     mmSocket.connect(); } catch (IOException connectException) 
                     {  
                            try 
                            { 
                                 mSocket.close(); 
                             } 
                             catch (IOException closeException) 
                              { 
                                    e.printStackTrace
                               } 
                              return; 
                       } 
         }

        public void cancel() 
        {
             try 
             { 
                     mmSocket.close(); 
             }
             catch (IOException e) 
             { } 
         }
 } 

Source 5. Thread used for connecting Bluetooth devices

This thread requires a BluetoothDevice as a parameter and uses it to create a BluetoothSocket. This socket is what Bluetooth uses to transfer data between devices. The UUID used in Source 5 tells the socket that data will be transferred serially, which means one byte at a time. To use this thread, add the code in Source 6 to the end of onCreate().

 mConnectThread = new ConnectThread(mDevice);
 mConnectThread.start(); 

Source 6. Creating the connection thread

The code will now connect the microcontroller’s Bluetooth module with the Android. The last objective is to send and receive data using this connection. Like connecting, transferring data is time-intensive and can block the thread, so this work should also take place in a separate thread. Create another inner thread class like that shown in Source 7. This is the most complex code in the program. The thread requires a BluetoothSocket as a parameter and uses it to create an InputStream and and OutputStream. The InputStream is used for reading data coming from the microcontroller’s , and the OutputStream is used for sending data to the microcontroller. Writing data is easier than reading data. The only data this program has to send is the asterisk character, for when it wants to receive a random number from the Microcontroller.

private class ConnectedThread extends Thread 
{ 
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream; 
        private final OutputStream mmOutStream;
        public ConnectedThread(BluetoothSocket socket)
        { 
             mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null;
             try 
             { 
                  tmpIn = socket.getInputStream(); 
                  tmpOut = socket.getOutputStream(); 
              } 
              catch (IOException e) { } 
              mmInStream = tmpIn; mmOutStream = tmpOut; 
         }
         public void run() 
         { 
                 byte[] buffer = new byte[1024]; int begin = 0; int bytes = 0; 
                 while (true) 
                 { 
                      try 
                      { 
                          bytes += mmInStream.read(buffer, bytes, buffer.length - bytes); 
                        for(int i = begin; i < bytes; i++) { if(buffer[i] == "#".getBytes()[0]) 
                        { 
                               mHandler.obtainMessage(1, begin, i, buffer).sendToTarget();
                               begin = i + 1; if(i == bytes - 1) 
                               { 
                                    bytes = 0; begin = 0; 
                               } 
                        } 
                   } 
                 } catch (IOException e) 
                  { break; } 
              } 
         }

          public void write(byte[] bytes) 
          { 
              try 
              { mmOutStream.write(bytes); } 
              catch (IOException e) { } 
           } 

           public void cancel() 
           { 
              try { mmSocket.close(); 
              } catch (IOException e) { } 
           }
 }

Source 7. Thread used for transferring data

Handler mHandler = new Handler()
{ 
         @Override public void handleMessage(Message msg) 
          { 
               byte[] writeBuf = (byte[]) msg.obj; 
               int begin = (int)msg.arg1; 
               int end = (int)msg.arg2; 
               switch(msg.what) 
               { 
                     case 1: String writeMessage = new String(writeBuf); 
                     writeMessage = writeMessage.substring(begin, end); 
                     break; 
                } 
           }
 };

Source 8. Handler code

The program is almost complete. The last step is to create and start the data thread. Add the code in Source 9 to the end of ConnectThread’s run() function.

mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start(); 

Source 9. Creating the data transfer thread

Results

With the completed code, the program will run correctly. When the Android program is first opened, it determines if Bluetooth is supported by the device, as well as whether or not Bluetooth is enabled. After this, it finds the Microcontroller’s Bluetooth module paired with the Android and uses it to form a connection. This connection process creates a socket that both devices will use to receive and transmit data.

Conclusions

Utilizing Bluetooth in Android applications can be daunting for those unfamiliar with the process. However, prior experience with Android’s Bluetooth API can reduce the learning curve tremendously. This application note can help Android developers gain this experience. This is helpful because Bluetooth is a popular, well-supported, and effective protocol for wireless communication, and can enhance mobile apps that require such a protocol.

Submit a Comment

Your email address will not be published. Required fields are marked *