Siri语音识别读取传感器数据 | ESP32学习之旅-Arduino版-Arduino中文社区 - Powered by Discuz! Archiver

铁熊 发表于 2020-6-5 15:45

Siri语音识别读取传感器数据 | ESP32学习之旅-Arduino版



大家好,我是铁熊。本期给大家带来的是掌控板 Siri 语音识别的第 2 篇:**如何通过 Siri 语音识别获取传感器数据**。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200322112451615.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2lyb25wYW5kYWFh,size_16,color_FFFFFF,t_70)

掌控板 Siri 语音识别的第 1 篇跳转:(https://mp.weixin.qq.com/s/iNKaNmAN3nTWsaPIg0lEXA)

国际惯例,先来看一下演示效果吧。点击下方链接跳转 B 站观看演示视频:

(https://www.bilibili.com/video/av98141978/)

# 项目概述

在上一篇中,我向大家详细展示了如何利用 Siri 控制掌控板和 LED 灯,这一篇是上一篇的进阶,我将继续教大家如何用 Siri 去读取各种传感器的数据。

没看过上一篇的朋友,建议先去看一下第 1 篇的内容。

跳转链接:[掌控板 Siri 语音识别的第 1 篇:LED 灯控制](https://mp.weixin.qq.com/s/iNKaNmAN3nTWsaPIg0lEXA)

这次主控板选择的仍然是掌控板,当然正如我前面篇章所说的,你也可以选择其他 ESP32 或者 ESP8266 系列开发板,实现的方法和效果是类似的。读取的传感器数据包括掌控板自带的声音传感器、光线传感器、以及外接的 DHT11 温湿度传感器,学习了本篇章之后,希望你可以学会修改相应代码,换成其他传感器。

在这个项目中,我们同样将掌控板 ESP32 设置为一个 Web 服务器,当用户在网页上访问这个服务器的域名地址(或 IP 地址)的时候,就会跳转到如下界面。最终实现的效果是,不仅可以用 Siri 语音识别去获取传感器数据,也可以直接在网页端查看传感器数据。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvd2VicGFnZS5wbmc?x-oss-process=image/format,png)

我们可以通过点击 **LED** 的切换开关来控制掌控板上的 RGB LED 的亮灭,也可以访问这个切换开关的对应域名地址,来控制 LED 灯的亮灭。

针对传感器,我们可以直接在网页上一次性读取所有传感器的数据,也可以单独访问每个传感器对应的域名地址来读取相应的数据。这样就完成了基本的通过 Web 页面控制掌控板以及读取数据的功能。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvd2ViLWtvbmctemhpLWt1YW5nLWppYS5wbmc?x-oss-process=image/format,png)

在这基础之后,我们可以通过设置一些语音助手,比如 Siri、天猫语音精灵等,通过语音命令访问对应的域名地址,从而实现语音识别开关灯、读取传感器数据的功能。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvc2lyaS1rb25nLXpoaS1rdWFuZy1qaWEucG5n?x-oss-process=image/format,png)

# 电路连接

本项目中,我们需要外接一个 DHT11 温湿度传感器,通过扩展板将它接在掌控板 P0 引脚,如下图所示。声音数据和光线数据,直接通过掌控板账面自带的两个传感器读取即可。

![电路接线](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvZGlhbi1sdS1qaWUteGlhbi5wbmc?x-oss-process=image/format,png)

# 库文件安装

这个项目需要用到 4 个 Arduino 库:除了上一篇章用到的 **Adafruit_NeoPixel**、**ESPAsyncWebServer**、**AsyncTCP** 之外,我们还加入了 **DHT** 函数库,它的功能主要是读取 DHT11 温湿度传感器的数值。。

Arduino 库安装的教程不是本篇的重点,这里不再赘述,只给出 4 个库的网址,大家可以自行百度查找 Arduino 怎么安装库。

- Adafruit_NeoPixel:https://github.com/adafruit/Adafruit_NeoPixel
- ESPAsyncWebServer:https://github.com/me-no-dev/ESPAsyncWebServer
- AsyncTCP:https://github.com/me-no-dev/AsyncTCP
- DHT:https://github.com/adafruit/DHT-sensor-library

