%3CLINGO-SUB%20id%3D%22lingo-sub-2095138%22%20slang%3D%22en-US%22%3EAzure%20Data%20Explorer%20Dashboards%20for%20IoT%20Data%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2095138%22%20slang%3D%22en-US%22%3E%3CH3%20id%3D%22toc-hId-1948888828%22%20id%3D%22toc-hId-1948888858%22%20id%3D%22toc-hId-1948888858%22%20id%3D%22toc-hId-1948888858%22%3E%3CSTRONG%3ECreate%20Azure%3C%2FSTRONG%3E%3CSTRONG%3E%20Data%20Explorer%20Dashboards%20%3C%2FSTRONG%3E%3CSTRONG%3Efor%20IoT%20Data%20and%20Alarm%20Visualisation%3C%2FSTRONG%3E%3C%2FH3%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EWe%20show%20how%20to%20configure%20simple%20but%20effective%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Data%20Explorer%3C%2FA%3E%20(ADX)%20dashboards%20on%20streaming%20data%20ingested%20from%20Azure%20IoT%20Hub%20with%20the%20aim%20of%20creating%20visual%20indication%20of%20alarm%20conditions%20(e.g.%20temperature%20exceeding%20a%20threshold).%26nbsp%3B%20ADX%20is%20a%20natural%20destination%20for%20IoT%20data%20as%20it%20provides%20managed%20ingestion%20from%20IoT%20Hub%20and%20advanced%20analytics%2Fad-hoc%20queries%20on%20the%20ingested%20data.%20Recently%2C%20the%20ADX%20team%20has%20added%20a%20powerful%20dashboarding%20feature%20that%20allows%20the%20mapping%20of%20ADX%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fkusto%2Fquery%2F%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EKusto%20Query%20Language%3C%2FA%3E%20(KQL)%20queries%20into%20dashboards%20within%20the%20ADX%20Web%20UI.%26nbsp%3B%20The%20native%20dashboards%20allow%20the%20user%20to%20seamlessly%20export%20queries%20from%20the%20Web%20UI%2C%20optimise%20dashboard%20rendering%20performance%20and%20provides%20auto%20refresh%20capability%20for%20near%20real-time%20visualisation%20experience.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EThe%20starting%20point%20is%20having%20an%20IoT%20Hub%20with%20sensors%20transmitting%20data%20to%20its%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fiot-hub%2Fiot-hub-devguide-messaging%23sending-device-to-cloud-messages-to-iot-hub%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Edevice%20to%20cloud%20endpoint%3C%2FA%3E.%20Once%20data%20starts%20flowing%20into%20the%20IoT%20Hub%2C%20start%20configuring%20the%20ingestion%20into%20an%20ADX%20table%20and%20building%20the%20dashboards%20using%20the%20typical%20end%20to%20end%20scenario%20in%20the%20following%20steps%3A%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%3E%0A%3CLI%3ECreate%20an%20ADX%20cluster%20by%20following%20the%20steps%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fcreate-cluster-database-portal%23create-a-cluster%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3Ehere%3C%2FA%3E.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%222%22%3E%0A%3CLI%3EEnable%20streaming%20ingestion%20on%20the%20ADX%20cluster%20as%20explained%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fingest-data-streaming%23enable-streaming-ingestion-on-your-cluster%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehere%3C%2FA%3E.%20Streaming%20ingestion%20is%20a%20powerful%20feature%20in%20situations%20where%20low%20latency%20between%20ingestion%20and%20query%20is%20needed%20as%20is%20typical%20for%20IoT%20scenarios.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%223%22%3E%0A%3CLI%3ECreate%20an%20ADX%20database%20by%20following%20the%20steps%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fcreate-cluster-database-portal%23create-a-database%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehere%3C%2FA%3E.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3EFor%20the%20remaining%20steps%20use%20the%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fweb-query-data%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EADX%20web%20interface%3C%2FA%3E%20to%20run%20the%20necessary%20queries%20and%20view%20the%20dashboards.%20Add%20the%20ADX%20cluster%20to%20the%20web%20interface%20as%20explained%20in%20the%20previous%20link.%20One%20of%20the%20great%20features%20of%20the%20ADX%20Web%20UI%20is%20that%20it%20can%20be%20hosted%20by%20other%20web%20portals%20as%20an%20HTML%20iframe.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%224%22%3E%0A%3CLI%3ECreate%20a%20table%20in%20ADX%20to%20put%20the%20ingested%20data%20in.%26nbsp%3B%20In%20this%20example%20a%20simple%20message%20json%20structure%20is%20used%20with%20many%20sensors%20identified%20by%20%E2%80%9CsensorName%E2%80%9D%2C%20where%2C%20for%20example%2C%20%E2%80%9Csensor1%E2%80%9D%20carries%20Temperature%20values%3A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-json%22%3E%3CCODE%3E%7B%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%22sensorName%22%3A%20%22sensor1%22%2C%0A%20%20%20%20%22SensorReading%22%3A%2021.171%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3EThe%20following%20ADX%20query%20creates%20a%20table%20%E2%80%98iot_parsed%E2%80%99%20with%20three%20columns.%20Note%20that%20since%20the%20message%20does%20not%20carry%20a%20timestamp%2C%20the%20'iothub-enqueuedtime'%20property%2C%20which%20is%20generated%20by%20the%20IoT%20Hub%2C%20is%20used%20for%20that%20purpose%3A%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3E.create%20table%20iot_parsed%20(Timestamp%3A%20datetime%2C%20Sensor%3A%20string%2C%20Value%3A%20real)%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3EAdd%20a%20json%20ingestion%20mapping%20to%20instruct%20the%20ADX%20cluster%20to%20place%20the%20message%20components%20in%20the%20correct%20table%20columns%3A%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3E.create%20table%20%5B'iot_parsed'%5D%20ingestion%20json%20mapping%0A'iot_parsed_mapping'%20'%5B%7B%22column%22%3A%22Timestamp%22%2C%22path%22%3A%22%24.iothub-enqueuedtime%22%2C%22datatype%22%3A%22datetime%22%7D%2C%7B%22column%22%3A%22Sensor%22%2C%22path%22%3A%22%24.sensorName%22%2C%22datatype%22%3A%22string%22%7D%2C%7B%22column%22%3A%22Value%22%2C%22path%22%3A%22%24.SensorReading%22%2C%22datatype%22%3A%22real%22%7D%2C%5D'%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fkusto%2Fmanagement%2Fmappings%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EThis%20link%3C%2FA%3E%20provides%20more%20information%20on%20ingestion%20mapping%20in%20ADX.%20The%20table%20is%20now%20ready%20to%20receive%20data%20from%20the%20IoT%20Hub.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%225%22%3E%0A%3CLI%3ENext%20use%20the%20instructions%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fingest-data-iot-hub%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehere%3C%2FA%3E%20to%20connect%20the%20IoT%20Hub%20to%20the%20ADX%20cluster%20and%20start%20ingesting%20the%20data%20into%20the%20staging%20table.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%226%22%3E%0A%3CLI%3EOnce%20the%20connection%20is%20verified%2C%20data%20will%20start%20flowing%20to%20the%20table.%20Use%20the%20following%20query%20in%20the%20ADX%20Web%20UI%20to%20examine%20a%20data%20sample%20of%2010%20rows%3A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Eiot%20_parsed%0A%7C%20take%2010%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20align%3D%22center%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-center%22%20image-alt%3D%22Picture1-1.png%22%20style%3D%22width%3A%20537px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249464i6812EE9DD3AE61D4%2Fimage-dimensions%2F537x407%3Fv%3D1.0%22%20width%3D%22537%22%20height%3D%22407%22%20role%3D%22button%22%20title%3D%22Picture1-1.png%22%20alt%3D%22Picture1-1.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3EIt%20is%20important%20to%20note%20at%20this%20point%20that%20since%20a%20very%20simple%20telemetry%20message%20structure%20is%20used%20in%20this%20example%2C%20it%20is%20straightforward%20to%20create%20a%20table%20with%20a%20specific%20schema%20to%20ingest%20the%20data%20directly%20from%20the%20IoT%20Hub.%26nbsp%3B%20In%20scenarios%20where%20the%20message%20structure%20is%20more%20complex%2C%20and%20probably%20variable%20over%20time%2C%20it%20is%20good%20practice%20to%20first%20ingest%20the%20data%20into%20a%20staging%20table%20with%20one%20%E2%80%98%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fkusto%2Fquery%2Fscalar-data-types%2Fdynamic%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Edynamic%E2%80%99%3C%2FA%3E%20column.%20The%20staging%20table%20can%20then%20be%20processed%20into%20other%20tables%20each%20of%20which%20with%20a%20specific%20schema%20to%20serve%20different%20analytics%20use-cases.%20This%20processing%20can%20be%20carried%20out%20as%20new%20data%20arrives%20in%20the%20staging%20table%20using%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fkusto%2Fmanagement%2Fupdatepolicy%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Eupdate%20policies%3C%2FA%3E.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%227%22%3E%0A%3CLI%3ENow%20that%20the%20data%20is%20streamed%20regularly%20into%20the%20table%2C%20start%20building%20dashboards%20to%20display%20the%20data%20and%20to%20indicate%20alarm%20conditions%20in%20near%20real-time.%20The%20dashboard%20experience%20is%20available%20in%20the%20web%20UI%20and%20can%20be%20accessed%20in%20the%20left%20menu.%20Select%20%E2%80%9CDashboards%20(Preview)%E2%80%9D%20and%20then%20select%20the%20option%20to%20build%20a%20new%20dashboard.%20Specify%20the%20ADX%20cluster%20URI%20and%20the%20database%20to%20use%20as%20a%20data%20source%20for%20the%20dashboards.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20align%3D%22center%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-center%22%20image-alt%3D%22Picture2-1.png%22%20style%3D%22width%3A%20631px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249469iC57409338CCB792B%2Fimage-dimensions%2F631x284%3Fv%3D1.0%22%20width%3D%22631%22%20height%3D%22284%22%20role%3D%22button%22%20title%3D%22Picture2-1.png%22%20alt%3D%22Picture2-1.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%228%22%3E%0A%3CLI%3EIn%20order%20to%20add%20flexibility%20and%20filtering%20capabilities%20to%20the%20dashboards%2C%20parameters%20can%20be%20configured%20for%20use%20in%20the%20visuals.%20After%20selecting%20%E2%80%9CParameters%E2%80%9D%20add%20two%20single%20selection%20parameters%20one%20representing%20the%20limit%20to%20trigger%20a%20high%20temperature%20alarm%20and%20the%20other%20as%20a%20limit%20for%20triggering%20a%20low%20temperature%20alarm.%20Note%20that%20by%20default%20there%20are%20two%20parameters%20defined%20for%20the%20start%20and%20end%20of%20the%20time%20period%20that%20is%20used%20in%20the%20time%20charts.%26nbsp%3B%20Each%20parameter%20in%20this%20case%20can%20have%20a%20number%20of%20values%20from%20which%20one%20value%20can%20be%20selected%20to%20use%20in%20the%20dashboards%20at%20any%20time%20(e.g.%20to%20change%20the%20alarm%20threshold%20at%20any%20time%20without%20having%20to%20re-build%20the%20dashboards).%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20align%3D%22center%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-center%22%20image-alt%3D%22Picture3-1.png%22%20style%3D%22width%3A%20594px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249476i01E70C6FA0FDD46B%2Fimage-dimensions%2F594x669%3Fv%3D1.0%22%20width%3D%22594%22%20height%3D%22669%22%20role%3D%22button%22%20title%3D%22Picture3-1.png%22%20alt%3D%22Picture3-1.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%229%22%3E%0A%3CLI%3EAdd%20a%20time%20chart%20of%20the%20temperature%20values%20(sensor1%20in%20this%20case)%20between%20time%20values%20represented%20by%20the%20built-in%20parameters%20_startTime%20and%20_endTime.%20Use%20the%20query%3A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Eiot_parsed%0A%7C%20where%20Timestamp%26nbsp%3B%20between%20(%5B'_startTime'%5D%20..%20%5B'_endTime'%5D)%0A%7C%20where%20Sensor%20%3D%3D%22sensor1%22%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3EOn%20the%20%E2%80%9CVisual%20formatting%E2%80%9D%20section%20use%20the%20%E2%80%9CTime%20chart%E2%80%9D%20visual%20type.%26nbsp%3B%26nbsp%3BFor%20the%20other%20fields%20leave%20the%20%E2%80%9CInfer%E2%80%9D%20option%20so%20that%20ADX%20can%20decide%20the%20values%20needed%20as%20shown%20below.%20Next%20click%20%E2%80%9CRun%E2%80%9D%20to%20see%20the%20time%20plot%20for%20sensor1.%20Apply%20the%20changes%20to%20use%20the%20visual%20in%20the%20dashboard.%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E(Note%3A%20inferring%20the%20axes%20parameters%20for%20the%20plot%20is%20straightforward%20in%20this%20case%20as%20the%20table%20has%20a%20simple%20schema.%20In%20cases%20where%20there%20is%20a%20more%20complex%20table%20structure%20it%20is%20advisable%20to%20specify%20the%20values%20by%20the%20developer).%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20align%3D%22center%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-center%22%20image-alt%3D%22Picture4-2.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249480i3D495FD06C4991E7%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22Picture4-2.png%22%20alt%3D%22Picture4-2.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%2210%22%3E%0A%3CLI%3EExtend%20the%20time%20chart%20of%20the%20first%20visual%20by%20adding%20values%20from%20the%20parameters%20that%20represent%20the%20alarm%20thresholds.%20In%20addition%2C%20add%20two%20logic%20variables%20(true%20or%20false)%20that%20would%20be%20set%20by%20the%20query%20if%20the%20actual%20temperature%20reading%20is%20larger%20than%20the%20high%20threshold%20or%20lower%20than%20then%20low%20threshold.%20The%20latter%20is%20achieved%20using%20the%20%E2%80%9Ciff%E2%80%9D%20operator.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Eiot_parsed%0A%7C%20where%20Timestamp%26nbsp%3B%20between%20(%5B'_startTime'%5D%20..%20%5B'_endTime'%5D)%0A%7C%20where%20Sensor%20%3D%3D%22sensor1%22%0A%7C%20project%20Timestamp%2C%20Value%2C%20_temp_High_Alarm%2C%20_temp_Low_Alarm%2C%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20HighAlarm%20%3D%20iff(Value%26gt%3B_temp_High_Alarm%2Ctrue%2Cfalse)%2C%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20LowAlarm%20%3D%20iff(Value%26lt%3B_temp_Low_Alarm%2Ctrue%2Cfalse)%0A%7C%20render%20timechart%20with%20(ysplit%20%3D%20panels)%26nbsp%3B%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3EExamining%20the%20resulting%20charts%20observe%20that%20the%20%E2%80%9CHighAlarm%E2%80%9D%20variable%20becomes%20%E2%80%9CTrue%E2%80%9D%20as%20soon%20as%20the%20temperature%20goes%20above%20the%20%E2%80%9C_temp_High_Alarm%E2%80%9D%20parameter%20value.%20By%20changing%20the%20parameter%20value%2C%20alarm%20thresholds%20can%20change%20immediately%20and%20applied%20in%20the%20visual.%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20align%3D%22center%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-center%22%20image-alt%3D%22Picture5-2.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249479iA08489C9764F151E%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22Picture5-2.png%22%20alt%3D%22Picture5-2.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%2211%22%3E%0A%3CLI%3EFinally%20use%20the%20%E2%80%9CConditional%20Formatting%E2%80%9D%20feature%20for%20the%20%E2%80%9CMulti%20Stat%E2%80%9D%20visual%20to%20build%20a%20coloured%20alarm%20indicator%20where%20a%20panel%20changes%20colour%20according%20the%20whether%20the%20temperature%20is%20above%20the%20high%20threshold%2C%20below%20the%20low%20threshold%20or%20in%20the%20normal%20region%20between%20the%20two%20thresholds.%20The%20query%20to%20use%20here%20is%3A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Eiot_parsed%0A%7C%20where%20Timestamp%26nbsp%3B%20between%20(%5B'_startTime'%5D%20..%20%5B'_endTime'%5D)%0A%7C%20where%20Sensor%20%3D%3D%22sensor1%22%0A%7C%20summarize%20arg_max(Timestamp%2C*)%0A%7C%20project%20Timestamp%2C%20TemperatureAlarm%20%3D%20iff(Value%26gt%3B_temp_High_Alarm%2C%22High%20Temperature%22%2Ciff(Value%26lt%3B_temp_Low_Alarm%2C%22Low%20Temperature%22%2C%22Normal%20Temperature%22))%2C%20Value%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3EThe%20above%20query%20uses%20the%20%E2%80%9Csummarize%20arg_max(Timestamp%2C*)%E2%80%9D%20operation%20to%20get%20the%20latest%20temperature%20value%2C%20then%20a%20nested%20%E2%80%9Ciff%E2%80%9D%20statement%20is%20used%20to%20set%20a%20variable%20called%20%E2%80%9CTemperatureAlarm%E2%80%9D%20to%20one%20of%20three%20values%20(%22High%20Temperature%22%2C%20%22Low%20Temperature%22%20or%20%22Normal%20Temperature%22).%20Use%20the%20value%20of%20%E2%80%9CTemperatureAlarm%E2%80%9D%20in%20the%20Conditional%20Formatting%20rule%20panel%20to%20set%20the%20visual%20colour%20to%20red%2C%20blue%20or%20green%20as%20shown%20below.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20align%3D%22center%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22Picture7-2.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249481i7546A4A92068464D%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22Picture7-2.png%22%20alt%3D%22Picture7-2.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%2212%22%3E%0A%3CLI%3EBelow%20is%20the%20final%20dashboard%20with%20all%20the%20three%20visuals%20together.%20Set%20this%20dashboard%20to%20update%20at%20regular%20time%20interval%20using%20the%20auto%20refresh%20feature%20to%20achieve%20a%20fast%20and%20near%20real%20time%20data%20and%20alarm%20display.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20align%3D%22center%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-center%22%20image-alt%3D%22Picture8-1.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249482i0892EBD39FD2042F%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22Picture8-1.png%22%20alt%3D%22Picture8-1.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%2213%22%3E%0A%3CLI%3EClean%20up%20resources%3A%20If%20the%20Azure%20resources%20used%20in%20this%20example%20are%20no%20further%20needed%20then%20remove%20the%20ADX%20cluster%20as%20explained%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fcreate-cluster-database-portal%23clean-up-resources%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehere%3C%2FA%3E.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EADX%20is%20an%20excellent%20destination%20for%20IoT%20data%20and%20we%20have%20demonstrated%20one%20reason%20for%20that%20in%20building%20these%20versatile%20dashboards.%20But%20this%20is%20not%20the%20end%20of%20the%20story%20and%20we%20highly%20recommend%20considering%20how%20to%20combine%20these%20dashboards%20with%20more%20advanced%20features%20of%20ADX%20such%20as%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Ftime-series-analysis%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3ETime%20Series%20Analysis%3C%2FA%3E%20and%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fanomaly-detection%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAnomaly%20Detection%3C%2FA%3E.%20Additionally%2C%20we%20can%20combine%20the%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2FIndustrial-IoT%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Industrial%20IoT%20platform%3C%2FA%3E%20with%20ADX%20to%20build%20a%20truly%20powerful%20solution%20for%20ingestion%2C%20analysing%20and%20displaying%20OPC-UA%20data%20from%20the%20factory%20floor.%20ADX%20also%20has%20powerful%20integration%20features%20that%20allow%20us%2C%20for%20example%2C%20%26nbsp%3Bto%20extend%20the%20alarm%20detection%20logic%20by%20sending%20emails%20or%20triggering%20other%20business%20processes%20using%20other%20Azure%20capabilities%20such%20as%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fdata-explorer%2Fkusto%2Ftools%2Flogicapps%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3ELogic%20Apps%3C%2FA%3E.%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-2095138%22%20slang%3D%22en-US%22%3E%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22PreviewImage%202.png%22%20style%3D%22width%3A%200px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249501i03159554FE81540A%2Fimage-size%2Fsmall%3Fv%3D1.0%26amp%3Bpx%3D200%22%20width%3D%220%22%20height%3D%220%22%20role%3D%22button%22%20title%3D%22PreviewImage%202.png%22%20alt%3D%22PreviewImage%202.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22PreviewImage5.png%22%20style%3D%22width%3A%20350px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F249505iEE759405924CB60B%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22PreviewImage5.png%22%20alt%3D%22PreviewImage5.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EBring%20your%20IoT%20data%20to%20life%20with%20effective%20and%20easy%20to%20implement%20dashboards%20in%20Azure%20Data%20Explorer.%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-TEASER%3E%3CLINGO-LABS%20id%3D%22lingo-labs-2095138%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3Eazure%20data%20explorer%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EIoT%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2111673%22%20slang%3D%22en-US%22%3ERe%3A%20Azure%20Data%20Explorer%20Dashboards%20for%20IoT%20Data%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2111673%22%20slang%3D%22en-US%22%3E%3CP%3E%3CSPAN%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F444903%22%20target%3D%22_blank%22%3E%40basim_majeed%3C%2FA%3E%26nbsp%3B%3C%2FSPAN%3E%3C%2FP%3E%3CP%3E%3CSPAN%3EI%20get%20this%20error%3C%2FSPAN%3E%3C%2FP%3E%3CP%3E%3CSPAN%3EError%20Syntax%20error%3A%20Query%20could%20not%20be%20parsed%3A%20.%20Query%3A%20'.create%20table%20iotparsed%20(Timestamp%3A%20datetime%2C%20Sensor%3A%20string%2C%20Value%3A%20real)'%20clientRequestId%3A%20KustoWebV2%3Bafab66d7-3be6-4700-9314-d7fb72cad78c%26nbsp%3B%40%3C%2FSPAN%3E%3C%2FP%3E%3C%2FLINGO-BODY%3E
Microsoft

