微信物联网生态主要分在微信硬件开发平台与腾讯物联开发平台,前者已经停止维护,但依然有着很大的学习价值,而后者作为主推的平台,集成很多功能,包括从微信小程序实现配网到控制;
为了兼顾更多的朋友和自己的学习笔记,我将会一直更新此专题笔记,欢迎关注本人CSDN半颗心脏,带你走进前沿领域,学习前沿技术!
自搭微信服务器&&微信硬件开发平台
【微信小程序控制硬件第1篇 】 全网首发,借助 emq 消息服务器带你如何搭建微信小程序的mqtt服务器,轻松控制智能硬件!
【微信小程序控制硬件第2篇 】 开始微信小程序之旅,导入小程序Mqtt客户端源码,实现简单的验证和通讯于服务器!
【微信小程序控制硬件第3篇 】 从软件到硬件搭建一个微信小程序控制esp8266的项目,自定义通讯协议,为面试职位和比赛项目加分!
【微信小程序控制硬件第4篇 】 深度剖析微信公众号配网 Airkiss 原理与过程,esp8266如何自定义回调参数给微信,实现绑定设备第一步!
【微信小程序控制硬件第5篇 】理清接下来必须走的架构思想,学习下 JavaScript 的观察者模式,在微信小程序多页面同时接收到设备推送事件!
【微信小程序控制硬件第6篇 】服务器如何集成七牛云存储SDK,把用户自定义设备图片存储在第三方服务器!
【微信小程序控制硬件第7篇 】动起来做一个微信小程序Mqtt协议控制智能硬件的框架,为自己心里全栈工程师梦想浇水!!
【微信小程序控制硬件第8篇 】微信小程序以 websocket 连接阿里云IOT物联网平台mqtt服务器,封装起来使用就是这么简单!
【微信小程序控制硬件第9篇 】巧借阿里云物联网平台的免费连接,从微信小程序颜色采集控制 esp8266 输出七彩灯效果,中秋节来个直播如何?!
【微信公众号控制硬件 第10篇 】如何在微信公众号网页实现连接mqtt服务器教程!!
【微信小程序控制硬件 第11篇 】全网首发,微信小程序ble蓝牙控制esp32,实现无需网络也可以控制亮度开关。
【微信小程序控制硬件 第12篇 】微信小程序蓝牙控制硬件应如何开发?为您全面解析微信小程序蓝牙API的使用。
【微信小程序控制硬件 第13篇 】安信可B站直播学习总结,微信小程序MQTT远程控制ESP8266 NodeMCU,谈谈微信生态那些事。
腾讯物联开发平台
【腾讯连连 - 腾讯物联开发平台 第1篇 】腾讯官方静鸡鸡发布的“腾讯连连”终于来了,按照官方教程教你在微信小程序实现配网、控制 ESP8266啦!
【腾讯连连 - 腾讯物联开发平台 第2篇 】深度解析微信小程序smartconfig配网原理,安信可ESP-12S直连腾讯物联开发平台!!
文章目录
一、前言;
- 网上留言抨击从来不是一天两天的事情,为此霍建华退出微博是情有可原的,因为水军太多了!男人大丈夫,不拘小节,做自己的事情,让别人说去吧。好了,从去年自学前端知识
H5+css+js
,从上个星期给大家带来的服务器搭建,今天有幸给大家带来我的小项目,对于学习微信小程序控制智能硬件(包括esp8266
)的原理与过程,我觉得对你有一定的启发! - 再次声明:到目前(2018/11/28)为止,微信小程序不支持给智能设备配网! 微信仅仅支持微信公众号给智能设备配网!
二、准备材料;
- ①:智能硬件
esp8266
最小系统一个,LED一个,2
个轻触开关,杜邦线若干; - ②:在微信公众平台:https://mp.weixin.qq.com 注册个人微信小程序 , 下载开发者工具点我下载。
- ③:服务器要求支持
wss
即websocket+ssl
,而且该端口必须是443
,为了大家方便,我这里教大家怎么接入百度天工服务器,因为百度天工已经支持微信小程序了!当然了,你可以看我第一篇怎么搭建属于自己域名的微信小程序MQTT
服务器,用自己的服务器作为桥梁也行!看业务需要!
三、通讯原理以及如何拟定通讯协议;

