【微信小程序控制硬件③】 从软件到硬件搭建一个微信小程序控制esp8266的项目,自定义通讯协议,为面试职位和比赛项目加分!

版权声明:本文为博主半颗心脏一心一血敲出来的原创作品,未经博主允许不得转载,多谢支持。 https://blog.csdn.net/xh870189248/article/details/84580239

  • 本博文由热爱分享热爱技术的半颗心脏原创,非官方人员、非组织名义编写,博文如有不对或侵犯您的权益,请及时留言,第一时间纠正!

【微信小程序控制硬件①】 全网首发,借助 emq 消息服务器带你如何搭建微信小程序的mqtt服务器,轻松控制智能硬件!
【微信小程序控制硬件②】 开始微信小程序之旅,导入小程序Mqtt客户端源码,实现简单的验证和通讯于服务器!
【微信小程序控制硬件③】 从软件到硬件搭建一个微信小程序控制esp8266的项目,自定义通讯协议,为面试职位和比赛项目加分!
【微信小程序控制硬件④】 深度剖析微信公众号配网 Airkiss 原理与过程,esp8266如何自定义回调参数给微信,实现绑定设备第一步!


一、前言;

  • 网上留言抨击从来不是一天两天的事情,为此霍建华退出微博是情有可原的,因为水军太多了!男人大丈夫,不拘小节,做自己的事情,让别人说去吧。好了,从去年自学前端知识H5+css+js,从上个星期给大家带来的服务器搭建,今天有幸给大家带来我的小项目,对于学习微信小程序控制智能硬件(包括esp8266)的原理与过程,我觉得对你有一定的启发!
  • 再次声明:到目前(2018/11/28)为止,微信小程序不支持给智能设备配网! 微信仅仅支持微信公众号给智能设备配网!

二、准备材料;

  • ①:智能硬件esp8266最小系统一个,LED一个,2个轻触开关,杜邦线若干;
  • ②:在微信公众平台:https://mp.weixin.qq.com 注册个人微信小程序 , 下载开发者工具点我下载
  • ③:服务器要求支持wsswebsocket+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();

七 、电路原理图以及开发过程的睬坑记录;


在这里插入图片描述

  • 原理图非常简单:

  • ①:gpio0gpio2都要上拉,虽然内部已经上拉。

  • ②:按键的另一端都是接地,我们代码是下降沿触发中断!

  • 效果图:

在这里插入图片描述


八 、后记;


  • 微信小程序是本人周末一天开发的,而且协议和服务器搭建是花费蛮多时间的,最重要的是,这博文是花费几乎五个小时排版和编写,哈哈!各位能力强的朋友就参考我思路可以了,群里有些人要Bug我的代码,所以,我也就放在咸鱼了。需要的去看看吧!
  • 因为这个是我以后的面试作品,需要的就光顾下,价格绝对地便宜,不喜勿喷哈不喜勿喷哈!博文技术参考还是可以的!哈哈!!咸鱼APP扫描即可!骚扰者请不要扫描了啦,只求真诚交易!

猜你喜欢

转载自blog.csdn.net/xh870189248/article/details/84580239