Статьи

Проект Интернета вещей: Соедините Android с Ubidots и Arduino — Часть 2

В этом посте рассказывается, как подключить смартфоны Android к убидотам, чтобы смартфон считывал данные, отправленные с Arduino . В предыдущем посте мы рассмотрели, как подключить Arduino к Ubidots, чтобы плата Arduino с датчиком температуры и влажности отправляла данные в Ubidots . В этой статье мы разработаем приложение для Android, которое использует сервисы Ubidots для получения информации, отправляемой Arduino .

Более того, приложение для Android не только читает данные, но и отображает их с помощью графиков. Для этого в приложении используется библиотека MPAndroidChart, библиотека с открытым исходным кодом для создания диаграмм в Android.

Чтобы разработать приложение для Android, необходимо:

  • Обработка HTTP-соединения для отправки запросов REST на сервер Ubidots
  • Обрабатывать формат JSON для чтения данных
  • Используйте MPAndroidChart для создания диаграмм на основе полученных данных

Кроме того, приложение для Android будет использовать дизайн материала . Окончательный результат показан ниже:

android_ubidots_iot

Android-клиент Ubidots

Даже если Ubidots предоставляет клиент для обработки запросов REST, это меня не удовлетворяет, поэтому я предпочитаю разработать собственный клиент на основе библиотеки OkHttp . Класс, который обрабатывает HTTP-запрос, называется UbidotsClient .

Клиент использует токен аутентификации для аутентификации приложения для обмена данными и идентификаторами переменных, чтобы выбрать переменную для чтения. Если вы помните, мы говорили об этих двух пунктах в предыдущем посте.

HTTP-клиент очень прост:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
OkHttpClient client = new OkHttpClient();
Request req = new Request.Builder().addHeader("X-Auth-Token", apiKey)
          .url("http://things.ubidots.com/api/v1.6/variables/" + varId + "/values")
          .build();
 
client.newCall(req).enqueue(new Callback() {
     @Override
     public void onFailure(Request request, IOException e) {
        Log.d("Chart", "Network error");
        e.printStackTrace();
     }
 
     @Override
     public void onResponse(Response response) throws IOException {
       // Here we handle the response
     }
}

В строке 2 приложение Android добавляет токен аутентификации в заголовок HTTP-запроса .

В строке 3 приложение вызывает сервис, предоставляемый Ubidots, передавая переменную id, которую мы хотим прочитать значения.

Наконец, в строке 5 приложение отправляет HTTP-запрос и ожидает ответа. Один интересный аспект клиента OkHTTP заключается в том, что он обрабатывает запросы в отдельном потоке, поэтому нам не нужно беспокоиться о проблемах ANR.

Разбор ответа Ubidots в JSON

Когда приложение Android вызывает удаленные службы, использующие REST , как службы Ubidots, оно получает ответ JSON, который необходимо проанализировать, чтобы можно было извлечь информацию.

Ответ Ubidots очень прост, он создается массивом JSON, и каждый элемент содержит два значения: само значение переменной и метку времени.

Имея в виду эту информацию, анализ JSON очень прост: в onResponse или, другими словами, когда ответ доступен, приложение анализирует JSON:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
public void onResponse(Response response) throws IOException {
    String body = response.body().string();
    Log.d("Chart", body);
     
    try {
        JSONObject jObj = new JSONObject(body);
        JSONArray jRes = jObj.getJSONArray("results");
        for (int i=0; i < jRes.length(); i++) {
            JSONObject obj = jRes.getJSONObject(i);
            Value val = new Value();
            val.timestamp = obj.getLong("timestamp");
            val.value  = (float) obj.getDouble("value");
            results.add(val);
        }
     
        listener.onDataReady(results);
     
    }
    catch(JSONException jse) {
        jse.printStackTrace();
    }
 
 }

body содержит ответ JSON в виде строки. В строках с 7 по 14 приложение анализирует массив JSON и создает простой класс, который содержит значение и временную метку каждого проанализированного элемента:

1
2
3
4
protected static class Value {
    float value;
    long timestamp;
}

Наконец, в строке 17 синтаксический анализатор уведомляет результат о главном классе так, чтобы он рисовал диаграмму.

Диаграмма в Android с MPAndroidChart

Как только данные станут доступны, приложение для Android сможет нарисовать диаграмму. Для этого мы используем MPAndroidChart. Первый шаг — добавление зависимости в файл оценки.

1
2
3
4
5
6
7
8
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.github.PhilJay:MPAndroidChart:v2.1.6'
    compile 'com.android.support:support-v4:23.1.1'
    compile 'com.squareup.okhttp:okhttp:2.6.0'
}

