微信硬件H5面板开发(二) ---- 实现一个灯的控制

第一节中讲解了openApi的调用,这一篇讲一下如何实现一个灯的控制。就用微信提供的lamp例子来做,将代码扒下来(实在是没办法,没有示例),整合到自己的项目中。lamp源码:http://files.cnblogs.com/files/stoneniqiu/lamp.zip

你可以自己扒,带参数的页面在浏览器中打开会马上跳转,不带参数的会提示参数不全,需要用mobile模式观看。

呈现的界面如下:

目录结构

解压开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:‘https://api.weixin.qq.com/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: ‘https://api.weixin.qq.com/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>
    <div>
        <div class="body">
            <div class="inner">
                <div id="switchBtn" class="status_button off">
                    <div class="button_wrp">
                        <div class="button_mask">
                            <div class="alerter_button" id="powerBtn">
                                <i class="status_pot"></i>
                                <span class="on">ON</span>
                                <span class="off">OFF</span>
                            </div>
                        </div>
                    </div>
                    <div class="on">
                        <h2>灯已开</h2>
                    </div>
                </div>
                <div id="reData"></div>
            </div>
        </div>
        <div class="foot">
            <div class="slider_box J_slider_box">
                <i class="slider_box_icon icon dark"></i>
                <div id="lightBar" class="slider_box_bar">
                    <div 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>
                    </div>
                    <div class="slider_box_line">
                        <span class="slider_box_line_fill J_fill" style="width:0%"></span>
                    </div>
                </div>
                <i class="slider_box_icon icon light"></i>
            </div>
        </div>
    </div>
    <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>

自己的实现就拿掉了遮罩和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);
    }
})

我将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中在绑定)之后,再进入循环。

setdata

public 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;
            }
        }
    }
}

这方法读到数据后就交给了userdata 缓存起来。在getdata方法中返回。

   private UserWxData getUserWxData()
        {
            var target = _cacheManager.Get<UserWxData>(userKey) ?? new UserWxData();
            return target;
        }

        private string userKey
        {
            get
            {
                var key = Session["warmwood"] ?? Session.SessionID;
                Session.Timeout = 240;
                return key.ToString();
            }
        }

UserWxData是我自定义的对象,包含了下面的几个熟悉。

    public class UserWxData
    {
        private WxResponseData _responseData;

        public UserWxData()
        {
            CreateTime = DateTime.Now;
        }
        public DateTime CreateTime { get; set; }
        public TokenResult AccessToken { get; set; }

        public WxResponseData ResponseData
        {
            get { return _responseData??(_responseData=new WxResponseData()); }
            set { _responseData = value; }
        }

        public string OpenId { get; set; }
    }

比较重要的是token和responseData。WxResponseData 也就是最终要发给页面上的对象。包含你需要的功能的参数。

 public class WxResponseData
    {
        public int asy_error_code { get; set; }

        public string asy_error_msg { get; set; }

        public string create_time { get; set; }

        public string msg_id { get; set; }

        /// <summary>
        /// notify 说明是设备变更
        /// set_resp 说明是设置设备
        /// get_resp 说明获取设备信息
        /// </summary>
        public string msg_type { get; set; }

        public string device_type { get; set; }
        public string device_id { get; set; }
        public object data { get; set; }

        public Service services { get; set; }

        public string user { get; set; }

        public string rawStr { get; set; }
    }

severices看自己的设备定义,比如我现在包含了空调,开关,温度湿度。

    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; }

        public tempe_humidity tempe_humidity { get; set; }
    }

到这儿,整个过程就讲完了,获取token和openid上一节讲过,就不赘述了。如果后端是node的话,就不需要这么多的类型转换了。

最后可以看下效果:

小结:以上就这一篇的全部内容,流程图画可能画的不够好,但这都是摸索出来的结果,微信硬件虽然提供了自定义的链接设置,但是没有提供demo。文中有不对或者不合适的地方欢迎拍砖,欢迎加Q交流。

时间: 2024-12-21 02:03:42

微信硬件H5面板开发(二) ---- 实现一个灯的控制的相关文章

微信硬件H5面板开发(一) ---- 调用openApi

微信硬件平台是微信推出连接物与人,物与物的IOT解决方案.也就是说可以通过微信控制各种智能设备.比如一些蓝牙设备.空调.电视等等. 我本身不懂硬件(虽然是电子信息专业),硬件是北航的两个研究生在弄,小团队里我负责开发H5自定义面板,刚开始看官方文档各种迷糊,对于jssdk.jsapi.Airkiss.openApi.直连SDK都不知道该用哪个做,官方论坛问问题基本上没结果,加了几个微信硬件群问问题,发现好些开发者和我一样,同一个问题,发到几个群里问,画面好心酸.给wxthings发邮件问,能回复

