cloud-based iot platformmokkas/files/michal_gutowski _s10894_bsc... · having selected microsoft...

113
FACULTY OF C OMPUTER S CIENCE D EPARTMENT OF C OMPUTER N ETWORKS MOBILE NETWORKING Michal Gutowski s10894 Cloud-based IoT platform Bachelor Thesis dr Michal Tomaszewski Warsaw, September 2017

Upload: others

Post on 04-Jun-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

FACULTY OF COMPUTER SCIENCE

DEPARTMENT OF COMPUTER NETWORKS

MOBILE NETWORKING

Michał Gutowskis10894

Cloud-based IoT platform

Bachelor Thesisdr Michał Tomaszewski

Warsaw, September 2017

Page 2: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

WYDZIAŁ INFORMATYKI

KATEDRA SIECI KOMPUTEROWYCH

SIECI URZADZEN MOBILNYCH

Michał Gutowskis10894

Platforma IoT oparta na usługachdziałajacych w chmurze

Praca Inzynierskadr Michał Tomaszewski

Warszawa, Wrzesien 2017

Page 3: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Contents

Introduction 1

1 Cloud Infrastructure 31.1 Choosing a Cloud Provider . . . . . . . . . . . . . . . . . . . . . 31.2 Designing Cloud Infrastructure . . . . . . . . . . . . . . . . . . . 5

2 Authentication and Authorization 112.1 IoT Gateway Identity . . . . . . . . . . . . . . . . . . . . . . . . 112.2 Cloud Service Identity . . . . . . . . . . . . . . . . . . . . . . . 182.3 User Authentication & Authorization . . . . . . . . . . . . . . . . 23

2.3.1 Mobile App Backend Authentication . . . . . . . . . . . 232.3.2 Client App Authentication . . . . . . . . . . . . . . . . . 25

3 Cloud Message Routing 283.1 IoT Hub Device-to-Cloud Message Routing . . . . . . . . . . . . 28

3.1.1 Event Processing Service Implementation . . . . . . . . . 313.2 Service Bus Queue Message Routing . . . . . . . . . . . . . . . . 35

3.2.1 WebJob Console Application Implementation . . . . . . . 35

4 Mobile App Backend 414.1 .NET Backend . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424.2 Data Persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

5 IoT Gateway 545.1 OS and Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . 555.2 UWP Application . . . . . . . . . . . . . . . . . . . . . . . . . . 57

5.2.1 Sensor Drivers . . . . . . . . . . . . . . . . . . . . . . . 605.2.2 Bluetooth Low Energy Connectivity . . . . . . . . . . . . 705.2.3 IoT Hub Connectivity . . . . . . . . . . . . . . . . . . . 78

i

Page 4: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

6 Client Application 856.1 User Interface Layout . . . . . . . . . . . . . . . . . . . . . . . . 876.2 Communication With Backend Service . . . . . . . . . . . . . . . 936.3 Push Notification Channel . . . . . . . . . . . . . . . . . . . . . 96

Conclusions 1016.4 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016.5 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102

Bibliography 103

ii

Page 5: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud
Page 6: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Abstract

The aim of this thesis is to build an IoT platform that enables its usersto receive real-time telemetry data and control Bluetooth Low Energy(BLE) devices connected to the central IoT device. The platform, co-denamed SlickHub, is composed of the IoT gateway, the cloud in-frastructure, and the software necessary to control the platform com-ponents. The IoT gateway enables BLE devices that are not directlyconnected to the Internet to reach cloud infrastructure and allows forcollecting telemetry data through the connected sensors. The teleme-try data includes the measurements of temperature, humidity, and at-mospheric pressure.

The hardware setup consists of the Raspberry Pi 3 Model B (IoT gate-way) and the atmospheric sensors. The IoT gateway is running Win-dows 10 IoT Core operating system with installed Universal WindowsPlatform (UWP) app.

The cloud infrastructure is based on Azure Cloud Services and is thecentral part of the platform responsible for managing the communi-cation between the IoT gateway and the client application running onthe user’s device.

Page 7: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud
Page 8: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Streszczenie

Celem pracy jest zbudowanie platformy IoT, która pozwala swoimuzytkownikom na odbieranie danych telemetrycznych przesyłanychw czasie rzeczywistym oraz kontrolowanie urzadzen Bluetooth LowEnergy (BLE) podłaczonych do centralnego urzadzenia IoT. Platformeo nazwie kodowej SlickHub współtworza urzadzenie bedace bramaIoT, infrastruktura chmurowa, oraz oprogramowanie niezbedne do za-rzadzania komponentami platformy. Brama IoT pozwala urzadzeniomBLE, które nie sa bezposrednio podłaczone do sieci Internet, na ko-munikacje z infrastruktura chmurowa, a takze odpowiada za zbieraniedanych telemetrycznych z podłaczonych sensorów. W skład danychtelemetrycznych wchodza pomiary temperatury, wilgotnosci powie-trza, oraz cisnienia atmosferycznego.

Konfiguracja sprzetowa składa sie z Raspberry Pi 3 Model B (be-dacego brama IoT) oraz sensorów wykonujacych pomiary atmosfe-ryczne. Brama IoT działa pod kontrola systemu operacyjnego Win-dows 10 IoT Core z zainstalowana aplikacja typu Universal WindowsPlatform (UWP).

Infrastruktura chmurowa bazuje na serwisach chmurowych platformyAzure i jest centralna czescia platformy odpowiedzialna za zarzadza-nie wymiana informacji pomiedzy brama IoT a aplikacja klienckadziałajaca na urzadzeniu uzytkownika.

Page 9: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Introduction

Internet of Things (IoT) can be described as an interconnected ecosystem of com-

puting devices embedded with network connectivity which can collect and ex-

change data. Such data can then be processed and presented to the end-user in

a meaningful way. The concept of IoT dates back to 1982, however due to the

technological limitations the concept was not so popular until the start of the 21st

Century. As of 2014, IoT market has started to rapidly gain traction due to a

convergence and general availability of cloud-enabled technologies. Nonetheless,

there are still many challenges to face among which the most critical ones are

interoperability of individual IoT devices, as well as the privacy and security con-

cerns.

This project aims to resolve the above key concerns by introducing the IoT

solution which can not only provide end-to-end security, but also deliver a cen-

tralized way to control other IoT-capable devices.

One of the most popular IoT applications is home automation. So far, there are

at least couple of different approaches to smart home solutions, and this project

is built around the idea of an IoT gateway. The IoT gateway is a cloud-enabled

device which lets the user connect individual IoT accessories such as smart light

bulbs or thermostats in order to customize and control user’s smart home. If im-

plemented correctly, such a solution can provide a secure connection and wide

product compatibility which I believe is a key to successful home automation.

1

Page 10: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

The IoT solution presented in this thesis has been designed to be highly scal-

able, modular, maintainable, and thus easy to extend with new functionalities. The

key design decisions were the selection of hardware and cloud service provider.

It was necessary to ensure that the selected hardware has a built-in support for

Bluetooth Low Energy, which is one of the most popular standards for wireless

communication. It was also crucial to choose the cloud service provider capable

of delivering all the services required for building a scalable and reliable cloud

infrastructure that can handle a large number of IoT devices. As a result, it was

possible to build the IoT platform that can serve as a solid base for numerous IoT

solutions.

2

Page 11: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Chapter 1

Cloud Infrastructure

1.1 Choosing a Cloud Provider

Choosing a cloud provider that can satisfy project requirements is a key to suc-

cessful implementation of a cloud solution. At the time of writing this thesis,

there were four industry-leading providers which, according to Synergy Research

Group, together accounted for more than 50% of the market share in Q4 2016.

Figure 1.1: Industry-Leading Cloud Service Providers

Having in mind the data presented in figure 1.1, it was decided to analyse

IoT solutions offered by Amazon Web Services (AWS), Microsoft Azure, Google

3

Page 12: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Cloud Platform, and IBM Bluemix. At this point it was important to recall all

project requirements that could strongly influence the decision-making process.

cIt has been stated that the application running on IoT gateway should provide

its user with a graphical user interface. During the project development Windows

10 IoT Core was the only OS, targeting embedded devices, offering SDK for de-

veloping apps with rich and touch-enabled GUI. The choice of Windows 10 IoT

Core and Universal Windows Platform indicated that the optimal IoT cloud ser-

vice should deliver SDK for connecting devices controlled with UWP app. While

choosing the cloud provider it was also taken into account the variety of supported

connection protocols, communication patterns, authentication features, and avail-

ability of Mobile backend as a service (MBaaS).

The results of the analysis have shown that all four platforms deliver support for

Hypertext Transfer Protocol (HTTP) and Message Queue Telemetry Transport

(MQTT) protocols, Transport Layer Security (TLS), strong authentication meth-

ods, as well as MBaaS. However, Microsoft Azure turned out to be the only plat-

form that provided services with built-in Advanced Message Queuing Protocol

(AMQP) support and open source subset of the .NET SDK including client SDK

for UWP apps. Greater variety of communication protocols means more flexi-

bility, whereas native C# SDK allows to safe a lot of time both in development

and integration. This makes Microsoft Azure an ideal cloud service provider for

discussed project.

4

Page 13: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

1.2 Designing Cloud Infrastructure

Having selected Microsoft Azure as a cloud service provider, it was possible to

move on to designing the cloud infrastructure. Azure offers a wide range of com-

pute options, ranging from virtual machines to specialized cloud services like IoT

Hub, thus providing a great flexibility when it comes to design decisions.

When designing the cloud infrastructure, the starting point was to define the end-

points of the IoT platform and specifying the amount and type of data that will be

sent and received by each endpoint. The platform should enable users to remotely

control Bluetooth Smart IoT accessories via client application installed on user’s

smartphone, tablet, or desktop PC. Based on that, we can conclude that there are

two platform endpoints - client application and IoT gateway. From the cloud per-

spective, client application will authenticate with the cloud, send HTTP requests

to the cloud, and receive notifications from the cloud. IoT gateway will authenti-

cate with the cloud, send telemetry/connectivity data to the cloud and interpret the

commands received from the cloud. To ensure responsiveness, the IoT platform

will need to leverage the real-time data processing.

Figure 1.2: IoT Platform - Endpoints

After establishing the endpoints shown in figure 1.2, it was possible to proceed

with the selection of cloud services. The decision was taken to start with IoT gate-

way and look for the Azure services designed for connecting IoT devices to the

cloud. Azure offers two very powerful event processing services, namely Azure

Event Hub and Azure IoT Hub. Both services enable event and telemetry ingress

5

Page 14: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

to the cloud at massive scale, ensuring low latency and high reliability. However,

IoT Hub is equipped with IoT-specific features making it especially suited for

IoT solutions. Unlike Event Hub, IoT Hub enables bi-directional communication

(both device-to-cloud and cloud-to-device), device state information, per-device

identity, file uploads from devices to the cloud, enhanced device protocol support,

and custom message routing rules. Additionally, IoT Hub is optimized to support

millions of simultaneously connected devices, whereas Event Hub can support a

more limited number of concurrent connections (up to 5,000 AMQP connections

[14]). At this point, it has been clear that IoT Hub is the right choice for the IoT

platform.

The next step was to decide which of the supported protocols to use in order to

connect IoT gateway device with IoT Hub cloud service.

Azure IoT Hub natively supports multiple communication protocols including

MQTT, AMQP, and HTTP. Since the IoT gateway is an embedded device with

limited processing power 1, it was decided to opt out the HTTP long polling in fa-

vor of event driven communication. That left a choice between MQTT and AMQP

protocols. While both protocols work on top of TCP/IP protocol suite, they differ

significantly in terms of the utilized communication models.

MQTT is a lightweight messaging protocol based on publish-subscribe model.

It has been designed for resource-constrained devices which use low bandwidth

and/or high latency networks. MQTT introduces the concepts of MQTT client

and MQTT broker. MQTT client is any device that has MQTT library running and

connecting to MQTT broker, whereas MQTT broker is responsible for receiving,

filtering, routing, and sending all messages to the relevant subscribed clients. It

can be said that MQTT broker is a middleware between two MQTT clients. The

main advantages of MQTT are fast communication model, small wire footprint,

1The hardware selection decisions are described in detail in chapter 5.

6

Page 15: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

and the relative simplicity of the protocol itself.

AMQP 1.0 is an efficient, binary wire-level, peer-to-peer protocol for reliable mes-

saging. Unlike MQTT, it doesn’t impose a particular structural mode, therefore it

can be used to support different topologies. AMQP has a rich feature set which

includes flexible routing model, reliable message queuing, transactions, and secu-

rity. Its main advantages are efficiency, reliability, and flexibility.

In case of IoT gateway, the extra overhead of AMQP long-lived sessions was not

a great concern and an overarching goal was to ensure secure and reliable con-

nection between the gateway and cloud service. Therefore, it was decided to use

AMQP protocol as a solid base for bi-directional communication between the IoT

gateway and cloud.

While Azure IoT Hub can handle device-to-cloud and cloud-to-device mes-

saging, the inbound messages need to be processed by back-end app in order to

be securely delivered to the authenticated user’s device. For that to happen, the

cloud infrastructure will need to include services responsible for message routing

and message queuing. IoT Hub exposes a built-in service-facing endpoint [18] to

enable other cloud services to read the device-to-cloud messages received by the

hub. This built-in endpoint is compatible with Event Hubs, which support several

mechanisms for reading messages. One of such mechanisms is the Event Hub

Processor hosted in Azure Worker Role. As a matter of fact, IoT Hub message

routing pattern has become so common that in December 2016 Microsoft has de-

cided to add a message routing feature directly to IoT Hub, making it possible to

add custom endpoints and routes. Both mechanisms have advantages and disad-

vantages 2, and the proposed cloud infrastructure assumes the use of any of the two

mechanisms with a preference for IoT Hub message routing whenever possible.

Once the device-to-cloud messages have been correctly filtered and routed,

2Chapter 3 provides a more detailed explanation of both of these mechanisms.

7

Page 16: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

they need to be reliably delivered to the back-end app for further processing. In

order to achieve this goal, Microsoft Azure offers a set of specialized queuing

mechanisms. At the time of writing the thesis, there are two types of queue mech-

anisms supported by Microsoft Azure; namely, Storage queues and Service Bus

queues. Based on the recommendations [19] provided by Microsoft, it was de-

cided to utilize the Service Bus queues. This queuing technology will satisfy the

reliability requirement by providing first-in-first-out (FIFO) ordered delivery, au-

tomatic duplicate detection, and at-most-once delivery guarantee. Furthermore,

using Service Bus queues provides an inherent loose coupling between the com-

ponents, because the producers (senders) and consumers (receivers) are not aware

of each other. This allows for the consumer to be upgraded without having any

effect on the producer. It was also decided to set up two Service Bus queues, one

for queuing telemetry data and the other one for queuing connectivity data. With

such a configuration, the messages containing sensor readings will be routed to

telemetry queue and messages containing information about newly connected ac-

cessories will be routed to connectivity queue respectively. This should result in

the higher throughput of the infrastructure, thus increasing the responsiveness.

The very last part of architecting the cloud infrastructure was the selection of

backend services. Microsoft Azure offers several ways to host backend solutions,

therefore before making the decision it was necessary to analyse all the require-

ments for backend functionality.

The backend service should expose REST API with endpoints for authenticating

users, registering IoT gateways at the IoT Hub identity registry, as well as re-

trieving information about and sending commands to the registered IoT gateways.

It should also provide push notifications, integration with social networking ser-

vices, and cloud storage. These requirements suggest the use of a model called

Mobile Backend as a Service (MBaaS). Microsoft Azure App Service platform

8

Page 17: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

offers several hosting resources, each of which is dedicated to running a specific

workload. One of the hosting resources is called Azure Mobile App and it is com-

pliant with MBaaS model, which makes it an ideal choice for the infrastructure.

Moving on to the cloud storage solution, it was opted to use Azure SQL Database

in favor of classical relational database ensuring advanced indexing capabilities

and high data integrity. Push notifications will be dispatched to the client applica-

tion via Azure Notification Hub, which delivers multi-platform, scaled-out push

notification engine. Both Azure SQL Database and Azure Notification Hub can

be easily integrated with the Azure Mobile App.

Having chosen the above services, the only remaining problem was to dequeue

the messages arriving at Service Bus queue and route them to the Notification

Hub in order for them to be dispatched to the authenticated users. Unlike IoT

Hub, Azure Mobile App does not provide a built-in message routing capabilities.

It does, however, allow for running background processes by means of Azure We-

bJobs. The idea behind WebJobs is to enable programs or scripts to be hosted and

run alongside the Azure App Service web app. Furthermore, WebJobs are well

suited for real-time processing scenarios as they can be configured to run contin-

uously. From the cloud infrastructure perspective, the mentioned characteristics

make WebJobs an optimal solution for running background tasks that will wire-up

the cloud services on the backend side.

Figure 1.3 presents a complete set of cloud services that constitute the cloud in-

frastructure.

9

Page 18: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Figure 1.3: IoT Platform - Final Cloud Infrastructure

10

Page 19: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Chapter 2

Authentication and Authorization

Without a doubt, IoT security is an issue of high concern. As the number of

connected IoT devices grows, the attack surface increases making the security one

of the biggest challenges in implementing IoT solutions. In order to address this

challenge a special care has been taken regarding the design and implementation

decisions that affect the security of individual components and IoT platform as a

whole. The sections below describe the key aspects of the security mechanisms

used to protect platform resources.

2.1 IoT Gateway Identity

The cloud infrastructure discussed in chapter 1 shows that every IoT gateway

establishes a bi-directional communication with the cloud by connecting to the

Azure IoT Hub. However, before an IoT gateway can connect to the IoT Hub,

it must be authenticated based on credentials that uniquely identify the device