Для этой цели мы используем фрагмент Android, который содержит график. Макет очень прост, доступный экран разделен на две области: одна содержит график температуры, а другая — график влажности. Макет показан ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.survivingwithandroid.ubiapp.ChartFragment"
    android:orientation="vertical">
 
    <com.github.mikephil.charting.charts.LineChart
        android:id="@+id/chartTemp"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
 
    <com.github.mikephil.charting.charts.BarChart
        android:id="@+id/chartPress"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
</LinearLayout>

Перед вызовом клиента Ubidots приложение инициализирует свойства диаграммы:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
private void initChartTemp(LineChart chart) {
    chart.setTouchEnabled(true);
    chart.setDrawGridBackground(true);
    chart.getAxisRight().setEnabled(false);
    chart.setDrawGridBackground(true);
 
    YAxis leftAxis = chart.getAxisLeft();
    leftAxis.setAxisMaxValue(30F);
    leftAxis.setAxisMinValue(10F);
    leftAxis.setStartAtZero(false);
    leftAxis.setAxisLineWidth(2);
    leftAxis.setDrawGridLines(true);
 
    // X-Axis
    XAxis xAxis = chart.getXAxis();
    xAxis.resetLabelsToSkip();
    xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
    xAxis.setDrawGridLines(true);
}

В строках 7-12 приложение устанавливает ось Y, устанавливая минимальные и максимальные значения диапазона, а в строке 15-18 приложение настраивает ось X

Теперь приложение для Android готово вызвать клиент Ubidots, как показано выше:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
( new UbidotsClient() ).handleUbidots(tempVarId, API_KEY, new UbidotsClient.UbiListener() {
            @Override
            public void onDataReady(List result) {
                Log.d("Chart", "======== On data Ready ===========");
                List entries = new ArrayList();
                List labels = new ArrayList();
                for (int i=0; i < result.size(); i++) {
 
                    Entry be = new Entry(result.get(i).value, i);
                    entries.add(be);
                    Log.d("Chart", be.toString());
                    // Convert timestamp to date
                    Date d = new Date(result.get(i).timestamp);
                    // Create Labels
                    labels.add(sdf.format(d));
                }
 
                LineDataSet lse = new LineDataSet(entries, "Tempearature");
 
                lse.setDrawHighlightIndicators(false);
                lse.setDrawValues(false);
                lse.setColor(Color.RED);
                lse.setCircleColor(Color.RED);
                lse.setLineWidth(1f);
                lse.setCircleSize(3f);
                lse.setDrawCircleHole(false);
                lse.setFillAlpha(65);
                lse.setFillColor(Color.RED);
 
                LineData ld = new LineData(labels, lse);
 
                tempChart.setData(ld);
                Handler handler = new Handler(ChartFragment.this.getActivity().getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        tempChart.invalidate();
                    }
                });
 
            }
        });

В этом фрагменте приложение создает LineDataSet который используется для рисования значений. Те же шаги применяются для рисования графика влажности.

В конце этого поста вы узнали, как извлекать данные из Ubidots с помощью приложения Android и как рисовать диаграммы с помощью MPAndroidChart, используя значения, отправленные Arduino с датчиком DHT11 .