微信硬件平台


調用openApi

 微信硬件平台是微信推出連接物與人,物與物的IOT解決方案。也就是說可以通過微信控制各種智能設備。比如一些藍牙設備、空調、電視等等。

 

我本身不懂硬件(雖然是電子信息專業),硬件是北航的兩個研究生在弄,小團隊里我負責開發H5自定義面板,剛開始看官方文檔各種迷糊,對於jssdk、jsapi、Airkiss、openApi、直連SDK都不知道該用哪個做,官方論壇問問題基本上沒結果,加了幾個微信硬件群問問題,發現好些開發者和我一樣,同一個問題,發到幾個群里問,畫面好心酸。給wxthings發郵件問,能回復就不錯了,往往還是只言片語。吐槽了這么多,還是得去解決問題,畢竟設備能搭上微信是一大賣點,最近摸索出來一些東西,於是有了此文。

 一、接入流程

 

 也就是說,首先你得有一個公眾號,然后開通設備功能、添加產品(也就是你的智能設備)。這些過程官方文檔比較清楚,我就不講了。接入方案我們選擇的是微信硬件雲標准接入方案。

設置面板

而我要說的H5面板開發,指的就是在微信中打開的一個H5控制頁面,它如何和微信硬件雲通信,如何讀取和設置設備的狀態。在添加產品的過程中有一欄設置面板

如果選擇標准面板,微信官方給出了三類標准面板:

 

 分別是空調、開關和燈,如果是自定義,則輸入地址即可。如果是標准面板,你是不需要服務器,但如果是自定義的面板,你就需要有自己的服務器,不然你無法處理微信雲發過來的消息

啟用服務器配置

在設置服務器地址的時候要注意,你必須按照它要求方式處理響應了,你才能啟用成功。

 你點擊啟用的時候,微信雲會發過來一個簽名、一個時間戳、一個隨機數和一個隨機字符串,驗證之后,返回那個隨機字符串,微信雲收到你返回的隨機字符串了,就能啟用成功。比如,如果你定義的地址是http://www.xxx.com/device/ReceiveWXMsg,那么先把代碼上傳服務器,然后再點擊啟用,微信雲會向這個地址post數據。

  View Code

直接返回就行,不要加個json什么的。這個地址是干嘛的呢,往下看。

二、通信方式

Wifi設備和藍牙設備是不同的,藍牙使用Airsync協議和微信通信,而wifi設備的話,我們在自己的服務器上調用微信提供的openApi獲取或設置設備狀態,微信服務器就會把數據以json格式post到我們上面設置的那個地址。硬件方面wifi設備可以使用微信提供的直連SDK來控制設備。

添加完設備,設置好服務器,你還需要硬件的同學打開設備,幫定你的微信。從微信的設置-->設備-->選擇設備-->打開面板。你就可以看到設備並進行控制了。

三、調用openApi

說了這么多前提工作,終於進入調用api環節。可以先看一下openApi的官方文檔:http://iot.weixin.qq.com/wiki/doc/hardwarecloud/openapi.pdf

文檔里面主要講了三個方法,一個是查詢設備狀態,一個是設置設備狀態,一個是接受設備狀態變化的消息,然后是一些錯誤信息等。但觀察api就會發現我們還需要兩個重要的參數,一個是access_token,一個是用戶的openid。還說明一點,網頁是Asp.net mvc。

1.獲取access_token

官方有一個接口調試頁面:http://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:

復制代碼
 public class OpenIdResult
    {
        private List<string> _openId;

        public List<string> open_id
        {
            get { return _openId??(_openId=new List<string>()); }
            set { _openId = value; }
        }

        public resp_msg resp_msg { get; set; }

        public string GetOpenId()
        {
            if (open_id!=null&&open_id.Count==3)
            {
                return open_id[2];
            }
            return "";
        }
    }
復制代碼

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:

對比錯誤代碼列表,我開始以為微信服務器出錯了。其實是我參數填錯了。

 

遇到的錯誤,將不止官方文檔公布的這幾個。

3.查詢設備狀態

查詢設備和上面的這兩個方法略有不同,因為流程是這的,我們的服務器先像向微信服務器請求,微信接受到請求后馬上返回一個確認json,然后微信服務器會馬上把數據post我們前面設置的那個地址上。

請求url:

   public const string GetDeviceStatusUrl="https://api.weixin.qq.com/hardware/mydevice/platform/get_device_status?access_token={0}";

從官方文檔可以看到,查詢設備還需要另外一個重要的參數,它包含device_type和device_id,services,user,data。

 

