Fix mxchip link and air traffic control simulator

This commit is contained in:
Arthur Ma 2019-04-12 19:10:58 +08:00
Родитель df82b384b7
Коммит 417a27fb0e
6 изменённых файлов: 2 добавлений и 1724 удалений

Просмотреть файл

@ -26,7 +26,7 @@ part1:
content:
- title: "Essential modules and sensors on the board save your time and money"
excerpt: "Wifi, OLED display, headphone, microphone, sensors like temperature, humidity, motion, pressure, you will love how much time and money you save to build your best IoT project."
url: "http://www.mxchip.com/az3166"
url: "https://aka.ms/iot-devkit-purchase"
btn_label: "Learn more about IoT DevKit hardware spec"
image_path: /assets/images/landingpage-banner2.png
attach:

Просмотреть файл

@ -1,276 +0,0 @@
---
title: "Air Traffic Control Simulator"
permalink: /docs/projects/air-traffic-control-simulator-01/
excerpt: "A comprehensive IoT solution with the very best features Microsoft Azure has to offer."
part: 1
header:
overlay_image: /assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight.png
overlay_full: true
teaser: /assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight-th.jpg
icons:
- url: /assets/images/icon-iot-hub.svg
target: https://azure.microsoft.com/en-us/services/iot-hub/
title: Azure IoT Hub
- url: /assets/images/icon-azure-functions.svg
target: https://azure.microsoft.com/en-us/services/functions/
title: Azure Functions
- url: /assets/images/icon-event-hub.svg
target: https://azure.microsoft.com/en-us/services/event-hubs/
title: Azure Event Hubs
- url: /assets/images/icon-stream-analytics.svg
target: https://azure.microsoft.com/en-us/services/stream-analytics/
title: Azure Stream Analytics
- url: /assets/images/icon-cognitive-services.svg
target: https://azure.microsoft.com/en-us/services/cognitive-services/
title: Cognitive Services
difficulty: HARD
last_modified_at: 2018-12-18
---
{% include toc icon="columns" %}
**Notice:** Content of this tutorial might be obsolete and subject to be updated.
{: .notice--warning}
## Introduction
In this hands-on lab and the ones that follow, you will build a comprehensive IoT solution that demonstrates some of the very best features Microsoft Azure has to offer, including [IoT Hubs](https://azure.microsoft.com/services/iot-hub/), [Event Hubs](https://azure.microsoft.com/services/event-hubs/), [Azure Functions](https://azure.microsoft.com/services/functions/), [Stream Analytics](https://azure.microsoft.com/services/stream-analytics/), and [Cognitive Services](https://azure.microsoft.com/services/cognitive-services/). The solution you build today will culminate into an Air-Traffic Control (ATC) app that shows simulated aircraft flying through an ATC sector and warns users when aircraft get too close to each other. While these labs are best to do with several peers, there is an application in the lab assets which can inject simulated drones into the workstream (details available in the [Labs section](#labs).)
![A user interface for an Air Traffic Control Application with dots and heading information overlaid on a geographical map. Also includes summary statistics for all flights shown on the map, as well as attitude information for selected airplanes.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/atc-app.png" | absolute_url }})
_The Air-Traffic Control application_
You will be the pilot of one of these aircraft. And to do the flying, you will use the [MXChip IoT DevKit](https://microsoft.github.io/azure-iot-developer-kit/), which is an Arduino-compatible device that is ideal for prototyping IoT solutions. It features an array of sensors, including an accelerometer, a gyrometer, and temperature and humidity sensors, and it includes built-in Wi-Fi so it can transmit data to Azure IoT Hubs wirelessly. It also features a micro-USB port by which you can connect it to your laptop, upload software, and power the hardware. You will control your aircraft by tilting the MXChip IoT DevKit backward and forward to go up and down, and rotating it left and right to turn.
![A Micro USB cable placed next to an Azure MXChip IoT DevKit IoT Development Board]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/cable-and-chip.png" | absolute_url }})
_IoT development board_
Here is how the solution is architected, with elements that you will build or deploy highlighted in light blue:
![A data flow diagram showing IoT information originating from an Azure MXChip IoT DevKit flowing through IoT Hub and onto an Azure Function. From the Azure Function, data is bifurcated to flow through a client application, as well as to an Event Hub shared by all workshop participants. The shared Event Hub forwards data to Azure Stream Analytics, where it is forwarded onto another event hub for distribution to the client application. Additionally, there are data flows from the client application to Cognitive Services and from Stream Analytics to Cosmos DB]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/architecture.png" | absolute_url }})
_Solution architecture_
Accelerometer data from the device is transmitted to an Azure IoT Hub. An Azure Function transforms the raw accelerometer data into *flight data* denoting airspeed, heading, altitude, latitude, longitude, pitch, and roll. The destination for that data is a pair of Event Hubs — one that you set up, and one that is shared by your peers or the simulator drones. Events from your Event Hub are consumed by a client app running on your laptop that shows the position and attitude of your aircraft. The events sent to the shared Event Hub go to a Stream Analytics job that analyzes fast-moving data for aircraft that are in danger of colliding and provides that data to the client app and the ATC app. When your aircraft comes too close to another, it turns red on the screen, and a warning appears on the screen of your MXChip. To top it off, Microsoft Cognitive Services translates the warning into the language of your choice.
The goal of this lab is to get the device up and running and sending events to an Azure IoT Hub. Let's get started!
<a name="Labs"></a>
## Labs ##
Here's a synopsis of the four labs that comprise this project:
- [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}) - Create an Azure IoT Hub and program an [MXChip IoT DevKit](https://microsoft.github.io/azure-iot-developer-kit/) to send accelerometer data to it.
- [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}) - Create an Azure Event Hub and deploy an Azure Function that transforms accelerometer data input to the IoT Hub into "flight data" denoting the disposition on an airplane and transmits it to the Event Hub. Then connect a UWP client app to the Event Hub and use their MXChip IoT DevKit to fly a simulated airplane.
- [Lab 3]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }}) - Creates a pair of Event Hubs and deploy a Stream Analytics job that analyzes all the air traffic for aircraft that are within two miles of each another. Also deploys a UWP app that shows all the air traffic.
- [Lab 4]({{"/docs/projects/air-traffic-control-simulator-04/" | absolute_url }}) - Modify the Azure Function deployed in [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}) to transmit flight data to the input hub used by Stream Analytics. Then connect the client app to the Stream Analytics output and modify the app to transmit warning messages back to the MXChip IoT DevKit when aircraft are within two miles of another.
The [asset repository](https://github.com/Azure/CloudIoTHack) also has four source-code folders:
- FlySim - A Visual Studio 2017 solution containing the client app that you use to fly simulated airplanes.
- FlySimEmbedded - The code you upload to the MXChip IoT DevKit to program it to send accelerometer data to an Azure IoT Hub.
- AirTrafficSim - A Visual Studio 2017 solution containing the air-traffic control (ATC) app that shows all the airplanes in flight and highlights those that are within two miles of each other.
- FlySimTest - A Visual Studio 2017 solution containing a command-line app for injecting simulated aircraft into AirTrafficSim. It's great for testing, and also for adding airplanes to the ATC sector, if you don't have peers working with you through this content. To prepare it for use, replace SHARED_EVENT_HUB_ENDPOINT on line 54 with the endpoint connection string for the Event Hub that provides input to Stream Analytics. By default, it injects 20 airplanes. You can inject more (or less) by specifying the desired number as a command-line parameter.
<a name="Prerequisites"></a>
## Prerequisites ##
The following are required to complete this lab:
- An [MXChip IoT DevKit](https://microsoft.github.io/azure-iot-developer-kit/)
- A computer running [Windows 10 Anniversary Edition](https://www.microsoft.com/en-us/software-download/windows10) or higher
- Finish the [Getting Started Guide]({{"/docs/get-started/" | absolute_url }}) to:
* Have your IoT DevKit connected to Wi-Fi
* Upgrade to the latest firmware
* Prepare the development environment
- An active Azure subscription. If you do not have one, you can register via one of the methods:
* Activate a [free 30-day trial Microsoft Azure account](https://azure.microsoft.com/en-us/free/){:target="_blank"}
* Claim your [Azure credit](https://azure.microsoft.com/en-us/pricing/member-offers/msdn-benefits-details/){:target="_blank"} if you are MSDN or Visual Studio subscriber
- An available Wi-Fi connection or mobile hotspot. Note that the Wi-Fi connection can (and should) be secure, but it must be ungated (i.e. no intermediate login page is required. Gated Wi-Fi is common in public venues and hotels).
**Note:** For developers work on a Mac, please see [this article](https://docs.microsoft.com/en-us/windows/uwp/porting/setting-up-your-mac-with-windows-10) for installing Windows 10 to enable building and running the UWP portion of this lab.
{: .notice--info}
---
## Exercises ##
This lab includes the following exercises:
- [Exercise 1: Provision an Azure IoT Hub](#Exercise1)
- [Exercise 2: Deploy an app to the device](#Exercise2)
- [Exercise 3: Check IoT Hub activity](#Exercise3)
Estimated time to complete this lab: **60** minutes including development environment setup.
<a name="Exercise1"></a>
### Exercise 1: Provision an Azure IoT Hub ###
[Azure IoT Hubs](https://docs.microsoft.com/azure/iot-hub/iot-hub-what-is-iot-hub) enable IoT devices to connect securely to the cloud and transmit messages (events) that can be ingested by apps and other Azure services. They support bidirectional communication, and they are built to be massively scalable. A single IoT Hub can handle millions of events per second. Messages can be sent over HTTP, or using the [Advanced Message Queuing Protocol](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-what-is-iot-hub) (AMQP) or [Message Queueing Telemetry Transport](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-what-is-iot-hub) (MQTT) protocol. Devices can be authenticated using per-device security keys or X.509 certificates.
In this exercise, you will provision an Azure IoT Hub for your MXChip IoT DevKit to transmit events to.
1. Open the [Azure Portal](https://portal.azure.com) in your browser. If asked to log in, do so using your Microsoft account.
1. Click **+ New**, followed by **Internet of Things** and **IoT Hub**.
![The Azure Portal quick start menu shows the selection to add a new IoT Hub to a subscription.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/portal-select-new.png" | absolute_url }})
_Provisioning a new IoT Hub_
1. Enter a unique name for IoT Hub in the **Name** field. IoT Hub names must be unique across Azure, so make sure a green check mark appears next to it. Also make sure **S1 - Standard** is selected as the pricing tier. Select **Create new** under **Resource group** and enter the resource-group name "FlySimResources." Select **East US** as the **Location** (important!). Accept the default values everywhere else, and then click **Create**.
> You selected East US as the location because in [Lab 3]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }}), you will create Azure resources in that same region for the IoT Hub to connect to. Azure resources can be connected across regions but keeping everything within the same data center reduces cost and minimizes latency.
![The Azure Portal's IoT Hub Configuration pane shows relevant configuration settings. The pricing tier is set to S1, and a single unit of IoT Hub and 4 Device-to-cloud partitions are entered.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/portal-configure-hub.png" | absolute_url }})
_Configuring an IoT Hub_
1. Click **Resource groups** in the ribbon on the left side of the portal, and then click **FlySimResources** to open the resource group.
![The Azure Portal's Resource Groups pane displays the newly created IoT Hub.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/open-resource-group.png" | absolute_url }})
_Opening the resource group_
1. Wait until "Deploying" changes to "Succeeded," indicating that the IoT Hub has been provisioned. You can click the **Refresh** button at the top of the blade to refresh the deployment status.
![The Azure Portal's Resource Group indicates that the IoT Hub deployment completed successfully.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/deployment-succeeded.png" | absolute_url }})
_Successful deployment_
Because you selected **S1 - Standard** as the pricing tier in Step 3, you can transmit up to 400,000 messages a day to the IoT Hub for $50 per month. A **Free** tier that accepts up to 8,000 messages per day is also available, but that tier might be too limiting for this exercise. For more information on the various pricing tiers that are available, see [IoT Hub pricing](https://azure.microsoft.com/pricing/details/iot-hub/).
<a name="Exercise2"></a>
### Exercise 2: Deploy an app to the device ###
In this exercise, you will compile an embedded C++ app that transmits events to your Azure IoT Hub and use Visual Studio Code to upload it to the MXChip. Once the app is uploaded, it will begin executing on the device, and it will send a JSON payload containing three accelerometer values (X, Y, and Z) as well as temperature and humidity readings approximately every two seconds. The app is persisted in the firmware and automatically resumes execution if the device is powered off and back on.
1. Using git, clone the [lab's assets](https://github.com/Azure/CloudIoTHack) to your local file system. You can optionally use the download link on the repository's home page to download the assets as a zip file.
1. Start Visual Studio Code and select **Open Folder...** from the **File** menu. Browse to the "FlySimEmbedded" folder included in the lab's assets.
1. Open **config.h** and replace YOUR_DISPLAY_NAME with a friendly display name. Then save the file. **This name will be seen by everyone when the ATC app is run in Lab 4**, so please choose a name that's appropriate. Also make it as **unique as possible** by including birth dates (for example, "Amelia Earhart 093059") or other values that are unlikely to be duplicated.
![Entering a display name]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-enter-display-name.png" | absolute_url }})
_Entering a display name_
1. Press **F1** and type "terminal" into the search box. Then select **Select Default Shell**.
![The VSCode quick start menu has the word 'terminal' entered in it's text box with the selection 'Terminal: Select Default Shell' highlighted.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/select-default-shell-1.png" | absolute_url }})
_Selecting the default shell_
1. Select **PowerShell** from the list of shells to make PowerShell the default shell.
![The VSCode quick start menu displays the available terminals to set as default; 'PowerShell' has been highlighted.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/select-default-shell-2.png" | absolute_url }})
_Making PowerShell the default shell_
1. Select **Run Task** from Visual Studio Code's **Tasks** menu, and then select **cloud-provision** from the drop-down list of tasks. This will begin the process of authorizing your device to access the IoT Hub created in the previous exercise.
![The VSCode task selection pane has the 'cloud-provision' task highlighted.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-select-cloud-provision.png" | absolute_url }})
_Starting the cloud-provisioning process_
1. When a "Device Login" screen appears in your browser, copy the login code displayed in Visual Studio Code's Terminal window to the clipboard.
![A VSCode terminal is displaying a device login code as the result of running the 'cloud-provision' task.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-code-prompt.png" | absolute_url }})
_Getting the device-login code_
1. Return to the "Device Login" screen in the browser, paste the login code into the input field, and click **Continue**.
![An Azure CLI device login screen with an indication of where to enter a device authorization code.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/portal-enter-device-login.png" | absolute_url }})
_Logging in to the device_
1. Return to the Terminal window in Visual Studio Code and wait for a list of Azure subscriptions to appear. Use the up- and down-arrow keys to select the Azure subscription that you used to provision the Azure IoT Hub in [Exercise 1](#Exercise1). Then press **Enter** to select that subscription.
1. When a list of IoT Hubs associated with the subscription appears in the Terminal window, select the IoT Hub that you provisioned in [Exercise 1](#Exercise1).
![The VSCode terminal windows is displayed, showing an IoT Hub from the user's subscription.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-select-iot-hub.png" | absolute_url }})
_Selecting an Azure IoT Hub_
1. Wait until the message "Terminal will be reused by tasks, press any key to close it" appears in the Terminal window. This indicates that the cloud-provisioning process completed successfully. Your MXChip IoT DevKit can now authenticate with the IoT Hub and send messages to it securely.
![The VSCode terminal window is displayed showing the results of running the 'cloud-provision' task.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-completed-provisioning.png" | absolute_url }})
_A successful cloud-provision task_
1. Now it's time to upload code to the device to have it transmit events to the IoT Hub. Select **Tasks** > **Run Task** again, and then select **device-upload**.
![The VSCode menu displays a list of executable tasks including 'cloud-provision', 'config_wifi' and 'device-upload'. The 'device-upload' selection is highlighted.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-select-device-upload.png" | absolute_url }})
_Starting the device-upload process_
1. Wait until you are prompted in the Terminal window to "hold on Button A and then press Button Reset to enter configuration mode." Then do the following:
- Press and hold the **A button** on the device
- With the A button held down, press and release the **Reset button**
- Release the **A button**
After a brief pause, the C++ app that reads accelerometer data and transmits it to the IoT Hub will begin uploading to your device. If you are curious to see what the source code looks like, examine the CPP files in the project directory in Visual Studio Code.
1. Wait until the message "Terminal will be reused by tasks, press any key to close it" appears in the Terminal window. After the device restarts, confirm that the message "IN FLIGHT" appears on the screen of the device, followed by X, Y, and Z values that change when you tilt the board in any direction. These are the accelerometer values passed to the IoT Hub. The fact that they appear on the screen confirms that the upload was successful, and that the app is running on the device.
![The MXChip IoT DevKit display shows a label of "In Flight" with telemetry data for x, y and z axis readings from the onboard gyroscope.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/chip-in-flight.png" | absolute_url }})
_MXChip IoT DevKit with your embedded code running on it_
We know that the device is transmitting events. Now let's make sure those events are being received by the IoT Hub.
<a name="Exercise3"></a>
### Exercise 3: Check IoT Hub activity ###
In this exercise, you will use the Azure portal to confirm that the MXChip IoT DevKit is registered with the IoT Hub you created in [Exercise 1](#Exercise1), and also confirm that the hub is receiving messages from the device.
1. Return to the Azure portal and to the "FlySimResources" resource group. Then click the IoT Hub that you created in Exercise 1.
![The Azure Portal's Resource Group for this workshop is displayed with the IoT Hub resource selected.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/open-iot-hub.png" | absolute_url }})
_Opening a blade for the IoT Hub_
1. Click **Overview** and look at the count of messages received and the number of devices registered. Confirm that the device count is 1, and that the number of messages received is greater than zero.
![The Azure Portal's IoT Hub blade is displaying the Overview tab with a highlight over the Usage statistics panel.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/portal-hub-usage.png" | absolute_url }})
_Stats regarding the IoT Hub_
1. Click **Device Explorer** to display a list of all devices that are registered to communicate with this IoT Hub. Confirm that your device ("AZ3166") appears in the list.
![The Azure Portal's IoT Hub blade is displayed with the Device Explorer tab highlighted. The pane to the right shows that the MXChip IoT DevKit has been registered with IoT Hub.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/portal-device-explorer.png" | absolute_url }})
_Devices registered with the IoT Hub_
1. Return to Visual Studio Code and click the **Connect** icon in the status bar at lower right.
![The document information display bar at the bottom of a VSCode window shows a two-prong plug symbol indicating where to click to change the baud rate of the MXChip IoT DevKit connection.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-click-connect.png" | absolute_url }})
_Connecting to the device via a COM port_
1. When the icon changes to an 'X', click the Baud rate on the left and select **115200** from the drop-down list to increase the Baud rate.
![The document information display bar at the bottom of a VSCode window that shows the baud rate configuration selection menu set to 9600.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-click-baud-rate.png" | absolute_url }})
_Increasing the Baud rate_
1. Look in Visual Studio Code's Output window and confirm that events are being transmitted. You can also see the JSON format in which they're transmitted. This is the raw data streaming to the IoT Hub. Note that the display name you entered in the previous exercise is transmitted in a field named "deviceId," and that each message includes a timestamp in the "timestamp" field.
![A VSCode terminal window displays the telemetry data generated by the MXChip.]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab1/vs-viewing-com-data.png" | absolute_url }})
_Events transmitted from the device to the IoT Hub_
The MXChip IoT DevKit is now running embedded code that sends accelerometer data to the IoT Hub. Consumers of that data can examine the X, Y, and Z values and determine the device's physical orientation in space. This sets the stage for the next lab, in which you will make use of that data.
<a name="Summary"></a>
## Summary ##
In this lab, you created an Azure IoT Hub and configured your MXChip IoT DevKit to send data to it.
In [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}), you will build the infrastructure necessary to fly a simulated aircraft using the MXChip. That infrastructure will consist of an Azure Function that transforms accelerometer readings passing through the IoT Hub into flight data denoting the position and attitude of an aircraft, as well as an Azure Event Hub that receives data from the Azure Function. Once the Function and Event Hub are in place, you will connect a client app to the Event Hub and practice flying an aircraft by tilting your MXChip IoT DevKit backward and forward to go up and down and rotating it right and left to bank and turn. In other words, the fun is just beginning!

Просмотреть файл

@ -1,619 +0,0 @@
---
title: "Air Traffic Control Simulator - Lab 2"
permalink: /docs/projects/air-traffic-control-simulator-02/
excerpt: "Using Azure Functions and Azure Event Hubs to Process IoT Data."
part: 2
header:
overlay_image: /assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight.png
overlay_full: true
teaser: /assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight-th.jpg
difficulty: HARD
last_modified_at: 2017-10-30
---
{% include toc icon="columns" %}
## Overview
In [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}), you configured an [MXChip](https://microsoft.github.io/azure-iot-developer-kit/) to transmit accelerometer data to an Azure IoT Hub. That IoT Hub receives a stream of data revealing the device's 3D orientation in space. It knows, for example, whether the device is tilted forward or backward (and by how much), and it knows when the device is rotated left and right. The app that you uploaded to the device transmits an event containing X, Y, and Z accelerometer readings every two seconds.
In this lab, you will build the infrastructure necessary to fly a simulated aircraft using your MXChip. That infrastructure will consist of an Azure Function that transforms accelerometer readings passing through the IoT Hub into flight data denoting the position and attitude of an aircraft, as well as an Azure Event Hub that receives data from the Azure Function. Once the Function and Event Hub are in place, you will connect a client app named **FlySim** to the Event Hub and practice flying an aircraft using your MXChip. The client app, pictured below, subscribes to events from the Event Hub and shows the disposition of your aircraft in near real time.
![The FlySim app]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight.png" | absolute_url }})
_The FlySim app_
<a name="Prerequisites"></a>
## Prerequisites ##
The following are required to complete this lab:
- An [MXChip IoT DevKit](https://microsoft.github.io/azure-iot-developer-kit/)
- A computer running [Windows 10 Anniversary Edition](https://www.microsoft.com/en-us/software-download/windows10) or higher
- Finish the [Getting Started Guide]({{"/docs/get-started/" | absolute_url }}) to:
* Have your IoT DevKit connected to Wi-Fi
* Upgrade to the latest firmware
* Prepare the development environment
- An active Azure subscription. If you do not have one, you can register via one of the methods:
* Activate a [free 30-day trial Microsoft Azure account](https://azure.microsoft.com/en-us/free/){:target="_blank"}
* Claim your [Azure credit](https://azure.microsoft.com/en-us/pricing/member-offers/msdn-benefits-details/){:target="_blank"} if you are MSDN or Visual Studio subscriber
- An available Wi-Fi connection or mobile hotspot. Note that the Wi-Fi connection can (and should) be secure, but it must be ungated (i.e. no intermediate login page is required. Gated Wi-Fi is common in public venues and hotels).
**Note:** For developers work on a Mac, please see [this article](https://docs.microsoft.com/en-us/windows/uwp/porting/setting-up-your-mac-with-windows-10) for installing Windows 10 to enable building and running the UWP portion of this lab.
{: .notice--info}
<a name="Lab-Sections"></a>
## Lab Sections ##
Here are labs that comprise this project:
- [Lab 1 - Getting started with the Azure MxChip and Azure IoT]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }})
- [Lab 2 - Using Azure Functions and Azure Event Hubs to Process IoT Data.]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }})
- [Lab 3 - Performing Real-Time Proximity Detection with Azure Stream Analytics]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }})
- [Lab 4 - Complete the solution and enable Cloud-to-Device communication.]({{"/docs/projects/air-traffic-control-simulator-04/" | absolute_url }})
---
<a name="Exercises"></a>
## Exercises ##
This lab includes the following exercises:
- [Exercise 1: Provision an Azure Event Hub](#Exercise1)
- [Exercise 2: Provision an Azure storage account](#Exercise2)
- [Exercise 3: Write an Azure Function to transform data](#Exercise3)
- [Exercise 4: Deploy the Azure Function to the cloud](#Exercise4)
- [Exercise 5: Connect the client app to the Event Hub](#Exercise5)
Estimated time to complete this lab: **60** minutes.
<a name="Exercise1"></a>
### Exercise 1: Provision an Azure Event Hub ###
Azure IoT Hubs were created to provide secure, bidirectional endpoints for IoT devices to talk to. They are wrappers around [Azure Event Hubs](https://azure.microsoft.com/services/event-hubs/), which support unidirectional communication only but are ideal for aggregating events at scale and disseminating those events to interested clients. "Client" could mean another Azure service such as [Stream Analytics](https://azure.microsoft.com/services/stream-analytics/), or it could be an app you've written that subscribes to events reaching the Event Hub.
In this exercise, you will use the Azure Portal to create an Event Hub that will ultimately receive data from an Azure Function attached to the IoT Hub you created in [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}), and that will provide input to the FlySim app.
1. Open the [Azure Portal](https://portal.azure.com) in your browser. If asked to log in, do so using your Microsoft account.
1. Click **+ New**, followed by **Internet of Things** and **Event Hubs**.
![Adding a new Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/new-event-hub.png" | absolute_url }})
_Adding a new event hub_
1. Type a namespace name into the **Name** box. The name must be unique within Azure, so make sure a green check mark appears next to it. Also make sure **Pricing tier** is set to **Standard**. Select **Use existing** under **Resource group** and select the "FlySimResources" resource group that you created in Lab 1. Choose the **East US** region in the **Location** drop-down, and then click **Create**.
> It is important to select the East US region to locate the Event Hub in the same region as the IoT Hub you created in [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}). This reduces cost and minimizes latency.
![Creating a namespace]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/create-namespace.png" | absolute_url }})
_Creating a namespace_
1. Click **Resource groups** in the ribbon on the left side of the portal, and then click **FlySimResources** to open the resource group.
![Opening the resource group]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/open-resource-group.png" | absolute_url }})
_Opening the resource group_
1. Wait until "Deploying" changes to "Succeeded," indicating that the IoT Hub has been provisioned. (You can click the **Refresh** button at the top of the blade to refresh the deployment status.) Then click the Event Hub that you just created.
![Successful deployment]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/open-event-hub.png" | absolute_url }})
_Successful deployment_
1. Click **+ Event Hub** at the top of the blade.
![Adding an Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/add-event-hub.png" | absolute_url }})
_Adding an Event Hub_
1. Type "flysim" (without quotation marks) into the **Name** box. Then click the **Create** button.
![Creating an Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/create-event-hub.png" | absolute_url }})
_Creating an Event Hub_
1. Wait a moment for the Event Hub to be created. Then confirm that "flysim" appears in the list of Event Hubs.
![The new Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/flysim-event-hub.png" | absolute_url }})
_The new Event Hub_
How much do Azure Event Hubs cost? The **Standard** pricing tier that you selected in Step 3 incurs a nominal charge per million events received, as well as a flat hourly charge per throughput unit. Currently, an Event Hub with one throughput unit (each throughput unit can handle 1 MB per second of data input and 2 MB per second of data output) that receives one million events per day costs less than a dollar a day. For more information and current pricing, see [Event Hubs pricing](https://azure.microsoft.com/pricing/details/event-hubs/).
<a name="Exercise2"></a>
### Exercise 2: Provision an Azure storage account ###
Before you deploy an Azure Function from Visual Studio, you need to create a repository for the Function's code, logs, and history. In this exercise, you will create an Azure storage account for that purpose.
1. Return to the Azure Portal. Click **+ New**, followed by **Storage** and **Storage account**.
![Creating a new storage account]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/new-storage-account.png" | absolute_url }})
_Creating a new storage account_
1. Enter a unique name for the storage account and make sure a green check mark appears next to it. Select **Use existing** under **Resource group** and select the "FlySimResources" resource group that you created in Lab 1. Choose **East US** as the **Location**, and then click the **Create** button.
![Creating a new storage account]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/create-storage-account.png" | absolute_url }})
_Creating a new storage account_
Now that the storage account has been created, it's time to create an Azure Function to transform accelerometer data reaching the IoT Hub into flight data and send it to the Event Hub you created in [Exercise 1](#Exercise1).
<a name="Exercise3"></a>
### Exercise 3: Write an Azure Function to transform data ###
[Azure Functions](https://azure.microsoft.com/services/functions/) enable you to deploy code to the cloud and execute it there without separately spinning up virtual machines (VMs) or other infrastructure to host them. They can be written in a number of languages, including C#, F#, Java, JavaScript, Python, Bash, and PowerShell, and they are easily connected to Azure IoT Hubs, Event Hubs and other Azure services.
You can write Azure Functions in the Azure Portal, or you can write them in Visual Studio 2017. The latter provides a more robust environment for testing and debugging your code. In this exercise, you will use Visual Studio 2017 to write an Azure Function that transforms raw accelerometer data arriving at the IoT Hub you created in Lab 1 into flight data denoting the disposition of an aircraft, and that transmits the transformed data to the Event Hub you created in [Exercise 1](#Exercise1).
1. Start Visual Studio and use the **Help** > **About Microsoft Visual Studio** command to verify that you are running Visual Studio 15.3 or higher. If not, update Visual Studio now.
1. Select **Extensions and Updates...** from Visual Studio's **Tools** menu, and select **Visual Studio Marketplace** under **Updates** on the left. If "Azure Functions and Web Jobs Tools" appears in the list of updates, click the **Update** button next to it.
![Installing the Azure Functions update]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/install-azure-tools.png" | absolute_url }})
_Installing the Azure Functions update_
1. Use Visual Studio's **File** > **New Project** command to create a new C# Azure Functions project named "FlySimFunctions."
![Creating a new Azure Functions project]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/vs-add-project.png" | absolute_url }})
_Creating a new Azure Functions project_
1. Right-click the FlySimFunctions project in Solution Explorer and use the **Add** > **New Item...** command to add an Azure Function file named **FlySimIoTFlightData.cs**.
![Adding an Azure Function to the project]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/vs-add-new-function.png" | absolute_url }})
_Adding an Azure Function to the project_
1. In the "New Azure Function" dialog, select **Event Hub trigger**, type "IoTHubConnection" into the **Connection** box, delete any default **Path** value, and then click **OK**.
![Specifying the Function trigger]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/vs-select-event-hub-trigger.png" | absolute_url }})
_Specifying the Function trigger_
1. Replace the contents of **FlySimIotFlightData.cs** with the following code:
```csharp
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.WebJobs.ServiceBus;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Threading.Tasks;
namespace FlySimFunctions
{
public static class FlySimIoTFlightData
{
private static DateTime? _last = null;
private static double _airspeed = 384.0;
private static double _heading = 0.0;
private static double _altitude = 32000.0;
private static double _latitude = 37.242;
private static double _longitude = -115.8190;
private static double _pitch = 0.0;
private static double _roll = 0.0;
[FunctionName("FlySimIoTFlightData")]
public async static Task Run([EventHubTrigger("", Connection = "IoTHubConnection")]string inputMessage, [EventHub("outeventhub", Connection = "EventHubConnection")] IAsyncCollector<string> outputMessage, TraceWriter log)
{
// Deserialize the JSON input
var converter = new IsoDateTimeConverter { DateTimeFormat = "MM/dd/yy HH:mm:ss" };
var input = JsonConvert.DeserializeObject<Input>(inputMessage, converter);
var outputPayload = "";
if (_last != null && input.timestamp > _last.Value)
{
// Compute milliseconds elapsed since last event was received
var milliseconds = (input.timestamp - _last.Value).TotalMilliseconds;
_last = input.timestamp;
// Constrain pitch to +/-15 degrees (positive == nose down)
_pitch = Math.Max(Math.Min(input.y / 11.0, 15.0), -15.0);
// Constrain roll to +/-30 degrees (positive == rolling right)
_roll = Math.Max(Math.Min(input.x / 11.0, 30.0), -30.0);
// Compute new heading assuming hard left or right turns 10 degrees per second
var delta = (milliseconds / 100.0) * (_roll / 30.0);
_heading += delta;
if (_heading < 0.0)
_heading += 360.0;
else if (_heading >= 360.0)
_heading -= 360.0;
// Compute new latitude and longitude
var radians = _heading * Math.PI / 180.0;
var distance = (milliseconds / 1000) * (_airspeed * 0.000277778); // 1 MPH == 0.000277778 miles per second
var dx = distance * Math.Sin(radians);
var dy = distance * Math.Cos(radians);
_latitude += (dy / 69.0); // Assume 69 miles per 1 degree of latitude
_longitude += (dx / 69.0); // Assume 69 miles per 1 degree of longitude
// Compute new altitude and constrain it to 1,000 to 40,000 feet
_altitude = _altitude - (distance * 5280.0 * Math.Sin(_pitch * Math.PI / 180.0));
_altitude = Math.Max(Math.Min(_altitude, 40000.0), 1000.0);
// Send JSON output
var output = new Output { deviceId = input.deviceId, timestamp = input.timestamp, temperature = input.temperature, humidity = input.humidity, airspeed = _airspeed, altitude = _altitude, heading = _heading, latitude = _latitude, longitude = _longitude, pitch = _pitch, roll = _roll };
outputPayload = JsonConvert.SerializeObject(output);
}
else
{
// This is the first event received, so compute initial parameters
_last = input.timestamp;
var hash = (uint)input.deviceId.GetHashCode();
_heading = hash % 360;
_altitude = 10000.0 + ((hash % 25) * 1000);
_latitude = 36.7 + ((double)((hash / 100) % 100) / 100.0);
_longitude = -116.8 + ((double)(hash % 100) / 50.0);
var output = new Output { deviceId = input.deviceId, timestamp = input.timestamp, temperature = input.temperature, humidity = input.humidity, airspeed = _airspeed, altitude = _altitude, heading = _heading, latitude = _latitude, longitude = _longitude, pitch = _pitch, roll = _roll };
outputPayload = JsonConvert.SerializeObject(output);
log.Info("First event received");
}
await outputMessage.AddAsync(outputPayload);
log.Info(String.Format("Heading={0}, Altitude={1}, Latitude={2}, Longitude={3}", _heading, _altitude, _latitude, _longitude));
return;
}
}
class Input
{
public string deviceId;
public DateTime timestamp;
public string messageId;
public double temperature;
public double humidity;
public double x;
public double y;
public double z;
}
class Output
{
public string deviceId;
public DateTime timestamp;
public double airspeed;
public double heading;
public double altitude;
public double latitude;
public double longitude;
public double pitch;
public double roll;
public double temperature;
public double humidity;
}
}
```
Take a moment to examine the code you pasted in, beginning with the method's parameter list. ```inputMessage``` holds the JSON-formatted message that arrived at the IoT Hub, while ```outputMessage``` represents the message (or messages) to be transmitted to the Event Hub. After deserializing the input message, this Azure Function computes new flight data — airspeed, heading, altitude, and so on — from the accelerometer values passed by the device. Then it serializes the flight data into JSON and outputs it to the Event Hub by calling ```AddAsync``` on the ```outputMessage``` parameter.
1. Open **local.settings.json** and replace the contents of the file with the following JSON:
```json
{
"IsEncrypted": false,
"Values": {
"IoTHubConnection": "IOT_HUB_ENDPOINT;EntityPath=IOT_HUB_NAME",
"EventHubConnection": "EVENT_HUB_ENDPOINT;EntityPath=flysim",
"AzureWebJobsStorage": "STORAGE_ACCOUNT_ENDPOINT",
"AzureWebJobsDashboard": "",
}
}
```
This file contains three values that must be updated before you build and test your Function:
- **IoTHubConnection** - Connection string for the IoT Hub created in the previous lab
- **EventHubConnection** - Connection string for the Event Hub created in [Exercise 1](#Exercise1)
- **AzureWebJobsStorage** - Connection string for the storage account created in [Exercise 2](#Exercise2)
You will update these values in the next few steps.
1. Return to the "FlySimResources" resource group in the Azure Portal and click the IoT Hub that you created in [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}).
![Opening a blade for the IoT Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/open-iot-hub.png" | absolute_url }})
_Opening a blade for the IoT Hub_
1. Click **Endpoints**, and then click **Events**.
![Viewing endpoint information]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/portal-click-iot-endpoints.png" | absolute_url }})
_Viewing endpoint information_
1. Click the **Copy** button next to "Event Hub-compatible endpoint" to copy the endpoint the clipboard.
![_Copying the endpoint to the clipboard]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/portal-copy-iot-endpoint.png" | absolute_url }})
_Copying the endpoint to the clipboard_
1. Return to Visual Studio and replace IOT_HUB_ENDPOINT in **local.settings.json** with the value on the clipboard. Then replace IOT_HUB_NAME on the same line with the name of your IoT Hub.
1. Return to the "FlySimResources" resource group in the Azure Portal and click the Event Hub that you created in [Exercise 1](#Exercise1).
![Opening a blade for the Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/open-event-hub-2.png" | absolute_url }})
_Opening a blade for the event hub_
1. Click **Shared access policies**, followed by **RootManageSharedAccessKey**.
![Opening RootManageSharedAccessKey]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/portal-click-event-hub-policy.png" | absolute_url }})
_Opening RootManageSharedAccessKey_
1. Click the **Copy** button next to "Connection string–primary key" to copy the connection string the clipboard.
![Copying the connection string to the clipboard]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/portal-copy-event-hub-sas.png" | absolute_url }})
_Copying the connection string to the clipboard_
1. Return to Visual Studio and replace EVENT_HUB_ENDPOINT in **local.settings.json** with the value on the clipboard.
1. Return to the "FlySimResources" resource group in the Azure Portal and click the storage account that you created in [Exercise 2](#Exercise2).
![Opening a blade for the storage account]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/open-storage-account.png" | absolute_url }})
_Opening a blade for the storage account_
1. Click **Access keys**, and then click the **Copy** button next to the first connection string to copy the connection string to the clipboard.
![Copying the connection string to the clipboard]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/portal-copy-storage-key.png" | absolute_url }})
_Copying the connection string to the clipboard_
1. Return to Visual Studio and replace STORAGE_ACCOUNT_ENDPOINT in **local.settings.json** with the value on the clipboard.
1. Now it's time to test the Function and make sure it is triggered each time an event from the MXChip IoT DevKit reaches the IoT Hub. If your MXChip IoT DevKit isn't plugged in, connect it to your laptop and confirm that the device screen says "IN FLIGHT."
![The MXChip IoT DevKit in flight]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/chip-in-flight.png" | absolute_url }})
_The MXChip IoT DevKit in flight_
1. Open **FlySimIoTFlightData.cs** in Visual Studio and set a breakpoint on line 27. Then press **F5** to start debugging.
> If Visual Studio prompts you to download the Azure Functions CLI tools, answer yes. You may then be warned that Windows Firewall has "blocked some features of this app." If that happens, click **Allow access** to unblock the CLI tools.
1. Wait for execution to stop at the breakpoint on line 27. Then hover the cursor over the ```inputMessage``` parameter to view the JSON payload sent from the device to the IoT Hub and input to the Azure Function.
> If the breakpoint is never hit but your MXChip IoT DevKit is plugged in and transmitting data, then the Azure Function isn't properly connected to the IoT Hub. If that's the case, confirm that the setting named "IoTHubConnection" in **local.settings.json** contains the connection string and IoT Hub name shown in Step 10 of this exercise.
![Viewing the input message in the debugger]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/vs-view-debug-info.png" | absolute_url }})
_Viewing the input message in the debugger_
1. Stop the debugger and remove the breakpoint from line 27.
The fact that the breakpoint was hit tells you that the IoT Hub is receiving messages from the device and that the Azure Function is being triggered when messages arrive. But at the moment, the Function is running locally. Testing Functions locally is a great way to work the bugs out and make sure they work as expected. But the ultimate home for an Azure Function is in the cloud.
<a name="Exercise4"></a>
### Exercise 4: Deploy the Azure Function to the cloud ###
In this exercise, you will use Visual Studio to deploy an Azure Function App containing the Azure Function that you wrote in the previous exercise.
1. In Solution Explorer, right-click the FlySimFunctions project and select **Publish...**. Make sure **Azure Function App** and **Create New** are selected, and then click the **Publish** button.
![Publishing an Azure Function App]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/vs-select-publish.png" | absolute_url }})
_Publishing an Azure Function App_
1. In the ensuing "Create App Service" dialog, select the "FlySimResources" group so the Function App will be added to the same resource group as the other resources you've created, and select the storage account that you created in [Exercise 2](#Exercise2). Click the **New...** button next to "App Service Plan" and create a new App Service plan named "FlySimFunctionsPlan" in the East US region. Then click the **Create** button.
> Azure Function Apps deployed with an App Service plan are billed at [normal App Service rates](https://azure.microsoft.com/pricing/details/app-service/). Function Apps can also employ a consumption plan that bills based on execution time, but Functions running under the consumption plan aren't guaranteed to execute immediately. For more information on consumption plans versus App Service plans, see [Azure Functions hosting plans comparison](https://docs.microsoft.com/azure/azure-functions/functions-scale).
![Entering Function App parameters]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/vs-create-app-service-dialog.png" | absolute_url }})
_Entering Function App parameters_
1. Wait for the Function App to be deployed. (It typically takes a few minutes.) Then return to the "FlySimResources" resource group in the Azure portal and click the Function App.
![Opening the Function App]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/open-function-app.png" | absolute_url }})
_Opening the Function App_
1. Click **Application settings**.
![Opening application settings for the Function App]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/portal-click-app-settings.png" | absolute_url }})
_Opening application settings for the Function App_
1. Click **+ Add new setting** in the "Application settings" section. Add a setting named "IoTHubConnection" and set its value equal to that of the setting with the same name in **local.settings.json**. Then add a setting named "EventHubConnection" whose value equals that of the same setting in **local.settings.json**. When you're finished, click **Save** at the top of the blade.
> When you tested the Function locally, these settings came from **local.settings.json**. Now that the Function is running in the cloud, the same settings will come from the Function App's application settings.
![Adding application settings]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/portal-add-app-settings.png" | absolute_url }})
_Adding application settings_
1. Make sure your MXChip IoT DevKit is plugged in and transmitting data. Then click the Function name in the menu on the left. Watch the output log at the bottom of the screen and confirm that the Function is sending and receiving data. A new entry should appear in the output log every couple of seconds. Observe that the JSON output includes properties such as "Heading" and "Altitude."
> If the log shows no output but your MXChip IoT DevKit is plugged in and transmitting data, then the Azure Function isn't properly connected to the IoT Hub. If that's the case, review Step 5 of this exercise and confirm that the application setting named "IoTHubConnection" contains the connection string and IoT Hub name shown in Exercise 3, Step 10.
![The FlySimIoTFlightData Function running in the portal]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/portal-function-running.png" | absolute_url }})
_The FlySimIoTFlightData Function running in the portal_
The Azure Function that you wrote is now running in cloud, transforming accelerometer data reaching the IoT Hub into flight data, and sending the flight data to the Event Hub. Now comes the fun part: wiring the Event Hub up to a client app so you can use the MXChip IoT DevKit to fly an aircraft!
<a name="Exercise5"></a>
### Exercise 5: Connect the client app to the Event Hub ###
The "FlySim" folder in the lab's assets contains a Universal Windows Platform (UWP) app that you can run to fly a simulated aircraft on your laptop using your MXChip. Before you run it, you need to make some modifications to connect it to the Event Hub that receives data from the Azure Function.
1. Go to the "FlySim" folder included in the lab download and open **FlySim.sln** in Visual Studio.
1. Right-click the FlySim solution in Solution Explorer and select **Restore NuGet Packages** to load all the dependencies.
1. Repeat Steps 12 through 14 of [Exercise 3](#Exercise3) to copy the Event Hub's connection string to the clipboard.
1. Return to Visual Studio and open **CoreConstants.cs** in the project's "Common" folder. Replace EVENT_HUB_ENDPOINT on line 11 with the connection string that's on the clipboard.
1. Right-click the project in Solution Explorer and use the **Add** > **New Folder** command to add a folder named "Listeners."
1. Right-click the "Listeners" folder in Solution Explorer and use the **Add** > **Class...** command to add a class file named **FlightActivityListener.cs**. Then replace the contents of the file with the following code:
```csharp
using System;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Devices.Geolocation;
using Windows.UI.Core;
using FlySim.Common;
using Newtonsoft.Json;
using ppatierno.AzureSBLite.Messaging;
namespace FlySim.Listeners
{
public class FlightActivityListener
{
private EventHubClient client { get; set; }
private EventHubConsumerGroup consumerGroup { get; set; }
private EventHubReceiver receiver { get; set; }
private FlightInformation flightInformation { get; set; }
private ObservableCollection<ActivePlaneInformation> activePlanes { get; set; }
private bool isInitialized { get; set; }
public async void StartListeningAsync(FlightInformation flightInformation,
ObservableCollection<ActivePlaneInformation> activePlanes)
{
this.activePlanes = activePlanes;
this.flightInformation = flightInformation;
var connectionString = $"{CoreConstants.FlightActivityEventHubEndpoint};EntityPath={CoreConstants.FlightActivityEventHubName}";
client = EventHubClient.CreateFromConnectionString(connectionString);
consumerGroup = client.GetDefaultConsumerGroup();
receiver = consumerGroup.CreateReceiver("0", DateTime.Now.ToUniversalTime());
await Task.Run(() => StartListeningForFlightActivityCommands());
}
private async void StartListeningForFlightActivityCommands()
{
while (true)
{
await Task.Delay(1);
var eventData = receiver.Receive();
if (eventData != null)
{
var bytes = eventData.GetBytes();
var payload = Encoding.UTF8.GetString(bytes);
var flightInfo = JsonConvert.DeserializeObject<NewFlightInfo>(payload);
UpdateFlightInformation(flightInfo);
}
}
}
private async void UpdateFlightInformation(NewFlightInfo info)
{
var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
flightInformation.Hydrate(info);
activePlanes.Add(new ActivePlaneInformation
{
DisplayName = info.deviceId,
Location = new Geopoint(new BasicGeoposition
{
Latitude = info.latitude,
Longitude = info.longitude
})
});
activePlanes.RemoveAt(0);
App.ViewModel.SetFlightStatus(info.deviceId);
if (!isInitialized)
{
isInitialized = true;
App.ViewModel.BringPlaneIntoView(info.latitude, info.longitude);
}
});
}
}
}
```
```EventHubClient```, ```EventHubReceiver```, and other classes used here come from a popular NuGet package named [AzureSBLite](https://github.com/ppatierno/azuresblite). These classes make it extremely easy to connect to Azure Event Hubs and receive events from them asynchronously. The call to ```EventHubReceiver.Receive``` is performed on a background thread, and it blocks until a message arrives at the Event Hub. After the message is retrieved and deserialized, it is passed to ```UpdateFlightinformation```, which uses ```Dispatcher.RunAsync``` to marshal back to the UI thread and update the UI.
1. Open **MainViewModel.cs** in the project's "ViewModels" folder and the following ```using``` statement to those at the top of the file:
```csharp
using FlySim.Listeners;
```
1. Now add the following statement just before the class constructor:
```csharp
public FlightActivityListener FlightActivityListener = new FlightActivityListener();
```
This statement creates an instance of the ```FlightActivityListener``` class you created in the previous step and assigns it to a public field.
1. Add the following statement to the ```MainViewModel``` class's ```InitializeSystem``` method to start listening for events from the Event Hub when the app starts up:
```csharp
FlightActivityListener.StartListeningAsync(CurrentFlightInformation, ActivePlanes);
```
1. Save your changes and build the solution to make sure it builds successfully.
1. Reset your aircraft to its default starting position over the Nevada desert by going to the Function App in the Azure Portal and clicking **Restart**.
![Restarting the Function App]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/restart-function-app.png" | absolute_url }})
_Restarting the Function App_
1. Make sure your MXChip IoT DevKit is plugged into your laptop. Then return to Visual Studio and press **Ctrl+F5** to launch FlySim. Confirm that the app starts and that after a few seconds, an "aircraft" labeled with the display name you entered in [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}) appears on the screen. Maximize the window so you can see all the readouts and controls.
> If your aircraft never appears in the app but your MXChip IoT DevKit is plugged in and transmitting data, review Step 4 of this exercise and confirm that the connection string you pasted into **CoreConstants.cs** is the one shown in Exercise 3, Step 14. Also review Exercise 4, Step 5 and make sure the application setting named "EventHubConnection" contains the same connection string.
![FlySim showing Amelia Earhart over the Nevada desert]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight.png" | absolute_url }})
_FlySim showing Amelia Earhart over the Nevada desert_
1. Hold the MXChip IoT DevKit in the palm of your hand so that the gold connectors are at the rear (pointed toward your body). Imagine that the MXChip IoT DevKit is an aircraft, and that the end with the gold connectors is the tail of the plane and the end with the micro-USB connector is the nose of the plane.
1. Tilt the board to the right and confirm that the artificial horizon rotates accordingly. Note that the artificial horizon will rotate in the **opposite direction of the board** — just like the artificial horizon in the instrument panel of a real plane. Also confirm that if you hold the right turn, the heading readout increases and the airplane on the map rotates clockwise.
> Expect a slight delay between the time you move the board and the app responds. Most of the delay is due to the fact that the app running on the MXChip IoT DevKit is only transmitting events every couple of seconds. The latency resulting from events being transmitted from the MXChip IoT DevKit to an IoT Hub in the cloud, then transformed, sent to an Event Hub, and transmitted down to the client app is minimal unless you have a very slow Wi-Fi connection.
![Making a right turn]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/app-turning.png" | absolute_url }})
_Making a right turn_
1. Now level the wings and tilt the nose of the plane up. Confirm that the background of the artificial horizon shifts down showing more blue, indicating that the plane is in a nose-up attitude. Also confirm that if you keep the nose up, the altitude readouts in the instrument panel and on the map increase over time.
> Tip: If your plane flies off the screen and is no longer visible on the map, click the airplane in the artificial horizon to bring it back into view.
![Pointing the nose up]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab2/app-ascending.png" | absolute_url }})
_Pointing the nose up_
Practice flying around until you feel confident in your ability to control the plane. Try flying a straight heading while maintaining a constant altitude. Also pick landmarks on the ground and practice flying around them at different altitudes. These skills will come in handy in [Lab 4]({{"/docs/projects/air-traffic-control-simulator-04/" | absolute_url }}).
<a name="Summary"></a>
## Summary ##
You can now fly a simulated aircraft using the MXChip IoT DevKit that you configured in [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}). An Azure Function transforms accelerometer data from the MXChip IoT DevKit into flight data, the flight data is transmitted to an Azure Event Hub, and a client app subscribes to events from the Event Hub so it can show the aircraft's position and attitude in real time.
In [Lab 3]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }}), you will add Azure Stream Analytics to the mix so it can see your peer's aircraft (or drones), determine when two aircraft are too close together, and transmit a warning to affected pilots. It's about to get very real — and very intense!

Просмотреть файл

@ -1,339 +0,0 @@
---
title: "Air Traffic Control Simulator - Lab 3"
permalink: /docs/projects/air-traffic-control-simulator-03/
excerpt: "Performing Real-Time Proximity Detection with Azure Stream Analytics"
part: 3
header:
overlay_image: /assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight.png
overlay_full: true
teaser: /assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight-th.jpg
difficulty: HARD
last_modified_at: 2017-10-30
---
{% include toc icon="columns" %}
## Overview
[Azure Stream Analytics](https://azure.microsoft.com/services/stream-analytics/) is a cloud-based service for ingesting high-velocity data streaming from devices, sensors, applications, Web sites, and other data sources and analyzing that data in real time. It supports a [SQL-like query language](https://msdn.microsoft.com/library/azure/dn834998.aspx) that works over dynamic data streams and makes analyzing constantly changing data no more difficult than performing queries on static data stored in traditional databases. With Azure Stream Analytics, you can set up jobs that analyze incoming data for anomalies or information of interest and record the results, present notifications on dashboards, or even fire off alerts to mobile devices. And all of it can be done at low cost and with a minimum of effort.
Scenarios for the application of real-time data analytics are numerous and include fraud detection, identity-theft protection, optimizing the allocation of resources (think of an Uber-like transportation service that sends drivers to areas of increasing demand *before* that demand peaks), click-stream analysis on Web sites, shopping suggestions on retail-sales sites, and countless others. Having the ability to process data *as it comes in* rather than waiting until after it has been aggregated offers a competitive advantage to businesses that are agile enough to make adjustments on the fly.
In this lab, you, or one of your peers, will create an Azure Stream Analytics job and use it to analyze data streaming in from the simulated aircraft driven by the IoT device. Specifically, you will perform a query that identifies aircraft that are within a specified distance of each other in order to alert the pilots of those aircraft that evasive maneuvers might be required. Then you will connect the ATC app to the Stream Analytics inputs and outputs so that in [Lab 4]({{"/docs/projects/air-traffic-control-simulator-04/" | absolute_url }}), the ATC app can show all air traffic and color-code aircraft that are too close together.
<a name="Prerequisites"></a>
## Prerequisites ##
The following are required to complete this lab:
- An [MXChip IoT DevKit](https://microsoft.github.io/azure-iot-developer-kit/)
- A computer running [Windows 10 Anniversary Edition](https://www.microsoft.com/en-us/software-download/windows10) or higher
- Finish the [Getting Started Guide]({{"/docs/get-started/" | absolute_url }}) to:
* Have your IoT DevKit connected to Wi-Fi
* Upgrade to the latest firmware
* Prepare the development environment
- An active Azure subscription. If you do not have one, you can register via one of the methods:
* Activate a [free 30-day trial Microsoft Azure account](https://azure.microsoft.com/en-us/free/){:target="_blank"}
* Claim your [Azure credit](https://azure.microsoft.com/en-us/pricing/member-offers/msdn-benefits-details/){:target="_blank"} if you are MSDN or Visual Studio subscriber
- An available Wi-Fi connection or mobile hotspot. Note that the Wi-Fi connection can (and should) be secure, but it must be ungated (i.e. no intermediate login page is required. Gated Wi-Fi is common in public venues and hotels).
**Note:** For developers work on a Mac, please see [this article](https://docs.microsoft.com/en-us/windows/uwp/porting/setting-up-your-mac-with-windows-10) for installing Windows 10 to enable building and running the UWP portion of this lab.
{: .notice--info}
<a name="Lab-Sections"></a>
## Lab Sections ##
Here are labs that comprise this project:
- [Lab 1 - Getting started with the Azure MXChip IoT DevKit and Azure IoT]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }})
- [Lab 2 - Using Azure Functions and Azure Event Hubs to Process IoT Data.]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }})
- [Lab 3 - Performing Real-Time Proximity Detection with Azure Stream Analytics]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }})
- [Lab 4 - Complete the solution and enable Cloud-to-Device communication.]({{"/docs/projects/air-traffic-control-simulator-04/" | absolute_url }})
---
<a name="Exercises"></a>
## Exercises ##
This lab includes the following exercises:
- [Exercise 1: Create Event Hubs for input and output](#Exercise1)
- [Exercise 2: Create a Stream Analytics job](#Exercise2)
- [Exercise 3: Prepare a query and test with sample data](#Exercise3)
- [Exercise 4: Connect the ATC app to the Event Hubs](#Exercise4)
Estimated time to complete this lab: **45** minutes.
<a name="Exercise1"></a>
## Exercise 1: Create Event Hubs for input and output ##
Azure Stream Analytics supports several types of input, including input from Azure blobs, input from Azure Event Hubs, and input from Azure IoT Hubs. A single Azure Event Hub or IoT Hub can handle millions of events per second transmitted from devices spread throughout the world.
In this exercise, you will create two Azure Event Hubs. One will provide input to Stream Analytics, while the other will receive output from Stream Analytics. In the next lab, you will modify the Azure Function written in [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}) to transmit data to the input Event Hub, enabling Stream Analytics to see all activity emanating from all aircraft. You will also connect the client app to the output Event Hub and modify the app to transmit messages back to their MXChip IoT DevKits.
1. In your browser, navigate to the [Azure Portal](https://portal.azure.com). If you are asked to sign in, do so using your Microsoft account.
1. In the portal, click **+ New**, followed by **Internet of Things** and **Event Hubs**.
![Adding a new Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/new-event-hub.png" | absolute_url }})
_Adding a new Event Hub_
1. Type a namespace name into the **Name** box. The name must be unique within Azure, so make sure a green check mark appears next to it. Select **Create new** under **Resource group** and enter the resource-group name "cloud-city-rg" (without quotation marks). Choose the **East US** region in the **Location** drop-down, and then click the **Create** button.
> It is important to select the East US region to locate the Event Hub in the same region as the other resources. Keeping everything in one data center reduces cost and minimizes latency.
![Creating a namespace]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/create-namespace.png" | absolute_url }})
_Creating a namespace_
1. Click **Resource groups** in the ribbon on the left, and then click the resource group created in the previous step.
![Opening the resource group]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/open-resource-group.png" | absolute_url }})
_Opening the resource group_
1. Wait until "Deploying" changes to "Succeeded." (You can click the **Refresh** button at the top of the blade to refresh the deployment status.) Then click the namespace whose name you specified in Step 3.
![Opening the namespace]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/open-namespace.png" | absolute_url }})
_Opening the namespace_
1. Click **+ Event Hub** to add an Event Hub to the namespace.
![Adding an Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/add-event-hub.png" | absolute_url }})
_Adding an Event Hub_
1. Type "flysim-shared-input-hub" (without quotation marks) into the **Name** box. Then click the **Create** button.
![Creating an Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/create-input-hub.png" | absolute_url }})
_Creating an Event Hub_
1. Wait a moment for the Event Hub to be created. Then click **+ Event Hub** again.
![Adding an Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/add-event-hub.png" | absolute_url }})
_Adding an Event Hub_
1. Type "flysim-shared-output-hub" (without quotation marks) into the **Name** box. Then click the **Create** button.
![Creating an Event Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/create-output-hub.png" | absolute_url }})
_Creating an Event Hub_
1. Wait a moment for the Event Hub to be created. Then scroll to the bottom of the blade and confirm that both Event Hubs appear in the list. Also confirm the spelling, since the apps that connect to these Event Hubs assume that the Event Hubs are named exactly as shown.
![Event Hubs created for input and output]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/event-hubs.png" | absolute_url }})
_Event Hubs created for input and output_
1. Click **Shared access policies**, followed by **RootManageSharedAccessKey**.
![Opening the shared access key]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/open-shared-access-key.png" | absolute_url }})
_Opening the shared access key_
1. Click the **Copy** button next to "Connection string—primary key" to copy the connection string to the clipboard.
![Copying the connection string]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/copy-connection-string.png" | absolute_url }})
_Copying the connection string_
1. Go to https://gist.github.com/ and sign in with your GitHub account if you aren't already signed in. Type "Endpoint for connecting to shared input and output hubs" into the description box, and paste the connection string that's on the clipboard into the content box. Then click **Create public gist** to create a public gist. Leave your browser window open so you can easily retrieve the connection string in Exercise 4.
> Remember to delete this gist when you are finished since it contains a shared-access signature that allows anyone to connect to the Event Hubs you just created.
![Creating a gist]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/create-gist.png" | absolute_url }})
_Creating a gist_
You have created a pair of Event Hubs: one to provide input to Stream Analytics, and another to receive output from Stream Analytics. The next step is to create the Stream Analytics job itself.
<a name="Exercise2"></a>
## Exercise 2: Create a Stream Analytics job ##
In this exercise, you will use the Azure Portal to create a Stream Analytics job and connect it to the Event Hubs you created in [Exercise 1](#Exercise1). The purpose of the Stream Analytics job is to examine all positional data being transmitted by all aircraft and identify aircraft that are too close together — *precisely the type of service that air-traffic controllers provide*.
1. Return to the [Azure Portal](https://portal.azure.com) and click **+ New**, followed by **Internet of Things** and **Stream Analytics job**.
![Creating a Stream Analytics job]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/new-stream-analytics-job.png" | absolute_url }})
_Creating a Stream Analytics job_
1. Type "flysim-analytics" (without quotation marks) into the **Job name** box. Select **Use Existing** under **Resource group** and select the "cloud-city-rg" resource group that you created in [Exercise 1](#Exercise1). Select the **East US** region in the **Location** drop-down. Then click the **Create** button.
![Specifying parameters for the Stream Analytics job]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/create-stream-analytics-job.png" | absolute_url }})
_Specifying parameters for the Stream Analytics job_
1. Click **Resource groups** in the ribbon on the left, and then click the "cloud-city-rg" resource group.
![Opening the resource group]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/open-resource-group.png" | absolute_url }})
_Opening the resource group_
1. Wait until the Stream Analytics job is created. Then click **flysim-analytics** to open the Stream Analytics job in the portal.
![Opening the Stream Analytics job]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/open-stream-analytics-job.png" | absolute_url }})
_Opening the Stream Analytics job_
1. Click **Inputs** to add an input to the Stream Analytics job.
![Adding an input]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/add-input-1.png" | absolute_url }})
_Adding an input_
1. Click **+ Add**.
![Adding an input]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/add-input-2.png" | absolute_url }})
_Adding an input_
1. Type "FlightDataInput" (without quotation marks) into the **Input alias** box. Select the namespace that you created in Exercise 1 in the **Service bus namespace** drop-down, and select **flysim-shared-input-hub** as the **Event Hub name**. Fill out the remainder of the form exactly as shown, and then click the **Create** button at the bottom of the blade.
![Creating an input]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/create-input.png" | absolute_url }})
_Creating an input_
1. Confirm that the new input appears in the list of inputs to the Stream Analytics job.
![Confirming the input]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/confirm-input.png" | absolute_url }})
_Confirming the input_
1. Return to the blade for the Stream Analytics job and click **Outputs** to add an output.
![Adding an output]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/add-output-1.png" | absolute_url }})
_Adding an output_
1. Click **+ Add**.
![Adding an output]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/add-output-2.png" | absolute_url }})
_Adding an output_
1. Type "FlightDataOutput" (without quotation marks) into the **Output alias** box. Select the namespace that you created in Exercise 1 in the **Service bus namespace** drop-down, and select **flysim-shared-output-hub** as the **Event Hub name**. Fill out the remainder of the form exactly as shown, and then click the **Create** button at the bottom of the blade.
![Creating an input]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/create-output.png" | absolute_url }})
_Creating an input_
1. Confirm that the new output appears in the list of outputs.
![Confirming the input]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/confirm-output.png" | absolute_url }})
_Confirming the output_
You have connected a Stream Analytics job to an input Event Hub and an output Event Hub. The next step is to do something with it — specifically, to bring the power of Azure Stream Analytics to bear on the data flowing into the input hub.
<a name="Exercise3"></a>
## Exercise 3: Prepare a query and test with sample data ##
In this exercise, you will use the [Stream Analytics Query Language](https://msdn.microsoft.com/en-us/library/azure/Dn834998.aspx) to query a sample data set for aircraft that are too close together. It is always a good idea to test your queries against sample data before deploying them against live data streams, because with sample data, you can verify that a known set of inputs produces the expected outputs.
To identify aircraft that are too close together, the query will ask for all aircraft that are within four miles of each other. And it will use a [tumbling window](https://msdn.microsoft.com/en-us/library/azure/dn835055.aspx) to output a list of such aircraft every 2 seconds.
1. Return to the blade for the Stream Analytics job and click **Query**.
![Opening the query viewer]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/add-query.png" | absolute_url }})
_Opening the query viewer_
1. Click the **ellipsis** (the three dots) to the right of **FlightDataInput** and select **Upload sample data from file** from the menu.
![Uploading sample data for testing queries]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/upload-test-data-1.png" | absolute_url }})
_Uploading sample data for testing queries_
1. Click the **folder** icon on the right and select the file named **flysim-2-in-proximity.json** from the "resources" subdirectory of this lab. Then click **OK** to upload the file.
![Uploading flysim-2-in-proximity.json]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/upload-test-data-2.png" | absolute_url }})
_Uploading flysim-2-in-proximity.json_
1. When the upload is complete, enter the following query:
```sql
WITH Results AS
(
SELECT System.Timestamp as endtime,
F1.deviceId AS plane1, F2.deviceId AS plane2,
SQRT(SQUARE((F2.latitude - F1.latitude) * 364320) + SQUARE((F2.longitude - F1.longitude) * 364320) + SQUARE(F2.altitude - F1.altitude)) as distance,
COUNT(*)
FROM FlightDataInput F1 TIMESTAMP BY timestamp
JOIN FlightDataInput F2 TIMESTAMP BY timestamp
ON DATEDIFF(second, F1, F2) BETWEEN 0 and 2
AND SQRT(SQUARE((F2.latitude - F1.latitude) * 364320) + SQUARE((F2.longitude - F1.longitude) * 364320) + SQUARE(F2.altitude - F1.altitude)) < 21120
WHERE F1.deviceId != F2.deviceId
GROUP BY F1.deviceId, F1.latitude, F1.longitude, F1.altitude,
F2.deviceId, F2.latitude, F2.longitude, F2.altitude,
TumblingWindow(second,2)
)
SELECT plane1, plane2, distance INTO FlightDataOutput FROM Results
```
This query uses a [tumbling window](https://msdn.microsoft.com/library/azure/dn835055.aspx) to detect aircraft that are within four miles of each other and produce a list every two seconds. Aircraft that are within two miles of each are considered "at risk."
TIMESTAMP BY is an important element of the [Stream Analytics Query Language](https://msdn.microsoft.com/library/azure/dn834998.aspx). If it was omitted from the query, distance calculations would be performed based on the times that the events arrived *at the Event Hub* rather than the times specified in the data stream. TIMESTAMP BY allows you to specify a field in the input stream — in this case, the "timestamp" field — as the event time.
1. Click the **Save** button at the top of the blade to save the query. Then click the **Test** button to execute it against the sample data you uploaded.
![Testing a query]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/test-query.png" | absolute_url }})
_Testing a query_
1. Confirm that you see the output pictured below. The test data contains 20 rows of flight data for two aircraft. The data was intentionally constructed so that the two aircraft pass within four miles of each other. The output comprises a 20-second time period, and each row identifies two aircraft that were within four miles of each other during that time and the distance (in feet) that separates them.
![Query results]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/query-results.png" | absolute_url }})
_Query results_
1. With the query now formulated and tested against a set of sample data, it's time to start the Stream Analytics job so it can process live data. Return to the blade for the Stream Analytics job. Then click **Start**.
![Starting the Stream Analytics job]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/start-stream-analytics-job-1.png" | absolute_url }})
_Starting the Stream Analytics job_
1. Make sure **Job output start time** is set to **Now**, and then click the **Start** button to start running the job.
> Billing for a Stream Analytics job starts when the job is fully running. A Stream Analytics job configured to use one streaming unit costs a few cents an hour to run. For the latest information regarding pricing, see [Stream Analytics pricing](https://azure.microsoft.com/pricing/details/stream-analytics/).
![Specifying the job start time]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/start-stream-analytics-job-2.png" | absolute_url }})
_Specifying the job start time_
It will probably take the Stream Analytics job a minute or two to start, but that's OK because it's not receiving data at the moment anyway. The live data stream will start in [Lab 4]({{"/docs/projects/air-traffic-control-simulator-04/" | absolute_url }}) when you modify the Azure Function to send output to the shared input hub that provides input to Stream Analytics.
<a name="Exercise4"></a>
## Exercise 4: Connect the ATC app to the Event Hubs ##
Now it's time to connect the ATC app, which is located in the "AirTrafficSim" folder of the Cloud City download, to the Event Hubs you created in Exercise 1. The app, named **AirTrafficSim**, is a Universal Windows Platform (UWP) app. Connecting AirTrafficSim to the Event Hub named "flysim-shared-input-hub" enables it to see all the aircraft that are flying. Connecting it to the Event Hub named "flysim-shared-output-hub" lets it know when two aircraft are too close together so it can color them red. Modifying the app to connect to the Event Hubs is a simple matter of copying a connection string into the source code.
1. Open **AirTrafficSim.sln** in Visual Studio.
1. Right-click the AirTrafficSim solution in Solution Explorer and select **Restore NuGet Packages** to load all the dependencies.
1. Open **CoreConstants.cs** in the project's "Common" folder. Replace "SHARED_EVENT_HUB_ENDPOINT" on line 11 with the connection string you saved as a gist in Exercise 1, Step 13. Then save the file.
1. Press **Ctrl+F5** to launch the app. After a short delay, AirTrafficSim will load and display an empty air traffic control map somewhere over the Nevada desert. The flight-information panel (A) shows the number of aircraft that are flying and indicates how many are "safe" and how many are "at risk" — that is, within two miles of each other. The Altitudes panel (B) shows the altitudes of the aircraft. The traffic map (C) shows where the aircraft are, and the status bar (D) shows the current time and provides controls for zooming out to show all active flights and showing the original grid coordinates. You can zoom in and out by clicking the **+** and **-** buttons, or by placing the cursor over the map and rolling the mouse wheel. You can also pan by dragging the map.
![The AirTrafficSim app]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab3/app-environment-labels.png" | absolute_url }})
_The AirTrafficSim app_
AirTrafficSim won't show any activity until the pilots have connected to the Event Hubs, too. But we will take care of that in the next lab. The fun is about to begin!
<a name="Summary"></a>
## Summary ##
Azure Stream Analytics is a powerful tool for analyzing live data streams from IoT devices or anything else that transmits data. In this lab, you created a Stream Analytics job, configured a pair of Event Hubs to provide input and receive output, and formulated a query that examines a real-time data stream and determines when two aircraft are too close together.
In closing, be aware that a single Stream Analytics job can accept multiple inputs and outputs. If you wanted to create a permanent record of all the events produced by the query's tumbling window, for example, you could add a second output — a Cosmos DB output — to the Stream Analytics job. Then output would flow both to the Event Hub and to a [Cosmos DB](https://azure.microsoft.com/services/cosmos-db/) database, and you could dive into the database to view a history of close calls.
Continue on to [Lab 4]({{"/docs/projects/air-traffic-control-simulator-04/" | absolute_url }}) where you will complete the wiring up of the solution and set up Cloud-to-Device communication.

Просмотреть файл

@ -1,488 +0,0 @@
---
title: "Air Traffic Control Simulator - Lab 4"
permalink: /docs/projects/air-traffic-control-simulator-04/
excerpt: "Complete the solution and enable Cloud-to-Device communication."
part: 4
header:
overlay_image: /assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight.png
overlay_full: true
teaser: /assets/images/mini-solution/air-traffic-control-simulator/lab2/app-in-flight-th.jpg
difficulty: HARD
last_modified_at: 2017-10-30
---
{% include toc icon="columns" %}
## Overview
In the previous session, you or your peer created an [Azure Stream Analytics](https://azure.microsoft.com/services/stream-analytics/) job that analyzes incoming data for aircraft that are too close together. Additionally, you created a pair of Event Hubs: one to provide input to the Stream Analytics job, and another to receive output.
In this lab, you will close the loop by marrying what you built in Labs 1 and 2 with the Event Hubs and Azure Stream Analytics query built in [Lab 3]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }}) to assemble a complete end-to-end solution. First, you will modify the Azure Function you wrote in [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}) to transmit flight data to the shared input hub — the one that provides input to Stream Analytics — so Stream Analytics *and* the ATC app presented at the end of the previous session can see all of the aircraft.
![The ATC app with many planes in flight]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/atc-app.png" | absolute_url }})
_The ATC app with many planes in flight_
Second, you will connect the client app that you built in [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}) to the shared output hub — the one that receives output from Stream Analytics — so that when your aircraft comes too close to another and turns red in the ATC app, it turns red in the client app, too.
Third, you will modify the client app so that when it is notified that your aircraft is too close to another, it transmits a warning message back to the MXChip IoT DevKit through the IoT Hub that the device is connected to. The MXChip IoT DevKit will respond by displaying the warning on its screen and lighting an LED. To top it off, you will use [Microsoft Cognitive Services](https://azure.microsoft.com/services/cognitive-services/) to translate the warning message into the language of the user's choice.
Finally, you will join with your peers (or the drones spawned by the **FlySimTest** application) to fly through a crowded air-traffic control sector, and see all the different pieces of the solution work together to analyze large volumes of data in real time and help ensure that all planes arrive safely at their destinations.
<a name="Prerequisites"></a>
## Prerequisites ##
The following are required to complete this lab:
- An [MXChip IoT DevKit](https://microsoft.github.io/azure-iot-developer-kit/)
- A computer running [Windows 10 Anniversary Edition](https://www.microsoft.com/en-us/software-download/windows10) or higher
- Finish the [Getting Started Guide]({{"/docs/get-started/" | absolute_url }}) to:
* Have your IoT DevKit connected to Wi-Fi
* Upgrade to the latest firmware
* Prepare the development environment
- An active Azure subscription. If you do not have one, you can register via one of the methods:
* Activate a [free 30-day trial Microsoft Azure account](https://azure.microsoft.com/en-us/free/){:target="_blank"}
* Claim your [Azure credit](https://azure.microsoft.com/en-us/pricing/member-offers/msdn-benefits-details/){:target="_blank"} if you are MSDN or Visual Studio subscriber
- An available Wi-Fi connection or mobile hotspot. Note that the Wi-Fi connection can (and should) be secure, but it must be ungated (i.e. no intermediate login page is required. Gated Wi-Fi is common in public venues and hotels).
**Note:** For developers work on a Mac, please see [this article](https://docs.microsoft.com/en-us/windows/uwp/porting/setting-up-your-mac-with-windows-10) for installing Windows 10 to enable building and running the UWP portion of this lab.
{: .notice--info}
<a name="Lab-Sections"></a>
## Lab Sections ##
Here are labs that comprise this project:
- [Lab 1 - Getting started with the Azure MxChip and Azure IoT]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }})
- [Lab 2 - Using Azure Functions and Azure Event Hubs to Process IoT Data.]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }})
- [Lab 3 - Performing Real-Time Proximity Detection with Azure Stream Analytics]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }})
- [Lab 4 - Complete the solution and enable Cloud-to-Device communication.]({{"/docs/projects/air-traffic-control-simulator-04/" | absolute_url }})
---
<a name="Exercises"></a>
## Exercises ##
This lab includes the following exercises:
- [Exercise 1: Connect the Azure Function to the shared input hub](#Exercise1)
- [Exercise 2: Connect the client app to the shared output hub](#Exercise2)
- [Exercise 3: Update the client app to talk back to the device](#Exercise3)
- [Exercise 4: Test the finished solution](#Exercise4)
Estimated time to complete this lab: **60** minutes.
<a name="Exercise1"></a>
## Exercise 1: Connect the Azure Function to the shared input hub ##
In [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}), you deployed an Azure Function that reads input from an Azure IoT Hub, transforms accelerometer data coming from your MXChip IoT DevKit into flight data, and transmits the output to an Azure Event Hub that provides input to the FlySim app. In this exercise, you will add an output to the Azure Function so that it transmits the same flight data to the shared input hub created by the instructor in [Lab 3]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }}). Because you and your peers are making the same modification, and because the shared input hub provides data to the ATC app and to Stream Analytics, the ATC app will be able to show all the aircraft that are in the air, and the Stream Analytics job will be able to detect when aircraft come too close together.
1. Start Visual Studio and open the FlySimFunctions solution that you created in [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}).
1. Add the following parameter to the ```Run``` method:
```csharp
[EventHub("sharedouteventhub", Connection = "SharedEventHubConnection")] IAsyncCollector<string> sharedOutputMessage,
```
The modified method signature should look like this:
![The modified Run method]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/modified-function-1.png" | absolute_url }})
_The modified Run method_
The ```sharedOutputMessage``` parameter that you added represents output messages to the shared Event Hub.
1. Scroll down to the end of the ```Run``` method and add the following statement, just after the statement that calls ```outputMessage.AddAsync()``` and before the call to ```log.Info()```:
```csharp
await sharedOutputMessage.AddAsync(outputPayload);
```
The last four lines of the method should now look like this:
![The modified Run method]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/modified-function-2.png" | absolute_url }})
_The modified Run method_
The statement that you added transmits the same flight data to the shared Event Hub that is already being transmitted to the personal Event Hub created in [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}).
1. Open **local.settings.json** and insert the following statement directly below "EventHubConnection:"
```json
"SharedEventHubConnection": "SHARED_EVENT_HUB_ENDPOINT;EntityPath=flysim-shared-input-hub",
```
1. Navigate to the Gist URL you created in [Lab 3]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }}) (for example, https://gist.github.com/scottgu) and copy the connection string from the public gist to the clipboard. Leave the browser window open so you can easily retrieve this connection string again.
![Copying the connection string to the clipboard]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/copy-from-gist.png" | absolute_url }})
_Copying the connection string to the clipboard_
1. Return to Visual Studio and replace "SHARED_EVENT_HUB_ENDPOINT" in **local.settings.json** with the value on the clipboard.
1. Save your changes and rebuild the solution to ensure that it builds successfully. Then right-click the project in Solution Explorer and use the **Publish...** command to publish the updated Azure Function.
1. The next step is to add the shared input hub's connection string to the Function App's application settings. Go to the Azure Portal and open the Function App that you published in [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}). Then click **Application settings**.
![Opening application settings]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/open-application-settings.png" | absolute_url }})
_Opening application settings_
1. Click **+ Add new setting** in the "Application settings" section. Add a setting named "SharedEventHubConnection" and set its value equal to the connection string that you copied to the clipboard in Step 5. When you're finished, click **Save** at the top of the blade.
![Adding an application setting]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/new-application-setting.png" | absolute_url }})
_Adding an application setting_
1. Connect your MXChip IoT DevKit to your laptop if it isn't already connected. Confirm that it's sending data by watching for "IN FLIGHT" to appear on the screen of the device. Then turn to the ATC app and watch for your airplane to appear. If necessary, zoom the ATC app out so that all aircraft are visible. Seeing your airplane in the ATC app is confirmation that you did everything correctly in this exercise.
> If your airplane doesn't show up, go to the Azure Function in the portal and check the output log to make sure it's sending and receiving data. If it's not, unplug the MXChip IoT DevKit and plug it back in. If the Azure Function *is* sending and receiving data, double-check the application setting named "SharedEventHubConnection" you added in Step 9 of this exercise and make sure its value is the connection string you retrieved in Step 5.
The Azure Function has now been updated to send flight information to the shared input hub, enabling air-traffic control to be aware of your plane's location. Now it's time to connect the Event Hub that receives output from Stream Analytics to the client app so the client app can be notified when your airplane is too close to another.
<a name="Exercise2"></a>
## Exercise 2: Connect the client app to the shared output hub ##
In [Lab 3]({{"/docs/projects/air-traffic-control-simulator-03/" | absolute_url }}), you created an Event Hub and configured Stream Analytics to send output to it. You also connected the ATC app to the Event Hub so the app could highlight planes that are too close together on the air-traffic control map. In this exercise, you will connect the FlySim client app to the same Event Hub so it can notify individual pilots when the distance between their aircraft and any other is less than two miles.
1. Open the FlySim solution from [Lab 2]({{"/docs/projects/air-traffic-control-simulator-02/" | absolute_url }}) in Visual Studio.
1. Open **CoreConstants.cs** in the "Common" folder, and add the following statements after the statements that declare static strings named ```FlightActivityEventHubEndpoint``` and ```FlightActivityEventHubName```:
```csharp
public static string SharedAirTrafficEventHubEndpoint = "SHARED_EVENT_HUB_ENDPOINT";
public static string SharedAirTrafficHubName = "flysim-shared-output-hub";
```
1. Return to the gist that you opened in the previous exercise and copy the connection string to the clipboard again.
![Copying the connection string to the clipboard]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/copy-from-gist.png" | absolute_url }})
_Copying the connection string to the clipboard_
1. Return to Visual Studio and replace "SHARED_EVENT_HUB_ENDPOINT" in **CoreConstants.cs** with the value on the clipboard.
1. Right-click the "Listeners" folder in Solution Explorer and use the **Add** > **Class...** command to add a class file named **AirTrafficListener.cs**. Then replace the contents of the file with the following code:
```csharp
using Newtonsoft.Json;
using ppatierno.AzureSBLite.Messaging;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Core;
namespace FlySim.Listeners
{
public class AirTrafficListener
{
private EventHubClient client { get; set; }
private EventHubConsumerGroup consumerGroup { get; set; }
private EventHubReceiver primaryReceiver { get; set; }
private EventHubReceiver secondaryReceiver { get; set; }
readonly List<PlaneStatusInformation> statusInfo = new List<PlaneStatusInformation>();
private List<FilteredPlaneStatusInfo> filteredStatus = new List<FilteredPlaneStatusInfo>();
public async void StartListeningAsync()
{
this.client = EventHubClient.CreateFromConnectionString(Common.CoreConstants.SharedAirTrafficEventHubEndpoint, Common.CoreConstants.SharedAirTrafficHubName);
this.consumerGroup = this.client.GetDefaultConsumerGroup();
this.primaryReceiver = this.consumerGroup.CreateReceiver("0", DateTime.Now.ToUniversalTime());
this.secondaryReceiver = this.consumerGroup.CreateReceiver("1", DateTime.Now.ToUniversalTime());
await Task.Run(() => StartListeningForTrafficCommands());
}
private async void StartListeningForTrafficCommands()
{
while (true)
{
await Task.Delay(1);
try
{
var primaryEventData = this.primaryReceiver.Receive();
if (primaryEventData != null)
{
GeneratePlaneStatus(primaryEventData.GetBytes());
}
var secondaryEventData = this.primaryReceiver.Receive();
if (secondaryEventData != null)
{
GeneratePlaneStatus(secondaryEventData.GetBytes());
}
filteredStatus = new List<FilteredPlaneStatusInfo>();
filteredStatus.AddRange(from info in statusInfo select new FilteredPlaneStatusInfo() { DisplayName = info.Plane1, Distance = info.Distance, });
filteredStatus.AddRange(from info in statusInfo select new FilteredPlaneStatusInfo() { DisplayName = info.Plane2, Distance = info.Distance, });
var orderedPlanes = filteredStatus.OrderBy(o => o.Distance).GroupBy(g => g.DisplayName);
var finalPlaneStatus = from plane in orderedPlanes
select new
{
displayName = plane.Key,
minimumDistance = plane.First().Distance,
};
var atRiskPlanes = (finalPlaneStatus
.Where(item => item.minimumDistance < Common.CoreConstants.AtRiskThreshold)
.Select(item => item.displayName)).Distinct().ToList();
App.ViewModel.AtRiskPlanes = atRiskPlanes;
}
catch { }
}
}
private void GeneratePlaneStatus(byte[] bytes)
{
if (bytes == null) return;
statusInfo.Clear();
try
{
var payload = Encoding.UTF8.GetString(bytes);
foreach (var info in payload.Split("\r\n".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries))
{
var status = JsonConvert.DeserializeObject<PlaneStatusInfo>(info);
statusInfo.Add(new PlaneStatusInformation()
{
Plane1 = status.plane1,
Plane2 = status.plane2,
Distance = Convert.ToDouble(status.distance),
});
}
}
catch { }
}
}
}
```
The purpose of this code is to listen for events coming from the shared output hub and to update the view-model so that if your plane is among those "at risk," it turns red in the view. The heavy lifting is performed by the ```EventHubClient``` and ```EventHubReciver``` classes, which are part of the NuGet package [AzureSBLite](https://github.com/ppatierno/azuresblite).
1. Open **MainViewModel.cs** in the project's "ViewModels" folder and insert the following line of code below the ```FlightActivityListener``` property on line 40 to create an instance of ```AirTrafficListener```:
```csharp
public AirTrafficListener AirTrafficListener = new AirTrafficListener();
```
1. Still in **MainViewModel.cs**, locate the ```InitializeSystem``` method and add the following line of code to it:
```csharp
AirTrafficListener.StartListeningAsync();
```
1. Rebuild the solution and confirm that your changes compile successfully.
FlySim now has the smarts to turn your airplane red if it receives information from the shared output hub indicating that it's within two miles of another plane. But don't run it just yet. Let's further enhance the app to display a warning on the screen of the MXChip IoT DevKit when your plane is too close to another.
<a name="Exercise3"></a>
## Exercise 3: Update the client app to talk back to the device ##
One of the benefits of using Azure IoT Hubs is that they support bidirectional communication. Devices can send messages to IoT Hubs, and IoT Hubs can send messages back to the devices connected to them. In this exercise, you will modify the FlySim client app to send a message to your MXChip IoT DevKit through the IoT Hub it's connected to when your airplane is too close to another airplane. That message will command the MXChip IoT DevKit to display a warning message on its screen. For an added touch, you will use Microsoft Cognitive Services to translate the warning message into the language of the user's choice.
1. In Visual Studio, open **CoreConstants.cs** in the project's "Common" folder and insert the following statement after the statement declaring ```SharedAirTrafficHubName``` that you added in the previous exercise:
```csharp
public static string DeviceMessagingConnectionString = "IOT_DEVICE_ENDPOINT";
```
1. Return to the Azure Portal and open the IoT Hub that you created in [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}). Click **Shared access policies**, and then click **iothubowner**.
![Viewing shared access policies for the IoT Hub]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/open-shared-access-policies.png" | absolute_url }})
_Viewing shared access policies for the IoT Hub_
1. Click the **Copy** button to the right of "Connection string—primary key" to copy the connection string to the clipboard.
![Copying the connection string to the clipboard]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/portal-iot-hub-endpoint.png" | absolute_url }})
_Copying the connection string to the clipboard_
1. Return to Visual Studio and replace "IOT_DEVICE_ENDPOINT" in **CoreConstants.cs** with the connection string on the clipboard.
1. Right-click the "Helpers" folder in Solution Explorer and use the **Add** > **Class...** command to add a class file named **MessageHelper.cs**. Then replace the contents of the file with the following code:
```csharp
using Microsoft.Azure.Devices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FlySim.Helpers
{
public static class MessageHelper
{
public async static Task<bool> SendMessageToDeviceAsync(string message)
{
bool successful = false;
try
{
var serviceClient = ServiceClient.CreateFromConnectionString(Common.CoreConstants.DeviceMessagingConnectionString);
var commandMessage = new Message(Encoding.ASCII.GetBytes(message.ToUpper()));
await serviceClient.SendAsync("AZ3166", commandMessage);
successful = true;
}
catch(Exception) { }
return successful;
}
}
}
```
The ```MessageHelper``` class contains a method named ```SendMessageToDeviceAsync``` that transmits an ASCII message to the device connected to the IoT hub. The message is transmitted by calling ```SendAsync``` on an instance of the ```Microsoft.Azure.Devices.ServiceClient``` class, which is included in the NuGet package named Microsoft.Azure.Devices. A listener in the embedded code you uploaded to the device in [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}) handles the message and executes the appropriate commands to display the text contained in the message on the screen of the device for 5 seconds before reverting back to the normal "IN FLIGHT" display. It also lights the red LED on the board.
1. In the lower-right corner of the FlySim app, there is a ```ComboBox``` control containing a list of languages. The default is English. The purpose of the ```ComboBox``` is to allow you to select the language used for warning messages displayed on the screen of the MXChip.
The app retrieves a list of supported languages from the [Translator Text API](https://www.microsoft.com/translator/translatorapi.aspx), which is one of more than two dozen services available in [Microsoft Cognitive Services](https://azure.microsoft.com/services/cognitive-services/). The Translator Text API can translate text from English into more than 50 different languages. It can also provide a list of languages it can translate to, which forms the basis for the list you see in the ```ComboBox``` control.
In order to call the Translator Text API, you must go to the Azure Portal and obtain an API key. Calls to the Translator Text API work right now because **CoreConstants.cs** contains a key that was provided for you. Before going further, you need to obtain a key of your own and replace the one in **CoreConstants.cs**.
To that end, return to the [Azure Portal](https"//portal.azure.com) and click **+ New**, followed by **AI + Cognitive Services** and **See all**.
![Adding a Cognitive Service]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/new-translator-text-1.png" | absolute_url }})
_Adding a Cognitive Service_
1. Click **More** in the "Cognitive Service" section to see a list of all Cognitive Services.
![Viewing all Cognitive Services]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/new-translator-text-2.png" | absolute_url }})
_Viewing all Cognitive Services_
1. Scroll down and click **Translator Text API**. Then click the **Create** button at the bottom of the ensuing "Translator Text API" blade.
![Selecting the Translator Text API]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/new-translator-text-3.png" | absolute_url }})
_Selecting the Translator Text API_
1. Fill in the information shown below. Then click the **Create** button.
![Creating an API key]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/new-translator-text-4.png" | absolute_url }})
_Creating an API key_
1. Return to the "FlySimResources" resource group and click **translator-text-api-key**.
![Opening the API key]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/open-api-key.png" | absolute_url }})
_Opening the API key_
1. Click **Keys** in the menu on the left. Then click the **Copy** button to the right of "KEY 1" to copy the API key to the clipboard.
![Copying the API key to the clipboard]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/copy-api-key.png" | absolute_url }})
_Copying the API key to the clipboard_
1. Return to Visual Studio. In **CoreConstants.cs**, replace the value of the field named ```TranslatorTextSubscriptionKey``` with the API key on the clipboard.
1. The project already contains a class named ```TranslationHelper``` located in the "Helpers" folder. Open the file named **TranslationHelper.cs** in that folder and take a moment to examine the code. The class contains three methods. The one that translates text from one language to another is named ```GetTextTranslationAsync```. It uses the Universal Windows Platform's ```HttpClient``` class to place a REST call to the Translator Text API's HTTP endpoint with the API key embedded in an ```Ocp-Apim-Subscription-Key``` header. It is that simple to translate text when you utilize the Translator Text API.
1. Return to **MainViewModel.cs** in Visual Studio and replace the ```SendWarningMessage``` method with this one:
```csharp
private async void SendWarningMessage()
{
string message = "Warning";
if (!this.SelectedLanguage.DisplayName.Equals("English"))
{
message = await Helpers.TranslationHelper.GetTextTranslationAsync(message, this.SelectedLanguage.Abbreviation);
}
await Helpers.MessageHelper.SendMessageToDeviceAsync(message);
}
```
This method calls ```TranslationHelper.GetTextTranslationAsync``` to convert the warning message to the language selected in the ```ComboBox``` (unless English is selected, in which case no translation is necessary). Then it calls ```MessageHelper.SendMessageToDeviceAsync``` to send the message to the device.
1. Finish up by building the solution and verifying that it builds without errors.
The stage is set. The FlySim app is connected to the output from Stream Analytics so it can warn you when your airplane is too close to another. All that remains is to test it out. It's time to get back into the air. And this time, you won't be alone.
<a name="Exercise4"></a>
## Exercise 4: Test the finished solution ##
In this exercise, you will join your peers (or the drones spawned by the **FlySimTest** app) to fly your airplane through a crowded air-traffic control sector. And each time you come within two miles of another airplane, you will confirm that your airplane turns red in the ATC app and in the client app, and that the MXChip IoT DevKit alerts you to the danger.
1. Reset your aircraft to its default starting position over the Nevada desert by going to the Function App in the Azure Portal and clicking the **Restart** button.
![Restarting the Function App]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/restart-function-app.png" | absolute_url }})
_Restarting the Function App_
1. Make sure your MXChip IoT DevKit is plugged into your laptop. Then return to Visual Studio and press **Ctrl+F5** to launch the FlySim app. Confirm that the app starts and that after a few seconds, an aircraft labeled with the display name you entered in [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}) appears on the screen. Maximize the window so you can see all the readouts and controls.
> Remember that if your plane flies off the screen and is no longer visible on the map, you can click the airplane in the artificial horizon to bring it back into view.
![FlySim showing Amelia Earhart over the Nevada desert]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/app-in-flight.png" | absolute_url }})
_FlySim showing Amelia Earhart over the Nevada desert_
1. Use the ComboBox in the lower-right corner the of the client app to select the language in which you want proximity warnings to appear.
![Specifying a language preference]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/select-language.png" | absolute_url }})
_Specifying a language preference_
1. Turn to the ATC app running on the big screen in the front of the room and find your airplane. Navigate toward an airplane near you and try to get within two miles of it. Pay attention to the altitude of the two aircraft, because if one is at 10,000 feet and the other is at 30,000, they won't turn red even if their flight paths cross. Remember that you can control your altitude by tilting your MXChip IoT DevKit forward (down) and backward (up).
![Two airplanes approaching each other]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/two-approaching.png" | absolute_url }})
_Two airplanes approaching each other_
1. When you get within two miles of another aircraft, confirm that your airplane turns red in the client app AND in the ATC app.
> If your airplane doesn't turn red in the client app, review Exercise 2, Step 4 and confirm that the field named ```SharedAirTrafficEventHubEndpoint``` in **CoreConstants.cs** is assigned the connection string you retrieved in Exercise 2, Step 3.
![Two airplanes within two miles of each other]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/two-at-risk.png" | absolute_url }})
_Two airplanes within two miles of each other_
1. At the same time, check your MXChip IoT DevKit. Confirm that the red LED in the lower-left corner lights up, and that the screen displays a warning message in the language selected in Step 3. The message disappears after 5 seconds, so if you miss it, circle around and aim for another close encounter.
![Warning messages displayed in English, French, and Polish]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/warning-messages.png" | absolute_url }})
_Warning messages displayed in English, French, and Polish_
1. Continue flying until you're comfortable that your app — and your device — are working as expected. If your airplane freezes on the screen, try unplugging your MXChip IoT DevKit and plugging it back in again. And if, at any time, you would like to reset your aircraft to its original position, restart the Function App as you did at the beginning of this exercise.
When you're finished, unplug your MXChip IoT DevKit from your laptop to stop the flow of messages to the IoT Hub. Also go into the Azure Portal and stop the Function App since your subscription incurs charges while it's running, even if it isn't processing messages — that is, even when the VM that hosts the Function App is idle. If you want to stop all charges for all of the Azure resources you deployed today, simply go into the portal and delete the "FlySimResources" resource group. But be careful, because once a resource group is deleted, it can't be undeleted.
<a name="Summary"></a>
## Summary ##
Let's take a moment to review what you built today. Here is the architecture diagram presented at the start of [Lab 1]({{"/docs/projects/air-traffic-control-simulator/" | absolute_url }}):
![Solution architecture]({{"/assets/images/mini-solution/air-traffic-control-simulator/lab4/architecture.png" | absolute_url }})
_Solution architecture_
Your MXChip IoT DevKit transmits messages containing accelerometer data to an Azure IoT Hub. An Azure Function receives those messages and transforms the accelerometer data into flight data. Flight data flows to a personal event hub connected to the client app, and to a shared event hub that provides input to Azure Stream Analytics and to the ATC app. The Stream Analytics job analyzes the data for aircraft that are in close proximity and provides that information to the client app and the ATC app. When your aircraft comes too close to another, it turns red on the screen, and a warning appears on the screen of your MXChip IoT DevKit. Microsoft Cognitive Services translates the warning into the language selected in the client app.
This a great example of how enterprise developers build end-to-end solutions by connecting Azure services and utilizing those services from their code. And the fact that you could assemble it all in one day, from scratch, is indicative of the richness of the Azure ecosystem and of the tools that support it.
Cloud City — over and out!

Просмотреть файл

@ -351,7 +351,7 @@
<p><a href="http://www.mxchip.com/az3166" class="btn btn--inverse">Hardware Specs</a></p>
<p><a href="https://aka.ms/iot-devkit-purchase" class="btn btn--inverse">Hardware Specs</a></p>
</div>
</div>