Create Azure Data Explorer Dashboards for IoT Data and Alarm Visualisation

 

We show how to configure simple but effective Azure Data Explorer (ADX) dashboards on streaming data ingested from Azure IoT Hub with the aim of creating visual indication of alarm conditions (e.g. temperature exceeding a threshold).  ADX is a natural destination for IoT data as it provides managed ingestion from IoT Hub and advanced analytics/ad-hoc queries on the ingested data. Recently, the ADX team has added a powerful dashboarding feature that allows the mapping of ADX Kusto Query Language (KQL) queries into dashboards within the ADX Web UI.  The native dashboards allow the user to seamlessly export queries from the Web UI, optimise dashboard rendering performance and provides auto refresh capability for near real-time visualisation experience.

 

The starting point is having an IoT Hub with sensors transmitting data to its device to cloud endpoint. Once data starts flowing into the IoT Hub, start configuring the ingestion into an ADX table and building the dashboards using the typical end to end scenario in the following steps: 

 

  1. Create an ADX cluster by following the steps here.

 

  1. Enable streaming ingestion on the ADX cluster as explained here. Streaming ingestion is a powerful feature in situations where low latency between ingestion and query is needed as is typical for IoT scenarios.

 

  1. Create an ADX database by following the steps here.

For the remaining steps use the ADX web interface to run the necessary queries and view the dashboards. Add the ADX cluster to the web interface as explained in the previous link. One of the great features of the ADX Web UI is that it can be hosted by other web portals as an HTML iframe.

 

  1. Create a table in ADX to put the ingested data in.  In this example a simple message json structure is used with many sensors identified by “sensorName”, where, for example, “sensor1” carries Temperature values:

 