# Arduino 代码

这一篇章的代码是在上一篇章的基础之上进行修改的,所以基础部分不再赘述,只讲解不同与添加部分。

### 头文件及初始化定义

在程序的开头,我们首先引入了需要用到的库函数:

```cpp
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "Adafruit_NeoPixel.h"
#include "Adafruit_Sensor.h"
#include "DHT.h"
```


然后设置网络的账号和密码:

```cpp
const char *ssid = "wifi_name";
const char *password = "wifi_password";
```

接着定义一些传感器与执行器引脚,并对他们进行一些初始化设置:

```cpp
#define SOUNDPIN 36   // P10
#define LIGHTPIN 39   // P4
#define LEDPIN 17   // P7

#define DHTPIN 33   // P0
```

接着定义了 DHT 对象、NeoPixel 对象(RGB LED 灯)和 WebServer 对象:

```cpp
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

Adafruit_NeoPixel pixels(3, LEDPIN, NEO_GRB + NEO_KHZ800);
AsyncWebServer server(80);
```

### Web 页面设计

然后是掌控板 Web 服务器的界面设计,界面设计使用的是 HTML 语言,这里先放一个最基础的界面设计。HTML 相关的代码存储在 **index_html** 变量中。

```cpp
const char index_html[] PROGMEM = R"rawliteral(
    // HTML code here
)rawliteral";
```

基础的 HTML 页面设计代码如下:

```html
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      html {
      font-family: "Microsoft Yahei";
      text-align: center;
      }
    </style>
</head>
<body>
    <h2>掌控板家庭数据中心</h2>
    <a href="/led=on">Light On</a>
    <p></p>
    <a href="/led=off">Light Off</a>
    <p>
      <span>声音:</span>
      <span>%SOUND%</span>
    </p>
    <p>
      <span>光线:</span>
      <span>%LIGHT%</span>
    </p>
    <p>
      <span>温度:</span>
      <span>%TEMPERATURE%</span>
      <span>℃</span>
    </p>
    <p>
      <span>湿度:</span>
      <span>%HUMIDITY%</span>
      <span>%</span>
    </p>
</body>
</html>
```

这段代码在网页中显示的效果如下。我们可以看到很多数据是在两个百分号(%)之间的,比如 **%SOUND%**,这个是占位符,我们在程序中读取相应传感器的数据之后,就可以自动替换了,程序中会有专门的函数程序去进行替换,这部分下面会讲。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvc2ltcGxld2VicGFnZS5wbmc?x-oss-process=image/format,png)

### 传感器数据读取函数

首先是读取 DHT11 温湿度传感器的函数,这部分比较简单,直接参考 DHT 函数库例程就好:

```cpp
String readDHTTemperature() {
float temperature = dht.readTemperature();
if (isnan(temperature)) {
    Serial.println("Failed to read from DHT sensor!");
    return "--";
}
else {
    Serial.println(temperature);
    return String(temperature);
}
}

String readDHTHumidity() {
float humidity = dht.readHumidity();
if (isnan(humidity)) {
    Serial.println("Failed to read from DHT sensor!");
    return "--";
}
else {
    Serial.println(humidity);
    return String(humidity);
}
}
```

然后是 **processor()** 函数,这个函数的功能主要就是**将网页部分的所有占位符替换为相应的传感器数值**。它可以根据占位符的名称,返回对应的数据。

```cpp
// Replaces placeholder with sensor values
String processor(const String& var) {
if (var == "SOUND") {
    return String(analogRead(SOUNDPIN));
}
if (var == "LIGHT") {
    return String(analogRead(LIGHTPIN));
}
if (var == "TEMPERATURE") {
    return readDHTTemperature();
}
if (var == "HUMIDITY") {
    return readDHTHumidity();
}
return String();
}
```

### setup()

在初始化函数 **setup()** 中,我们首先对串口、RGB 灯和 DHT11 传感器进行了初始化:

