最近幫朋友研究一個單片機的項目,簡單接觸了一下微信公衆號的硬件平臺,遇到不少問題,簡單記錄一下。html
最終要實現的效果很簡單,就是用經過公衆號遠程控制單片機上的組件,由於圖片大小的限制,上傳一張比較模糊的圖,可是基本效果能夠看到4個按鍵能夠分別控制單片機上的四個LED,既然能夠經過網頁來操做,那麼公衆號上操做基本沒什麼問題java
首先無論用什麼接口,作硬件和軟件的交互通常仍是先想着怎麼去作一個基礎的鏈接操做,最開始查到一些教程並參考微信官方的說法就是先申請設備接入的權限,以測試號來講,申請很是簡單,如圖所示算法
申請完成後,點擊【設置】進入設備管理頁面,按照提示一步步操做就能夠添加設備,我這邊是使用的是第三方的硬件設備,經過wifi進行鏈接,根據相關文檔進行以下設置,具體選項內容應該要根據硬件設備類型來定。api
通過簡單的設置就能夠生成一個設備,能夠在設備列表看到,另外提一下,彷佛一直都存在一個意義不明的undefined設備,應該是平臺開發人員保留的,不影響使用瀏覽器
經過這種方式新建的設備默認擁有100個配額,表明能受權100個能夠控制的設備,我這裏的截圖中是已經受權了一個設備,受權須要經過接口發送請求,具體接口內容在後面詳述。以後開始說第一次鏈接這個重要的問題,可是我這邊並不方便驗證結果,在這裏說下最後的實踐結果。一些教程會提到經過掃描產品詳情裏的二維碼就能夠執行鏈接操做,但對於普通測試狀況並不符合。如下是一般狀況的操做流程:服務器
問題就出在最後一步,我在這裏進行了反覆的測試,前置的配置操做重複了不少遍,還換過開發板,在這裏都是搜索不到設備,通過大量的查找資料發現若是想經過這種方式掃描到設備必須在設備芯片的固件中寫入公衆號的ID,而且我後來也在設備詳情中發現了相關依據微信
雖然找到了問題,可是固件的編寫是個很大的問題,簡單的燒錄能夠作到,但修改編譯固件的代碼倒是不懂,所幸後面發現了另外一種方法,可是因爲最終使用的固件版本是第三方平臺機智雲的,因此沒法驗證其餘的狀況是否能夠,這裏主要是記錄一下開發的過程。app
上面介紹的方法在掃碼後就會自動跳出一個頁面,這個是微信官方提供的,若是不想使用這個頁面的話就能夠經過JS-SDK的方式。框架
在進行下一步操做以前咱們還要了解一下這個跳出的頁面是什麼,官方的描述以下:
Airkiss是微信硬件平臺爲Wi-Fi設備提供的微信配網、局域網發現和局域網通信的技術。開發者若要實現經過微信客戶端對Wi-Fi設備配網、經過微信客戶端在局域網發現Wi-Fi設備,或者把微信客戶端內的音樂、圖片、文件等消息經過局域網發送至Wi-Fi設備,須要在硬件設備中集成相應的AirKiss靜態庫。
經過這句話咱們能夠知道要想在局域網內發現設備就能夠經過這一方法,更詳細的說明能夠看這個頁面
AirKiss概述及應用場景
根據Airkiss2.0的文檔咱們能夠知道經過JSAPI能夠進行配網,以達到咱們的目的。首先在Web層引用微信JSAPI,JSAPI技術是微信JS-SDK的一部分,,主要是經過 wx.ready 和 wx.config 這兩個函數調用官方的接口,具體說明參考
JSAPI介紹
使用Airkiss文檔裏的configWXDeviceWiFi這個方法就能夠進行自定義的AirKiss鏈接,這裏我使用的框架是ASP.NET MVC,因此能夠看到AppID、timestamp、nonceStr、signature這幾個參數是從後臺傳入的,具體的後臺生成代碼放在下面參考,有些參數須要自行傳入,注意修改。
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> <script type="text/javascript"> $(function () { }); $('#btnLink').click(function () { wx.config({ beta: true, debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: '@ViewBag.appId', // 必填,公衆號的惟一標識 timestamp: '@ViewBag.timeStamp', // 必填,生成簽名的時間戳 nonceStr: '@ViewBag.randomStr', // 必填,生成簽名的隨機串 signature: '@ViewBag.signatur',// 必填,簽名 jsApiList: ["configWXDeviceWiFi"] // 必填,須要使用的JS接口列表 }); wx.invoke('configWXDeviceWiFi'); }); </script>
C#後臺代碼參考
public class AirkissHelper { public static string appID = BaseConfig.appID; public static string appsecret = BaseConfig.appsecret; class TokenResultMessage // 封裝調用access_token接口返回的數據 { public string access_token; public string expires_in; } class JsapiResultMessage // 封裝調用jsapi_ticket接口返回的數據 { public string errcode; public string errmsg; public string ticket; public string expires_in; } /// <summary> /// Get請求封裝 /// </summary> /// <param name="url"></param> /// <returns></returns> private static string GetWebUrl(string url) { WebClient client = new WebClient(); // 建立瀏覽器 Stream stream = client.OpenRead(url); // 傳入url地址 return new StreamReader(stream).ReadToEnd(); // 獲得響應字符串 } /// <summary> /// sha1簽名算法 /// </summary> /// <param name="str"></param> /// <returns></returns> private static string Sha1(string str) { var sha1 = System.Security.Cryptography.SHA1.Create(); byte[] bytes = Encoding.UTF8.GetBytes(str); byte[] bytesArr = sha1.ComputeHash(bytes); StringBuilder sb = new StringBuilder(); foreach (var item in bytesArr) { sb.AppendFormat("{0:x2}", item); } return sb.ToString(); } /// <summary> /// 生成時間戳 /// </summary> public static string GetTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1); return Convert.ToInt64(ts.TotalSeconds).ToString(); } /// <summary> /// 生成32位隨機字符串 /// </summary> public static string GetRandomStr() { string strArr = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; Random rand = new Random(); string randStr = ""; for (int i = 0; i < 32; i++) { int index = rand.Next(strArr.Length); randStr += strArr.Substring(index, 1); } return randStr; } /// <summary> /// 生成簽名 /// </summary> public static string GetSignatur(string timestamp,string nonceStr) { // 經過API獲取access_token string tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appID + "&secret=" + appsecret; var tokenInfo = new JavaScriptSerializer().Deserialize<TokenResultMessage>(GetWebUrl(tokenUrl)); // 經過API獲取jsapi_ticket string jsapiUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + tokenInfo.access_token + "&type=jsapi"; var jsapiInfo = new JavaScriptSerializer().Deserialize<JsapiResultMessage>(GetWebUrl(jsapiUrl)); // 當前網頁的URL,不包含#及其後面部分 string nowUrl = BaseConfig.nowUrl; //string nowUrl = Request.Url.AbsoluteUri; // 部署服務器後應動態獲取頁面url // 用Dictionary集合存儲各變量 Dictionary<string, string> dic = new Dictionary<string, string> { ["timestamp"] = timestamp, ["noncestr"] = nonceStr, ["url"] = nowUrl, ["jsapi_ticket"] = jsapiInfo.ticket }; // 對變量名字典排序 string[] arrKey = new string[] { "timestamp", "noncestr", "url", "jsapi_ticket" }; arrKey = arrKey.OrderBy(n => n).ToArray(); // 拼接字符串 string signatureStr = ""; foreach (var item in arrKey) { signatureStr += item + "=" + dic[item] + "&"; } signatureStr = signatureStr.Substring(0, signatureStr.Length - 1); // 對拼接串sh1簽名,獲得最終簽名 return Sha1(signatureStr); } }
作好配置部分的代碼後,在頁面上使用 wx.invoke('configWXDeviceWiFi');就能夠手動調起Airkiss頁面,輸入wifi密碼後手動鏈接,根據wx.config裏面的debug配置會返回提示消息。