关于微信网页/H5游戏开发中二维码无法识别的解决方法

我接触微信H5开发已经有一年多了,做过很多案例也遇到很多的问题.今天我把困扰我半年之久的问题分享出来,也就是关于微信网页/H5游戏开发中二维码无法识别的解决方法. 我在百度搜索了许久,关于微信H5网页/游戏开发问题以及解决方案的相关文章少之又少,在相关前端交流群中问别人,一问三不知,平时这些群就会上班吹牛逼,真正交流问题的人少又少,真是揪心啊,最后还是得靠自己解决了. [这里,我先举个栗子] 上面这个页面,相信从事微信H5开发的人应该很熟悉,就是常见的分享到朋友圈的页面,通常以[引导分享图标]+

能挣钱的微信JSSDK+H5混合开发

H5喊了那么久,有些人都说不实用,有些人却利用在微信中开发H5应用赚得盆满钵满.微信JSSDK + HTML 5,让移动Web开发与微信结合轻而易举!跨平台.零成本,让大众创业变得更方便. 我觉得现在大众创业就要从一个微信公众号开始,这个公众号可以有基本的1-3个功能,拿“悠泊停车”来说,刚开始就只有一个微信公众号,它代替了所有的Native APP功能,让“悠泊停车”迅速打开了市场,并拉来百万美元投资. 目前微信公众号开发已经遍地都是,但真正H5场景应用还少得可怜,大部分小企业都只有简单的菜单

微信支付h5客户端开发步骤

第一步:用户同意授权,获取code 在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下 服务号获得高级接口后,默认拥有scope参数中的snsapi_base和snsapi_userinfo),引导关注者打开如下页面: https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&s

H5混合开发二维码扫描以及调用本地摄像头

今天主管给了我个需求,说要用混合开发,用H5调用本地摄像头进行扫描二维码,我之前有做过原生安卓的二维码扫一扫,主要是通过调用zxing插件进行操作的,其中还弄了个闪光灯.但是纯H5的没接触过,心里没底,于是晚上回家开始网上各处找方案.以下是我对于H5扫描二维码以及调用本地摄像头的理解以及代码. 科普网址: H5如何生成安卓组件对象 H5调用安卓本地摄像头api 在线二维码图片生成器 二维码扫描:(使用的是mui的框架,下面是html代码) <!doctype html> <html>

微信公众号平台开发(二)信息的分类.md

在上一篇博客中,我们只是简单地与微信服务器建立了连接,接下来就是从微信服务器中接收信息了.在SecurityController中,我定义了两个方法(get和post).Get方法是我们用来与微信服务器建立连接,而我们将通过Post方法来接收微信服务器发给我们的响应. 当我们完成服务器验证后,以后用户对公众号的每个事件,微信服务器都会通过我们配置的URL推送到我们自己的服务器,然后我们服务器根据自身业务逻辑进行响应! 在正式实现用户与服务器之间的沟通前,我们需要进行一些知识储备和对信息的分类.

CMDB硬件信息管理系统开发(二)

完成任务: 1.网卡.内存资产变更数据及日志记录: 2.get请求获取今日未采集主机列表: 1 # -*- coding: utf-8 -*- 2 # __author__ = "maple" 3 from repository import models 4 5 6 class Nic: 7 def __init__(self, server_obj, info): 8 self.server_obj = server_obj 9 self.nic_dict = info 10 se

微信企业号第三方应用开发[三]——授权应用

创建应用后即可测试授权应用 点击“测试授权”  确认发起授权安装测试 登陆企业号  勾选需要授权的应用  对应用进行可见范围设置  授权成功后等待跳转即可  在企业号管理员确认授权后微信后台会向开发者后台推送消息,开发者后台必须根据“第三方回调协议——授权成功推送auth_code事件”规则响应推送. 使用方式为‘线上自助注册授权使用’的套件,从企业号第三方官网发起授权时,微信服务器会向应用提供商的套件事件接收 URL(创建套件时填写)推送授权成功通知:从应用提供商网站发起的应用套件授权流程,由

基于微信硬件公众平台的智能控制开发流程

一.微信硬件公众平台整体架构 上一篇<物联网架构场景技术分析>已经探讨和分析了物联网架构的演进,基于微信硬件公众平台的智能控制方案即属于文中的第三种架构--基于统一后台服务的物联架构.其中的架构如下: 各部分的角色和分工如下: 1.微信硬件公众号平台服务器,是物联网的基础和核心部分,其负责外设设备ID的认证,类似公安部给每个公民一个身份证一样,保证每个外设都有一个合法并且唯一的ID.目前微信平台的设备ID由两部分组成,一部分是厂商运维的公众号(即手机微信关注的公众号)的原始ID,称为设备类型,