```cpp
Serial.begin(9600);
pixels.begin();
dht.begin();
```

然后将掌控板连接到网络,并把 IP 地址在串口中打印出来:

```cpp
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
    delay(1000);
    Serial.println("Connecting to WiFi..");
}
Serial.println("WiFi connected");

// Print ESP32 Local IP Address and Some Tips
Serial.print("Open your brower, and visit: http://");
Serial.println(WiFi.localIP());
Serial.println();
```

最后就是最重要的 Web 服务器设置。关于 Web 服务器设置的详细教程,可以查看官网:https://github.com/me-no-dev/ESPAsyncWebServer

这里只放出本文需要的代码。当访问根目录“**/**”时,会显示所有的数据以及相关的控制按钮。这里显示数据调用的就是上面讲到的 **processor** 函数。

```cpp
// Root / Webpage
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/html", index_html, processor);
});
```

当访问“**/led=on**”路径时,设置 LED 灯为亮;当访问“**/led=off**”路径时,设置 LED 灯为灭。

```cpp
// Webpage to turn on light
server.on("/led=on", HTTP_GET, [](AsyncWebServerRequest *request) {
    pixels.setPixelColor(0, 0xFF0000);
    pixels.setPixelColor(1, 0xFF0000);
    pixels.setPixelColor(2, 0xFF0000);
    pixels.show();
    Serial.println("LED is on");
    request->send_P(200, "text/plain", "led on");
});

// Webpage to turn off light
server.on("/led=off", HTTP_GET, [](AsyncWebServerRequest *request) {
    pixels.setPixelColor(0, 0x000000);
    pixels.setPixelColor(1, 0x000000);
    pixels.setPixelColor(2, 0x000000);
    pixels.show();
    pixels.clear();
    Serial.println("LED is off");
    request->send_P(200, "text/plain", "led off");
});
```

然后当访问每个传感器相应路径时,比如"**/temperature**"、"**/humidity**"、"**/sound**"、"**/light**"这些路径,程序会调用相应的函数读取传感器数据,通过串口将数据打印出来,然后将它们转化成文本 String 类型,并显示在网页上:

```cpp
// Webpage to get the temperature value
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request) {
    Serial.print("Temperature: ");
    Serial.println(readDHTTemperature());
    request->send_P(200, "text/plain", readDHTTemperature().c_str());
});

// Webpage to get the humidity value
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request) {
    Serial.print("Humidity: ");
    Serial.println(readDHTHumidity());
    request->send_P(200, "text/plain", readDHTHumidity().c_str());
});

// Webpage to get the sound value
server.on("/sound", HTTP_GET, [](AsyncWebServerRequest *request) {
    Serial.print("Sound: ");
    Serial.println(analogRead(SOUNDPIN));
    request->send_P(200, "text/plain", String(analogRead(SOUNDPIN)).c_str());
});

// Webpage to get the light value
server.on("/light", HTTP_GET, [](AsyncWebServerRequest *request) {
    Serial.print("Light: ");
    Serial.println(analogRead(LIGHTPIN));
    request->send_P(200, "text/plain", String(analogRead(LIGHTPIN)).c_str());
});
```

在 setup() 函数的最后,运行 Web 服务器:

```cpp
server.begin();
```

至此,整个程序就编写完成了,**在 loop() 函数中,不需要做任何事**,当然你也可以运行其他你想要的代码。

# 程序上传

在 Arduino 中选择掌控板或者 ESP32 相关的芯片,然后将程序上传,打开串口监视器,我们可以看到串口监视器中提示我们访问相应的网址。(如果没看到相应信息,可以按一下掌控板后面的 RST 按键,重启程序)

![串口监视器打印网址](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvY2h1YW4ta291LWppYW4tc2hpLXFpLWRhLXlpbi13YW5nLXpoaS5wbmc?x-oss-process=image/format,png)

打开电脑浏览器或者手机浏览器,访问相应的 IP 地址,这里是:192.168.10.202,我们可以看到网页上显示了相应的信息。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvd2VicGFnZS1qaWFuLWRhbi1iYW4ucG5n?x-oss-process=image/format,png)

