Android 最近也在 IoT 正火热的时候,推出了 Android Things 的 preview 版本.
Android Things 基本上跟写 mobile app 是差不多的,而且多了 Things Support Library 提供给开发者使用,非常的便利.
[gallery size="full" columns="1" ids="3043"]
出自 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 的组合.
开始前,我们需要准备一些硬件工具:
- Raspberry Pi 3 + SD Card
- LED
- 电阻
- 开关
- 面包板 + 跳线
- NAS 一台
软件工具:
工具都准备完成后,可以先参考此连结,安装 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 上.
[gallery columns="1" size="full" ids="3044"]
成功推送后,可以在 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 接上,请参考下图.
[gallery columns="1" size="full" ids="3045"]
来源: https://github.com/androidthings/sample-button
完成后,开启 Android Things,再执行刚刚的程序,就可以直接透过按钮控制 LED 的开关,按压住按钮 LED 灯会恒量,放开则熄灭. (临时找不到按钮开关,用触摸式传感器代替)
[gallery columns="1" size="full" ids="3046"]
写到这边,先来讲解一下 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.
完成 Node-Red 的布署后,可以实时的观察每次按压按钮的状态.
[gallery columns="1" size="full" ids="3047"]
Android Things 目前虽然还是 preview 的版本,但依照目前的 support library 完整性还蛮高的,而且 image 的大小也压缩在 200MB 上下,看来算是轻量化的 Android Things,希望未来正式的版本推出后,支持的功能可以更多.
更多QIoT教学文 https://qiot.qnap.com/blog/tw/category/%E6%95%99%E5%AD%B8-tw/
留言列表