Skip to content

Commit edf65b8

Browse files
committed
Changed Cosmos DB functionality
1 parent 77eb622 commit edf65b8

File tree

7 files changed

+29
-121
lines changed

7 files changed

+29
-121
lines changed

articles/iot-hub/iot-hub-how-to-order-connection-state-events.md

Lines changed: 29 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,18 @@ ms.author: asrastog
1212

1313
# Order device connection events from Azure IoT Hub using Azure Cosmos DB
1414

15-
Azure Event Grid helps you build event-based applications and easily integrate IoT events in your business solutions. This article walks you through a setup, which can be used to track and store the latest device connection state in Cosmos DB. We'll use the sequence number available in the Device Connected and Device Disconnected events and store the latest state in Cosmos DB. We're going to use a stored procedure, which is an application logic that is executed against a collection in Cosmos DB.
15+
[Azure Event Grid](/azure/event-grid/overview) helps you build event-based applications and easily integrates IoT events in your business solutions. This article walks you through a setup using Cosmos DB, Logic App, IoT Hub Events, and a simulated Raspberry Pi to track, collect, and store connection and disconnection events of a device.
1616

17-
The sequence number is a string representation of a hexadecimal number. You can use string compare to identify the larger number. If you're converting the string to hex, then the number will be a 256-bit number. The sequence number is strictly increasing, and the latest event will have a higher number than other events. This sequence is useful if you have frequent device connects and disconnects, and want to ensure only the latest event is used to trigger a downstream action, as Azure Event Grid doesn’t support ordering of events.
17+
From the moment your device runs, an order of operations activates:
18+
19+
1. The Pi device, using your IoT hub device key, is started and then stopped
20+
1. An IoT Hub event captures the device activity, then sends an HTTP request to your Logic App
21+
1. The Logic App processes the HTTP request with a condition you set (to track the connections and disconnections of your device)
22+
1. The Logic App tracks and stores the latest device connection state in Cosmos DB
23+
24+
A sequence number is used in the *Device Connected* and *Device Disconnected* to track and order events.
25+
26+
The sequence number is a string representation of a hexadecimal number. You can use a string comparison to identify the larger number. If you're converting the string to hexadecimal, then the number will be a 256-bit number. The sequence number is strictly increasing, and the latest event will have a higher number than past events. This sequence is useful if you have frequent device connects and disconnects, and want to ensure only the latest event is used to trigger a downstream action, as Azure Event Grid doesn't support the ordering of events.
1827

1928
## Prerequisites
2029

@@ -24,107 +33,6 @@ The sequence number is a string representation of a hexadecimal number. You can
2433

2534
* An IoT Hub in Azure. If you haven't created one yet, see [Get started with IoT Hub](../iot-develop/quickstart-send-telemetry-iot-hub.md?pivots=programming-language-csharp) for a walkthrough.
2635

