在前面随笔《基于华为物联网iot的应用开发 — 基于.net 的sdk封装》介绍过iot中应用侧sdk的封装,主要就是基于华为iot的应用侧封装,以便在应用系统中进行调用。应用侧sdk的封装是一切应用开发的基础,不过华为并没有提供对应.net的sdk封装,不过sdk都是基于web  api 的json数据进行交互,因此花了一点时间进行了华为.net 的sdk进行了全面封装,本篇随笔介绍如何基于封装好的iot 应用侧的sdk进行界面管理的开发,实现对iot业务数据的管理等。

1、应用侧sdk封装回顾

应用侧的开发接口一般云平台都会提供不同平台的sdk,如阿里云开源提供java sdk/c# sdk等;而华为则提供了java、php等sdk,没有包含.net 的sdk。华为物联网云的应用侧api接口包括:

 

基于对应应用侧api接口的定义,我们使用c#进行了对应接口的封装。

  包含了一个测试接口项目、一个sdk封装接口项目,以及一个订阅的消息推送接口的解析和处理,例如新增设备、设备信息变化、设备绑定激活等。

对于事件的通知,我们一般是在应用端被动的进行相应的处理,因此需要对它们的消息进行转换和处理。

类似在管理后台订阅这些事件,然后这些事件触发后会推送给应用服务器。

  

2、接口的测试使用

根据iot的应用侧api的定义,我们编写一个快速测试sdk工作情况的winform程序来测试,如获取授权信息,以及查询产品、注册设备、修改设备、获取设备状态和详细等等接口的正常与否,然后再在web应用中进行整合,这样可以减少返工调试的问题。

按照业务接口的归类测试,我们编写如下程序用来测试对应sdk接口。

 在使用sdk接口前,我们需要知道,华为iot的api接口,基本上全部需要证书的对接的,这个和我们开发微信api有所差异。例如,我们的winform测试程序,让它带有一个cert目录下的证书文件,这个证书文件可以在api的demo里面找到,或者在华为iot平台上下载。

 我们最终用到的是cert/outgoing.certwithkey.pkcs12这个证书文件。

 我们创建一个httprequest对象获取数据的时候,需要指定这个证书,如下所示。

helper.contenttype = "application/json";
helper.clientcertificates = new x509certificatecollection() { new x509certificate2(constants.certfilepath, constants.certpassword) };

其他部分就是对api接口封装的调用测试了。

如首先是授权的测试,用来获取accesstoken的,这个是调用其他接口的前提。

private void btnlogin_click(object sender, eventargs e)
{
    var result = basicapi.authentication();
    console.writeline(result != null ? "accesstoken:" + result.tojson() : "获取结果出错");

    if (result != null)
    {
        var refreshresult = basicapi.refreshtoken(result.refreshtoken);

        console.writeline(refreshresult != null ? "accesstoken:" + refreshresult.tojson() : "获取结果出错");
        this.accesstoken = refreshresult.accesstoken;//记录待用
    }
}

华为iot接口很多没有全部整合在一起,有的在https://support.huaweicloud.com/api-iot/iot_06_0003.html ,而有的则在, 就拿授权来说,还有另外一个版本的接口可以获取,两个接口获得的token都可以通用。

var url = constants.appbaseurl + "/iocm/app/sec/v1.1.0/login";
var url = constants.appbaseurl + "/api/v3.0/auth/tokens";

这两个地址都可以获取accesstoken,如设备创建,也是有多个接口,版本不同。

我们针对各个接口的封装,对相关接口进行测试,如基于产品、产品下面的列表等信息,可以在一个接口测试代码里面进行测试,如下所示。

        /// <summary>
        /// 产品相关接口测试
        /// </summary>
        private void btnproduct_click(object sender, eventargs e)
        {
            if (string.isnullorempty(accesstoken))
            {
                messageutil.showtips("请先鉴权获取accesstoken");
                return;
            }
            try
            {
                var productapi = new productapi();
                var deviceapi = new datacollectionapi();

                //查询产品列表
                var queryjson = new queryproductjson { ownerappid = constants.appid };
                var result = productapi.queryproduct(accesstoken, queryjson);
                console.writeline(result != null ? result.tojson() : "no result");

                if (result != null && result.products != null)
                {
                    //遍历产品,根据产品id获取产品信息
                    foreach (var p in result.products)
                    {
                        var detailresult = productapi.queryproduct(accesstoken, p.productid, constants.appid);
                        console.writeline(detailresult != null ? detailresult.tojson() : "no result");
                    }

                    //遍历产品下面的设备信息
                    foreach (var p in result.products)
                    {
                        var devicejson = new querydevicejson { ownerappid = constants.appid, productid = p.productid };
                        var deviceresult = deviceapi.batchquerydevice2(accesstoken, devicejson);
                        console.writeline(deviceresult != null ? deviceresult.tojson() : "no result");
                    }
                }
            }
            catch (exception ex)
            {
                messageutil.showerror(ex.message);
            }
        }

