|
| 1 | +--- |
| 2 | +title: Use the REST API to query devices in Azure IoT Central |
| 3 | +description: How to use the IoT Central REST API to query devices in an application |
| 4 | +author: dominicbetts |
| 5 | +ms.author: dobett |
| 6 | +ms.date: 10/12/2021 |
| 7 | +ms.topic: how-to |
| 8 | +ms.service: iot-central |
| 9 | +services: iot-central |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +# How to use the IoT Central REST API to query devices |
| 14 | + |
| 15 | +The IoT Central REST API lets you develop client applications that integrate with IoT Central applications. You can use the REST API to query devices in your IoT Central application. The following are examples of how you can use the query REST API: |
| 16 | + |
| 17 | +- Get the last 10 telemetry values reported by a device. |
| 18 | +- Get the last 24 hours of data from devices that are in the same room. Room is a device or cloud property. |
| 19 | +- Find all devices that are in an error state and have outdated firmware. |
| 20 | +- Telemetry trends from devices, averaged in 10-minute windows. |
| 21 | +- Get the current firmware version of all your thermostat devices. |
| 22 | + |
| 23 | +This article describes how to use the `/query` API to query devices. |
| 24 | + |
| 25 | +A device can group the properties, telemetry, and commands it supports into _components_ and _modules_. |
| 26 | + |
| 27 | +Every IoT Central REST API call requires an authorization header. To learn more, see [How to authenticate and authorize IoT Central REST API calls](howto-authorize-rest-api.md). |
| 28 | + |
| 29 | +For the reference documentation for the IoT Central REST API, see [Azure IoT Central REST API reference](/rest/api/iotcentral/). |
| 30 | + |
| 31 | +## Run a query |
| 32 | + |
| 33 | +Use the following request to run a query: |
| 34 | + |
| 35 | +```http |
| 36 | +POST https://{your app subdomain}.azureiotcentral.com/api/query?api-version=1.1-preview |
| 37 | +``` |
| 38 | + |
| 39 | +The query is in the request body and looks like the following example: |
| 40 | + |
| 41 | +```json |
| 42 | +{ |
| 43 | + "query": "SELECT $id, $ts, temperature, humidity FROM urn:modelDefinition:fupmoiu28b:ymju9efv9 WHERE WITHIN_WINDOW(P1D)" |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +The `urn:modelDefinition:fupmoiu28b:ymju9efv9` value in the `FROM` clause is a *device template ID*. To find a device template ID, navigate to the **Devices** page in your IoT Central application and hover over a device that uses the template. The card includes the device template ID: |
| 48 | + |
| 49 | +:::image type="content" source="media/howto-query-with-rest-api/show-device-template-id.png" alt-text="Screenshot that shows how to find the device template ID in the page URL."::: |
| 50 | + |
| 51 | +The response to this request looks like the following example: |
| 52 | + |
| 53 | +```json |
| 54 | +{ |
| 55 | + "results": [ |
| 56 | + { |
| 57 | + "$id": "sample-003", |
| 58 | + "$ts": "2021-09-10T12:59:52.015Z", |
| 59 | + "temperature": 47.632160152311016, |
| 60 | + "humidity": 49.726422005390816 |
| 61 | + }, |
| 62 | + { |
| 63 | + "$id": "sample-001", |
| 64 | + "$ts": "2021-09-10T13:01:34.286Z", |
| 65 | + "temperature": 58.898120617808495, |
| 66 | + "humidity": 44.66125772328022 |
| 67 | + }, |
| 68 | + { |
| 69 | + "$id": "sample-001", |
| 70 | + "$ts": "2021-09-10T13:04:04.96Z", |
| 71 | + "temperature": 52.79601469228174, |
| 72 | + "humidity": 71.5067230188416 |
| 73 | + }, |
| 74 | + { |
| 75 | + "$id": "sample-002", |
| 76 | + "$ts": "2021-09-10T13:04:36.877Z", |
| 77 | + "temperature": 49.610062789623264, |
| 78 | + "humidity": 52.78538601804491 |
| 79 | + } |
| 80 | + ] |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +## Syntax |
| 85 | + |
| 86 | +The query syntax is similar to SQL syntax and is made up of the following clauses: |
| 87 | + |
| 88 | +- `SELECT` is required and defines the data you want to retrieve, such as the device telemetry values. |
| 89 | +- `FROM` is required and identifies the device type you're querying. This clause specifies the device template ID. |
| 90 | +- `WHERE` is optional and lets you filter the results. |
| 91 | +- `ORDER BY` is optional and lets you sort the results. |
| 92 | +- `GROUP BY` is optional and lets you aggregate results. |
| 93 | + |
| 94 | +The following sections describe these clauses in more detail. |
| 95 | + |
| 96 | +## SELECT clause |
| 97 | + |
| 98 | +The `SELECT` clause lists the data values to include in the query output and can include the following items: |
| 99 | + |
| 100 | +- Telemetry. Use the telemetry names from the device template. |
| 101 | +- Reported properties. Use the property names from the device template. |
| 102 | +- Cloud properties. Use the cloud property names from the device template. |
| 103 | +- `$id`. The device ID. |
| 104 | +- `$provisioned`. A boolean value that shows if the device is provisioned yet. |
| 105 | +- `$simulated`. A boolean value that shows if the device is a simulated device. |
| 106 | +- `$ts`. The timestamp associated with a telemetry value. |
| 107 | + |
| 108 | +If your device template uses components such as the **Device information** component, then you reference telemetry or properties defined in the component as follows: |
| 109 | + |
| 110 | +```json |
| 111 | +{ |
| 112 | + "query": "SELECT deviceInformation.model, deviceInformation.swVersion FROM urn:modelDefinition:fupmoiu28b:ymju9efv9" |
| 113 | +} |
| 114 | +``` |
| 115 | + |
| 116 | +You can find the component name in the device template: |
| 117 | + |
| 118 | +:::image type="content" source="media/howto-query-with-rest-api/show-component-name.png" alt-text="Screenshot that shows how to find the component name."::: |
| 119 | + |
| 120 | +The following limits apply in the `SELECT` clause: |
| 121 | + |
| 122 | +- There's no wildcard operator. |
| 123 | +- You can't have more than 15 items in the select list. |
| 124 | +- In a single query, you either select telemetry or properties but not both. A property query can include both reported properties and cloud properties. |
| 125 | + |
| 126 | +### Aliases |
| 127 | + |
| 128 | +Use the `AS` keyword to define an alias for an item in the `SELECT` clause. The alias is used in the query output. You can also use it elsewhere in the query. For example: |
| 129 | + |
| 130 | +```json |
| 131 | +{ |
| 132 | + "query": "SELECT $id as ID, $ts as timestamp, temperature as t, pressure as p FROM urn:modelDefinition:fupmoiu28b:ymju9efv9 WHERE WITHIN_WINDOW(P1D) AND t > 0 AND p > 50" |
| 133 | +} |
| 134 | +``` |
| 135 | + |
| 136 | +> [!TIP] |
| 137 | +> You can't use another item in the select list as an alias. For example, the following isn't allowed `SELECT id, temp AS id...`. |
| 138 | +
|
| 139 | +The result looks like the following output: |
| 140 | + |
| 141 | +```json |
| 142 | +{ |
| 143 | + "results": [ |
| 144 | + { |
| 145 | + "ID": "sample-002", |
| 146 | + "timestamp": "2021-09-10T11:40:29.188Z", |
| 147 | + "t": 40.20355053736378, |
| 148 | + "p": 79.26806508746755 |
| 149 | + }, |
| 150 | + { |
| 151 | + "ID": "sample-001", |
| 152 | + "timestamp": "2021-09-10T11:43:42.61Z", |
| 153 | + "t": 68.03536237975348, |
| 154 | + "p": 58.33517075380311 |
| 155 | + } |
| 156 | + ] |
| 157 | +} |
| 158 | +``` |
| 159 | + |
| 160 | +### TOP |
| 161 | + |
| 162 | +Use the `TOP` to limit the number of results the query returns. For example, the following query returns the first 10 results: |
| 163 | + |
| 164 | +```json |
| 165 | +{ |
| 166 | + "query": "SELECT TOP 10 $id as ID, $ts as timestamp, temperature, humidity FROM urn:modelDefinition:fupmoiu28b:ymju9efv9" |
| 167 | +} |
| 168 | +``` |
| 169 | + |
| 170 | +If you don't use `TOP`, the query returns a maximum of 10,000 results. |
| 171 | + |
| 172 | +To sort the results before `TOP` limits the number of results, use [ORDER BY](#order-by-clause). |
| 173 | + |
| 174 | +## FROM clause |
| 175 | + |
| 176 | +The `FROM` clause must contain a device template ID. The `FROM` clause specifies the type of device you're querying. |
| 177 | + |
| 178 | +To find a device template ID, navigate to the **Devices** page in your IoT Central application and hover over a device that uses the template. The card includes the device template ID: |
| 179 | + |
| 180 | +:::image type="content" source="media/howto-query-with-rest-api/show-device-template-id.png" alt-text="Screenshot that shows how to find the device template ID in the page URL."::: |
| 181 | + |
| 182 | +You can also use the [Devices - Get](/rest/api/iotcentral/1.1-previewdataplane/devices/get) REST API call to get the device template ID for a device. |
| 183 | + |
| 184 | +## WHERE clause |
| 185 | + |
| 186 | +The `WHERE` clause lets you use values and time windows to filter the results: |
| 187 | + |
| 188 | +### Time windows |
| 189 | + |
| 190 | +To get telemetry received by your application within a specified time window, use `WITHIN_WINDOW` as part of the `WHERE` clause. For example, to retrieve temperature and humidity telemetry for the last day use the following query: |
| 191 | + |
| 192 | +```json |
| 193 | +{ |
| 194 | + "query": "SELECT $id, $ts, temperature, humidity FROM urn:modelDefinition:fupmoiu28b:ymju9efv9 WHERE WITHIN_WINDOW(P1D)" |
| 195 | +} |
| 196 | +``` |
| 197 | + |
| 198 | +The time window value uses the [ISO 8601 durations format](https://en.wikipedia.org/wiki/ISO_8601#Durations). The following table includes some examples: |
| 199 | + |
| 200 | +| Example | Description | |
| 201 | +| ------- | -------------------------- | |
| 202 | +| PT10M | Past 10 minutes | |
| 203 | +| P1D | Past day | |
| 204 | +| P2DT12H | Past 2 days and 12 hours | |
| 205 | +| P1W | Past week | |
| 206 | +| PT5H | Past five hours | |
| 207 | +| '2021-06-13T13:00:00Z/2021-06-13T15:30:00Z' | Specific time range | |
| 208 | + |
| 209 | +> [!NOTE] |
| 210 | +> You can only use time windows when you're querying for telemetry. |
| 211 | +
|
| 212 | +### Value comparisons |
| 213 | + |
| 214 | +You can get telemetry or property values based on specific values. For example, the following query returns all messages where the temperature is greater than zero, the pressure is greater than 50, and the device ID is one of **sample-002** and **sample-003**: |
| 215 | + |
| 216 | +```json |
| 217 | +{ |
| 218 | + "query": "SELECT $id, $ts, temperature AS t, pressure AS p FROM urn:modelDefinition:fupmoiu28b:ymju9efv9 WHERE WITHIN_WINDOW(P1D) AND t > 0 AND p > 50 AND $id IN ['sample-002', 'sample-003']" |
| 219 | +} |
| 220 | +``` |
| 221 | + |
| 222 | +The following operators are supported: |
| 223 | + |
| 224 | +- Logical operators `AND` and `OR`. |
| 225 | +- Comparison operators `=`, `!=`, `>`, `<`, `>=`, `<=`, `<>`, and `IN`. |
| 226 | + |
| 227 | +> [!NOTE] |
| 228 | +> The `IN` operator only works with telemetry and `$id`. |
| 229 | +
|
| 230 | +The following limits apply in the `WHERE` clause: |
| 231 | + |
| 232 | +- You can use a maximum of 10 operators in a single query. |
| 233 | +- In a telemetry query, the `WHERE` clause can only contain telemetry and device metadata filters. |
| 234 | +- In a property query, the `WHERE` clause can only contain reported properties, cloud properties, and device metadata filters. |
| 235 | + |
| 236 | +## Aggregations and GROUP BY clause |
| 237 | + |
| 238 | +Aggregation functions let you calculate values such as average, maximum, and minimum on telemetry data within a time window. For example, the following query calculates average temperature and humidity from device `sample-001` in 10-minute windows: |
| 239 | + |
| 240 | +```json |
| 241 | +{ |
| 242 | + "query": "SELECT AVG(temperature), AVG(pressure) FROM urn:modelDefinition:fupmoiu28b:ymju9efv9 WHERE WITHIN_WINDOW(P1D) AND $id='{{DEVICE_ID}}' GROUP BY WINDOW(PT10M)" |
| 243 | +} |
| 244 | +``` |
| 245 | + |
| 246 | +The results look like the following output: |
| 247 | + |
| 248 | +```json |
| 249 | +{ |
| 250 | + "results": [ |
| 251 | + { |
| 252 | + "$ts": "2021-09-14T11:40:00Z", |
| 253 | + "avg_temperature": 49.212146114456104, |
| 254 | + "avg_pressure": 48.590304135023764 |
| 255 | + }, |
| 256 | + { |
| 257 | + "$ts": "2021-09-14T11:30:00Z", |
| 258 | + "avg_temperature": 52.44844454703927, |
| 259 | + "avg_pressure": 52.25973211022142 |
| 260 | + }, |
| 261 | + { |
| 262 | + "$ts": "2021-09-14T11:20:00Z", |
| 263 | + "avg_temperature": 50.14626272506926, |
| 264 | + "avg_pressure": 48.98400386898757 |
| 265 | + } |
| 266 | + ] |
| 267 | +} |
| 268 | +``` |
| 269 | + |
| 270 | +The following aggregation functions are supported: `SUM`, `MAX`, `MIN`, `COUNT`, `AVG`, `FIRST`, and `LAST`. |
| 271 | + |
| 272 | +Use `GROUP BY WINDOW` to specify the window size. If you don't use `GROUP BY WINDOW`, the query aggregates the telemetry over the last 30 days. |
| 273 | + |
| 274 | +> [!NOTE] |
| 275 | +> You can only aggregate telemetry values. |
| 276 | +
|
| 277 | +## ORDER BY clause |
| 278 | + |
| 279 | +The `ORDER BY` clause lets you sort the query results by a telemetry value, the timestamp, or the device ID. You can sort in ascending or descending order. For example, the following query returns the most recent results first: |
| 280 | + |
| 281 | +```json |
| 282 | +{ |
| 283 | + "query": "SELECT $id as ID, $ts as timestamp, temperature, humidity FROM urn:modelDefinition:fupmoiu28b:ymju9efv9 ORDER BY timestamp DESC" |
| 284 | +} |
| 285 | +``` |
| 286 | + |
| 287 | +> [!TIP] |
| 288 | +> Combine `ORDER BY` with `TOP` to limit the number of results the query returns after sorting. |
| 289 | +
|
| 290 | +## Limits |
| 291 | + |
| 292 | +The current limits for queries are: |
| 293 | + |
| 294 | +- No more than 15 items in the `SELECT` clause list. |
| 295 | +- No more than 10 logical operations in the `WHERE` clause. |
| 296 | +- Queries return a maximum of 10,000 records. |
| 297 | +- The maximum length of a query string is 350 characters. |
| 298 | +- You can't use the wildcard (`*`) in the `SELECT` clause list. |
| 299 | + |
| 300 | +## Next steps |
| 301 | + |
| 302 | +Now that you've learned how to query devices with the REST API, a suggested next step is to learn [How to use the IoT Central REST API to manage users and roles](howto-manage-users-roles-with-rest-api.md). |
0 commit comments