Software apps and online services
In this project we will use a Raspberry Pi 2 running Windows 10 IoT to monitor a PIR motion sensor that triggers a USB webcam to snap a picture and upload it to Microsoft Azure Storage using C#. Additionally, we’ll wire up an LED as a simple status indicator. We’ll also create a Microsoft Azure Web App website to view the pictures remotely from any internet capable device.
This project is intended for beginners interested in learning more about Windows 10 IoT running on a Raspberry Pi 2, and/or Microsoft Azure Services. It assumes you have some basic knowledge of C#, though not necessarily around Raspberry Pi or Azure/ASP.NET programming. All of the code in this project was written in the free version of Microsoft’s Visual Studio 2015 Community Edition (the single best IDE ever produced, hands down).
This project can be seen as having the following distinct parts:
• A motion detector piece (PIR sensor)
• A camera, picture taking piece (Webcam)
• An “upload picture file to Azure Storage” piece (Azure)
• A simple LED status light (LED)
• And a separate Azure Website that displays the latest uploaded photos from Azure Storage (ASP.NET Website)
I’ve purposefully structured the code to clearly label and segment the above areas of code as much as possible, in case you’re interested in learning only a particular piece (e.g., “taking picture from webcam”, or “detect motion from Raspberry Pi”).
Note: The last Azure Website piece is somewhat optional. The Azure Portal offers a way to view all the uploaded photos online. But you’ll find that it’s extremely easy to create an Azure Website that gives a much better viewing experience.
In the real world, this solution would best operate as a headless application, but it’s presented here as a Universal Windows Application (C#) to help you monitor various statuses on-screen and make all logic easier to debug. You should be able to modify the application very easily to run in Windows 10 IoT’s headless mode (mind you, this application will still run as expected, as-is, without a screen output attached).
On startup, the application initializes the GPIO ports (used for PIR sensor reading and LED displaying) and the webcam. A function is tied to the PIR signal pin’s “ValueChanged” typed event handler to be called when motion is detected. It calls functions to take a picture using the USB webcam and then uploads the image to Microsoft Azure Blob Storage.
Raspberry Pi Configuration
This solution requires the Raspberry Pi to have an internet connection in order for it to upload the pictures to Azure. It can use a wired network connection, though that might not be logistically feasible in a real world installation. A USB Wi-Fi dongle will also work. This article describes the steps to connect a Raspberry Pi’s Wi-Fi to your network.
This solution also relies on a USB Webcam (any Windows 10 compatible webcam will do). Plug the camera in before launching the application and ensure the Raspberry Pi recognizes it. You’ll see it in the list of Connected Devices on the IoT boot up desktop screen when it’s recognized and ready to use (note: it may not show ‘webcam’ in its description).
PIR Motion Sensors
After testing with different sensor types, I found the PIR (Pyroelectric "Passive" Infrared) to be the perfect choice for this solution. They are inexpensive, tiny, low-powered and effective at detecting human movement at a reasonable distance (Adafruit’s site has a great article on How PIR Sensors Work). Other sensors that could be used in place of a PIR might include infrared break beams, ultrasonic distance measurers or magnetic door switches (to trigger on a door opening).
You’ll see it takes very minimal code to read the PIR sensor through the Raspberry Pi. There is some standard initialization code in the InitializeGPIO() function (MainPage.xaml.cs ~lines 88-99) where we specify GPIO Pin16 to use for the PIR signal.
This line is the most important as it ties the Typed Event Handler of the GPIO Pin 16’s value changed event to the function PinPIR_ValueChanged()….meaning, the app will continually poll Pin 16 of the Raspberry Pi’s GPIO port and when a signal is detected (motion was detected), the function is called:
PinPIR.ValueChanged += PinPIR_ValueChanged;
This line sets the DebounceTimeout for GPIO’s Pin 16, which is a timespan to ignore changes in the port. Think of it as a fine-tuning piece of code that says “don’t report events happening within 50 milliseconds of each other”. Try running the app with this line removed, or with the setting at 100-500ms, and see what different behaviors you get with your PIR sensor.
PinPIR.DebounceTimeout = new TimeSpan(0, 0, 0, 0, 50);
After initialization has occurred successfully, the app sits in a waiting mode and whenever the PIR detects motion, the function PinPIR_ValueChanged() is called.
In that function, you’ll see the variable IsInPictureCaptureMode is used to prevent this function from being triggered a 2nd time before its logic is completed (it takes X amount of time to snap a picture and upload it and we want that process to complete before we repeat it). There are various other ways to achieve this singleton guard but I kept the logic simple for this tutorial.
Past that, you’ll find this function does what you’d expect it to do. It calls the TakePicture() function and then the UploadPictureToStorageFile() function (both explained more in their respective sections).
The Raspberry Pi has a CSI-2 (Camera Serial Interface) port meant to connect different camera types via a ribbon cable, however, Windows 10 IoT applications cannot connect to it with the current version at this time of writing. The CSI port would have been my preferred method to connect a very small, low-powered yet high-quality camera. (Yes, you can connect to the CSI-2 port via Linux running C# with Mono importing C/C++ libraries, but Universal Apps cannot import or wrap around those C,C++ libraries at this time....on the up side, Microsoft is working on it...)
Not to be deterred, I found great success using normal everyday webcam connected to one of the Raspberry Pi’s USB ports. A USB webcam brings other advantages like a long connection cable and they generally have better mounting options. If your webcam works on a Windows 10 desktop/laptop/tablet (just by plugging in the USB), then it should work fine in this project.
There’s very little C# code required to get the photo taking functionality we need. There’s an InitializeWebcam() function that configures the .NET MediaCapture object we’ll use to take the picture. We also register a callback function with the MediaCapture’s Failed event. This callback will get called if there’s any sort of error in the picture taking process.
The main picture taking logic is across these 3 lines of the TakePicture() function:
StorageFile photoFile = await KnownFolders.PicturesLibrary.CreateFileAsync("RaspPiSecurityPic.jpg", CreationCollisionOption.GenerateUniqueName);
ImageEncodingProperties imageProperties = ImageEncodingProperties.CreateJpeg();
await MediaCap.CapturePhotoToStorageFileAsync(imageProperties, photoFile);
The remaining logic in the TakePicture() function displays the image on-screen. This logic is just here for tutorial purposes and isn’t necessary for the picture to be uploaded to Azure.
Note: it would be relatively easy to modify this application to record a video clip from the webcam instead of taking a picture. This would introduce some timing caveats that need to be thought through. Video files are much larger than picture files, so if you record a minute of video, it will take longer to upload that video to Azure. You can reference this sample project if you want to see how to record audio & video from the webcam.
LED Status Light
This project includes an LED wired to be used as a status indicator. When lit, the PIR motion sensor is ready to sense movement. It turns off while the webcam is taking the picture and uploading to Microsoft Azure Storage and then turns back on when ready to detect movement again.
The LED code and wiring is not required for the other components of the solution to work, per se. It’s just included as a simple status light addition to the solution. It also demonstrates the use of GPIO output signal coding (vs. the GPIO input signal coding used for the PIR sensor).
The LED logic starts in the InitializeGPIO() function where we specify we’re using GPIO Pin 5 to power the LED. And there’s a simple ShowLED() function to control the LED light (pass in TRUE to turn light on, pass in FALSE to turn light off). We turn the LED on when the system is ready and waiting for movement to be detected and we turn it off when the system is busy uploading the picture.
Upload to Microsoft Azure Logic
It is EXTREMELY easy to work with Azure files from a client application as you’ll see in the one function needed to upload a file to our Azure Blob Storage aptly named UploadPictureToAzure(). The first few lines gather our Azure credential information and the Azure Container name from the 3 Azure class variables which are then used to get a reference to the blob container. Then the last line calls an asynchronous upload function from the CloudBlockBlob object. Amazingly easy, isn’t it?
Don’t forget to update these lines (at the top of MainPage.xaml.cs) with your actual Azure values (you’ll get these values from the next section, if you don’t already have them):
private readonly string Azure_StorageAccountName = "<YOUR Azure_StorageAccountName>";
private readonly string Azure_ContainerName = "<YOUR Azure_ContainerName>";
private readonly string Azure_AccessKey = "<YOUR Azure_ContainerName>";
Note: the PiMotionSensorPhotoUpload project uses the WindowsAzure.Storage NuGet package. This should install automatically with default Visual Studio options when you first compile the project. If not, you'll want to right click the project in Solution Explorer and choose 'Manage NuGet packages' and then search for, and install, 'WindowsAzure.Storage'
We will need to setup an Azure Storage Account (to store the photos as blobs) and an Azure Web App (to host the website that views the pictures).
If you don’t already have an Azure account, you will need to create one. You can get a 30-day free trial by going to azure.microsoft.com and clicking the ‘Try it for Free’ button. Once you have an account, log into to the portal.
The following section will walk you through step-by-step instructions to setup the Azure pieces for this solution, but if you don’t have any prior experience with Azure you will find these links helpful: Getting Started with Azure (Videos), Creating your first Azure Website & Creating an Azure Storage Account.
A handy feature that we will take advantage of is that you can easily and directly access a blob in your storage account using the following URL format:
Setting up Azure Storage
Within the Azure Portal, follow these instructions to create a new instance of Azure Storage:
(1) Click NEW(2) Click DATA + STORAGE(3) Click STORAGE ACCOUNT(4) Click CREATE
It will then prompt you to enter the name of the storage account (any name will do, but remember it because we’ll reference it later) and review/choose the other details like Pricing Tier and Subscription account to tie this to. Click CREATE when finished.
It may take a few minutes to create your storage account. To check the status, you can monitor the notifications at the bottom of the portal. After the storage account has been created, it will show an Online status and is ready for use.
Click on the Storage Account to have its summary page to appear and then click Containers. Think of containers as groupings of files. Create a new container and remember the name. This will be the area we upload pictures to.
Copy the Storage Access Key
When you create a storage account, Azure generates two 512-bit storage access keys, which are used for authentication whenever the storage account is accessed by external code. By providing two storage access keys, Azure enables you to regenerate one of the keys with no interruption to your storage service or access to that service.
In the Azure portal, use Manage Keys on the dashboard to copy a storage access key to use in a connection string. The connection string requires the storage account name and an access key to use in authentication.
1. In the Azure portal, click Storage, and then click the name of the storage account to open the dashboard.
2. Click Manage Keys. (The Manage Access Keys window opens.)
3. To copy a storage access key (either the Primary or Secondary), select the key text. Then right-click, and click Copy.
We will need to use the Storage Account Name, the Container Name and the Storage Access Key in the area of the Raspberry Pi code that uploads the pictures to Azure. We’ll also use them in the area of the Azure Website code that views the images.
Creating the Azure Web App
This project is really around the Raspberry Pi side of things, but we’ll make it very easy for you to create this Azure Website portion even if you have no other experience than running through the above instructions to setup the Azure Storage Account.
Within the Azure Portal, follow these instructions to create a new instance of an Azure Web App that will host our website:
(1) Click NEW(2) Click WEB + MOBILE(3) Click WEB APP(4) Fill in the App Name (this name will show in your website URL) & the review/choose the other parameters
(5) Click CREATE
It may take a few minutes for Azure to fully create your site (you can monitor progress from the Azure Portal's dashboard)
There's one more piece we need while we're still in the Azure Portal. Click on your newly created WebApp in the Azure Portal to pop out it's detail window.
Click on the "Get Publish Profile" button across the top menu and it'll download a *.publishsettings file. We'll use this file in just a bit to easily publish the site.
AzureWebsite Solution in Visual Studio 2015
When you download the code from GitHub you'll see that the one solution file contains both the Raspberry Pi client application and the ASP website. This was done just for convenience sake. The Raspberry Pi project is the default project to launch, so you'll want to right click on the AzureWebsite project and choose "Set as Start Up Project" to use the website project.
Open the Web.config file and find the keys defined in lines 12 and 13.
In line 12, replace the text ENTER_YOUR_ACCOUNT_NAME_HERE with the Storage Account name you previously setup. Also replace the text ENTER_YOUR_ACCOUNT_KEY_HERE with one the Storage Access Keys you previously setup.
On line 13, replace the text ENTER_YOUR_CONTAINER_NAME_HERE with the name of the Storage Container you previously setup.
Those are all the changes you need to make! You can test the changes by hitting F5, to launch the debugger. The website should appear and if you have any pictures uploaded to your Storage Container, you’ll see them now (but you probably don’t have any pictures there just yet).
Note: If you receive an error around the "Microsoft.CodeDom.Providers.DotNetCompilerPlatform" then be sure and either install OR upgrade the NUGET package through the "Manage NuGet Packages" option in Visual Studio. I've seen fresh installs of Visual Studio 2015 throw this error until the package was upgraded.
Once you've got the local debug version running, it's EASY to publish to your Azure site. In Visual Studio 2015, choose BUILD, PUBLISH AZUREWEBSITE. In the "Publish Web" window, choose the first selection on the top left, PROFILE. Then choose the import option. A file chooser windows will let you select the *.publishsettings file you just downloaded in the steps above. At this point, you can publish your site permanently, or until you delete it through the Azure Portal. The publish settings will now be saved in your project for future use (it's stored in the Properties/PubilshProfiles folder of the solution, fyi).
There is one quick thing you'll need to do after you download the code from GitHub in order to compile. You'll need to enter a certificate from your PC (since this is a Windows Universal Application, it requires a certificate to compile against).
Here's the steps to take, once you've opened the code in Visual Studio:
1) In Solution Explorer, delete the 'PiMotionSensorPhotoUpload_TemporaryKey.pfx' file from the project (Right Click and choose DELETE).
2) In Solution Explorer, double click on 'Package.appxmanifest' and the Package properties window should pop up.
3) Click on the "Packaging" tab (tabs run across the top)
4) Click the Choose Certificate button
5) In the window that pops up, open the "Configure Certificate" drop down and choose "Create test certificate..."
6) The certificate window will ask for name (input any name you want), and a password (any password, must be 6 characters)
NOW try and compile and all should be well.
One more thing to note, especially if you download the code as a ZIP file from GitHub: Make sure the folder path of your solution file (the folder where the "PiMotionSensorPhotoUpload.sln" is in) is less than 256 characters. If the folder path is too large, you'll receive tons of compile errors, mostly stemming from the main error that it cannot restore all the NuGet packages. To fix this copy the solution folder (the folder where the "PiMotionSensorPhotoUpload.sln" is in) to the root of your C drive and try opening/compiling again.
As you can see, it's extremely easy to develop apps for the Raspberry Pi running Windows 10 IoT and to integrate with Azure Storage. Newcomers to Raspberry Pi who have a bit of prior experience with C# will find themselves right at home. The rich environment of Visual Studio and the powerful debugging experience will help you learn even more features of the Raspberry Pi.
Enjoy your Raspberry Pi and the Internet of Things!!!!!