WeChat hardware H5 development to control lights
Mar 16, 2018 pm 02:27 PM這次給大家?guī)?lái)微信硬件H5開(kāi)發(fā)之控制燈光,微信硬件H5開(kāi)發(fā)控制燈光的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來(lái)看一下。
你可以自己扒,帶參數(shù)的頁(yè)面在瀏覽器中打開(kāi)會(huì)馬上跳轉(zhuǎn),不帶參數(shù)的會(huì)提示參數(shù)不全,需要用mobile模式觀看。
呈現(xiàn)的界面如下:
目錄結(jié)構(gòu)?
解壓開(kāi)lamp.js ,目錄如下,這個(gè)demo是基于sea.js+zepto實(shí)現(xiàn),sea.js用來(lái)加載模塊,zepto提供ajax請(qǐng)求和tab事件等。
common中包含了一個(gè)keyConfig.js(地址參數(shù)),一個(gè)reqData.js(請(qǐng)求封裝)還有一個(gè)zepto,ui里是一個(gè)上面圖片的中的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"),?//?開(kāi)關(guān)按鈕????????lightBar;????var?device_status=?{ ????????services:?{ ????????????lightbulb:?{alpha:0}, ????????????operation_status:{status:0} ????????} ????};?//?數(shù)據(jù)對(duì)象 ????(function?()?{????????if(!pageParam.device_id?||?!pageParam.device_type){ ????????????alert("頁(yè)面缺少參數(shù)");????????????return; ????????} ????????log("appid:"?+?pageParam.appid); ????????log("device_id:"?+?pageParam.device_id); ????????log("device_type:"?+?pageParam.device_type); ????????powerBtn.on("tap",?togglePower);?//?開(kāi)關(guān)按鈕事件????????initBar(); ????????initInterval();????????//?todo?:?for?test,?delete?before?submit//????????renderPage({});????})();????/** ?????*?初始化進(jìn)度條?????*/ ????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(); ????????????} ????????}); ????}????/** ?????*?請(qǐng)求數(shù)據(jù)?????*/ ????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("獲取數(shù)據(jù)失敗:"?+?JSON.stringify(msg)); ????????????} ????????}); ????}????/** ?????*?設(shè)置數(shù)據(jù)?????*/ ????function?setData()?{ ????????console.log("setUrl",?keyConfig.SET_LAMP_STATUS); ????????lastModTime?=?new?Date().getTime();?//?更新最后一次操作時(shí)間????????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)); ????}????/** ?????*?開(kāi)關(guān)按鈕事件?????*/ ????function?togglePower()?{ ????????$("#switchBtn").toggleClass("on").toggleClass("off"); ????????log("燈的狀態(tài)status:"+device_status.services.operation_status.status);????????if(device_status.services.operation_status.status==0){ ????????????device_status.services.operation_status.status?=?1; ????????????log("燈的狀態(tài):1"); ????????}?else?{ ????????????device_status.services.operation_status.status?=?0; ????????????log("燈的狀態(tài):0"); ????????}????????setData(); ????}????/** ?????*?輪詢(xún)?????*/ ????function?initInterval()?{ ????????getData(); ????????setInterval(function?()?{????????????if((new?Date().getTime()?-?lastModTime)?>?2000){?//?當(dāng)有設(shè)置操作時(shí),停止1s輪詢(xún),2秒后繼續(xù)輪詢(xún)????????????????getData(); ????????????} ????????},?1000); ????}????/** ?????*?渲染頁(yè)面?????*/ ????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對(duì)象是獲取頁(yè)面上參數(shù)的,device_id,device_type以及appid三個(gè)參數(shù)。其實(shí)有用的只有前面兩個(gè),因?yàn)閍ppid的話,后臺(tái)服務(wù)器已經(jīng)配置了,而且在微信中的通過(guò)“進(jìn)入面板”的時(shí)候只附帶了id和type兩個(gè)參數(shù)。然后device_status是一個(gè)設(shè)備狀態(tài)對(duì)象對(duì)象是燈,根據(jù)微信services的定義,燈有一個(gè)亮度值。這個(gè)在上一篇提到過(guò)。然后是一個(gè)立即執(zhí)行的匿名函數(shù),這個(gè)函數(shù)函數(shù)里面會(huì)先檢查一下參數(shù),然后初始化開(kāi)關(guān)和亮度條。最好進(jìn)入循環(huán)。initInterval中就是不斷的通過(guò)getdata獲取數(shù)據(jù)。注意到這兒有一個(gè)lastModTime的比較,然后延時(shí)2秒再觸發(fā),這個(gè)地方主要是因?yàn)槊看卧O(shè)置之后再?gòu)姆?wù)器撈到數(shù)據(jù)有一個(gè)延時(shí)。原本是10,你設(shè)置了20,bar也到了20的位置,但是呢,服務(wù)器還有一個(gè)10在路上發(fā)過(guò)來(lái),你設(shè)置的20并沒(méi)有馬上失效,這會(huì)有一個(gè)卡頓的效果。但這個(gè)兩秒也不是那么的有效,卡頓還是會(huì)有;另外一方面就是,不能設(shè)置太快,設(shè)置太快了會(huì)報(bào)50019的錯(cuò)誤(設(shè)備正在被操作);getdata成功后,就是renderpage,這個(gè)不用解釋了。注意到在綁定開(kāi)關(guān)時(shí)間的地方,其實(shí)是先調(diào)用了一次setdata
?powerBtn.on("tap",?togglePower);?function?togglePower()?{ ????????$("#switchBtn").toggleClass("on").toggleClass("off"); ????????log("燈的狀態(tài)status:"+device_status.services.operation_status.status);????????if(device_status.services.operation_status.status==0){ ????????????device_status.services.operation_status.status?=?1; ????????????log("燈的狀態(tài):1"); ????????}?else?{ ????????????device_status.services.operation_status.status?=?0; ????????????log("燈的狀態(tài):0"); ????????}????????setData(); ????}
?這個(gè)作用有兩個(gè),一個(gè)是獲取設(shè)備目前的狀態(tài),因?yàn)樵O(shè)備可能沒(méi)有開(kāi)啟,或者沒(méi)有聯(lián)網(wǎng),二個(gè)是將參數(shù)傳遞給后臺(tái),不然getdata無(wú)效。最后理清一下思路就是
獲取參數(shù)-->初始化-->setdata一次-->循環(huán)-->渲染頁(yè)面 ?界面操作-->setdata-->延時(shí)讀取。 加上后端的部分,全部的流程圖如下。
所以拿到前端代碼只是一半,后端還需要自己實(shí)現(xiàn)。
實(shí)現(xiàn)
純靜態(tài)文件是無(wú)法請(qǐng)求微信服務(wù)器的,所以我們需要自己實(shí)現(xiàn)后臺(tái)的部分,這也是第一節(jié)中要講的目的。
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 class="body"> ????????????<p class="inner"> ????????????????<p id="switchBtn" class="status_button off"> ????????????????????<p class="button_wrp"> ????????????????????????<p class="button_mask"> ????????????????????????????<p class="alerter_button" id="powerBtn"> ????????????????????????????????<i class="status_pot"></i> ????????????????????????????????<span class="on">ON</span> ????????????????????????????????<span class="off">OFF</span> ????????????????????????????</p> ????????????????????????</p> ????????????????????</p> ????????????????????<p class="on"> ????????????????????????<h2>燈已開(kāi)</h2> ????????????????????</p> ????????????????</p> ????????????????<p id="reData"></p> ????????????</p> ????????</p> ????????<p class="foot"> ????????????<p class="slider_box J_slider_box"> ????????????????<i class="slider_box_icon icon dark"></i> ????????????????<p id="lightBar" class="slider_box_bar"> ????????????????????<p class="slider_box_slider J_slider" style="left:0%"> ????????????????????????<p class="slider_box_slider_label J_value"></p> ????????????????????????<i class="slider_box_slider_touch"></i> ????????????????????</p> ????????????????????<p class="slider_box_line"> ????????????????????????<span class="slider_box_line_fill J_fill" style="width:0%"></span> ????????????????????</p> ????????????????</p> ????????????????<i class="slider_box_icon icon light"></i> ????????????</p> ????????</p> ????</p> ????<script src="/js/sea.js"></script> ????<script> ????????seajs.config({ ????????????base:?'/js/',????????????//map:?[[/^(.*\.(?:css|js))(.*)$/i,?"$1"]],????????????charset:?'utf-8' ????????}); ????????seajs.use("baby");????</script></body></html>
View Code
自己的實(shí)現(xiàn)就拿掉了遮罩和config部分,將sea.js的目錄改到自己對(duì)應(yīng)的目錄即可:
???seajs.config({ ????????????base:?'/js/',????????????//map:?[[/^(.*\.(?:css|js))(.*)$/i,?"$1"]], ????????????charset:?'utf-8' ????????}); ????????seajs.use("baby");
這個(gè)baby(命名和產(chǎn)品有關(guān)~)就相當(dāng)于是lamp。 另外就是,修改請(qǐng)求地址。也就是通過(guò)后臺(tái)調(diào)用api來(lái)實(shí)現(xiàn)getdate和setdata。第一版我修改的js和lamp.js的差別不大 就增加了一個(gè)log為了調(diào)試,修改調(diào)用路徑。
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"),?//?開(kāi)關(guān)按鈕???????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("頁(yè)面缺少參數(shù)");????????????return; ????????} ????????powerBtn.on("tap",?togglePower);?//?開(kāi)關(guān)按鈕事件????????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"); ????}????/** ?????*?初始化進(jìn)度條?????*/ ????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(); ????????????} ????????}); ????}????/** ???*?開(kāi)關(guān)按鈕事件???*/ ????function?togglePower()?{ ????????$("#switchBtn").toggleClass("on").toggleClass("off");????????if?(requestData.services.operation_status.status?==?0)?{ ????????????requestData.services.operation_status.status?=?1; ????????????log("燈的狀態(tài):1"); ????????}?else?{ ????????????requestData.services.operation_status.status?=?0; ????????????log("燈的狀態(tài):0"); ????????} ????????setData(); ????}????function?queryDevice()?{ ????????$.getJSON('/device/RequestDeviceStatus',?{?reqstr:?JSON.stringify(requestData)?},????????????function?(data)?{ ????????????????console.log(data);????????????????if?(data.error_code?==?0)?{????????????????????//請(qǐng)求成功;????????????????????initInterval(); ????????????????????console.log("查詢(xún)成功"); ????????????????}?else?{ ????????????????????alert(data.error_msg); ????????????????} ????????????}); ????}????/** ???*?輪詢(xún)???*/ ????function?initInterval()?{ ????????getData(); ????????setInterval(function?()?{????????????if?((new?Date().getTime()?-?lastModTime)?>?2000)?{?//?當(dāng)有設(shè)置操作時(shí),停止1s輪詢(xún),2秒后繼續(xù)輪詢(xún)????????????????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("設(shè)置成功"); ????????????} ????????}); ????}????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做成了一個(gè)對(duì)象。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:?'', ????};
后臺(tái)就是兩個(gè)主要方法,一個(gè)設(shè)置(查詢(xún)頁(yè)就是設(shè)置),一個(gè)讀取。這里又回到上一節(jié)的內(nèi)容了。我先查詢(xún)一次設(shè)備(lamp中在綁定)之后,再進(jìn)入循環(huán)。
setdata
public?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("請(qǐng)求失?。?quot;?+?e.Message); ????????????}????????????return?Json("-1",?JsonRequestBehavior.AllowGet); ????????}
這個(gè)方法先將字符串轉(zhuǎn)成我們的RequestData對(duì)象,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就是根據(jù)微信services定義的,可以參考上一節(jié),然后用wxDeviceService請(qǐng)求。
?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);
設(shè)置之后馬上會(huì)受到是否設(shè)置成功的響應(yīng),error_code 可能為50019(設(shè)置頻繁),50013(網(wǎng)絡(luò)問(wèn)題)等等。真正的設(shè)備狀態(tài)是通過(guò)getdata獲得的。
getdata
????????public?JsonResult?GetData() ????????{????????????var?userdata?=?getUserWxData();????????????return?Json(userdata.ResponseData,?JsonRequestBehavior.AllowGet); ????????}
getdata比較簡(jiǎn)單就是返回?cái)?shù)據(jù),但是這個(gè)數(shù)據(jù)是在ReceiveWXMsg方法中設(shè)置的。這個(gè)上一節(jié)也講過(guò),這是在公眾號(hào)后臺(tái)我們?cè)O(shè)置的一個(gè)地址。
???public?string?ReceiveWXMsg() ????????{ ????????????//somecode ????????????try ????????????{????????????????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如下:
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("收到數(shù)據(jù):"?+?postContent); ????????????}????????????try ????????????{????????????????var?data?=?JsonConvert.DeserializeObject<WxResponseData>(postContent); ????????????????data.rawStr?=?postContent; ????????????????Logger.Debug("轉(zhuǎn)換消息狀態(tài):"?+?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
這方法讀到數(shù)據(jù)后就交給了userdata 緩存起來(lái)。在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是我自定義的對(duì)象,包含了下面的幾個(gè)熟悉。
????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 也就是最終要發(fā)給頁(yè)面上的對(duì)象。包含你需要的功能的參數(shù)。
?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?說(shuō)明是設(shè)備變更????????///?set_resp?說(shuō)明是設(shè)置設(shè)備????????///?get_resp?說(shuō)明獲取設(shè)備信息????????///?</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看自己的設(shè)備定義,比如我現(xiàn)在包含了空調(diào),開(kāi)關(guān),溫度濕度。
????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;?} ????}
到這兒,整個(gè)過(guò)程就講完了,獲取token和openid上一節(jié)講過(guò),就不贅述了。如果后端是node的話,就不需要這么多的類(lèi)型轉(zhuǎn)換了。
最后可以看下效果:
相信看了本文案例你已經(jīng)掌握了方法,更多精彩請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
推薦閱讀:
JavaScript關(guān)于IE8兼容問(wèn)題的處理
The above is the detailed content of WeChat hardware H5 development to control lights. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

When using HTML5SSE, the methods to deal with reconnection and errors include: 1. Understand the default reconnection mechanism. EventSource retrys 3 seconds after the connection is interrupted by default. You can customize the interval through the retry field; 2. Listen to the error event to deal with connection failure or parsing errors, distinguish error types and execute corresponding logic, such as network problems relying on automatic reconnection, server errors manually delay reconnection, and authentication failure refresh token; 3. Actively control the reconnection logic, such as manually closing and rebuilding the connection, setting the maximum number of retry times, combining navigator.onLine to judge network status to optimize the retry strategy. These measures can improve application stability and user experience.

HTML5, CSS and JavaScript should be efficiently combined with semantic tags, reasonable loading order and decoupling design. 1. Use HTML5 semantic tags, such as improving structural clarity and maintainability, which is conducive to SEO and barrier-free access; 2. CSS should be placed in, use external files and split by module to avoid inline styles and delayed loading problems; 3. JavaScript is recommended to be introduced in front, and use defer or async to load asynchronously to avoid blocking rendering; 4. Reduce strong dependence between the three, drive behavior through data-* attributes and class name control status, and improve collaboration efficiency through unified naming specifications. These methods can effectively optimize page performance and collaborate with teams.

To control HTML5 video and audio playback using JavaScript, master the following key operations to achieve basic control. 1. Start or pause play can be achieved through the .play() and .pause() methods, and it is recommended to trigger through user interaction to be compatible with mobile browsers; 2. Control the volume and set the value from 0 to 1 through the volume attribute, and switch by setting the muted attribute to true or false; 3. Jump to a specific time to play, you can use the currentTime attribute, which supports direct assignment or increase or decrease the current time, and it is recommended to add error handling; 4. Listen to the playback status changes can be achieved through events such as play, pause, ended and timeupdate.

Server-SentEvents (SSE) is a lightweight solution provided by HTML5 to push real-time updates to the browser. It realizes one-way communication through long HTTP connections, which is suitable for stock market, notifications and other scenarios. Create EventSource instance and listen for messages when using: consteventSource=newEventSource('/stream'); eventSource.onmessage=function(event){console.log('Received message:',event.data);}; The server needs to set Content-Type to text/event

Doctype is a statement that tells the browser which HTML standard to use to parse the page. Modern web pages only need to be written at the beginning of the HTML file. Its function is to ensure that the browser renders the page in standard mode rather than weird mode, and must be located on the first line, with no spaces or comments in front of it; there is only one correct way to write it, and it is not recommended to use old versions or other variants; other such as charset, viewport, etc. should be placed in part.

To build standardized and clear HTML5 documents, the following best practices must be followed: 1. Use standard document type declarations; 2. Build a basic skeleton including three tags and pay attention to the character set, title and script location; 3. Use semantic tags such as , , to improve accessibility and SEO; 4. Reasonably nest the title levels to ensure that the structure is clear and there is only one per page. These steps help improve code quality, collaboration efficiency and user experience.

Using HTML5 semantic tags and Microdata can improve SEO because it helps search engines better understand page structure and content meaning. 1. Use HTML5 semantic tags such as,,,, and to clarify the function of page blocks, which helps search engines establish a more accurate page model; 2. Add Microdata structured data to mark specific content, such as article author, release date, product price, etc., so that search engines can identify information types and use them for display of rich media summary; 3. Pay attention to the correct use of tags to avoid confusion, avoid duplicate tags, test the effectiveness of structured data, regularly update to adapt to changes in schema.org, and combine with other SEO means to optimize for long-term.

It is a block-level element, suitable for layout; it is an inline element, suitable for wrapping text content. 1. Exclusively occupy a line, width, height and margins can be set, which are often used in structural layout; 2. No line breaks, the size is determined by the content, and is suitable for local text styles or dynamic operations; 3. When choosing, it should be judged based on whether the content needs independent space; 4. It cannot be nested and is not suitable for layout; 5. Priority is given to the use of semantic labels to improve structural clarity and accessibility.
