【微信小程序控制硬件第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,实现无需网络也可以控制亮度开关。
H5+css+js
,从上个星期给大家带来的服务器搭建,今天有幸给大家带来我的小项目,对于学习微信小程序控制智能硬件(包括esp8266
)的原理与过程,我觉得对你有一定的启发!esp8266
最小系统一个,LED一个,2
个轻触开关,杜邦线若干;wss
即websocket+ssl
,而且该端口必须是443
,为了大家方便,我这里教大家怎么接入百度天工服务器,因为百度天工已经支持微信小程序了!当然了,你可以看我第一篇怎么搭建属于自己域名的微信小程序MQTT
服务器,用自己的服务器作为桥梁也行!看业务需要!H5+css+javaSrcipt
,微信的小程序开发和这个非常相似!如果想入门微信小程序开发,自己可以去琢磨!主题 | 发送端 | 接收端 | 消息(JSON格式) | 消息含义 |
---|---|---|---|---|
/light/deviceOut | 微信小程序 | esp8266 | “{“change”:“power”,“value”:true}” | 开灯 |
“{“change”:“power”,“value”:“false”}” | 关灯 | |||
“{“change”:“pwm”,“value”:50}” | 调节亮度:value为亮度值 ,范围 [0,100] | |||
“{“change”:“query”,“value”:0}” | 微信小程序主动请求最新状态 |
主题 | 发送端 | 接收端 | 消息(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
,一个是微信小程序连接客户端;
MQTT
的账号密码肯定需要的!那么上面已经拿到了账号和密码,那么域名和端口号在哪呢?看下图: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)
}
});
}
电源:
当前亮度:{{lightValue}}
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
都要上拉,虽然内部已经上拉。
②:按键的另一端都是接地,我们代码是下降沿触发中断!
效果图:
Bug
我的代码,所以,我小费出售,下面是联系方式!