Android Things + NAS

Android 最近也在 IoT 正火熱的時候,推出了 Android Things 的 preview 版本.

Android Things 基本上跟寫 mobile app 是差不多的,而且多了 Things Support Library 提供給開發者使用,非常的便利.

出自 https://developer.android.com/things/sdk/index.html

在第一次時間,也快速的測試 Android Things 是否可以連上 NAS,並透過 Node-Red + Dashboard 的方式,快速呈現 NAS IoT 的應用.

目前 Android Things 的 preview 版本,只有支援 3 種 IoT 開發裝置:

  • Intel Edison
  • NXP Pico i.MX6UL (台灣似乎不太好買到這一塊開發板)
  • Raspberry Pi 3

其它的開發裝置,未來應該會加入更多的選擇。

下面將開始介紹,如何使用 Android Things + NAS 的組合.

開始前,我們需要準備一些硬體工具:

  1. Raspberry Pi 3 + SD Card
  2. LED
  3. 電阻
  4. 開關
  5. 麵包板 + 跳線
  6. NAS 一台

軟體工具:

  1. Android Studio ( 需要使用 2.2 以上版本)
  2. Android adb debug tool
  3. Button and LED sample for Android Things

工具都準備完成後,可以先參考此連結,安裝 Android Things 到 Raspberry Pi 3上.

關於 Android Things image,這部份跟 Raspberry Pi 提供的 image 設定方式都一樣,只是跑在上面的作業系統不同.

完成後,將 Raspberry Pi 3 上電,過一會可以透過 adb 工具進行測試.

透過下面指令連到 Android Things, 成功連線會看到 connected to xxx 的訊息

$ adb connect "ip-address"
connected to xxxxx:5555

成功連線後,接下來就是開始來寫 Android Things 的 code.

將剛剛的範例先下載下來,並透過 Android Studio 進行編譯.

如果剛剛有透過 adb connect 連線成功,可以透過 Android Studio 直接編譯好的程式推送到 Android Things 上.

screen-shot-2016-12-30-at-5-37-49-pm

成功推送後,可以在 debug 的訊息欄裡面看到程式啟動成功的訊息.

12-30 10:01:48.665 20111-20111/com.example.androidthings.button I/ButtonActivity: Starting ButtonActivity
12-30 10:01:48.683 20111-20111/com.example.androidthings.button I/ButtonActivity: Configuring GPIO pins
12-30 10:01:48.690 20111-20111/com.example.androidthings.button I/ButtonActivity: Registering button driver

接著,我們要把剛剛準備好的 LED、電阻與 Button 接上,請參考下圖.

rpi3_schematics
來源: https://github.com/androidthings/sample-button

完成後,開啟 Android Things,再執行剛剛的程式,就可以直接透過按鈕控制 LED 的開關,按壓住按鈕 LED 燈會恆量,放開則熄滅. (臨時找不到按鈕開關,用觸摸式感測器代替)

2016-12-30-18-09-26

寫到這邊,先來講解一下 Things Support Library 多了些什麼!

從 gradle config 中可以發現,多了兩個 library.

第一行,主要用來處理按鈕事件的處理,主要是針對使用 GPIO 的按鈕進行處理.

第二行,是 Things Support Library, 主要是 Android Things 相關 dependency library.

compile 'com.google.android.things.contrib:driver-button:0.1'
provided 'com.google.android.things:androidthings:0.1-devpreview'

Note: 目前 Android Things 提供用來處理硬體相關的 driver, 可以從 Android Things 的 GitHub 裡找到目前支援的類型有哪些(目前支援 12 種).

以下是使用 Things Support Library 來控制接上 GPIO 的按鈕.

PeripheralManagerService pioService = new PeripheralManagerService();
try {
    Log.i(TAG, "Configuring GPIO pins");
    mLedGpio = pioService.openGpio(BoardDefaults.getGPIOForLED());
    mLedGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);

    Log.i(TAG, "Registering button driver");
    // Initialize and register the InputDriver that will emit SPACE key events
    // on GPIO state changes.
    mButtonInputDriver = new ButtonInputDriver(
            BoardDefaults.getGPIOForButton(),
            Button.LogicState.PRESSED_WHEN_HIGH,
            KeyEvent.KEYCODE_SPACE);
    mButtonInputDriver.register();
} catch (IOException e) {
    Log.e(TAG, "Error configuring GPIO pins", e);
}

