认识众多玩家高手/拆客/DIYer,查阅更多资源,一起学习技术知识
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
本帖最后由 hzy3774 于 2020-1-8 00:45 编辑
* 实验的对象是一个基于ESP8266的WiFi排插,目标是通过Arduino编程实现天猫精灵语音控制排插每个插孔的通断电功能。* 编写程序主要需关心的硬件配置是:ESP-12模块x1,轻触按键x1,220V插口x4,USB接口x2,Wifi信号LEDx1,电源LEDx1
* 实物如图
DSC04258.JPG (88.44 KB, 下载次数: 0)
2020-1-7 22:54 上传
* 先来看看最终效果吧,一看就明白怎么回事了。点击观看视频
* 模块与IO连接如图:
微信图片编辑_20200107233554.jpg (35.75 KB, 下载次数: 0)
2020-1-7 23:37 上传
* 下面开始写程序,首先是使用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个开关,就会麻烦一点,我的做法是使用子设备:
* 先添加一个设备,设备的类型必须要选择万能遥控器,万能遥控器的子设备才会生效:
微信截图_20200108000733.png (50.39 KB, 下载次数: 0)
2020-1-8 00:09 上传
* 之后在子设备栏里添加4个子设备,当然,子设备的数量取决于主设备有多少路控制IO,这些子设备的ID会在之后编程中用到:
微信截图_20200108001109.png (52.23 KB, 下载次数: 0)
2020-1-8 00:11 上传
* 然后我们在手机天猫精灵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();
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
#include
#include
//============= 此处必须修该============
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();
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开发板结束