数码之家

 找回密码
 立即注册
搜索
查看: 10948|回复: 26

[Arduino] ESP8266基于Arduino接入贝壳物联,使用天猫精灵控制WS2812B灯带

[复制链接]
发表于 2019-12-30 22:31:01 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
* 上次搞清楚了ESP8266怎么使用Arduino控制WS2812B灯带,可以参考:https://www.mydigit.cn/forum.php?mod=viewthread&tid=112534
* 这次在此基础上添加天猫精灵智能音箱控制操作,这个原理也可以用到实际灯具中。
* 先看一看最后实现了哪些功能:
1. 无线配网
2. 天猫精灵语音控制:
  天猫精灵,开灯。。
  天猫精灵,亮度50。。
  天猫精灵,灯光绿色。。
  天猫精灵,关灯。。

* 最终效果如视频:查看视频效果


* 下面就是一步步来接入,首先再来看看连接图
111502z4v4l4vzmmmaie49.png

* 第一步就是配网,配网我用的是Arduino中的WifiManager库:
微信截图_20191230212036.png


* 它的原理是用ESP8266开启热点,电脑或手机连接热点后访问192.168.4.1,就可以访问一个网页
微信图片编辑_20191229201337.jpg

* 我们把要连接的路由器Wifi热点名和密码输入,ESP8266会把账号密码保存到Flash
微信截图_20191229201443.png



* 下次起机的时候,ESP8266发现有保存了可用的Wifi热点,就会通过热点接入互联网。
微信截图_20191229201516.png

* 完成上述的配网操作所需要写的代码仅有两行:
  1. void setup() {
  2.   // 设置Wifi
  3.   WiFiManager wifiManager;
  4.   wifiManager.autoConnect();
  5. }
复制代码




* ESP8266能连接互联网还不够,需要和贝壳互联云平台连接,才能推送命令。
访问贝壳互联网站注册账号,再注册设备即可,关键的是得到id和apikey,这是给设备做命令推送的凭据:
微信截图_20191230213259.png



* 下一步就是写代码让设备连接贝壳互联的服务器,可参考官方例程:https://github.com/bigiot/bigiotArduino
关键代码如下:
  1. void loop() {
  2.   // 检测网络是否通畅
  3.   while (WiFi.status() != WL_CONNECTED) {
  4.     delay(1000);
  5.     Serial.print(".");
  6.   }
  7.   // 检测是否连接到服务器
  8.   if (!client.connected()) {
  9.     if (!client.connect(host, httpPort)) {
  10.       Serial.println("connection failed");
  11.       delay(5000);
  12.       return;
  13.     }
  14.   }
  15.   // 检测是否需要发送心跳包
  16.   if (millis() - lastCheckInTime > postingInterval || lastCheckInTime == 0) {
  17.     Serial.println("Send HeartBeat!!");
  18.     sendHeartBeat();
  19.   }
  20.   // 检测是否收到服务器推送
  21.   if (client.available()) {
  22.     String inputString = client.readStringUntil('\n');
  23.     onMessageReceive(inputString);
  24.   }
  25.   // 判断是否需要将LED闪烁
  26.   if (ledOn) {
  27.     doLedStep();
  28.   }
  29. }
复制代码




* 可以看出,在loop里面,关键要做的有两件事,
  1. 每隔40秒左右向服务端发送心跳包,告诉服务器这个设备还在线
  2. 轮询服务端接口是否有下发命令,有的话需要立即响应,至于收到了一个消息,我们要做什么样的处理,这都是我们自由发挥了。


* 为了扩展性,发送和接收的消息都是要编码成json格式,所以为了方便,我们还是要使用个json解析库才行,官方例程里用的是aJson,但是我在IDE里搜索不到这个,还要单独安装。我便没有用aJson,找了一个比较流行的ArduinoJson,大同小异,也可以用。
微信截图_20191230214736.png



* 有了JSON解析库,我们就可以解析消息了,先用串口打印消息看看。现在还没有接天猫精灵,先用贝壳物联后台的面板试试Play和Stop按钮的消息是啥:
微信截图_20191230215408.png




* Play和Stop的消息打印出来,其实开灯和关灯用的就是这两个:
  1. {"M":"say","ID":"U11085","NAME":"hzy3774(web)","C":"play","T":"1577714088"}
  2. {"M":"say","ID":"U11085","NAME":"hzy3774(web)","C":"stop","T":"1577714088"}