and grant access to a set of per-device resources. To enable per-device identity,

IoT Hub has a built in identity registry [20] - an authentication model for man-

aging per-device credentials. The identity registry stores device identities, au-

thentication keys, and status codes. Every device that is being provisioned must

be registered in the identity registry with a unique device ID. The IoT gateway

11

Page 20: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

provisioning process is handled by Azure Mobile App backend service 1, which

exposes REST API for registering new devices with the IoT platform.

Listing 2.1: IoT Gateway Provisioning Endpoint

[HttpPost][Route("")][ResponseType(typeof(BootstrapResponse))]public async Task<IHttpActionResult> Post([FromBody]BootstrapRequest

bootstrapRequest){

var account = await GetAuthorizedUserAccountAsync<MasterAccount>();

string connectionString;

try{

connectionString = await GetDeviceConnectionStringAsync(bootstrapRequest.DeviceId, account);

if (connectionString != null){

return Ok(new BootstrapResponse{

ConnectionString = connectionString});

}}catch (Exception){

return Unauthorized();}

if (account == null){

account = await CreateAuthorizedUserAccountAsync<MasterAccount>();}

connectionString = await CreateDeviceAsync(bootstrapRequest.DeviceId, account);

await UnitOfWork.CompleteAsync();

return Ok(new BootstrapResponse{

ConnectionString = connectionString});

}

...

private async Task<string> CreateDeviceAsync(Guid deviceId, MasterAccount account)

{var device = new Device{

Id = deviceId,Account = account

1The Mobile App backend service is described in detail in chapter 4.

12

Page 21: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

};

UnitOfWork.Devices.Add(device);

var iotDevice = await IotHubRegistryService.AddIotDeviceAsync(deviceId);

return iotDevice.GetConnectionString();}

...

The action method responsible for handling IoT gateway provisioning requests

is contained inside the controller decorated with Authorize attribute. This implies

that the provisioning request can only be made by an authenticated user (see sec-

tion 2.3). The CreateDeviceAsync method adds a new record to the Devices table

and delegates a registration process to the AddIotDeviceAsync method exposed

by IotHubRegistryService class. Once the IoT gateway is successfully registered

in the identity registry, the action method returns a connection string, in the format

HostName={iothubname};DeviceId={deviceid};SharedAccessKey={devicekey}, that

enables IoT gateway to establish a connection to the IoT Hub.

Listing 2.2: Registration of IoT Gateway in IoT Hub Identity Registry

public async Task<Device> AddIotDeviceAsync(Guid deviceId){

Device device;

try{

device = await registry.AddDeviceAsync(new Device(deviceId.ToString()));}catch (DeviceAlreadyExistsException){

device = await registry.GetDeviceAsync(deviceId.ToString());}

return device;}

The AddIotDeviceAsync method registers a new device with the IoT Hub using

an instance of RegistryManager class, which is a part of Microsoft.Azure.

Devices NuGet package.

Once the IoT gateway has received the connection string, it is ready to authen-

ticate itself to the IoT Hub. As described in chapter 1, the communication be-

13

Page 22: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

tween IoT Hub and IoT gateway is based on AMQP 1.0 messaging protocol.

The IoT Hub supports two authentication mechanisms [16] for AMQP clients;

namely, SASL PLAIN and AMQP Claims-Based-Security. The IoT gateway uses

the latter mechanism (AMQP CBS) to ensure efficient use of network resources

and lower the latency of each device connection. The current implementation

of UWP app responsible for managing IoT gateway uses a DeviceClient class

from Microsoft.Azure.Devices.Client NuGet package for establish-

ing AMQP connection with IoT Hub. However, before June 2016 the Device SDK

for Azure IoT Devices did not support communication over AMQP for UWP apps.

The workaround was to use AMQPNetLite library that provides an AMQP proto-

col stack for multiple .Net frameworks including UWP apps. The downside of us-

ing AMQPNetLite library was that the client component responsible for creating

secure connection to IoT Hub had to be implemented from scratch. Nevertheless,

it was decided to use the code from my AMQPNetLite-based implementation of

DeviceClient class to better explain the process of transmitting SAS tokens as part

of claims-based authentication.

The IoT Hub authenticates a specific device by verifying a token against the secu-

rity credentials stored in the identity registry, but before the token can be transmit-

ted one must be first created. The security token structure supported by IoT Hub

along with the sample snippets for generating the token is described in MSDN

documentation [16].

Listing 2.3: Generating Security Token

private static string CreateSharedAccessSignatureToken(string resourceUri, stringsharedAccessKey, TimeSpan ttl)

{// For more information about generating a SAS token, see// https://azure.microsoft.com/en-us/documentation/articles/service-bus-sas-

overview/

string expiry = (DateTimeOffset.UtcNow + ttl).ToUnixTimeSeconds().ToString();string stringToSign = WebUtility.UrlEncode(resourceUri) + "\n" + expiry;

var objMacProv = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.

14

Page 23: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

HmacSha256);

var hash = objMacProv.CreateHash(Convert.FromBase64String(sharedAccessKey).AsBuffer());

hash.Append(CryptographicBuffer.ConvertStringToBinary(stringToSign,BinaryStringEncoding.Utf8));

string signature = CryptographicBuffer.EncodeToBase64String(hash.GetValueAndReset());

var sasToken = string.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}",

WebUtility.UrlEncode(resourceUri), WebUtility.UrlEncode(signature), WebUtility.UrlEncode(expiry));

return sasToken;}

The CreateSharedAccessSignatureToken method computes the SAS token from

the specified inputs, which include resource URI ({IoT hub name}.azure-devices

.net/devices/{deviceid}), signing key for the ’{deviceid}’ identity, and a time in-

terval used to calculate expiration time. A signing key used for creating base-

64 encoded signature is a symmetric key stored in the IoT Hub identity reg-

istry and returned as part of IoT gateway connection string. The resulting secu-

rity token has the following format: SharedAccessSignature sr={URL-encoded-

resourceURI}&sig={signature-string}&se={expiry}. It is worth noting that when

using the symmetric key from the identity registry, the ’{policyName}’ (skn) ele-

ment of the token is omitted.

Once the security token has been generated, it is ready to be transmitted to the IoT

Hub for verification. The implementation of the token transmission process fol-

lows the AMQP 1.0 authentication scheme described in the official OASIS stan-

dard specification for AMQP CBS [22].

Listing 2.4: Sending Token to IoT Hubs CBS Node

private static async Task PutCbsTokenAsync(Connection connection, string token,string audience)

{// For more information about an AMQP authentication scheme based on claims-

based security tokens, see// https://www.oasis-open.org/committees/download.php/50506/amqp-cbs-v1%200-

15

Page 24: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

wd02%202013-08-12.doc

Session session = new Session(connection);

const string cbsReplyToAddress = "cbs-reply-to";

// Note that we MUST initialize both AMQP links before sending the SAS token;// otherwise the reply from the service will never get delivered.var cbsSender = new SenderLink(session, "cbs-sender", "$cbs");var cbsReceiver = new ReceiverLink(session, cbsReplyToAddress, "$cbs");

// Construct and transfer a "put-token" messagevar request = CreatePutTokenRequestMessage(token, cbsReplyToAddress, audience

);

await cbsSender.SendAsync(request);

// Process a token validation resultvar response = await cbsReceiver.ReceiveAsync();

VerifyPutTokenResponseMessage(response);

// Clean-upawait cbsSender.CloseAsync();await cbsReceiver.CloseAsync();await session.CloseAsync();

}

private static Message CreatePutTokenRequestMessage(string token, string replyTo,string audience)

{var message = new Message(token){

Properties = new Properties{

MessageId = Guid.NewGuid().ToString(),ReplyTo = replyTo

},ApplicationProperties = new ApplicationProperties{

["operation"] = "put-token",["type"] = "azure-devices.net:sastoken",["name"] = audience

}};

return message;}

According to the specification, the token transmission begins by sending a

’put-token’ message to an AMQP endpoint responsible for managing tokens. This

endpoint is referred to as a Claim-Based Security Node (CBS Node). The PutCb-

sTokenAsync method creates a new session using the specified AMQP connection,

opens sender and receiver links to CBS Node with the address ’$cbs’, creates and

16

Page 25: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

sends the ’put-token’ message over the sender link, and processes the token val-

idation result received by the receiver link. If the response message contains a

200 OK HTTP response code, then the request is considered successful and the

Client is authorized to access device-facing endpoints exposed by IoT Hub. The

CreatePutTokenRequestMessage method creates a ’put-token’ message according

to the format defined by the AMQP CBS specification [22]. It is important to

note that the CBS is connection-scoped, which means that the links to CBS Node

must be made over the same connection as the links to /devices/deviceid/mes-

sages/events and /devices/deviceid/messages/deviceBound nodes 2 that are being

secured using CBS. It is also important to remember that the SAS tokens grant a

time-bounded access to claimed resources, therefore the Client must send updated

tokens to the CBS Node in order to keep the TCP connection alive.

Listing 2.5: Establishing Connection With Azure IoT Hub

private async Task EstablishConnectionAsync(){

var connState = ConnectionState;

if (connState != ConnectionState.Closed && connState != ConnectionState.Broken &&CbsTokenExpiryTime > DateTime.UtcNow)

{return;

}

connEstablishedEvent.Reset();

ConnectionState = ConnectionState.Connecting;

var createSession = connState == ConnectionState.Closed || connState ==ConnectionState.Broken;

try{

if (createSession){

CreateNewSession();}

CbsTokenExpiryTime = await AuthenticateAsync(session.Connection,DeviceCredentials.HostName, DeviceCredentials.DeviceId,DeviceCredentials.SharedAccessKey);

2The two listed nodes correspond to IoT Hubs device-to-cloud and cloud-to-device endpointsrespectively.

17

Page 26: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

// Create the sender and receiver linksvar entity = string.Format("/devices/{0}/messages/events",

DeviceCredentials.DeviceId);

senderLink = new SenderLink(session, "sender-link", entity);

entity = string.Format("/devices/{0}/messages/deviceBound",DeviceCredentials.DeviceId);

receiverLink = new ReceiverLink(session, "receiver-link", entity);}catch (Exception){

ConnectionState = ConnectionState.Broken;throw;

}

ConnectionState = ConnectionState.Open;

// Signal to the waiting threads that the connection has been successfullyestablished

connEstablishedEvent.Set();}

2.2 Cloud Service Identity

While most of the authentication scenarios focus on user-to-service authentica-

tion, it is often necessary for one cloud service to call API of another cloud ser-

vice. Such a scenario is usually referred to as service-to-service authentication.

During the development of cloud message routing 3 it was necessary to solve the

problem of mapping the IoT gateway to associated user and sending push noti-

fications to all devices registered by that user (targeted push). As explained in

chapter 1, the responsibility of sending push notifications has been delegated to

Azure WebJob instances running alongside the Mobile App backend service. In

order to enable targeted push, the WebJob instance has to retrieve a list of user ID

tags for the given IoT gateway ID. The user ID tag consists of _UserId: prefix fol-

lowed by SID of an authenticated user stored in the database. The infrastructure

assumes that Mobile App backend service has the exclusive access to the platform

3Cloud message routing implementation details are covered in chapter 3.

18

Page 27: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

database, which means that in order to enable WebJob instances to retrieve user

ID tags the backend service must expose the relevant endpoints. Azure App Ser-

vice offers three authentication methods for handling service-to-service scenarios

[8]; namely Azure Active Directory, client certificates, and basic authentication.

While Azure Active Directory will suit most of the service-to-service authenti-

cation scenarios, in case of WebJob-to-AppService authentication it is enough to

use basic authentication. It is important to remember that the App Service back-

end along with the attached WebJob instances share the same physical resources.

This implies that the backend and WebJob instances can share a secret that will be

securely stored in the server and used to authorize API calls.

App Service issues a JSON web token (JWT) to every client authenticated with

third-party identity provider (see section 2.3). The obtained authentication token

is then included in all requests made to the App Service backend, allowing client

to perform actions that require authenticated-user level permissions. The tokens

issued by App Service are signed with the symmetric security key known as the

signing key. The signing key is stored in WEBSITE_AUTH_SIGNING_KEY envi-

ronment variable. To enable viewing App Service server environment variables,

Azure provides a set of troubleshooting and analysis tools called KUDU.

The KUDU console can be accessed by navigating to:

"https://{app-service-name}.scm.azurewebsites.net".

19

Page 28: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Figure 2.1: KUDU Console - Environment Variables

The environment variables can be accessed by all services hosted by the server,

thus allowing the WebJob console application to retrieve the value of WEBSITE

_AUTH_SIGNING_KEY environment variable to obtain the signing key. The re-

trieved key can then be used to create a valid JSON web token as shown in the

following source code listing.

Listing 2.6: Factory Class Used For Creating JSON Web Token

internal class AuthenticationTokenFactory{

private static readonly TimeSpan DefaultLifetime = TimeSpan.FromHours(1);

private readonly IList<Claim> OutputClaims = new List<Claim> { new Claim(ClaimTypes.Role, "WebJob") };

public AuthenticationTokenFactory(){

var groupSid = CloudConfigurationManager.GetSetting(Constants.Identity.SidSettingKey);

if (String.IsNullOrEmpty(groupSid)){

throw new KeyNotFoundException($"{Constants.Identity.SidSettingKey}setting could not be found.");

}

OutputClaims.Add(new Claim(ClaimTypes.GroupSid, groupSid));}

public string CreateWebToken(){

return CreateWebToken(DefaultLifetime);}

public string CreateWebToken(TimeSpan lifetime){

// Create JSON Web Tokenvar tokenHandler = new JwtSecurityTokenHandler();

20

Page 29: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

var ts = DateTime.UtcNow;var hostName = $"https://{EnvironmentUtils.GetHostName()}/";var signingKey = HexStringUtils.ToByteArray(EnvironmentUtils.

GetSigningKey());

var tokenDescriptor = new SecurityTokenDescriptor{

Subject = new ClaimsIdentity(OutputClaims),AppliesToAddress = hostName,TokenIssuerName = hostName,Lifetime = new Lifetime(ts, ts.Add(lifetime)),SigningCredentials = new SigningCredentials(new

InMemorySymmetricSecurityKey(signingKey),SignatureAlgorithms.HmacSha512,DigestAlgorithms.Sha512)

};

var token = tokenHandler.CreateToken(tokenDescriptor);

return tokenHandler.WriteToken(token);}

}

The CreateWebToken method generates a JWT token by creating an instance

of the SecurityTokenDescriptor class, populating its properties with the attributes

related to the issued token, and passing that instance as a parameter to the JwtSe-

curityTokenHandler.CreateToken method. The interesting part is the output claims

list that will be included in the token payload. Every token created by the Authen-

ticationTokenFactory class contains two public claims, which specify the role of

the service and the SID for the group to which the service belongs to. The group

SID is the secret shared between the App Service backend and WebJob instances.

The secret is stored as an app setting entry, which means that it can be easily ac-

cessed and managed via Microsoft Azure portal by navigating to the Application

settings blade of the App Service. Having generated the security token, the We-

bJob console application is ready to make authenticated requests to the backend

service.

In order to protect the service-facing endpoints from being accessed by an unau-

thorized entity, the backend app uses authorization filters. The authorization fil-

ter can be created by subclassing the AuthorizeAttribute class and overriding the

OnAuthorization method with a logic that will verify the identity of the client

21

Page 30: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

making the request.

Listing 2.7: Service Authorization Filter

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]public sealed class TrustedClientAttribute : AuthorizeAttribute{

public override void OnAuthorization(HttpActionContext actionContext){

var principal = (ClaimsPrincipal)actionContext.RequestContext.Principal;

var groupSid = ConfigurationManager.AppSettings[Constants.Identity.SidSettingKey];

if (principal.HasClaim(ClaimTypes.GroupSid, groupSid)){

base.OnAuthorization(actionContext);}else{

HandleUnauthorizedRequest(actionContext);}

}}

The client identity is verified by comparing the value of the group SID claim

with the shared secret. The TrustedClient attribute can be used to add additional

layer of security to service-facing endpoints.

Listing 2.8: Action Method Representing Service-Facing Endpoint For RetrievingUser ID Tags

[HttpGet][TrustedClient][Route("{id:guid}/tags")][ResponseType(typeof(IEnumerable<string>))]public async Task<IHttpActionResult> GetUserNotificationTags(Guid id){

var device = await UnitOfWork.Devices.GetAsync(id);

if (device == null) return NotFound();

var masterAccount = device.Account;

var accounts = new List<Account> { masterAccount };accounts.AddRange(masterAccount.AffiliateAccounts);

var tags = accounts.Select(a => $"{Constants.Services.NotificationHubUserIdTagPrefix}{a.Sid}").ToList();

return Ok(tags);}

22

Page 31: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

2.3 User Authentication & Authorization

In order to secure the mobile backend, Azure App Service provides a built-in

Authentication / Authorization feature that enables the backend application to sign

in users via third-party identity providers (IdPs). Such a federated identity model

greatly simplifies the user authentication process, because the application relies

on the identity information provided by the IdP and it doesn’t have to store that

information itself. In order to authenticate by using one of the supported identity

providers, the Mobile App App Service application must first be configured with

the IdP to obtain the trust relationship. The configuration process usually involves

IDs and secrets, which are generated by the IdP and saved on the App Service

application server. The platform’s backend application has been configured to use

Facebook [10], Google [11], and Twitter [12] identity providers. All three identity

providers are officially supported by the App Service and they conform to OAuth

2.0 standard. The relevant configuration instructions for each of the supported

IdPs are documented on MSDN.

2.3.1 Mobile App Backend Authentication

The process of adding authentication to the App Service .NET backend app is rela-

tively simple and involves installing Microsoft.Azure.Mobile.Server.

