Android Things 教程:Android Things 与 Twillo 构建智能门铃

在家工作时,拥有一个狂热的 Marilyn Manson 风扇,便意味着当有人敲我的门时,我通常会错过。我们有一个门铃,但效果不如耳机上的降噪功能。

我的耳机与我的手机配对,这仍然意味着我会想念一个人在门外,但从来没有任何电话。我们如何建立一个聪明的门铃,当有人在门口时打电话给我?

我们将使用 Node.js 创建一个后端,以便我们可以与 Twilio 交互,并构建一个将在 Raspberry Pi 上运行的 Android 应用程序,它将作为我们的智能门铃。

材料清单

  • Twilio 电话号码。
  • 在 Raspberry Pi 3 上运行的 Android Things
  • Android Studio
  • 安装有 Node.js 和你最喜欢的编辑器。我将使用 Visual Studio
  • 公对母和公对公跳线
  • 一个 400 点的面包板
  • 一个 1K 的电阻(棕色,黑色,红色,金色)
  • 用作触发器的触觉按钮。

后台

我们将开始构建我们的应用程序的后端。 当有人按下门铃时,它使用 Twilio API 拨打我们的号码。

Twillo 后台

如果你不想经过后端的构建,你可以克隆这个仓库,或者点击下面的链接来将你自己的后端部署到 Heroku

首先打开一个新的终端窗口,并创建一个名为 “Doorbell” 的新文件夹。我通常会在 〜/Projects/JavaScript 中创建我的项目。

mkdir Doorbell; 
cd Doorbell

在该文件夹内,创建一个新的 Node.js 项目,并安装 Twilio Node Helper Library 和 Express。

npm init -y; npm install twilio express —save

你现在应该有一个名为 package.json 的文件和一个名为 node_modules 的文件夹,其中包含 twilio 和 express 库。

接着,仍在 Doorbell 文件夹中创建一个名为 index.js 的新文件,并用您最喜欢的编辑器打开它。在该文件中创建一个基本的快速应用程序,以确保您的设置已准备就绪。

const express = require('express');
const twilio = require('twilio');

const PORT = process.env.PORT || 3000;
let app = express();

app.get('/', (req, res) => {
    res.send('Hello World!');
});

app.listen(PORT, () => {
    console.log(`Doorbell listening on port ${PORT}`);
});

通过运行 node . 启动应用程序。在你的终端上,你现在应该可以在你的浏览器上点击 http://localhost:3000/ 来看到一个神话般的“Hello World”页面。

Doorbell Hello, World

我们准备使用Twilio API。 我们的后端不仅要打电话给我们,还要给我们一个语音信息,说有人在门口。这样,即使我们不看我们的电话,当有人在门口时,我们也会知道谁在打电话。

在现有的 “/” 路由下,我们将创建两条路由。其中一个将用语音信息生成 TwiML,另一人将从我们的 Twilio 号码拨打我们的真实电话号码。

app.all('/greeting, (req, res) => {
    let twiml = new twilio.twiml.VoiceResponse();
    twiml.say("There's someone at the door", { voice: 'alice' });
    res.type('text/xml');
    res.send(twiml.toString());
});

app.get('/call', (req, res) => {
    let client = new twilio(
      process.env.TWILIO_ACCOUNT_SID,
      process.env.TWILIO_AUTH_TOKEN
    );
    let greetingUrl = req.protocol + '://' + req.get('host') + '/greeting';

    client.calls.create(
        {
            url: greetingUrl,
            to: process.env.MY_NUMBER,
            from: process.env.TWILIO_NUMBER
        },
        (err, call) => {
            if (err) {
                console.log(err);
            }
            res.send(call.sid);
        }
    );
});

请注意,我们如何将 greetingUrl 设置为应用程序内部的请求。当调用启动 Twilio 发出请求/调用,我们的应用程序将告诉 Twilio 从哪里得到 TwiML。