复制代码



* 从消息内容可以看出,我们主要解析消息中的C这个字段,即可判断是什么动作,代码如下
  1. void onMessageReceive(String msg) {
  2.   msg.trim();
  3.   Serial.println(msg);
  4.   if (msg.startsWith("{") && msg.endsWith("}")) {
  5.     DynamicJsonDocument doc(1024);
  6.     deserializeJson(doc, msg);
  7.     JsonObject obj = doc.as<JsonObject>();
  8.     String M = obj["M"];
  9.     if (M == "say") {
  10.       String C = obj["C"];
  11.       if (C == "play") {
  12.         ledOn = 1;
  13.       } else if (C == "stop") {
  14.         ledOn = 0;
  15.         turnLedColor(0);
  16.       } else if (C.startsWith("{") && C.endsWith("}")) {
  17.         deserializeJson(doc, C);
  18.         obj = doc.as<JsonObject>();
  19.         onExtraCommand(obj);
  20.       }
  21.     }
  22.   }
  23. }
复制代码



* 只要串口能打印,就说明能收到消息了。下一步来接入天猫精灵。
* 操作很简单,主要有三步,在天猫精灵App中添加设备,搜索贝壳,授权绑定后再登陆贝壳账号,即可看到设备信息。
未命名_meitu_0.jpg



* 绑定完成后就可以对天猫精灵说“开灯”,在串口打印中看到命令是Play,这说明天猫精灵也对接成功了。
  1. {"M":"say","ID":"U11085","C":"play","SIGN":"Aligenie","T":"1577716165"}
复制代码



* 这个时候如果还想实现更复杂的灯光控制功能,比如对精灵说“亮度50”,“灯光变绿色”,命令的内容就稍微复杂了:
  1. {"M":"say","ID":"U11085","C":"{"n":"SetColor","a":"color","v":"Green"}","SIGN":"Aligenie","T":"1577715366"}
  2. {"M":"say","ID":"U11085","C":"{"n":"SetBrightness","a":"brightness","v":"10"}","SIGN":"Aligenie","T":"1577715412"}
复制代码
* 这时候C变得复杂,不过也没关系,对C再做一次JSON解析即可:
  1. void onExtraCommand(JsonObject obj) {
  2.   String aa = obj["a"];
  3.   if (aa == "brightness") {
  4.     int vv = obj["v"];
  5.     FastLED.setBrightness(vv * 255 / 100);
  6.   } else if (aa == "color") {
  7.     String color = obj["v"];
  8.     ledOn = 0;
  9.     if (color == "Red") {
  10.       turnLedColor(CRGB::Red);
  11.     } else if (color == "Green") {
  12.       turnLedColor(CRGB::Green);
  13.     } else if (color == "Blue") {
  14.       turnLedColor(CRGB::Blue);
  15.     } else if (color == "White") {
  16.       turnLedColor(CRGB::White);
  17.     }
  18.   }
  19. }
复制代码



