Building Comfort

Installing the Building Comfort sample application on self-hosted Drasi

Prerequisites

Overview of the app

This application illustrates the use of Drasi for a hypothetical building management scenario, including:

  • The use of Continuous Queries over a Cosmos Gremlin database.
  • Continuous Queries that include aggregations across hierarchical graph data.
  • The use of the Gremlin Reaction to update a Gremlin database based on the output of a Continuous Query.
  • The use of the SignalR Reaction to integrate Continuous Query output with a React JS Application.

In this sample, Continuous Queries are used to calculate a comfort level metric for building management. This is a human-centric measurement that combines the physical measurements in a room such as temperature, humidity, and CO2 levels into a perceptual rating of its comfort. For the purposes of this sample, the comfort level will be calculated dynamically for a room from the physical measurements using the simplified formula:

comfortLevel = trunc(50+(temp-72) + (humidity-42) + if( CO2 > 500,(CO2 - 500)/25,0)) 

A range of 40 to 50 is considered acceptable: a value below 40 indicates that temperature and/or humidity is too low, while a value above 50 indicates that temperature, humidity, and/or CO2 levels are too high.

The app will provide a dashboard frontend to visualize the comfort levels of rooms and floors, as well as a way to change the environment measurements in the database to simulate changes in the building environment. The dashboard will also show alerts for rooms, floors, and the building when the comfort level is out of range, where the aggregated comfort levels for the floors and building are calculated from the average comfort levels of the rooms and floors respectively by Reactions.

App Architecture

Architecture

This app consists of:

  • A Source getting changes to building environment data from Cosmos DB.
  • Several Continuous Queries that calculate comfort levels and alerts for the rooms, as well as aggregate values for the floors and building as a whole.
  • A Gremlin Reaction that updates the Cosmos DB database with the calculated comfort levels and aggregate values based on changes in the room environment measurements.
  • A SignalR Reaction that receives changes and forwards them to any connected front end clients.
  • An Azure Function App that provides HTTP endpoints for the demo app to directly change the environment values in the database.
  • A React frontend that invokes updates via the Function App and listens for changes via the SignalR reaction.

Deploying the App

1. Set up the sample data provider

From the apps/building-comfort/devops/azure-resources folder, use the Azure CLI to deploy cosmosdb.bicep:

az login  # If you are not already logged in
az deployment group create -f cosmosdb.bicep --resource-group <your resource group> -p cosmosAccountName=<your account name>

Fill in the name of the resource group you want deploy the demo (you will need to create a new resource group first if you don’t already have one), and a name of your choice for the Cosmos DB account. For example:

az deployment group create -f cosmosdb.bicep --resource-group my-resource-group -p cosmosAccountName=my-drasi-db

The bicep deployment will create a new CosmosDB account with the Gremlin API enabled and a database named Contoso with an empty Facilities graph.

Populate the sample data

Copy the following into a config.py file under apps/building-comfort/devops/data and edit the cosmosUri and cosmosPassword values to match your created Cosmos DB account.

cosmosUri = "wss://my-drasi-db.gremlin.cosmos.azure.com:443/"
cosmosUserName = "/dbs/Contoso/colls/Facilities"
cosmosPassword = "xxx...xxx"
buildingCount = 1
floorCount = 3
roomCount = 5
defaultRoomTemp = 70
defaultRoomHumidity = 40
defaultRoomCo2 = 10

You can find the values for the cosmosUri and cosmosPassword in the Azure portal under your Cosmos DB account or by using the Azure CLI:

# For the cosmosUri, you can use the gremlinEndpoint returned by:
COSMOS_DB_ID=$(az cosmosdb show -n my-drasi-db -g my-resource-group --query id -o tsv)
az resource show --id "$COSMOS_DB_ID" --query properties.gremlinEndpoint -o tsv

# For the cosmosPassword, you can use the primaryMasterKey returned by:
az cosmosdb keys list --name my-drasi-db --resource-group my-resource-group --type keys --query primaryMasterKey -o tsv

Once you have the config.py file, you can run the load_graph.py script in the same directory to populate the graph with sample data:

pip install gremlinpython  # If you don't already have the gremlinpython package installed
python load_graph.py

2. Deploy the Drasi components

Deploy the sources

Currently, we are unable to create a Kubernetes Secret using the Drasi CLI, so it needs to be manually created using kubectl. Navigate to your CosmosDB account in the Azure Portal. You will need to retrieve the value of PRIMARY CONNECTION STRING from the Keys blade. Run the following command to create the secrets:

kubectl create secret generic comfy-creds --from-literal=accountEndpoint='${PRIMARY CONNECTION STRING}'

You can also look up the SourceAccountEndpoint value in the Azure portal or by using the Azure CLI:

az cosmosdb keys list --name my-drasi-db -g my-resource-group --type connection-strings --query "connectionStrings[?contains(description, 'Primary Gremlin Connection String')].[connectionString]" -o tsv

From the apps/building-comfort/devops/reactive-graph folder, apply the source-facilities.yaml file with the drasi CLI to your cluster:

drasi apply -f source-facilities.yaml

Deploy the queries

From the apps/building-comfort/devops/reactive-graph folder, use the drasi CLI to deploy the continuous queries:

drasi apply -f query-alert.yaml
drasi apply -f query-comfort-calc.yaml
drasi apply -f query-ui.yaml

Breaking down the Continuous Queries specified in each file:

  • query-alert.yaml specifies the queries that detect when the comfort level in a room, a floor, or the whole building is outside the acceptable range of 40-50.

  • query-comfort-calc.yaml specifies the queries that calculate the comfort level for each room based on the temperature, humidity, and CO2 levels as described in the overview. It also specifies queries to aggregate the comfort level for each floor based on its rooms, and for the building based on its floors.

  • query-ui.yaml query gets the relevant properties and the relationships between rooms, floors and the building for visualization in the frontend React app.

Deploy the reactions

To deploy the gremlin reaction, we need to create another secret using kubectl to specify your Gremlin graph in the Cosmos DB instance:

kubectl create secret generic comfy-creds --from-literal=DatabaseHost=${DatabaseHost} --from-literal=DatabasePrimaryKey='${DatabasePrimaryKey}'
  • DatabaseHost with the host DNS name for the Gremlin endpoint. This is the same as the cosmosUri in config.py without the wss:// prefix or the port number.
  • DatabasePrimaryKey with the primary key, same as the cosmosPassword in config.py.

Apply the reaction-gremlin.yaml file and the reaction-signalr.yaml file with the drasi CLI to your cluster:

drasi apply -f reaction-gremlin.yaml
drasi apply -f reaction-signalr.yaml

The Gremlin Reaction is used to update the graph in Cosmos DB with the latest comfort level for each room, floor, and building. The SignalR Reaction is used to send the updates of the UI query to the frontend React app.

To connect the React app to the SignalR Reaction, forward the gateway port for the SignalR reaction to a port on your local machine:

kubectl port-forward services/signalr-building-gateway 5001:8080 -n default

3. Run the demo backend and frontend

Configure and start the backend Functions App for updating the data

From the apps/building-comfort/functions folder, create a file named local.settings.json and paste the following content with the appropriate FACILITIES_URL (same as the cosmosUri value) and FACILITIES_KEY (same as the cosmosPassword) value.

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "FACILITIES_DB_NAME": "Contoso",
    "FACILITIES_CNT_NAME": "Facilities",
    "FACILITIES_URL": "wss://my-drasi-db.gremlin.cosmos.azure.com:443/",
    "FACILITIES_KEY": "xxx...xxx",
  },
  "Host": {
    "LocalHttpPort": 7071
  }
}

Install the dependencies and run the Functions app locally:

npm install
npm start -- --javascript

Configure and start the frontend React app

From the apps/building-comfort/app folder, edit the config.json file to specify the local URLs for your deployment:

{
  "crudApiUrl": "http://localhost:7071",     // LocalHttpPort of the backend Functions app
  "signalRUrl": "http://localhost:5001/hub", // Kubectl port-forward of SignalR reaction
  ...
}

Install the dependencies and run the React app locally:

npm install
npm start

The front-end should launch at http://localhost:3000 by default.

NOTE: If you are experiencing issues with CORS policy (e.g. clicking a button and not seeing any changes), you can follow this workaround solution:

  1. Install Chrome
  2. In a terminal, execute the following line:
open /Applications/Google\ Chrome.app --args --user-data-dir="/var/tmp/chrome-dev-disabled-security" --disable-web-security --disable-site-isolation-trials
  1. Navigate to localhost:3000

Using the frontend app

Building Comfort UI

The UI shows the measured levels of temperature, humidity, and CO2 levels in each room, and the comfort level calculated from those values for each room, floor, and the building. Any alerts for rooms, floors, of the building are show under Comfort Alerts on the left, for example:

Building Comfort UI with alerts

You can use the buttons associated with each room to change the temperature, humidity, and CO2 levels in each room, and see the comfort level and alerts update in real time:

  • The BREAK button sets the temperature to 40, humidity to 20, and CO2 to 700, which will result in a room comfort level outside the acceptable range of 40-50. It will set each property individually with a slight delay between them to simulate a real scenario and show the how the comfort level calculations done by the Continuous Queries are affected in real time.

  • The RESET button sets the temperature to 70, humidity to 40, and CO2 to 10, which will restore the room to an acceptable comfort level. As with the BREAK button, it will set each property individually with a slight delay between them.