• Recent
    • Tags
    • Popular
    • Register
    • Login

    Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

    Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website Mango 5 Documentation Website

    Intesis integration

    User help
    2
    6
    2.2k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      dovydasz
      last edited by

      Hello
      I'm wondering how to integrate air conditioners connected with Intesis adapters.
      They provide this REST API documentation:
      https://www.intesishome.com/developers/rest-api-documentation/

      Can you give some tips or even better examples of how to do it with Mango?

      Sincerely,
      Dovydas

      1 Reply Last reply Reply Quote 0
      • phildunlapP
        phildunlap
        last edited by phildunlap

        Hi Dovydas,

        Here's a script I wrote to integrate with a REST API, stripped down a little to make it more generic. It's a token authenticated service, where if you set a value to the API key it will login and request a token it can use to refresh. I think that's similar to what you would need to do, or you could manually provide the token to the script.

        You will want to be using the latest version of Mango. We recently added some HTTP utilities to the scripting data source that this script hinges on, and we just made the release that contains them. Here's the git issue describing the feature (it may not be fully documented yet) https://github.com/infiniteautomation/ma-core-public/issues/1094

        var baseUrl = "sptth://api.com";
        var createdPoints = [];
        var createdFolders = {};
        
        //We will use this to see if points have already been defined in the context.
        var global = this;
        
        function refreshSessionToken() {
        	if(typeof sessionToken === 'undefined') {
        		var sessionInfo = refresh.value.split("~");
        		sessionToken = sessionInfo[0];
        		refreshToken = sessionInfo[1];
        		session = {"Session-Token": sessionToken};
        	}
        	return HttpBuilder.post(baseUrl + "/refresh", session, {"RefreshToken": refreshToken})
        		.err(function(status, headers, content) {
        			//print("Refresh Login failure!" + content);
        			return false;
        		}).resp(function(status, headers, content) {
        			var login = JSON.parse(content);
        			sessionToken = login.SessionToken;
        			refreshToken = login.RefreshToken;
        			refresh.set(sessionToken + "~" + refreshToken);
        			session = {"Session-Token": sessionToken};
        			//print("Refresh Login success!" + content);
        			RuntimeManager.sleep(100);
        			return true;
        		}).execute();
        }
        
        function createApiPoint(deviceName, name, varName, isBool) {
        	var basePoint = JSON.parse(JsonEmport.dataPointQuery("eq(xid,DP_API_Example_BaseNumeric)")).dataPoints[0];
        	basePoint.xid = "DP_API_Example_"+varName;
        	basePoint.pointLocator.varName = varName;
        	basePoint.deviceName = deviceName;
        	basePoint.name = name;
        	basePoint.enabled = true;
        	if(isBool) {
        		basePoint.pointLocator.dataType = "BINARY";
        		basePoint.templateXid = "BINARY_DEFAULT";
        		//You may need to set some other properties to get it to work....
        		/*
        		basePoint.plotType = "STEP";
        		basePoint.textRenderer = {
                    "type":"BINARY",
                    "oneColour":"black",
                    "oneLabel":"one",
                    "zeroColour":"blue",
                    "zeroLabel":"zero"
                 };
        		basePoint.chartRenderer = {
                    "type":"TABLE",
                    "limit":10
                 };*/
        	}
        	// This is a great place to build the point hierarchy too!
        	/*
        	if(!(basePoint.deviceName in createdFolders) {
        		newFolder = {"name":basePoint.deviceName,"subfolders":[],"points":[]};
        		newFolder.points.push(basePoint.xid);
        		createdFolders[newFolder.deviceName] = newFolder;
        	} else
        		createdFolders[basePoint.deviceName].points.push(basePoint.xid);
        	*/
        	createdPoints.push(basePoint);
        }
        
        var errReconnect = function(status, headers, content) {
        							if(status == 401 && refreshSessionToken()) {
        							    //print("Re-requested!");
        								return true;
        							} else if(status != 401) {
        							    //print("Non-authorization error: " + status + " " + content);
        							    //LOG.error("Non-authorization error: " + status + " " + content);
        							}
        							return false;
        			};
        			
        var mainResponse = function(status, headers, content) {
        				//Do what needs doing as far as querying data or parsing the content response
        				/*
        				var body = JSON.parse(content);
        				for(int k = 0; k < body.length; k++) {
        					var info = body[k];
        					if(typeof global[info.variableName] === 'undefined') //we're using global to identify if that variable name already exists
        						createApiPoint(info.deviceName, info.name, info.variableName, info.isBool);
        					else
        						global[info.variableName].set(info.value);
        				}
        				*/
        				return false; //return false so we know we didn't reconnect and need to poll again
        			};
        			
        if(apiKey.value !=="") {
        	HttpBuilder.post(baseUrl + "/tokens", {"Content-Type":"application/json"},
        	{
        		"Key" : apiKey.value,
        		"Remember" : true,
        		"Device" : "Example API Script"
        	}).err(function(status, headers, content) {
        		if(status == -1) { /* an exception was probably thrown */ }
        		//else print(content);
        	}).resp(function(status, headers, content) {
        		var response = JSON.parse(content);
        		sessionToken = response.SessionToken;
        		refreshToken = response.RefreshToken;
        		session = {"Session-Token": sessionToken};
        		if(typeof refreshToken !== 'undefined')
        			refresh.set(sessionToken + "~" + refreshToken);
        	}).execute();
        	apiKey.set("");
        } else { //Wrap in else so API key context update executes this from set to ""
        	while(true) {
        		if(typeof session !== 'undefined') {
        			if(HttpBuilder.get(baseUrl + "/beginning/request", session, null)
        			    .err(errReconnect).resp(mainResponse).execute())
        		    	continue;
        			break;
        		} else if(refreshSessionToken()) {
                    //print("Else if main clause reconnect");
        			continue;
        		} else //Failed to authenticate for some reason
        			break;
        	}
        }
        
        ph = [];
        for(var k in createdFolders)
            ph.push(createdFolders[k]);
        //print(JSON.stringify(ph))
        if(createdPoints.length > 0) {
            JsonEmport.doImport(JSON.stringify({"dataPoints":createdPoints, "pointHierarchy":ph}));
        }
        

        So we've got a script to reconnect and get a new session, and it creates the points for you!

        Here's the JSON for my example (not tested, but derived from a working scripting data source), which includes the apiKey, refresh, and DP_API_Example_BaseNumeric points referenced in the script.

        {
           "dataSources":[
              {
                 "xid":"DS_a42f2287-aecc-4ad9-8f3c-97a2acddc0d8",
                 "name":"Generic Rest Script",
                 "enabled":false,
                 "type":"SCRIPTING",
                 "alarmLevels":{
                    "SCRIPT_ERROR":"URGENT",
                    "DATA_TYPE_ERROR":"URGENT",
                    "POLL_ABORTED":"URGENT",
                    "LOG_ERROR":"URGENT"
                 },
                 "purgeType":"YEARS",
                 "updateEvent":"CONTEXT_UPDATE",
                 "context":[
                 ],
                 "logLevel":"NONE",
                 "cronPattern":"0 * * * * ?",
                 "executionDelaySeconds":0,
                 "historicalSetting":false,
                 "script":"var baseUrl = \"sptth:\/\/api.com\";\r\nvar createdPoints = [];\r\nvar createdFolders = {};\r\n\r\n\/\/We will use this to see if points have already been defined in the context.\r\nvar global = this;\r\n\r\nfunction refreshSessionToken() {\r\n\tif(typeof sessionToken === 'undefined') {\r\n\t\tvar sessionInfo = refresh.value.split(\"~\");\r\n\t\tsessionToken = sessionInfo[0];\r\n\t\trefreshToken = sessionInfo[1];\r\n\t\tsession = {\"Session-Token\": sessionToken};\r\n\t}\r\n\treturn HttpBuilder.post(baseUrl + \"\/refresh\", session, {\"RefreshToken\": refreshToken})\r\n\t\t.err(function(status, headers, content) {\r\n\t\t\t\/\/print(\"Refresh Login failure!\" + content);\r\n\t\t\treturn false;\r\n\t\t}).resp(function(status, headers, content) {\r\n\t\t\tvar login = JSON.parse(content);\r\n\t\t\tsessionToken = login.SessionToken;\r\n\t\t\trefreshToken = login.RefreshToken;\r\n\t\t\trefresh.set(sessionToken + \"~\" + refreshToken);\r\n\t\t\tsession = {\"Session-Token\": sessionToken};\r\n\t\t\t\/\/print(\"Refresh Login success!\" + content);\r\n\t\t\tRuntimeManager.sleep(100);\r\n\t\t\treturn true;\r\n\t\t}).execute();\r\n}\r\n\r\nfunction createApiPoint(deviceName, name, varName, isBool) {\r\n\tvar basePoint = JSON.parse(JsonEmport.dataPointQuery(\"eq(xid,DP_API_Example_BaseNumeric)\")).dataPoints[0];\r\n\tbasePoint.xid = \"DP_API_Example_\"+varName;\r\n\tbasePoint.pointLocator.varName = varName;\r\n\tbasePoint.deviceName = deviceName;\r\n\tbasePoint.name = name;\r\n\tbasePoint.enabled = true;\r\n\tif(isBool) {\r\n\t\tbasePoint.pointLocator.dataType = \"BINARY\";\r\n\t\tbasePoint.templateXid = \"BINARY_DEFAULT\";\r\n\t\t\/\/You may need to set some other properties to get it to work....\r\n\t\t\/*\r\n\t\tbasePoint.plotType = \"STEP\";\r\n\t\tbasePoint.textRenderer = {\r\n            \"type\":\"BINARY\",\r\n            \"oneColour\":\"black\",\r\n            \"oneLabel\":\"one\",\r\n            \"zeroColour\":\"blue\",\r\n            \"zeroLabel\":\"zero\"\r\n         };\r\n\t\tbasePoint.chartRenderer = {\r\n            \"type\":\"TABLE\",\r\n            \"limit\":10\r\n         };*\/\r\n\t}\r\n\t\/\/ This is a great place to build the point hierarchy too!\r\n\t\/*\r\n\tif(!(basePoint.deviceName in createdFolders) {\r\n\t\tnewFolder = {\"name\":basePoint.deviceName,\"subfolders\":[],\"points\":[]};\r\n\t\tnewFolder.points.push(basePoint.xid);\r\n\t\tcreatedFolders[newFolder.deviceName] = newFolder;\r\n\t}\r\n\t*\/\r\n\tcreatedPoints.push(basePoint);\r\n}\r\n\r\nvar errReconnect = function(status, headers, content) {\r\n\t\t\t\t\t\t\tif(status == 401 && refreshSessionToken()) {\r\n\t\t\t\t\t\t\t    \/\/print(\"Re-requested!\");\r\n\t\t\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t\t\t} else if(status != 401) {\r\n\t\t\t\t\t\t\t    \/\/print(\"Non-authorization error: \" + status + \" \" + content);\r\n\t\t\t\t\t\t\t    \/\/LOG.error(\"Non-authorization error: \" + status + \" \" + content);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn false;\r\n\t\t\t};\r\n\t\t\t\r\nvar mainResponse = function(status, headers, content) {\r\n\t\t\t\t\/\/Do what needs doing as far as querying data or parsing the content response\r\n\t\t\t\t\/*\r\n\t\t\t\tvar body = JSON.parse(content);\r\n\t\t\t\tfor(int k = 0; k < body.length; k++) {\r\n\t\t\t\t\tvar info = body[k];\r\n\t\t\t\t\tif(typeof global[info.variableName] === 'undefined') \/\/we're using global to identify if that variable name already exists\r\n\t\t\t\t\t\tcreateApiPoint(info.deviceName, info.name, info.variableName, info.isBool);\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\tglobal[info.variableName].set(info.value);\r\n\t\t\t\t}\r\n\t\t\t\t*\/\r\n\t\t\t\treturn false; \/\/return false so we know we didn't reconnect and need to poll again\r\n\t\t\t};\r\n\t\t\t\r\nif(apiKey.value !==\"\") {\r\n\tHttpBuilder.post(baseUrl + \"\/tokens\", {\"Content-Type\":\"application\/json\"},\r\n\t{\r\n\t\t\"Key\" : apiKey.value,\r\n\t\t\"Remember\" : true,\r\n\t\t\"Device\" : \"Example API Script\"\r\n\t}).err(function(status, headers, content) {\r\n\t\tif(status == -1) { \/* an exception was probably thrown *\/ }\r\n\t\t\/\/else print(content);\r\n\t}).resp(function(status, headers, content) {\r\n\t\tvar response = JSON.parse(content);\r\n\t\tsessionToken = response.SessionToken;\r\n\t\trefreshToken = response.RefreshToken;\r\n\t\tsession = {\"Session-Token\": sessionToken};\r\n\t\tif(typeof refreshToken !== 'undefined')\r\n\t\t\trefresh.set(sessionToken + \"~\" + refreshToken);\r\n\t}).execute();\r\n\tapiKey.set(\"\");\r\n} else { \/\/Wrap in else so API key context update executes this from set to \"\"\r\n\twhile(true) {\r\n\t\tif(typeof session !== 'undefined') {\r\n\t\t\tif(HttpBuilder.get(baseUrl + \"\/beginning\/request\", session, null)\r\n\t\t\t    .err(errReconnect).resp(mainResponse).execute())\r\n\t\t    \tcontinue;\r\n\t\t\tbreak;\r\n\t\t} else if(refreshSessionToken()) {\r\n            \/\/print(\"Else if main clause reconnect\");\r\n\t\t\tcontinue;\r\n\t\t} else \/\/Failed to authenticate for some reason\r\n\t\t\tbreak;\r\n\t}\r\n}\r\n\r\nph = [];\r\nfor(var k in createdFolders)\r\n    ph.push(createdFolders[k]);\r\n\/\/print(JSON.stringify(ph))\r\nif(createdPoints.length > 0) {\r\n    JsonEmport.doImport(JSON.stringify({\"dataPoints\":createdPoints, \"pointHierarchy\":ph}));\r\n}\r\n",
                 "scriptPermissions":{
                    "customPermissions":"",
                    "dataPointReadPermissions":"superadmin",
                    "dataPointSetPermissions":"superadmin",
                    "dataSourcePermissions":"superadmin"
                 },
                 "editPermission":"",
                 "purgeOverride":false,
                 "purgePeriod":1
              }
           ],
           "dataPoints":[
              {
                 "xid":"DP_API_Example_ApiKey",
                 "name":"Api Key",
                 "enabled":true,
                 "loggingType":"ON_CHANGE",
                 "intervalLoggingPeriodType":"MINUTES",
                 "intervalLoggingType":"INSTANT",
                 "purgeType":"YEARS",
                 "pointLocator":{
                    "dataType":"ALPHANUMERIC",
                    "contextUpdate":true,
                    "settable":true,
                    "varName":"apiKey"
                 },
                 "eventDetectors":[
                 ],
                 "plotType":"STEP",
                 "rollup":"NONE",
                 "unit":"",
                 "path":"",
                 "templateXid":"Alphanumeric_Default",
                 "chartColour":"",
                 "chartRenderer":{
                    "type":"TABLE",
                    "limit":10
                 },
                 "dataSourceXid":"DS_a42f2287-aecc-4ad9-8f3c-97a2acddc0d8",
                 "defaultCacheSize":1,
                 "deviceName":"Generic Rest Script",
                 "discardExtremeValues":false,
                 "discardHighLimit":1.7976931348623157E308,
                 "discardLowLimit":-1.7976931348623157E308,
                 "intervalLoggingPeriod":15,
                 "intervalLoggingSampleWindowSize":0,
                 "overrideIntervalLoggingSamples":false,
                 "preventSetExtremeValues":false,
                 "purgeOverride":false,
                 "purgePeriod":1,
                 "readPermission":"",
                 "setExtremeHighLimit":1.7976931348623157E308,
                 "setExtremeLowLimit":-1.7976931348623157E308,
                 "setPermission":"",
                 "textRenderer":{
                    "type":"PLAIN",
                    "useUnitAsSuffix":true,
                    "unit":"",
                    "renderedUnit":"",
                    "suffix":""
                 },
                 "tolerance":0.0
              },
              {
                 "xid":"DP_API_Example_RefreshTokens",
                 "name":"Refresh Tokens",
                 "enabled":true,
                 "loggingType":"ON_CHANGE",
                 "intervalLoggingPeriodType":"MINUTES",
                 "intervalLoggingType":"INSTANT",
                 "purgeType":"YEARS",
                 "pointLocator":{
                    "dataType":"ALPHANUMERIC",
                    "contextUpdate":false,
                    "settable":true,
                    "varName":"refresh"
                 },
                 "eventDetectors":[
                 ],
                 "plotType":"STEP",
                 "rollup":"NONE",
                 "unit":"",
                 "path":"",
                 "templateXid":"Alphanumeric_Default",
                 "chartColour":"",
                 "chartRenderer":{
                    "type":"TABLE",
                    "limit":10
                 },
                 "dataSourceXid":"DS_a42f2287-aecc-4ad9-8f3c-97a2acddc0d8",
                 "defaultCacheSize":1,
                 "deviceName":"Generic Rest Script",
                 "discardExtremeValues":false,
                 "discardHighLimit":1.7976931348623157E308,
                 "discardLowLimit":-1.7976931348623157E308,
                 "intervalLoggingPeriod":15,
                 "intervalLoggingSampleWindowSize":0,
                 "overrideIntervalLoggingSamples":false,
                 "preventSetExtremeValues":false,
                 "purgeOverride":false,
                 "purgePeriod":1,
                 "readPermission":"",
                 "setExtremeHighLimit":1.7976931348623157E308,
                 "setExtremeLowLimit":-1.7976931348623157E308,
                 "setPermission":"",
                 "textRenderer":{
                    "type":"PLAIN",
                    "useUnitAsSuffix":true,
                    "unit":"",
                    "renderedUnit":"",
                    "suffix":""
                 },
                 "tolerance":0.0
              },
              {
                 "xid":"DP_API_Example_BaseNumeric",
                 "name":"BaseNumeric",
                 "enabled":false,
                 "loggingType":"INTERVAL",
                 "intervalLoggingPeriodType":"MINUTES",
                 "intervalLoggingType":"AVERAGE",
                 "purgeType":"YEARS",
                 "pointLocator":{
                    "dataType":"NUMERIC",
                    "contextUpdate":false,
                    "settable":true,
                    "varName":"baseNumericPoint"
                 },
                 "eventDetectors":[
                 ],
                 "plotType":"SPLINE",
                 "rollup":"NONE",
                 "unit":"",
                 "path":"",
                 "templateXid":"Numeric_Default",
                 "chartColour":"",
                 "chartRenderer":{
                    "type":"IMAGE",
                    "timePeriodType":"DAYS",
                    "numberOfPeriods":1
                 },
                 "dataSourceXid":"DS_a42f2287-aecc-4ad9-8f3c-97a2acddc0d8",
                 "defaultCacheSize":1,
                 "deviceName":"Generic Rest Script",
                 "discardExtremeValues":false,
                 "discardHighLimit":1.7976931348623157E308,
                 "discardLowLimit":-1.7976931348623157E308,
                 "intervalLoggingPeriod":1,
                 "intervalLoggingSampleWindowSize":0,
                 "overrideIntervalLoggingSamples":false,
                 "preventSetExtremeValues":false,
                 "purgeOverride":false,
                 "purgePeriod":1,
                 "readPermission":"",
                 "setExtremeHighLimit":1.7976931348623157E308,
                 "setExtremeLowLimit":-1.7976931348623157E308,
                 "setPermission":"",
                 "textRenderer":{
                    "type":"ANALOG",
                    "useUnitAsSuffix":true,
                    "unit":"",
                    "renderedUnit":"",
                    "format":"0.00"
                 },
                 "tolerance":0.0
              }
           ]
        }
        

        Alternatively, it's possible you may be able to get what you want out of an HTTP Json Retriever if you can set your session token such that it doesn't time out and is a static header for the data source.

        1 Reply Last reply Reply Quote 0
        • D
          dovydasz
          last edited by

          Hello Phillip,
          thanks for your answer!

          I updated my Mango to newest version 3.2.2+20171009170034 but unfortunately still have this error:
          ReferenceError: "HttpBuilder" is not defined in at line number 15

          Should I install this somehow manually?

          Dovydas

          1 Reply Last reply Reply Quote 0
          • phildunlapP
            phildunlap
            last edited by

            I wonder if something has gone awry in your upgrade process. I just updated a Mango to the version you have and when I run print(HttpBuilder) in a Scripting data source I get a description of the utility.

            Is it possible that you have more than one mango-X.Y.Z.jar in your Mango/lib/ directory, or have one elsewhere on the classpath? How did you update?

            1 Reply Last reply Reply Quote 0
            • D
              dovydasz
              last edited by

              There were some errors (can't find jar or smth) on updating process so I just extracted m2m2-core-3.2.2.zip into my Mango directory. And yes, there were two files - mango-3.2.1.jar and mango-3.2.2.jar, so I deleted 3.2.1 and now it started with HttpBuilder.
              Thanks! Going to analyze your script..

              1 Reply Last reply Reply Quote 0
              • phildunlapP
                phildunlap
                last edited by

                Great!

                You may consider placing the m2m2-core-3.2.2.zip into your Mango/ directory again and then simply restart Mango. It will automatically perform an upgrade if there is a new core zip in the Mango/ directory. It's possible there were other JARs update and you'd have duplicates of those too, which would produce uncertain results.

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post