{
    "sensorName": "sensor1",
    "SensorReading": 21.171
}

 

 

The following ADX query creates a table ‘iot_parsed’ with three columns. Note that since the message does not carry a timestamp, the 'iothub-enqueuedtime' property, which is generated by the IoT Hub, is used for that purpose:

 

.create table iot_parsed (Timestamp: datetime, Sensor: string, Value: real)

 

 

Add a json ingestion mapping to instruct the ADX cluster to place the message components in the correct table columns:

 

.create table ['iot_parsed'] ingestion json mapping
'iot_parsed_mapping' '[{"column":"Timestamp","path":"$.iothub-enqueuedtime","datatype":"datetime"},{"column":"Sensor","path":"$.sensorName","datatype":"string"},{"column":"Value","path":"$.SensorReading","datatype":"real"},]'

 

 

This link provides more information on ingestion mapping in ADX. The table is now ready to receive data from the IoT Hub.

 

  1. Next use the instructions here to connect the IoT Hub to the ADX cluster and start ingesting the data into the staging table.

 

  1. Once the connection is verified, data will start flowing to the table. Use the following query in the ADX Web UI to examine a data sample of 10 rows:

 

iot _parsed
| take 10

 

 

 

Picture1-1.png

 

It is important to note at this point that since a very simple telemetry message structure is used in this example, it is straightforward to create a table with a specific schema to ingest the data directly from the IoT Hub.  In scenarios where the message structure is more complex, and probably variable over time, it is good practice to first ingest the data into a staging table with one ‘dynamic’ column. The staging table can then be processed into other tables each of which with a specific schema to serve different analytics use-cases. This processing can be carried out as new data arrives in the staging table using update policies.

 

  1. Now that the data is streamed regularly into the table, start building dashboards to display the data and to indicate alarm conditions in near real-time. The dashboard experience is available in the web UI and can be accessed in the left menu. Select “Dashboards (Preview)” and then select the option to build a new dashboard. Specify the ADX cluster URI and the database to use as a data source for the dashboards.

 