Authentication NuGet package and registering the OWIN middleware com-

ponent responsible for validating App Service tokens. The authentication com-

ponent can be registered by calling the UseAppServiceAuthentication extension

method in the application configuration method. Alternatively, one can install

Microsoft.Azure.Mobile.Server.Quickstart NuGet package and

call the UseDefaultConfiguration extension method, which will register a whole

set of OWIN middleware components including the authentication component.

23

Page 32: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Listing 2.9: .NET Backend App Authentication Middleware Configuration

public partial class Startup{

public static void ConfigureMobileApp(IAppBuilder app){

HttpConfiguration config = new HttpConfiguration();

// Web API attribute routingconfig.MapHttpAttributeRoutes();

// Enable required server featuresnew MobileAppConfiguration()

.UseDefaultConfiguration()

.ApplyTo(config);

...}

...

}

The ConfigureMobileApp method registers the OWIN middleware authentica-

tion component by calling the UseDefaultConfiguration extension method. Apart

from OWIN middlewares, the ConfigureMobileApp method also configures other

application mechanisms discussed in chapter 4.

Once the application has been correctly configured, the Authorize attribute can be

added to any controller or method that requires authentication.

Listing 2.10: Base Controller Class

[Authorize][MobileAppController]public abstract class AppServiceController : ApiController{

...}

The AppServiceController is an abstract class decorated with the Authorize

attribute, which implies that access to the action methods of its subclasses is re-

stricted to authorized clients. Thus, it is a base class for all controllers that require

authentication.

24

Page 33: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

2.3.2 Client App Authentication

There are two approaches for adding authentication to the client app. One can ei-

ther use the provider SDK to establish identity used to gain access to App Service

or let the Mobile Apps client SDK sign in users. The former approach usually

results in more consistent sign in experience and provides the client with provider

token, which makes it much easier to consume graph APIs. The latter approach is

based on the mechanism that is often referred to as server-directed flow, because

the management of the process that signs in users is delegated to the server. In this

approach, the Mobile Apps client SDK will open a web view to the selected iden-

tity provider and sign in the user. This time the client only gets the App Service

JSON web token which is automatically attached to all requests to the App Ser-

vice backend. However, it is still possible for the client to access provider-specific

identity information. At this point, it is worth mentioning that the App Service

Authentication / Authorization feature has an advanced capability called the to-

ken store. The token store is responsible for collecting and storing the OAuth

tokens issued by an authorization server [6] of the identity provider during the

user sign in process. In order to enable access to the identity information stored

in the token store, App Service has a built-in /.auth/me endpoint that supports the

authenticated GET requests. The client can take advantage of this endpoint to ob-

tain a richer set of information about the signed in user.

The current implementation of the UWP client app authenticates users using Mo-

bile Apps client SDK [9]. Note that in order to use that SDK, one must first

install Microsoft.Azure.Mobile.Client NuGet package. To keep the

code loosely coupled, clean, and more reusable the authentication logic has been

extracted into a dedicated service. The service can be registered in IoC container

and injected into view models responsible for managing user sign in process.

25

Page 34: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Listing 2.11: Client Authentication With Mobile Apps Client SDK

public class AuthenticationService : IAuthenticationService{

...

private async Task<bool> AuthenticateCoreAsync(PasswordVault vault,MobileServiceAuthenticationProvider provider)

{bool success = true;

try{

// Facebook and Twitter both have a long access token expiration,however in case of Google authentication provider,

// where the token expiration is 1 hour, we need to use additionalparameters to enable the app to refresh the access tokens.

var loginParams = provider == MobileServiceAuthenticationProvider.Google

? new Dictionary<string, string> { { "access_type", "offline" }, { "approval_prompt", "force" } } :null;

await MobileServiceClient.LoginAsync(provider, loginParams);

var credential = new PasswordCredential(provider.ToString(),MobileServiceClient.CurrentUser.UserId,

MobileServiceClient.CurrentUser.MobileServiceAuthenticationToken);

vault.Add(credential);

var localSettings = ApplicationData.Current.LocalSettings;

localSettings.Values[Constants.UserIdentityProviderLSK] = provider.ToString();

}catch (Exception){

await ForgetCurrentUserCoreAsync(vault);success = false;

}

await UpdateCurrentUserAsync();

return success;}

...

}

The AuthenticateCoreAsync method authenticates users by calling the Logi-

nAsync method of Mobile Apps client SDK, which opens a web view to the spec-

ified authentication provider allowing the user to sign in. The AuthenticateCore-

Async method also takes care of securely storing the authentication token on the

26

Page 35: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

client device, so that the user can be signed in automatically the next time the app

is launched.

27

Page 36: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Chapter 3

Cloud Message Routing

One of the most common challenges in cloud computing is the exchange of infor-

mation between individual cloud services. Every non-trivial cloud solution will

use a certain set of services that process and exchange information, and the dis-

cussed solution is no different. This chapter will cover the implementation aspects

of the services responsible for message routing.

3.1 IoT Hub Device-to-Cloud Message Routing

Azure IoT Hub is a communication gateway between the cloud and IoT devices.

It provides a bi-directional communication meaning that it is also responsible for

collecting the data sent by the IoT devices (device-to-cloud messages). IoT Hub

supports two distinct mechanisms for routing messages, namely routing rules and

custom event processor. The first mechanism is much easier to implement and

maintain, therefore it was selected as the preferred way for handling simple rout-

ing scenarios.

In order to configure IoT Hub to route messages to the backend processing ser-

vices via Service Bus messaging (such as queues or topics), one can sign in to

Azure portal, navigate to IoT Hub information pane, and set up messaging end-

points and routes.

28

Page 37: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Figure 3.1: IoT Hub - Endpoints Configuration

In chapter 1, it has been said that the cloud infrastructure would utilize Service

Bus queues for delivering messages to the backend processing services. From

figure 3.1 one can see that the Service Bus queue, used for telemetry data, has

been added to IoT Hubs custom routing endpoints. It is important to note that

the slickhub-telemetry-queue-iothub queue has been created specifically for use

with IoT Hub endpoints. There are certain restrictions [18] for custom endpoints,

which must be met in order for the endpoint to function correctly.

Figure 3.2: IoT Hub - Routes Configuration

Once the custom endpoints have been set up correctly, one can proceed to

29

Page 38: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

configuring routes. Figure 3.2 shows a single route, named telemetry-data, which

has been configured to route all the messages satisfying the given condition to the

telemetry-queue endpoint. The route conditions use a dedicated query language

[13] for writing query expressions, which are evaluated on the message properties.

For example, the telemetry-data route will be matched against all messages where

’messageType’ property is assigned ’telemetry’ value and which include ’deviceId’

property. Note that the routing rules do not require to write a single line of code,

which means that changes related to the routing logic can be made on the fly

without worrying about time-consuming implementation and deployment details.

While such a code-free solution is easy to maintain, thus simplifying the de-

velopment, it is not suitable for more advanced routing scenarios where additional

control and data processing is required. Fortunately, IoT Hub makes it possible to

use an alternative mechanism which delivers a fine-grained control over the mes-

sage routing logic.

By default, all inbound messages that do not match any routing rules are written

to the built-in service-facing endpoint messages/events. Such messages can then

be read by the Event Hub Processor, which is one of the commonly used mecha-

nisms for reading data from Event Hubs stream. This mechanism is much more

complex to implement and deploy, but it also offers greater control and flexibility.

In order to implement the event processing service Azure Worker Role project

hosted in Azure Cloud Service has been created. The project utilizes Microsoft.

Azure.ServiceBus.EventProcessorHost and WindowsAzure.ServiceBus

NuGet packages. The technical implementation details are depicted in subsection

3.1.1.

30

Page 39: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

3.1.1 Event Processing Service Implementation

The main event processing logic is located in the IEventProcessor.ProcessEventsAsync

method, which is a member of IEventProcessor interface and it is called whenever

there are new messages in the Event Hubs stream. The following listing shows the

method implementation.

Listing 3.1: Processing Events From Event Hubs Stream

async Task IEventProcessor.ProcessEventsAsync(PartitionContext context,IEnumerable<EventData> messages)

{foreach (EventData eventData in messages){

await routeManager.RouteAsync(eventData);}

await context.CheckpointAsync();

Trace.TraceInformation("{0} Checkpoint -> Partition: ’{1}’, Offset: ’{2}’",nameof(SlickHubEventProcessor),

context.Lease.PartitionId, context.Lease.Offset);}

Every message polled from the Event Hubs stream is consumed by the Route-

Manager and the progress is saved by PartitionContext. The RouteManager is

responsible for mapping the message type to the registered route. All the routes

can be registered by calling RegisterRoute method on the RouteManager object

as shown below.

Listing 3.2: Route Manager Configuration

routeManager = new RouteManager();

// Register route for telemetry datarouteManager.RegisterRoute(Constants.Messages.TelemetryMessageId, new

TelemetryQueueRoute());

The above code registers an instance of the TelemetryQueueRoute to be matched

against all messages of type ’telemetry’. Once the matching route has been found,

it is used for forwarding the message to the associated target endpoint.

Listing 3.3: Route Manager Event Data Routing Logic

public async Task RouteAsync(EventData eventData)

31

Page 40: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

{if (eventData == null){

throw new ArgumentNullException(nameof(eventData));}

string messageType;

if (!eventData.Properties.ContainsKey(MessageTypeKey) ||(messageType = eventData.Properties[MessageTypeKey] as string) == null ||!routes.ContainsKey(messageType))

{return;

}

var routeList = routes[messageType];

foreach (var route in routeList){

await route.ForwardAsync(eventData);}

}

Every route must implement the IRoute interface, which declares a Target

property representing the target endpoint and ForwardAsync method containing

the logic for forwarding the message.

Listing 3.4: IRoute Interface Declaration

public interface IRoute{

ClientEntity Target { get; }

Task<bool> ForwardAsync(EventData eventData);}

Since the cloud infrastructure assumes the use of multiple queues as messaging

endpoints, it was decided to implement a base class for all the routes that use the

queue client object as the target endpoint. With such a design one can avoid

duplicate code making the service easier to maintain.

Listing 3.5: QueueRouteBase Implementation - IRoute Members

public async Task<bool> ForwardAsync(EventData eventData){

if (eventData == null){

throw new ArgumentNullException(nameof(eventData));}

if (!ValidateEventData(eventData)) return false;

32

Page 41: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

var message = CreateBrokeredMessage(eventData);

await queueClient.SendAsync(message);

return true;}

public ClientEntity Target => queueClient;

The base implementation provides two overridable methods: ValidateEvent-

Data and CreateBrokeredMessage. The ValidateEventData method is used for

validating the message data and it contains the logic analogous to the routing rule’s

query expression, which has been discussed earlier. The CreateBrokeredMessage

method wraps the message data inside the BrokeredMessage object, which is then

consumed by the queue client object (an instance of the QueueClient class). The

QueueClient class is a part of the WindowsAzure.ServiceBus API.

Listing 3.6: Creating Brokered Message

protected virtual BrokeredMessage CreateBrokeredMessage(EventData eventData){

string messageId = null;

if (eventData.SystemProperties.ContainsKey("message-id")){

messageId = (string)eventData.SystemProperties["message-id"];}

byte[] data = eventData.GetBytes();

var message = new BrokeredMessage(new MemoryStream(data)){

// Each message is stamped with MessageId to enable Service Bus to ensurethat, in the specified

// deduplication time window, no two messages with the same MessageId aredelivered to the receivers.

MessageId = messageId ?? Guid.NewGuid().ToString()};message.Properties[DeviceIdKey] = eventData.Properties[DeviceIdKey];message.Properties[MessageTypeKey] = eventData.Properties[MessageTypeKey];

return message;}

The concrete queue-based route implementation can derive from the QueueR-

outeBase class by supplying a connection string to the base class constructor. The

supplied connection string is used to create the queue client object.

33

Page 42: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Listing 3.7: Telemetry Data Route Definition

public TelemetryQueueRoute() : base(EnvironmentUtils.GetTelemetryQueueConnectionString())

{ }

Finally, the event processor is registered with the host for processing Event

Hubs event data. The code responsible for host creation and event processor reg-

istration is contained in the WorkerRole class that extends the RoleEntryPoint class

and adds functionality to the role instances.

Listing 3.8: Worker Role Entry Point

public override void Run(){

Trace.TraceInformation("{0} Running", nameof(EventProcessorRole));

// Register the Event ProcessoreventProcessorHost.RegisterEventProcessorAsync<SlickHubEventProcessor>().Wait

();

// Keep the Worker Role runningrunCompleteEvent.WaitOne();

}

public override bool OnStart(){

Trace.TraceInformation("{0} Starting", nameof(EventProcessorRole));

// Set the maximum number of concurrent connectionsServicePointManager.DefaultConnectionLimit = 12;

var iotHubConnectionString = EnvironmentUtils.GetIotHubConnectionString();var storageConnectionString = EnvironmentUtils.GetStorageConnectionString();var eventProcessorHostName = RoleEnvironment.CurrentRoleInstance.Id;

eventProcessorHost = new EventProcessorHost(eventProcessorHostName, Constants.Endpoints.IotHubD2CEndpoint,

EventHubConsumerGroup.DefaultGroupName, iotHubConnectionString,storageConnectionString,

Constants.Storage.LeaseContainerName);

bool result = base.OnStart();

return result;}

After the Azure Worker Role project has been deployed to the Azure Cloud

Service, all connection strings stored in the ServiceConfiguration.Cloud.

cscfg file can be easily modified through the Azure Cloud Service Configuration

blade as can be seen in figure 3.3.

34

Page 43: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Figure 3.3: Event Processing Service - Cloud Service Configuration

3.2 Service Bus Queue Message Routing

All messages that arrive at IoT Hub are being routed to the matching Service

Bus queue in order to be delivered to the backend processing services, which in-

clude Azure App Service Mobile App and Azure Notification Hub. Before the

messages can be delivered to those services, they need to be polled from the

Service Bus queue and wrapped into packages supported by each service. The

cloud infrastructure assumes the use of Azure WebJobs, which allow for run-

ning programs and scripts alongside the Mobile App service. In order to sat-

isfy the mentioned assumptions a Console Application has been created. The ap-

plication utilizes the Microsoft.Azure.WebJobs, Microsoft.Azure.

Mobile.Client, Microsoft.Azure.NotificationHubs, WindowsAzure.

ServiceBus, System.IdentityModel.Tokens.Jwt, and Microsoft.

Practices.EnterpriseLibrary.TransientFaultHandlingNuGet

packages. The technical implementation details are depicted in subsection 3.2.1.

3.2.1 WebJob Console Application Implementation

Similarly to the Event Processing Service, the WebJob project has been carefully

crafted to ensure clean architecture. The main logic responsible for polling and

processing queue messages has been located in PushService class. The instances

35

Page 44: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

of this class can be created by providing the PushServiceConfiguration object

which stores preconfigured instances of MobileServiceClient and Notification-

HubClient classes (both of which are the part of Azure API). Once initialized,

the PushService can be wired-up to the source Service Bus queue via the connec-

tion string.

Listing 3.9: Push Service Configuration

private PushService CreateAndConfigurePushService(){

var configuration = PushServiceConfiguration.DefaultConfiguration;

var pushService = new PushService(configuration);

// Setup push notifications for telemetry datavar telemetryQueueConnectionString = EnvironmentUtils.

GetTelemetryQueueConnectionString();

var telemetryDataConsumer = new TelemetryDataConsumer(configuration.MobileServiceClient);

pushService.Subscribe(telemetryQueueConnectionString, telemetryDataConsumer);

return pushService;}

The PushService.Subscribe method also allows for specifying an optional mes-

sage data consumer, which will be called every time a new message is being pro-

cessed. In case of telemetry data, it is necessary to update rows in the database

to ensure data integrity between the client application and backend service. The

TelemetryDataConsumer.ProcessDataAsync method contains the logic that invokes

REST API responsible for updating telemetry data for the specified device.

Listing 3.10: Updating Telemetry Data

public override async Task ProcessDataAsync(string deviceId, string data){

if (deviceId == null || data == null) return;

await RequestExecutor.ExecuteAsync(() =>MobileServiceClient.InvokeApiAsync($"v1/devices/{deviceId}/telemetry"

, JToken.FromObject(data)));

Trace.TraceInformation("{0} Telemetry data updated", Assembly.GetEntryAssembly().GetName().Name);

}

36

Page 45: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

All data consumer components derive from the DeviceDataConsumerBase ab-

stract class, which implements IDeviceDataConsumer interface and provides its

subclasses with RequestExecutor object that ensures transient fault handling while

executing REST API requests.

The queue message processing is delegated to the OnMessageCallbackAsync call-

back method that is registered with QueueClient.OnMessageAsync method. Every

message is validated, wrapped into notification payload that is sent via Notifica-

tion Hub, and passed to the optional data consumer.

Listing 3.11: Queue Message Processing

private async Task OnMessageCallbackAsync(BrokeredMessage message,IDeviceDataConsumer dataConsumer)

{try{

string messageType, deviceId;

if (!message.TryGetProperty(MessageTypeKey, out messageType) || !message.TryGetProperty(DeviceIdKey, out deviceId))

{await message.DeadLetterAsync();return;

}

var tags = await GetNotificationTagsAsync(deviceId);var data = message.ReadMessageData(Encoding.UTF8);

if (tags != null && data != null){

var payload = new NotificationPayload(messageType, data);

await SendNotificationAsync(payload, tags);

if (dataConsumer != null){

await dataConsumer.ProcessDataAsync(deviceId, data);}

await message.CompleteAsync();}else{

await message.DeadLetterAsync();}

}catch (Exception){

await message.AbandonAsync();}

}

37

Page 46: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

The current implementation only supports Windows Push Notification Ser-

