Arduino应用开发-通过小爱控制灯光
目录
- Arduino应用开发-通过小爱控制灯光
-
- 前言
- 1 工作原理
- 2 硬件准备
- 3 软件准备
-
- 3.1 Arduino IDE环境搭建
- 3.2 Blinker APP注册和使用帐户
- 4 编写程序
- 5 关联米家APP和Blinker设备
- 6 语音控制测试
- 7 进阶用法
-
- 7.1 亮度控制
- 7.2 色温控制
- 7.3 模式控制
- 结束语
前言
我之前发表过一篇关于如果用手机的文章APP控制LED灯的文章,是基于Blink APP以及它的服务器,我们在以前的基础上做了一些扩展,通过手机爱学生,使用语音控制灯。没有看过最后一个博客的学生可以先看看。
Arduino应用开发-手机APP控制LED
1 工作原理
Blinker制造商有自己的服务器,我们的设备(esp8266、esp32.手机等。)可以通过网络访问此服务器app我们看不到源代码不确定以什么方式访问。我主要谈谈MCU(esp8266、esp32等)这边,MCU是通过WIFI连接到互联网的,然后通过MQTT协议接入到Blinker的服务器,MCU服务器作为客户端,作为服务端。具体MQTT这里就不多说实现原理了,光是MQTT这个话题可以写很多文章,想深入了解的同学可以自己查资料。 当MQTT连成功后,MCU将继续听,等待服务器发布数据。这个时候,我们可以通过手机app比如点击开灯,服务器收到开灯命令后会通过MQTT发送命令到MCU,MCU执行点灯操作后,接收数据并分析命令。这里的服务器相当于一个中转站,将手机操作转发到设备端,实现手机与设备之间的互动。但需要注意的是,设备和服务器是通过的MQTT而手机app服务器不一定使用MQTT,个人觉得用http它更有可能,但看不到源代码,所以不清楚它是如何通信的是很重要,也不影响实际使用。
: 注:这里的小爱同学可以是小米手机里的小爱,也可以是小米的智能音箱。 我们已经把我们的设备放在前面了(esp8266、esp32等)连接到Blinker实现数据上传下发的服务器。而Blinker对接小爱本身,并设置了一些固定的语音指令。我们只通过米家APP关联Blinker小爱可以实现小爱同学和Blinker服务器前的服务器联动Blinker通过连接服务器和我们的硬件设备,可以间接实现小硬件设备的交互。 简单来说就是我们的语音指令通过小爱同学发送到Blinker服务器,再由Blinker将服务器转发给我们的硬件设备。Blinker服务器在数据分析和据分析和中转的作用。
2 硬件准备
我这里以ESP8266和ESP32为例讲解,其他MCU方法和原则是一样的,所以根据自己的原则MCU选择其中一个。 硬件配置如下:
模块 | 型号 | 说明 |
---|---|---|
ESP8266 | ESP-12F | 这是安信可的模块,主要用于乐信ESP8266EX再加一个片外FLASH组成,开发板型号是NodeMCU-12F(CH340版本) |
ESP32 | ESP-WROOM-32 | MCU是乐信的芯片,开发板型号ESP32 DEVKITV1 |
这里就不发出具体的硬件参数和电路原理图了,不同厂家做的开发板引脚可能会有同。
3 软件准备
版本说明: 各软件使用的版本如下:
软件 | 版本 | 备注 |
---|---|---|
Arduino IDE | 1.8.16 | Blinker需要配合1.8.x以上版本Arduino IDE |
ESP8266 package | 3.0.2 | Blinker需配合使用3.0.0或以上release版本的ESP8266 package |
ESP32 package | 3.0.2 | Blinker需配合使用2.0.0或以上版本ESP32 package |
Blinker arduino package | 0.3.9 | 当前最新版本未来可能会更新 |
Blinker APP | 2.5.2(安卓版) | 当前最新版本未来可能会更新 |
米家APP | 7.5.705.5319(安卓版) | 当前最新版本未来可能会更新 |
3.1 Arduino IDE环境搭建
这在我的博客里已经说过很多次了,这里就不说了。不懂的同学先按一下,把环境搭好(根据自己的情况)MCU选择对应的教程)。 Arduino应用开发-手机APP控制LED esp基于8266开发入门教程Arduino)——环境安装 ESP32 Arduino开发环境建设
3.2 Blinker APP注册和使用帐户
这个内容比较多,这里就不赘述了。不懂的同学先看上面说的第四点。 Arduino应用开发-手机APP控制LED
4 编写程序
上一个教程讲了怎么用。Blinker APP创建设备并实现远程控制。 Arduino应用开发-手机APP控制LED
在此基础上,增加了小艾的语音控制。我们保留了最后一个功能,然后增加了两个回调函数电源控制和设备查询。这两个函数的接口在Blinker库源码已经定义,我们可以直接使用。我们通过电源控制回调函数实现LED灯的开关控制。 示例代码: 提示:代码中的WIFI根据实际情况修改帐号和密码。
#define BLINKER_WIFI
#
define BLINKER_MIOT_LIGHT // 灯设备
// #define BLINKER_MIOT_OUTLET // 插座设备
// #define BLINKER_MIOT_MULTI_OUTLET // 多个插座设备
// #define BLINKER_MIOT_SENSOR // 传感器设备
// #define BLINKER_MIOT_FAN // 风扇设备
// #define BLINKER_MIOT_AIR_CONDITION // 空调设备
#include <Blinker.h>
char auth[] = "e6fce38e525a"; // 设备密钥
char ssid[] = "test"; // WIFI账号
char pswd[] = "123456789"; // WIFI密码
#define LED_PIN 2 // LED引脚
// 新建组件对象
BlinkerButton Button1("btn-abc");
BlinkerNumber Number1("num-abc");
int counter = 0;
bool oState = false;
// 电源控制回调函数
void miotPowerState(const String & state)
{
BLINKER_LOG("need set power state: ", state);
if (state == BLINKER_CMD_ON)
{
// 打开开关
digitalWrite(LED_PIN, HIGH); // 开灯
BlinkerMIOT.powerState("on");
BlinkerMIOT.print();
oState = true;
}
else if (state == BLINKER_CMD_OFF)
{
// 关闭开关
digitalWrite(LED_PIN, LOW); // 关灯
BlinkerMIOT.powerState("off");
BlinkerMIOT.print();
oState = false;
}
}
// 查询设备状态回调函数
void miotQuery(int32_t queryCode)
{
BLINKER_LOG("MIOT Query codes: ", queryCode);
switch (queryCode)
{
case BLINKER_CMD_QUERY_ALL_NUMBER : // 查询所有设备
BLINKER_LOG("MIOT Query All");
BlinkerMIOT.powerState(oState ? "on" : "off");
BlinkerMIOT.print();
break;
case BLINKER_CMD_QUERY_POWERSTATE_NUMBER : // 查询电源类设备
BLINKER_LOG("MIOT Query Power State");
BlinkerMIOT.powerState(oState ? "on" : "off");
BlinkerMIOT.print();
break;
default : // 查询其他设备
BlinkerMIOT.powerState(oState ? "on" : "off");
BlinkerMIOT.print();
break;
}
}
// 按下按键即会执行该函数
void button1_callback(const String & state)
{
BLINKER_LOG("get button state: ", state);
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // 翻转LED灯状态
}
// 如果未绑定的组件被触发,则会执行其中内容
void dataRead(const String & data)
{
BLINKER_LOG("Blinker readString: ", data);
counter++;
Number1.print(counter);
}
void setup()
{
// 初始化串口
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);
BLINKER_DEBUG.debugAll();
// 初始化LED的IO
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
// 初始化blinker
Blinker.begin(auth, ssid, pswd);
Blinker.attachData(dataRead); // 未绑定设备回调
Button1.attach(button1_callback); // 按键回调
BlinkerMIOT.attachPowerState(miotPowerState); // 电源控制回调
BlinkerMIOT.attachQuery(miotQuery); // 查询设备状态回调
}
void loop() {
Blinker.run();
}
5 关联米家APP和Blinker设备
打开 米家APP
,点击我的
,点击其他平台设备
,点击添加
,在列表中找到点灯科技
,点击绑定账号
,登录你的Blinker账号,最后点击同步设备
即可。设备同步成功之后就可以看到你在Blinker APP上创建的所有设备。 提示1:Blinker账号的注册以及APP的使用请跳转到3.2查看。我在上一篇博客有详细的教程。 提示2:同步设备可能会出现失败的情况,我一开始同步的时候一直失败,过了一段时间之后再尝试又没出现了,不知道是不是APP的bug。
6 语音控制测试
特别说明:我没有小爱同学的智能音箱,我这里是直接用小米的手机来测试的。 注:其他品牌的手机可以下载米家APP,但是没法使用小爱同学。 把烧录好代码的设备通上电,通过串口打印的一些信息,我们可以看到设备正常连上网络之后会连接到Blinker的服务器,连接成功之后可以在Blinker的APP上看到设备的状态由 ‘离线’ 变成 ‘在线’。
小爱同学支持的开关类控制语音如下:
打开/关闭{
门口}的{
灯}
提示1:{}里面的内容是通配多种关键词的,你可以在Blinker APP修改设备的名称,然后语音对应的命令也要跟着改变,保持一致才能正确的控制设备。
对着小米手机呼叫小爱同学
,收到回应之后再说打开灯
,就能看到设备的LED灯被打开了。同理,关闭灯的指令也是一样的操作。 通过串口打印的信息也可以看到开灯和关灯相关的指令。 至此,从小爱同学到硬件设备的整个流程就走通了。流程走通了之后我们就可以在这个基础上增加更多的功能,比如控制灯的亮度,设备工作模式等等,也可以修改设备的名称,或者控制更多其他类型的设备。
7 进阶用法
通过Blinker关联小爱同学控制设备其实有很大的局限性,因为小爱同学所有的语音指令都是Blinker定义好的,不支持做过多的修改,而且目前支持的语音指令实在是有点少,当我们需要自定义一些指令时并不能通过这套代码实现。不过如果只是玩一下或者学习的话,还是可以去研究一下的。 关于Blinker以及小爱同学所支持的设备和语音指令在点灯科技的官网上其实有比较详细的介绍。 点灯科技小米小爱技术文档:https://diandeng.tech/doc/xiaoai
我们这里也基于这些给定的语音指令做一些进阶的操作。 前面的示例我们通过小爱同学控制了灯的亮灭,然后现在我们增加LED灯亮度、色温以及模式的控制。 特别说明:要实际控制灯的亮度和色温的话我们需要用到RGB灯,而且有些比较简单的GRB灯只能调节三色灯的亮灭,最多也只能调出8种颜色,如果需要调节出多种色温,还需要调节三色灯里面每一个灯的亮度。每个灯的亮度阶梯越多,能跳出来的色彩就越多。如果是单色LED的话最多只能调亮度,是没办法改变颜色的,亮度调节可以通过PWM实现。 我这里因为现在手头上也没有合适的灯,这里就不做具体的演示了,我这里只讲一下怎么把小爱语音和LED灯的控制代码关联起来,至于实际的一些操作,感兴趣的同学可以自己再补充。
7.1 亮度控制
小爱同学支持的亮度控制语音如下:
把{
卧室}的{
灯}的{
亮度调高一点}
亮度范围为1-100
注:括号里面的的关键字是可以用户自己修改定义的。比如:灯可以换成其他关键字,如氛围灯、大灯等,这个是跟你在Blinker APP里面修改的设备名称保持一致的。
示例代码: 提示:我这里只把新增的函数列出来,等后面把亮度、色温以及模式的控制全部讲完之后再列一个完整的代码。
// 灯光亮度控制回调函数
void miotBright(const String & bright)
{
BLINKER_LOG("need set brightness: ", bright); // 打印需要设置的亮度
uint8_t colorW = bright.toInt();
BLINKER_LOG("now set brightness: ", colorW);
// 在此处我们可以根据实际情况添加一些控制的代码,比如:通过修改PWM占空比的值,从而达到调节灯亮度的目的
BlinkerMIOT.brightness(colorW);
BlinkerMIOT.print();
}
// 灯光亮度控制初始化
BlinkerMIOT.attachBrightness(miotBright);
测试结果: 特别说明:因为我的硬件并没有接入能调光的灯,所以这里我只把接收到的语音指令打印了出来,硬件上并没有做实际的操作。 对着小爱同学说:把灯的亮度调到60
。通过串口打印的信息我们可以看到,设备已经收到了这个命令,并且把要调节的亮度值60解析出来了,只不过我实际上并没有做控灯的操作,因此,LED灯是没有变化的。
7.2 色温控制
小爱同学支持的色温控制语音如下:
把{
卧室}的{
灯}调为{
红色}
颜色范围为0-16777215(0xFFFFFF)
示例代码: 提示:我这里只把新增的函数列出来,等后面把亮度、色温以及模式的控制全部讲完之后再列一个完整的代码。
// 灯光色温控制回调函数
void miotColor(int32_t color)
{
BLINKER_LOG("need set color: ", color);
// 从接收到的数据中解析得到需要配置的R G B三色光的亮度值
uint8_t colorR = color >> 16 & 0xFF;
uint8_t colorG = color >> 8 & 0xFF;
uint8_t colorB = color & 0xFF;
BLINKER_LOG("colorR: ", colorR, ", colorG: ", colorG, ", colorB: ", colorB);
// 在此处我们可以根据实际情况添加一些控制的代码,比如:通过修改R G B三个灯的亮度从而达到修改灯颜色的目的
BlinkerMIOT.color(color);
BlinkerMIOT.print();
}
// 灯光色温控制初始化
BlinkerMIOT.attachColor(miotColor);
测试结果: 特别说明:因为我的硬件并没有接入能调光的灯,所以这里我只把接收到的语音指令打印了出来,硬件上并没有做实际的操作。 对着小爱同学说:把灯调为紫色
。通过串口打印的信息我们可以看到,设备已经收到了改命令,只不过我实际上并没有做控灯的操作,因此,LED灯是没有变化的。 提示:这里RGB三元光的亮度范围是0-255,把三种亮度不同的光混合在一起就能产生多种多样的颜色。
7.3 模式控制
小爱同学支持的色温控制语音如下:
把{
卧室}的{
灯}设置为{
xx模式}
示例代码: 提示:我这里只把新增的函数列出来,后面有完整的代码。
// 模式控制回调函数
void miotMode(uint8_t mode)
{
BLINKER_LOG("need set mode: ", mode); // 打印接收到需要设置的模式,数值是(0-6),对应7种模式
if (mode == BLINKER_CMD_MIOT_DAY) {
// 日光模式,在这里面可以添加自己实际需要控制的代码
}
else if (mode == BLINKER_CMD_MIOT_NIGHT) {
// 夜光模式,在这里面可以添加自己实际需要控制的代码
}
else if (mode == BLINKER_CMD_MIOT_COLOR) {
// 彩光模式,在这里面可以添加自己实际需要控制的代码
}
else if (mode == BLINKER_CMD_MIOT_WARMTH) {
// 温馨模式,在这里面可以添加自己实际需要控制的代码
}
else if (mode == BLINKER_CMD_MIOT_TV) {
// 电视模式,在这里面可以添加自己实际需要控制的代码
}
else if (mode == BLINKER_CMD_MIOT_READING) {
// 阅读模式,在这里面可以添加自己实际需要控制的代码
}
else if (mode == BLINKER_CMD_MIOT_COMPUTER) {
// 电脑模式,在这里面可以添加自己实际需要控制的代码
}
BlinkerMIOT.mode(mode);
BlinkerMIOT.print();
}
// 模式控制初始化
BlinkerMIOT.attachMode(miotMode);
测试结果: 特别说明:因为我的硬件并没有接入能调光的灯,所以这里我只把接收到的语音指令打印了出来,硬件上并没有做实际的操作。 对着小爱同学说:把灯调为夜光模式
。通过串口打印的信息我们可以看到,设备已经收到了改命令,只不过我实际上并没有做控灯的操作,因此,LED灯是没有变化的。 前面我也讲过,Blinker这套方案有比较大的局限性,就比如这里的模式,虽然支持多种模式,但是每一个模式都只能通过固定的关键字(日光、夜光、彩光等)来触发,不能自定义,如果是控灯还好,很多都可以用上,但是如果控制的是其他设备,这些模式的关键字就牛头不对马嘴了。 我也没有找到改指令关键字的接口,应该是Blinker没有开放这个接口或者不支持这个功能。这一点是不太友好的,不过Blinker毕竟是一个公司,目的还是盈利,而且维护服务器也是需要成本的,白嫖党也不能要求太多。
#define BLINKER_WIFI #define BLINKER_MIOT_LIGHT // 灯设备 // #define BLINKER_MIOT_OUTLET // 插座设备 // #define BLINKER_MIOT_MULTI_OUTLET // 多个插座设备 // #define BLINKER_MIOT_SENSOR // 传感器设备 // #define BLINKER_MIOT_FAN // 风扇设备 // #define BLINKER_MIOT_AIR_CONDITION // 空调设备 #include <Blinker.h> char auth[] = "e6fce38e525a"; // 设备密钥 char ssid[] = "tst"; // WIFI账号 char pswd[] = "123456789"; // WIFI密码 #define LED_PIN 2 // LED引脚 // 新建组件对象 BlinkerButton Button1("btn-abc"); BlinkerNumber Number1("num-abc"); int counter = 0; bool oState = false; // 电源控制回调函数 void miotPowerState(const String & state) { BLINKER_LOG("need set power state: ", state); if (state == BLINKER_CMD_ON) { // 打开开关 digitalWrite(LED_PIN, HIGH); // 开灯 BlinkerMIOT.powerState("on"); BlinkerMIOT.print(); oState = true; } else if (state == BLINKER_CMD_OFF) { // 关闭开关 digitalWrite(LED_PIN, LOW); // 关灯 BlinkerMIOT.powerState("off"); BlinkerMIOT.print(); oState = false; } } // 查询设备状态回调函数 void miotQuery(int32_t queryCode) { BLINKER_LOG("MIOT Query codes: ", queryCode); switch (queryCode) { case BLINKER_CMD_QUERY_ALL_NUMBER : // 查询所有设备 BLINKER_LOG("MIOT Query All"); BlinkerMIOT.powerState(oState ? "on" : "off"); BlinkerMIOT.print(); break; case BLINKER_CMD_QUERY_POWERSTATE_NUMBER : // 查询电源类设备 BLINKER_LOG("MIOT Query Power State"); BlinkerMIOT.powerState(oState ? "on" : "off"); BlinkerMIOT.print(); break; default : // 查询其他设备 BlinkerMIOT.powerState(oState ? "on" : "off"); BlinkerMIOT.print(); break; } } // 灯光亮度控制回调函数 void miotBright(const String & bright) { BLINKER_LOG("need set brightness: ", bright); uint8_t colorW = bright.toInt(); BLINKER_LOG("now set brightness: ", colorW); // 在此处我们可以根据实际情况添加一些控制的代码,比如:通过修改PWM占空比的值从而达到调节灯亮度的目的 BlinkerMIOT.brightness(colorW); BlinkerMIOT.print(); } // 灯光色温控制回调函数 void miotColor(int32_t color) { BLINKER_LOG("need set color: ", color); // 从接收到的数据中解析得到需要配置的R G B三色光的亮度值 uint8_t colorR = color >> 16 & 0xFF; uint8_t colorG = color >> 8 & 0xFF; uint8_t colorB = color & 0xFF; BLINKER_LOG("colorR: ", colorR, ", colorG: ", colorG, ", colorB: ", colorB); // 在此处我们可以根据实际情况添加一些控制的代码,比如:通过修改R G B三个灯的亮度从而达到修改灯颜色的目的 BlinkerMIOT.color(color); BlinkerMIOT.print(); } // 模式控制回调函数 void miotMode(uint8_t mode) { BLINKER_LOG("need set mode: ", mode); // 打印接收到需要设置的模式,数值是(0-6),对应7种模式 if (mode == BLINKER_CMD_MIOT_DAY) { // 日光模式,在这里面可以添加自己实际需要控制的代码 } else if (mode == BLINKER_CMD_MIOT_NIGHT) { // 夜光模式,在这里面可以添加自己实际需要控制的代码 } else if (mode == BLINKER_CMD_MIOT_COLOR) { // 彩光模式,在这里面可以添加自己实际需要控制的代码 } else if (mode == BLINKER_CMD_MIOT_WARMTH) { // 温馨模式,在这里面可以添加自己实际需要控制的代码 } else if (mode == BLINKER_CMD_MIOT_TV) { // 电视模式,在这里面可以添加自己实际需要控制的代码 } else if (mode == BLINKER_CMD_MIOT_READING) { // 阅读模式,在这里面可以添加自己实际需要控制的代码 } else if (mode == BLINKER_CMD_MIOT_COMPUTER) { // 电脑模式,在这里面可以添加自己实际需要控制的代码 } BlinkerMIOT.mode(mode); BlinkerMIOT.print(); } // 按下按键即会执行该函数 void button1_callback(const String & state) { BLINKER_LOG("get button state: ", state); digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // 翻转LED灯状态 } // 如果未绑定的组件被触发,则会执行其中内容 void dataRead(const String & data) { BLINKER_LOG("Blinker readString: ", data); counter++; Number1.print(counter