Picture2-1.png

 

  1. In order to add flexibility and filtering capabilities to the dashboards, parameters can be configured for use in the visuals. After selecting “Parameters” add two single selection parameters one representing the limit to trigger a high temperature alarm and the other as a limit for triggering a low temperature alarm. Note that by default there are two parameters defined for the start and end of the time period that is used in the time charts.  Each parameter in this case can have a number of values from which one value can be selected to use in the dashboards at any time (e.g. to change the alarm threshold at any time without having to re-build the dashboards).

 

Picture3-1.png

 

  1. Add a time chart of the temperature values (sensor1 in this case) between time values represented by the built-in parameters _startTime and _endTime. Use the query:

 

iot_parsed
| where Timestamp  between (['_startTime'] .. ['_endTime'])
| where Sensor =="sensor1"

 

 

On the “Visual formatting” section use the “Time chart” visual type.  For the other fields leave the “Infer” option so that ADX can decide the values needed as shown below. Next click “Run” to see the time plot for sensor1. Apply the changes to use the visual in the dashboard.

(Note: inferring the axes parameters for the plot is straightforward in this case as the table has a simple schema. In cases where there is a more complex table structure it is advisable to specify the values by the developer).

 

Picture4-2.png

 

  1. Extend the time chart of the first visual by adding values from the parameters that represent the alarm thresholds. In addition, add two logic variables (true or false) that would be set by the query if the actual temperature reading is larger than the high threshold or lower than then low threshold. The latter is achieved using the “iff” operator.

 

iot_parsed
| where Timestamp  between (['_startTime'] .. ['_endTime'])
| where Sensor =="sensor1"
| project Timestamp, Value, _temp_High_Alarm, _temp_Low_Alarm,
    HighAlarm = iff(Value>_temp_High_Alarm,true,false),
    LowAlarm = iff(Value<_temp_Low_Alarm,true,false)
| render timechart with (ysplit = panels) 

 

 

Examining the resulting charts observe that the “HighAlarm” variable becomes “True” as soon as the temperature goes above the “_temp_High_Alarm” parameter value. By changing the parameter value, alarm thresholds can change immediately and applied in the visual.

 

Picture5-2.png

 

  1. Finally use the “Conditional Formatting” feature for the “Multi Stat” visual to build a coloured alarm indicator where a panel changes colour according the whether the temperature is above the high threshold, below the low threshold or in the normal region between the two thresholds. The query to use here is:

 

iot_parsed
| where Timestamp  between (['_startTime'] .. ['_endTime'])
| where Sensor =="sensor1"
| summarize arg_max(Timestamp,*)
| project Timestamp, TemperatureAlarm = iff(Value>_temp_High_Alarm,"High Temperature",iff(Value<_temp_Low_Alarm,"Low Temperature","Normal Temperature")), Value

 

 

