UPDATED: The Sensor Telemetry project has been digitally remastered. Updated as of May 17th, 2017 and renamed to Sensor Telemetry 2.0.1Introduction
Overview
In this project, we will monitor a temperature sensor (MCP9808) and send telemetry readings to a Microsoft Azure IoT Hub where a Stream Analytics job will process the messages and write them to an Azure SQL Database table. We will use Mobile Apps to view the history of the sensor readings.
The Application
The project contains two Universal Windows Applications (on the Universal Windows Platform, UWP) that share about 99% of the code. One is targeted towards the Raspberry Pi (or ARM) and the other is targeted towards the x86 or x64 platforms.
The IoT version of the application runs on the Raspberry Pi and reads the temperature from the MCP9808. The application sends telemetry events to the Azure IoT Hub and the SignalR hub. This version will also listen for commands from the Azure IoT Hub.
The client version, started on a computer, will listen for sensor updates from the SignalR hub and display them on screen. This version will also send commands to the IoT version via the Azure IoT Hub.
Technologies
The application in this project is based on the MVVM (Model-View-ViewModel) pattern and was built using the Prism library and uses Prism.Unity for the IoC (Inversion of Control) container. In addition to these libraries, the application uses the Event Aggregator found in the Prism.Event library to create, as best as possible, a purely event-driven architecture. The application uses this library to allow the internal modules to communicate while remaining loosely coupled.
The application also uses SignalR on Azure Mobile App to allow multiple instances of the application to communicate with each other. The temperature readings are “broadcast” to all clients running remotely so that they can receive temperature sensor readings to display in the main view.
Architecture
At the heart of the application is the MCP9808 library built as a separate project that can be reused in other applications. This project is developed as a UWP library that can be used in any Windows 10 application. If the library is used on a device that does not have an I2C bus the library will not return any device object. This approach can be used to “detect” a sensor and gracefully ignore the library when a senor is not found.
In the UWP client application there are several blocks that make up the overall application. The Views are the visible pages and each view has a View Model responsible for the state of the View. There are three repositories: applications settings (IApplicationSettingsRepository), debugging information (IDebugConsoleRepository) and reading and writing the MCP9808 (ITemperatureRepository). There are two concrete classes built around ITemperatureRepository; one wraps the MCP9808 library and one is a null device used when the application is not running on the Raspberry Pi.
The class Mcp9808TemperatureRepository monitors the MCP9808 using the timer service and publishes temperature information via the internal event aggregator every time the temperature reading or alert status changes. A new event is sent only when the current reading is different from the previous reading.
There are also a series of services defined by IBackgroundService that run in the background for various activities.
The diagram below depicts a high level view of the architecture and the connectivity between the various blocks and services.
Telemetry Service
This service monitors the temperature-changed event (via a subscription) and sends a message to the Azure Service Bus Event Hub whenever the temperature changes.
Timer Service
This simple service is a timer that publishes an event every 500 milliseconds and is used by the view models to display the current time on a view. It is also used by the Mcp9808TemperatureRepository to read the sensor once every second. The timer event arguments include a counter that can be used with the mod function to easily divide the timer interval into the desired length. There is a method called IsMyInterval(TimeSpan interval) on the event argument that does the math for you. All you need to do is supply the interval as a TimeSpan object.
Alert Pin Monitoring Service
This service monitors the state of the GPIO pin connected to the alert pin on the MCP9808. When the value of the GPIO is changed, this service publishes an event.
LED Service
This service is responsible for turning the LEDs on and off. This is done by monitoring (via subscription) the temperature-changed event which also includes the alert status of the MCP9808. When the alert status changes the LEDs are updated accordingly.
Push Button Monitoring Service
This service monitors the GPIO pin connected to the push button and publishes an event when the button is released. This event is picked up by the Mcp9808TemperatureRepository when the device is in manual alert reset mode (MCP9808 interrupt mode). Debug events are also published so that the state of the button can be viewed in the debug console.
Notification Relay Service
The service monitors the SignalR hub and the internal event aggregator and relays messages between the two based on a predefined mapping (using the EventRelayMap class). This essentially allows the application to only be aware of the internal event system and still able to send and receive messages with other instances of the application.
Debug Console Service
This service monitors the applications (via subscription) for debugging events and adds them to an internal collection. It also implements DebugConsoleRepository, which allows the debug console view to display these events in the application via the View Model.
Application Initialization
When the application starts, it launches the StartPage view first, which automatically invokes the StartPageViewModel. This view model gets everything up and running before launching into the main view.
Getting StartedCircuit Requirements
The circuit requires a large, solderless breadboard, and optionally, a T-shaped cobbler and ribbon cable (I use the version sold by Vilros). The breadboard can be obtained from a multitude of places (I've purchased from local stores and from Amazon). The circuit also uses a momentary tactile push button switch with four pins. There are many types; any will do. Finally, for the temperature sensor, I am using the MCP9808 High Accuracy I2C Temperature Sensor Breakout Board from Adafruit.
The circuit can be built without the cobbler. Simply follow the alternate breadboard diagram at the end of the project.
Circuit Assembly
Use this guide to assemble the circuit while using the diagram located near the bottom of the page as a guide (note: the color of the wires are optional and have been selected to help make the circuit easy to follow when it is constructed).
- Place each of the four LEDs onto the breadboard.
- Connect one end of a 220 Ω resistor to the anode of each LED and connect the other end of the resistor to the 3V3 (pin 1 or 17) on the Raspberry Pi. All four LED anodes should be connected to 3V3 via a 220 Ω resistor. It is best to use one of the + rails on your breadboard for the 3V3 connections.
- Place the MCP9808 onto the breadboard.
- Connect Vdd on the MCP9808 to the 3V3 on the Raspberry Pi.
- Connect GND on the MCP9808 to GND on the Raspberry Pi. Ground on the Raspberry Pi can be any of the following pins: 6, 9, 14, 20, 25, 30, 34 and 39.
- Connect SCL on the MCP9808 to SCL on the Raspberry Pi (pin 5).
- Connect SDA on the MCP9808 to SDA on the Raspberry Pi (pin 3).
- Connect a 10K Ω resistor between the Alert pin on the MCP9808 and 3V3 on the Raspberry Pi.
- Connect the Alert pin on the MCP9808 to the GPIO 6 (pin 31) on the Raspberry Pi.
- Place the push button switch onto the breadboard.
- Connect one side of the switch to GPIO 5 (pin 29) on the Raspberry Pi.
- Connect the other side of the switch GND on the Raspberry Pi.
- Connect a 10K Ω resistor between the GPIO 5 and 3V3 on the Raspberry Pi.
Below are some photos of the circuit I built using the cobbler.
If you do not have an Azure account, you will need to create one. You can get a $200 credit when you start your account. Go to azure.com and click the FREE ACCOUNT link. If you already have an account, sign in to the portal at portal.azure.com.
NOTE: This guide is not an exhaustive guide to configuring Azure. You may need to familiarize yourself with the portal if you have never used it before. I will walk through the steps necessary for this project as best I can.
Leave yourself logged into the Azure portal during the entire setup process. You will need to refer back to it many times.
Azure IoT Event Hub Setup
- Select New in the left menu of the portal.
- Select Internet of Things
- Select Iot Hub
- Enter a unique name for your hub.
- Select a subscription.
- Under Resource Group select Create New and enter a name for your group. Note you will use this group for all Azure resources created during this project.
- Choose a location (try to keep all resources in the same region to keep charges low).
- If this is your first IoT hub, select Pricing and scale tier. Then select F1 Free. You can have one free tier in your account.
- Finally, click create and wait for the IoT Hub to be created.
- Click IoT Hub in the left menu to see the new hub.
- Click the new hub to see an overview of the details. You will need to refer back to this view later.
Create a Device
The Azure IoT Hub requires that each device be uniquely identified and registered in the hub for security purposes. A device can be registered using the Azure SDK and code, but for this project we will use the Device Explorer available in the Azure SDK.
- Download the Azure SDK from GitHub from https://github.com/Azure/azure-iot-sdk-csharp either by getting the zip file or cloning the repository.
- If you downloaded the zip file, expand it to a folder on your disk.
- Open the folder azure-iot-sdk--csharp-master\tools\DeviceExplorer.
- Open the DeviceExplorer project in Visual Studio.
- Run the application.
- Go back to the Azure portal and select your IoT Hub. Click the Shared access policies link and select iothubowner. Click the copy button next to the Connection string - primary key.
- In the Device Explorer window, paste this string into the text box labeled IoT Hub Connection String.
- Click the Update button.
- Change to the Management tab in the Device Explorer and click Create.
- Type a name for your device (example, TemperatureDevice1).
- Make sure the Auto Generate Keys check box is selected and click Create.
- Click Done.
- You will need to come back to this application to get the device connection string later.
Azure SQL Database Setup
The telemetry data will be stored in an Azure SQL Database. Use the portal to create the database.
- Click SQL Databases in the portal menu.
- Click the Add button.
- Enter a name for the database (i.e. SensorTelemetry)
- Select a subscription.
- For Resource group choose Use existing and select Sensor Telemetry from the drop down.
- Click the server link to setup a new server.
- Enter a name for the server.
- Enter a user name (you will need this later, so remember it).
- Enter a password (you will need this later, so remember it).
- Choose a location (try to keep all resources in the same region to keep charges low).
- Click Select.
- Click Pricing tier.
- Select Basic.
- Click Select.
- Click Create.
- Click the new server in the SQL Server list,
- Click the Set server firewall to allow access from your computer to the SQL Server.
- Enter a name for the connection and your external IP address in the Start IP and End IP range.
- Click the ellipses to save the entry.
- Click Save to save the IP address.
Create the Database Table
The table used will be created manually. Code First deployment can be used in Mobile Apps, but the table created will not be compatible with Stream Analytics.
- Open Visual Studio.
- Select SQL Server Object Explorer from the View menu.
- Right-click the SQL Server object and select Add SQL Server.
- Browse the Azure databases and select the database you created in the previous step.
- Enter your username and password and click Connect.
- Expand the object explorer items until you see the database you created.
- Right-click this database and choose New Query.
- Copy the SQL script from the bottom of this project page and paste it into the Visual Studio code window.
- Select Execute from the SQL menu to run the script.
- Expanding the tables object in the explorer will reveal the newly created table called SensorReadings.
Create the App Service Plan
The App Service Plan is required for creating an App Service.
- Select App Service plans in the portal menu.
- Enter a name for the plan.
- For Resource group choose Use existing and select Sensor Telemetry from the drop down.
- Chose a location.
- Click Pricing tier and select B1 Basic.
- Click Create.
Create the App Service (Mobile App)
The web site and SignalR hub will run with an App Service.
- Click New from the portal menu.
- Choose Web+Mobile from the list.
- Choose Mobile App.
- Enter a name for the application.
- Select a subscription.
- For Resource group choose Use existing and select Sensor Telemetry from the drop down.
- Chose the App Service Plan you created in the previous step.
- App Insights is optional.
- Click Create.
Azure Stream Analytics Setup
The Stream Analytics job will monitor data events on the IoT Hub and write them to a SQL Server database. The job will consist of an input (the IoT Hub), and output (the SQL Table) and a Query that chooses which fields to use.
- Choose New.
- Select Data + Analytics from the menu.
- Select Stream Analytics Job from the menu.
- Enter a unique name for the job.
- Select a subscription.
- For Resource group choose Use existing and select Sensor Telemetry from the drop down.
- Choose a location (try to keep all resources in the same region to keep charges low).
- Click Create.
- Select More Services > from the menu.
- Scroll down to Stream Analytics and click the star. This will pin it to the portal menu.
- Click Stream Analytics jobs in the portal menu.
- Select the job you just created.
- Click Inputs.
- Click Add.
- Enter a name for the input (i.e. SensorTelemetry-Input).
- Change the source to IoT Hub.
- Accept the remaining default values.
- Click Create.
- Click Outputs.
- Click Add.
- Enter a name for the output (i.e. SensorTelemetry-Output).
- Select SQL Database as the sink.
- Select the Sensor Telemetry database.
- Enter the user name you specified when you created the database server.
- Enter the password you specified when you created the database server.
- Enter SensorReadings for the table name.
- Click Create.
- Select Query.
- Replace the text [YourOutputAlias] with the name of the output (keeping the square brackets).
- Replace the text [YourInputAlias] with the name of the input (keeping the square brackets).
- Replace the asterick (*) with this text: [TimestampUtc], Source, Temperature, IsCritical, IsAboveUpperThreshold, IsBelowLowerThreshold
- Click Save and then click Yes if prompted.
- Click Overview in the Stream Analytics job menu.
- Click the Start button.
- Choose Now.
- Click Start.
Using the repository link at the bottom of the page, either download the code as a zip file or clone the repository to your computer and open the project in Visual Studio.
Configure and Publish the Mobile App
The web application (located in the Web folder) needs to be published to the Azure App Service.
- Right-click the project in Visual Studio and select Publish.
- Click Microsoft Azure App Service.
- Select your App Service from the list (you may need to log in if this is the first time).
- Click OK.
- Click Next.
- Go to the Azure portal
- Select SQL Databases from the portal menu.
- Select your database.
- Click the Show database connection strings link.
- Click the copy button next to ADO.NET string.
- Go back to Visual Studio and paste this string into the text box labeled MS_TableConnectionString.
- Change the user name and password to the values you set when you created the SQL Server.
- Click Next.
- Click Publish.
- When the publish has completed, a browser will be launched pointed at your new web site.
Enter the IoT Hub Credentials
Before running the application, you will need to enter your IoT Hub device credentials into the code.
- Open the project in Visual Studio.
- Expand the Sensor Telemetry project under the UWP folder and open the code behind for the App.xaml.
- Scroll down to the section with the definition for IIotHubConfiguration.
- Open the Device Explorer project in another instance of Visual Stduio.
- Click to the Management tab.
- Right-click the device you created previously.
- Click the Copy connection string for selected device option in the menu.
- Go back to the Sensor Telemetry prject and paste the connection string over the text {YOUR CONNECTION STRING HERE}.
- Enter the name of the device over the text {YOUR DEVICE ID HERE}.
- Save this file.
- Expand the Sensor Telemetry IoT project and find the code behidn for App.xaml.
- Scroll down to the section with the definition for IIotHubConfiguration.
- Copy and paste the same configuration from the previous app.cs file.
Enter the Mobile App URL
The Mobile App URL also needs to be entered into the code.
- Open the project in Visual Studio.
- Expand the Shared project.
- Open the UnityConfiguration.cs.
- Scroll down to the section containng the IMobileServicesConfiguration definition.
- Open the Azure portal.
- Click App Services.
- Select the App Service you created for this project.
- Hover the mouse over the URL and click the Copy icon.
- Goback to Visual Studio and paste the URL over the text {YOUR MOBILE SERVICES URL HERE}.
- Save the file.
The application can be run through the Visual Studio debugger deployed to the target machine and run as a normal application. When targeting a laptop or desktop, choose between x86 or x64. When targeting the Raspberry Pi 2 or 3, select the ARM configuration.
To run the application from the debugger, select the appropriate application and set it as the startup application. Press F5 to start the application in debug mode. If you are targeting the Raspberry Pi, the application will deploy first. After it has deployed, the application will be started and the debugger will attach to the process.
Ensure that you have configured your Raspberry Pi and that you have the latest tools from Microsoft. Follow the guide at the Windows IoT Dev Center Getting Started Guide.
Deploy the application to your Raspberry Pi.
- Open the project in Visual Studio.
- Select ARM as the target platform.
- Change the target device to Remote Machine.
- If your device was shown in the Auto Detected section, click the device and click Select.
- If not, enter the IP Address of your Raspberry Pi manually and click Select the IP Address is displayed on the Raspberry Pi screen).
- Right-click the project called Sensor Telemetry IoT.
- Click Deploy.
- Watch the Output window to know when it has completed.
Deploy the application to your local machine.
- With the project still open in Visual Studio...
- Select x86 or x64 as the target platform.
- Change the target device to Local Machine.
- Right-click the project called Sensor Telemetry.
- Click Deploy.
- Watch the Output window to know when it has completed.
Start the application on the Raspberry Pi.
- Start the Windows 10 IoT Core Dashboard application.
- Right-click your device and select Open in Device Portal.
- Log in to the device with your credentials.
- Select Apps from the menu.
- Select the Start button next to the Sensor Telemetry IoT application.
Start the application on your local machine.
- Enter the text Sensor in your Cortana search window.
- Click the Sensor Telemetry icon.
Screen Shots
The following images are screen shots of the application running on the Raspberry Pi.
Below is a video demonstration of the application.
Where to go Next?Try Power BI
Connect your IoT Hub to Power BI: The data collected from the temperature sensor via the IoT Hub can be sent to Microsoft Power BI to create reports and dashboards or to perform analytics. The data can also be combined with other data sources for advanced analysis.
To send the data to Power BI, you will modify the Stream Analytics job you previously created by adding a new output and modifying the query.
- Open the Azure portal.
- Click the Stream Analytics jobs menu.
- Select the job you created previously.
- If the job is currently running, click Stop.
- Click Outputs.
- Select Add.
- Give the output a unique name (i.e. SensorTelemetry-BI).
- Select Power BI as the sink.
- Click Authorize to link your Office 365/Power BI account. If you do not have one you can create a new account by clicking the Sign Up link.
- Enter SensorTelemetry for the Dataset Name.
- Enter SensorReadings for the Table Name.
- Click Query.
- Add the following query text under the current query text: SELECT [TimestampUtc], Source, Temperature, IsCritical, IsAboveUpperThreshold, IsBelowLowerThreshold INTO [SensorTelemetry-BI] FROM [SensorTelemetry-Input].
- Save the query.
- Close the Query window by clicking the X in the upper-right corner.
- Start the job.
Using the Data in Power BI: Log into your Power BI account to view the data feed. The data source named SensorTelemetry will show up in the menu under the Datasets menu. Click the data source to build a new report
- Click SensorTelemetry under Datasets.
- Build a report using the various controls.
- Save the report.
- Click Pin Live Page to pin the report to a new dashboard.
- Select New dashboard.
- Click Pin Live to save the dashboard.
- Give you dashboard a name.
The screen shot below is a sample report created in the web interface.
Using Azure SQL Database: It is also possible to connect directly to the Azure SQL Database with Power BI, but this requires the desktop version. There is a download link in the upper-right corner of the web version.
Download and install the desktop version. After it has been installed, open it and log into your account. Select Get data in the tool bar. Select Azure from the list on the left and select Microsoft Azure SQL Database. Enter the name of the server and use the credentials you entered when you created the database server (select Database as the type of credentials). Lastly, expand the database and choose the SensorReadings table and finally, click Load.
Stream Analytics Windowing
Using Windowing in Stream Analystics Jobs: The Stream Analytics jobs can be used to aggregate data. If the device is sending a temperature update ever 1 second, having this data stream to another service may be too much information to be useful. Perhaps receiving an average temperature over a period of time would be more useful.
There are a lot of options available, so providing an in-depth explanation is beyond the scope of this article. For more information, see the Azure documentation on Windowing.
To create a simple averaging window, use the query shown below.
SELECT
DateAdd(second,-15,System.TimeStamp) AS WindowStartTime, System.TimeStamp AS WindowEndTime, Source, AVG(Temperature)
INTO
[SensorTelemetry-Output]
FROM
[SensorTelemetry-Input]
GROUP BY Source, SLIDINGWINDOW(Duration(second, 15))
This query will average using a sliding window every 15 seconds. It can be added to a job and then used to write data to a SQL Database or to Power BI just like the query we used previously in the project.
The image below shows a quick Power BI report I created using the data. This report contains a line graph with the average temperature plotted against the start timestamp of the window in which the average was taken.
Use TPM to Store Credentials
The credentials used to connect the device to the Azure IoT Hub can be stored in a Trusted Platform Module (TPM). The Raspberry Pi does not have a TPM, but Windows 10 IoT Core provides a software module for testing.
- Open the device portal on your Raspberry Pi.
- Select TPM Configuration from the menu.
- If not installed, install the software emulator. The device will need to reboot.
- Select a Logical device ID of 0.
- Enter the Azure IoT Hub URL in hostname.
- Enter the Device ID and the Device Primary Key. Remember you can get these from the Device Explorer. Open the Device Explorer in Visual Studio and run it. You may need to obtain the connection string for the iothubowner access policy from the Azure portal.
- Save the configuration in the device portal.
The code requires a NuGet package called Microsoft.Devices.Tpm (this package is already installed in the solution). The code to use the stored TPM configuration is shown below.
// ***
// *** Create a TpmDevice to access the credential information. Specify
// *** a logical device ID of 0 (this is the slot we used to store the
// *** credentials).
// ***
uint logicalDeviceId = 0;
TpmDevice tpm = new TpmDevice(logicalDeviceId);
// ***
// *** Get the connection properties from the TPM.
// ***
string uri = tpm.GetHostName();
string deviceId = tpm.GetDeviceId();
string sasToken = tpm.GetSASToken();
// ***
// *** Create the device connection.
// ***
this.DeviceClient = DeviceClient.Create(uri, AuthenticationMethodFactory.CreateAuthenticationWithToken(deviceId, sasToken));
To enable the TPM in the Sensor Telemetry solution, open the app.xaml.cs code and find the OnInitializeAsync method. Find the line of code that registers IRelayProviderReceiver<DeviceCommandEventArgs> in the unity container and replace IotHubRelayProviderReceiver with IotHubRelayProviderReceiverTpm.
Use Service Bus in Place of SignalR
SignalR is used in this project to send temperature sensor readings, in real-time, from the main IoT instance to other clients. The SignalR transport mechanism can be replaced by Azure Service Bus Queues.
This article does not go into a lot of detail about using Service Bus. Check out the tutorial on the Azure web site to learn more. The code in this project uses a NuGet package called AzureSBLite, which has already been added to the solution.
- Using the tutorial link above, create a Service Bus and a Queue in the Azure portal (I called my Service Bus SensorTelemetryBus and the Queue I named Temperature).
- Open the solution and enter the connection string for the bus and the Queue name in the UnityConfiguration.cs file (look for the IServiceBusConfiguration definition). The connection string can be obtained by clicking the Connection Strings link found in the Overview section for the Service Hub you created.
- In UnityConfiguration.cs, change SignalrRelayProviderSender to ServiceBusRelayProviderSender.
- In UnityConfiguration.cs, change SignalrRelayProviderReceiver to ServiceBusRelayProviderReceiver.
- Redeploy the project to your Raspberry Pi and then run it.
- Run the locally on your workstation to receive the events from the Raspberry Pi.
Device Management
In this article, I used the Device Explorer solution that is included as part of the Azure IoT SDK to manage devices. This tool is very flexible, it even allows you to send and recieve messages on the hub.
You can also use the Azure portal to view devices, get connection strings and keys and to enable or disable the devices. Click the Devices tab under your IoT Hub to see the list of devices that are registered on your specific hub. Click any device to see the details of that device.
Comments