【移动应用开发技术】微信硬件H5开发之控制灯光的示例分析_第1页
【移动应用开发技术】微信硬件H5开发之控制灯光的示例分析_第2页
【移动应用开发技术】微信硬件H5开发之控制灯光的示例分析_第3页
【移动应用开发技术】微信硬件H5开发之控制灯光的示例分析_第4页
【移动应用开发技术】微信硬件H5开发之控制灯光的示例分析_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】微信硬件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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论