需要說明一下的就是services,意思是指設備的能力項,也就是你要查詢設備的哪些屬性,這個在設置設備的時候一樣用到。完成的產品能力定義請看:http://iot.weixin.qq.com/wiki/doc/intro/%E4%BA%A7%E5%93%81%E8%83%BD%E5%8A%9B%E5%AE%9A%E4%B9%89%E6%8C%87%E5%BC%95%20V1.2.pdf 

因此定義一個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; }
    }
復制代碼
復制代碼
 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; }
    }
復制代碼

service包括兩個部分,一個是能力部分,好比上面這個service,就包含了三種能力,燈、空調以及開關(這只是測試,不是真正產品的能力)。和一個操作狀態。操作狀態就是指這個設備是否開着或者關閉了。而每一個能力,又包括兩部分,拿燈來說:

復制代碼
    public class lightbulb
    {
        public int alpha { get; set; }
        public lightbulb_value_range value_range { get; set; }
    }

    public class lightbulb_value_range
    {
        public string alpha { get; set; }
    }
復制代碼

燈有一個亮度值,和一個范圍屬性。范圍值中包含了最大和最小值以及單位值。

"lightbulb":{"alpha":10,"value_range":{"alpha":"0|100|1"}},"

這表示燈的亮度是10,返回是0到100,每次可以調節1個單位。

發送查詢請求后,微信返回一個json,定義對象為下:

復制代碼
 public class OpenApiResult
    {
        public int error_code { get; set; }
        public string error_msg { get; set; }

        public string msg_id { get; set; }
    }
復制代碼

 WxDeviceService中:

   public OpenApiResult RequestDeviceStatus(string accessToken, RequestData data)
        {
            var url = string.Format(WxDeviceConfig.GetDeviceStatusUrl, accessToken);
            return SendHelp.Send<OpenApiResult>(accessToken, url, data);
        }

4.接受消息

那么問題來了,如何接受post過來的數據,以及如何存儲呢。微信post的數據格式如下:

定義了一個WxResponseData對象:

  View Code

msg_type代表着不同類型的消息, notify 說明是設備變更,set_resp 說明是設置設備 get_resp 說明獲取設備信息。在WxDeviceService中增加GetDeviceStatus方法:

復制代碼
   public T GetWxResponse<T>(HttpRequestBase request)
        {
            Stream postData = request.InputStream;
            StreamReader sRead = new StreamReader(postData);
            string postContent = sRead.ReadToEnd();
            if (!string.IsNullOrEmpty(postContent))
            {
                Logger.Debug("收到數據:"+postContent);
            }
            try
            {
                return JsonConvert.DeserializeObject<T>(postContent);
            }
            catch (Exception e)
            {
                Logger.Debug(e.Message);
                throw;
            }
        }

        public WxResponseData GetDeviceStatus(HttpRequestBase request)
        {
            return GetWxResponse<WxResponseData>(request);
        }
復制代碼

需要先讀取請求中的json字符串然后轉換成C#對象。然后在最初啟用的ReceiveWXMsg方法中隨時准備接受消息:

復制代碼
  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);
            try
            {
                var userdata = getUserWxData();
                var data = wxDeviceService.GetDeviceStatus(Request);
                userdata.ResponseData = data;
                setUserWxData(userdata);
            }
            catch (Exception e)
            {
                Logger.Debug(e.Message);
            }
            return echostr;
        }
復制代碼

因為讀取到的數據需要及時呈現給頁面,所以這里選用了緩存來存儲設備信息以及用戶相關信息。

UserWxData:

  View Code
  View Code

緩存是Nop中的MemoryCacheManager:

  View Code

而為什么不是PerRequestCacheManager呢,想一想~

  View Code

5.設置設備狀態

有了前面幾步,這里也好說了。url:

 public const string SetDeviceUrl ="https://api.weixin.qq.com/hardware/mydevice/platform/ctrl_device?access_token={0}";

設置設備的參數和請求是一樣的,

  View Code

調用openApi基本上就這樣了,如有不完善的地方還請指正。

四、常見錯誤

 

如果硬件通信沒有開啟這個能力,去查詢的會報這個錯誤。

剛開始看到"device not login"實在沒明白什么意思,文檔里也沒說明這個錯誤。設備還需要什么登錄?原來是硬件同學沒有連接設備... ORZ

如果你的requestData結構不對,特別是附加的那個Data參數只能是字符串,不要寫成空對象{},就會出現這個錯誤。

token超時

同一個設備同時被操作。

小結:以上是硬件面板開發過程中遇到的種種“經驗”總結。限於篇幅這一節只講了openapi的調用。下一節將如何用seajs構建h5控制面板。敬請關注!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM