开发者中心

应用程序开发

概述

在这一部分中, 我们接触一些使用QuarkIoEREST API开发应用程序的基本用例。通常情况下, 你需要:

注册资产

资产是你业务和应用程序聚焦的事物。例如, 如果你的业务是建筑管理或家庭自动化,资产可能是建筑和房间。如果你的业务是机器维护, 资产可能是路由器和机器。

资产和设备一起保存在设备清单中, 但它们通常有独立于设备的结构。通过发送POST请求在设备清单托管对象集合中创建资产。例如, 在设备清单中创建新房间:


    POST /inventory/managedObjects HTTP/1.1
    Content-Type: application/vnd.com.nsn.cumulocity.managedObject+json
    Accept: application/vnd.com.nsn.cumulocity.managedObject+json
    ...
{
    "name": "Building 043",
    "type": "c8y_Building"
}

    HTTP/1.1 201 Created
    Content-Type: application/vnd.com.nsn.cumulocity.managedObject+json;charset=UTF-8;ver=0.9
...
{
    "owner": "admin",
    "id": "2549800",
    "self": "http://.../inventory/managedObjects/2549800",
    "type": "c8y_Building",
    "lastUpdated": "2013-09-05T16:38:31.250+02:00",
    "name": "Building 043",
    "assetParents": {
    "references": [],
    "self": "https://.../inventory/managedObjects/2549800/assetParents"
},
    "childAssets": {
    "references": [],
    "self": "https://.../inventory/managedObjects/2549800/childAssets"
},
    "childDevices": {
    "references": [],
    "self": "https://.../inventory/managedObjects/2549800/childDevices"
},
    "deviceParents": {
    "references": [],
    "self": "https://.../inventory/managedObjects/2549800/deviceParents"
    }
}
                      

如果成功创建设备, 则返回201状态码。如果原始请求象例子中一样包含"Accept"头, 则返回完整对象, 包含ID和用于后续访问的指向此对象的URL。返回的对象还包括指向子设备子资产集合的引用,可以向设备添加子设备和子资产。

例如, 假设我们已经创建了一个房间, 房间的"self"属性是"https://inventory/managedObjects/2549700"。为连接此房间到建筑, 发送POST请求到建筑的子资产集合 (见上面"childAssets"的"self"属性):


    POST /inventory/managedObjects/2549800/childAssets HTTP/1.1
    Content-Type: application/vnd.com.nsn.cumulocity.managedObjectReference+json

    { "managedObject" : { "self" : "http://.../inventory/managedObjects/2549700" } } 

    HTTP/1.1 201 Created
                      

现在再次查询建筑显示房间已经注册为建筑的子资产:


    GET /inventory/managedObjects/2549800 HTTP/1.1

    HTTP/1.1 200 OK
    Content-Type: application/vnd.com.nsn.cumulocity.managedObject+json; charset=UTF-8; ver=0.9
    ...
    {
    "owner": "admin",
    "id": "2549800",
    "self": "http://.../inventory/managedObjects/2549800",
    ...
    "childAssets": {
    "references": [
    {
    "managedObject": {
    "id": "2549700",
    "name": "Room 042",
    "self": "https://.../inventory/managedObjects/2549700"
},
    "self": "https://.../inventory/managedObjects/2549800/childAssets/2549700"
}
],
    "self": "https://.../inventory/managedObjects/2549800/childAssets"
}
}
                      

连接设备到资产

就像连接资产到子资产, 可以连接资产到监控此资产的设备。例如, 假设房间安装了一个光线传感器。 发送POST请求到房间的"childDevices":


    POST /inventory/managedObjects/2549700/childDevices HTTP/1.1
    Content-Type: application/vnd.com.nsn.cumulocity.managedObjectReference+json

    { "managedObject" : { "self" : "https://.../inventory/managedObjects/2480500" } } 

    HTTP/1.1 201 Created
                      

和外部系统同步资产

通常, QuarkIoE不会是处理公司资产的唯一IT系统。技术过程上同步保存在外部IT系统中的资产和 注册设备的过程完全相同:

  • 使用身份识别API连接外部IT系统资产ID到QuarkIoE资产ID。
  • 使用设备清单API创建和更新QuarkIoE中基于外部系统数据的资产。

查询特定功能

为了从应用程序解耦特定类型设备的细节, 应用程序使用所谓的片段查询设备清单 (参见 "QuarkIoE领域模型"的片段部分)。例如, 要查找具有位置的所有托管对象, 使用


    GET /inventory/managedObjects?fragmentType=c8y_Position&withTotalPages=true HTTP/1.1

    HTTP/1.1 200 OK
    Content-Type: application/vnd.com.nsn.cumulocity.managedObjectCollection+json; charset=UTF-8; ver=0.9
    ...
    {
    "managedObjects": [
    {
    "id": "2480700",
    "lastUpdated": "2013-08-30T10:15:44.218+02:00",
    "name": "RaspPi BCM2708 0000000017b769d5 Gps eM9",
    "owner": "admin",
    "self": "https://.../inventory/managedObjects/2480700",
    "type": "c8y_TinkerForge_Gps",
    "c8y_Position": {
    "alt": 102.36,
    "lng": 6.769717,
    "lat": 51.267259
},
...
},
...
]
   "next": "https://.../inventory/managedObjects?withTotalPages=true&fragmentType=c8y_Position&pageSize=5&currentPage=2",
   "statistics": {
   "currentPage": 1,
   "pageSize": 5,
   "totalPages": 4
},
   "self": "https://.../inventory/managedObjects?withTotalPages=true&fragmentType=c8y_Position&pageSize=5&currentPage=1"
}
                        

现在, 你可以把对象放在地图中。标志片段定义在 设备管理库传感器库

查询"/platform" 资源的结果可以进一步查询数据 (参见 介绍)。

注意, 查询不一定一次返回全部查询结果, 而只是结果中的一"页"。关于分页的更多信息, 参见 查询结果分页。 可选参数"withTotalPages"可以让查询包含完整分页统计, 代价是轻微降低性能。

查询传感器读数

和设备清单类似, 可以查询特定传感器读数。例如, 我们查询过去一个月的光线测量值(从写这篇文章算起):


   GET /measurement/measurements?dateFrom=2013-08-05&dateTo=2013-09-05&fragmentType=c8y_LightMeasurement HTTP/1.1

    HTTP/1.1 200 OK
    Content-Type: application/vnd.com.nsn.cumulocity.measurementCollection+json; charset=UTF-8; ver=0.9
    ... 
    {
    "measurements": [
    {
    "id": "2480900",
    "self": "https://.../measurement/measurements/2480900",
    "source": {
    "id": "2480500",
    "self": "https://.../inventory/managedObjects/2480500"
},
    "time": "2013-08-29T21:19:52.321+02:00",
    "type": "c8y_LightMeasurement",
    "c8y_LightMeasurement": {
    "e": { "unit": "lux", "value": 169.2 }
}
},
...
]
...
}
                       

发送操作到设备

要在设备上触发操作, 用POST方式向 设备控制API发送操作。 下面的例子重启ID为"2480300"的设备(这是一个树莓派, 我们 前面集成的):


    POST /devicecontrol/operations HTTP/1.1
    Content-Type: application/vnd.com.nsn.cumulocity.operation+json;
    Accept: application/vnd.com.nsn.cumulocity.operation+json;
    ...
    {
    "deviceId": "2480300",
    "c8y_Restart":{}
}

    HTTP/1.1 201 Created
    Content-Type: application/vnd.com.nsn.cumulocity.operation+json; charset=UTF-8; ver=0.9
...
{
    "creationTime": "2013-09-05T19:18:16.117+02:00",
    "deviceId": "2480300",
    "id":"2550200", 
    "self": "https://.../devicecontrol/operations/2550200",
    "status": "PENDING",
    "c8y_Restart": {}
}
                      

队列中有这个设备的操作时POST命令立即返回。实际操作异步执行。由于我们在例子的请求中添加了可选的"Accept"头, 我们将在应答中得到完整的排队操作, 包括"self"属性中包含的URL。在URL上使用GET, 可以检查操作执行的当前状态:


    GET /devicecontrol/operations/2550200 HTTP/1.1

    HTTP/1.1 200 OK
    Content-Type: application/vnd.com.nsn.cumulocity.operation+json; charset=UTF-8; ver=0.9
    ...
    {
    "status": "PENDING",
    ...
}
                       

"PENDING"状态意味着设备还没有提取操作。 "EXECUTING"意味着操作在执行过程中。 最后, "SUCCESSFUL" 或 "FAILED" 表示操作已经完成。

监听事件

除了查询QuarkIoE数据存储, 还可以实时处理和接收事件 QuarkIoE中的实时处理。例如, 假设你想在地图上显示实时位置更新。 使用管理用户界 (或 REST API) 生成一个新的规则模块 "myRule":


   select * 
    from EventCreated e
    where e.event.type = "c8y_LocationUpdate";
                       

如果有一个发送位置更新的设备, 应该立即在用户界面中看到。要在自己的REST客户端接收它们, 使用 通知API 订阅。 此API基于Bayeux协议。 首先, 需要一个握手。握手告诉QuarkIoE客户端支持什么通知协议并为客户端分配客户端ID。


    POST /cep/notifications HTTP/1.1
    Content-Type: application/json
    ...
    [ {
    "id": "1",
    "supportedConnectionTypes": ["long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0"
} ]

HTTP/1.1 200 OK
...
[ {
    "id": "1",
    "supportedConnectionTypes": ["websocket","long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0",
    "clientId": "71fjkmy0495rxrkfcmp0mhcev1",
    "minimumVersion": "1.0",
    "successful": true
}]
                      

握手结束后, 客户端需要订阅以上规则的输出。这是通过使用模块名和语句名作为订阅通道发送POST请求来完成的。在我们的例子中, 我们使用模块名"myRule", 没有给"select"语句命名("@Name('')"), 所以订阅通道是"/myRule/*"。


    POST /cep/notifications HTTP/1.1
    Content-Type: application/json
    ...
    [ {
    "id": "2",
    "channel": "/meta/subscribe",
    "subscription": "/myRule/*",
    "clientId":"71fjkmy0495rxrkfcmp0mhcev1"
}]

HTTP/1.1 200 OK
...
[ { 
"id":"2",
"channel": "/meta/subscribe",
"subscription": "/myRule/*",
"successful": true,
} ]
                       

最后, 客户端连接并等待事件发送给它。


    POST /cep/notifications HTTP/1.1
    Content-Type: application/json
    ...
    [ {
    "id": "3",
    "connectionType": "long-polling",
    "channel": "/meta/connect",
    "clientId": "71fjkmy0495rxrkfcmp0mhcev1"
} ]
                        

此请求将挂起, 直到有一个操作发出。这是一个带有单一位置应答的例子:


    HTTP/1.1 200 OK
    ...
    [ 
    {
    "id": "139", 
    "data": {
    "creationTime": "2013-08-30T09:38:45.551+02:00",
    "id": "2481400",
    "self": "https://.../event/events/2481400",
    "source": {
    "id": "2480700",
    "name": "RaspPi BCM2708 0000000017b769d5 Gps eM9",
    "self": "https://.../inventory/managedObjects/2480700"
},
    "text": "Location updated",
    "time": "2013-08-29T21:20:01.671+02:00",
    "type": "c8y_LocationUpdate",
    "c8y_Position": {
    "alt": 58.34,
    "lng": 6.769717,
    "lat": 51.267259
},
    "channel": "/myRule/*"
}, {
    "id": "3",
    "successful": true,
    "channel": "/meta/connect"
}
]