Building a Restful API interface using Android Things
Building a Restful API interface using Android Things is useful whenever we have to connect Android Things to an external system. This article explains how to build a Restful API interface using Android Things so that other apps or applications can invoke this API. There are several scenarios, where Android Things has to be integrated with external systems and it is necessary to have a Restful interface to invoke its services. Even if there are different solutions to this integration problem, implementing a Restful API interface in Android Things guarantees a large compatibility with other systems implemented using different technologies.
We have already discussed how to exchange data between Android Things and Firebase or how to integrate Android Things with a cloud platform, this article covers a different integration aspect. Depending on the scenario we have to face, we can select the right integration strategy. We don’t have to forget that one of the best choices when we have to exchange data between different systems is using MQTT protocol.
To focus our attention on the process of building a Restful API interface in Android Things we will use a simple sensor that reads temperature, pressure, and humidity. This sensor is BMP280 that is a I2C sensor.
There are two different parts that make this tutorial:
- The schematic: how to connect the sensor to Android Things
- How to build a Restful API interface to read the sensor data
How to connect the BMP280 to Android Things
In this first step, we cover how to connect the BMP280 sensor to the Android Things. This topic was covered several times on this blog anyway just to refresh your memory, BMP280 is a I2C sensor so it connects to Android Things using 4 pins:
- Vcc
- Ground
- Clock (CLK)
- Data (SDA)
The schematic showing the connections is:
Please refer to the Android Things Peripherals I/O to know the pins used in this project. This project uses Raspberry Pi, anyway, you can use any platform compatible with Android Things.
Create a new Project using Android Things Studio and add the following dependency to the gradle file:
dependencies { ... compile 'com.google.android.things.contrib:driver-bmx280:0.4' }
Let us create a new class that manages the connection to the sensor and read the temperature and the pressure:
package com.survivingwithandroid.androidthings.api; import com.google.android.things.contrib.driver.bmx280.Bmx280; import com.google.android.things.pio.PeripheralManagerService; import java.io.IOException; public class DeviceManager { private static DeviceManager me; private static final String I2C_BUS = "I2C1"; private Bmx280 sensor; private DeviceManager() { init(); } public static final DeviceManager getInstance() { if (me == null) me = new DeviceManager(); return me; } private void init() { try { sensor = new Bmx280(I2C_BUS); sensor.setTemperatureOversampling(Bmx280.OVERSAMPLING_1X); sensor.setPressureOversampling(Bmx280.OVERSAMPLING_1X); } catch(IOException ioe) { ioe.printStackTrace(); } } public float readTemp() { if (sensor != null) try { return sensor.readTemperature(); } catch (IOException e) { e.printStackTrace(); } return 0; } public float readPress() { if (sensor != null) try { return sensor.readPressure(); } catch (IOException e) { e.printStackTrace(); } return 0; } }
That’s all, now Android Things is connected to the sensor and the Android Things app can read its values.
Building a Restful API interface using Android Things
This is the most interesting part of this article. The target of this paragraph is building a Restful API interface using Android Things so that we can expose a set of services to read the temperature and the pressure from the sensor. In other words, we can imagine we have an external application or an app that wants to read remotely the temperature and the pressure from a sensor.
To this purpose, this Android Things project uses the Restlet framework. This framework provides several implementations and one of them is for Android OS. It is very simple to use and simplifies the process of building a Restful API interface in Android.
The process of exposing a Restful API interface is made of three steps:
- Defining the resources to expose as a service
- Build an Android Service to handle the incoming requests
- Define a simple Android Activity to start and stop the service
Before digging into the implementation details, it is necessary to add the following libraries to our Android Things project:
- org.restlet.jar
- org.restlet.ext.nio.jar
- org.restlet.ext.json.jar
These libraries are necessary to implement the Restful API Interface using Android Things.
Let us see how to implement all these steps.
Step 1: Defining the resource to expose as a service
We have supposed, previously, to implement two Restful APIs: one reading the temperature and another one reading the pressure. To this purpose, it is necessary to implement two different classes:
public class SensorTempResource extends ServerResource { @Get("json") public Representation getTemperature() { JSONObject result = new JSONObject(); float temp = DeviceManager.getInstance().readTemp(); try { result.put("temp", temp); } catch(JSONException jsoe) { } return new StringRepresentation(result.toString(), MediaType.APPLICATION_ALL_JSON); } }
and the other one for the pressure:
public class SensorPressResource extends ServerResource { @Get("json") public Representation getPressure() { JSONObject result = new JSONObject(); float press = DeviceManager.getInstance().readPress(); try { result.put("press", press); } catch(JSONException jsoe) { } return new StringRepresentation(result.toString(), MediaType.APPLICATION_ALL_JSON); } }
Both classes extend a ServerResource
and an external app can invoke them using an HTTP GET request because we want to read the information from the sensor.
Moreover, this API returns a JSON data structure. You can notice, in the previous classes, that they invoke the DeviceManager
, implemented in the previous steps, that handles the connection to the sensor.
Step 2: Build an Android Service to handle the incoming requests
In this step, it is necessary to implement an Android service to handle incoming requests. As you may already know, we have to use an Android Service because an Android Service has a “longer” life than an Android Activity and if we want a task is completed even if the app UI is no longer available.
This Android Things project uses an IntentService and the class is:
public class APIServerService extends IntentService { private String LOG_NAME = getClass().getName(); private Component restComponent; private static final int PORT = 8090; public static final String START_API_SERVER = "com.survivingwithandroid.api.start"; public static final String STOP_API_SERVER = "com.survivingwithandroid.api.stop"; public APIServerService() { super("APiServerService"); // start the Rest server restComponent = new Component(); restComponent.getServers().add(Protocol.HTTP, PORT); // listen on 8090 // Router to dispatch Request Router router = new Router(); router.attach("/temp", SensorTempResource.class); router.attach("/press", SensorPressResource.class); restComponent.getDefaultHost().attach("/sensor", router); } @Override protected void onHandleIntent(@Nullable Intent intent) { if (intent != null) { String action = intent.getAction(); try { if (action.equals(START_API_SERVER)) { Log.d(LOG_NAME, "Starting API Server"); restComponent.start(); } else if (action.equals(STOP_API_SERVER)) { Log.d(LOG_NAME, "Stopping API Server"); restComponent.stop(); } } catch(Exception ex) { ex.printStackTrace(); } } } }
This class is very simple: at the beginning, it defines the port where the server listens to and then define a Router. In this context, the router is necessary to dispatch the requests to the different resources. We can suppose to attach the following URI:
- /temp to get the current temperature
- /press to get the current pressure
Then the class implements the onHandleIntent to manages the start and stop of the server.
Step 3: Defining the Activity
This is the last step in this process and contemplates to build the Android Things Activity:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent i = new Intent(this, APIServerService.class); i.setAction(APIServerService.START_API_SERVER); startService(i); } @Override protected void onDestroy() { super.onDestroy(); Intent i = new Intent(this, APIServerService.class); i.setAction(APIServerService.STOP_API_SERVER); startService(i); } }
In this class, simply, the Android Things app invokes the Intent Service defined previously using two types of Intents.
That’s all, we can run the Android Things app and test it.
Testing the Restful API interface using Android Things
In this step, we can test the app and check the results.
To read the temperature, for example, let us open a browser and write the following URL:
http://<raspberry_ip>:port/sensor/temp
while to get the pressure:
http://<raspberry_ip>:port/sensor/temp
The result is a JSON data holding the temperature or the pressure.
Summary
At the end of this post, hopefully, you gained the knowledge how to implement a Restful API interface using Android Things and how to invoke it. This is a simple project but it demonstrates how we can use a Restful API interface to integrate Android Things with external systems. We can further expand this Android Things project implementing other APIs. For example, we can use POST requests to send data and control remote peripherals like motors or LEDs.
Published on Java Code Geeks with permission by Francesco Azzola, partner at our JCG program. See the original article here: Building a Restful API interface using Android Things Opinions expressed by Java Code Geeks contributors are their own. |