1: PeripheralManagerService 是用來管理開發板上的硬體服務
4: 設定 LED GPIO pin, 目前是透過 BoardDefaults 取得使用 BCM6 的腳位(參考相關 pin out)
5: 設定 pin out 為低電位
10: 使用 driver-button library 來控制按鈕的狀態,使用 BCM21 作為輸入,並且預設當按下按鈕為高電位(PRESSED_WHEN_HIGH)
14: 註冊按鈕, 並且使用 KeyEvent 的方式處理按壓事件.

成功註冊按鈕後,可以透過 onKeyDown 和 onKeyUp callback 來處理按鈕的事件.

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_SPACE) {
        // Turn on the LED
        setLedValue(true);

        return true;
    }

    return super.onKeyDown(keyCode, event);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_SPACE) {
        // Turn off the LED
        setLedValue(false);

        return true;
    }

    return super.onKeyUp(keyCode, event);
}

/**
 * Update the value of the LED output.
 */
private void setLedValue(final boolean value) {
    try {
        mLedGpio.setValue(value);
    } catch (IOException e) {
        Log.e(TAG, "Error updating GPIO value", e);
    }
}

2, 14: 當按下或放開按鈕時的 callback.
30: 主要是用來處理當按鈕按下後,設定 LED 為高電位或低電位.

以上是如何透過按鈕來控制 LED 的亮滅,那我們要如何將 LED 的狀態傳回到 NAS 並將 LED 狀態進行回傳呢?其實很簡單,我們可以實作 MQTT 在 Android Things上,並將 LED 狀態回傳.

首先,先將 MQTT library 加入到 gradle config.

compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.0.2'
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.0.2'

以下是如何實作 MQTT publish 和 subscribe,並將資料回傳到 MQTT Server

public class PiActivity extends Activity implements MqttCallback{

...
...

public void connectMQTT(){
    try {
        MemoryPersistence persistence = new MemoryPersistence();
        client = new MqttClient("tcp://your-mqtt-server:1883", "JarvisPi", persistence);
        client.connect();
        client.setCallback(this);
        client.subscribe("PiLEDStatus");
    } catch (MqttException e) {
        e.printStackTrace();
    }
}

@Override
public void connectionLost(Throwable cause) {
    Log.d(TAG, "MQTT Connection Lost!");
}

@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
    Log.d(TAG, "LED Status:" + topic + " msg:" + message.getPayload().toString());
}

@Override
public void deliveryComplete(IMqttDeliveryToken token) {}

}

1, 19, 24, 29: 實作 MqttCallback
8: 資料暫存到 memory, 如果不使用此方式,會有錯誤訊息.
9: 連線資訊, 包含 MQTT server 位置, clientId
11: 套用 MqttCallback
12: subscribe PiLEDStatus
19: 連線失敗 callback
24: 收到 PiLEDStatus 的訊息

修改剛剛的 setLedValue, 並加上 MQTT 訊息的推送.

/**
 * Update the value of the LED output.
 */
private void setLedValue(final boolean value) {
    try {
        mLedGpio.setValue(value);

        MqttMessage message = new MqttMessage();
        if(value) {
            message.setPayload("true".getBytes());
        }else{
            message.setPayload("false".getBytes());
        }
        try {
            client.publish("PiLEDStatus", message);
        } catch (MqttException e) {
            e.printStackTrace();
        }
        Log.i(TAG, "PiLEDStatus send...");
        
    } catch (IOException e) {
        Log.e(TAG, "Error updating GPIO value", e);
    }
}

8 – 13: 建立 MQTT message 容器
15: publish PiLEDStatus 並將訊息送到 MQTT Server

完成 MQTT 的實作後,再一次編譯程式,並推送至 Android Things.

接下來,開啟 NAS 的 Node-Red,建立一個 MQTT Node, 並 subscribe PiLEDStatus, 把輸出指向 Node-Red Dashboard.

screen-shot-2016-12-31-at-12-07-22-am

完成 Node-Red 的佈署後,可以即時的觀察每次按壓按鈕的狀態.

2016-12-30-18-19-37

Android Things 目前雖然還是 preview 的版本,但依照目前的 support library 完整性還蠻高的,而且 image 的大小也壓縮在 200MB 上下,看來算是輕量化的 Android Things,希望未來正式的版本推出後,支援的功能可以更多.

 

Related posts

發表迴響