尝试访问对应的地址,当访问 **192.168.10.202/led=on** 时,浏览器和串口监视器中,都输出了相应的提示信息,同时我们也可以看到掌控板上的 RGB 灯也亮了起来。当访问 **192.168.10.202/led=off** 时,浏览器和串口监视器中,也都输出了相应的提示信息,同时掌控板上的 RGB 灯也熄灭了。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvbGVkLnBuZw?x-oss-process=image/format,png)

当访问 **192.168.10.202/sound** 以及其他传感器对应的网址是,浏览器和串口监视器中,也都输出了相应的提示信息,如下图所示。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvc291bmQucG5n?x-oss-process=image/format,png)

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvdGVtcGVyYXR1cmUucG5n?x-oss-process=image/format,png)

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvaHVtaWRpdHkucG5n?x-oss-process=image/format,png)

# 网页设计

*这部分不是本文的重点,也不会影响最终语音控制的效果,所以如果您对网页设计不感兴趣,也可以略过,直接跳转到下一节。*

在上文中,我们已经基本完成了通过网页来控制 LED 灯、以及读取传感器数据的相关功能,但是这个网页毕竟还是太简陋了。所以我们对网页稍微进行一些优化。

具体 HTML 优化代码请下载附件,这部分参考了国外大神的网站:https://randomnerdtutorials.com/

上述代码最终形成的效果如下。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvd2VicGFnZS5wbmc?x-oss-process=image/format,png)

# 语音助手设置

接下来就是语音识别的设置,原理与上一篇 Siri 教程类似。由于笔者手上没有其他语音助手或者智能音箱类产品,所以这里还是以 Siri 为例。

打开 iOS 系统自带的**捷径** App(英文名称 **Shortcuts**),没有没有的话,也可以去 App Store 免费下载:

![捷径下载](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMTUvamllLWppbmcteGlhLXphaS5qcGc?x-oss-process=image/format,png)

快捷指令设置如下图所示。捷径的设置原理很简单,就是访问给定的 URL 地址。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvc2hvcnRjdXRzLXNoZS16aGkucG5n?x-oss-process=image/format,png)

由于 iPhone 中的捷径是支持 Siri 语音识别调用的,所以我们可以直接通过 Siri 来运行这个捷径,从而达到语音识别获取传感器数据的效果。

如果不知道怎么设置快捷指令的话,也可以直接下载笔者的指令。复制下面的链接到 iPhone 浏览器中,就会提示你将这个指令添加到手机中。

(https://www.icloud.com/shortcuts/4e20f185da76479a90f0716c9521cc7a)

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvc2hvcnRjdXRzLWZlbi14aWFuZy5wbmc?x-oss-process=image/format,png)

# 效果演示

唤醒你的 Siri 看看效果吧。不过这里需要注意的是,你的 iPhone 和掌控板,必须处于同一局域网中。

!(https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pcm9ucGFuZGEtMTI1OTc4MTExNS5jb3MuYXAtc2hhbmdoYWkubXlxY2xvdWQuY29tLzIwMjAtMDMtMjEvc2lyaS15dS15aW4tZmFuLWt1aS5wbmc?x-oss-process=image/format,png)

# 总结

在本章中,我们学习了:

- 进一步学习了 WebServer 的基础用法;
- 然后通过设计 HTML 网页代码,让交互界面更加友好方便;
- 最后通过 iOS 的捷径应用,实现了语音识别获取传感器数据的功能

相比上一篇 Siri 控制 LED 灯的内容,如果不考虑网页设计相关内容的话,其实 Arduino 代码端基本是类似的,希望读者可以学会扩展。

如果本文对你有帮助的话,点个赞支持一下喽。

# 代码下载

点击下方链接,查看完整代码下载地址:

(https://mp.weixin.qq.com/s/w1-XIcgaddqlcSpnqZPD8A)
页: [1]
查看完整版本: Siri语音识别读取传感器数据 | ESP32学习之旅-Arduino版