|
爱科技、爱创意、爱折腾、爱极致,我们都是技术控
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 hzy3774 于 2020-1-8 00:45 编辑
* 实验的对象是一个基于ESP8266的WiFi排插,目标是通过Arduino编程实现天猫精灵语音控制排插每个插孔的通断电功能。
* 编写程序主要需关心的硬件配置是:ESP-12模块x1,轻触按键x1,220V插口x4,USB接口x2,Wifi信号LEDx1,电源LEDx1
* 侧面加装了USB接口方便下载调试程序,过程可以参考另一个帖子:基于ESP8266的WiFi排插拆机加装USB调试板,改造成Arduino开发板
* 实物如图
* 先来看看最终效果吧,一看就明白怎么回事了。点击观看视频
* 模块与IO连接如图:
* 下面开始写程序,首先是使用WifiManager库配网:
- // 设置Wifi
- WiFiManager wifiManager;
- wifiManager.autoConnect();
复制代码
* 之后是来初始化中断,因为插板上有一个按钮,使用中断来处理按钮事件,处理的逻辑是:如果插座全关的情况下按下按钮,则变为全开,否则就变为全关。
- // 中断响应
- ICACHE_RAM_ATTR void onKeyClick() {
- // 全关的状态全部打开,否则都是全关闭
- if ((portStatus & 0B1111000) == 0B1111000) {
- portStatus &= 0B0000111;
- } else {
- portStatus |= 0B1111000;
- }
- refreshOutput();
- }
- void initPanelKey() {
- attachInterrupt(digitalPinToInterrupt(5), onKeyClick, FALLING);
- }
复制代码
* 我们使用了一个变量portStatus来表示用到的所有插孔和LED的开关状态,这样我们只要修改portStatus,再调用refreshOutput()就可以改变所有输出IO状态:
- //7个端口分别对应 K1, K2, K3, K4,USB,LED_WIFI, LED_ROUND
- char swPorts[portNum] = {14, 12, 13, 4, 16, 0, 3};
- //除了USB充电口,其他都是低电平有效
- int portStatus = 0B0000110; //7个IO开关
- //======================================
- // 初始化插板
- void initOutputMode() {
- for (int i = 0; i < portNum; i++) {
- pinMode(swPorts[i], OUTPUT);
- }
- }
- // 根据开关状态刷新IO电平
- void refreshOutput() {
- int c = 1;
- for (int i = portNum - 1; i >= 0; i--) {
- digitalWrite(swPorts[i], (c & portStatus) ? HIGH : LOW);
- c <<= 1;
- }
- }
复制代码
* 有了中断,也可以修改IO输出状态,下面就是对接贝壳互联平台。
* 对接详情可以参考我的另一片帖子:ESP8266基于Arduino接入贝壳物联,使用天猫精灵控制WS2812B灯带
* 但是与其他单设备不同,我们一个设备上有4个开关,就会麻烦一点,我的做法是使用子设备:
* 先添加一个设备,设备的类型必须要选择万能遥控器,万能遥控器的子设备才会生效:
* 之后在子设备栏里添加4个子设备,当然,子设备的数量取决于主设备有多少路控制IO,这些子设备的ID会在之后编程中用到:
* 然后我们在手机天猫精灵APP里绑定账号之后,设备里一下子就会多出来4个设备:
* 在天猫精灵里可以给这些子设备设置不同的类型,冰箱,电视,空调啊,可以随意设置,不过设置了什么类型,到时候和天猫精灵语音控制的时候就要说对应的设备类型,比如:“天猫精灵,打开空调”
* 但是如果我想4路开关一起控制,那我就说“天猫精灵,打开万能遥控器”即可。
设置完成后,我们来继续写云平台相关代码:
* 一样的套路,在loop循环中,主要做两件事,定期向服务端发送心跳包,每个循环中收一下消息,再处理一下消息。
- void loop() {
- // 检测网络是否通畅
- while (WiFi.status() != WL_CONNECTED) {
- delay(1000);
- Serial.print(".");
- }
- // 检测是否连接到服务器
- if (!client.connected()) {
- if (!client.connect(host, httpPort)) {
- Serial.println("connection failed");
- delay(5000);
- return;
- }
- }
- // 检测是否需要发送心跳包
- if (millis() - lastCheckInTime > postingInterval || lastCheckInTime == 0) {
- Serial.println("Send HeartBeat!!");
- sendHeartBeat();
- }
- // 检测是否收到服务器推送
- if (client.available()) {
- String inputString = client.readStringUntil('\n');
- onMessageReceive(inputString);
- }
- }
复制代码
* 发送心跳包的代码:
- void sendHeartBeat() {
- String msg = "{"M":"checkin","ID":"" + DEVICEID + "","K":"" + APIKEY + ""}\n";
- client.print(msg);
- lastCheckInTime = millis();
- }
复制代码
* 处理推送消息的代码:
- void onMessageReceive(String msg) {
- msg.trim();
- Serial.println(msg);
- if (msg.startsWith("{") && msg.endsWith("}")) {
- DynamicJsonDocument doc(1024);
- deserializeJson(doc, msg);
- JsonObject obj = doc.as<JsonObject>();
- String M = obj["M"];
- if (M == "say") {
- String S = obj["S"];
- String C = obj["C"];
- int device = 0B1111000;
- if (S == "D1160") {
- device = 0B1000000;
- } else if (S == "D1161") {
- device = 0B0100000;
- } else if (S == "D1162") {
- device = 0B0010000;
- } else if (S == "D1163") {
- device = 0B0001000;
- }
- if (C == "play") {
- portStatus &= ~device;
- } else if (C == "stop") {
- portStatus |= device;
- }
- refreshOutput();
- } else if (M == "checkinok") {
- portStatus &= 0B1111101;
- refreshOutput();
- }
- }
- }
复制代码
解释一下消息处理部分的代码:我目前只处理了say和checkinok的消息。
* checkinok消息:由于刚起机连上网的时候,设备并不能马上连接上推送服务,一般要等待几十秒到数分钟才能链接完成,连接成功后云平台会发送checkinok消息,所以收到checkinok消息时,我们把WIFI_LED点亮,表示设备联网成功了。
* say消息:表示设备需要响应命令,两个参数比较重要:C和S,
S表示子设备的id,通过S便可以知道需要操作哪个子设备(为空的话表示操作所有设备)
C表示动作,play表示打开设备,stop表示关闭设备。
当然这些都是我根据串口打印消息内容猜测的,具体情况还要参考天猫精灵和贝壳互联的说明才比较准确。
完整的代码如下,需对应修改DEVICE ID和API KEY:
- #include <ESP8266WiFi.h>
- #include <WiFiManager.h>
- #include <ArduinoJson.h>
- //============= 此处必须修该============
- String DEVICEID = "00000"; // 你的设备编号 ==
- String APIKEY = "000000000"; // 设备密码==
- unsigned long lastCheckInTime = 0; //记录上次报到时间
- const unsigned long postingInterval = 40000; // 每隔40秒向服务器报到一次
- const char* host = "www.bigiot.net";
- const int httpPort = 8181;
- WiFiClient client;
- //======插座控制端口=======
- const int portNum = 7;
- //7个端口分别对应 K1, K2, K3, K4,USB,LED_WIFI, LED_ROUND
- char swPorts[portNum] = {14, 12, 13, 4, 16, 0, 3};
- //除了USB充电口,其他都是低电平有效
- int portStatus = 0B0000110; //7个IO开关
- //======================================
- // 初始化插板
- void initOutputMode() {
- for (int i = 0; i < portNum; i++) {
- pinMode(swPorts[i], OUTPUT);
- }
- }
- // 根据开关状态刷新IO电平
- void refreshOutput() {
- int c = 1;
- for (int i = portNum - 1; i >= 0; i--) {
- digitalWrite(swPorts[i], (c & portStatus) ? HIGH : LOW);
- c <<= 1;
- }
- }
- // 中断响应
- ICACHE_RAM_ATTR void onKeyClick() {
- // 全关的状态全部打开,否则都是全关闭
- if ((portStatus & 0B1111000) == 0B1111000) {
- portStatus &= 0B0000111;
- } else {
- portStatus |= 0B1111000;
- }
- refreshOutput();
- }
- void initPanelKey() {
- attachInterrupt(digitalPinToInterrupt(5), onKeyClick, FALLING);
- }
- void setup() {
- // 设置串口
- Serial.begin(115200);
- //初始化输出端口
- initOutputMode();
- refreshOutput();
- //初始化按键中断
- initPanelKey();
- // 设置Wifi
- WiFiManager wifiManager;
- wifiManager.autoConnect();
- }
- void loop() {
- // 检测网络是否通畅
- while (WiFi.status() != WL_CONNECTED) {
- delay(1000);
- Serial.print(".");
- }
- // 检测是否连接到服务器
- if (!client.connected()) {
- if (!client.connect(host, httpPort)) {
- Serial.println("connection failed");
- delay(5000);
- return;
- }
- }
- // 检测是否需要发送心跳包
- if (millis() - lastCheckInTime > postingInterval || lastCheckInTime == 0) {
- Serial.println("Send HeartBeat!!");
- sendHeartBeat();
- }
- // 检测是否收到服务器推送
- if (client.available()) {
- String inputString = client.readStringUntil('\n');
- onMessageReceive(inputString);
- }
- }
- void onMessageReceive(String msg) {
- msg.trim();
- Serial.println(msg);
- if (msg.startsWith("{") && msg.endsWith("}")) {
- DynamicJsonDocument doc(1024);
- deserializeJson(doc, msg);
- JsonObject obj = doc.as<JsonObject>();
- String M = obj["M"];
- if (M == "say") {
- String S = obj["S"];
- String C = obj["C"];
- int device = 0B1111000;
- if (S == "D1160") {
- device = 0B1000000;
- } else if (S == "D1161") {
- device = 0B0100000;
- } else if (S == "D1162") {
- device = 0B0010000;
- } else if (S == "D1163") {
- device = 0B0001000;
- }
- if (C == "play") {
- portStatus &= ~device;
- } else if (C == "stop") {
- portStatus |= device;
- }
- refreshOutput();
- } else if (M == "checkinok") {
- portStatus &= 0B1111101;
- refreshOutput();
- }
- }
- }
- void sendHeartBeat() {
- String msg = "{"M":"checkin","ID":"" + DEVICEID + "","K":"" + APIKEY + ""}\n";
- client.print(msg);
- lastCheckInTime = millis();
- }
复制代码
基于ESP8266的WiFi排插拆机加装USB调试板,改造成Arduino开发板
结束
|
打赏
-
查看全部打赏
|