27-
## Create a stored procedure
28-
29-
Let's create a stored procedure and configure it to compare sequence numbers of incoming events and to record the latest event per device in the database.
30-
31-
1. In your Cosmos DB SQL API, select **Data Explorer** > **Items** > **New Stored Procedure**.
32-
33-
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/create-stored-procedure.png" alt-text="Screenshot of how to create a new stored procedure in the Azure portal." lightbox="media/iot-hub-how-to-order-connection-state-events/create-stored-procedure.png":::
34-
35-
2. Enter **LatestDeviceConnectionState** for the stored procedure ID and paste the following in the **Stored Procedure body**. This code should replace any existing code in the stored procedure body. This code maintains one row per device ID and records the latest connection state of that device ID by identifying the highest sequence number.
36-
37-
```javascript
38-
// SAMPLE STORED PROCEDURE
39-
function UpdateDevice(deviceId, moduleId, hubName, connectionState, connectionStateUpdatedTime, sequenceNumber) {
40-
var collection = getContext().getCollection();
41-
var response = {};
42-
43-
var docLink = getDocumentLink(deviceId, moduleId);
44-
45-
var isAccepted = collection.readDocument(docLink, function(err, doc) {
46-
if (err) {
47-
console.log('Cannot find device ' + docLink + ' - ');
48-
createDocument();
49-
} else {
50-
console.log('Document Found - ');
51-
replaceDocument(doc);
52-
}
53-
});
54-
55-
function replaceDocument(document) {
56-
console.log(
57-
'Old Seq :' +
58-
document.sequenceNumber +
59-
' New Seq: ' +
60-
sequenceNumber +
61-
' - '
62-
);
63-
if (sequenceNumber > document.sequenceNumber) {
64-
document.connectionState = connectionState;
65-
document.connectionStateUpdatedTime = connectionStateUpdatedTime;
66-
document.sequenceNumber = sequenceNumber;
67-
68-
console.log('replace doc - ');
69-
70-
isAccepted = collection.replaceDocument(docLink, document, function(
71-
err,
72-
updated
73-
) {
74-
if (err) {
75-
getContext()
76-
.getResponse()
77-
.setBody(err);
78-
} else {
79-
getContext()
80-
.getResponse()
81-
.setBody(updated);
82-
}
83-
});
84-
} else {
85-
getContext()
86-
.getResponse()
87-
.setBody('Old Event - current: ' + document.sequenceNumber + ' Incoming: ' + sequenceNumber);
88-
}
89-
}
90-
function createDocument() {
91-
document = {
92-
id: deviceId + '-' + moduleId,
93-
deviceId: deviceId,
94-
moduleId: moduleId,
95-
hubName: hubName,
96-
connectionState: connectionState,
97-
connectionStateUpdatedTime: connectionStateUpdatedTime,
98-
sequenceNumber: sequenceNumber
99-
};
100-
console.log('Add new device - ' + collection.getAltLink());
101-
isAccepted = collection.createDocument(
102-
collection.getAltLink(),
103-
document,
104-
function(err, doc) {
105-
if (err) {
106-
getContext()
107-
.getResponse()
108-
.setBody(err);
109-
} else {
110-
getContext()
111-
.getResponse()
112-
.setBody(doc);
113-
}
114-
}
115-
);
116-
}
117-
118-
function getDocumentLink(deviceId, moduleId) {
119-
return collection.getAltLink() + '/docs/' + deviceId + '-' + moduleId;
120-
}
121-
}
122-
```
123-
124-
3. Save the stored procedure:
125-
126-
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/save-stored-procedure.png" alt-text="Screenshot of how to save a stored procedure in a Cosmos DB service in the Azure portal." lightbox="media/iot-hub-how-to-order-connection-state-events/save-stored-procedure.png":::
127-
12836
## Create a logic app
12937

13038
Let's create a logic app and add an Event Grid trigger that monitors the resource group for your virtual machine.
@@ -169,7 +77,9 @@ A trigger is a specific event that starts your logic app. For this tutorial, the
16977
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/sample-payload.png" alt-text="Screenshot of how to use a sample payload to generate a schema." lightbox="media/iot-hub-how-to-order-connection-state-events/sample-payload.png":::
17078

17179

172-
4. Paste the following sample JSON code into the text box, then select **Done**:
80+
4. Paste the following sample JSON code into the text box, then select **Done**.
81+
82+
This JSON is only used as a template, so the exact values aren't important.
17383