vice (WNS) and uses general purpose push notifications called raw notifications.

The notification payload objects are serialized to a JSON string, enclosed in an

instance of the WindowsNotification class, and sent to the authenticated users.

Listing 3.12: Sending Targeted Push Notifications

private async Task SendNotificationAsync(NotificationPayload payloadObject,IEnumerable<string> tags)

{var payload = payloadObject.CreatePayloadString();

// According to MSDN, the string payload of the raw notification MUST besmaller than 5 KB in size.

// For further information, see https://msdn.microsoft.com/en-us/library/windows/apps/jj676791.aspx

// and https://msdn.microsoft.com/en-us/library/windows/apps/hh761463.aspx.if (Encoding.UTF8.GetByteCount(payload) >= 5120){

Trace.TraceWarning("{0} Dropping notification payload - size limit (5KB)exceeded", Assembly.GetEntryAssembly().GetName().Name);

return;}

// Create a payload for raw notificationNotification notification = new WindowsNotification(payload);notification.ContentType = "application/octet-stream";notification.Headers["X-WNS-Type"] = "wns/raw";

var outcome = await NotificationHubClient.SendNotificationAsync(notification,tags);

Trace.TraceInformation("Notification Hub -> Notification State: {0}", outcome.State);

}

Every user authenticated by the Mobile App backend service is automatically

tagged with User ID to enable targeted push notifications [15]. In order to retrieve

those tags, the WebJob application executes REST API request that returns a list

of User ID tags matched with the specified device ID.

Listing 3.13: Retrieving User ID Tags From Mobile App Backend

private async Task<IEnumerable<string>> GetNotificationTagsAsync(string deviceId){

var queryParams = MobileServiceClient.GetApiQueryParameters();

var json = await requestExecutor.ExecuteAsync(() =>MobileServiceClient.InvokeApiAsync($"v1/devices/{deviceId}/

tags", HttpMethod.Get, queryParams))as JArray;

38

Page 47: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

return json?.Select(t => t.ToObject<string>());}

The REST API requests are executed by an instance of the RequestExecutor

class to ensure transient fault handling. The retry logic of the RequestExecutor

class is based on the retry mechanisms (RetryPolicy and RetryStrategy) provided

by Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling

API.

Listing 3.14: Transient Fault Handling - Retry Policy Creation

private RetryPolicy<T> CreateRequestRetryPolicy(){

var retryStrategy = new ExponentialBackoff(3, TimeSpan.FromSeconds(1),TimeSpan.FromSeconds(10),

TimeSpan.FromSeconds(2));

var policy = new RetryPolicy<T>(retryStrategy);

policy.Retrying += (o, args) =>{

Trace.TraceInformation("RequestExecutor Retry Policy -> Count: {0}, Delay: {1}, Exception: {2}",

args.CurrentRetryCount, args.Delay, args.LastException);

retryCallback?.Invoke(args.LastException);};

return policy;}

After the WebJob project has been deployed to the Azure App Service Mobile

App, all connection strings and app settings stored in the app.config file can

be easily modified through the Azure App Service Application Settings blade as

can be seen in figure 3.4.

39

Page 48: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Figure 3.4: App Service - Mobile App & WebJobs Settings

40

Page 49: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Chapter 4

Mobile App Backend

One of the major challenges in developing cloud solutions is to provide a secure

way for the users to interact with cloud services. To address this challenge, the

cloud providers introduced a model called Mobile Backend as a Service (MBaaS).

MBaaS is a backend solution that greatly simplifies the process of scaffolding

RESTful API for multi-platform mobile apps by providing a unified API that

adds an abstraction layer to the server-side infrastructure. In addition, MBaaS

also provides integration with social networks, push notifications, and cloud stor-

age. It can be said that MBaaS acts as a bridge between client app and various

cloud-based services. Microsoft Azure offers MBaaS solution called Azure Mo-

bile App, which delivers all of the aforementioned features. The discussed IoT

platform uses this service to enable a secure bi-directional communication be-

tween the client application and other cloud services that make up the platform.

Azure Mobile App provides a wide range of supported backend platforms for de-

veloping custom back-end logic. At the time of writing, the supported platforms

include ASP.NET, Node.js, PHP, Java, and Python. In order to ensure a com-

mon programming language across all cloud services, it was decided to develop

backend service with C# and ASP.NET.

41

Page 50: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

4.1 .NET Backend

The REST API was built based on ASP.NET Web API framework. A special fo-

cus was put on authentication 1, versioning, maintainability, and testability. The

service is hosted within a server compatible with Open Web Interface for .NET

(OWIN). OWIN defines a standard interface that allows for decoupling web appli-

cation from the underlying web server. In addition, OWIN allows to split the web

app infrastructure into separate modules, which can be chained together into a

middleware pipeline. The backend service uses OWIN to register various middle-

ware components responsible for adding default home page, mapping endpoints

to table controllers, integration with Notification Hub, authentication, and custom

API capabilities for controllers used by Azure Mobile App client. The middle-

ware components are registered into the application pipeline by OWIN startup

class, which is connected with the hosting runtime via an OwinStartup attribute.

Listing 4.1: .NET Backend App Configuration

[assembly: OwinStartup(typeof(SlickHubWebApi.Startup))]

public partial class Startup{

public static void ConfigureMobileApp(IAppBuilder app){

HttpConfiguration config = new HttpConfiguration();

// Web API attribute routingconfig.MapHttpAttributeRoutes();

// Enable required server featuresnew MobileAppConfiguration()

.UseDefaultConfiguration()

.ApplyTo(config);

var container = CreateContainer();

config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

// Register the Autofac middleware FIRSTapp.UseAutofacMiddleware(container);

// Use Entity Framework Code First to create database tables

1The backend app authentication is covered in chapter 2.

42

Page 51: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MobileServiceContext, MigrationsConfiguration>());

MobileAppSettingsDictionary settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings();

if (string.IsNullOrEmpty(settings.HostName)){

app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions{

// This middleware is intended to be used locally for debugging.By default, HostName will

// only have a value when running in an App Service application.SigningKey = ConfigurationManager.AppSettings[Constants.Identity.

WebsiteAuthSigningKeySettingKey],ValidAudiences = new[] { ConfigurationManager.AppSettings[

Constants.Identity.WebsiteAuthValidAudienceSettingKey] },ValidIssuers = new[] { ConfigurationManager.AppSettings[Constants

.Identity.WebsiteAuthValidIssuerSettingKey] },TokenHandler = config.GetAppServiceTokenHandler()

});}

// Register Web API middlewaresapp.UseAutofacWebApi(config);app.UseWebApi(config);

}

...

}

Apart from registering middleware components that are specific to Azure Mo-

bile App service, the

emphConfigureMobileApp method also configures HTTP request routing, depen-

dency injection (DI) container, and the database initializer.

When designing the software, one of the most important goals is to ensure loosely-

coupled architecture. In order to achieve that goal, the application uses Autofac

IoC container that manages the dependencies between controllers. The use of

DI increases the flexibility and testability of code modules allowing to easily

inject components with mock data. However, in case of backend services, the

well-designed application architecture is not sufficient. Since the backend service

exposes API to be used by the clients, it is also important to introduce API ver-

sioning to make sure that the API can be updated without affecting the existing

functionality. There are three most commonly used ways to accomplish API ver-

43

Page 52: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

sioning. One can either specify the version information in the URL, use custom

request headers, or use accept headers. In the discussed project, it was decided

to use versioned URL due to its simplicity and ease of implementation with a use

of attribute routing mechanism. With attribute routing it is possible to include the

version number for each controller in the route prefix specified by the RoutePre-

fix attribute. In such a way, every controller is explicitly decorated with the API

version to which it belongs.

Listing 4.2: Versioned URL With Attribute Routing

[RoutePrefix("api/v1/devices")]public class DevicesController : AppServiceController{

...}

[RoutePrefix("api/v1/accessories")]public class AccessoriesController : AppServiceController{

...}

[RoutePrefix("api/v1/bootstrap")]public class BootstrapController : AppServiceController{

...}

Moving on to the REST API itself, the application exposes a set of endpoints

for registering IoT gateways (see chapter 2), retrieving a list of registered IoT

gateways for an authorized user, sending cloud commands to the selected IoT

accessory, and retrieving the current state of the IoT accessory. In addition, there

is a set of service-facing endpoints used by the WebJob instances as discussed in

chapter 3. All of the controller action methods operate on data transfer objects

(DTOs) that represent the relevant request and response data. It was decided to

use DTOs in order to avoid exposing the entity data that should be hidden from

the client.

Listing 4.3: Action Method Returning DTO With Accessory State

[RoutePrefix("api/v1/accessories")]

44

Page 53: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

public class AccessoriesController : AppServiceController{

...

[HttpGet][Route("{id:guid}")][ResponseType(typeof(AccessoryDescriptionResponse))]public async Task<IHttpActionResult> Get(Guid id){

var account = await GetAuthorizedUserAccountAsync<MasterAccount>();

if (account == null) return BadRequest();

var accessory = await UnitOfWork.Accessories.GetAsync(id);

if (accessory == null) return BadRequest();

var device = accessory.Device;

// Check request integrityif (device.Account.Sid != account.Sid && device.Account.Id != account.Id){

return BadRequest();}

return Ok(new AccessoryDescriptionResponse{

Description = accessory.PropertySet});

}}

[DataContract(Name = "AccessoryDescriptionResponse")]public class AccessoryDescriptionResponse{

[DataMember(Name = "description", IsRequired = true)]public string Description { get; set; }

}

The AccessoryDescriptionResponse class represents a DTO that is used by the

AccessoriesController.Get(Guid) action method to return the state of the acces-

sory with the specified identifier. It is worth noting that all data transfer objects

are decorated with DataContract attribute to indicate that they can be serialized

by Web API media-type formatters. The media-type formatters are responsible for

reading CLR objects from an HTTP request body and writing CLR objects into

an HTTP response body. With DTO, it is possible to return only the JSON string

that represents the accessory state without exposing the rest of the data contained

in Accessory entity.

Looking at the above code snippets, one can notice that the controller classes de-

45

Page 54: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

rive from AppServiceController class. As mentioned in chapter 2, the AppService-

Controller is an abstract base class for all controllers that require authentication.

Listing 4.4: Methods Accessible by AppServiceController Subclasses

[Authorize][MobileAppController]public abstract class AppServiceController : ApiController{

...

protected async Task<TAccount> GetAuthorizedUserAccountAsync<TAccount>()where TAccount : Account, new()

{var account = await GetAuthorizedUserAccountAsync();

if (account == null) return null;

if (account.GetType() == typeof (AffiliateAccount) && typeof (TAccount)== typeof (MasterAccount))

{return ((AffiliateAccount) account).MasterAccount as TAccount;

}

return account as TAccount;}

protected async Task<Account> GetAuthorizedUserAccountAsync(){

var principal = (ClaimsPrincipal) User;

var id = principal.GetGloballyUniqueUserId();

if (id == null){

throw new InvalidOperationException("Identity does not exist.");}

// Get a hash used for linking a user across two providersvar sid = principal.FindFirst(ClaimTypes.NameIdentifier).Value;

var account = (Account) await GetAccountFromDatabaseAsync<MasterAccount>(id, sid) ??

(Account) await GetAccountFromDatabaseAsync<AffiliateAccount>(id, sid);

return account;}

protected async Task<TAccount> CreateAuthorizedUserAccountAsync<TAccount>()where TAccount : Account, new()

{var principal = (ClaimsPrincipal) User;

var id = principal.GetGloballyUniqueUserId();

if (id == null){

throw new InvalidOperationException("Identity does not exist.");}

46

Page 55: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

// Get a hash used for linking a user across two providersvar sid = principal.FindFirst(ClaimTypes.NameIdentifier).Value;

var account = await AddAccountToDatabaseAsync<TAccount>(id, sid);

return account;}

...}

The AppServiceController class provides its subclasses with GetAuthorize-

dUserAccountAsync and GetAuthorizedUserAccountAsync<TAccount> methods,

which retrieve an entity that represents authenticated identity associated with a

client request. The two methods are also used to determine whether an autho-

rized user is actually registered with the platform. The user can be registered by

calling a CreateAuthorizedUserAccountAsync<TAccount> method, which is also

provided by the AppServiceController class. It is worth noting that the user ac-

count is created based on the information contained in a principal associated with

the request. The principal contains the claims generated by App Service Authen-

tication feature. There are two very useful claims that represent the user IDs,

namely sid and stable_sid [7]. The value of the stable_sid claim represents a sta-

ble and unique (when combined with the provider name) user ID, therefore it is

used as a primary key for user account. The value of sid claim is the hash ID

generated based on the user email and it is used for linking user account across

different identity providers.

By extracting the aforementioned methods to a base class it was possible to avoid

code duplication, since vast majority of action methods manipulate data associ-

ated with authorized user.

47

Page 56: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

4.2 Data Persistence

One of the most important aspects of MBaaS solution is the integration with cloud

storage. There are two commonly used approaches for setting up a cloud storage,

both of which are supported by Azure. One can either use an Infrastructure as a

Service (IaaS) approach or Platform as a Service (PaaS) approach. To enable the

use of IaaS, Azure provides an option to install and host SQL Server on Azure

Virtual Machines. This approach is optimized for migrating existing SQL Server

applications from on-premises to cloud-based solutions. When compared with

PaaS approach, IaaS provides much greater control over the operating system, the

specific version of the database engine used, updates, and backups. However, a

greater control also requires a lot more operational work during the development

and maintenance of the solution. Such administrative costs can be minimized

to a great extent by using PaaS solutions. Due to the cost savings and perfor-

mance optimization, PaaS is a recommended approach for building new cloud

storage applications. Following from these guidelines, the discussed Azure Mo-

bile App backend service was configured to use a PaaS-based cloud storage solu-

tion, known as Azure SQL Database [17]. The current configuration uses a single

instance of Azure SQL database that is assigned a set of fully-managed compute

and storage resources. Every Azure SQL database instance is hosted on Azure

SQL Database logical server, which allows for configuring firewall rules for the

databases. To obtain a connection to the database, the backend application uses

a connection string, which consists of key/value parameter pairs that specify the

server name, database name, and SQL authentication credentials.

Upon configuring cloud storage, it was possible to design a relational database

for the discussed IoT platform. The database was designed by determining the

entities to be stored in the database and establishing the relationships between

48

Page 57: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

those entities. The resulting database model consists of four entities: Master-

Account representing a registered user account, AffiliateAccount representing a

linked user account used to enable multiple users on a single IoT gateway device,

Device representing a registered IoT gateway device, and Accessory representing

an IoT accessory connected to IoT gateway. Figure 4.1 shows a detailed entity

relationship diagram describing the structure of the individual entities and their

relationships to each other. Since the Azure SQL Database service uses Microsoft

SQL Server Engine, the diagram includes the relevant data types and constraints

for entity columns.

Figure 4.1: ERD Physical Model For Microsoft SQL Server

To simplify the tasks related to database creation and updating database schema,

it was decided to use Entity Framework code first migrations. The code first ap-

49

Page 58: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

proach allows to create the database based on the POCO classes, which represent

the domain entities. In addition, code first migrations allow to update the database

schema without loss of data.

Listing 4.5: POCO Class For Device Entity

public class Device{

[Key][DatabaseGenerated(DatabaseGeneratedOption.None)]public Guid Id { get; set; }

[MaxLength(255)]public string Name { get; set; }

public string TelemetryData { get; set; }

[MaxLength(128)]public string AccountId { get; set; }

[ForeignKey("AccountId")]public virtual MasterAccount Account { get; set; }

public virtual ICollection<Accessory> Accessories { get; set; } = new HashSet<Accessory>();

}

Apart from code first migrations, it was also decided to use Entity Frame-

work to automate a standard CRUD operations. Since Entity Framework is an

object-relational mapper (ORM), it simplifies the data-access code by mapping

domain-specific objects to relational database objects. In other words, the ORM

allows to perform CRUD operations against the database using strongly typed ob-

jects and queries. In this way, it solves the object-relational impedance mismatch

problem and enables the developer to write more maintainable and extendable

code. However, despite its undoubtful advantages, the Entity Framework has a

disadvantage of generating SQL queries, which are less efficient than their raw

SQL equivalents. It is therefore important to design the application architecture

that will allow to easily switch to raw SQL queries in case the performance of

ORM will become a bottleneck. In order to achieve such a flexible architecture,

it was decided to use repository and unit of work patterns to add an additional

abstraction layer between data access layer and business logic layer. By imple-

50

Page 59: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

menting these patterns it was possible to insulate the business logic from changes

in the data access logic.

Listing 4.6: Repository Class For MasterAccount & AffiliateAccount Entities

public sealed class AccountRepository : RepositoryBase<Account, string>,IAccountRepository

{...

public async Task<TAccount> GetAsync<TAccount>(string id) where TAccount :Account

{if (id == null){

throw new ArgumentNullException(nameof(id));}

var account = await InternalContext.Set<TAccount>().FindAsync(id);

return account;}

public async Task<TAccount> GetBySidAsync<TAccount>(string sid) whereTAccount : Account

{if (sid == null){

throw new ArgumentNullException(nameof(sid));}

var account = await InternalContext.Set<TAccount>().FirstOrDefaultAsync(a=> a.Sid == sid);

return account;}

public void Add<TAccount>(TAccount account) where TAccount : Account{

if (account == null){

throw new ArgumentNullException(nameof(account));}

InternalContext.Set<TAccount>().Add(account);}

public void Remove<TAccount>(TAccount account) where TAccount : Account{

if (account == null){

throw new ArgumentNullException(nameof(account));}

InternalContext.Set<TAccount>().Remove(account);}

...}

51

Page 60: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Every repository class implements an interface, which defines a contract used

