版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】微信硬件H5开发之控制灯光的示例分析
这篇文章主要介绍了微信硬件H5开发之控制灯光的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让在下带着大家一起了解一下。呈现的界面如下:目录结构解压开lamp.js,目录如下,这个demo是基于sea.js+zepto实现,sea.js用来加载模块,zepto提供ajax请求和tab事件等。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:'/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:
'/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-->延时读取。加上后端的部分,全部的流程图如下。所以拿到前端代码只是一半,后端还需要自己实现。实现纯静态文件是无法请求微信服务器的,所以我们需要自己实现后台的部分,这也是第一节中要讲的目的。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">
<h3>灯已开</h3>
</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>ViewCode自己的实现就拿掉了遮罩和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);
}
})ViewCode我将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获得的。getdata
public
JsonResult
GetData()
{
var
userdata
=
getUserWxData();
return
Json(userdata.ResponseData,
JsonRequestBehavior.AllowGet);
}getdata比较简单就是返回数据,但是这个数据是在ReceiveWXMsg方法中设置的。这个上一节也讲过,这是在公众号后台我们设置的一个地址。
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("收到数据:"
+
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;
}
}
}
}ViewCode这方法读到数据后就交给了userdata缓存起来。在getdata方法中返回。
private
UserWxData
getUserWxData()
{
var
target
=
_cacheManage
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 生物质燃气发电项目投资回报分析考核试卷
- 2024至2030年中国冷冻鳄鱼肉数据监测研究报告
- 外卖行业绿色配送模式探索考核试卷
- 《中煤能源基于平衡计分卡绩效评价体系的改进与应用研究》
- 智能医疗在肿瘤治疗中的应用考核试卷
- 污水处理中的曝气生物膜技术考核试卷
- 天然气长期供需趋势与预测考核试卷
- 《封闭聚氨酯改进丁苯橡胶金属(钢)热硫化粘合剂性能的研究》
- 制糖业市场区域分布分析考核试卷
- 天然气开采业的资源储备与勘探技术考核试卷
- 三国演义第三回读后感100字 三国演义第三回读后感1000字以上(三篇)
- 双阳区巡游出租汽车驾驶员从业资格考试区域科目考试题库
- 口腔修复学名解及案例分析题
- 制糖工艺基础知识及煮糖技术(上课)
- 企业法人委托书模板
- FZ/T 64078-2019熔喷法非织造布
- 高三英语一轮复习读后续写导学案
- 如何看懂体检报告
- 《民航英语口语》课程标准
- 2023年陕西投资集团有限公司校园招聘笔试题库及答案解析
- 科目二考试成绩单
评论
0/150
提交评论