The above query uses the “summarize arg_max(Timestamp,*)” operation to get the latest temperature value, then a nested “iff” statement is used to set a variable called “TemperatureAlarm” to one of three values ("High Temperature", "Low Temperature" or "Normal Temperature"). Use the value of “TemperatureAlarm” in the Conditional Formatting rule panel to set the visual colour to red, blue or green as shown below.

 

Picture7-2.png

 

  1. Below is the final dashboard with all the three visuals together. Set this dashboard to update at regular time interval using the auto refresh feature to achieve a fast and near real time data and alarm display.

 

Picture8-1.png

 

  1. Clean up resources: If the Azure resources used in this example are no further needed then remove the ADX cluster as explained here.

 

ADX is an excellent destination for IoT data and we have demonstrated one reason for that in building these versatile dashboards. But this is not the end of the story and we highly recommend considering how to combine these dashboards with more advanced features of ADX such as Time Series Analysis and Anomaly Detection. Additionally, we can combine the Azure Industrial IoT platform with ADX to build a truly powerful solution for ingestion, analysing and displaying OPC-UA data from the factory floor. ADX also has powerful integration features that allow us, for example,  to extend the alarm detection logic by sending emails or triggering other business processes using other Azure capabilities such as Logic Apps.

3 Comments
Microsoft

Great blog Basim! Big fan of ADX functionality to price ratio. 

Regular Visitor

@basim_majeed 

I get this error

Error Syntax error: Query could not be parsed: . Query: '.create table iotparsed (Timestamp: datetime, Sensor: string, Value: real)' clientRequestId: KustoWebV2;afab66d7-3be6-4700-9314-d7fb72cad78c @

Microsoft

@deomaximo The command should definitely work , but as a reference see .create table - Azure Data Explorer | Microsoft Docs