to manipulate the entity data. The application controllers are only aware of the

contract and not the concrete implementation, thus it is possible to modify a spe-

cific implementation without affecting the dependent code or inject a mock imple-

mentation to perform unit tests. Since the current implementation of the backend

application utilizes the Entity Framework every repository class requires a refer-

ence to the database context. To avoid undesired partial updates, it is necessary

to use a single, shared instance of database context for all repositories. Such a

behavior was achieved by creating a unit of work class, which provides a Com-

pleteAsync method for coordinating the database updates. The unit of work class

also provides a set of read-only properties to enable controllers to access the repos-

itories.

Listing 4.7: Unit of Work Class

public class UnitOfWork : IUnitOfWork{

private readonly MobileServiceContext _context;

...

public async Task<int> CompleteAsync(){

return await _context.SaveChangesAsync();}

public IAccountRepository Accounts => _accounts ?? (_accounts = newAccountRepository(_context));

public IDeviceRepository Devices => _devices ?? (_devices = newDeviceRepository(_context));

public IAccessoryRepository Accessories => _accessories ?? (_accessories =new AccessoryRepository(_context));

...}

To ensure loose coupling the unit of work class is registered with the depen-

dency injection container. The registered implementation of IUnitOfWork inter-

face can be injected into the constructors of the dependent controllers, thus im-

proving the testability of the code.

52

Page 61: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Listing 4.8: Registration of IUnitOfWork Implementation With DI Container

public partial class Startup{

...

private static IContainer CreateContainer(){

var builder = new ContainerBuilder();

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

RegisterDependencies(builder);

var container = builder.Build();

return container;}

private static void RegisterDependencies(ContainerBuilder builder){

// Register unit of workbuilder.RegisterType<UnitOfWork>().As<IUnitOfWork>();

...}

}

53

Page 62: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Chapter 5

IoT Gateway

While the concept of IoT brings a large set of new possibilities, it also introduces

non-trivial security challenges related to data exchange. Let’s imagine a smart

home in which we have smart LED lighting system, air conditioner, thermostat,

automated window blinds, and a couple of smart plugs. Now let’s say that we

would like to be able to remotely control all of our smart devices from anywhere

in the world, provided there’s an Internet connection available. The trivial solution

would be to connect individual IoT devices to the mobile backend service that

would handle the communication between user’s mobile device and IoT device.

Such an architecture implies that the number of registered IoT devices would be

directly proportional to the number of IoT devices owned by the users, which

would result in serious security and scalability problems. To solve these problems,

IoT industry has introduced the concept of IoT gateway. An IoT gateway can be

thought of as a device that manages the local ecosystem of IoT accessories. The

gateway device is responsible for security tasks and protocol translation enabling

the devices without direct access to the Internet (such as Bluetooth devices) to

reach cloud services.

54

Page 63: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

5.1 OS and Hardware

On 29 July 2015, Microsoft released Windows 10 operating system. Along with

the baseline Windows 10 editions, Microsoft also released the device-specific edi-

tions such as Windows 10 IoT Core, which was designed specifically for use in

small-footprint devices and IoT scenarios. From an IoT developer’s point of view,

Windows 10 IoT Core is particularly interesting due to the fact that it has a built-

in support for the Universal Windows Platform (UWP) apps running on top of

WinRT stack and it is the first OS in Windows embedded OS family that is avail-

able for free. These two factors make Windows 10 IoT Core an optimal choice for

IoT gateway solution, as the UWP makes it possible to build an app with a pow-

erful set of features and modern UI design, while keeping costs low. We should

not forget, however, that due to the lightweight nature of embedded operating sys-

tems, Windows 10 IoT Core also has some limitations that the developer must be

aware of. One of the major limitations is a lack of Win32 desktop shell, which

means that there is no support for Win32 GUI apps. Yet another limitation is that

Windows 10 IoT Core only allows one foreground app to run at any given time. As

an example, the above-mentioned limitations imply that there is no way to open a

new window with embedded web view to sign in user using server-directed flow.

It is therefore important to take these limitations into consideration when design-

ing UWP app targeting IoT device family.

Having selected Windows 10 IoT Core as an OS for the IoT gateway, it was possi-

ble to move on to hardware selection. The first thing was to choose a single-board

computer (SBC). At the time of writing, Windows 10 IoT Core includes support

for Raspberry Pi 2/3 Model B, MinnowBoard MAX, Qualcomm DragonBoard

410c, and Intel Joule. Among the supported SBCs, Raspberry Pi is the most af-

fordable unit equipped with all the necessary features for creating IoT gateway.

55

Page 64: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Since the Raspberry Pi 2 Model B was already owned, the initial plan was to

reuse it for making the gateway device. The only problem with RPi 2 Model B is

the lack of built-in Bluetooth Low Energy support, therefore it was necessary to

use an external BLE module. Such a module can be easily connected using Gen-

eral Purpose Input Output (GPIO) pins of the RPi. The first attempt was Adafruit

Bluefruit LE UART Friend module [2]. The module uses the Nordic nRF51822

SoC with custom firmware that includes a support for AT commands. Unfortu-

nately, the Adafruit module can only operate in peripheral (GATT Server) mode,

which means that there is no way for this module to detect other BLE peripherals

in range. In order to discover other BLE devices and send connection requests,

the IoT gateway must operate in GATT Client mode. The Adafruit module does

not satisfy this requirement, thus there was a need to look for an alternative unit.

The second attempt was a HM-11 BLE module [4], which uses Texas Instru-

ments CC2540 SoC with custom firmware that also includes a support for AT

commands. The module supports both GATT Server and GATT Client opera-

tional modes, which can be switched using AT+ROLE AT command. While the

HM-11 module can scan for other BLE devices and send connection request to

the selected device, it has a limit of only one BLE connection at a time. After

the HM-11 is connected to another BLE device, the module stops responding to

AT commands and acts as a serial port emulator allowing for data transmission

only. Such a drawback is also unacceptable for the IoT gateway device, as the

gateway should allow users to connect and control multiple BLE accessories. The

two failed attempts of using the external BLE module were convincing enough

to switch to Raspberry Pi 3, which has a built-in Bluetooth support without the

above-mentioned limitations. An additional advantage of using RPi 3 is that it is

possible to use the UWP Bluetooth API for managing BLE connectivity, which

allows to save a lot of development time and write more maintainable code. Apart

56

Page 65: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

from Bluetooth support, the RPi 3 also includes a built-in WiFi module, which

means that it has a greater potential for adding new connectivity capabilities.

Upon selecting the SBC that satisfies the Bluetooth connectivity requirements, it

was possible to move on to selecting the sensors for collecting telemetry data. In

order to collect the temperature and humidity readings the decision was taken to

use the popular AM2302 DHT22 digital sensor module. For collecting the atmo-

spheric pressure readings the high precision BMP180 digital barometric pressure

sensor module was selected. The two selected modules use 1-Wire and I2C serial

communication protocols respectively. Both protocols are supported by RPi 3 and

Windows 10 IoT Core.

Figure 5.1: IoT Gateway Wiring

5.2 UWP Application

While designing a UWP app for IoT gateway, one of the main goals was to cre-

ate a solid code base for future app development. It is crucial to carefully craft

the scalable application architecture that will allow for adding new features while

57

Page 66: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

keeping the code base manageable. In order to achieve that it was decided to use

a Prism framework [23] for UWP. The Prism framework provides an implementa-

tion of various design patterns including Model-View-ViewModel (MVVM), De-

pendency Injection, and Event Aggregator. In addition, Prism provides platform-

specific services responsible for navigation and session state management.

The current app implementation supports collecting and sending telemetry data

(see subsections 5.2.1 and 5.2.3), controlling BLE smart bulb (see subsection

5.2.2), and parsing cloud commands to GATT transactions (see subsection 5.2.3).

To enable access to APIs required to implement the aforementioned functionali-

ties it was necessary to declare a relevant capabilities in app’s package manifest.

Listing 5.1: App Capability Declarations

<?xml version="1.0" encoding="utf-8"?><Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"

xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"IgnorableNamespaces="uap mp iot">

...

<Dependencies><TargetDeviceFamily Name="Windows.IoT" MinVersion="10.0.0.0"

MaxVersionTested="10.0.0.0" /></Dependencies>

...

<Capabilities><Capability Name="internetClient" /><iot:Capability Name="systemManagement" /><iot:Capability Name="lowLevelDevices" /><DeviceCapability Name="bluetooth" />

</Capabilities></Package>

58

Page 67: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

The app’s user interface consists of a single dashboard screen (see figure

5.2), which displays the name of IoT gateway, the current readings from sen-

sor modules, and network connectivity status. The application also includes the

developer tools (see figure 5.3) that provide system information, a list of con-

nected BLE accessories, and a list of log messages. The app UI was created in

XAML and the data binding was used to link the data with UI controls. In ad-

dition, the Microsoft.Toolkit.Uwp.UI, Microsoft.Toolkit.Uwp.

UI.Controls, and Microsoft.Xaml.Behaviors.Uwp.ManagedNuGet

packages were used in order to simplify the UI development.

Figure 5.2: IoT Gateway App Dashboard

59

Page 68: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Figure 5.3: IoT Gateway App Developer Tools

5.2.1 Sensor Drivers

In order to get the sensor readings, it is necessary to use a dedicated sensor drivers.

In case of Linux-based operating systems there are multiple implementations of

Linux drivers for both DHT22 and BMP180 sensor modules, which are free to

download and easy to use. In case of Windows 10 IoT Core, however, the sensor

driver availability is a lot more problematic. While developing the IoT gateway, it

was not possible to find the UWP-compatible drivers for the selected modules and

so it was necessary to implement the required drivers from scratch. In order to do

so, the decision was made to use C++/CX 1 to create a Windows Runtime com-

ponent that can be used by a UWP app. To access device GPIO, it was necessary

to use Windows IoT Extension SDK. It is worth noting that it is also possible to

create a managed Windows Runtime component with C# programming language,

but to ensure optimal performance of GPIO operations it is recommended to use

1C++/CX is a set of language extensions for C++ compilers introduced by Microsoft to enablethe creation of Windows apps and WinRT components.

60

Page 69: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

native code.

Moving on to the drivers implementation, it started off by creating the driver for

DHT22 sensor module (also known as AM2302). The driver has been imple-

mented based on the official AM2302 datasheet [3].

Listing 5.2: DHT22 - Interface Declaration

public ref struct DhtReading sealed{

private:const double _temperature;const double _humidity;unsigned _retryCount;

DhtReading(double temperature, double humidity): _temperature(temperature), _humidity(humidity), _retryCount(0)

{ }internal:

static DhtReading^ CreateFromBitset(std::bitset<40>* bits);public:

property double Temperature {double get() {

return _temperature;}

}property double Humidity {

double get() {return _humidity;

}}property uint32 RetryCount {

uint32 get() {return _retryCount;

}internal:

void set(uint32 value) {_retryCount = value;

}}

};

public ref class Dht22 sealed{

public:virtual ~Dht22();

static Windows::Foundation::IAsyncOperation<Dht22^>^ InitAsync(intdataPinNumber);

Windows::Foundation::IAsyncOperation<DhtReading^>^ TryGetReadingAsync();Windows::Foundation::IAsyncOperation<DhtReading^>^ TryGetReadingAsync(

uint32 maxRetryCount);

property Windows::Devices::Gpio::GpioPin^ DataPin {Windows::Devices::Gpio::GpioPin^ get() {

return _pin;}

61

Page 70: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

}private:

enum DHT22 { MCU_START_SIGNAL_MILLIS = 18, DEFAULT_MAX_RETRY_COUNT = 20};

Windows::Devices::Gpio::GpioPin^ _pin;Windows::Devices::Gpio::GpioPinDriveMode inputReadMode;

Dht22(Windows::Devices::Gpio::GpioController^ controller, intdataPinNumber);

inline HRESULT WaitForSensorResponseSignal() const;internal:

DhtReading^ InternalGetReading() const;};

The AM2302 module uses the 1-Wire protocol to communicate with the mi-

crocontroller unit (MCU). It is worth noting, however, that the module is not com-

patible with Dallas 1-Wire bus in that it does not have a unique 64-bit address, thus

each module needs its own single bi-directional digital I/O line to the MCU. The

bits that the AM2302 module sends to MCU are encoded as pulse widths. To

begin the communication, the MCU sends a start signal by pulling the data-bus

low for at least 18ms. Upon receiving the start signal, AM2302 sends a response

signal followed by the 40-bit data that reflect the relative humidity and tempera-

ture. The first 16 bits represent the relative humidity (RH) data, the next 16 bits

represent the temperature (T) data, and the last 8 bits represent the check sum. To

enable the use of 1-Wire interface, the Windows IoT Extension SDK provides the

GpioController and GpioPin classes.

Listing 5.3: DHT22 - Getting Sensor Reading

DhtReading ^ Dht22::InternalGetReading() const{

DhtReading^ reading = nullptr;

LARGE_INTEGER pcf; // a performance-counter frequency (in counts per second)QueryPerformanceFrequency(&pcf);

// A ’0’ has a pulse time of 76us, while a ’1’ has a pulse time of 120us -// 110us is chosen as a reasonable threshold used to determine whether a bit

is a ’0’ or a ’1’.// We convert the value to QPC units for later use.const unsigned int oneThreshold = static_cast<unsigned int>(110LL * pcf.

QuadPart / 1000000LL);

// Set pin as output

62

Page 71: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

this->_pin->SetDriveMode(GpioPinDriveMode::Output);

// Data-bus’s free status is high voltage level - latch low value onto pin// to begin communication.this->_pin->Write(GpioPinValue::Low);

// Send start signal and keep this signal at least 18 msSleep(MCU_START_SIGNAL_MILLIS);

// Latch high value onto pinthis->_pin->Write(GpioPinValue::High);

// Set pin back to inputthis->_pin->SetDriveMode(this->inputReadMode);

HRESULT hr = this->WaitForSensorResponseSignal();

if (hr != S_OK){

return reading;}

bitset<40> bits; // a buffer for the 40-bit reading

GpioPinValue prevValue = this->_pin->Read(), currValue;LARGE_INTEGER prevTime = { 0 }, currTime;

const ULONG readingTimeoutMillis = 10;ULONGLONG endTickCount = GetTickCount64() + readingTimeoutMillis;

// Capture every falling edge until all bits are received or timeout occurs.for (unsigned int i = 0; i < (bits.size() + 1);){

if (GetTickCount64() > endTickCount){

return reading;}

currValue = this->_pin->Read();

if ((prevValue == GpioPinValue::High) && (currValue == GpioPinValue::Low))

{QueryPerformanceCounter(&currTime);

if (i != 0){

unsigned int difference = static_cast<unsigned int>(currTime.QuadPart - prevTime.QuadPart);

bits[bits.size() - i] = difference > oneThreshold;}

prevTime = currTime;++i;

}

prevValue = currValue;}

reading = DhtReading::CreateFromBitset(&bits);

63

Page 72: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

return reading;}

DhtReading ^ DhtReading::CreateFromBitset(bitset<40>* bits){

unsigned long long value = bits->to_ullong();

unsigned int checksum = ((value >> 32) & 0xFF) + ((value >> 24) & 0xFF) +((value >> 16) & 0xFF) + ((value >> 8) & 0xFF);

if ((checksum & 0xFF) != (value & 0xFF)) // checksum mismatch{

return nullptr;}

double temp, hum;

// AM2303 has a humidity resolution of 0.1% RHhum = ((value >> 24) & 0xFFFF) * 0.1;

// AM2303 has a temperature resolution of 0.1 Celsiustemp = ((value >> 8) & 0x7FFF) * 0.1;

if ((value >> 8) & 0x8000) temp *= -1;

return ref new DhtReading(temp, hum);}

Moving on to the second of two sensors, the driver for BMP180 sensor module

has been implemented based on the information provided in the official BMP180

datasheet [5].

Listing 5.4: BMP180 - Interface Declaration

public enum class BmpMode { UltraLowPower = 0, Standard = 1, HighRes = 2,UltraHighRes = 3 };

public ref struct BmpReading sealed{

private:const double _temperature;const unsigned _pressure;

internal:BmpReading(double temperature, unsigned pressure)

: _temperature(temperature), _pressure(pressure){ }

public:property double Temperature {

double get() {return _temperature;

}}property unsigned Pressure {

unsigned get() {return _pressure;

}}

};

64

Page 73: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

public ref class Bmp180 sealed{

public:virtual ~Bmp180();

static Windows::Foundation::IAsyncOperation<Bmp180^>^ InitAsync(BmpModemode);

Windows::Foundation::IAsyncOperation<double>^ ReadTemperatureAsync();Windows::Foundation::IAsyncOperation<unsigned>^ ReadPressureAsync();Windows::Foundation::IAsyncOperation<double>^ ReadAltitudeAsync(unsigned

seaLevelPressure);Windows::Foundation::IAsyncOperation<BmpReading^>^ GetReadingAsync();

property BmpMode SamplingMode {BmpMode get() {

return _oss;}

}private:

enum BMP180 {ADDRESS = 0x77, ADDRESS_READ = 0xEF, ADDRESS_WRITE = 0xEE,WRITE_REG = 0xF4, READ_REG = 0xF6, READ_TEMP_CMD = 0x2E,

READ_PRESSURE_CMD = 0x34};enum BMP180_CAL {

AC1 = 0xAA, AC2 = 0xAC, AC3 = 0xAE, AC4 = 0xB0, AC5 = 0xB2, AC6 = 0xB4,

B1 = 0xB6, B2 = 0xB8, MB = 0xBA, MC = 0xBC, MD = 0xBE};

Windows::Devices::I2c::I2cDevice^ i2cDevice;BmpMode _oss;

short ac1, ac2, ac3;unsigned short ac4, ac5, ac6;short b1, b2, mb, mc, md;

Bmp180(Windows::Devices::I2c::I2cController^ controller, BmpMode mode);

double ReadTemperatureCore(int ut) const;unsigned ReadPressureCore(int ut, int up) const;double ReadAltitudeCore(unsigned pressure, unsigned seaLevelPressure)

const;void ReadCalibrationData();int ReadUTemperature() const;int ReadUPressure() const;inline int ReadData(Platform::Array<unsigned char>^ writeBuffer, Platform

::Array<unsigned char>^ readBuffer) const;};

