{"id":2934,"date":"2020-05-19T15:40:00","date_gmt":"2020-05-19T13:40:00","guid":{"rendered":"https:\/\/www.basyskom.de\/?p=2934"},"modified":"2020-06-10T21:04:34","modified_gmt":"2020-06-10T19:04:34","slug":"consuming-protobuf-messages-via-azure-functions","status":"publish","type":"post","link":"https:\/\/www.basyskom.de\/en\/consuming-protobuf-messages-via-azure-functions\/","title":{"rendered":"How to consume Protobuf messages in Azure Functions (Part 3 of 4)"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"2934\" class=\"elementor elementor-2934\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-ffb8f03 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no\" data-id=\"ffb8f03\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d112d7d\" data-id=\"d112d7d\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-a4f3471 elementor-widget elementor-widget-text-editor\" data-id=\"a4f3471\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Introduction<\/h2><p>Now that the <a href=\"https:\/\/www.basyskom.de\/2020\/protobuf-for-iot\">Protobuf messages<\/a> of our IoT device has arrived at the IoT Hub, we have to consume the incoming messages. This could mean forwarding them to a processing system or storing them for later use.<\/p><p>For JSON or AVRO encoded data, we could directly route the messages into Azure Storage. To consume Protobuf encoded data, we have to execute custom code to perform the deserialization.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-cc25918 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no\" data-id=\"cc25918\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-162144c\" data-id=\"162144c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-316d9b3 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no\" data-id=\"316d9b3\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-2cd3374\" data-id=\"2cd3374\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-d85bf7f\" data-id=\"d85bf7f\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-ddbc201 elementor-view-default elementor-invisible elementor-widget elementor-widget-icon\" data-id=\"ddbc201\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;swing&quot;}\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"hm hm-key\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-cae4b59\" data-id=\"cae4b59\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-1621bd1 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no\" data-id=\"1621bd1\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-935c4b7\" data-id=\"935c4b7\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6b6f81d elementor-widget elementor-widget-text-editor\" data-id=\"6b6f81d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Azure Functions<\/h2><p><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/azure-functions\/functions-overview\" target=\"_blank\" rel=\"noopener\">Azure Functions<\/a> offer a way to execute custom functions in the Azure cloud.<\/p><p>Functions are invoked by a\u00a0<a style=\"background-color: #ffffff;\" href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/azure-functions\/functions-triggers-bindings\" target=\"_blank\" rel=\"noopener\">trigger or binding<\/a>, for a example a cron style timer, an HTTP request or an event like incoming data on other Azure services, for example ServiceBus Queues and Topics, Event Hubs or Event Grids.\u00a0<\/p><p>The functions can be hosted on Windows or Linux. Both platforms support a\u00a0<a style=\"background-color: #ffffff;\" href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/azure-functions\/supported-languages\" target=\"_blank\" rel=\"noopener\">wide range<\/a>\u00a0of programming languages like JavaScript, TypeScript, C#, F#, Java, Python and Powershell.<\/p><p>Depending on the selected\u00a0<a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/azure-functions\/functions-scale\" target=\"_blank\" rel=\"noopener\">service plan<\/a>, resources can be scaled out dynamically to handle an increased load and will be scaled in automatically if the load drops.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-b1d7fad elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no\" data-id=\"b1d7fad\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-683bcaa\" data-id=\"683bcaa\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-4e58632 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"4e58632\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"hm hm-ghost\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-dcc91f5 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no\" data-id=\"dcc91f5\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4c851e6\" data-id=\"4c851e6\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-92c7260 elementor-widget elementor-widget-text-editor\" data-id=\"92c7260\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Example<\/h2><p>To demonstrate how Protobuf messages received by an IoT Hub can be consumed, we will implement a simple Azure Function in JavaScript. It will decode the Protobuf messages and write the decoded data into an Azure Table Storage.<\/p><p>The full example code is hosted on\u00a0<a href=\"https:\/\/github.com\/basysKom\/iot_from_scratch\/tree\/master\/Part3_Azure_Functions_Consume_Protobuf\" target=\"_blank\" rel=\"noopener\">github<\/a>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-57b8735 elementor-widget elementor-widget-text-editor\" data-id=\"57b8735\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>External resources<\/h3>\n<ul>\n \t<li>An IoT Hub with at least one IoT device<\/li>\n \t<li>An Azure Storage account with two storage tables named <code>Sensordata<\/code> and <code>Events<\/code><\/li>\n \t<li>The example IoT device application from the\u00a0<a href=\"https:\/\/www.basyskom.de\/2020\/protobuf-for-iot\/\" target=\"_blank\" rel=\"noopener\">previous<\/a>\u00a0blog post<\/li>\n<\/ul>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4328377 elementor-widget elementor-widget-text-editor\" data-id=\"4328377\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>Node.js modules<\/h3><div>The handling code for our Protobuf messages is generated using protoc. It requires the&nbsp;<a href=\"https:\/\/www.npmjs.com\/package\/google-protobuf\" target=\"_blank\" rel=\"noopener\">google-protobuf<\/a>&nbsp;module.<\/div>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-993bfb2 elementor-widget elementor-widget-text-editor\" data-id=\"993bfb2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>Custom environment variables<\/h3>\n<ul style=\"font-size: 24px; background-color: #ffffff;\">\n \t<li style=\"font-size: 24px;\"><code>IOTHUB_CONNECTION_STRING<\/code> is the connection string for the EventHub compatible endpoint of your IoT Hub instance<\/li>\n \t<li style=\"font-size: 24px;\"><code>STORAGE_CONNECTION_STRING<\/code> is the connection string for the Azure Storage account where the two storage tables are located<\/li>\n<\/ul>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-de005a6 elementor-widget elementor-widget-text-editor\" data-id=\"de005a6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>Input and output bindings<\/h3><div><p>We use an <code>eventHubTrigger<\/code> input binding to have our function executed whenever there is a new message on the EventHub compatible endpoint of our IoT Hub. The binding is configured to combine multiple messages (if available) in one function invocation.<\/p><\/div><p>Two table storage output bindings are configured for the tables mentioned in the requirements.<\/p><p>Bindings are defined in a file named <code>function.json<\/code> which resides in the same directory as the function code. The property values can be environment variables which are initialized from the <code>App Settings<\/code> of the Function App the function is running in. In our example, the <code>connection<\/code> properties are configured that way.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c7416b4 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"c7416b4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-json'>{\n  &quot;bindings&quot;: [\n    {\n      &quot;type&quot;: &quot;eventHubTrigger&quot;,\n      &quot;name&quot;: &quot;IoTHubMessages&quot;,\n      &quot;direction&quot;: &quot;in&quot;,\n      &quot;eventHubName&quot;: &quot;samples-workitems&quot;,\n      &quot;connection&quot;: &quot;IOTHUB_CONNECTION_STRING&quot;,\n      &quot;cardinality&quot;: &quot;many&quot;,\n      &quot;consumerGroup&quot;: &quot;$Default&quot;,\n      &quot;dataType&quot;: &quot;binary&quot;\n    },\n    {\n      &quot;tableName&quot;: &quot;Sensordata&quot;,\n      &quot;connection&quot;: &quot;STORAGE_CONNECTION_STRING&quot;,\n      &quot;name&quot;: &quot;sensorDataTableBinding&quot;,\n      &quot;type&quot;: &quot;table&quot;,\n      &quot;direction&quot;: &quot;out&quot;\n    },\n    {\n      &quot;tableName&quot;: &quot;Events&quot;,\n      &quot;connection&quot;: &quot;STORAGE_CONNECTION_STRING&quot;,\n      &quot;name&quot;: &quot;eventsTableBinding&quot;,\n      &quot;type&quot;: &quot;table&quot;,\n      &quot;direction&quot;: &quot;out&quot;\n    }\n  ]\n}\n <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7f415f2 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"7f415f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"hm hm-ufo\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-22b1b87 elementor-widget elementor-widget-text-editor\" data-id=\"22b1b87\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>Code walkthrough<\/h3><div><p>First, we create two arrays for our output bindings. Their names must correspond to the names specified in the bindings and all values that have been pushed to these arrays will be processed after our custom code has finished executing.<\/p><p>The <code>IoTHubMessages<\/code> parameter corresponds to the name given in the input binding. It contains an array of raw messages that have been pushed to the IoT Hub by one or several different clients. In our case, this is Protobuf encoded data of the <code>DeviceMessages<\/code> type.<\/p><p>The serialized Protobuf data is now deserialized using the\u00a0code generated by protoc.<br \/>Information on the IoT Hub device that has sent the message is embedded in the <code>context<\/code> object. We extract the sender&#8217;s <code>device id<\/code> to use it as identifying information in our Table Storage entries.<\/p><p>As the <code>DeviceMessages<\/code> message can contain multiple telemetry messages from the same sender, an inner loop is required.<\/p><p>For each message, we prepare a Table Storage entry with the sender&#8217;s <code>device id<\/code> as the <code>partition key<\/code> and the message&#8217;s <code>unix timestamp<\/code> as the <code>row key<\/code>. In case of the <code>EnvironmentData<\/code> message, the <code>partition key<\/code> is extended with <code>'_environmentData'<\/code>. This allows distinguishing and querying more message types later if it should become necessary.<br \/>The <code>timestamp<\/code> field is converted to a <code>Date<\/code> object and added to the entry as a property named <code>sourceTimestamp<\/code>.<\/p><p>After preparing the Table Storage entry, the properties of the <code>Event<\/code> or <code>EnvironmentData<\/code> message are merged into the object which is then pushed to the corresponding output binding arrays.<\/p><p>When we have finished processing the data, <code>context.done()<\/code> is called to notify the function host of the successful function execution.<\/p><\/div>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b3f03cd elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"b3f03cd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-javascript'>const messages = require(&#039;..\/generated\/environment_iot_messages_pb&#039;)\n\nmodule.exports = function (context, IoTHubMessages) {\n\n    context.bindings.sensorDataTableBinding = []\n    context.bindings.eventsTableBinding = []\n\n    for (let i = 0; i &lt; IoTHubMessages.length; ++i) {\n        const deserializedMessage = new proto.iotexample.DeviceMessages.deserializeBinary(IoTHubMessages[i]);\n\n        const sender = context.bindingData.systemPropertiesArray[i][&#039;iothub-connection-device-id&#039;];\n\n        for (const message of deserializedMessage.getTelemetryMessagesList()) {\n            console.log(`Message from device ${sender}`);\n\n            let data = message.toObject();\n\n            const tableStorageEntry = {\n                PartitionKey: sender,\n                RowKey: data.timestamp,\n                sourceTimestamp: new Date(data.timestamp)\n            }\n\n            if (data.environmentData) {\n                tableStorageEntry.PartitionKey += &#039;_environmentData&#039;;\n                context.bindings.sensorDataTableBinding.push({...tableStorageEntry, ...data.environmentData});\n            } else if (data.event) {\n                context.bindings.eventsTableBinding.push({...tableStorageEntry, ...data.event});\n            }\n        }\n    }\n\n    context.done();\n}; <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-13c3402 elementor-widget elementor-widget-text-editor\" data-id=\"13c3402\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>Testing the example<\/h3>\nThe example can be deployed to an Azure Function App, but for learning purposes, it is also very handy to run the application locally using <a href=\"https:\/\/code.visualstudio.com\/\" target=\"_blank\" rel=\"noopener\">Visual Studio Code<\/a>. This requires a file named <code>local.settings.json<\/code> with the environment variables our Function App needs to run.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b7f0eee elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"b7f0eee\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-json'>{\n  &quot;IsEncrypted&quot;: false,\n  &quot;Values&quot;: {\n    &quot;AzureWebJobsStorage&quot;: &quot;Put your storage account connection string here&quot;,\n    &quot;FUNCTIONS_WORKER_RUNTIME&quot;: &quot;node&quot;,\n    &quot;FUNCTIONS_EXTENSION_VERSION&quot;: &quot;~3&quot;,\n    &quot;IOTHUB_CONNECTION_STRING&quot;: &quot;Put your IoT Hub connection string here&quot;,\n    &quot;STORAGE_CONNECTION_STRING&quot;: &quot;Put your storage account connection string here&quot;\n  }\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a0e56e8 elementor-widget elementor-widget-text-editor\" data-id=\"a0e56e8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Just press <code>F5<\/code> and the application should be launched.<\/p><p>If you run the Qt based example application in parallel, you should see the function being invoked and messages will start showing up in the storage tables.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-40c4aec elementor-widget elementor-widget-image\" data-id=\"40c4aec\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"507\" height=\"263\" src=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/05\/Spectacle.h28246.png\" class=\"attachment-large size-large wp-image-2974\" alt=\"basysKom, HMI Dienstleistung, Qt, Cloud, Azure\" srcset=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/05\/Spectacle.h28246.png 507w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2020\/05\/Spectacle.h28246-300x156.png 300w\" sizes=\"(max-width: 507px) 100vw, 507px\">\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4b628bc elementor-widget elementor-widget-text-editor\" data-id=\"4b628bc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tInstead of or in addition to writing the data into a storage table, the deserialized data could also be pushed to an <code>Event Hub<\/code> to feed <code>Azure Stream Analytics<\/code> or some other data processing system.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-0b00a9e elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no\" data-id=\"0b00a9e\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2cdba49\" data-id=\"2cdba49\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-d5596b9 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"d5596b9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"hm hm-beach-seat\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fe1cefb elementor-widget elementor-widget-text-editor\" data-id=\"fe1cefb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Conclusion<\/h2>\n<div>By combining the Azure IoT SDK, an IoT Hub and Azure Functions, it is possible to create an end to end prototype for getting sensor data into the cloud in just a few hours.<\/div>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>In the third part of our series, we show how Protobuf messages from the IoT Hub can be processed in Azure Functions.<\/p>","protected":false},"author":4,"featured_media":3026,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1,2,134,7],"tags":[139,216,137,138,135],"class_list":["post-2934","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-allgemein","category-blog","category-cloud","category-general","tag-azure","tag-azure-functions","tag-cloud","tag-iot-hub","tag-protobuf"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/2934","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/comments?post=2934"}],"version-history":[{"count":55,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/2934\/revisions"}],"predecessor-version":[{"id":3768,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/2934\/revisions\/3768"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/media\/3026"}],"wp:attachment":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/media?parent=2934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/categories?post=2934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/tags?post=2934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}