我正在使用环境变量来设置我的帐户凭据和电话号码。我的同事 Dominik 写了一篇文章,介绍如何在 Windows、MacOS 和 Linux 上设置环境变量。如果这不是你想要做的,你可以用你的令牌和电话号码替换 process.env.TWILIO_ACCOUNT_SIDprocess.env.TWILIO_AUTH_TOKENprocess.env.MY_NUMBERprocess.env.TWILIO_NUMBER 的值,你可以在 Twilio 仪表板。

我们的后端已经准备就绪,但是现在尝试运行它会导致失败,因为我们告诉 Twilio 访问仅在本地计算机上运行的应用程序。我们可以用 ngrok 来运行它。我的另一个同事 Kevin 写了一篇文章,告诉你如何用 ngrok 在本地测试你的 webhook

停止并重新启动 Node 应用程序,并在新的终端窗口上运行:

ngrok http 3000

它会给你一个转发网址,你可以复制和粘贴到浏览器。

Ngrok 代理到本地

在您的浏览器上打开 URL 会给你 “Hello World” 页面,但是如果你去到 /call 路由,你的手机应该会响,你会得到一个消息,说 there's someone at the door

让我们看看,如何将这个 API 与我们的 Android Things 应用程序结合。

连接硬件

现在,我们已经启动并运行了后端API,让我们将硬件连接在一起,当有人按下按钮时,我们的 Android Things 应用程序向我们的 API 发出请求,使我们的电话响起。

我们将在 Raspberry Pi 3 上使用 3 个引脚:

  • **BCM6(31)是一个通用 I/O 引脚
  • 5V 电源(2)
  • GND 接地(39)。

连接硬件

我们也会把我们的按钮和电阻连接到面包板上,如下所示:

Raspberry Pi 连接面包板

让我们看看,需要监听的按钮,并按 API 调用做出反应。

构建应用程序

打开 Android Studio 并创建一个名为 Doorbell的新项目。我将所有 Android Things 的项目存储在 ~/Projects/Android/Things 目录下。你也可以在这个仓库中看到所有的代码。

请确保此项目的最低 SDK 为 24 或以上,因为 Android Things 仅在 Nougat 后兼容。

Android Things 版本

接下来,选择 Empty Activity,然后在下一个屏幕上按结束以创建一个空的 Activity

我们将开始为我们的新 Android 项目添加一些依赖关系,并通过更改 Manifest 以使应用程序具有正确的权限,最重要的是,当 Raspberry Pi 上电时它会自行启动。这一点很重要,因为我们没有接口来在 Raspberry Pi 上启动应用程序。

打开应用程序级别的 build.gradle,并添加以下依赖项:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.1.0'
    testCompile 'junit:junit:4.12'
    compile 'com.google.android.things.contrib:driver-button:0.2'
    provided 'com.google.android.things:androidthings:0.1-devpreview'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-scalars:2.1.0'
}

首先,我们添加了 Android Things 以及允许我们与硬件按钮交互的按钮驱动程序。然后,我们添加 Retrofit,这将使我们更容易地使用我们的门铃的 API。让 gradle 现在就做这件事,然后同步。

打开 AndroidManifest.xml 并请求 INTERNET 的权限。 我们需要这个能够从应用程序发出外部 HTTP 请求。

<?xml version="1.0" encoding="utf-8"?>
<manifest package="rocks.androidthings.doorbell" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"></uses-permission>

仍然在清单文件(manifest)中,在现有的 .MainActivity 下添加一个新的 Intent Filter,以便应用程序在启动时自动启动。

<activity android:name=".MainActivity">
<!-- Launch activity as default from Android Studio -->
<intent-filter>
<action android:name="android.intent.action.MAIN"></action>
<category android:name="android.intent.category.LAUNCHER"></category>
</intent-filter>
<!-- Launch activity automatically on boot -->
<intent-filter>
<action android:name="android.intent.action.MAIN"></action>
<category android:name="android.intent.category.IOT_LAUNCHER"></category>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</activity>

Retrofit 使用接口来生成将与 API 通信的代码。在 Doorbell 包中创建一个称为 “Doorbell” 的新 Java 类,与您的 MainActivity 一起使用。