* 一步步调试完成,就可以完美运行了,完整代码如下可做个参考,需要替换自己设备的ID和APIKEY即可。
* 目前实现了天猫精灵开关灯,调灯颜色,调灯亮度,其他功能还有待发现。
* 调试灯光的说明可以参考其他帖子如:https://www.mydigit.cn/forum.php?mod=viewthread&tid=112534
  1. #include <ESP8266WiFi.h>
  2. #include <WiFiManager.h>
  3. #include <ArduinoJson.h>

  4. //=============  此处必须修该============
  5. String DEVICEID = "00000"; // 你的设备编号   ==
  6. String  APIKEY = "0000000"; // 设备密码==

  7. unsigned long lastCheckInTime = 0; //记录上次报到时间
  8. const unsigned long postingInterval = 40000; // 每隔40秒向服务器报到一次

  9. const char* host = "www.bigiot.net";
  10. const int httpPort = 8181;

  11. WiFiClient client;

  12. //============  LED 相关 ======================
  13. int ledOn = 0;
  14. int hue = 0;
  15. #include <FastLED.h>

  16. #define LED_PIN     8     //我的LED信号线IN接在8引脚
  17. #define NUM_LEDS    12    //我的灯带一共级联了12颗LED
  18. CRGB leds[NUM_LEDS];


  19. void setup() {
  20.   Serial.begin(115200);
  21.   // 设置LED
  22.   FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
  23.   FastLED.setBrightness(20);  //可以设置全局亮度,调低亮度不刺眼
  24.   turnLedColor(0);

  25.   // 设置Wifi
  26.   WiFiManager wifiManager;
  27.   wifiManager.autoConnect();
  28. }

  29. void loop() {
  30.   // 检测网络是否通畅
  31.   while (WiFi.status() != WL_CONNECTED) {
  32.     delay(1000);
  33.     Serial.print(".");
  34.   }
  35.   // 检测是否连接到服务器
  36.   if (!client.connected()) {
  37.     if (!client.connect(host, httpPort)) {
  38.       Serial.println("connection failed");
  39.       delay(5000);
  40.       return;
  41.     }
  42.   }
  43.   // 检测是否需要发送心跳包
  44.   if (millis() - lastCheckInTime > postingInterval || lastCheckInTime == 0) {
  45.     Serial.println("Send HeartBeat!!");
  46.     sendHeartBeat();
  47.   }
  48.   // 检测是否收到服务器推送
  49.   if (client.available()) {
  50.     String inputString = client.readStringUntil('\n');
  51.     onMessageReceive(inputString);
  52.   }
  53.   // 判断是否需要将LED闪烁
  54.   if (ledOn) {
  55.     doLedStep();
  56.   }
  57. }

  58. void turnLedColor(int c) {
  59.   for (int i = 0; i < NUM_LEDS; i++) {
  60.     leds[i] = c;
  61.   }
  62.   FastLED.show();
  63. }

  64. void doLedStep() {
  65.   for (int i = 0; i < NUM_LEDS; i++) {
  66.     leds[i] = CHSV( (hue + (255 / NUM_LEDS) * i), 255, 255); //用HSV色彩空间,不断改变H即可
  67.   }
  68.   FastLED.show();
  69.   delay(5);
  70.   hue = (hue + 3) % 255;
  71. }

  72. void onExtraCommand(JsonObject obj) {
  73.   String aa = obj["a"];
  74.   if (aa == "brightness") {
  75.     int vv = obj["v"];
  76.     FastLED.setBrightness(vv * 255 / 100);
  77.   } else if (aa == "color") {
  78.     String color = obj["v"];
  79.     ledOn = 0;
  80.     if (color == "Red") {
  81.       turnLedColor(CRGB::Red);
  82.     } else if (color == "Green") {
  83.       turnLedColor(CRGB::Green);
  84.     } else if (color == "Blue") {
  85.       turnLedColor(CRGB::Blue);
  86.     } else if (color == "White") {
  87.       turnLedColor(CRGB::White);
  88.     }
  89.   }
  90. }

  91. void onMessageReceive(String msg) {
  92.   msg.trim();
  93.   Serial.println(msg);
  94.   if (msg.startsWith("{") && msg.endsWith("}")) {
  95.     DynamicJsonDocument doc(1024);
  96.     deserializeJson(doc, msg);
  97.     JsonObject obj = doc.as<JsonObject>();
  98.     String M = obj["M"];
  99.     if (M == "say") {
  100.       String C = obj["C"];
  101.       if (C == "play") {
  102.         ledOn = 1;
  103.       } else if (C == "stop") {
  104.         ledOn = 0;
  105.         turnLedColor(0);
  106.       } else if (C.startsWith("{") && C.endsWith("}")) {
  107.         deserializeJson(doc, C);
  108.         obj = doc.as<JsonObject>();
  109.         onExtraCommand(obj);
  110.       }
  111.     }
  112.   }
  113. }

  114. void sendHeartBeat() {
  115.   String msg = "{"M":"checkin","ID":"" + DEVICEID + "","K":"" + APIKEY + ""}\n";
  116.   client.print(msg);
  117.   lastCheckInTime = millis();
  118. }
复制代码


结束


打赏

参与人数 3家元 +66 收起 理由
温力口 + 10 谢谢分享。。。。。资料很齐全。。。。。。.
kindzhon + 6 熱心助人
家睦 + 50

查看全部打赏

