During Connect(); 2017 event this year we presented beautiful app demos using Xamarin and many features of Azure. For //build/ 2018's keynote, we updated some components of the back-end API code to support Azure Kubernetes Service (AKS). This repository contains the setup instructions and sample code needed for the Internet of Things (IoT) Demo utilizing Digital Twins that was announced at Ignite 2018.
For this reference app scenario, we built several consumer and line-of-business apps and an Azure backend. You can find all SmartHotel360 repos in the following locations:
Welcome to the SmartHotel360 IoT repository. Here you'll find everything you need to run the website and backend for the IoT demo.
Check out our Channel9 IoT Show Video about the SmartHotel360 Demo Powered by Digital Twnis:
We have deployed a public environment to show the end result of the website connected to the Digital Twin Solution. Please notice the sliders control will be disabled because we are using the basic authentication mode.
- Website: https://aka.ms/smarthotel360-FacilityManagement
- Username: admin
- Password: admin
SmartHotel360 uses a microservice oriented architecture implemented using containers. For the IoT Demo, there are various services developed in different technologies: .NET Core 2, ASP.NET Core 2, and Angular. These services use different Azure Resources like Digital Twins, App Services, Cosmos DB, Event Hubs, Azure Functions, and IoT Hubs to name a few. The step by step walkthrough for creating and provisioning the demo can be found next in the Setup section.
End-to-end setup takes about an hour provided you have all of the development environment prerequisites met AND that your user has the required permissions in your Azure subscription.
You can find a demo scripts with a walkthroughs once you have finished the setup of this demo.
- Powershell for running provisioning Azure provisioning scripts. Powershell Core is available for Mac and Linux users.
- Docker to build the containers.
- Visual Studio 2017 with the
.NET desktop development
andASP.NET and web development
workloads installed. - Azure CLI
- Kubernetes CLI
- Angular CLI
- You also will need the Azure IoT Extension for Azure CLI. You can install it with the following command:
az extension add -n azure-cli-iot-ext
Note: We have updated the deployment script to work with version 0.7.0 or higher.
- Required Azure Subscription Permissions
- Create and modify Azure AD Application Registrations or have someone else do it for you
- Create a new Service Principal for Role Based Access Control (RBAC) or have someone else do it for you
- Create or add 2 new guest users to the Active Directory (AD) or have someone else do it for you and get you the Object Ids of those users
- Create a ResourceGroup or have one that someone else already created for you to use
- Create a deployment into a ResourceGroup
- Give the Service Principal in #2 read permissions to read from the ACR created by the deployment (if not, then script provides the user with an Azure Cli command to execute to be run by someone with the required permission, and pauses until the user says this step has been completed)
Follow these instructions to create a service principal and register an Azure Active Directory application.
- Choose
Web app / API
as the Application Type
During the creation process you will need to take note of the following information:
- Tenant Id
- App Id
- App Key
To obtain the service principal Id, open a Powershell window and follow these steps:
Login-AzureRmAccount -SubscriptionId {subcription id}
Get-AzureRmADServicePrincipal -ApplicationId {app Id}
- If
AzureRM
is not installed you will receive errors saying that it needs to be installed. Run the following command in an Administrator Powershell:Install-Module -Force AzureRM
Click settings --> Required Permissions
- Digital Twins API
- Click
Add
on the top left - Under select an API, type
Azure
, then chooseAzure Digital Twins (Azure Smart Spaces Service)
- NOTE: If this option does NOT show, you may need to register the Digital Twins resource provider using the following steps in a Powershell window:
Login-AzureRmAccount -SubscriptionId {subcription id}
Register-AzureRmResourceProvider -ProviderNamespace 'Microsoft.IoTSpaces'
- Wait until the provider registration is complete, can be checked via:
Get-AzureRmResourceProvider -ProviderNamespace 'Microsoft.IoTSpaces'
- NOTE: If this option does NOT show, you may need to register the Digital Twins resource provider using the following steps in a Powershell window:
- Check the Read/Write Access delegated permissions box
- Save
- Click
- Time Series Insights API
- Click
Add
on the top left - Under select an API, type
Azure
, then chooseAzure Time Series Insights
- NOTE: If this option does NOT show, you may need to register the Time Series Insights resource provider using the following steps in a Powershell window:
Login-AzureRmAccount -SubscriptionId {subcription id}
Register-AzureRmResourceProvider -ProviderNamespace 'Microsoft.TimeSeriesInsights'
- Wait until the provider registration is complete, can be checked via:
Get-AzureRmResourceProvider -ProviderNamespace 'Microsoft.TimeSeriesInsights'
- NOTE: If this option does NOT show, you may need to register the Time Series Insights resource provider using the following steps in a Powershell window:
- Check the Access Azure Time Series Insights service delegated permissions box
- Save
- Click
- Click
Grant Permissions
(right next to the Add button).
To create a service principal for an AKS Cluster, open a Powershell/Command Prompt/Bash window and follow these steps:
az login
az account set -s {subscription id}
az ad sp create-for-rbac --skip-assignment
The sp create-for-rbac
command will return a json object that will have the information needed later in this process.
{
"appId": "{aks app id}",
"displayName": "{aks display name}",
"name": "{aks uri}",
"password": "{aks service principal password}",
"tenant": "{aks tenant id}"
}
You need to create users having access to your AAD. These can either be users created in your AAD or guest users that you add. For all of these users, you need to collect the Object Id for them and update /Source/ARM/UserAADObjectIds.json
with those values.
- To get the Object Id, view the user in AAD and you will see Object ID under the Identity Section. This is a similar process to using the Admin Center of a subscription backed by an Office 365 environment.
- The following users are required for this demo:
- Head of Operations: This user is able to view all the Hotel Brands and below.
- Hotel Brand 1 Manager: This user is able to view all the Hotels under the first Brand.
- Hotel 1 Manager: This user is able to view all the Floors under the first Hotel.
- Hotel 1 Employee: This user is able to view Non-VIP Floors under the first Hotel.
- The following users are optional. They help provide more visibility into the Role Based Access Control (RBAC) functionality of Digital Twins.
- Hotel Brand 2 Manager
- Hotel 2 Manager
- Hotel 3 Manager
- Hotel 4 Manager
- Hotel 5 Manager
- Hotel 6 Manager
- Hotel 7 Manager
- Hotel 8 Manager
- Hotel 9 Manager
- Hotel 10 Manager
In /Source/ARM/
folder of this repository is the deployment script to create and stand up all of the resources to run this demo in Azure. To execute the deployment script, run the following in a Powershell window:
.\deploy.ps1 -subscriptionId {subscription id} -resourceGroupName {resource group name} -resourceGroupLocation {resource group location} -clientId {app id} -clientSecret {app key} -clientServicePrincipalId {service principal id} -aksServicePrincipalId {AKS Service Principal App Id} -aksServicePrincipalKey {AKS Service Principal password}
The following information parameters are required for the deployment script:
{subscription id}
: the Azure subscription id that has been used in this setup{resource group name}
: the resource group name to add the created resource, if it doesn't exist it will be created{resource group location}
: location for the resource group: (ie. 'westus2'){app id}
: app id obtained from creating an AAD app{app key}
: app key obtained from creating an AAD app{service principal id}
: service principal id from above{AKS service principal app id}
: AKS app id from above{AKS service principal password}
: AKS service principal password from above
There is a collection of parameters that are used by the deployment script that determine properties like resource location, pricing tiers, and naming. If you wish to modify any of these parameters you can edit the values in parameters.json.
NOTE: In order to support the number of virtual devices required for the demo in the Kubernetes cluster, it will deploy 3 nodes. Please be aware that this can be a large cost.
The Resource Group should look like this:
Note: Due the amount of resources of this demo the consumption of Azure is around $200 approximately per month with three nodes on the AKS cluster. Depending on the Azure region with the default paramenters.
This demo only creates active devices in 1 hotel (SmartHotel360 -> SH360 Elite 1) to reduce the deployment time as well as cost in Azure.
If you want to have devices active in every hotel you will need to add the following parameters when executing the deployment script:
{digitalTwinsProvisioningTemplateFilePath}
: This should be set to"DigitalTwinsProvisioning-Full/SmartHotel_Site_Provisioning.yaml"
- This template ensures that the Digital Twins provisioning and the IoT Hub device creation have devices in every single room.
{numberOfAksNodes}
: This should be set to10
- The number of virtual devices running in the kubernetes cluster increases by 4 times for the full data, and therefore the number of nodes running all those pods needs to increase.
NOTE: The full deployment can take well over an hour.
If you choose to modify any of the provisioning by increasing the number of rooms that are included in a floor, a new floorplan (found in /Source/ARM/Images/floorplans
) file will be required. Otherwise any new rooms will most likely not be displayed or accessible in the floorplan view. Make sure to mimic the svg structure and id naming to ensure the website functions properly.
When the deployment script is complete, it will output a userSettings.json
file with information needed for the rest of the deployment.
{
"tenantId": "{tenant id}",
"clientId": "{client id}",
"aadReplyUrl": "{facility management web reply uri for ADAL}",
"digitalTwinsManagementEndpoint": "{digital twins management endpoint}",
"digitalTwinsManagementApiEndpoint": "{digital twins management api endpoint}",
"facilityManagementWebsiteUri": "url to the facility management website",
"facilityManagementApiUri": "{facility management api}",
"facilityManagementApiEndpoint": "{facility management api endpoint}",
"storageConnectionString": "{connection string to azure storage account}",
"eventHubConsumerConnectionString": "{consumer connection string to the event hub}",
"iotHubConnectionString": "{connection string to the iot hub}",
"cosmosDbConnectionString": "{connection string to the cosmos db}",
"azureMapsKey": "{auth key to connect to the Azure Maps resource}",
"roomDevicesApiEndpoint": "{room devices api endpoint - needed for running the Xamarin Mobile Clients}",
"demoRoomSpaceId": "{space id of the room needed for running demos using the Xamarin Mobile Clients}",
"demoRoomKubernetesDeployment": "{name of the demo room kubernetes deployment}",
"deviceRelayFunctionEndpoint": "{uri of the device azure function}",
"deviceRelayFunctionKey": "{default key of the device azure function}"
}
NOTE: If you are going to run the IoT Demo for the Xamarin Mobile Apps, then you will need the roomDevicesApiEndpoint
and mobileRoomSpaceId
values from the userSettings.json
file.
IMPORTANT: Anytime you re-run deploy.ps1
, make sure to revert the following files first, otherwise they will not be updated properly:
Source/Backend/SmartHotel.PhysicalDevices/SmartHotel.PhysicalDevices.MXChip/Device/config.h
Source/FacilityManagementWebsite/SmartHotel.FacilityManagementWeb/SmartHotel.FacilityManagementWeb/ClientApp/src/environments/environment.ts
Source/FacilityManagementWebsite/SmartHotel.FacilityManagementWeb/SmartHotel.FacilityManagementWeb/ClientApp/src/environments/environment.prod.ts
You will need to give the Azure AD Application you created earlier access to the Time Series Insights environment for the charts to work.
- Upon completion of the deployment, navigate to the Time Series Insights environment that was created in the portal. It's name should be something like:
sh360iot-Tsi-*
. - Select
Data Access Policies
from the left side menu. - Click
Add
from the top left - Under
Select user
enter theclientId
value from the userSettings.json file from the User Settings into the search box, and then choose the AD Application when it shows up. - Under
Select role
checkReader
ANDContributor
- Click OK
At the writing of this we were unable to get the ARM template deployment to create this data access policy successfully, thus requiring the manual step.
To verify that everything is working correctly, open up the facilityManagementWebsiteUri
(from the userSettings.json
in the browser and log in with one of the two users created during the provisioning steps.
By default, the chart in the website will show data for the last day. If you wish to see more days back from today, you can update the Application Settings to have an additional field (tsiHowManyDays
) and enter an integer greater than 1.
- Keep in mind that the more days you show, the more information will be shown on the map and the worse it may look.
Portions of this demo can be run locally. In order to do so, you still must complete the Setup section. Once you have completed the provisioning, you can follow these steps to configure, build, and deploy the resource locally.
The Sensor Data function can run locally in Visual Studio. However, in order to avoid conflicts, you must first disable the Azure Function that was created during Setup.
- Log in to the Azure Portal.
- Navigate to Function Apps and select the Azure Function that was created during Setup.
- Click the Stop button to disable the Azure Function.
- Open the
/Source/Backend/SmartHotel.Services/SmartHotel.Services.sln
solution in Visual Studio 2017 - Set the
SmartHotel.Services.SensorDataFunction
project as the startup project - Right-click the
SmartHotel.Services.SensorDataFunction
project in the Solution Explorer - Add a new json file named:
local.settings.json
and set the contents to this:{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "{storage connection string}", "AzureWebJobsDashboard": "{storage connection string}", "FUNCTIONS_WORKER_RUNTIME": "dotnet", "EventHubConnectionString": "{event hub consumer connection string}", "CosmosDBConnectionString": "{cosmos db connection string}", } }
- {storage connection string}:
storageConnectionString
from the userSettings.json file from the User Settings section - {event hub consumer connection string}:
eventHubConsumerConnectionString
from the userSettings.json file from the User Settings section - {cosmos db connection string}:
cosmosDbConnectionString
from the userSettings.json file from the User Settings section
- {storage connection string}:
- Run in debug mode.
While running the devices locally, we need to remove the instances that exist in the Kubernetes cluster. Run the following steps from a Powershell/Command Prompt/Bash window:
kubectl delete pods,deployments,replicasets --all
- this removes ALL pods from the cluster, including the Room Devices Api pod.- If NOT running the Room Devices Api locally, then re-deploy that pod to the cluster:
- Change directory to
/Source/Backend/SmartHotel.Services
kubectl apply -f deployments.demo.yaml
- Change directory to
To redeploy the devices to the cluster:
- Change directory to
/Source/Backend/SmartHotel.Devices
kubectl apply -f deployments.demo.yaml
The Apis can be run locally at the same time as their Azure counterparts.
From a Powershell/Command Prompt/Bash window
- Change directory to
/Source/Backend/SmartHotel.Services
docker-compose build
- only required if you're making changes and want to see them.docker-compose -f docker-compose.yml -f docker-compose.override.yml up
- Open the
/Source/Backend/SmartHotel.Services/SmartHotel.Services.sln
solution in Visual Studio 2017 - Select either the
SmartHotel.Services.FacilityManagement
orSmartHotel.Services.FacilityManagement
project as the startup project - Update the
appsettings.json
file.- SmartHotel.Services.FacilityManagement:
- ManagementApiUrl:
digitalTwinsManagementEndpoint
from the userSettings.json file from the User Settings section - MongoDBConnectionString:
cosmosDbConnectionString
from the userSettings.json file from the User Settings section
- ManagementApiUrl:
- SmartHotel.Services.RoomDevicesApi:
- IoTHubConnectionString:
iotHubConnectionString
from the userSettings.json file from the User Settings section - DatabaseConnectionString:
cosmosDbConnectionString
from the userSettings.json file from the User Settings section
- IoTHubConnectionString:
- SmartHotel.Services.FacilityManagement:
- Run in debug mode.
The Website can be run locally at the same time as its Azure counterpart.
-
Open the
/Source/FacilityManagementWebsite/SmartHotel.FacilityManagementWeb/SmartHotel.FacilityManagementWeb.sln
solution in Visual Studio 2017 -
If you desire the website to connect to the Facility Management API in Azure, then run in debug mode.
-
Otherwise, update the
environment.ts
andenvironment.prod.ts
files under/SmartHotel.FacilityManagementWeb/ClientApp/src/environments
:export const environment = { production: true, version: 'Production', sensorDataTimer: {sensorDataTime}, adalConfig: { tenant: '{tenantId}', clientId: '{clientId}', endpoints: { '{apiUri}': '{clientId}' } } as adal.Config, apiEndpoint: '{apiEndpoint}', resourceId: '0b07f429-9f4b-4714-9392-cc5e8e80c8b0' };
- {apiUri}: Must be updated to point to wherever your local Facility Management Api is running (e.g.
http://localhost:3000
) - {apiEndpoint}: Must be updated to point to wherever your local Facility Management Api is running, but append
/api
(e.g.http://localhost:3000/api
)
- {apiUri}: Must be updated to point to wherever your local Facility Management Api is running (e.g.
-
Then run in debug mode.
In order to run a physical device, we need to remove the virtual device that exists in the Kubernetes cluster, otherwise they will be sending conflicting messages to Digital Twins. Run the following steps from a Powershell/Command Prompt/Bash window:
kubectl delete deployments {deploymentname}
- Replace
{deploymentname}
with thedemoRoomKubernetesDeployment
value from the User Settings section - this removes the pod running the virtual device from the cluster.
- Replace
To redeploy the virtual device pod to the cluster when done with the physical device:
- Change directory to
/Source/Backend/SmartHotel.Devices
kubectl apply -f deployments.demo.yaml
- This will attempt to deploy all the virtual devices. Since we only removed the one deployment, it will show as created and the rest will show as unchanged.
To set up an MXChip as one of our room devices, follow the instructions from Get Started with MXChip IoT DevKit. IMPORTANT - make sure the device is NOT connected via USB when installing the Arduino IDE
and ST-Link driver
, otherwise you may need to repeat the process for VS Code to see the device.
- Skip the instructions in the Open IoT Workbench Examples section. Instead, open the Project workspace in VS Code.
- Also, note that in the Provision Azure service section, you should select your IoT hub and the device named in the
demoIoTHubDeviceId
value from the User Settings section. - The instructions from the Serial monitor usage section and beyond can be ignored.
- Once the sketch code is successfully deployed to the MXChip, it will automatically run anytime it is powered.
Note: If you receive a fatal error stating that a header file (a .h file) could not be found simply try again.
For this demo we are utilizing a number of the built in sensors/components of the device.
-
Temperature
- The built-in temperature sensor is used to determine the current temperature.
- The current and desired temperature values are shown on the display.
-
Occupancy
- The integrated magnetometer, is being utilized to demonstrate the ability to detect the room occupancy. It is mimicking the idea that we could detect the opening and closing of a door with a magnet on it. In order to toggle the occupancy status of the room, simply bring a strong magnet (a small rare-earth magnet works well) near the sensor at the bottom center of the MXChip board. The last line on the display will toggle between
Vacant
andOccupied
each time the magnet is brought near the sensor. - In case the magnetometer is not working properly, pressing and releasing button A will provide the same toggle effect.
- The integrated magnetometer, is being utilized to demonstrate the ability to detect the room occupancy. It is mimicking the idea that we could detect the opening and closing of a door with a magnet on it. In order to toggle the occupancy status of the room, simply bring a strong magnet (a small rare-earth magnet works well) near the sensor at the bottom center of the MXChip board. The last line on the display will toggle between
-
Light
- The color of RGB LED indicates what the current setting of the room's light is.
- 0%-30%:
Blue
- 31%-65%:
Green
- 66%-100%:
Red
- 0%-30%:
- The current and desired light percentage values are shown on the display.
- The color of RGB LED indicates what the current setting of the room's light is.
-
The MXChip will only send messages when there is a change in the sensor data, but minor fluctuations in temperature can result in frequent messages.
- Stop Sending Messages - you can use the Azure Portal to invoke the
StopDeviceFeed
method on the device. The last line of the MXChip's display will then displayIdle
, indicating that no data is being sent. - Start Sending Messages - either reboot the MXChip, or invoke the
StartDeviceFeed
method.
- Stop Sending Messages - you can use the Azure Portal to invoke the
Below is diagram showing how the MXChip integrates into the existing architecture. NOTE: The Iot Hub, Azure Function and Digital Twins are the same as displayed in the main architecture diagram.
The Facility Management website and api both support being downgraded from using ADAL to a very simple basic authentication. This mode is read-only, meaning sliders are not available on the rooms to change the desired temperature and light values.
NOTE: This mode is NOT recommended, unless absolutely desired.
The following Application Settings must be supplied (in addition to the ones that are supplied via the deployment). Once set, the Api will downgrade to basic auth.
BasicAuth__Username
: whatever username you desire. This will be the username that MUST be supplied when logging into the website.BasicAuth__Password
: whatever password you desire. This will be the password that MUST be supplied when logging into the website.
To verify this change is working, navigate to the facilityManagementApiUri
(from the userSettings.json file from the User Settings section) and add /swagger
to the end. In the Swagger UI, click the Authorize
button that will show in the top-right corner and the dialog that pops up should say Basic authorization
.
The following Application Settings must be supplied (in addition to the ones that are supplied via the deployment). Once set, the Website will downgrade to basic auth.
useBasicAuth
:true
To verify this change is working, navigate to the facilityManagementWebsiteUri
(from the userSettings.json file from the User Settings section) and you will see fields to enter a username and password to login.
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.