Unlike DHT22 sensor module, the BMP180 communicates with the MCU via

I2C bus. Prior to reading the temperature and pressure measurements, the driver

needs to be initialized with the calibration data that can be read out from the

BMP180 E2PROM via the I2C interface. The calibration data consists of a set of

65

Page 74: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

11 parameters {ac1, ac2, ac3, ac4, ac5, ac6, b1, b2, mb, mc, md}. Once the driver

has been initialized, the calibration data is used for calculating the temperature in

°C and pressure in hPa. To enable the use of I2C bus, the Windows IoT Extension

SDK provides the I2cController and I2cDevice classes.

Listing 5.5: BMP180 - Getting Sensor Reading

IAsyncOperation<BmpReading^>^ Bmp180::GetReadingAsync(){

return create_async([this]() -> BmpReading^{

int ut, up;unsigned pressure;double temperature;

ut = ReadUTemperature();up = ReadUPressure();

pressure = ReadPressureCore(ut, up);temperature = ReadTemperatureCore(ut);

BmpReading^ reading = ref new BmpReading(temperature, pressure);

return reading;});

}

double Bmp180::ReadTemperatureCore(int ut) const{

double t;int x1, x2, b5;

x1 = ((ut - ac6) * ac5) >> 15; // X1=(UT-AC6)*AC5/2^15x2 = (mc << 11) / (x1 + md); // X2=MC*2^11/(X1+MD)b5 = x1 + x2; // B5=X1+X2

t = (b5 + 8) >> 4; // T=(B5+8)/2^4t *= 0.1;

return t;}

unsigned Bmp180::ReadPressureCore(int ut, int up) const{

int p;int b3, b5, b6, x1, x2, x3;unsigned b4, b7;

x1 = ((ut - ac6) * ac5) >> 15; // X1=(UT-AC6)*AC5/2^15x2 = (mc << 11) / (x1 + md); // X2=MC*2^11/(X1+MD)b5 = x1 + x2; // B5=X1+X2

b6 = b5 - 4000; // B6=B5-4000x1 = (b2 * ((b6 * b6) >> 12)) >> 11; // X1=(B2*(B6*B6/2^12))/2^11x2 = (ac2 * b6) >> 11; // X2=AC2*B6/2^11x3 = x1 + x2; // X3=X1+X2b3 = ((((ac1 << 2) + x3) << (int)_oss) + 2) >> 2; // (((AC1*4+X3)<<oss)+2)/4

66

Page 75: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

x1 = (ac3 * b6) >> 13; // X1=AC3*B6/2^13x2 = (b1 * ((b6 * b6) >> 12)) >> 16; // X2=(B1*(B6*B6/2^12))/2^16x3 = ((x1 + x2) + 2) >> 2; // X3=((X1+X2)+2)/2^2b4 = (ac4 * (unsigned)(x3 + 32768)) >> 15; // B4=AC4*(unsigned long)(X3

+32768)/2^15b7 = ((unsigned)up - b3) * (50000U >> (int)_oss); // B7=((unsigned long)UP-B3

)*(50000>>oss)

if (b7 < 0x80000000) {p = (b7 << 1) / b4; // p=(B7*2)/B4

}else {

p = (b7 / b4) << 1; // p=(B7/B4)*2}

x1 = (p >> 8) * (p >> 8); // X1=(p/2^8)*(p/2^8)x1 = (x1 * 3038) >> 16; // X1=(X1*3038)/2^16x2 = (-7357 * p) >> 16; // X2=(-7357*p)/2^16

p += (x1 + x2 + 3791) >> 4; // p=p+(X1+X2+3791)/2^4

return (unsigned)p;}

int Bmp180::ReadUTemperature() const{

Array<unsigned char>^ writeBuffer = ref new Array<unsigned char>(2);Array<unsigned char>^ readBuffer = ref new Array<unsigned char>(2);

writeBuffer[0] = WRITE_REG;writeBuffer[1] = READ_TEMP_CMD;

i2cDevice->Write(writeBuffer);

Sleep(5); // wait at least 4.5ms

writeBuffer = ref new Array<unsigned char>(1);writeBuffer[0] = READ_REG;

int ut = ReadData(writeBuffer, readBuffer);

return ut;}

int Bmp180::ReadUPressure() const{

Array<unsigned char>^ writeBuffer = ref new Array<unsigned char>(2);Array<unsigned char>^ readBuffer = ref new Array<unsigned char>(3);

writeBuffer[0] = WRITE_REG;writeBuffer[1] = READ_PRESSURE_CMD + ((int)_oss << 6);

i2cDevice->Write(writeBuffer);

// According to the data sheet, the wait time for pressure readings is// dependent on the oversampling setting.Sleep(2 + (3 << (int)_oss));

writeBuffer = ref new Array<unsigned char>(1);

writeBuffer[0] = READ_REG;

67

Page 76: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

int up = ReadData(writeBuffer, readBuffer) >> (8 - (int)_oss); // 16 to 19bits

return up;}

inline int Bmp180::ReadData(Array<unsigned char>^ writeBuffer, Array<unsignedchar>^ readBuffer) const

{i2cDevice->WriteRead(writeBuffer, readBuffer);

unsigned char* data = readBuffer->Data;int count = readBuffer->Length - 1, ret = 0;

for (int i = 0; i <= count; i++, data++){

ret |= (*data) << (8 * (count - i));}

return ret;}

Having created the Windows Runtime component with sensor drivers, it was

possible to reference it from the main UWP application project and use the Dht22

and Bmp180 classes for collecting sensor readings. The actual telemetry data

(a.k.a. sensor readings) is collected through TelemetrySender class of which in-

stance is registered as an IoT Hub message sender (see subsection 5.2.3). The

TelemetrySender class creates a periodic timer, which invokes the specified call-

back each time the sensing period elapses. The class is also responsible for de-

tecting anomalous DHT22 sensor readings to ensure the stable and reliable data.

Listing 5.6: Class Responsible For Collecting Sensor Readings

public class TelemetrySender : IotHubMessageSender<AtmosphereTelemetryData>,ITelemetrySender

{...

public void Start(){

Stop(); // stop all running timers first

timer = ThreadPoolTimer.CreatePeriodicTimer(OnGetReading, TimeSpan.FromMilliseconds(SensingPeriod));

}

...

private async Task InitializeAsync(){

68

Page 77: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

SensorState = SensorState.Initializing;

try{

dht22 = await Dht22.InitAsync(Dht22PinNumber);

bmp180 = await Bmp180.InitAsync(BmpMode.UltraHighRes);}catch (Exception){

SensorState = SensorState.NotAvailable;return;

}

await StabilizeReadingsAsync();}

...

private async void OnGetReading(ThreadPoolTimer sender){

if (SensorState != SensorState.Ready && SensorState != SensorState.Unstable)

{return;

}

var dhtRd = await dht22.TryGetReadingAsync();var bmpRd = await bmp180.GetReadingAsync();

var isAnomalous = false;var dhtOk = dhtRd != null && CompareExchangeDhtReading(ref dhtReading,

dhtRd, out isAnomalous);var bmpOk = bmpRd != null && CompareExchangeBmpReading(ref bmpReading,

bmpRd);

if (dhtReading != null && bmpReading != null && (dhtOk || bmpOk) && !isAnomalous)

{var avgTemp = Math.Round((dhtReading.Temperature + bmpReading.

Temperature) / 2, 1);

var data = new AtmosphereTelemetryData(avgTemp, dhtReading.Humidity,bmpReading.Pressure / 100d);

await Logger.Instance.LogAsync($"{nameof(TelemetrySender)}", $"Temperature: {data.Temperature}\u00B0C | Humidity: {data.Humidity}% | " + $"Pressure: {data.Pressure}hPa");

OnDataChanged(data);OnSendMessage(data, DeviceMessageType.Telemetry, useRetryPolicy: true

);

SensorState = SensorState.Ready;}else if (isAnomalous){

if (SensorState == SensorState.Unstable){

await StabilizeReadingsAsync();}else

69

Page 78: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

{SensorState = SensorState.Unstable;

}}

}

...}

5.2.2 Bluetooth Low Energy Connectivity

Bluetooth Low Energy (BLE) is a lightweight subset of classic Bluetooth. It was

officially introduced in 2010 as a part of the Bluetooth Core Specification Ver-

sion 4.0 maintained and developed by the Bluetooth Special Interest Group (SIG).

The BLE is characterized by an entirely new protocol stack optimized for low

power, low latency, and low throughput applications. The standard is widely used

for IoT services due to the low energy consumption and relatively low manu-

facturing costs. In order to add BLE connectivity to the IoT gateway, the UWP

Bluetooth API was used. The process of obtaining the connection between the

peripheral (IoT accessory) and the central device (IoT gateway) begins with de-

vice discovery, which is done through the Generic Access Profile (GAP) protocol

[1]. The Windows API provides a DeviceWatcher class, which can be used for

finding BLE devices. To obtain an instance of DeviceWatcher for BLE devices,

one must call the DeviceInformation.CreateWatcher factory method with the ap-

propriate Advanced Query Syntax (AQS) string filter. The AQS filter for BLE

devices has the following form: "System.Devices.Aep.ProtocolId:

=bb7bb05e-5972-42b5-94fc-76eaa7084d49". After obtaining a pre-

configured instance of DeviceWatcher class, we can register the event handlers to

receive notifications whenever the devices are added, removed, or changed. In or-

der to simplify this process, a BluetoothLEScanner class was created that exposes

a simple interface for BLE scanning.

70

Page 79: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Listing 5.7: Scanning For BLE Devices

public sealed class BluetoothLEScanner{

private DeviceWatcher deviceWatcher;private List<DeviceInformation> scanResults;private ScanResultsChangedCallback scanResultsChangedCallback;

public void StartScan(ScanResultsChangedCallback callback){

if (callback == null){

throw new ArgumentNullException(nameof(callback));}

StopScan();

scanResults = new List<DeviceInformation>();scanResultsChangedCallback = callback;

deviceWatcher = DeviceWatcherHelper.CreateBluetoothLEDeviceWatcher();

deviceWatcher.Added += OnDeviceAdded;deviceWatcher.Updated += OnDeviceUpdated;deviceWatcher.Removed += OnDeviceRemoved;

deviceWatcher.Start();}

public void StopScan(){

if (deviceWatcher == null) return;

deviceWatcher.Added -= OnDeviceAdded;deviceWatcher.Updated -= OnDeviceUpdated;deviceWatcher.Removed -= OnDeviceRemoved;

if (deviceWatcher.Status == DeviceWatcherStatus.Started ||deviceWatcher.Status == DeviceWatcherStatus.EnumerationCompleted)

{deviceWatcher.Stop();

}

deviceWatcher = null;

scanResults.Clear();scanResults = null;scanResultsChangedCallback = null;

}

private void OnScanResultsChanged(){

scanResultsChangedCallback?.Invoke(scanResults);}

private void OnDeviceAdded(DeviceWatcher sender, DeviceInformation deviceInfo)

{scanResults.Add(deviceInfo);

OnScanResultsChanged();

71

Page 80: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

}

private void OnDeviceUpdated(DeviceWatcher sender, DeviceInformationUpdatedeviceInfoUpdate)

{var deviceInfo = scanResults.FirstOrDefault(res => res.Id ==

deviceInfoUpdate.Id);

if (deviceInfo == null) return;

deviceInfo.Update(deviceInfoUpdate);

OnScanResultsChanged();}

private void OnDeviceRemoved(DeviceWatcher sender, DeviceInformationUpdatedeviceInfoUpdate)

{var deviceInfo = scanResults.FirstOrDefault(res => res.Id ==

deviceInfoUpdate.Id);

if (deviceInfo == null) return;

scanResults.Remove(deviceInfo);

OnScanResultsChanged();}

}

public delegate void ScanResultsChangedCallback(IList<DeviceInformation>scanResults);

The BluetoothLEScanner class is used by the BluetoothAccessoriesService

class, which represents a service responsible for managing a list of connected

BLE accessories. The service contains a callback for handling BLE scan results.

Upon receiving the scan results, the service attempts to connect to the detected

device provided that it belongs to a set of supported BLE accessories. Please note

that the current implementation only supports the Magic Blue Smart Bulb, but it

can be easily modified to support other BLE accessories.

Listing 5.8: Class Managing Connected BLE Devices

public class BluetoothAccessoriesService : IBluetoothAccessoriesService{

...

public BluetoothAccessoriesService(IEventAggregator eventAggregator){

EventAggregator = eventAggregator;

EventAggregator.GetEvent<PubSubEvent<LedLightCommand>>().Subscribe(HandleLedLightCommand);

}

72

Page 81: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

public void StartDiscovery(){

StopDiscovery();

scanner = new BluetoothLEScanner();

scanner.StartScan(OnScanResultsChanged);}

public void StopDiscovery(){

if (scanner == null) return;

scanner.StopScan();scanner = null;

}

private async void OnScanResultsChanged(IList<DeviceInformation> scanResults){

if (scanResults.Count == 0){

_connectedAccessories.ForEach(a => a.Dispose());_connectedAccessories.Clear();

OnConnectedAccessoriesChanged();}else{

if (_connectedAccessories.Any(a => a is MagicBlueSmartBulb)) return;

var deviceInfo = scanResults.FirstOrDefault(MagicBlueSmartBulb.CanCreateInstance);

if (deviceInfo == null) return;

try{

var smartBulb = await MagicBlueSmartBulb.CreateInstanceAsync(deviceInfo);

if (smartBulb != null){

_connectedAccessories.Add(smartBulb);

OnConnectedAccessoriesChanged();

await Logger.Instance.LogAsync(nameof(BluetoothAccessoriesService),

$"Successfully connected BLEaccessory {{{deviceInfo.Id}}}");

}}catch (Exception ex){

await Logger.Instance.LogAsync(nameof(BluetoothAccessoriesService), ex.Message);

}}

}

73

Page 82: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

...

private void HandleLedLightCommand(LedLightCommand command){

foreach (var accessory in _connectedAccessories.Where(a => a is IHandle<LedLightCommand>))

{((IHandle<LedLightCommand>)accessory).Handle(command);

}}

...}

Most of the Bluetooth Low Energy peripherals use a custom set of services and

characteristics. Therefore, each BLE accessory should be treated individually. For

demonstration purposes a MagicBlueSmartBulb class was created. This class im-

plements the GATT profile of Magic Blue UU E27 Bulb, which can be discovered

by reverse engineering [24] the GATT services and characteristics used to control

the BLE peripheral. In case of Magic Blue Smart Bulb there is only one writable

characteristic 0xFFE9 contained in the service 0xFFE5.

Listing 5.9: Magic Blue Smart Bulb GATT Profile Implementation

public sealed class MagicBlueSmartBulb : BluetoothAccessory, IHandle<LedLightCommand>

{private const string DeviceName = "LEDBLE-786009A5";

private static readonly Guid CmdServiceUuid = Guid.Parse("0000ffe5-0000-1000-8000-00805f9b34fb");

private static readonly Guid CmdCharacteristicUuid = Guid.Parse("0000ffe9-0000-1000-8000-00805f9b34fb");

private const byte MagicNumber = 0x56;

...

public static bool CanCreateInstance(DeviceInformation deviceInformation){

if (deviceInformation == null){

throw new ArgumentNullException(nameof(deviceInformation));}

return deviceInformation.Name == DeviceName &&deviceInformation.Kind == DeviceInformationKind.

AssociationEndpoint;}

public static async Task<MagicBlueSmartBulb> CreateInstanceAsync(DeviceInformation deviceInformation)

{

74

Page 83: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

var instance = new MagicBlueSmartBulb(deviceInformation);

bool paired = await instance.TryPairAsync();

if (paired){

instance.StartGattServicesWatcher();}

return paired ? instance : null;}

public async Task<bool> TrySetColorAsync(byte red, byte green, byte blue){

byte[] payload = { MagicNumber, red, green, blue, 0x00, 0xF0, 0xAA };

return await TrySetPropertyAsync(CmdServiceUuid, CmdCharacteristicUuid,payload);

}

public async Task<bool> TrySetWarmLightAsync(byte intensity){

byte[] payload = { MagicNumber, 0x00, 0x00, 0x00, intensity, 0x0F, 0xAA};

return await TrySetPropertyAsync(CmdServiceUuid, CmdCharacteristicUuid,payload);

}

...

public async void Handle(LedLightCommand command){

var intensity = (byte)(0xFF * command.Description.Intensity);

await TrySetWarmLightAsync(intensity);}

}

The MagicBlueSmartBulb class exposes methods for setting the color and light

intensity of the light bulb. These methods are specific to the Magic Blue Smart

Bulb, however there is a certain set of operations that is common to all BLE ac-

cessories. Such operations include pairing with the device, watching for GATT

services, and writing data to / reading data from the characteristic. To avoid dupli-

cate code a BluetoothAccessory abstract base class was created that contains the

methods for performing operations common to all BLE accessories.

Listing 5.10: Base Class For Bluetooth Low Energy Accessories

