Android Things 教程:Raspberry Pi 与 Android Things 实现一个 RESTful 接口

Android Things(以前称为 Brillo)是针对小型化和物联网设备而设计的 Android 精简版。下面是一个简单的事物(Things)应用程序示例,它提供了一个 REST 风格的 Web 界面来控制 Raspberry Pi GPIO 端口上的 LED 状态。

你将需要的东西有:

  • 一个 Raspberry Pi 3 Model B
  • 一个面包板,带状电缆,330欧姆电阻,LED,跳线
  • 8GB 或更大的 Micro SD 卡
  • 以太网电缆
  • HDMI 电缆
  • Android Studio 安装了 API 25 或更高版本的工具
  • cURL

有许多 Raspberry Pi 3 套件可用,与你需要的一切开始。查看 Android Things Raspberry Pi 硬件页面,获取有关将事物预览图像加载到 SD 卡上并启动的更多信息。

您还需要从命令行使用 adb 访问。

设置硬件

拔掉你的 Raspberry Pi,并连接带状电缆和面包板。在 BCM 21(见引脚)和 LED 的长脚(阳极/+)之间连接一个 330 欧姆的电阻。使用跳线将 LED 的短路(阴极/-)接地。 例如:

Raspberry Pi BCM21 LED

仔细检查您的连接并启动设备。连接 Android 调试器:

adb connect <ipaddress>

这个 IP 地址应该显示在 Android Things 引导屏幕的底部。

创建应用程序

这个例子的完整源代码可以在 Github 上找到。

打开 Android Studio 并创建一个新项目。

  • 您可以选择 “Phone and Tablet”,因为 Android Studio 尚未安装 Android Things 设备。
  • 选择 API: 24 Android 7.0 (Nougat) 作为最低的 SDK。
  • 选择一个空的 activity 开始。
  • 取消选中 “Customize Activity” 页面上的 “Backwards Compatibility”,因为我们不需要担心在旧设备上运行。

添加必需的库

下载并解压 Android 版本的 Restlet Framework。 将 lib 目录中的下列 jar 文件复制到应用程序的 app/libs 文件夹中:

  • org.restlet.jar
  • org.restlet.ext.nio.jar
  • org.restlet.ext.json.jar

现在,在 Android Studio 中,编辑“Module:app” 中的 build.gradle 文件,并将 Restlet 和 Android Things 的必要库添加到 dependencies 部分,如下所示:

compile files('libs/org.restlet.ext.nio.jar')
compile files('libs/org.restlet.ext.json.jar')
compile files('libs/org.restlet.jar')

以及:

provided 'com.google.android.things:androidthings:0.1-devpreview'

更新 AndroidManifest.xml

打开 app/manifests/AndroidManifest.xml 文件,并将以下内容添加到 application 部分:

<uses-library android:name="com.google.android.things"></uses-library>

并将 main activity 修改为如下的内容:

<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"></action>
<category android:name="android.intent.category.LAUNCHER"></category>
<category android:name="android.intent.category.IOT_LAUNCHER"></category>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</activity>

这会将您的应用程序设置为设备的默认 activity。

检查点:运行应用程序

此时,您应该能够在 Raspberry Pi 上启动应用程序,并看到 “Hello,World!”消息。确保 adb 已连接(请参阅上文),然后单击 Android Studio 中的 “运行” 图标。

编写 Android Things 应用程序

添加 LED Control Model

创建一个名为 LEDModel 的新类。该类将提供对控制 LED 状态的 GPIO 引脚的访问:

package com.example.restfulthings;

import com.google.android.things.pio.Gpio;
import com.google.android.things.pio.PeripheralManagerService;

import java.io.IOException;

public class LEDModel {
    private static LEDModel instance = null;
    private PeripheralManagerService mPMSvc;
    private Gpio mBCM21;

    public static LEDModel getInstance() {
        if (instance == null) {
            instance = new LEDModel();
        }
        return instance;
    }