对于设备,产品、设备组,都属于设备的入口之一,因此设备组也是管理接口设备的一个类别,我们可以根据sdk对设备组接口进行测试,如下代码所示。

        /// <summary>
        /// 设备分组测试
        /// </summary>
        private void btndevicegroup_click(object sender, eventargs e)
        {
            if (string.isnullorempty(accesstoken))
            {
                messageutil.showtips("请先鉴权获取accesstoken");
                return;
            }

            try
            {
                //根据自己数据修改
                var deviceid = "64bf5869-b271-4007-8db8-fab185e19c10";
                var groupname = "testgroup";
                var groupapi = new devicegroupapi();
                var groupjson = new createdevicegroupjson()
                {
                    appid = constants.appid,
                    name = groupname,
                    description = "测试设备分组",
                    deviceids = { deviceid }
                };

                //创建设备组
                var result = groupapi.createdevicegroup(accesstoken, groupjson);
                console.writeline(result != null ? result.tojson() : "no result");

                //查询设备组
                var queryjson = new querydevicegroupjson()
                {
                    accessappid = constants.appid,
                    name = groupname
                };
                var queryresult = groupapi.querydevicegroup(accesstoken, queryjson);
                console.writeline(queryresult != null ? queryresult.tojson() : "no result");

                //查询设备组成员
                if (queryresult != null && queryresult.list != null)
                {
                    foreach (var group in queryresult.list)
                    {
                        //设备明细
                        var groupresult = groupapi.getdevicegroup(accesstoken, group.id, constants.appid);
                        console.writeline(groupresult != null ? groupresult.tojson() : "no result");

                        //设备组成员
                        var querymemberjson = new querydevicegroupmemberjson()
                        {
                            appid = constants.appid,
                            devgroupid = group.id
                        };
                        var querymemberresult = groupapi.querydevicegroupmember(accesstoken, querymemberjson);
                        console.writeline(querymemberresult != null ? querymemberresult.tojson() : "no result");
                    }
                }
            }
            catch (exception ex)
            {
                messageutil.showerror(ex.message);
            }
        }

 

3、iot业务界面管理开发

当我们把大多数接口都跑一遍,并解决相关问题后,我们就可以根据这些接口进行web应用的开发了。

为了方便,我们把iot相关的业务,定义在一个控制器里面,方便管理,以后如果有需要,可以拆分进行管理。

 例如,对于数据提供,主要就是分页json数据的处理,方便界面控件通过ajax进行获取数据显示。

例如,对于产品列表,我们构建了一个控制器方法,如下所示。

        /// <summary>
        /// 根据条件查询产品列表,并返回对象集合(用于分页数据显示)
        /// </summary>
        /// <returns>指定对象的集合</returns>
        public virtual actionresult findproductwithpager()
        {
            var pagerinfo = getpagerinfo();
            var sort = getsortorder();
            var accesstoken = getaccesstoken();

            var queryjson = new queryproductjson(pagerinfo) { ownerappid = constants.appid };
            var result = productapi.queryproduct(accesstoken, queryjson);

            var list = result != null ? result.products : null;
            var totalcount = result != null ? result.totalcount : 0;

            //json格式的要求{total:22,rows:{}}
            var jsonresult = new { total = totalcount, rows = list };
            return tojsoncontent(jsonresult);
        }

其他,如设备组、设备列表等类似的处理,都是先通过接口获取数据,然后组装为对应的json格式提供给视图即可。

 有时候,除了列表展示外,我们可能还需要对视图中创建、删除、获取单个明细的接口进行处理,如下所示是设备分组的管理接口。

 其他的业务对象也是类似的封装,有了这些接口,我们就可以处理分页、获取详细、编辑、删除等接口的处理了。

在web应用中定义几个业务菜单,用来管理产品信息、设备组和设备信息。

  产品管理界面如下所示。

如果我们要查看产品明细,调用对应接口进行展示即可。

包含设备列表,我们根据产品id获取对应设备列表返回到界面进行展示即可,如下所示效果。

 设备分组如下所示。

 而设备列表展示可以通过产品和设备组进行限定查询,我们如下管理这个设备列表的展示的。

 同样,设备详细信息,通过对应id调用sdk接口获取数据,并返回到视图即可展示出来了。设备的相关信息,如下历史数据、历史命令等,我们也可以通过对应接口进行数据获取返回,在界面的tab控件进行展示即可。

 如设备历史命令,可以获取到相关历史命令信息。

 以上就是对iot应用侧api接口的封装和应用界面的管理开发,不过使用过程中,对于iot的接口还是不够完善,希望华为在这方便能够继续完善和提供良好的开发人员支持,我们也继续关注,以便在后续项目中整合物联网的硬件设备进行使用。