public abstract class BluetoothAccessory : IDisposable{

...

75

Page 84: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

protected BluetoothAccessory(DeviceInformation deviceInformation){

if (deviceInformation == null){

throw new ArgumentNullException(nameof(deviceInformation));}

DeviceInformation = deviceInformation;SupportedPairingCeremonies = DevicePairingKinds.ConfirmOnly;

}

...

protected virtual async Task<bool> TryPairAsync(){

var pairing = DeviceInformation.Pairing;

if (!pairing.IsPaired && !pairing.CanPair){

return false;}

if (pairing.IsPaired) return true;

var customPairing = pairing.Custom;

customPairing.PairingRequested += OnPairingRequested;

var result = await customPairing.PairAsync(SupportedPairingCeremonies);

customPairing.PairingRequested -= OnPairingRequested;

if (result.Status != DevicePairingResultStatus.Paired){

return false;}

return true;}

protected void StartGattServicesWatcher(){

var serviceUuids = GetGattServiceUuidList();

if (serviceUuids == null || serviceUuids.Count == 0){

throw new InvalidOperationException("GATT service UUID list must notbe null or empty.");

}

StopGattServicesWatcher();

servicesWatcher = DeviceWatcherHelper.CreateGattDeviceServicesWatcher(serviceUuids);

servicesWatcher.Added += OnServiceAdded;servicesWatcher.Updated += OnServiceUpdated;servicesWatcher.Removed += OnServiceRemoved;

servicesWatcher.Start();}

76

Page 85: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

...

protected GattCharacteristic GetWritableGattCharacteristic(Guid serviceUuid,Guid characteristicUuid)

{var service = GattServices.FirstOrDefault(s => s.Uuid == serviceUuid);

var characteristics = service?.GetCharacteristics(characteristicUuid);

var characteristic =characteristics?.FirstOrDefault(

c => c.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write));

return characteristic;}

protected async Task<bool> WriteValueToCharacteristicAsync(GattCharacteristiccharacteristic, byte[] payload)

{if (characteristic == null){

throw new ArgumentNullException(nameof(characteristic));}if (payload == null){

throw new ArgumentNullException(nameof(payload));}if (!characteristic.CharacteristicProperties.HasFlag(

GattCharacteristicProperties.Write)){

throw new ArgumentException($"The specified {nameof(characteristic)}is not writable.", nameof(characteristic));

}

GattCommunicationStatus status;

using (var writer = new DataWriter()){

writer.WriteBytes(payload);

status = await characteristic.WriteValueAsync(writer.DetachBuffer());}

return status == GattCommunicationStatus.Success;}

protected async Task<bool> TrySetPropertyAsync(Guid serviceUuid, GuidcharacteristicUuid, byte[] payload)

{var characteristic = GetWritableGattCharacteristic(serviceUuid,

characteristicUuid);

if (characteristic == null) return false;

bool result = await WriteValueToCharacteristicAsync(characteristic,payload);

return result;}

...

77

Page 86: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

}

5.2.3 IoT Hub Connectivity

The IoT gateway UWP app communicates with the cloud by establishing a con-

nection to the Azure IoT Hub. The connection is initiated by IotHubService.

OpenConnectionAsync method that is called on application startup. The Open-

ConnectionAsync method initializes and configures the components managing the

flow of information between the IoT gateway and IoT Hub service. Those compo-

nents include the telemetry sender for collecting telemetry data, cloud command

receiver for handling cloud commands, and connection manager for coordinating

the flow of IoT Hub messages.

Listing 5.11: Initiating Connection With Azure IoT Hub

public class IotHubService : IIotHubService{

...

public async Task OpenConnectionAsync(){

await Task.Run(async () =>{

InternalTelemetrySender = await IotHub.Senders.TelemetrySender.CreateAsync();

InternalCloudCommandReceiver = new CloudCommandReceiver(EventAggregator);

var deviceClient = DeviceClient.CreateFromConnectionString(Constants.IotHubDeviceConnectionString, TransportType.Amqp);

connectionManager = await IotHubConnectionManager.CreateAsync(deviceClient);

connectionManager.RegisterMessageSender(InternalTelemetrySender);connectionManager.RegisterMessageReceiver(

InternalCloudCommandReceiver, CloudMessageType.Command);

InternalTelemetrySender.Start();});

}

...}

The IotHubConnectionManager class represents a connection manager, which

coordinates the cloud message flow using the concept of message senders and

78

Page 87: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

message receivers. The message senders publish the messages that are to be send

to the cloud, whereas the message receivers handle the data contained in the mes-

sages received form the cloud. Once initialized, both the senders and receivers

can be registered with the connection manager that handles all the complexity

related to message filtering, data conversion, and transient fault handling. Such

a model ensures loose-coupling between the individual components while being

highly flexible and extensible.

To establish a secure connection to the IoT Hub service 2, the IotHubConnec-

tionManager class uses a DeviceClient class from the Microsoft.Azure.

Devices.Client NuGet package. The DeviceClient class is also used to re-

ceive cloud messages in a message loop and send the messages published by the

message senders. To avoid blocking the main application thread, the message loop

runs in a separate thread.

Listing 5.12: Class Managing IoT Hub Message Flow

public sealed class IotHubConnectionManager : IDisposable{

...

private IotHubConnectionManager(DeviceClient deviceClient){

this.deviceClient = deviceClient;

senders = new List<IIotHubMessageSender>();receivers = new ConcurrentDictionary<string, List<IIotHubMessageReceiver

>>();

cloudMsgLoopTask = StartCloudMessageLoopAsync();}

...

private Task StartCloudMessageLoopAsync(){

if (cts != null && !cts.IsCancellationRequested){

return Task.CompletedTask;}

cts = new CancellationTokenSource();

var token = cts.Token;

2The IoT gateway authentication is discussed in detail in chapter 2.

79

Page 88: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

return Task.Factory.StartNew(() => CloudMessageLoopAsync(token), token);}

...

private async void CloudMessageLoopAsync(CancellationToken token){

Message cloudMessage = null;

while (!token.IsCancellationRequested){

try{

var retryPolicy = CreateOperationRetryPolicy();

await retryPolicy.ExecuteAsync(async () => cloudMessage = awaitInternalReceiveMessageAsync(), token);

}catch (Exception ex){

await Logger.Instance.LogAsync($"{nameof(IotHubConnectionManager)}", ex.ToString());

continue;}

if (cloudMessage == null) continue;

await ProcessCloudMessageAsync(cloudMessage);}

}

private async Task ProcessCloudMessageAsync(Message message){

string messageBody = null, messageTypeString = null;

if (message.Properties.ContainsKey("messageType")){

messageTypeString = message.Properties["messageType"];}

var messageType = CloudMessageType.TryParse(messageTypeString);

if (messageType == null){

await deviceClient.RejectAsync(message);return;

}

var data = message.GetBytes();

if (data != null){

messageBody = Encoding.UTF8.GetString(data);}

var args = new MessageReceivedEventArgs(messageBody ?? "", messageType);

await deviceClient.CompleteAsync(message);

NotifyMessageReceivers(args);

80

Page 89: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

}

private void NotifyMessageReceivers(MessageReceivedEventArgs args){

List<IIotHubMessageReceiver> rcvs;

// Notify the receivers that were registered to handle the specificmessage type

receivers.TryGetValue(args.MessageType.Id, out rcvs);

if (rcvs != null){

foreach (var receiver in rcvs){

receiver.OnMessageReceived(args);}

}

// Notify the receivers that were registered to handle all message typesreceivers.TryGetValue("", out rcvs);

if (rcvs == null) return;

foreach (var receiver in rcvs){

receiver.OnMessageReceived(args);}

}

...

private async void OnSendMessage(IIotHubMessageSender sender,SendMessageEventArgs e)

{var message = CreateAmqpMessage(e.MessageBody, e.MessageType.Id);

Interlocked.Exchange(ref sendMessageId, message.MessageId);

await Task.Factory.StartNew(async () =>{

try{

await Logger.Instance.LogAsync($"{nameof(IotHubConnectionManager)}", $"Sending message {{{message.MessageId}}}");

if (e.UseRetryPolicy){

var retryPolicy = CreateOperationRetryPolicy();

await retryPolicy.ExecuteAsync(() => InternalSendMessageAsync(message));

}else{

await InternalSendMessageAsync(message);}

await Logger.Instance.LogAsync($"{nameof(IotHubConnectionManager)}", $"Message has been sent {{{message.MessageId}}}");

}catch (Exception ex){

81

Page 90: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

await Logger.Instance.LogAsync($"{nameof(IotHubConnectionManager)}", ex.ToString());

}});

}

...}

All message senders registered with an instance of the IotHubConnectionMan-

ager class must implement the IIotHubMessageSender interface. The interface

defines a simple event that is used to notify the connection manager about the

message that is to be sent. Most of the message senders will operate on data types

other than JSON string. To simplify the process of serializing data object to JSON

string, an IotHubMessageSender generic abstract base class was created that hides

the complexity of this process.

Listing 5.13: IoT Hub Message Sender Interface & Base Implementation

public interface IIotHubMessageSender{

event SendMessageEventHandler SendMessage;}

public abstract class IotHubMessageSender<TData> : IIotHubMessageSender whereTData : class

{protected virtual void OnSendMessage(TData data, DeviceMessageType

messageType, bool useRetryPolicy = false){

using (var stream = new MemoryStream()){

var serializer = new DataContractJsonSerializer(typeof(TData));

serializer.WriteObject(stream, data);

stream.Seek(0, SeekOrigin.Begin);

using (var reader = new StreamReader(stream)){

OnSendMessage(reader.ReadToEnd() ?? "", messageType,useRetryPolicy);

}}

}

private void OnSendMessage(string messageData, DeviceMessageType messageType,bool useRetryPolicy)

{var args = new SendMessageEventArgs(messageData, messageType,

useRetryPolicy);

SendMessage?.Invoke(this, args);

82

Page 91: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

}

public event SendMessageEventHandler SendMessage;}

Similarly to message senders, all message receivers registered with an instance

of the IotHubConnectionManager class must implement the IIotHubMessageRe-

ceiver interface. This time the interface defines a callback method that is called

by the connection manager to notify the message receiver about the received mes-

sage. Most of the message receivers will operate on data types other than JSON

string. To simplify the process of deserializing JSON string to data object, an Io-

tHubMessageReceiver generic abstract base class was created that hides the com-

plexity of this process.

Listing 5.14: IoT Hub Message Receiver Interface & Base Implementation

public interface IIotHubMessageReceiver{

void OnMessageReceived(MessageReceivedEventArgs args);}

public abstract class IotHubMessageReceiver<TData> : IIotHubMessageReceiver whereTData : class

{public void OnMessageReceived(MessageReceivedEventArgs args){

TData data = args.MessageBody as TData;

if (data == null){

using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(args.MessageBody)))

{var serializer = new DataContractJsonSerializer(typeof(TData));

data = serializer.ReadObject(stream) as TData;}

}

OnMessageReceivedCore(data, args.MessageType);}

protected virtual void OnMessageReceivedCore(TData data, CloudMessageTypemessageType)

{ }}

In order to parse the cloud messages to commands that can be consumed by

objects representing BLE accessories, a CloudCommandReceiver class was cre-

83

Page 92: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

ated. This class parses the message data to command object and uses the event

aggregator to notify the BluetoothAccessoriesService (see subsection 5.2.2 about

the received command.

Listing 5.15: Parsing & Handling Cloud Commands

public class CloudCommandReceiver : IotHubMessageReceiver<string>,ICloudCommandReceiver

{public event TypedEventHandler<ICloudCommandReceiver, ICloudCommand>

CommandReceived;

...

protected override async void OnMessageReceivedCore(string data,CloudMessageType messageType)

{ICloudCommand cloudCommand;

if (LedLightCommand.TryParse(data, out cloudCommand)){

EventAggregator.GetEvent<PubSubEvent<LedLightCommand>>().Publish((LedLightCommand)cloudCommand);

}

if (cloudCommand == null) return;

CommandReceived?.Invoke(this, cloudCommand);

await Logger.Instance.LogAsync($"{nameof(CloudCommandReceiver)}", "Command has been received");

}

...}

84

Page 93: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Chapter 6

Client Application

The final part of the discussed IoT platform is the client application of which

purpose is to allow user to control the IoT gateway together with the connected

IoT accessories. The client application is based on the Universal Windows Plat-

form (UWP) and it was written in C# and XAML. In order to achieve a highly

scalable and maintainable code, the application architecture complies with the

MVVM pattern and utilizes the dependency injection mechanism. Moreover, the

application skeleton was built with components provided by the Prism framework

[23] for UWP. Following from these architectural design decisions, the applica-

tion components can be divided into three main groups: the models containing

the business logic, the views defining the layout of the displayed content, and the

view models containing the view logic and wiring-up the views with models. The

view model binds to the view using a data binding mechanism for UWP apps and

manipulates the models in response to commands triggered by view. Even though

the MVVM pattern provides a clear separation of concerns, as the application

grows, the view models can become large and difficult to maintain. It was there-

fore decided to introduce the services, which encapsulate the application logic

that would otherwise be contained inside the view models. Such services can be

responsible for user authentication, push notifications, background task registra-

85

Page 94: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

tion, internet connectivity information, and other common application logic. The

discussed application registers the services with the IoC container provided by the

Prism framework, thus enabling the loose coupling between the services and view

models.

Since the application requires an Internet access and uses the background tasks

to perform certain operations, it was necessary to declare the Internet (Client)

capability along with the background tasks declaration in app’s package manifest.

Listing 6.1: App Capability & Background Task Declarations

<?xml version="1.0" encoding="utf-8"?><Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"

xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"IgnorableNamespaces="uap mp">

...

<Dependencies><TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0"

MaxVersionTested="10.0.0.0" /></Dependencies>

...

<Applications><Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="

SlickHubRemote.App">...

<Extensions><Extension Category="windows.backgroundTasks" EntryPoint="

SlickHubRemote.BackgroundTasks.PushNotificationTask"><BackgroundTasks><Task Type="pushNotification" />

</BackgroundTasks></Extension>

</Extensions></Application>

</Applications><Capabilities><Capability Name="internetClient" />

</Capabilities></Package>

86

Page 95: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

6.1 User Interface Layout

Since the UWP apps can run on a wide range of Windows 10 devices, one of

the main challenges was to design and implement the UI that would adapt to

different screen sizes. The XAML layout system provides three main approaches

for creating a responsive UI. The first approach is called a fluid layout and it

assumes the use of layout properties and panels to reposition and scale the content.

The second approach, an adaptive layout, is based on the visual states, which

define a set of values applied to layout properties whenever the visual state is

activated by the state trigger. Finally, there is a tailored layout approach, which

allows to create the UI layout optimized for a specific device family by either using

custom device family trigger or by creating per-device family XAML views. Due

to major differences in UI design principles between mobile and desktop devices

it was decided to define separate XAML views tailored to mobile devices. Such an

approach allowed to create a responsive UI optimized for different device families

while keeping the XAML code clean and simple.

As an example, listing 6.2 shows the UI definition for dashboard view that is

displayed on non-mobile devices. The resulting view can be seen on figure 6.1.

Listing 6.2: Client App Dashboard - UI Definition

<base:TopViewx:Class="SlickHubRemote.Views.Dashboard.DashboardView"...prism:ViewModelLocator.AutoWireViewModel="True">

<base:TopView.Transitions><TransitionCollection>

<NavigationThemeTransition><NavigationThemeTransition.DefaultNavigationTransitionInfo>

<DrillInNavigationTransitionInfo /></NavigationThemeTransition.DefaultNavigationTransitionInfo>

</NavigationThemeTransition></TransitionCollection>

</base:TopView.Transitions>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<controls:HamburgerMenu x:Name="HamburgerMenu"DisplayMode="CompactOverlay"

87

Page 96: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

PanePlacement="Left"Foreground="{StaticResource

AppThemeBaseMediumBrush}"PaneBackground="{StaticResource

AppThemeAltBaseHighBrush}"CompactPaneLength="48"OpenPaneLength="240"HamburgerHeight="48"ItemTemplate="{StaticResource

HamburgerMenuGlyphItemTemplate}"OptionsItemTemplate="{StaticResource

HamburgerMenuCommandGlyphItemTemplate}"Loaded="HamburgerMenu_OnLoaded"ItemClick="HamburgerMenu_OnItemClick">

<controls:HamburgerMenu.ItemsSource><controls:HamburgerMenuItemCollection>

<controls:HamburgerMenuGlyphItem Label="Home"Glyph="{StaticResource

HomeGlyph}"TargetPageType="

children:DashboardHomeChildView" />

<controls:HamburgerMenuGlyphItem Label="Accessories"Glyph="{StaticResource

DevicesGlyph}"TargetPageType="

children:DashboardAccessoriesChildView" />

</controls:HamburgerMenuItemCollection></controls:HamburgerMenu.ItemsSource>

<controls:HamburgerMenu.OptionsItemsSource><controls:HamburgerMenuItemCollection>

<menuItems:HamburgerMenuCommandGlyphItem Label="Settings"Glyph="{

StaticResourceSettingsGlyph}"

Command="{x:BindViewModel.GoToSettingsCommand}" />

<menuItems:HamburgerMenuCommandGlyphItem Label="Switch Hub"Glyph="{

StaticResourceSwitchGlyph}"

Command="{x:BindViewModel.GoToSwitchHubCommand}" />

<menuItems:HamburgerMenuCommandGlyphItem Label="Sign Out"Glyph="{

StaticResourceSwitchUserGlyph}"

Command="{x:BindViewModel.LogoutCommand}"/>

</controls:HamburgerMenuItemCollection></controls:HamburgerMenu.OptionsItemsSource>

88

Page 97: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

<controls:HamburgerMenu.Content>

<Frame x:Name="ChildViewFrame" />

</controls:HamburgerMenu.Content>

</controls:HamburgerMenu>

</Grid>

</base:TopView>