发表于 2019-12-31 09:16:02 | 显示全部楼层
神速,控制花样什么的语音命令就比较复杂了,是不是可以预设,比如:运行预设1,运行预设2。。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-12-31 11:45:16 | 显示全部楼层
zengcym 发表于 2019-12-31 09:16
神速,控制花样什么的语音命令就比较复杂了,是不是可以预设,比如:运行预设1,运行预设2。。。。 ...

不知道天猫精灵可以支持些什么命令,现在我就试了
可以听懂:开关灯,换颜色,调亮度,模式设为闪烁。
其他的不知道还可以用啥命令
回复 支持 反对

使用道具 举报

发表于 2020-1-5 11:46:33 | 显示全部楼层
可惜小度音箱只能开关。
回复 支持 反对

使用道具 举报

发表于 2020-2-3 00:47:00 | 显示全部楼层
都是大神,我先记号一下备用
回复 支持 反对

使用道具 举报

发表于 2020-2-3 00:49:38 | 显示全部楼层
都是大神,我先记号一下备用
回复 支持 反对

使用道具 举报

发表于 2020-2-26 09:29:50 | 显示全部楼层
  String msg = "{"M":"checkin","ID":"" + DEVICEID + "","K":"" + APIKEY + ""}\n";    提示expected ',' or ';' before 'M'是什么原因呢??
回复 支持 反对

使用道具 举报

发表于 2020-2-26 19:59:57 来自手机浏览器 | 显示全部楼层
这种灯珠比较好玩。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-2-27 17:00:10 | 显示全部楼层
582475119 发表于 2020-2-26 09:29
String msg = "{"M":"checkin","ID":"" + DEVICEID + "","K":"" + APIKEY + ""}\n";    提示expected ',' ...

不好意思,这个代码复制到论坛把转义字符去掉了,需要手动补充一下,实际上是:
String msg = "{\"M\":\"checkin\",\"ID\":\"" + DEVICEID + "\",\"K\":\"" + APIKEY + "\"}\n";
回复 支持 1 反对 0

使用道具 举报

发表于 2020-2-27 21:44:50 | 显示全部楼层
谢谢分享。。。。。资料很齐全。。。。。。
回复 支持 反对

使用道具 举报

发表于 2020-3-11 20:06:46 | 显示全部楼层
用的01模块,刚开始怎么也不成功,后来发现,必须烧录前先拔下来,估计接上改变烧录所需电平了。

回复 支持 反对

使用道具 举报

发表于 2020-5-22 17:02:42 | 显示全部楼层
hzy3774 发表于 2019-12-31 11:45
不知道天猫精灵可以支持些什么命令,现在我就试了
可以听懂:开关灯,换颜色,调亮度,模式设为闪烁。
其 ...

为啥我这个天猫精灵只能开关灯,还有,串口打印的数据在哪里?是在贝壳物联吗
回复 支持 反对

使用道具 举报

发表于 2020-6-23 17:23:30 | 显示全部楼层
这是什么情况啊?
image.png
回复 支持 2 反对 0

使用道具 举报

发表于 2020-6-24 10:09:48 | 显示全部楼层
CHSV是什么 ?我在这里报错了
回复 支持 反对

使用道具 举报

发表于 2020-6-24 11:56:19 | 显示全部楼层
大佬能不能传个代码上来 ?搞了一天 一直报错。
回复 支持 反对

使用道具 举报

发表于 2020-7-21 16:12:21 | 显示全部楼层
melody361 发表于 2020-6-23 17:23
这是什么情况啊?

不用点 复制代码,直接用鼠标手动全选复制即可
1595319008(1).jpg
回复 支持 反对

使用道具 举报

发表于 2020-7-23 09:33:35 | 显示全部楼层
复制的时候里面带有隐藏的转义字符 或者字符编码问题,以前复制网上的代码经常出这问题,复制到记事本有时候也有问题(空格或者特殊字符的问题)。如果不手懒自己敲一遍呗
回复 支持 反对

使用道具 举报

发表于 2020-9-5 14:52:28 | 显示全部楼层
本帖最后由 hbliwww 于 2020-9-5 14:58 编辑

试着搞一下,看看能不能成功。
image.png
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-9-13 15:38:32 | 显示全部楼层
hbliwww 发表于 2020-9-5 14:52
试着搞一下,看看能不能成功。

需要安装一下FastLED库就可以了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-3-29 07:39 , Processed in 0.218400 second(s), 18 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

快速回复 返回顶部 返回列表