我本身不懂硬件(虽然是电子信息专业),硬件是北航的两个研究生在弄,小团队里我负责开发H5自定义面板,刚开始看官方文档各种迷糊,对于jssdk、jsapi、Airkiss、openApi、直连SDK都不知道该用哪个做,官方论坛问问题基本上没结果,加了几个微信硬件群问问题,发现好些开发者和我一样,同一个问题,发到几个群里问,画面好心酸。给wxthings发邮件问,能回复就不错了,往往还是只言片语。吐槽了这么多,还是得去解决问题,毕竟设备能搭上微信是一大卖点,最近摸索出来一些东西,于是有了此文。
一、接入流程
也就是说,首先你得有一个公众号,然后开通设备功能、添加产品(也就是你的智能设备)。这些过程官方文档比较清楚,我就不讲了。接入方案我们选择的是微信硬件云标准接入方案。
设置面板
而我要说的H5面板开发,指的就是在微信中打开的一个H5控制页面,它如何和微信硬件云通信,如何读取和设置设备的状态。在添加产品的过程中有一栏设置面板
如果选择标准面板,微信官方给出了三类标准面板:
分别是空调、开关和灯,如果是自定义,则输入地址即可。如果是标准面板,你是不需要服务器,但如果是自定义的面板,你就需要有自己的服务器,不然你无法处理微信云发过来的消息。
启用服务器配置
在设置服务器地址的时候要注意,你必须按照它要求方式处理响应了,你才能启用成功。
你点击启用的时候,微信云会发过来一个签名、一个时间戳、一个随机数和一个随机字符串,验证之后,返回那个随机字符串,微信云收到你返回的随机字符串了,就能启用成功。比如,如果你定义的地址是http://www.xxx.com/device/ReceiveWXMsg,那么先把代码上传服务器,然后再点击启用,微信云会向这个地址post数据。 每一次微信向服务器发送数据时,都会先发这验证(也就是说如果不校验就返回会有安全问题)。
public string ReceiveWXMsg() { var signature = Request.QueryString["signature"]; var timestamp = Request.QueryString["timestamp"]; var echostr = Request.QueryString["echostr"]; var nonce = Request.QueryString["nonce"]; Logger.Debug("signature:" + signature); Logger.Debug("timestamp:" + timestamp); Logger.Debug("nonce:" + nonce); Logger.Debug("echostr:" + echostr); //验证 return echostr; }
View Code
直接返回就行,不要加个json什么的。这个地址是干嘛的呢,往下看。
二、通信方式
Wifi设备和蓝牙设备是不同的,蓝牙使用Airsync协议和微信通信,而wifi设备的话,我们在自己的服务器上调用微信提供的openApi获取或设置设备状态,微信服务器就会把数据以json格式post到我们上面设置的那个地址。硬件方面wifi设备可以使用微信提供的直连SDK来控制设备。
添加完设备,设置好服务器,你还需要硬件的同学打开设备,帮定你的微信。从微信的设置-->设备-->选择设备-->打开面板。你就可以看到设备并进行控制了。
三、调用openApi
说了这么多前提工作,终于进入调用api环节。可以先看一下openApi的官方文档:iot.weixin.qq.com/wiki/doc/hardwarecloud/openapi.pdf
文档里面主要讲了三个方法,一个是查询设备状态,一个是设置设备状态,一个是接受设备状态变化的消息,然后是一些错误信息等。但观察api就会发现我们还需要两个重要的参数,一个是access_token,一个是用户的openid。还说明一点,网页是Asp.net mvc。
1.获取access_token
官方有一个接口调试页面:mp.weixin.qq.com/debug/ ,获取access_token需要appid和secret。
而这两个值,是在公众号后台的基本配置中查看,secret是个很重要的参数,所以请保密好。
查看密钥还需要扫二维码得到管理员的确认... 拿到这两个参数了,我们就可以生成token了。注意返回的json是一个token字符串再加一个超时时间。定义一个TokenResult:
public class TokenResult { public string access_token { get; set; } public int expires_in { get; set; } }
要注意的一点是,token两小时后会过期。所以在我们的代码里面需要检查是否超时,然后自动重新获取。
public const string AccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
getAccessToken方法定义在一个服务类中,比如WxDeviceService
using SendHelp= Senparc.Weixin.CommonAPIs.CommonJsonSend;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; }
使用Senparc.Weixin框架封装好的api来处理请求。
2.获取openid
这个参数在查询和设置设备状态的时候会用到,对应user参数名。获取openid需要三个参数,access_token已经有了,然后需要device_type和device_id
public const string GetOpenid ="https://api.weixin.qq.com/device/get_openid?access_token={0}&device_type={1}&device_id={2}";
而type和id是前端页面传过来的,当用户微信中打开控制面板的时候,微信会自动将这两个参数追加到url后面。而这个url的返回值结构是这样:
{"open_id":["oxa1otw5sk-Azgd8mx1bmBqoM2_E","oxa1ot8-j9j5bYUJJyAexe9d41_Y","oxa1ot5QTdxn0xNQ0DmYzoN0tUp1"],"resp_msg":{"ret_code":0,"error_info":"ok"}}
openid部分是一个数组,实际使用的是第三个(我目前也不知道前面两个id是干啥的),定义一个openidResult:
List<> List<> { _openId??(_openId= List<> { _openId = resp_msg resp_msg { ;
service中:
public string GetOpenId(string accessToken,string deviceType,string deviceId) { var url = string.Format(WxDeviceConfig.GetOpenid, accessToken, deviceType, deviceId); var res = SendHelp.Send<OpenIdResult>(accessToken, url, null, CommonJsonSendType.GET); return res.GetOpenId(); }
如果你的devicetype和deviceId错误,微信会返回一个不太恰当的错误json:
对比错误代码列表,我开始以为微信服