89

Page 98: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Figure 6.1: Client App Dashboard

90

Page 99: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Unlike the standard Page files (XAML and code-behind), the XAML views

are decorated with qualifier string to denote the device family to which the UI

definition contained in the XAML view applies. The qualifier string can be either

added to the XAML view file name or used as a name for the folder containing

the XAML view file. Following from these requirements, the XAML view files

containing UI definition for mobile device family were placed in a folder named

DeviceFamily-Mobile. Listing 6.3 shows the UI definition for dashboard view

tailored to mobile devices. The resulting dashboard view for mobile devices can

be seen on figure 6.2.

Listing 6.3: Client App Dashboard - UI Definition For Mobile Device Family

<base:TopViewx:Class="SlickHubRemote.Views.Dashboard.DashboardView"...prism:ViewModelLocator.AutoWireViewModel="True">

<base:TopView.Transitions><TransitionCollection>

<NavigationThemeTransition><NavigationThemeTransition.DefaultNavigationTransitionInfo>

<DrillInNavigationTransitionInfo /></NavigationThemeTransition.DefaultNavigationTransitionInfo>

</NavigationThemeTransition></TransitionCollection>

</base:TopView.Transitions>

<Pivot Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"HeaderTemplate="{StaticResource PivotHeaderGlyphItemTemplate}">

<PivotItem>

<PivotItem.Header><headerItems:PivotHeaderGlyphItem Label="Home" Glyph="{

StaticResource HomeGlyph}" /></PivotItem.Header>

<components:DashboardHomeComponentView base:ViewBase.ViewModel="{x:Bind ViewModel.DashboardHomeComponent}" />

</PivotItem>

<PivotItem>

<PivotItem.Header><headerItems:PivotHeaderGlyphItem Label="Accessories" Glyph="{

StaticResource DevicesGlyph}" /></PivotItem.Header>

<components:DashboardAccessoriesComponentView base:ViewBase.ViewModel="{x:Bind ViewModel.DashboardAccessoriesComponent}" />

91

Page 100: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

</PivotItem>

</Pivot>

<base:TopView.BottomAppBar><CommandBar Foreground="{StaticResource AppThemeBaseMediumBrush}"

Background="{StaticResource AppThemeAltBaseHighBrush}"><CommandBar.SecondaryCommands>

<AppBarButton Label="Settings"Command="{x:Bind ViewModel.GoToSettingsCommand}"Foreground="{StaticResource AppThemeBaseMediumBrush

}" /><AppBarButton Label="Switch Hub"

Command="{x:Bind ViewModel.GoToSwitchHubCommand}"Foreground="{StaticResource AppThemeBaseMediumBrush

}" /><AppBarButton Label="Sign Out"

Command="{x:Bind ViewModel.LogoutCommand}"Foreground="{StaticResource AppThemeBaseMediumBrush

}" /></CommandBar.SecondaryCommands>

</CommandBar></base:TopView.BottomAppBar>

</base:TopView>

Figure 6.2: Client App Dashboard Tailored To Mobile Devices

92

Page 101: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

6.2 Communication With Backend Service

To enable Windows and Xamarin client apps to access the Azure Mobile Apps

backend service, Microsoft has released a managed client library. The library is

distributed as Microsoft.Azure.Mobile.Client NuGet package and it

provides a MobileServiceClient class that enables access to various backend ser-

vice resources, including authentication endpoints 1, custom endpoints, and push

notifications. To ensure compatibility with dependency injection mechanisms, the

library also provides an IMobileServiceClient interface that describes the methods

and properties implemented by MobileServiceClient class. In this way, the client

object can be initialized during the application startup and registered with IoC

container, thus allowing it to be reused by all components that require an access

to the backend service.

Listing 6.4: Initialization of MobileServiceClient Object

public sealed partial class App : PrismUnityApplication{

...

protected override void ConfigureContainer(){

base.ConfigureContainer();

RegisterServices();RegisterComponents();

}

...

private void RegisterServices(){

var mobileService = new MobileServiceClient(new Uri(@"https://slickhub.azurewebsites.net/", UriKind.Absolute));

Container.RegisterInstance<IMobileServiceClient>(mobileService, newContainerControlledLifetimeManager());

...}

...}

1The client app authentication is covered in chapter 2.

93

Page 102: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

As can be seen in listing 6.4, an instance of the MobileServiceClient class (a

client object) is initialized with the mobile service URL. The initialized client ob-

ject exposes several InvokeApiAsync method overloads, which can be used to call a

custom REST API. The overloads were implemented to run various requests, thus

the InvokeApiAsync method allows to specify the endpoint path, HTTP method,

optional request body and request headers, as well as optional query string param-

eters. Such a method implementation provides a thorough dose of flexibility at the

expense of lower maintainability. To overcome this issue, it was decided to intro-

duce an additional abstraction layer between application code and backend API

calls by creating a service that encapsulates the InvokeApiAsync method calls. The

service hides the request-specific information and exposes a simple interface that

allows to work with well-defined set of data types.

Listing 6.5: REST API Client Service

public class SlickHubClientService : ISlickHubClientService{

...

public async Task<AccessoryDescriptionResponse<TDescription>>GetAccessoryDescription<TDescription>(AccessoryDescriptionRequest request) where TDescription : class

{if (request == null){

throw new ArgumentNullException(nameof(request));}

var queryParams = MobileServiceClient.GetApiQueryParameters();

var json = await MobileServiceClient.InvokeApiAsync($"v1/accessories/{request.AccessoryId}", HttpMethod.Get, queryParams);

return json?.ToObject<AccessoryDescriptionResponse<TDescription>>();}

public async Task PostDeviceCommandAsync(CommandRequest request){

if (request == null){

throw new ArgumentNullException(nameof(request));}

var json = JObject.FromObject(request);

await MobileServiceClient.InvokeApiAsync($"v1/devices/commands", json);}

94

Page 103: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

...}

The SlickHubClientService class is registered with the IoC container and in-

jected into all view models that require a communication with the backend ser-

vice. As an example, the SmartBulbSettingsComponentViewModel class uses the

injected instance of SlickHubClientService to send a command informing about

the change in light intensity of a smart bulb. It is worth noting that the meth-

ods specified by the ISlickHubClientService interface do not require the caller to

specify the endpoint path and HTTP method to be used - it is enough to pass an

instance of the request object containing the data to be sent.

Listing 6.6: Sending Led Light Command

public class SmartBulbSettingsComponentViewModel :AccessorySettingsComponentViewModelBase

{...

public SmartBulbSettingsComponentViewModel(ISlickHubClientServiceslickHubClientService, LedLightDescription description)

: base(slickHubClientService){

// Initialize bindable propertiesIntensity = _intensityValue = description?.Intensity * 100 ?? 0d;

}

...

private async void SendLightIntensityCommand(){

if (AccessoryId == Guid.Empty) return;

var request = new CommandRequest{

AccessoryId = AccessoryId,Command = new LedLightCommand{

Description = new LedLightDescription(Intensity * 0.01)}.ToString()

};

await SlickHubClientService.PostDeviceCommandAsync(request);}

...}

95

Page 104: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

6.3 Push Notification Channel

As explained in chapter 3, the telemetry data collected by the IoT gateway are

transmitted to the client app using push notifications. The UWP app can receive

push notifications by means of the notification channel URI issued by the Win-

dows Push Notification Service (WNS) [21]. The WNS is the notification ser-

vice for Windows devices, which generates and manages the channel URIs used

to uniquely identify the registered users. The application requests a notification

channel by calling a CreatePushNotificationChannelForApplicationAsync static

method provided by the PushNotificationChannelManager class. The obtained

channel can then be registered with Azure Notification Hub service by retrieving

a push object from the MobileServiceClient instance and calling the RegisterAsync

method on that object. The registered channel URI is then used by the Azure No-

tification Hub service to send an HTTP POST request containing the notification

payload, which in turn will be delivered to the client app via WNS. Since the

backend service uses a user ID tag to send targeted push notifications (see chapter

3), the application must ensure that the channel URI is registered after the user au-

thentication process is complete in order for this tag to be included in the channel

registration metadata.

Listing 6.7: Requesting & Registering Push Notification Channel URI

public sealed class PushNotificationService : IPushNotificationService{

...

public async Task<PushNotificationChannel> RequestNotificationChannelAsync(){

PushNotificationChannel channel = null;

var retryCount = 3;

do{

try{

channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

96

Page 105: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

break;}catch (Exception){

// Could not create a channel. Use 10-second delay between eachunsuccessful attempt.

await Task.Delay(RetryDelay);}

} while (--retryCount > 0);

if (channel != null){

await MobileServiceClient.GetPush().RegisterAsync(channel.Uri);}

return channel;}

...}

The logic responsible for requesting and registering push notification chan-

nel URI has been extracted into a PushNotificationService class, which serves as

a service that can be injected into other application components. The PushNo-

tificationService class exposes a RequestNotificationChannelAsync asynchronous

method that returns a notification channel object. The callers of this method can

use the returned notification channel object to subscribe to a notification delivery

event and intercept the push notifications while the app is running.

Listing 6.8: Receiving Push Notifications Through Notification Delivery Event

public sealed class DashboardViewModel : ViewModelBase{

...

private async Task RegisterPushNotificationHandlerAsync(){

if (PushNotificationService == null) return;

try{

channel = await PushNotificationService.RequestNotificationChannelAsync();

if (channel != null){

channel.PushNotificationReceived += OnPushNotification;}

}catch (Exception){

// ignore}

97

Page 106: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

}

...

private async void OnPushNotification(PushNotificationChannel sender,PushNotificationReceivedEventArgs e)

{if (e.NotificationType == PushNotificationType.Raw && e.RawNotification

!= null){

try{

var payload = NotificationPayload.CreateFromJson(e.RawNotification.Content);

var data = TelemetryData.LoadFromNotificationPayload<AtmosphereTelemetryData>(payload);

if (data != null){

await Execute.OnUIThreadAsync(() =>{

DashboardHomeComponent.UpdateAtmosphereReadings(data);});

ApplicationData.Current.LocalSettings.Values[Constants.UserHubDataLSK] = e.RawNotification.Content;

}}catch (Exception){

// ignored}

}

e.Cancel = true;}

...}

The DashboardViewModel class subscribes to the notification delivery event

after the user navigates to the application dashboard screen. The OnPushNotifica-

tion event handler processes the received notifications by deserializing a notifica-

tion payload into telemetry data, which is then displayed on the dashboard Home

tab. It is important to note that the notification delivery event only allows to inter-

cept the push notifications while the app is running in the foreground. However,

because the platform uses raw notifications to send telemetry data, the background

running app can still receive those notifications by registering a background task

that gets triggered whenever a new raw notification arrives.

98

Page 107: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Listing 6.9: Receiving Push Notifications Through Background Task

public sealed class PushNotificationTask : IBackgroundTask{

...

public void Run(IBackgroundTaskInstance taskInstance){

deferral = taskInstance.GetDeferral();

var notification = (RawNotification) taskInstance.TriggerDetails;

if (!string.IsNullOrEmpty(notification.Content)){

ApplicationData.Current.LocalSettings.Values[Constants.UserHubDataLSK] = notification.Content;

}

deferral.Complete();}

...}

The PushNotificationTask class implements an IBackgroundTask interface, which

provides a Run method. The Run method is an entry point to the background task,

thus it must be implemented by all tasks that are to be registered with the system.

The discussed implementation of the Run method saves the notification payload

in the local application settings, so that the next time the app is launched the user

is presented with the most up to date telemetry data. In order for a PushNotifi-

cationTask background task to be invoked in response to the receipt of the raw

notification, the background task was registered with a PushNotificationTrigger

task event trigger.

Listing 6.10: Background Task Registration

public sealed partial class App : PrismUnityApplication{

...

private async Task RegisterBackgroundTasksAsync(){

if (BackgroundTaskService == null){

Logger.Log("Failed to register background tasks", Category.Warn,Priority.High);

return;}

var status = await BackgroundExecutionManager.RequestAccessAsync();

99

Page 108: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

// Ensure that app has been granted lock screen accessif (status != BackgroundAccessStatus.DeniedByUser && status !=

BackgroundAccessStatus.DeniedBySystemPolicy){

var pushTrigger = new PushNotificationTrigger();

BackgroundTaskService.RegisterBackgroundTask<PushNotificationTask>(pushTrigger);

}}

...}

100

Page 109: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Conclusions

The project discussed in this thesis addressed the problems related to security and

interoperability in IoT solutions. It has been presented how the selected Azure

cloud services can be connected together to form a scalable IoT platform that

provides secure and reliable communication between IoT accessories, gateways,

and client application. The main focus has been put on the choice of messaging

protocols, the authentication mechanisms, as well as the device and user iden-

tity management. In addition, the thesis stressed the importance of architectural

design in software engineering by showing the practical implications of various

design patterns and their positive impact on maintainability and extensibility of

the code.

6.4 Limitations

Even though the main project goals have been achieved, there still exist areas

for continued development. In the discussed implementation it has been shown

how the real-time telemetry data is sent from the IoT gateway device to the client

application. However, the presented solution does not include a mechanism for

communicating the connection status of the BLE accessories. The implementa-

tion of such a mechanism requires modifications in all parts of the platform, but

the general implementation scheme is identical to the implementation of telemetry

data mechanism. The discussed solution is also lacking the IoT gateway activa-

101

Page 110: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

tion mechanism. The backend API exposes the endpoint for provisioning the IoT

gateway device, but there is no way for the gateway to authenticate itself to the

backend service in order to use that endpoint. The authentication issue could be

resolved by transferring the user credentials from the client application to the IoT

gateway via BLE connection. Unfortunately, at the time of project implementa-

tion, the Bluetooth API for UWP apps did not support GATT Server role, and

therefore it was impossible to complete the implementation of activation mecha-

nism within the timeframe available.

6.5 Future Work

Apart from the aforementioned limitations of the presented implementation, the

discussed project has a great potential for further improvements. One of the ideas

is to use the Azure Cognitive Services in order to extend the client application

with a speech recognition feature, that would enable the IoT gateway to be con-

trolled with voice commands. The client application could also be improved by

adding the feature that would enable the user to manage multiple IoT gateways

and to share the selected IoT gateways with other users. It is worth noting that

this feature is already partially supported by the backend service, thus the imple-

mentation would mainly involve changes in the client application code.

The discussed project could also be used as a foundation for researching the pos-

sibility of remote management of GATT profiles with the idea that compatibility

with unknown BLE devices will be added without making any changes to the

IoT gateway app. The proposed research could involve the comparison of BLE

with other wireless communication protocols such as ZigBee or Z-Wave, and the

discussion on interoperability that can be achieved with a use of each of the pro-

tocols.

102

Page 111: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

Bibliography

[1] Introduction to bluetooth low energy. https://learn.adafruit.com/introduction-to-bluetooth-low-energy, 2014.

[2] Introducing the adafruit bluefruit le uart friend. https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-uart-friend,2015.

[3] Am2303 product manual. http://akizukidenshi.com/download/ds/aosong/AM2302.pdf, 2013.

[4] Hm bluetooth module datasheet. http://fab.cba.mit.edu/classes/863.15/doc/tutorials/programming/bluetooth/bluetooth40_en.pdf, 2014.

[5] Bmp180 digital pressure sensor. https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf,2015.

[6] E. D. Hardt. The OAuth 2.0 Authorization Framework. RFC 6749, Internet Engi-neering Task Force (IETF), October 2012.

[7] Understanding user ids. https://github.com/Azure/azure-mobile-apps-net-server/wiki/Understanding-User-Ids, 2016.

[8] Authentication and authorization in azure app service. https://github.com/Microsoft/azure-docs/blob/master/articles/app-service/app-service-authentication-overview.md, 2017.

[9] Add authentication to your windows app. https://docs.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-windows-store-dotnet-get-started-users,2016.

[10] How to configure your app service application to use facebook login. https://docs.microsoft.com/en-us/azure/app-service-mobile/

103

Page 112: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

app-service-mobile-how-to-configure-facebook-authentication,2016.

[11] How to configure your app service application to use google login. https://docs.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-how-to-configure-google-authentication,2016.

[12] How to configure your app service application to use twitter login. https://docs.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-how-to-configure-twitter-authentication,2016.

[13] Reference - iot hub query language for device twins and jobs.https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-query-language, 2016.

[14] Service bus quotas. https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-quotas, 2016.

[15] Azure notification hubs. https://docs.microsoft.com/en-us/azure/notification-hubs/notification-hubs-push-notification-overview, 2017.

[16] Control access to iot hub. https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-security, 2017.

[17] Create an azure sql database in the azure portal. https://docs.microsoft.com/en-us/azure/sql-database/sql-database-get-started-portal, 2017.

[18] Reference - iot hub endpoints. https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-endpoints, 2017.

[19] Storage queues and service bus queues - compared and contrasted. https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-azure-and-service-bus-queues-compared-contrasted,2017.

[20] Understand identity registry in your iot hub. https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-identity-registry, 2017.

[21] Windows push notification services (wns) overview. https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-windows-push-notification-services--wns--overview,2017.

104

Page 113: Cloud-based IoT platformmokkas/files/Michal_Gutowski _s10894_BSc... · Having selected Microsoft Azure as a cloud service provider, it was possible to move on to designing the cloud

[22] Advanced message queuing protocol (amqp) claims-based security.http://docs.oasis-open.org/amqp/amqp-cbs/v1.0/csd01/amqp-cbs-v1.0-csd01.doc, 2013.

[23] Prism. https://github.com/PrismLibrary/Prism, 2015.

[24] U. Shaked. Reverse engineering a bluetoothlightbulb. https://medium.com/@urish/reverse-engineering-a-bluetooth-lightbulb-56580fcb7546,2016.

105