Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 15 Next »

 

 

Background

Greenhouse Monitoring System will be taken as an example to illustrate creating User Interface applications using TQL Queries.


TQL Queries Vs REST Services

REST is an architecture style for designing networked applications and in virtually all cases, the HTTP protocol is used. In many ways, the World Wide Web itself, based on HTTP, can be viewed as a REST-based architecture. By this definition of REST coupled with the fact that TQL Queries are executed over an HTTP endpoint that is automatically generated when models are deployed to TQLEngine, make TQL Queries Restful in nature.

In the table below we note fixed REST pattern that is applicable to TQL Queries.

TQL QueriesRestful Services

XML Oriented (Request & Response)

(Note that TQLEngine supports both JSON & XML;

the recommended guideline is XML for TQL Queries

readability)

Restful Services are JSON oriented

TQL Queries are sent as payload, therefore the HTTP Method to be used

always POST.

Method can be: GET/PUT/POST/DELETE

 

UI Technologies

Most commonly used UI technologies are:

    • HTML,CSS and JavaScript
    • JavaScript Frameworks (Angular JS, Backbone JS, etc.)
    • HTML5, CSS/CSS3 and JavaScript/jQuery

Design Patterns

Model-View-Controller (MVC) is popular design pattern to develop HTML/JS app that consumes TQL Queries.

ViewTechnologyIn this tutorial
ViewHTML, CSS, JS (Bootstrap is a good starting point)index.html
Model

JS - Services & Factories independent of underlying framework (OR) Angular JS

provided Model

Angular Model Service (TQLQueryService.js)
Controller

JS - Can be independent of underlying framework (Write your own using JS) or

Angular provided model

Angular Controller and bind with HTML

using Angular directive ng-controller. [MainController.js]

Implementation Steps

All the implementation steps must be against Simulated Greenhouse project.

Creating View

a) Main View - Single Page HTML file

View - Greenhouse Monitoring App
<!DOCTYPE html>
<html ng-app="GreenhouseUIApp">
<head>
<title>Smart Greenhouse</title>
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<script type="text/javascript"
  src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<link
  href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
  rel="stylesheet">
<link href="style.css" rel="stylesheet">
<script
  src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/x2js/1.2.0/xml2json.min.js"></script>
<script type="text/javascript" src="config/url_config.js"></script>
<script type="text/javascript" src="controllers/mainController.js"></script>
<script type="text/javascript" src="services/queryService.js"></script>
</head>
<body>
  <div ng-controller="mainController">
    <div class="row text-center header">
      <h2>SMART GREENHOUSE</h2>
    </div>
    <div class="row text-center greenhouseDetails">
      <h4>{{selectedGreenhouse.GreenhouseName}}&nbsp;&nbsp;|&nbsp;&nbsp;
        Zones: {{selectedGreenhouse.ZoneCount}}&nbsp;&nbsp;|&nbsp;&nbsp;
        Location: ({{selectedGreenhouse.Location.latitude}},
        {{selectedGreenhouse.Location.longitude}})</h4>
    </div>
    <div class="row">
      <div class="col-md-2"></div>
      <div class="col-md-3 statusBlock">
        <div>
          <h3>Internal Status</h3>
        </div>
        <div>Temperature: {{selectedGreenhouse.InternalEnv.Temperature}}
          &deg;C</div>
        <div>Humidity: {{selectedGreenhouse.InternalEnv.Humidity}} %</div>
        <div>Amb. Light: {{selectedGreenhouse.InternalEnv.Light}} lux</div>
        <div>Soil Moisture:
          {{selectedGreenhouse.InternalEnv.SoilMoisture}} cb</div>
      </div>
      <div class="col-md-1"></div>
      <div class="col-md-4 statusBlock">
        <div>
          <h3>External Conditions</h3>
        </div>
        <div>Temperature: {{selectedGreenhouse.ExternalEnv.Temperature}}
          &deg;C</div>
        <div>Humidity: {{selectedGreenhouse.ExternalEnv.Humidity}} %</div>
        <div>Sunlight: {{selectedGreenhouse.ExternalEnv.Light}} lux</div>
        <div>Soil Moisture:
          {{selectedGreenhouse.ExternalEnv.SoilMoisture}} cb</div>
        <div>Wind: {{selectedGreenhouse.ExternalEnv.Wind}} mph</div>
      </div>
      <div class="col-md-3"></div>
    </div>
  </div>
</body>
</html>

b) Creating Style Sheet

View - Stylesheet Greenhouse Monitoring App
body{
   background: url(images/greenhouse.jpg);
   background-size: cover;
   padding: 0; margin: 0;
}
.header{
   background: #000; color: #fff; margin-bottom:
20px;
}
.greenhouseDetails{
   background: #39404a;
   color: #fff;
}
.statusBlock{
   background: #39404a;
   color: #fff;
   padding: 30px; margin: 30px 0;      
}

Creating Model

Model is where we capture consuming of TQL Queries.

