As part of a process I am going through to re-platform my logic for the eternal question “should we open the windows” I have begun migrating all automation into Logic Apps. For background, I am gathering information on the current weather, weather forecast and Nest thermostat information to make decisions on whether the windows should be opened. The overall goal is to provide a method to increase energy efficiency in our home through using the outside temperature to adapt the inside temperature when the right conditions apply.

At MMS Jazz edition, I attended a session called “Behind the Curtain – The Automation Behind MMS” where Donnie and Greg showcased how they made their automation re-usable through creating them in Azure and re-deploying them through ARM templates. I blame them both and their session for all the work I will now be facing to re-platform my existing solutions into Logic Apps and a more modular approach to these.

The first of the sources of data which I wanted to gather from was the NEST API (I previously blogged on my experiences with NEST if you are interested). In theory this should have been easy as Logic Apps has built-in connectors to query REST API’s. However, there was a challenge here which I did not expect. The NEST API does a redirect which while apps like Postman handle it like a champ this was a little more difficult to accomplish with Logic Apps.

Generic approach to reading from an API:

This is the approach I take when I need to query data from a new API.

1) Start from the vendor’s documentation (https://developers.nest.com/guides/api/how-to-read-data in this case).

2) From the vendor’s documentation work through the process to get the required credentials for authentication and authorization (https://developers.nest.com/guides/api/how-to-auth in this case).

3) Use any sample code provided by the vendor (in this situation the Python 3 version) to validate that the process works as expected.

4) Move to Postman to make sure the headers are configured properly.

5) Once that is functional, move on to the platform where you want the final automation to run from (in this case Logic Apps).

Challenges with getting data from the NEST API via Logic Apps: (supporting redirects)

The NEST API uses redirects (https://developers.nest.com/guides/api/how-to-handle-redirects) which was the primary challenge I had in gathering this data. To handle this, I ended up with the following steps:

  • For “Recurrence” I configured this to run every hour during the day.
  • On “Initialize variable” I defined the authorization string as a variable called NESTAuth.
  • On “Set variable” I provided the authorization string value which I had gotten from NEST.

  • On “Query NEST to find the redirected URL” I did a Get from https://developer-api.nest.com specifying the Authorization (with “Bearer ” in front of it) and the content type as application/json
  • I built a split of paths at this level, the one to the left doing a “Parse JSON” and the one to the right doing “Query NEST devices (no redirect)”. During my testing I had occasional results which came back without the redirect so I added the path in case that occurred. The first “Parse JSON” goes through the headers and uses the information provided in the “Schema for Parse JSON” section of this blog post.
  • The second “Parse JSON 2” goes through the results of the first Parse JSON and goes through the Body and uses the information provided in the “Schema for Parse JSON 2” section of this blog post.
  • The final step on the left path does the query to gather the required data from NEST.

 

The high level of the process is shown below.

Schema for Parse JSON:

[code lang=”js”]
{
"properties": {
"headers": {
"properties": {
"Access-Control-Allow-Origin": {
"type": "string"
},
"Cache-Control": {
"type": "string"
},
"Connection": {
"type": "string"
},
"Content-Length": {
"type": "string"
},
"Content-Type": {
"type": "string"
},
"Location": {
"type": "string"
},
"Pragma": {
"type": "string"
}
},
"type": "object"
},
"statusCode": {
"type": "integer"
}
},
"type": "object"
}

[/code]
 
Schema for Parse JSON 2:

[code lang=”js”]
{
"properties": {
"Access-Control-Allow-Origin": {
"type": "string"
},
"Cache-Control": {
"type": "string"
},
"Connection": {
"type": "string"
},
"Content-Length": {
"type": "string"
},
"Content-Type": {
"type": "string"
},
"Location": {
"type": "string"
},
"Pragma": {
"type": "string"
}
},
"type": "object"
}
[/php]
 

<strong>Summary</strong>: When querying a REST API which uses redirects the approach above gives a method to gather that data via Logic Apps (query the first URL, find the second URL through parsing the JSON and then query the redirected URL for the results).

Thank you to <a href="https://twitter.com/donnie_taylor">Donnie Taylor</a>, <a href="https://mvp.microsoft.com/en-us/PublicProfile/33629?fullName=Greg%20%20Ramsey">Greg Ramsey</a> and <a href="https://www.linkedin.com/in/ryan-ephgrave-1a153139/">Ryan Ephgrave</a> for their help working through the URL redirection challenge in this blog post! Once I finish this series my goal is to provide an ARM template deployable version of these solutions.

&nbsp;

<strong>Below is the current code view (minus definition of my NEST authorization string):</strong>

[code]
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Initialize_variable": {
"inputs": {
"variables": [
{
"name": "NESTAuth",
"type": "string"
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Parse_JSON": {
"inputs": {
"content": "@outputs(‘Query_NEST_to_find_the_redirected_URL’)[‘headers’]",
"schema": {
"properties": {
"headers": {
"properties": {
"Access-Control-Allow-Origin": {
"type": "string"
},
"Cache-Control": {
"type": "string"
},
"Connection": {
"type": "string"
},
"Content-Length": {
"type": "string"
},
"Content-Type": {
"type": "string"
},
"Location": {
"type": "string"
},
"Pragma": {
"type": "string"
}
},
"type": "object"
},
"statusCode": {
"type": "integer"
}
},
"type": "object"
}
},
"runAfter": {
"Query_NEST_to_find_the_redirected_URL": [
"Failed"
]
},
"type": "ParseJson"
},
"Parse_JSON_2": {
"inputs": {
"content": "@body(‘Parse_JSON’)",
"schema": {
"properties": {
"Access-Control-Allow-Origin": {
"type": "string"
},
"Cache-Control": {
"type": "string"
},
"Connection": {
"type": "string"
},
"Content-Length": {
"type": "string"
},
"Content-Type": {
"type": "string"
},
"Location": {
"type": "string"
},
"Pragma": {
"type": "string"
}
},
"type": "object"
}
},
"runAfter": {
"Parse_JSON": [
"Succeeded"
]
},
"type": "ParseJson"
},
"Query_NEST_devices_(no_redirect)": {
"inputs": {
"headers": {
"Authorization": "Bearer @{variables(‘NESTAuth’)}",
"Content-Type": "application/json"
},
"method": "GET",
"uri": "https://developer-api.nest.com"
},
"runAfter": {
"Query_NEST_to_find_the_redirected_URL": [
"Succeeded"
]
},
"type": "Http"
},
"Query_NEST_devices_(redirect)": {
"inputs": {
"headers": {
"Authorization": "Bearer @{variables(‘NESTAuth’)}",
"Content-Type": "application/json"
},
"method": "GET",
"uri": "@body(‘Parse_JSON_2’)?[‘Location’]"
},
"runAfter": {
"Parse_JSON_2": [
"Succeeded"
]
},
"type": "Http"
},
"Query_NEST_to_find_the_redirected_URL": {
"inputs": {
"headers": {
"Authorization": "Bearer @{variables(‘NESTAuth’)}",
"Content-Type": "application/json"
},
"method": "GET",
"uri": "https://developer-api.nest.com"
},
"runAfter": {
"Set_variable": [
"Succeeded"
]
},
"type": "Http"
},
"Set_variable": {
"inputs": {
"name": "NESTAuth",
"value": "&lt;***ADD YOUR AUTH HERE FOR NEST***&gt;"
},
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "SetVariable"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"Recurrence": {
"recurrence": {
"frequency": "Month",
"interval": 1,
"timeZone": "Central Standard Time"
},
"type": "Recurrence"
}
}
},
"parameters": {}
}
&nbsp;
[/code]