Doorbell 接口里添加一个 GET 请求到门铃 API。

interface Doorbell {
   @GET("call")
   Call<string> startCall();
}

我们将 call 作为属性传递给 @GET,因为它直接映射到我们的 Node 应用程序路由,在本例中为 /call

现在打开 MainActivity 并将以下变量添加到类的顶部:

public class MainActivity extends AppCompatActivity {
    private final String BUTTON_GPIO_PIN = "BCM6";
    private static final String TAG = "MainActivity";
    private static final String BASE_URL = "http://6e9c6cf2.ngrok.io/";

    private Button mButton;
    private Doorbell mDoorbellApi;

您可以通过按 Alt + Enter 来解决依赖关系,但是在解析 Button 时要注意,因为至少会有一些选项,您应该选择 com.google.android.things.contrib.driver.button.Button

并确保你改变了 BASE_URL 来匹配你从服务器得到的 URL,或者在你本地运行应用程序的情况下使用 ngrok。

onCreate 方法下创建一个名为 initialiseDoorbellButton 的新方法。这个方法将注册我们的物理按钮,并添加一个事件监听器,当按钮被按下时。

private void initialiseDoorbellButton() {
   try {
       mButton = new Button(BUTTON_GPIO_PIN,
               Button.LogicState.PRESSED_WHEN_LOW);
       mButton.setOnButtonEventListener(mButtonCallback);
   } catch (IOException e) {
       Log.e(TAG, "button driver error", e);
   }
}

让我们创建按钮被按下时的事件监听器。

private Button.OnButtonEventListener mButtonCallback =
    new Button.OnButtonEventListener() {
        @Override
        public void onButtonEvent(Button button, boolean pressed) {
            if (pressed) {
                // Doorbell rang!
                Log.d(TAG, "button pressed");
            }
        }
    };

onCreate 方法上,添加一个调用 initialiseDoorbellButton(); 所以我们注册的应用程序启动时,按钮和事件监听器。

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

    initialiseDoorbellButton();
}

连接测试

按下运行按钮或按 CTRL + R 运行应用程序。如果您的 Raspberry Pi 没有列在连接的设备列表中,请切换回您的终端并运行 adb connect Android.local。你的树莓派现在应该显示在列表中。

应用程序完成构建和安装后,按面包板上的按钮,每次按下按钮时都会看到 Android Monitor 中记录的消息。

真棒! 我们现在已经集成了外部硬件和我们的 Android 应用程序,但是我们还没有接到任何电话。

与 Twilio 搭档

仍然在 MainActivity 中添加一个调用 onCreate 方法内的 Retrofit 来请求我们的门铃 API。

initialiseDoorbellButton();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(ScalarsConverterFactory.create())
        .build();

mDoorbellApi = retrofit.create(Doorbell.class);

现在我们要在每次按下按钮时调用 mDoorbellApi 中的 startCall方法。回滚到 Button.OnButtonEventListener 并在 “button press” 日志下,添加一个调用我们的 API。

// Doorbell rang!
Log.d(TAG, "button pressed");
Call<string> call = mDoorbellApi.startCall();
call.enqueue(new Callback<string>() {
    @Override
    public void onResponse(Call<string> call, Response<string> response) {
        Log.i(TAG, response.body());
    }

    @Override
    public void onFailure(Call<string> call, Throwable t) {
        Log.e(TAG, t.getMessage());
    }
});

我们正在根据 API 请求的结果记录调用 Sid 或错误消息。

再次运行应用程序,当按下按钮时,手机应该响起。

总结

我们现在有了一个聪明的门铃,每当有人在门口,我们就会打电话给我们。 我知道我再也不会错过包裹送货。

但是,如何使用相机模块,以便您还可以获得彩铃信息,其中包含门铃铃声的图片?

通过 @marcos_placona 在 Twitter 上联系我,或者通过邮箱 marcos@twilio.com 告诉我你在做些什么。

英语原文链接:https://www.twilio.com/blog/2017/06/build-a-smart-doorbell-with-twilio-and-android-things.html

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

观光\评论区

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