View - Greenhouse Monitoring App
angular.module('GreenhouseUIApp').service('QueryService', function ($http){
	return{
		discoverGreenhouseEndpoint : discoverGreenhouseEndpoint,
		getGreenhouses : getGreenhouses,
		getLanesForGreenhouse : getLanesForGreenhouse,
		getZonesForLane : getZonesForLane
	}
	function discoverGreenhouseEndpoint(){
		var findProjectQuery = "<query><find><project><projName eq='Greenhouse'/></project></find></query>";
		return $http.post(TQLEngineManagerURL, findProjectQuery).then(function(response) {
			var x2js = new X2JS();
			var jsonObj = x2js.xml_str2json(response.data);
			var findProjectEndpointsQuery = "<GetProjectEndPoints><ProjectSysId>"+jsonObj.Find.Result.Project.SysId+"</ProjectSysId></GetProjectEndPoints>";
			return $http.post(TQLEngineManagerURL, findProjectEndpointsQuery).then(function(response) {
				var x2js = new X2JS();
				var endpointsJson = x2js.xml_str2json(response.data);
				return endpointsJson;
			});
		});
	}
	function getGreenhouses(endpointURL){
		var query = "<Query><Find><Greenhouse><GreenhouseID ne=''/></Greenhouse></Find></Query>";
		return $http.post(endpointURL, query).then(function(response) {
			var x2js = new X2JS();
			var jsonObj = x2js.xml_str2json(response.data);
			return jsonObj;
		});
	}

	function getLanesForGreenhouse(GreenhouseID){
		var query = "<Query><Find><Lane><GreenhouseID eq="+ GreenhouseID +"/></Lane></Find></Query>";
		return $http.post(url, query).then(function(response) {
			var x2js = new X2JS();
			var jsonObj = x2js.xml_str2json(response.data);
			return jsonObj;
		});
	}
	function getZonesForLane(LaneID){
		var query = "<Query><Find><Zone><LaneID eq="+LaneID+" /></Zone></Find></Query>";
		return $http.post(url, query).then(function(response) {
			var x2js = new X2JS();
			var jsonObj = x2js.xml_str2json(response.data);
			return jsonObj;
		});
	}
});

Identify Queries

Before we start wrapping TQL Queries into a Service model, we need to identify the list of queries to be executed. 

  • Discovering TQL EndPoints URL:  

    Application TQL endpoint discovery query
    <Query>
      <Find>
        <project>
          <projName eq='Greenhouse'/>
        </project>
      </Find>
    </Query>
    <GetProjectEndPoints>
      <ProjectSysId>
         Find.Result.Project.SysId
      </ProjectSysId>
    </GetProjectEndPoints>
  • Never hardcode the TQL Query endpoint urls as they are subject to change.

  • Instead the endpoints must be auto discovered given the project name. 

  • The model developer (owner) will project you appropriate project name to discover your query endpoints.

  • You can test the queries and make sure they are working via Query Editor (TQLStudio or Local TQLEngine)
  1. Gather App related queries: In this example we will wrap only one single query to get Greenhouse information.

    App Queries - Greenhouse Monitoring App
    <Query>
      <Find>
        <Greenhouse>
          <GreenhouseID ne=''/>
        </Greenhouse>
      </Find>
    </Query>

Creating Controller

Controller - Greenhouse Monitoring App
angular.module('GreenhouseUIApp', [])
.controller('mainController', function($scope, QueryService) {
	$scope.greenhouses = [];
	$scope.httpEndpoint = "";
	$scope.wsEndpoint = "";
	$scope.getGreenhouses = function(){
		QueryService.getGreenhouses($scope.httpEndpoint).then(function(response){
			if(angular.isArray(response.Find.Result.Greenhouse)){
				$scope.greenhouses = response.Find.Result.Greenhouse;
			} else if(angular.isObject(response.Find.Result.Greenhouse)){
				$scope.greenhouses.push(response.Find.Result.Greenhouse);
			}
			$scope.selectedGreenhouse = $scope.greenhouses[0];
			console.log($scope.greenhouses);
		});
	};
	$scope.replaceIPWithHostName = function(){
		$scope.wsEndpoint = $scope.wsEndpoint.replace( /:.*?\:/, '://'+greenhouseHostName+':' );
		$scope.httpEndpoint = $scope.httpEndpoint.replace( /:.*?\:/, '://'+greenhouseHostName+':' );
	};
	QueryService.discoverGreenhouseEndpoint().then(function(data){
		angular.forEach(data.Find.projectEndpointMap.DataMap, function(obj){
			if(obj.Value.indexOf("ws:") > -1){
				$scope.wsEndpoint = obj.Value;
			} else if(obj.Value.indexOf("http:") > -1 || obj.Value.indexOf("https:") > -1){
				$scope.httpEndpoint = obj.Value;
			}
		});
		$scope.replaceIPWithHostName();
		$scope.getGreenhouses();
	});
}

Deploy & Test

It is recommended to serve your applications (html,css,js) files directly from the running TQLEngine.

Download & Install TQLEngine

Please refer to download section to download and install TQLEngine.

Attach applications to the project

Now you can point your browser to URL and load the UI



  • No labels