- 注意角色:(设备 --> esp8266,设备商云 --> 服务器,微信客户端 --> 微信小程序):
- 先上图,也请认真观看上图,这是我本篇实现的控制过程,也是我想到的控制过程,哈哈!
- 概述:
- ①:服务器我们不用微信硬件云,而是我们自己的服务器,上位机就是微信客户端,我们是在微信的环境下开发的,也就避免不了和微信打交道,避免不了要遵循微信开发的规范!所以要有一定的前端开发知识哦!也就是
H5+css+javaSrcipt
,微信的小程序开发和这个非常相似!如果想入门微信小程序开发,自己可以去琢磨! - ②:设备商云也就是我们的服务器,仅仅做一个中转信号处理,不做任何的消息存储和分析哈!
- ③:通讯过程是 esp8266上报消息到服务器,服务器转发消息到微信小程序!反过来,微信小程序控制下发,先发送消息到服务器,然后到esp8266!
- ④:既然服务器仅仅是一个中转信号处理,那么我们的微信小程序和esp8266的通讯协议,自己拟定就好,下面是我拟定的,也是本文项目的协议!
- ①:服务器我们不用微信硬件云,而是我们自己的服务器,上位机就是微信客户端,我们是在微信的环境下开发的,也就避免不了和微信打交道,避免不了要遵循微信开发的规范!所以要有一定的前端开发知识哦!也就是
- 微信小程序下发控制的通讯协议:
主题 | 发送端 | 接收端 | 消息(JSON格式) | 消息含义 |
---|---|---|---|---|
/light/deviceOut | 微信小程序 | esp8266 | “{“change”:“power”,“value”:true}” | 开灯 |
“{“change”:“power”,“value”:“false”}” | 关灯 | |||
“{“change”:“pwm”,“value”:50}” | 调节亮度:value为亮度值 ,范围 [0,100] | |||
“{“change”:“query”,“value”:0}” | 微信小程序主动请求最新状态 |
- esp8266上报同步的通讯协议:
主题 | 发送端 | 接收端 | 消息(JSON格式) | 消息含义 |
---|---|---|---|---|
/light/deviceIn | esp8266 | 微信小程序 | “{“power”:“false”,“brightNess”:50}” | power为灯的状态,brightNess是亮度值,范围 [0,100] |
四、开始服务器准备;
- 对于服务器的搭建,一直都是我们嵌入式开发攻城狮的弊病,因为我们确实不懂怎么弄服务器开发!呵呵!好,那么我带大家用百度天工服务器去搭建我们的微信小程序
MQTT
硬件服务器!还是啰嗦一句,如果您有自己的服务器,那么这个章节可以不看!
第一步:在百度云:https://console.bce.baidu.com 注册账号,找到 物接入 loT Hub。
第二步:这个 物接入 loT Hub接入也不是完全免费的,是按照流量收费的,我选择为1元一个月的流量然后付款一年才十元,足够自己一个人用了!之后选择创建项目,按照如下步骤:
第三步:在认真观看了上面协议的通讯协议之后,我们按照上面的协议来创建策略。
第四步:之后我们要去创建身份,拿到
MQTT
连接的密码和账号!吐槽下,真麻烦,还要说什么是身份列表,呵呵。
第五步:创建策略后,我们还需要创建用户!过程中的身份、策略选择都是上几个步骤创建的即可!然后,我们点击设备测试下;
第六步:一样的步骤,我们一共要创建2个用户,一个是设备
esp8266
,一个是微信小程序连接客户端;
五 、微信小程序代码部分详解;
5.1 配置获取;
- 作为客户端,连接的域名和端口号以及
MQTT
的账号密码肯定需要的!那么上面已经拿到了账号和密码,那么域名和端口号在哪呢?看下图:
- 微信小程序开发的第一步,就是必须要在微信小程序后台配置下域名和地址,这个有必要去配置下,下面的服务器域名就填上面这个!
- 之后我们用微信小程序开发工具打开我提供的微信小程序工程,配置详情:
5.2 代码讲解;
- 连接核心代码,主要看注释:
- 第一步:先配置好服务器连接的参数,之后开始连接;
- 第二步:设置服务器下发回调函数,并在里面解析数据做我们的
UI
同步工作。 - 第三步:特别注意,我们在异常回调函数检测到异常断开服务器之后,要重连服务器哦!
connect: function() {
var that = this;
//获取全局变量,server_domain是MQTT服务器的域名
var client = new Client(app.globalData.server_domain, "DeviceId-7zne322b0g");
client.connect({
useSSL: true, //使用SSL
cleanSession: true, //清理会话为true
keepAliveInterval: 60, //心跳
userName: '7qfp623/wechatapp', //用户名
password: '5bXUJ3FfTJdK95sdh9', //用户密码
onSuccess: function() {
wx.showToast({
title: '连接成功'
})
that.data.client = client
// 服务器下发消息回调匿名回调处理
client.onMessageArrived = function(msg) {
if (typeof that.data.onMessageArrived === 'function') {
return that.data.onMessageArrived(msg)
}
console.log("收到消息:" + msg.payloadString);
var jsonObj = JSON.parse(msg.payloadString);
if (typeof jsonObj.power == "boolean")
console.log("解析 power :" + jsonObj.power);
if (typeof jsonObj.brightNess == "number")
console.log("解析 brightNess :" + jsonObj.brightNess);
//根据esp8266发过来的 power字段内容做不同的图片显示
var temp;
if (jsonObj.power == true) {
temp = '../pic/light_on.jpg'; //开灯图片加载显示
} else
temp = '../pic/light_off.jpg'; //关灯图片加载显示
//开始同步界面显示处理
that.setData({
valueSlier: jsonObj.brightNess,
lightValue: jsonObj.brightNess,
isOpen: jsonObj.power,
valuePic:temp,
})
}
//开始订阅主题
that.subscribe(app.globalData.subTopic, {
qos: 1
})
//连接异常断开,我们要做重连服务器的逻辑
client.onConnectionLost = function(responseObject) {
if (typeof that.data.onConnectionLost === 'function') {
return that.data.onConnectionLost(responseObject)
}
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:" + responseObject.errorMessage);
//检测到与服务器断开连接,设置定时函数一秒后重新连接服务器
setTimeout(function() {
_self.connect();
}, 1000)
}
}
//每次连接服务器都要主动查询设备的最新状态,保证界面是最新状态!
var obj = new Object();
obj.change = "query";
obj.value = 0;
that.publish(app.globalData.pubTopic, JSON.stringify(obj), 1, false)
}
});
}
- 我们的控制界面的代码非常简答,也就是绑定几个变量罢了!
<view class="container">
<view>
<image src="{{valuePic}}" class='imgLight'></image>
</view>
<view class='item-power'>
<text class='ele_text'>电源:</text>
<switch bindchange="onSwitch" checked="{{isOpen}}" class='ele_switch' />
</view>
<view class='line'></view>
<view class='item_adjust_light'>
<text class="section_title">当前亮度:{{lightValue}}</text>
<slider value="{{valueSlier}}"class='slider' block-size="20" activeColor="#00BFFF" bindchange="eventSlider"/>
</view>
</view>
- 看起来还是蛮整洁的!hh --em!
- 下面是按钮和拖动条的点击回调函数处理发送消息到设备代码,至于
CSS
样式代码,我就不贴了!
//拖动条点击下发
eventSlider: function(e) {
console.log("发生 change 事件,携带值为:" + e.detail.value);
this.setData({
lightValue: e.detail.value
})
//开始构造json数据
var obj = new Object();
obj.change = "pwm";
obj.value = e.detail.value;
//开始发布消息
this.publish(app.globalData.pubTopic, JSON.stringify(obj), 1, false)
},
//按键触发
onSwitch: function(e) {
console.log("onSwitch success :" + e.detail.value);
//开始构造json数据
var jsonObj = new Object();
jsonObj.change = "power";
jsonObj.value = "" + e.detail.value + "";
//开始发布消息
this.publish(app.globalData.pubTopic, JSON.stringify(jsonObj), 1, false)
},
六 、esp8266
工程代码部分详解;
- 首先说明的是,这份代码是基于
Rtos 2.2
的 ,不是3.0
版本的哈!而且MQTT
连接库是我提供的,在我的GitHub
有,稳定性不得说很好哈!- ①:按键长按触发一键配网模式
smartConfig
,短按就是调节亮度的明暗,很好! - ②:短按调节明暗,也要上报到服务器以此同步上位机的控制面板!
- ③:因为我们的
pwm
调节方法输入的参数duty
是0到1023,但是我们的微信小程序发来的是0到100,所以要转换一下,这样就可以了:pwm_set_duty(1023 * apkPwm / 100, 0);
,其中apkPwm
是微信小程序发来的数值!
- ①:按键长按触发一键配网模式
- 按键回调代码:
//按键一短按的回调逻辑处理
static void key_13_short_press(void) {
INFO("short press..");
//每次pwm百分比输出加10,如果大于100强制为最大值100!
apkPwm += 10;
if (apkPwm > 100) {
apkPwm = 100;
}
pwm_set_duty(1023 * apkPwm / 100, 0); //因为微信发来的是 0到100,我们取百分比之后再相乘 1023
pwm_start();
//上报当前状态服务器
post_data_to_clouds();
}
//按键一长按3秒的回调逻辑处理
static void key_13_long_press(void) {
INFO("long press.. into smartConfig..");
//标志位设置为5,下次开机读取标志位,如果为5就进去配网模式
u8 saveNumber[4];
saveNumber[0] = 5;
spi_flash_erase_sector(520);
spi_flash_write(520 * 4096, (uint32 *) &saveNumber, 4);
//重启
system_restart();
}
//按键二短按的回调逻辑处理
static void key_sw2_short_press(void) {
INFO("short press..");
//每次减去百分比10的亮度,当小于0强制为0;
apkPwm -= 10;
if (apkPwm < 0) {
apkPwm = 0;
}
pwm_set_duty(1023 * apkPwm / 100, 0); //因为微信发来的是 0到100,我们取百分比之后再相乘 1023
pwm_start();
//上报当前状态服务器
post_data_to_clouds();
}
//按键二长按3秒的回调逻辑处理
static void key_sw2_long_press(void) {
INFO("long press.. into smartConfig..");
//标志位设置为5,下次开机读取标志位,如果为5就进去配网模式
u8 saveNumber[4];
saveNumber[0] = 5;
spi_flash_erase_sector(520);
spi_flash_write(520 * 4096, (uint32 *) &saveNumber, 4);
//重启
system_restart();
}
- 服务器配置:从下面可以看到,我们硬件是走
TCP
的,所以端口号是1883
,以此同时,订阅的主题发布的主题和微信小程序刚刚是相反的!
//MQTT服务器设置
//MQTT ip地址或域名
#define MQTT_BROKER_HOST "7qfp6898.mqtt.iot.gz.baidubce.com"
//端口号
#define MQTT_BROKER_PORT 1883
//userName
#define MQTT_USER_NAME "7qfp6898/esp8266"
//userPassword
#define MQTT_USER_PASSWORD "5bXUJ3FfTJdKs8h9"
- 下面是收到服务器下发的消息的逻辑处理:
//收到消息
INFO("topic:\"%s\"", rMsg.topic);
INFO("payload(%3d)---> %s", rMsg.payloadlen, rMsg.payload);
/**
* 解析 "{"change":"power","value":true}"
*/
cJSON *pRoot = cJSON_Parse(rMsg.payload);
if (NULL == pRoot) {
INFO("arrive Error get Json : [%s] ",
cJSON_GetErrorPtr());
cJSON_Delete(pRoot);
break;
}
INFO("-----------arrive ok get Json-------------");
cJSON *pJSON_change = cJSON_GetObjectItem(pRoot, "change");
if (!pJSON_change) {
cJSON_Delete(pRoot);
INFO("- error parse Json : pJSON_change --");
break;;
}
cJSON *pJSON_value = cJSON_GetObjectItem(pRoot, "value");
//判断是否开关按钮
if (strcmp(pJSON_change->valuestring, "power") == 0) {
INFO("--arrive ok get Json --> power-------------");
if (strcmp(pJSON_value->valuestring, "true") == 0) {
pwm_set_duty(512, 0); //开灯
pwm_start();
apkPwm = 50;
} else {
apkPwm = 0;
pwm_set_duty(0, 0); //关灯
pwm_start();
}
post_data_to_clouds();//同步上报服务器
//判断是否调节亮度
} else if (strcmp(pJSON_change->valuestring, "pwm") == 0) {
INFO("---arrive ok get Json --> pwm-------------");
u8 value = pJSON_value->valueint;
apkPwm = value;
pwm_set_duty(1023 * value / 100, 0); //因为微信发来的是 0到100,我们取百分比之后再相乘 1023
pwm_start();
post_data_to_clouds();//同步上报服务器
} else if (strcmp(pJSON_change->valuestring, "query")
== 0) {
post_data_to_clouds(); //同步上报服务器
}
cJSON_Delete(pRoot);
- 下面是程序入口部分:
//按键初始化
TaskKeyInit();
//station模式开启
wifi_set_opmode(STATION_MODE);
u8 tempSaveData[4];
spi_flash_read(520 * 4096, (uint32 *) &tempSaveData, 4);
//如果标志位读取失败
if (tempSaveData[0] == -1) {
tempSaveData[0] = 1;
spi_flash_erase_sector(520);
spi_flash_write(520 * 4096, (uint32 *) &tempSaveData, 4);
}
printf("spi_flash_read tempSaveData--> %d \n" ,tempSaveData[0]);
if (tempSaveData[0] == 5 ) {
//进去配网模式
xTaskCreate(TaskSmartConfig, "TaskSmartConfig", 512, NULL, 2, NULL);
//记得恢复标志为0
u8 saveNumber[4];
saveNumber[0]=0;
spi_flash_erase_sector(520);
spi_flash_write(520 * 4096, (uint32 *) &saveNumber, 4);
} else {
//否则则自动连接上次过的路由器
wifi_set_event_handler_cb(wifi_event_handler_cb);
//设置自动连接
wifi_station_connect();
}
uint32 pwm_duty_init[1] = { 0 };
uint32 io_info[][3] = { { PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12, 12 } }; //GPIO12作为pwm输出脚位
pwm_init(1000, pwm_duty_init, 1, io_info); //初始化 PWM
pwm_set_duty(1023, 0); //最大亮度
pwm_start();
七 、电路原理图以及开发过程的睬坑记录;
-
原理图非常简单:
-
①:
gpio0
和gpio2
都要上拉,虽然内部已经上拉。 -
②:按键的另一端都是接地,我们代码是下降沿触发中断!
-
效果图:
八 、后记;
- 微信小程序是本人周末一天开发的,而且协议和服务器搭建是花费蛮多时间的,最重要的是,这博文是花费几乎五个小时排版和编写,哈哈!需要的私聊我!