    private LEDModel() {
        mPMSvc = new PeripheralManagerService();
        try {
            mBCM21 = mPMSvc.openGpio("BCM21");
            mBCM21.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void setState(boolean state) {
        try {
            getInstance().mBCM21.setValue(state);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean getState() {
        boolean value = false;
        try {
            value = getInstance().mBCM21.getValue();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return value;
    }
}

有关控制设备的 GPIO 输出的更多信息,请参阅 Android Things SDK 文档。

添加 Restlet 资源

创建一个名为 LEDResource 的新类,它继承 org.restlet.resource.ServerResource。 该类提供了 LED 状态的 RESTful 表示形式:

package com.example.restfulthings;

import android.util.Log;
import org.json.JSONObject;
import org.restlet.data.MediaType;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.ServerResource;

public class LEDResource extends ServerResource {

    @Get("json")
    public Representation getState() {
        JSONObject result = new JSONObject();
        try {
            result.put("state", LEDModel.getState());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new StringRepresentation(result.toString(), MediaType.APPLICATION_ALL_JSON);
    }

    @Post("json")
    public Representation postState(Representation entity) {
        JSONObject result = new JSONObject();
        try {
            JsonRepresentation json = new JsonRepresentation(entity);
            result = json.getJsonObject();
            boolean state = (boolean)result.get("state");
            Log.d(this.getClass().getSimpleName(), "new LED state: "+state);
            LEDModel.setState(state);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new StringRepresentation(result.toString(), MediaType.APPLICATION_ALL_JSON);
    }
}

添加服务

HTTP 服务器将作为后台服务在与用户界面活动不同的线程上运行。 添加一个名为 RESTfulService 的新类,继承 IntentService:

package com.example.restfulthings;

import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
import android.util.Log;

import org.restlet.Component;
import org.restlet.data.Protocol;
import org.restlet.engine.Engine;
import org.restlet.ext.nio.HttpServerHelper;
import org.restlet.routing.Router;

public class RESTfulService extends IntentService {
    // IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
    private static final String ACTION_START = "com.example.restfulthings.action.START";
    private static final String ACTION_STOP = "com.example.restfulthings.action.STOP";

    private Component mComponent;

    public RESTfulService() {
        super("RESTfulService");
        Engine.getInstance().getRegisteredServers().clear();
        Engine.getInstance().getRegisteredServers().add(new HttpServerHelper(null));
        mComponent = new Component();
        mComponent.getServers().add(Protocol.HTTP, 8080);
        Router router = new Router(mComponent.getContext().createChildContext());
        router.attach("/led", LEDResource.class);
        mComponent.getDefaultHost().attach("/rest", router);
    }

    public static void startServer(Context context) {
        Intent intent = new Intent(context, RESTfulService.class);
        intent.setAction(ACTION_START);
        context.startService(intent);
    }

    public static void stopServer(Context context) {
        Intent intent = new Intent(context, RESTfulService.class);
        intent.setAction(ACTION_STOP);
        context.startService(intent);
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_START.equals(action)) {
                handleStart();
            } else if (ACTION_STOP.equals(action)) {
                handleStop();
            }
        }
    }

    private void handleStart() {
        try {
            mComponent.start();
        } catch (Exception e) {
            Log.e(getClass().getSimpleName(), e.toString());
        }
    }

    private void handleStop() {
        try {
            mComponent.stop();
        } catch (Exception e) {
            Log.e(getClass().getSimpleName(), e.toString());
        }
    }
}

该服务提供了主要活动可用于启动和停止服务器的 Intent 操作。

集成服务

最后,编辑 MainActivity 类来启动和停止服务:

package com.example.restfulthings;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // start the server
        RESTfulService.startServer(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // stop the server
        RESTfulService.stopServer(this);
    }
}

测试

启动应用程序。您应该在 logcat 输出中看到一条消息:Starting the internal [HTTP/1.1] server on port 8080

打开命令行窗口,并使用 curl 来请求 LED 的状态:

curl http://<ipaddress>:8080/rest/led

这里的 <ipaddress> 是您的设备的 IP 地址。 这应该返回 JSON 格式的当前状态(false):

{"state":false}

打开 LED 只需要:

curl -H "Content-type: application/json" -X POST -d '{"state": true}' http://<ipaddress>:8080/rest/led

LED 现在应该点亮。再次关闭它:

curl -H "Content-type: application/json" -X POST -d '{"state": false}' http://<ipaddress>:8080/rest/led

完整的代码见:GitHub

英语原文链接:https://keathmilligan.net/implement-a-restful-interface-with-android-things-and-raspberry-pi/

尚未评分
您的评分将帮助我们做出更好的玩法

观光\评论区

Copyright © 2017 玩点什么. All Rights Reserved.