In this Code Pattern, we'll demonstrate how to build a custom Perceptive Application within a TRIRIGA instance.
TRIRIGA is a system used to monitor enterprise facilities by integrating data from real estate portfolios, construction projects, workplace assets, etc. We can extend the TRIRIGA capabilities with custom business logic by deploying a "Perceptive Application". A Perceptive App is a dynamic, custom application built using the TRIRIGA UX Framework. This is structured as a model-view-controller (MVC) architecture. The application "View" is built using the Polymer library, which makes it simple to create an interactive dashboard using modular web components. Web components can provide visual elements such as graphs, maps, images, and so on. Each component can be rendered by data pulled from internal TRIRIGA reports and/or API data from other offerings (Building Insights, Weather Company).
The project dependencies (Polymer, Web Components, UX Framework) are all pre-installed within the TRIRIGA instance. Additional third-party dependencies can be uploaded along with the project code.
The Building Insights service provides APIs to retrieve real time occupancy/energy sensor data, as well as an analytics engine to perform prediction and anomalies. Our solution demonstrates a way to integrate the Building Insights analytics engine and data into TRIRIGA. This is achieved by using a deploying a Node.js backend on Kubernetes to periodically make REST calls to the available APIs. As data is retrieved, it is then cached in a Cloudant Database.
When the reader has completed this Code Pattern, they will understand how to:
- Design and publish a customized Polymer application to a TRIRIGA instance
- Pull Occupancy and Energy data via Building Insights APIs.
- Persist historical data in a Cloudant database
-
Node.js back-end requests updates dataset from Building Insights APIs every hour and persists certain values into a Cloudant database. This allows for us to build a chronological hourly dataset, which can be used to create custom analytics models/graphics.
-
Custom TRIRIGA app pulls formatted sensor data from Node.js back end to render graphics and tables.
- Deploy Cloud Services
- Generate Application In TRIRIGA Dashboard
- Deploy Node.js application
- Push Perceptive App to TRIRIGA
To interact with the hosted offerings, the IBM Cloud CLI will need to be installed beforehand. The latest CLI releases can be found at the link here. An install script is maintained at the mentioned link, which can be executed with one of the following commands
# Mac OSX
curl -fsSL https://clis.ng.bluemix.net/install/osx | sh
# Linux
curl -fsSL https://clis.ng.bluemix.net/install/linux | sh
# Powershell
iex(New-Object Net.WebClient).DownloadString('https://clis.ng.bluemix.net/install/powershell')
After installation is complete, confirm the CLI is working by printing the version like so
ibmcloud -v
Also install the container service plugin
ibmcloud plugin install container-service
Linux
sudo apt-get update && sudo apt-get install -y apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl
MacOS
brew install kubernetes-cli
If expecting to run this application locally, please continue by installing Node.js runtime and NPM. We'd suggest using nvm to easily switch between node versions, which can be done with the following commands.
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
# Place next three lines in ~/.bash_profile
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
nvm install v8.9.0
nvm use 8.9.0
Create the following services:
To upload our application to TRIRIGA, we'll need to first enter a few metadata records.
Log in to the TRIRIGA Dashboard and click on the "Tools" section in the top menu
Next, click "Model Designer"
Click the "Add" button, and then enter a name for the application into the "Name", "ID", and "Exposed Name" Fields
Click on the "Tools" section in the top menu again, and select the "Model and View Designer" icon
Click the "Add" button, and then enter a name for the application. The name entered in the previous step can go into the "Name", "ID", and "Exposed Name" fields. Also confirm the "View Type" section has "Web View" selected.
Return to the "Tools" section again, and select "Application designer". The same value entered in the previous step can go into the "Name", and "ID", and "Exposed Name" fields. Also add a string descriptor in the "Label" section
Return to the "Tools" section a final time, and select "Web View Designer". The name entered in the previous steps can go into the "Name", and "ID" fields. The "Exposed Name" field will need to include an underscore, we'll use "tut-occupancy" in this case.
Next, open a terminal and navigate to the app
directory
Run the following command using the included WebViewSync_3.6.0.jar
binary to authenticate to the TRIRIGA server. This will prompt for the URL, and password, and place them in a WebViewSync.json
file.
java -jar WebViewSync_3.6.0.jar init
To generate a custom view, we can execute the "add view" command. This generates and pulls a template that can be used as a starting point. In this case, we've already placed a modified starter template in the app
directory, so this step can be bypassed.
java -jar WebViewSync_3.6.0.jar addview --view <app_name> --starter
After configuring the TRIRIGA dashboard, we can continue on to deploy the nodejs backend. The purpose of this process is to add additional logic to periodically query for building sensor data, perform data transformations, and to persist data in a database.
Fill out your credientals from the Building Insights and Cloudant services in the .env file as shown below:
usr=<building insights username>
password=<building insights password>
instance_id=<>
login_domain=https://<bi endpoint>-agg/api/v1/user/activity/login
agg_domain=https://<bi endpoint>-agg.mybluemix.net/api
kitt_domain=https://<bi endpoint>-KITT.mybluemix.net/api
domain=https://<bi endpoint>-agg.mybluemix.net/api
cloudant_username=<cloudant username>
cloudant_password=<cloudant password>
source .env
Create a kubernetes cluster
ibmcloud ks cluster-create --name my_cluster
Export the KUBECONFIG
path. This value will be printed just after creating the container cluster
export KUBECONFIG=/Users/$USER/.bluemix/plugins/container-service/clusters/mycluster/kube-config-hou02-mycluster.yml
Create a kubernetes "secret", which allows the above credentials to be set as environment variables in the container runtime
kubectl create secret generic auth --from-file=.env
Deploy the kubernetes application with the following command
kubectl apply -f kubernetes/kube-config.yml
Finally, get the public ip address of the Kubernetes cluster with the following commands
# Get id of cluster
ibmcloud ks clusters
# Print workers associated with cluster, take note of public ip.
ibmcloud ks workers <cluster_name>
# Load credentials
source .env
# Install Dependencies
npm install
# Start server
node app.js
# In a separate tab, run
ngrok http 3000
Open the file at ./app/tut-occupancy/tut-occupancy.html
, and edit lines 236-242, replacing each of the iron-ajax URLs with the public kubernetes cluster ip from the previous step.
Next, run the following commands to push the application code to the TRIRIGA server.
cd app
java -jar WebViewSync_3.5.3.jar push -a
If the push is successful, the application should be accessible at the following endpoint
http://${TRIRIGA_URL}/tririga/p/web/${APP_NAME}
Each of the visuals in the front-end application implemented as Polymer elements, which allows for us to reference packages in a HTML like syntax.
First, we'll generate a table that shows a list of each of the buildings, and their last reported occupancy. This shows how close each building is to capacity, as well as the predicted occupancy in the next hour.
This table is rendered by utilizing the triblock-table
element. To fetch the data for this element, the application will first make a call to the "/getbuildings" endpoint defined in the backend, which pulls and parses the registered building IDs from the Building Insights instance. This is done by making an HTTP request using the iron-ajax
package like so. The url defines the endpoint the application will be making a call to, and the last-response
key sets the response as a variable, which can then be referenced by any of the other Polymer elements
<iron-ajax auto url="http://127.0.0.1/genbuildingtable" handle-as="json" last-response="{{ajaxSampleTable}}"></iron-ajax>
After the building IDs have been collected, the application then queries the BI /FootFallByHourPopupBuilding
endpoint for each registered building. The results are then parsed and aggregated into an array of JSON objects like so.
'[\
{"id":"B008", "Occupancy":"30", "Percentage":"55%", "Prediction":"39" }, \
{"id":"EGLD", "Occupancy":"52", "Percentage":"71%", "Prediction":"43" },\
...
]
Each object in the above payload can then be loaded in the table with the following syntax. Note the "property" in the triblock-table-column
definition matches the keys in the above objects. And the result of the above iron-ajax call is set to the data
key
<triblock-table id="table1" title="Occupancy Stats" data="{{ajaxSampleTable}}" style="width:100%; height:500px;">
<triblock-table-column title="Building" property="id"></triblock-table-column>
<triblock-table-column title="Occupancy" property="Occupancy"></triblock-table-column>
<triblock-table-column title="Percentage" property="Percentage"></triblock-table-column>
<triblock-table-column title="Prediction (Next hour)" property="Prediction"></triblock-table-column>
</triblock-table>
The next visual shows a line graph comparing the hourly occupancy of each building during the last reported workday (6 AM - 6 PM). This is rendered via the third party "Google Charts" package, which is pre-installed as part of the TRIRIGA instance.
This chart can be rendered with the following Polymer syntax
<google-chart
style="width:100%; height:400px;"
type='line'
options='{"title": "Estate Occupancy (24hr)"}'
data="{{ajaxLineData}}"
</google-chart>
And the chart expects an "array of arrays" like so.
'[
["Time", "B008", "EGLD", "EGLD"], \
["06:00", 12, 10, 4], \
["07:00", 16, 12, 6], \
["08:00", 21, 20, 10], \
...
]'
TRIRIGA Perceptive App Documentation
This code pattern is licensed under the Apache License, Version 2. Separate third-party code objects invoked within this code pattern are licensed by their respective providers pursuant to their own separate licenses. Contributions are subject to the Developer Certificate of Origin, Version 1.1 and the Apache License, Version 2.