17484
```json
17585
[{
@@ -205,51 +115,49 @@ In your logic app workflow, conditions help run specific actions after passing t
205115

206116
1. Select inside the **Choose a value** box and a pop up appears, showing the **Dynamic content** — the fields that can be selected.
207117

208-
* Choose **eventType**. The popup closes and you see **Body** is placed in **Select an output from previous steps**, automatically. Select **Condition** to reopen it.
209-
* Change **is equal to** to **ends with**.
210-
* Type in **nected** as the value to end with. This is a search term that will include both "connected" and "disconnected" when parsed.
118+
* Choose **eventType**. The popup closes and you see **Body** is placed in **Select an output from previous steps**, automatically. Select **Condition** to reopen your conditional statement.
119+
* Keep the **is equal to** value.
120+
* Type in **Microsoft.Devices.DeviceConnected** as the last value of that row.
121+
* Select **+ Add** to add another row.
122+
* This second row is similar to the first row, except we look for disconnection events.
211123

212-
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/condition-detail.png" alt-text="Screenshot of the full For Each condition." lightbox="media/iot-hub-how-to-order-connection-state-events/condition-detail.png":::
124+
Use **eventType**, **is equal to**, and **Microsoft.Devices.DeviceDisconnected** for the row values.
125+
126+
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/condition-detail.jpg" alt-text="Screenshot of the full For Each condition." lightbox="media/iot-hub-how-to-order-connection-state-events/condition-detail.jpg":::
213127

214128
1. In the **if true** dialog, click on **Add an action**.
215129

216130
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/action-if-true.png" alt-text="Screenshot of the 'If true' box in Azure." lightbox="media/iot-hub-how-to-order-connection-state-events/action-if-true.png":::
217131

218-
1. Search for Cosmos DB and select **Azure Cosmos DB — Execute stored procedure (V2)**
132+
1. Search for Cosmos DB and select **Azure Cosmos DB — Execute stored procedure (V3)**
219133

220134
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/cosmosDB-search.png" alt-text="Screenshot of the search for Azure Cosmos DB." lightbox="media/iot-hub-how-to-order-connection-state-events/cosmosDB-search.png":::
221135

222136
1. Fill in **cosmosdb-connection** for the **Connection Name** and choose an [authentication type](/azure/connectors/connectors-create-api-cosmos-db?tabs=consumption.md#connect-to-azure-cosmos-db), then select **Create**.
223137

224-
1. You see the **Execute stored procedure (V2)** panel. Enter the values for the fields:
138+
1. You see the **Execute stored procedure (V3)** panel. Enter the values for the fields:
225139

226140
**Azure Cosmos DB account name**: {Add your account name}
227141

228142
**Database ID**: ToDoList
229143

230144
**Collection ID**: Items
231145

232-
**Sproc ID**: LatestDeviceConnectionState
233-
234-
1. For the final field, select **Add new parameter**. In the dropdown that appears, check the boxes next to **Partition key value** and **Parameters for the stored procedure**, then click anywhere else on the screen to process your entry; it adds a field for **Partition key value** and a field for **Parameters for the stored procedure**.
235-
236-
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/logicapp-stored-procedure.jpg" alt-text="Screenshot shows an Execute stored procedure (V2) item with 'Add new parameter' selected." lightbox="media/iot-hub-how-to-order-connection-state-events/logicapp-stored-procedure.jpg":::
237-
238-
1. Now enter the partition key value and parameters as shown. Add the dash, brackets, double-quotes, and commas around your values. You may have to select **Add dynamic content** to get these valid values.
146+
**Document**: Choose `Current item` from the dynamic content parameter list
239147

240-
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/logicapp-stored-procedure-2.jpg" alt-text="Screenshot shows an 'Execute stored procedure' item with parameters entered." lightbox="media/iot-hub-how-to-order-connection-state-events/logicapp-stored-procedure-2.jpg":::
148+
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/logic-app-create-or-update-doc.jpg" alt-text="Screenshot shows an Execute stored procedure (V3) item with 'Add new parameter' selected." lightbox="media/iot-hub-how-to-order-connection-state-events/logic-app-create-or-update-doc.jpg":::
241149

242150
1. Save your logic app.
243151

244152
### Copy the HTTP URL
245153

246154
Before you leave the Logic Apps Designer, copy the URL that your logic app is listening to for a trigger. You use this URL to configure Event Grid.
247155

248-
1. Expand the **When a HTTP request is received** trigger configuration box by clicking on it.
156+
1. Expand the **When a HTTP request is received** trigger configuration box by selecting it.
249157

250158
1. Copy the value of **HTTP POST URL** by selecting the copy button next to it.
251159

252-
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/copy-url.png" alt-text="Screenshot of where to find the HTTP URL to copy." lightbox="media/iot-hub-how-to-order-connection-state-events/copy-url.png":::
160+
:::image type="content" source="media/iot-hub-how-to-order-connection-state-events/copy-url.jpg" alt-text="Screenshot of where to find the HTTP URL to copy." lightbox="media/iot-hub-how-to-order-connection-state-events/copy-url.jpg":::
253161

254162
1. Save this URL so that you can use it in the next section.
255163

@@ -285,7 +193,7 @@ In this section, you configure your IoT Hub to publish events as they occur.
285193

286194
Select **Create** to save the event subscription.
287195

288-
## Observe events
196+
## Run device and observe events
289197

290198
Now that your event subscription is set up, let's test by connecting a device.
291199

30.2 KB
Loading
64.3 KB
Loading
12.1 KB
Loading
49.2 KB
Loading

0 commit comments

Comments
 (0)