In this project, we used Raspberry Pi 2, Adafruit kit components, Azure components and USB Camera. We have a push button, which when pressed, triggers the USB camera to take photo, then upload the photo in to azure storage container with help of SAS (Shared Access Signature) URL, and finally send notification to the respective mobile apps. Here we developed Windows 10 UWP app to receive notification and for performing actions.
Prerequisites:
Hardware
- Raspberry Pi2 Model B
- Breadboard
- Logitech USB Camera (This component is not there in Adafruit kit)
- Adafruit Push button
- 10K Ohm Resistor
- Adafruit Female to Male Jumper Wires
Software
- Windows 10 PC
- Visual Studio 2015 Community Edition or Enterprise Edition Update1
- Azure Subscription
- Dot net Back-end Mobile Service
- Azure Storage Account
- Service Bus Queue
- Scheduler
- Windows 10 IoT Core
Fritzing Image of theProject
High-Level Architectural Diagram
You can skip the step 1 and step 2, if you already set Up your PC and Raspberry Pi2.
Step 1. Set up Your PC- First you need a Windows 10 PC running the public release of Windows 10 (version 10.0.10586) or better.
- Install Visual Studio Community 2015 or Visual Studio Professional 2015 or Visual Studio Enterprise 2015 with Update 1.
- Install Windows IoT Core Project Templates from here.
- Enable developer mode on your Windows 10 device by following https://msdn.microsoft.com/library/windows/apps/xaml/dn706236.aspx
- 5v Micro USB power supply with at least 1.0A current. If you plan on using several power-hungry USB peripherals, use a higher current power supply instead (>2.0A).
- 8GB Micro SD card - class 10 or better.
- HDMI cable and monitor (Optional)
- Ethernet Cable
- Micro SD card reader - due to an issue with most internal micro SD card readers, we suggest an external USB micro SD card reader.
- Install the Windows 10 IoT Core tools:Download a Windows 10 IoT Core image from http://ms-iot.github.io/content/en-US/Downloads.htm Save the ISO to a local folder.Double click on the ISO (Iot Core RPi.iso). It will automatically mount itself as a virtual drive so you can access the contents.
- Install Windows_10_IoT_Core_RPi2.msi. When installation is complete, flash.ffu will be located at C:\Program Files (x86)\Microsoft IoT\FFU\RaspberryPi2.
- Eject the Virtual CD when installation is complete - this can be done by navigating to the top folder of File Explorer, right clicking on the virtual drive, and selecting "Eject" like shown in below figure.
- Insert a Micro SD Card into your SD card reader.
- Use IoTCoreImageHelper.exe to flash the SD card. Search for "WindowsIoT" from start menu and select the shortcut "WindowsIoTImageHelper".
- After launch the IoTCoreImageHelper.exe and select your SD Card and the flash.ffu found in the directory.
- Once the process has completed, you are ready to run Windows 10 IoT Core on your Raspberry Pi 2.NOTE: IoTCoreImageHelper.exe is the recommended tool to flash the SD card. However, instructions are available for using http://ms-iot.github.io/content/en-US/win10/samples/DISM.htm directly.
- Safely remove your USB SD card reader by clicking on "Safely Remove Hardware" in your task tray, or by finding the USB device in File Explorer, right clicking, and choosing "Eject". Failing to do this can cause corruption of the image.
- Hook up your board
- Insert the micro SD card you prepared into your Raspberry Pi 2.
- Connect a network cable from your local network to the Ethernet port on the board. Make sure your development PC is on the same network.NOTE: If you don't have a local wired network, see http://ms-iot.github.io/content/en-US/win10/ConnectToDevice.htm for additional connection options.
- Connect an HDMI (High-Definition Multimedia Interface) monitor to the HDMI port on the board (Optional).
- Connect the power supply to the micro USB port on the board.
Once we complete setting up the Development PC and Raspberry Pi, Open Visual Studio and create a new project by selecting Universal –> Blank App template as shown in screenshot below.
Now add reference of Windows 10 IoT Extensions to the recently created project.
Select an appropriate version of IoT Extensions, here I am using 10.0.10586.0 version and my Raspberry Pi 2 also installed the same version of Windows 10 IoT core.
Initialize the Push Button
Here we are assuming that the push button is a Doorbell in our project.
Open the MainPage.xaml.cs file, declare the following properties in the top of the class like below.
//A GPIO pin for the pushbutton
GpioPin buttonPin;
//The GPIO pin number we want to use to control the pushbutton
int gpioPin = 4;
To Initialize the GPIO pin for the pushbutton, then call InitializeGpio method under OnNavigatedTo method of MainPage.xaml.cs file like below.
base.OnNavigatedTo(e);
try
{
//Initialize the GPIO pin for the pushbutton
InitializeGpio();
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message);
}
Next add the following code in MainPage.xaml.cs file.
//This method is used to initialize a GPIO pin
private void InitializeGpio()
{
//Create a default GPIO controller
GpioController gpioController = GpioController.GetDefault();
//Use the controller to open the gpio pin of given number
buttonPin = gpioController.OpenPin(gpioPin);
//Debounce the pin to prevent unwanted button pressed events
buttonPin.DebounceTimeout = new TimeSpan(1000);
//Set the pin for input
buttonPin.SetDriveMode(GpioPinDriveMode.Input);
//Set a function callback in the event of a value change
buttonPin.ValueChanged += buttonPin_ValueChanged;
}
buttonPin_ValueChanged event will be called every time there is a change in the GPIO pin value, and add the following code in MainPage.xaml.cs file.
//This method will be called everytime there is a change in the GPIO pin value
private async void buttonPin_ValueChanged(object sender, GpioPinValueChangedEventA rgs e)
{
//Only to initialize the camera and take photo when the button is released
if (e.Edge == GpioPinEdge.RisingEdge)
{
//write to the code to intialize the camera and take photo from it.
}
}
Initialize the camera and capture photo when we press the push button
When we press the push button the buttonPin_ValueChangedEvent will be fired, in that event we will check whether the Edge property value of the button is at RisingEdge or FallingEdge. Based on the value in the Edge property we will identify whether the bell got rang or not. According to the code here we initialize camera and capture a photo when the value in the Edge property is at RisingEdge. Here we will call the two methods named as initVideo() for initializing the camera and takePhoto_Click() to capture a photo from it.
Next add following lines code in buttonPin_ValueChanged event.
//Only to initialize the camera and take photo when the button is released
if (e.Edge == GpioPinEdge.RisingEdge)
{
await initVideo();
await takePhoto_Click();
}
Declare following properties at the class level of the MainPage.xaml.cs file
private MediaCapture mediaCapture;
private StorageFile photoFile;
private readonly string PHOTO_FILE_NAME = "photo.jpg";
private bool isPreviewing;
private bool isRecording;
To set the false value to isPreviewing property under the constructor of this class like below.
isPreviewing = false;
Add the following code in MainPage.xaml.cs file, in that I have to write the code like if the mediaCapture is null, then we have to initialize the camera otherwise it stop the camera preview.
private async Task initVideo()
{
try
{
if (mediaCapture != null)
{
// Cleanup MediaCapture object
if (isPreviewing)
{
await mediaCapture.StopPreviewAsync();
isPreviewing = false;
}
mediaCapture.Dispose();
mediaCapture = null;
}
mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync();
// Set callbacks for failure
mediaCapture.Failed += new MediaCaptureFailedEventHandler(mediaCapture_Failed);
// Start Preview
await mediaCapture.StartPreviewAsync();
isPreviewing = true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Add the following code in MainPage.xaml.cs file, in that I have to write the code like to take photo from camera.
private async Task takePhoto_Click()
{
try
{
photoFile = await KnownFolders.PicturesLibrary.CreateFileAsync(
PHOTO_FILE_NAME, CreationCollisionOption.GenerateUniqueName);
ImageEncodingProperties imageProperties = ImageEncodingProperties.CreateJpeg();
await mediaCapture.CapturePhotoToStorageFileAsync(imageProperties, photoFile);
path = photoFile.Path;
IRandomAccessStream photoStream = await photoFile.OpenReadAsync();
TakeAndSendPicture(photoFile);
}
catch (Exception ex)
{
Cleanup();
Debug.WriteLine(ex.Message);
}
}
Add the following lines of code, to stop the camera preview if it is already in streaming state.
private async void Cleanup()
{
if (mediaCapture != null)
{
// Cleanup MediaCapture object
if (isPreviewing)
{
await mediaCapture.StopPreviewAsync();
isPreviewing = false;
}
mediaCapture.Dispose();
mediaCapture = null;
}
}
Step 4: Upload the Captured Photo into Azure
Storage AccountWe have to follow three Steps to upload a photo in to your Azure Storage Account.
- Create a Storage Account in Azure.
- Create an API in your Dot Net Mobile Service for requesting the SAS (Shared Access Signature) URL/Key.
- Finally from IoT UWP App, we can upload a photo in to your Azure Storage Container with help of SAS Key/URL.
Create Storage Account :-
- Go to Azure classic Portal site through this link Azure Portal.
- Login with your own credentials of Azure Account.
- After Login Successfully, see the left side pane list in that there is an option like STORAGE then Select it, like shown in below Figure 1.
- After selecting the STORAGE option, See the bottom there is a one more option like New, then Hit the “New” option it will open the popup like below Figure 2.
- Next Select the option as quick create, it will open the popup like below Figure 3.
- In that Type in a unique URL is nothing but name of your storage account.
- Choose a region that you are consistent with. Mobile Services that we will provision will need the same region to avoid latency.
- After Enter all fields then Hit on CREATE STORAGE ACCOUNT, It will take less than 1 minute to Create your own storage account like shown in below Figure 4.
- Click MANAGE ACCESS KEYS. We will need this later for Azure Mobile Services.
- Drill into the service by hitting your Storage Account what you created earlier.
- Next Choose CONTAINERS like shown in below Figure 7.
- Select ADD Option, then it will open the popup like below Figure 8.
- Provide a container name and write it down. You will need it later.
- After Provided the Name and Access Hit on Check Mark it will created the your own Container named as photoscontainer like shown in below Figure 9.
- Next Note Down the account name, access key and container name like shown below Figure 10.
- We can also upload photo in to your azure storage account named as iotdoorbell with out the help SAS URL.
- If you follow this approach, you must provided the storage account name and access key directly in your code (means you have to hardcode those values in your code), that’s why this is not a secure way to maintain your storage account.
- If you want to maintain your storage account Securely, you must create your own API in either .net or Node.Js Languages, that it return SAS URL of your storage account.
- By using this SAS URL you can upload photo into your storage account.
- If you follow this approach there is no need to provide the storage account name and access key in your code (means there is no needed to hardcode those values in your code), only provide SAL URL in your code.
Create an API in your Dot Net Mobile Service for requesting the SAS (Shared Access Signature) URL/Key
If you haven't created a .Net backend Mobile Service, Please follow the below steps
- Login to your Azure classic portal and create a Mobile Service as .Net backend and cofigure it with Sql Database like below
- At the time of creating Mobile Service make sure you have selected the Back-end as .NET and check the configure advance push settings.
- Database can be an existing one or you can create a new database. If you are selecting the existing database make sure you have selected the same region of your SQL Database otherwise you cant create it.
- Also check the storage account region also be the same.(Not mandatory)
- Configure Push setting, you can create a new one or can select the existing one but cross check the region otherwise there will be a latency.
- Now download your service project
- Open your Dot Net mobile service project in Visual Studio 2015, next expand your mobile service and see the what are the folders are available inside your mobile service like shown in below figure.(Eg : iotpocservice)
- Next Right click –> Controllers folder, select the Add –>choose Controller Option, like shown in below figure.
- After choose the Controller option next popup it will be open like this below figure, in that choose the Microsoft Azure Mobile Services Custom Controller option then click on ADD.
- After click on Add, next popup will be open like this below figure.
- In this Project I was given the Controller name as RequestSASController then click on Add , it will create custom controller in controllers folder like this below figure.
- Next open the RequestSASController file and copy the below code, for return SAS URL.
public class RequestSASController : ApiController
{
public ApiServices Services { get; set; }
// GET api/RequestSAS
public async System.Threading.Tasks.Task<PhotoResponse> Get()
{
string storageAccountName;
string storageAccountKey;
string containerName;
string sasQueryString = "";
string imageUri = "";
// Try to get the Azure storage account token from app settings.
if (!(Services.Settings.TryGetValue("STORAGE_ACCOUNT_NAME", out storageAccountName) |
Services.Settings.TryGetValue("STORAGE_ACCOUNT_ACCESS_KEY", out storageAccountKey) | Services.Settings.TryGetValue("CONTAINER_NAME", out containerName)))
{
Services.Log.Error("Could not retrieve storage account settings.");
}
// Set the URI for the Blob Storage service.
Uri blobEndpoint = new Uri(string.Format("https://{0}.blob.core.windows.net", storageAccountName));
// Create the BLOB service client.
CloudBlobClient blobClient = new CloudBlobClient(blobEndpoint,
new StorageCredentials(storageAccountName, storageAccountKey));
PhotoResponse photoResponse = null;
if (Services.Settings.TryGetValue("CONTAINER_NAME", out containerName))
{
// Set the BLOB store container name on the item, which must be lowercase.
containerName = containerName.ToLower();
// Create a container, if it doesn't already exist.
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
await container.CreateIfNotExistsAsync();
// Create a shared access permission policy.
BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
// Enable anonymous read access to BLOBs.
containerPermissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(containerPermissions);
// Define a policy that gives write access to the container for 5 minutes.
SharedAccessBlobPolicy sasPolicy = new SharedAccessBlobPolicy()
{
SharedAccessStartTime = DateTime.UtcNow,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5),
Permissions = SharedAccessBlobPermissions.Write
};
// Get the SAS as a string.
sasQueryString = container.GetSharedAccessSignature(sasPolicy);
Services.Log.Info("sasQueryString: " + sasQueryString);
// Set the URL used to store the image.
var blobName = genRandNum() + ".jpg";
imageUri = string.Format("{0}{1}/{2}", blobEndpoint.ToString(),
containerName, blobName);
Services.Log.Info("imageUri: " + imageUri);
photoResponse = new PhotoResponse();
photoResponse.sasUrl = sasQueryString;
photoResponse.photoId = imageUri;
photoResponse.expiry = sasPolicy.SharedAccessExpiryTime.ToString();
photoResponse.ContainerName = containerName;
photoResponse.ResourceName = blobName;
}
if (photoResponse != null)
{
return photoResponse;
}
else
{
Services.Log.Info("Failed to generate SAS");
return photoResponse;
}
}
private int genRandNum()
{
var rand = new Random();
return (rand.Next(1, 90000)) + 10000;
}
}
public class PhotoResponse
{
public string sasUrl { get; set; }
public string photoId { get; set; }
public string expiry { get; set; }
public string ResourceName { get; set; }
public string ContainerName { get; set; }
}
- Next go to Azure Portal and login with your Azure Credentials, and Select the Mobile Services tap In that choose your .net mobile service and choose MANAGE KEYS, like shown in below figure.
- Take note that the application keys below. Clients will use these to connect to the service. Save this application key to be used later when we use a rest-based client to test our mobile service.
STORING CONFIDENTIAL INFORMATION INSIDE APP SETTINGS
- App settings is a safe and convenient way to avoid hard coded in your .net Custom API’s.
- It is similar to the configuration file for a web application.
- We will use it to store our storage account information, such as the computer name, storage account name, and access keys.
ADDING APP SETTINGS
- Choose CONFIGURE from the menu below.
- Notice the app settings provided below.
- This information comes from the previously provisioned storage account. This information is available from the Azure storage account portal.
- Putting it here avoids hard coding it into our mobile service application.
Publish Mobile Service to Azure
Now we are ready to publish the mobile service and call the SAS request controller to request the SAS Key/URL.
TESTING WITH A REST CLIENT :-
- We are now ready to begin testing our newly created service.
- There are many number of rest-based client applications to test, the one below is a Google Chrome extension called advanced rest client. It is free and works well for testing purposes.
HOW TO USE ADVANCED REST CLIENT :
Notice that there are five pieces to this
- This is the URL by clients who used to request the shared access signature
a) Notice the first part of the URL is the name of the mobile service b) The last part of the URL is the actual API name we provided
- The request type will be GET
- There needs to be one header entry is seen below.
a) X-XUMO-APPLICATION is the key
b) The value here is the application key for the mobile service we created.
- Click send to call into the mobile service API.
- View the shared access signature returned by the service.
a) Client applications that received this signature can then upload blobs to the specified storage account.
b) The scenario might be a client application that wants to upload a photo using a shared access signature.
- Till now I had illustrated all the needed steps to be able to call into a mobile services API. It even demonstrated how to test the API using the Google Chrome extension,Advanced REST client.
- You are required to provision both a Azure storage account as well as an Azure mobile service.
Now with the help of SAS Key\URL we can Upload a photo in to Azure Storage Container:
- In step 3 explained about how to Initialize the camera and how to take photo from it.
- Now will see how to upload a photo in to azure storage account with the help of SAS URL, which will be received from SASRequest API which we created in above step.
- Open the MainPage.xaml.cs file, add the following code to upload photo into your storage account with the help of SAS URL.
async void TakeAndSendPicture(StorageFile photoFile)
{
PhotoResponse photoResp = null;
//Get Photo Url while the rapistill process is taking the picture.
//This request will ask the server for a new photo blob that we can upload the picture to.
WebRequest photoRequest = WebRequest.Create("https://iotpoc.azure-mobile.net/api/RequestSAS");
photoRequest.Method = "GET";
//IotPoc
photoRequest.Headers["X-ZUMO-APPLICATION"] = "JBhzQTNRwDsHyqARgYGJHDAlsqnkXl43";
HttpWebResponse response = await photoRequest.GetResponseAsync() as HttpWebResponse;
using (var sbPhotoResponseStream = response.GetResponseStream())
{
StreamReader sr = new StreamReader(sbPhotoResponseStream);
string data = sr.ReadToEnd();
photoResp = JsonConvert.DeserializeObject<PhotoResponse>(data);
}
//We've gotten the Shared Access Signature for the blob in URL form.
//This URL points directly to the blob and we are now authorized to
//upload the picture to this url with a PUT request
Debug.WriteLine("Pushing photo to SAS Url: " + photoResp.sasUrl);
// If we have a returned SAS, then upload the blob.
if (!string.IsNullOrEmpty(photoResp.sasUrl))
{
// Get the URI generated that contains the SAS
// and extract the storage credentials.
StorageCredentials cred = new StorageCredentials(photoResp.sasUrl);
var imageUri = new Uri(photoResp.photoId);
// Instantiate a Blob store container based on the info in the returned item.
CloudBlobContainer container = new CloudBlobContainer(
new Uri(string.Format("https://{0}/{1}",
imageUri.Host, photoResp.ContainerName)), cred);
// Upload the new image as a BLOB from the stream.
CloudBlockBlob blobFromSASCredential =
container.GetBlockBlobReference(photoResp.ResourceName);
try
{
await blobFromSASCredential.UploadFromFileAsync(photoFile);
}
catch (Exception)
{
Debug.WriteLine("Failed to upload file");
}
StopPreview();
}
- And also declare the following class as PhotoResponse in MainPage.xaml.cs file, in the PhotoResponse class I have declared the three properties as sasUrl, photoId and expiry, by using these properties we can get or set the SAS URL, Photo Id values in our C# code.
public class PhotoResponse
{
public string sasUrl { get; set; }
public string photoId { get; set; }
public string expiry { get; set; }
}
- Above method will be called once completed to capture photo from camera, If you observe it was called in the end of the takePhoto_Click method.
- After added the above code, next add following code to stop the camera preview once uploaded the photo in to Azure storage account.
private async void StopPreview()
{
if (mediaCapture != null)
{
// Cleanup MediaCapture object
if (isPreviewing)
{
await mediaCapture.StopPreviewAsync();
isPreviewing = false;
}
if (isRecording)
{
await mediaCapture.StopRecordAsync();
isRecording = false;
}
mediaCapture.Dispose();
mediaCapture = null;
}
Debug.WriteLine("Camera Stopped");
}
Step 5: Sending Message to Azure Service Bus Queue after successfully uploading Photo to Azure StorageSo far, we have learned how to use Azure Mobile service and Azure Storage account in an IoT UWP app. Now we will see how we can use Azure Service Bus Messaging Queues and take advantages of it in to our project. With the help of scheduled tasks will read messages from Service Bus Queue which are sent by Raspberry Pi2 and send it to the Mobile Devices. We will integrate both Service Bus Queue and Scheduler with the help of Mobile Service. If the scheduler reads the message successfully from the Queue, then we will save the details into SQL Database which is configured earlier at the time of Mobile Service creation.
Service Bus are mainly used for Distributed Messaging, in the IoT context the service bus queuing capabilities gives very powerful Ideas to develop. Due to its asynchronous messaging capabilities it can easily handle any workload. With the help it we can even communicate on-premises without any virtual networking.
- First create a Service Bus with name as smartdoorqueue (in my case)
- Enter name for the Service Bus
- Now go and create a Messaging Queue, select New icon which is located bottom left corner of the classic portal and select App Services-> Service Bus –> Queue
- Enter name for the Queue and also select the namespace which is the name of the service bus which you created in earlier step here it is called smartdoorqueue is the namespace name.
- Now you are ready with the Messaging Queue in azure.
- Coming to our project, Once we successfully upload the photo to Azure Storage we will send Message to Queue. At the time of doing this POC the windows 10 UWP app does not support Azure Service Bus queue to send message directly from the app. So here we created an API to send message to queue.
- In earlier steps how we created RequestSASController similarly we will create one more controller for sending message to Service bus queue. For that open the Mobile Service Project, right click on controllers folder and add new Scaffholded Item like below.
- Select Mobile Service Custom Controller template.
- Enter name for the controller as MessageQueueController.
- Add reference for Azure Service Bus using NuGet package manager
- Now open MessageQueueController class and replace the existing code with the below code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Microsoft.WindowsAzure.Mobile.Service;
using Newtonsoft.Json;
using Microsoft.WindowsAzure;
using Microsoft.ServiceBus.Messaging;
namespace iotpocService.Controllers
{
public class MessageQueueController : ApiController
{
public ApiServices Services { get; set; }
public string Post(string jsonObj)
{
Services.Log.Info("doorbellInfo Json String: " + jsonObj);
var doorbellNotification = JsonConvert.DeserializeObject<DoorBellNotification>(jsonObj);
string SuccessCode = "Failed";
Services.Log.Info("Sending notification to service bus queue");
try
{
if (doorbellNotification != null)
{
string connectionString = CloudConfigurationManager.GetSetting("MS_ServiceBusConnectionString");
QueueClient Client =
QueueClient.CreateFromConnectionString(connectionString, "smartdoordemo");
string body = JsonConvert.SerializeObject(new DoorBellNotification()
{
doorBellID = doorbellNotification.doorBellID,
imageUrl = doorbellNotification.imageUrl
});
var brokeredMsg = new BrokeredMessage(body);
brokeredMsg.Properties["doorBellID"] = doorbellNotification.doorBellID;
brokeredMsg.Properties["imageUrl"] = doorbellNotification.imageUrl;
// Send message to the queue.
Client.Send(brokeredMsg);
SuccessCode = "Success";
Services.Log.Info("Message Sent Successfully!");
}
}
catch (Exception ex)
{
Services.Log.Info("Message Failed to Send: " + ex.Message);
SuccessCode = "Failed";
}
return SuccessCode;
}
public class DoorBellNotification
{
public string doorBellID { get; set; }
public string imageUrl { get; set; }
}
}
}
- In MessageQueueController class have a Post method which accepts Uploaded Photo storage account URL and DoorBell Id to identify from which door bell the photo captured.
- First will create a connectionString for the Service Bus Queue using the below code.
string connectionString = CloudConfigurationManager.GetSetting("MS_ServiceBusConnectionString");
- Under Web.config file define an AppSetting called MS_ServiceBusConnectionString and pass the connection string of the Service Bus Queue to value like below.
<add key = "MS_ServiceBusConnectionString"
value="Endpoint=sb://smartdoorqueue.servicebus.windows.net/;
SharedAccessKeyName=RootManageSharedAccessKey;
SharedAccessKey=Enter your key"/>
- To get connection string go to your Service Bus and select Connection string setting bottom of the page.
- Copy the SharedAccessKey and paste it into your Mobile Service App Settings in Web.Config.
- If you want to change the permissions of the Queue go to configure tab and can regenerate or modify the policies like below.
- Once we are done with adding Service Bus connection string create QueueClient object with the help of the connection string and create a brokered message as json object. Pass the brokered message object to QueueClient Send method to send message to Message queue
QueueClient Client =
QueueClient.CreateFromConnectionString(connectionString, "smartdoordemo");
string body = JsonConvert.SerializeObject(new DoorBellNotification()
{
doorBellID = doorbellNotification.doorBellID,
imageUrl = doorbellNotification.imageUrl
});
var brokeredMsg = new BrokeredMessage(body);
brokeredMsg.Properties["doorBellID"] = doorbellNotification.doorBellID;
brokeredMsg.Properties["imageUrl"] = doorbellNotification.imageUrl;
// Send message to the queue.
Client.Send(brokeredMsg);
- Publish the Mobile Service project to Azure.
- Accessing or calling the MessageQueue API from the IoT app after successfully uploading the photo to azure.
- After stoppreview() method write the below code to call the MessageQueue API and pass the Photo URL and doorbell ID.
try
{
Debug.WriteLine("Sending notification to service bus queue");
var MobileService = new MobileServiceClient("https://iotpoc.azure-mobile.net/", "JBhzQTNRwDsHyqARgYGJHDAlsqnkXl43");
var dictionary = new Dictionary<string, string>();
var doorbellObject = JsonConvert.SerializeObject(new DoorBellNotification()
{
doorBellID = "123456",
imageUrl = photoResp.photoId
});
dictionary.Add("jsonObj", doorbellObject);
//dictionary.Add("imageUrl", photoResp.photoId);
var result = await MobileService
.InvokeApiAsync<string>("MessageQueue",
System.Net.Http.HttpMethod.Post, dictionary);
if (result == "Success")
{
Debug.WriteLine("Sending notification to service bus queue Success");
}
else
{
Debug.WriteLine("Sending notification to service bus queue Failed");
}
}
catch (Exception ex)
{
Debug.WriteLine("Sending notification to service bus queue Failed: "+ex.Message);
}
- The MessageQueue API will receive the Photo URL, Door bell Id and send to the message queue.
- Before creating a Scheduler we need two tables Doorbells to store Door bell information and Pictures to store captured photo information in to database.Add the following classes under DataObjects folder in Mobile service project.
using Microsoft.WindowsAzure.Mobile.Service;
namespace iotpocService.DataObjects
{
public class DoorBells : EntityData
{
public string DoorBellID { get; set; }
public string PicturesId { get; set; }
}
}
using Microsoft.WindowsAzure.Mobile.Service;
namespace iotpocService.DataObjects
{
public class Pictures : EntityData
{
public string Url { get; set; }
public string TimeStamp { get; set; }
public string DoorBellID { get; set; }
}
}
- Add Controllers for Doorbells and Pictures DataObjects, to do that right click on Controllers folder and select add-> New Scaffholded Item –> Select Mobile Service Table Controller as template
- Select Doorbells class as Model, Context as Mobile Service context class name which you will find under Models folder.
- Repeat the above step for Pictures controller.
- We have completed setting up back end models/tables for storing the Door Bell and Picture information.
- Now this is the time to create scheduler, go to the Mobile Service Project add a new job called doorlistener under ScheduledJobs folder.
- Under Scheduled Jobs select the Mobile Service Scheduled Job template
- The above step creates a class file under ScheduledJobs folder, open it and replace the code with the following code.
using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.ServiceBus;
using Microsoft.WindowsAzure;
using System;
using Microsoft.ServiceBus.Messaging;
using iotpocService.Models;
using System.Collections.Generic;
using iotpocService.DataObjects;
using System.Linq;
using System.Data.Entity;
using Microsoft.WindowsAzure.Mobile.Service.ScheduledJobs;
using System.Threading;
namespace iotpocService
{
// A simple scheduled job which can be invoked manually by submitting an HTTP
// POST request to the path "/jobs/sample".
public class doorlistener : ScheduledJob
{
string connectionString =
CloudConfigurationManager.GetSetting("MS_ServiceBusConnectionString");
iotpocContext DBcontext;
protected override void Initialize(ScheduledJobDescriptor scheduledJobDescriptor,
CancellationToken cancellationToken)
{
base.Initialize(scheduledJobDescriptor, cancellationToken);
// Create a new context with the supplied schema name.
DBcontext = new iotpocContext();
}
public override Task ExecuteAsync()
{
// Create the queue if it does not exist already.
var namespaceManager =
NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.QueueExists("smartdoordemo"))
{
namespaceManager.CreateQueue("smartdoordemo");
Services.Log.Info("smartdoordemo Queue created successfully!");
}
else
{
Services.Log.Info("smartdoordemo Queue Already Exist!");
}
try
{
listenForMessages();
}
catch (Exception ex)
{
Services.Log.Info("Exception :" + ex.Message);
}
Services.Log.Info("doorlistener scheduled job Done!");
return Task.FromResult(true);
}
private void listenForMessages()
{
Services.Log.Info("listenForMessages");
// Long poll the service bus for seconds
QueueClient Client =
QueueClient.CreateFromConnectionString(connectionString, "smartdoordemo");
// Configure the callback options.
OnMessageOptions options = new OnMessageOptions();
options.AutoComplete = false;
options.AutoRenewTimeout = TimeSpan.FromMinutes(1);
// Callback to handle received messages.
Client.OnMessageAsync(async (message) =>
{
try
{
Services.Log.Info("Callback to handle received messages");
// Process message from queue.
Services.Log.Info("Body: " + message.GetBody<string>());
Services.Log.Info("MessageID: " + message.MessageId);
Services.Log.Info("doorBellID: " +
message.Properties["doorBellID"]);
Services.Log.Info("imageUrl: " +
message.Properties["imageUrl"]);
var doorBellId = message.Properties["doorBellID"];
var imgURL = message.Properties["imageUrl"];
Services.Log.Info("Query the database");
var doorbell = await (from x in DBcontext.DoorBells
where x.DoorBellID == doorBellId.ToString()
select x).ToListAsync();
Services.Log.Info("Query completed");
if (doorbell.Count > 0)
{
Services.Log.Info("doorBell Already Found");
var newPicture = new DataObjects.Pictures()
{
Id = Guid.NewGuid().ToString(),
Url = imgURL.ToString(),
DoorBellID = doorBellId.ToString()
};
DBcontext.Pictures.Add(newPicture);
Services.Log.Info("Picture Guid : " + newPicture.Id);
await DBcontext.SaveChangesAsync();
SendNotificationToClient(newPicture);
}
else
{
Services.Log.Info("doorBell Not Found, So creating new one");
var newDoorBell = new DataObjects.DoorBells()
{
Id = Guid.NewGuid().ToString(),
DoorBellID = doorBellId.ToString()
};
DBcontext.DoorBells.Add(newDoorBell);
var newPicture = new DataObjects.Pictures()
{
Id = Guid.NewGuid().ToString(),
Url = imgURL.ToString(),
DoorBellID = doorBellId.ToString()
};
DBcontext.Pictures.Add(newPicture);
await DBcontext.SaveChangesAsync();
Services.Log.Info("NewdoorBell Guid : " + newDoorBell.Id);
Services.Log.Info("Picture Guid : " + newPicture.Id);
SendNotificationToClient(newPicture);
}
// Remove message from queue.
message.Complete();
}
catch (Exception ex)
{
// Indicates a problem, unlock message in queue.
message.Abandon();
Services.Log.Info("Exception :" + ex.Message);
}
}, options);
Services.Log.Info("listenForMessages End");
}
private async void SendNotificationToClient(Pictures item)
{
Services.Log.Info("Sending notification to Client App");
WindowsPushMessage message = new WindowsPushMessage();
var tags = new List<string>();
tags.Add(item.DoorBellID);
// Define the XML paylod for a WNS native toast notification
// that contains the text of the inserted item.
message.XmlPayload = "<toast scenario=\'reminder\' launch =\'deals\'>" +
"<visual>" +
"<binding template =\'ToastGeneric\'>" +
"<text>Door Bell Id</text>" +
"<text>Someone ringing your Door bell with Id: " + item.DoorBellID + "</text>" +
"<image placement=\'inline\' src=\'" + item.Url + "\'/>" +
"</binding></visual>" +
"</toast>";
try
{
var result = await Services.Push.SendAsync(message, tags);
Services.Log.Info(result.State.ToString());
}
catch (System.Exception ex)
{
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
message.XmlPayload =
@"<tile version ='3'>
<visual branding = 'nameAndLogo'>
<binding template = 'TileWide'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
<binding template = 'TileLarge'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
<binding template = 'TileMedium'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
</visual>
</tile>";
try
{
await Services.Push.SendAsync(message, tags);
}
catch (System.Exception ex)
{
// Write the failure result to the logs.
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
}
private Int64 GetTime(DateTime date)
{
Int64 retval = 0;
var st = new DateTime(1970, 1, 1);
TimeSpan t = (DateTime.Now.ToUniversalTime() – st);
retval = (Int64)(t.TotalMilliseconds + 0.5);
return retval;
}
}
}
- The ExecuteAsync method will read the messages from Message Queue with the help of Service Bus connection string which declared in class level variable.
string connectionString =
CloudConfigurationManager.GetSetting("MS_ServiceBusConnectionString");
- We have to check whether the Queue is exist or not, If Queue exist will call the method called listenForMessages which contains code for reading messages from the Queue.
public override Task ExecuteAsync()
{
// Create the queue if it does not exist already.
var namespaceManager =
NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.QueueExists("smartdoordemo"))
{
namespaceManager.CreateQueue("smartdoordemo");
Services.Log.Info("smartdoordemo Queue created successfully!");
}
else
{
Services.Log.Info("smartdoordemo Queue Already Exist!");
}
try
{
listenForMessages();
}
catch (Exception ex)
{
Services.Log.Info("Exception :" + ex.Message);
}
Services.Log.Info("doorlistener scheduled job Done!");
return Task.FromResult(true);
}
- For listening messages from Queue first we need to create a Queue Client
QueueClient Client =
QueueClient.CreateFromConnectionString(connectionString, "smartdoordemo");
- With the help of QueueClient configure Callback method to read messages whenever a new message found, for the callback method have options to setup like AutoComplete, AutoRenewTimeout. Finally will pass the OnMessageOptions to callback method.
// Configure the callback options.
OnMessageOptions options = new OnMessageOptions();
options.AutoComplete = false;
options.AutoRenewTimeout = TimeSpan.FromMinutes(1);
// Callback to handle received messages.
Client.OnMessageAsync(async(message) =>
{
//Code for reading Message Information
}, options);
- OnMessageAsync callback method runs when a new message received from the Queue. In this method we will read the Message and save the Doorbell Id and Picture information in to respective tables into the database.
- Once after reading the message we will manually calls the Message complete method so, that from next time it wont read the same message again. If we set AutoComplete true then there is a chance to miss the messages reading from the Queue.
// Callback to handle received messages.
Client.OnMessageAsync(async(message) =>
{
try
{
Services.Log.Info("Callback to handle received messages");
// Process message from queue.
Services.Log.Info("Body: " + message.GetBody<string>());
Services.Log.Info("MessageID: " + message.MessageId);
Services.Log.Info("doorBellID: " +
message.Properties["doorBellID"]);
Services.Log.Info("imageUrl: " +
message.Properties["imageUrl"]);
var doorBellId = message.Properties["doorBellID"];
var imgURL = message.Properties["imageUrl"];
Services.Log.Info("Query the database");
var doorbell = await(from x in DBcontext.DoorBells
where x.DoorBellID == doorBellId.ToString()
select x).ToListAsync();
Services.Log.Info("Query completed");
if (doorbell.Count > 0)
{
Services.Log.Info("doorBell Already Found");
var newPicture = new DataObjects.Pictures()
{
Id = Guid.NewGuid().ToString(),
Url = imgURL.ToString(),
DoorBellID = doorBellId.ToString()
};
DBcontext.Pictures.Add(newPicture);
Services.Log.Info("Picture Guid : "+ newPicture.Id);
await DBcontext.SaveChangesAsync();
SendNotificationToClient(newPicture);
}
else
{
Services.Log.Info("doorBell Not Found, So creating new one");
var newDoorBell = new DataObjects.DoorBells()
{
Id = Guid.NewGuid().ToString(),
DoorBellID = doorBellId.ToString()
};
DBcontext.DoorBells.Add(newDoorBell);
var newPicture = new DataObjects.Pictures()
{
Id = Guid.NewGuid().ToString(),
Url = imgURL.ToString(),
DoorBellID = doorBellId.ToString()
};
DBcontext.Pictures.Add(newPicture);
await DBcontext.SaveChangesAsync();
Services.Log.Info("NewdoorBell Guid : " + newDoorBell.Id);
Services.Log.Info("Picture Guid : " + newPicture.Id);
SendNotificationToClient(newPicture);
}
// Remove message from queue.
message.Complete();
}
catch (Exception ex)
{
// Indicates a problem, unlock message in queue.
message.Abandon();
Services.Log.Info("Exception :" + ex.Message);
}
}, options);
- Once we read a message from Queue and save the information into database we will send notifications to the Mobile devices or tablets or even to PCs. For that we will call the SendNotificationToClient method.
Sending Push Notification :-
We will send notifications to the respective devices which are registered with the DoorBellID. From Message queue we will get doorbell information and picture URL.
WindowsPushMessage message = new WindowsPushMessage();
var tags = new List<string>();
tags.Add(item.DoorBellID);
// Define the XML paylod for a WNS native toast notification
// that contains the text of the inserted item.
message.XmlPayload = "<toast scenario=\'reminder\' launch =\'deals\'>" +
"<visual>" +
"<binding template =\'ToastGeneric\'>" +
"<text>Door Bell Id</text>" +
"<text>Someone ringing your Door bell with Id: " + item.DoorBellID + "</text>" +
"<image placement=\'inline\' src=\'" + item.Url + "\'/>" +
"</binding></visual>" +
"</toast>";
try
{
var result = await Services.Push.SendAsync(message, tags);
Services.Log.Info(result.State.ToString());
}
catch (System.Exception ex)
{
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
Sending Tile Notifications
message.XmlPayload =
@"<tile version ='3'>
<visual branding = 'nameAndLogo'>
<binding template = 'TileWide'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
<binding template = 'TileLarge'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
<binding template = 'TileMedium'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
</visual>
</tile>";
try
{
await Services.Push.SendAsync(message, tags);
}
catch (System.Exception ex)
{
// Write the failure result to the logs.
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
Complete code for SendingNotificationToClient Method:
private async void SendNotificationToClient(Pictures item)
{
Services.Log.Info("Sending notification to Client App");
WindowsPushMessage message = new WindowsPushMessage();
var tags = new List<string>();
tags.Add(item.DoorBellID);
// Define the XML paylod for a WNS native toast notification
// that contains the text of the inserted item.
message.XmlPayload = "<toast scenario=\'reminder\' launch =\'deals\'>" +
"<visual>" +
"<binding template =\'ToastGeneric\'>" +
"<text>Door Bell Id</text>" +
"<text>Someone ringing your Door bell with Id: " + item.DoorBellID + "</text>" +
"<image placement=\'inline\' src=\'" + item.Url + "\'/>" +
"</binding></visual>" +
"</toast>";
try
{
var result = await Services.Push.SendAsync(message, tags);
Services.Log.Info(result.State.ToString());
}
catch (System.Exception ex)
{
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
message.XmlPayload =
@"<tile version ='3'>
<visual branding = 'nameAndLogo'>
<binding template = 'TileWide'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
<binding template = 'TileLarge'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
<binding template = 'TileMedium'>
<image src='" + item.Url + @"' placement='background' hint-overlay='60'/>
<image src='" + item.Url + @"' placement='peek'/>
<group>
<subgroup>
<text hint-style ='body'>Door Bell Id</text>
<text hint-style ='captionSubtle' hint-wrap = 'true'>" + item.DoorBellID + @"</text>
</subgroup>
</group>
</binding>
</visual>
</tile>";
try
{
await Services.Push.SendAsync(message, tags);
}
catch (System.Exception ex)
{
// Write the failure result to the logs.
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
}
Now we are ready to publish the Mobile Service project code to Azure. After publishing the code to Azure we need to configure the scheduler to run every minute to read the messages from the queue.
Go to Azure classic Portal –> Go to Mobile Service (iotpoc) –> Scheduler
Select the doorlistener scheduled job and go to Schedule Section then set the Every to 1 minute.
If you are not seeing your doorlistener job under Scheduler then create a new ScheduledJob from Create button which is located under bottom of the portal page and give the same name of the Scheduled Job which you created in your service project.
(or)
Now we need a client app which will get notified when ever a person rings your doorbell.
Step 7: Building UWP Client App called DoorBellCLient- Create a new project in visual studio 2015.
Connect the mobile service to the Project by creating object to the mobile service. Add the WindowsAzure MobileServices Sdk to the project. Add the following code in App.xaml.cs file.
public static MobileServiceClient MobileService = new MobileServiceClient("https://iotpoc.azure-mobile.net/", " * *************************");
Call the following method from OnLaunched method which will register the device for accepting toast notifications and tile notifications.
private async Task RegisterForNotificationsAsync()
{
try
{
var channel = await Windows.Networking.PushNotifications.PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
var tags = new List<string>();
tags.Add("123456");
await App.MobileService.GetPush().RegisterNativeAsync(channel.Uri, tags);
}
catch (Exception ex)
{
}
}
In the above method we are passing the tags to the notifications register method in which we will add all doorbell Ids here in this sample I am passing 123456 as doorbellId, In real time scenario we have to pass the doorbell Id dynamically instead of hard coding.
Open MainPage.Xaml Page and add the following code.
<Page
x:Class="DoorBellClient.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DoorBellClient"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Items}"/>
<DataTemplate x:Key="Standard130ItemTemplatedeal">
<Grid Height="310" Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="310"></RowDefinition>
</Grid.RowDefinitions>
<Border Background="#1e364f" Width="310" Height="310" Grid.Row="0">
<Image Source="{Binding Url}" Stretch="Fill"/>
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="20,0,0,0" Grid.RowSpan="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="DoorBell Id:" Style="{StaticResource SubheaderTextBlockStyle}" Foreground="White" TextWrapping="NoWrap"></TextBlock>
<TextBlock Text="{Binding DoorBellID}" Style="{StaticResource SubheaderTextBlockStyle}"
Foreground="White" TextWrapping="NoWrap" Margin="5,0,0,0"/>
</StackPanel>
<TextBlock Text="Date/Time:" Style="{StaticResource SubtitleTextBlockStyle}" Foreground="White" TextWrapping="NoWrap"></TextBlock>
<TextBlock Text="{Binding UpdatedAt}" Style="{StaticResource SubtitleTextBlockStyle}"
Foreground="White" TextWrapping="NoWrap"></TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Refresh" Click="Button_Click" VerticalAlignment="Top"
HorizontalAlignment="Right" Margin="5"/>
<ProgressBar x:Name="progressBar" IsIndeterminate="True" VerticalAlignment="Top"
Foreground="Cyan" Background="Transparent"
Visibility="Collapsed"/>
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemsListView"
AutomationProperties.Name="Items"
TabIndex="1"
Grid.Row="1"
Margin="10,40,0,0" SelectionMode="None"
Padding="0,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
IsSwipeEnabled="False"
ItemTemplate="{StaticResource Standard130ItemTemplatedeal}"/>
</Grid>
</Page>
- Add Azure Mobile Services reference from NuGet package manager and add the following two models into the solution.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json;
namespace DoorBellClient.Models
{
public class Pictures
{
public string Id { get; set; }
[JsonProperty(PropertyName = "Url")]
public string Url { get; set; }
[JsonProperty(PropertyName = "DoorBellID")]
public string DoorBellID { get; set; }
[UpdatedAt]
public DateTimeOffset UpdatedAt { get; set; }
}
}
using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DoorBellClient.Models
{
public class DoorBells
{
public string Id { get; set; }
[JsonProperty(PropertyName = "DoorBellID")]
public string DoorBellID { get; set; }
[JsonProperty(PropertyName = "PicturesId")]
public string PicturesId { get; set; }
[UpdatedAt]
public DateTimeOffset UpdatedAt { get; set; }
}
}
- In MainPage.xaml.cs file replace the code with the following code.
using DoorBellClient.Models;
using Microsoft.WindowsAzure.MobileServices;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Threading.Tasks;
using Windows.UI.Popups;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace DoorBellClient
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private IMobileServiceTable<Pictures> picturesTbl = App.MobileService.GetTable<Pictures>();
private Timer timer;
public MainPage()
{
this.InitializeComponent();
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
if (App.ConnectedToInternet())
{
loadPics();
timer = new Timer(new TimerCallback(timer_Tick), timer, 15000, 15000);
}
else
{
await new MessageDialog("Please check your Internet Connection").ShowAsync();
}
}
private void timer_Tick(object state)
{
loadPics();
}
private async void loadPics()
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
progressBar.Visibility = Visibility.Visible;
var pictures = await picturesTbl.Where(x => x.DoorBellID == "123456").OrderByDescending(x => x.UpdatedAt).ToCollectionAsync();
itemListView.ItemsSource = pictures;
progressBar.Visibility = Visibility.Collapsed;
});
}
private void Button_Click(object sender, RoutedEventArgs e)
{
loadPics();
}
}
}
- Now the app is ready to display the doorbell Id with respective pictures in the app.But for receiving notifications we need to do little more work.
Associate DoorBellClient app to the Store :
- Right click on DoorBellClient Project and select store option and then click on Associate app with the store.
- Login to your Devcenter account.
- After that reserve a new app name in the store or Select existing app.
- After reserving the name click on ok and then click on associate.
- Now, project is associated with the app.
Adding Package SID and Client secret to the mobile services :
- Go to your Devcenter Dashboard, select your app and go to Push notifications under Services section.
- After that click on live services site PACKAGE SID and CLIENT SECRET.
- Open your mobile service (iotpoc) and select the Push tab paste the Package SID and Client secrete under Windows application credentials. After pasting save the details.
Screenshots for the Client App In PC :
Screenshots for the Client App In PC :
Comments