重庆小潘seo博客

当前位置:首页 > 重庆网络营销 > 小潘杂谈 >

小潘杂谈

微信硬件H5开发之控制灯光

时间:2020-09-08 10:00:09 作者:重庆seo小潘 来源:
这次给大家带来微信硬件H5开发之控制灯光,微信硬件H5开发控制灯光的注意事项有哪些,下面就是实战案例,一起来看一下。 你可以自己扒,带参数的页面在浏览器中打开会马上跳转,不带参数的会提示参数不全,需要用mobile模式观看。 呈现的界面如下: 目录结构

这次给大家带来微信硬件H5开发之控制灯光,微信硬件H5开发控制灯光的注意事项有哪些,下面就是实战案例,一起来看一下。

你可以自己扒,带参数的页面在浏览器中打开会马上跳转,不带参数的会提示参数不全,需要用mobile模式观看。

呈现的界面如下:

微信硬件H5开发之控制灯光目录结构 解压开lamp.js ,目录如下,这个demo是基于sea.js+zepto实现,sea.js用来加载模块,zepto提供ajax请求和tab事件等。

微信硬件H5开发之控制灯光

common中包含了一个keyConfig.js(地址参数),一个reqData.js(请求封装)还有一个zepto,ui里是一个上面图片的中的slider一样的组件。util中是一组方法集合。最重要的就是lamp.js 。define(function (require) {var $ = require("common/zepto");var keyConfig = require("common/keyConfig");var reqData = require("common/reqData");var util = require("util/util");var ProcessBar = require("ui/process-bar");var pageParam = {device_id: util.getQuery("device_id"),device_type: util.getQuery("device_type"),appid: util.getQuery("appid")};var lastModTime = 0;var powerBtn = $("#powerBtn"), // 开关按钮lightBar;var device_status= {services: {lightbulb: {alpha:0},operation_status:{status:0}}}; // 数据对象(function () {if(!pageParam.device_id || !pageParam.device_type){alert("页面缺少参数");return;}log("appid:" + pageParam.appid);log("device_id:" + pageParam.device_id);log("device_type:" + pageParam.device_type);powerBtn.on("tap", togglePower); // 开关按钮事件initBar();initInterval();// todo : for test, delete before submit//renderPage({});})();/*** 初始化进度条*/function initBar() {log("初始化lightBar");lightBar = new ProcessBar({$id: "lightBar",min: 0,stepCount: 100,step: 1,touchEnd: function (val) {device_status.services.lightbulb.alpha = val;log("亮度值为:"+val);setData();}});}/*** 请求数据*/function getData() {reqData.ajaxReq({//url: keyConfig.GET_LAMP_STATUS,url:'https://api.weixin.qq.com/device/getlampstatus',data: pageParam,onSuccess: renderPage,onError:function(msg) {log("获取数据失败:" + JSON.stringify(msg));}});}/*** 设置数据*/function setData() {console.log("setUrl", keyConfig.SET_LAMP_STATUS);lastModTime = new Date().getTime(); // 更新最后一次操作时间reqData.ajaxReq({// url: keyConfig.SET_LAMP_STATUS,url: 'https://api.weixin.qq.com/device/setlampstatus',type: "POST",data: JSON.stringify(device_status)});log("setData:" + JSON.stringify(device_status));}/*** 开关按钮事件*/function togglePower() {$("#switchBtn").toggleClass("on").toggleClass("off");log("灯的状态status:"+device_status.services.operation_status.status);if(device_status.services.operation_status.status==0){device_status.services.operation_status.status = 1;log("灯的状态:1");} else {device_status.services.operation_status.status = 0;log("灯的状态:0");}setData();}/*** 轮询*/function initInterval() {getData();setInterval(function () {if((new Date().getTime() - lastModTime) > 2000){ // 当有设置操作时,停止1s轮询,2秒后继续轮询getData();}}, 1000);}/*** 渲染页面*/function renderPage(json) {// todo : for test, delete before submit//json = {//device_status: {//services: {//operation_status: {//status: 0//},//lightbulb: {//alpha: 0//}//}//}//};log("renderPage:"+json);if(!json.device_status){return;}console.log("json", json);device_status = json.device_status;log(device_status);if(device_status.services.operation_status.status==0){$("#switchBtn").addClass("on").removeClass("off");} else {$("#switchBtn").addClass("off").removeClass("on");}lightBar.setVal(device_status.services.lightbulb.alpha);}});/*|xGv00|4199711a9ade00e2807e7ea576d92f55 */ 首先我们看到pageParam对象是获取页面上参数的,device_id,device_type以及appid三个参数。其实有用的只有前面两个,因为appid的话,后台服务器已经配置了,而且在微信中的通过“进入面板”的时候只附带了id和type两个参数。然后device_status是一个设备状态对象对象是灯,根据微信services的定义,灯有一个亮度值。这个在上一篇提到过。然后是一个立即执行的匿名函数,这个函数函数里面会先检查一下参数,然后初始化开关和亮度条。最好进入循环。initInterval中就是不断的通过getdata获取数据。注意到这儿有一个lastModTime的比较,然后延时2秒再触发,这个地方主要是因为每次设置之后再从服务器捞到数据有一个延时。原本是10,你设置了20,bar也到了20的位置,但是呢,服务器还有一个10在路上发过来,你设置的20并没有马上失效,这会有一个卡顿的效果。但这个两秒也不是那么的有效,卡顿还是会有;另外一方面就是,不能设置太快,设置太快了会报50019的错误(设备正在被操作);getdata成功后,就是renderpage,这个不用解释了。注意到在绑定开关时间的地方,其实是先调用了一次setdata powerBtn.on("tap", togglePower); function togglePower() {$("#switchBtn").toggleClass("on").toggleClass("off");log("灯的状态status:"+device_status.services.operation_status.status);if(device_status.services.operation_status.status==0){device_status.services.operation_status.status = 1;log("灯的状态:1");} else {device_status.services.operation_status.status = 0;log("灯的状态:0");}setData();} 这个作用有两个,一个是获取设备目前的状态,因为设备可能没有开启,或者没有联网,二个是将参数传递给后台,不然getdata无效。最后理清一下思路就是

获取参数-->初始化-->setdata一次-->循环-->渲染页面界面操作-->setdata-->延时读取。 加上后端的部分,全部的流程图如下。

微信硬件H5开发之控制灯光

所以拿到前端代码只是一半,后端还需要自己实现。实现纯静态文件是无法请求微信服务器的,所以我们需要自己实现后台的部分,这也是第一节中要讲的目的。

html:@{Layout = null;}<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta id="viewport" name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"><title>我的灯泡</title><link href="/css/common.css" rel="stylesheet" /><link href="/css/light_switch.css" rel="stylesheet" /></head><body><p><p>View Code

自己的实现就拿掉了遮罩和config部分,将sea.js的目录改到自己对应的目录即可:seajs.config({base: '/js/',//map: [[/^(.*.(?:css|js))(.*)$/i, "$1"]],charset: 'utf-8'});seajs.use("baby");这个baby(命名和产品有关~)就相当于是lamp。 另外就是,修改请求地址。也就是通过后台调用api来实现getdate和setdata。第一版我修改的js和lamp.js的差别不大 就增加了一个log为了调试,修改调用路径。define(function (require) {var $ = require("common/zepto");var util = require("util/util");var ProcessBar = require("ui/process-bar");var requestData = {services: {lightbulb: { alpha: 10 },air_conditioner: {},power_switch: {},operation_status: { status: 0 }},device_type: util.getQuery("device_type"),device_id: util.getQuery("device_id"),user: '',};var lastModTime = 0;var powerBtn = $("#powerBtn"), // 开关按钮lightBar;function log(msg, arg) {console.log(msg, arg);msg = JSON.stringify(msg);if (arg) {msg = msg + "," + JSON.stringify(arg);}$.post('/device/log', { msg: msg });}(function () {bindEvent();if (!requestData.device_id || !requestData.device_type) {alert("页面缺少参数");return;}powerBtn.on("tap", togglePower); // 开关按钮事件initBar();queryDevice();})();function bindEvent() {$(".footer .nav_side li").click(function () {activePage($(this).data("index"), $(this));});}function activePage(index, $self) {$self.parent('li').addClass("on");$body.find('.page:eq(' + index + ')').addClass("active").siblings().removeClass("active");}/*** 初始化进度条*/function initBar() {log("初始化lightBar");lightBar = new ProcessBar({$id: "lightBar",min: 0,stepCount: 100,step: 1,touchEnd: function (val) {requestData.services.lightbulb.alpha = val;log("亮度值为:" + val);setData();}});}/*** 开关按钮事件*/function togglePower() {$("#switchBtn").toggleClass("on").toggleClass("off");if (requestData.services.operation_status.status == 0) {requestData.services.operation_status.status = 1;log("灯的状态:1");} else {requestData.services.operation_status.status = 0;log("灯的状态:0");}setData();}function queryDevice() {$.getJSON('/device/RequestDeviceStatus', { reqstr: JSON.stringify(requestData) },function (data) {console.log(data);if (data.error_code == 0) {//请求成功;initInterval();console.log("查询成功");} else {alert(data.error_msg);}});}/*** 轮询*/function initInterval() {getData();setInterval(function () {if ((new Date().getTime() - lastModTime) > 2000) { // 当有设置操作时,停止1s轮询,2秒后继续轮询getData();}}, 1000);}function setData() {$.getJSON('/device/RequestDeviceStatus', { reqstr: JSON.stringify(requestData) }, function (data) {console.log(data);lastModTime = new Date().getTime();if (data.error_code == 0) {console.log("设置成功");}});}function getData() {$.post('/device/getData', function (data) {$("#reData").html(JSON.stringify(data));if (data && data.services) {renderPage(data);}});};function renderPage(json) {if (!json.services) {return;}console.log("json", json);requestData = json;if (requestData.services.operation_status.status == 0) {$("#switchBtn").addClass("off").removeClass("on");} else {$("#switchBtn").addClass("on").removeClass("off");}lightBar.setVal(requestData.services.lightbulb.alpha);}})View Code

我将pageParam和device_status做成了一个对象。requestData。var requestData = {services: {lightbulb: { alpha: 10 },// air_conditioner: {},power_switch: {},operation_status: { status: 0 }},device_type: util.getQuery("device_type"),device_id: util.getQuery("device_id"),user: '',};后台就是两个主要方法,一个设置(查询页就是设置),一个读取。这里又回到上一节的内容了。我先查询一次设备(lamp中在绑定)之后,再进入循环。setdatapublic ActionResult RequestDeviceStatus(string reqstr){if (string.IsNullOrEmpty(reqstr)){return Json("-1", JsonRequestBehavior.AllowGet);}var args = JsonConvert.DeserializeObject<RequestData>(reqstr);args.user = getOpenId(args.device_type, args.device_id);Session["warmwood"] = args.device_id;//args.services.air_conditioner = null;args.services.power_switch = null;args.services.lightbulb.value_range = null;try{var res = wxDeviceService.RequestDeviceStatus(getToken(), args);if (res.error_code != 0){Logger.Debug("error_code:" + res.error_code);Logger.Debug("error_msg:" + res.error_msg);}return Json(res, JsonRequestBehavior.AllowGet);}catch (ErrorJsonResultException e){if (e.JsonResult.errcode.ToString() == "access_token expired"){//重新获取token}Logger.Debug("请求失败:" + e.Message);}return Json("-1", JsonRequestBehavior.AllowGet);}这个方法先将字符串转成我们的RequestData对象,RequestData如下:public class RequestData{public string device_type { get; set; }public string device_id { get; set; }public string user { get; set; }public Service services { get; set; }public object data { get; set; }}services就是根据微信services定义的,可以参考上一节,然后用wxDeviceService请求。 var res = wxDeviceService.RequestDeviceStatus(getToken(), args);if (res.error_code != 0){Logger.Debug("error_code:" + res.error_code);Logger.Debug("error_msg:" + res.error_msg);}return Json(res, JsonRequestBehavior.AllowGet);设置之后马上会受到是否设置成功的响应,error_code 可能为50019(设置频繁),50013(网络问题)等等。真正的设备状态是通过getdata获得的。getdatapublic JsonResult GetData(){var userdata = getUserWxData();return Json(userdata.ResponseData, JsonRequestBehavior.AllowGet);}getdata比较简单就是返回数据,但是这个数据是在ReceiveWXMsg方法中设置的。这个上一节也讲过,这是在公众号后台我们设置的一个地址。public string ReceiveWXMsg(){//somecodetry{var userdata = getUserWxData();var data = wxDeviceService.GetDeviceStatus(Request);userdata.ResponseData = data;Logger.Debug("ResponseData.asy_error_code:" + userdata.ResponseData.asy_error_code);Logger.Debug("ResponseData.asy_error_msg:" + userdata.ResponseData.asy_error_msg);setUserWxData(userdata);}catch (Exception e){Logger.Debug(e.Message);}return echostr;}wxDeviceService如下:

微信硬件H5开发之控制灯光微信硬件H5开发之控制灯光using System;using System.Collections.Generic;using System.Diagnostics;using System.IO;using System.Linq;using System.Net.Http;using System.Web;using Newtonsoft.Json;using Niqiu.Core.Domain.Common;using Senparc.Weixin;using Senparc.Weixin.Exceptions;using SendHelp= Senparc.Weixin.CommonAPIs.CommonJsonSend;namespace Portal.MVC.WXDevice{public class WxDeviceService:IWxDeviceService{//private readonly ICacheManager _cacheManager;//public WxDeviceService(ICacheManager cacheManager)//{//_cacheManager = cacheManager;//}public TokenResult GetAccessToken(){var url = string.Format(WxDeviceConfig.AccessTokenUrl, WxDeviceConfig.AppId, WxDeviceConfig.APPSECRET);var res = SendHelp.Send<TokenResult>(null, url, null, CommonJsonSendType.GET);return res;}public WxResponseData GetDeviceStatus(HttpRequestBase request){Stream postData = request.InputStream;StreamReader sRead = new StreamReader(postData);string postContent = sRead.ReadToEnd();if (!string.IsNullOrEmpty(postContent)){Logger.Debug("收到数据:" + postContent);}try{var data = JsonConvert.DeserializeObject<WxResponseData>(postContent);data.rawStr = postContent;Logger.Debug("转换消息状态:" + data.asy_error_msg);return data;}catch (Exception e){Logger.Debug(e.Message);throw;}}public OpenApiResult RequestDeviceStatus(string accessToken, RequestData data){var url = string.Format(WxDeviceConfig.GetDeviceStatusUrl, accessToken);return SendHelp.Send<OpenApiResult>(accessToken, url, data);}public OpenApiResult SetDevice(string accessToken, RequestData data){var url = string.Format(WxDeviceConfig.GetDeviceStatusUrl, accessToken);return SendHelp.Send<OpenApiResult>(accessToken, url, data);}public string GetOpenId(string accessToken,string deviceType,string deviceId){try{var url = string.Format(WxDeviceConfig.GetOpenid, accessToken, deviceType, deviceId);var res = SendHelp.Send<OpenIdResult>(accessToken, url, null, CommonJsonSendType.GET);return res.GetOpenId();}catch (ErrorJsonResultException e){Logger.Debug(e.Message);throw;}}}}View Code

这方法读到数据后就交给了userdata 缓存起来。在getdata方法中返回。private UserWxData getUserWxData(){var target = _cacheManager.Get<UserWxData>(userKey) ?? new UserWxData();return target;}private string userKey{get{var key = Session["warmwood"] ?? Session.SessionID;Session.Timeout = 240;return key.ToString();}}View Code

UserWxData是我自定义的对象,包含了下面的几个熟悉。public class UserWxData{private WxResponseData _responseData;public UserWxData(){CreateTime = DateTime.Now;}public DateTime CreateTime { get; set; }public TokenResult AccessToken { get; set; }public WxResponseData ResponseData{get { return _responseData??(_responseData=new WxResponseData()); }set { _responseData = value; }}public string OpenId { get; set; }}比较重要的是token和responseData。WxResponseData 也就是最终要发给页面上的对象。包含你需要的功能的参数。 public class WxResponseData{public int asy_error_code { get; set; }public string asy_error_msg { get; set; }public string create_time { get; set; }public string msg_id { get; set; }/// <summary>/// notify 说明是设备变更/// set_resp 说明是设置设备/// get_resp 说明获取设备信息/// </summary>public string msg_type { get; set; }public string device_type { get; set; }public string device_id { get; set; }public object data { get; set; }public Service services { get; set; }public string user { get; set; }public string rawStr { get; set; }}severices看自己的设备定义,比如我现在包含了空调,开关,温度湿度。public class Service{public lightbulb lightbulb { get; set; }public air_conditioner air_conditioner { get; set; }public power_switch power_switch { get; set; }public operation_status operation_status { get; set; }public tempe_humidity tempe_humidity { get; set; }}到这儿,整个过程就讲完了,获取token和openid上一节讲过,就不赘述了。如果后端是node的话,就不需要这么多的类型转换了。

最后可以看下效果:

微信硬件H5开发之控制灯光

相信看了本文案例你已经掌握了方法,更多精彩请关注小潘博客其它相关文章!

推荐阅读:

JS里特别好用的轻量级日期插件

JavaScript关于IE8兼容问题的处理以上就是微信硬件H5开发之控制灯光的详细内容,更多请关注小潘博客其它相关文章!