[Release] Tado (Connect)

This is how I have changed mine to poll users every 15 seconds while the system state is every 30 seconds.
Not sure if this helps.

// Schedule it to run every 5 minutes
//	runEvery5Minutes("poll")
//    runEvery5Minutes("userPoll")
    schedule("5/30 * * * * ? *", "poll")
    schedule("5/15 * * * * ? *", "userPoll")
}

You could change my example to...
image

Hi. I have tado connect since 2 years aprox. I update my hubitat and now it isn´t works. I don´t know what happend. I try to update the app driver. I can´t do it because it reports error on line 39. anyone can help me please? thanks in advance

i have installed: c7 hubitat with 2.3.8.120 and v2.8 tado connect version

Hi,

I've installed Tado Connect and the drivers from Bibbleq repo but when I attempt to authenticate the app with Tado I'm getting Bad Tado Creds error message. OAuth is enabled for the app.

Any ideas? Thanks

Have you entered Client ID and Client Secret correct?
You can use
Client ID: public-api-preview
Client Secret: 4HJGRffVR8xb3XdEUQpjgZ1VplJi6Xgw
See post nr 71 (Nov 2023)

Thanks for the reply. I had missed that completely. Can you confirm where exactly I should put these? I'm not familiar with groovy so a bit unsure here. Thanks in advance

After you have inserted the app code and drivers. Go to "Apps" - add user app - Choose Tado Connect

In the next screen you can put the Client ID, Client Secret and your username and password.

Thanks. In the version from the @Bibbleq repo it doesn't prompt me for the Oauth details

I've installed the alternate version from @user3860 and now get the same as your screenshot.

Thanks for the help

Hi, I installed the app and drivers from the @Bibbleq repo earlier this week and got the same problem as @echoes675, so following his example I replaced the app code with that of @user3860.

Now Tado is connected to my HE, and I can see all my Thermostats and TRVs which is great.

However, the devices in HE soon get out of sync with the Tado devices, and this is causing me a problem. I wanted to use the Tado thermostats to control the Zigbee switch controlling the electric towel radiator in the shower room. The Tado stat controls the underfloor heating, but the radiator is set in HE to come on for a couple of hours a day, my intention was to turn off the towel rad if the room temperature exceeded the Tado setpoint. I used HE's built-in Rule Machine 5.1 to create the automation. I only read data from the Tado devices and don't use HE to update TADO.

There are 2 problems that I can see.

  • Randomly the HE device representing the Tado thermostat, stops reporting the current temperature and remains at a constant temperature. Hitting refresh or poll on the HE device has no effect. Sometimes all the devices are reporting the wrong temperature, and sometimes it is only 1 or 2 out of 9 devices that are wrong.

  • The HE device gets locked in the Heating state and won't reset.

Reinitialisng the Tado Connect HE app seems to resolve the temperature reading (for a while) but the Heating state won't reset. I have also tried forcing state changes from Tado's app to see if that will force a change in the HE device state, but again no effect. My heating dashboard in HE constantly shows every room as heating even though the temperatures all exceed the set points.

It is impractical to have to remove and reinstall the Tado Connect app in HE.

Any help would be greatly appreciated.

In response to my previous post, I think I can see what is causing the problem with the HE device being stuck in Heating mode.

If the Tado device is running a schedule with a setpoint say a setback temp of 10degC and the room is at say 18degC; the Tado device has a state of Power ON. If the device is in 'Frost Protection' mode, the Power is OFF. The current state of whether the device is Heating seems to depend on the ActivityDataPoints - Heating Power element. I have included a sample from a call to /API/v2/homes/{homeId}/zones/{zoneId}/state to illustrate this; see below.

{
   "tadoMode": "HOME",
   "geolocationOverride": false,
   "geolocationOverrideDisableTime": null,
   "preparation": null,
   "setting":    {
      "type": "HEATING",
      "power": "ON",
      "temperature":       {
         "celsius": 10,
         "fahrenheit": 50
      }
   },
   "overlayType": null,
   "overlay": null,
   "openWindow": null,
   "nextScheduleChange":    {
      "start": "2024-04-17T15:00:00Z",
      "setting":       {
         "type": "HEATING",
         "power": "ON",
         "temperature":          {
            "celsius": 18,
            "fahrenheit": 64.4
         }
      }
   },
   "nextTimeBlock": {"start": "2024-04-17T15:00:00.000Z"},
   "link": {"state": "ONLINE"},
   "activityDataPoints": {"heatingPower":    {
      "type": "PERCENTAGE",
      "percentage": 0,
      "timestamp": "2024-04-17T09:49:24.921Z"
   }},
   "sensorDataPoints":    {
      "insideTemperature":       {
         "celsius": 18.38,
         "fahrenheit": 65.08,
         "timestamp": "2024-04-17T09:43:36.450Z",
         "type": "TEMPERATURE",
         "precision":          {
            "celsius": 0.1,
            "fahrenheit": 0.1
         }
      },
      "humidity":       {
         "type": "PERCENTAGE",
         "percentage": 48.9,
         "timestamp": "2024-04-17T09:43:36.450Z"
      }
   }
}

This does not resolve the other issue of devices randomly freezing the reported temperature.

I received a message from Tado that from March 21, 2025 the connection via Tado (Connect) would no longer be possible.

Their message that I received:

We’ve noticed that you’re using the unofficial tado° REST API with the password grant flow and the clients ‘tado-web-app’ or ‘public-api-preview’.

To meet strict security standards, we haven’t used the password grant flow in any official tado° applications for a while and we’ll be removing access to it on 21 March 2025.

If you’ve written your own software, we’ve provided an alternative method of authentication, please check out our article for details.
We’ve already informed Home Assistant and python-tado, the largest open-source software systems using this authentication method, and they’ve confirmed that they'll provide an update by the deadline. If you’re using any other open-source or commercial home automation software, we recommend reaching out to them directly.

Their alternative method: https://support.tado.com/en/articles/8565472-how-do-i-authenticate-to-access-the-rest-api

This is way too technical for me :pensive:.
Does anyone have an idea what needs to be done?

3 Likes

Oh shxt.
Mine stopped working today.
Could it be because of this? Most probably....
I didn't receive an email I bet it's related.

1 Like

Indeed. As of today, my Tado no longer works with Hubitat.

I really hope there is someone here with more knowledge than me to find a solution with Tado's “alternative method”.

Same here. Anyone find a solution?

1 Like

I just raised this in a hope someone can help, mines broken too and I'm missing the integration :slight_smile:

2 Likes

@Fuzzyligic Are you still maintaining this code? Can you help us here?

Same issue, so thanks for sharing the e-mail with link to the updated authentication details. I have it a try, and the version below seems to be working (have been working for roughly 24 hours for me). I get some errors in the log from time to time when refreshing the access token, but seems to be running through these errors.

Also did some work on the logs, and added a debug log flag in the settings, to allow disabling the many details in the log (which are usefull when analyzing errors etc.).

I installed it side-by-side with the old one, so didn't test replacing the old code. You could try that, and it might work and re-establish the connection. Otherwise please install a seperate app and install that one. The name is the same as the old app, so you might want to change the name of the old one (in the code) to distinguish between the two.

Code is too long to paste in one reply here (and I'm not up and running on GitHub), so please copy the code parts below into one app.

Code part 1/2:

/**
 *  Tado Connect
 *
 *  Copyright 2016 Stuart Buchanan
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 * 22/11/2023 v3.0 Adjusted to Password Grant flow
 * 22/11/2023 v2.9 Adjusted to OAuth 2 authentication flow
 * 27/04/2018 v2.8 fixed issue with null values when trying to retrieve current setpoint when null as the try and catch arent working as expected.
 * 27/04/2018 v2.7 Modified for Hubitat
 * 07/02/2018 v2.7 Added some new try catch blocks around parse capability as there were exceptioons after v2.1 occuring for air conditioners, this now works correctly
 * 06/02/2018 v2.6 Fixed Commands for those with Heat Cool that do not support Fan Modes
 * 08/06/2017 v2.5 Amended bug where Hot water type was set to WATER, Instead or HOT_WATER, with thanks to @invisiblemountain
 * 08/06/2017 v2.4 Added Device name to DNI, trying to avaid issue with multiple devices in a single Zone
 * 26/05/2017 v2.3 removed erronous jsonbody statements in the coolCommand Function.
 * 26/05/2017 v2.2 Corrected bug with parseCapability function as this was returning the map instead of the value, this would account for lots of strange behaviour.
 * 25/05/2017 v2.1 Added support for Air Condiioners which have a mandatory swing field for all Commands, corrected prevois bugs in v2.0, thanks again to @Jnick
 * 20/05/2017 v2.0 Added support for Air Condiioners which have a mandatory swing field in the heating & cool Commands, thanks again to @Jnick
 * 17/05/2017 v1.9 Corrected issue with the wrong temp unit being used on some thermostat functions when using Farenheit, many thanks again to @Jnick for getting the logs to help diagnose this.
 * 04/05/2017 v1.8 Corrected issue with scheduling which was introduced in v1.7 with merge of pull request. Many thanks to @Jnick for getting the logs to help diagnose this.
 * 17/04/2017 v1.7 General Bugfixes around Tado user presence with thanks to @sipuncher
 * 14/04/2017 v1.6 fixed defects in user presence device polling
 * 06/04/2017 v1.5 scheduled refresh of tado user status every minute (Thanks to @sipuncher for pointing out my mistake)
 * 03/04/2017 v1.4 Added ability to have your Tado Users created as Smarthings Virtual Presence Sensors for use in routines etc..
 * 03/01/2017 v1.3 Corrected Cooling Commands and Set Points issue with incorrect DNI statement with thanks to Richard Gregg
 * 03/12/2016 v1.2 Corrected Values for Heating and Hot Water set Points
 * 03/12/2016 v1.1 Updated to Support Multiple Hubs, and fixed bug in device discovery and creation, however all device types need updated also.
 * 26/11/2016 V1.0 initial release
 */

import java.text.DecimalFormat
import groovy.json.JsonSlurper
import groovy.json.JsonOutput

private apiUrl() 			{ "https://my.tado.com" }
private getApiUrl()		    { "https://my.tado.com" }
private getTadoLoginUri()   { "https://login.tado.com" }
private getDeviceCodePath() { "/oauth2/device_authorize" }
private getDeviceTokenPath() { "/oauth2/token" }
private getAccessTokenUri()  { "https://login.tado.com" }
private getAccessTokenPath() { "/oauth2/token" }
private getVendorName() 	{ "Tado" }
private getVendorIcon()		{ "https://dl.dropboxusercontent.com/s/fvjrqcy5xjxsr31/tado_128.png" }
private getVendorAuthPath()	{ "/oauth2/authorize" }
private getVendorTokenPath(){ "https://auth.tado.com/oauth/token" }
private getClientId() 		{ settings.clientId }
private getClientSecret() 	{ settings.clientSecret }
private getRefreshToken()   { state.refreshToken }
private getAccessToken()    { state.accessToken }
private getDebugLogStatus() { settings.debugLog } //Use: On or Off
private getDefaultLogForceSecs() { 600 }
private getCallbackUrl()	{ getServerUrl()+ "/oauth/callback?access_token=${state.accessToken}" }
private getBuildRedirectUrl() { getServerUrl() + "/oauth/initialize?access_token=${state.accessToken}" }
private getServerUrl() 		{ return getFullApiServerUrl() }
private getTokenExpOffset() { 420000 } //Miliseconds offset used from expiriry to refresh of token


 // Automatically generated. Make future change here.
definition(
    name: "Tado (Connect)",
    namespace: "fuzzysb",
    author: "Stuart Buchanan",
    description: "Tado Integration, This SmartApp supports all Tado Products. (Heating Thermostats, Extension Kits, AC Cooling & Radiator Valves.)",
    category: "Heating",
	iconUrl:   "https://dl.dropboxusercontent.com/s/fvjrqcy5xjxsr31/tado_128.png",
	iconX2Url: "https://dl.dropboxusercontent.com/s/jyad58wb28ibx2f/tado_256.png",
	oauth: true,
    singleInstance: false
) {
	appSetting "clientId"
	appSetting "clientSecret"
	appSetting "serverUrl"
}

preferences {
	page(name: "startPage", title: "Tado Integration", content: "startPage", install: false)
	page(name: "Credentials", title: "Enter authentication details", content: "credentialsPage", install: false )
    page(name: "authPage", title: "Tado Authentication Verification", content: "authPage", install: false)
    page(name: "getAccessCodePage", title: "Finalize Tado Authentication Verification", content: "getAccessCodePage", install: false)
	page(name: "mainPage", title: "Tado Integration (API)", content: "mainPage")
	page(name: "completePage", title: "${getVendorName()} is now connected to Hubitat!", content: "completePage")
	page(name: "listDevices", title: "Tado Devices", content: "listDevices", install: false)
    page(name: "listUsers", title: "Tado Users", content: "listUsers", install: false)
	page(name: "advancedOptions", title: "Tado Advanced Options", content: "advancedOptions", install: false)
	page(name: "badCredentials", title: "Invalid Credentials", content: "badAuthPage", install: false)
}
mappings {
	path("/receivedHomeId"){action: [POST: "receivedHomeId", GET: "receivedHomeId"]}
}

def startPage() {
    
    logDebug( "In startPage" )
    
    if ( !getRefreshToken() )
      { return credentialsPage() }
    else if (state.homeId ) 
      { return mainPage() }
    else 
      { return credentialsPage() }
}

def credentialsPage() {
	logDebug( "In credentialsPage" )
    
    //Always force debug log in the authorization flow
    openForcedDebugLog(getDefaultLogForceSecs())
    
    logDebug( "In credentialsPage" )

	def description
	def uninstallAllowed = false
	def clientIdProvided = false
    
    logDebug( "Showing the login page" )
		return dynamicPage(name: "Credentials", title: "Authorize Connection", nextPage:authPage, uninstall: false , install:false) {
			section("Enter Application Details...") {
				paragraph "Field is filled with default Client ID provided by Tado. Please update if needed, or proceed with default Client ID"
                paragraph "Also check https://support.tado.com/en/articles/8565472-how-do-i-authenticate-to-access-the-rest-api for further details"
				input(name: 'clientId', title: 'Client ID', type: 'text', required: true, defaultValue: '1bb50063-6b0c-4d11-bd99-387f4a91cc46')
			}
		}
    
}

def authPage( ) {
	logDebug( "In authPage" )    

    //Always force debug log in the authorization flow
    openForcedDebugLog(getDefaultLogForceSecs())
   
    //Initiate flow and get user code for verification
    initiateDeviceCodeFlow()    
    
    return dynamicPage(name: "Authorize", title: "Authorize with Tado", nextPage:getAccessCodePage, uninstall: false , install:false) {
        section("Follow the steps below, to authorize with Tado:") {
            paragraph "1) Please visit the URL below to authorize your device with your Tado Account:"
            paragraph "     " + " " + state.deviceCodeVerificationUriComplete
            paragraph "     " + " " + "User code should be set automatically. If prompted for a device/user code, please enter:" + " " + state.userCode
            paragraph "2) Once authorized with Tado, please click next"
            paragraph " "
            paragraph "Please authenticate within" + " " + state.deviceCodeExpiresIn + " " + "seconds or restart the process."
        }
    }
    
}
    
def getAccessCodePage( ) {
	logDebug( "In getAccessCodePage" )
    
    def deviceAccessTokenRetreived = getDeviceAccessToken()
    
      if (deviceAccessTokenRetreived) {
      return mainPage()
       } else {
         return badAuthPage()
       }
   }

def mainPage() {
    logDebug( "In mainPage" )

    // Try to get access Token if not available
    if (isAccessTokenExpired()){    
        logDebug( "Access token expired - calling token refresh" )
        refreshToken() }
    
    // Call up credentials flow if access token is still no available (to allow new authentication)
    if (isAccessTokenExpired()){
        logDebug( "Access token expired - calling credentialsPage" )
        return credentialsPage() }
    
  	getidCommand()
    getTempUnitCommand()
  	logDebug( "Logging debug: ${state.homeId}" )
	   if (state.homeId) {
       return completePage()
       } else {
         return badAuthPage()
       }
}

def completePage(){
	def description = "Tap 'Next' to proceed"
			return dynamicPage(name: "completePage", title: "Credentials Accepted!", uninstall:true, install:false,nextPage: listDevices) {
				section { href url: buildRedirectUrl("receivedHomeId"), style:"embedded", required:false, title:"${getVendorName()} is now connected to Hubitat!", description:description }
                section("App preferences") {
      				input("debugLog", "enum", title: "Debug Log", options: ["Off","On"], required: false)
    	}
			}
}

def badAuthPage(){
	logDebug( "In badAuthPage" )    
       		return dynamicPage(name: "badCredentials", title: "Bad Tado Credentials", install:false, uninstall:true, nextPage: Credentials) {
				section("") {
					paragraph "Authentication failed. Please repeat authentication process."
           		}
            }
}

def advancedOptions() {
	logDebug( "In Advanced Options" )
	def options = getDeviceList()
	dynamicPage(name: "advancedOptions", title: "Select Advanced Options", install:true) {
    	section("Default temperatures for thermostat actions. Please enter desired temperatures") {
      	input("defHeatingTemp", "number", title: "Default Heating Temperature?", required: true)
      	input("defCoolingTemp", "number", title: "Default Cooling Temperature?", required: true)
		}
		section("Tado Override Method") {
      	input("manualmode", "enum", title: "Default Tado Manual Overide Method", options: ["TADO_MODE","MANUAL"], required: true)
    	}
        section(){
    		if (getHubID() == null){
        		input(
            		name		: "myHub"
            		,type		: "hub"
            		,title		: "Select your hub"
            		,multiple		: false
            		,required		: true
            		,submitOnChange	: true
        		)
     		} else {
        		paragraph("Tap done to finish the initial installation.")
     		}
		}
        section("App preferences") {
      	input("debugLog", "enum", title: "Debug Log", options: ["Off","On"], required: false, default: "Off")
    	}
    }
}

def listDevices() {
	logDebug( "In listDevices" )
	def options = getDeviceList()
	dynamicPage(name: "listDevices", title: "Choose devices", install:false, uninstall:true, nextPage: listUsers) {
		section("Devices") {
			input "devices", "enum", title: "Select Device(s)", required: false, multiple: true, options: options, submitOnChange: true
		}
	}
}

def listUsers() {
	logDebug( "In listUsers" )
	def options = getUserList()
	dynamicPage(name: "listUsers", title: "Choose users you wish to create a Virtual Smarthings Presence Sensors for", install:false, uninstall:true, nextPage: advancedOptions) {
		section("Users") {
			input "users", "enum", title: "Select User(s)", required: false, multiple: true, options: options, submitOnChange: true
		}
	}
}

//def getToken(){
//  if (!state.accessToken) {
//		try {
//			getAccessToken()
//			DEBUG("Creating new Access Token: $state.accessToken")
//		} catch (ex) {
//			DEBUG("Did you forget to enable OAuth in SmartApp IDE settings")
//            DEBUG(ex)
//		}
//	}
//}

def receivedHomeId() {
	logDebug( "In receivedToken" )

	def html = """
        <!DOCTYPE html>
        <html>
        <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>${getVendorName()} Connection</title>
        <style type="text/css">
            * { box-sizing: border-box; }
            @font-face {
                font-family: 'Swiss 721 W01 Thin';
                src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.eot');
                src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.eot?#iefix') format('embedded-opentype'),
                     url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.woff') format('woff'),
                     url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.ttf') format('truetype'),
                     url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.svg#swis721_th_btthin') format('svg');
                font-weight: normal;
                font-style: normal;
            }
            @font-face {
                font-family: 'Swiss 721 W01 Light';
                src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.eot');
                src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.eot?#iefix') format('embedded-opentype'),
                     url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.woff') format('woff'),
                     url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.ttf') format('truetype'),
                     url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.svg#swis721_lt_btlight') format('svg');
                font-weight: normal;
                font-style: normal;
            }
            .container {
                width: 560px;
                padding: 40px;
                /*background: #eee;*/
                text-align: center;
            }
            img {
                vertical-align: middle;
            }
            img:nth-child(2) {
                margin: 0 30px;
            }
            p {
                font-size: 2.2em;
                font-family: 'Swiss 721 W01 Thin';
                text-align: center;
                color: #666666;
                margin-bottom: 0;
            }
        /*
            p:last-child {
                margin-top: 0px;
            }
        */
            span {
                font-family: 'Swiss 721 W01 Light';
            }
        </style>
        </head>
        <body>
            <div class="container">
                <img src=""" + getVendorIcon() + """ alt="Vendor icon" />
                <img src="https://s3.amazonaws.com/smartapp-icons/Partner/support/connected-device-icn%402x.png" alt="connected device icon" />
                <img src="https://cdn.shopify.com/s/files/1/2575/8806/t/20/assets/logo-image-file.png" alt="Hubitat logo" />
                <p>Tap 'Done' to continue to Devices.</p>
			</div>
        </body>
        </html>
        """
	render contentType: 'text/html', data: html
}

def buildRedirectUrl(endPoint) {
	logDebug( "In buildRedirectUrl" )
	logDebug( "returning: " + getServerUrl() + "/${hubUID}/apps/${app.id}/${endPoint}?access_token=${state.accessToken}")
	return getServerUrl() + "/${hubUID}/apps/${app.id}/${endPoint}?access_token=${state.accessToken}"
}

def getDeviceList() {
  def TadoDevices = getZonesCommand()
  return TadoDevices.sort()
}

def getUserList() {
  def TadoUsers = getMobileDevicesCommand()
  return TadoUsers.sort()
}

def installed() {
	logDebug( "Installed with settings: ${settings}" )
	initialize()
}

def updated() {
	logDebug( "Updated with settings: ${settings}" )
  	unsubscribe()
	unschedule()
	initialize()
}

def uninstalled() {
  logDebug( "Uninstalling Tado (Connect)" )
  revokeAccessToken()
  removeChildDevices(getChildDevices())
  log.debug "Tado (Connect) Uninstalled"
}

def initialize() {
	logDebug( "Initialized with settings: ${settings}" )
	// Pull the latest device info into state
	getDeviceList();
    def children = getChildDevices()
    if(settings.devices) {
    	settings.devices.each { device ->
        logDebug( "Devices Inspected ${device.inspect()}" )
		def item = device.tokenize('|')
        def deviceType = item[0]
        def deviceId = item[1]
        def deviceName = item[2]
        def existingDevices = children.find{ d -> d.deviceNetworkId.contains(deviceId + "|" + deviceType) }
        logDebug( "existingDevices Inspected ${existingDevices.inspect()}" )
    	if(!existingDevices) {
          logDebug( "Some Devices were not found....creating Child Device ${deviceName}" )
          try {
            if (deviceType == "HOT_WATER")
            {
              logDebug( "Creating Hot Water Device ${deviceName}" )
              createChildDevice("Tado Hot Water Control", deviceId + "|" + deviceType + "|" + now() + "|" + devicename, "${deviceName}", deviceName)
            }
            if (deviceType == "HEATING")
            {
              logDebug( "Creating Heating Device ${deviceName}" )
              createChildDevice("Tado Heating Thermostat", deviceId + "|" + deviceType + "|" + now() + "|" + devicename, "${deviceName}", deviceName)
            }
            if (deviceType == "AIR_CONDITIONING")
            {
              logDebug( "Creating Air Conditioning Device ${deviceName}" )
              createChildDevice("Tado Cooling Thermostat", deviceId + "|" + deviceType + "|" + now() + "|" + devicename, "${deviceName}", deviceName)
            }
 			} catch (Exception e) 
            {
					log.error "Error creating device: ${e}"
			}
    		}
		}
    }
    
    getUserList();
       if(settings.users) {
    	settings.users.each { user ->
        logDebug( "Devices Inspected ${user.inspect()}" )
		def item = user.tokenize('|')
        def userId = item[0]
        def userName = item[1]
        def existingUsers = children.find{ d -> d.deviceNetworkId.contains(userId + "|" + userName) }
        logDebug( "existingUsers Inspected ${existingUsers.inspect()}" )
    	if(!existingUsers) {
          logDebug( "Some Users were not found....creating Child presence Device ${userName}" )
          try 
          	{
              createChildDevice("Tado User Presence", userId + "|" + userName + "|" + now(), "${userName}", userName)
 			} catch (Exception e) 
            {
					log.error "Error creating device: ${e}"
			}
    		}
		}
    }
    
    
	// Do the initial poll
    getInititialDeviceInfo()
	
	// Schedule it to run every 5 minutes
	runEvery5Minutes("poll")
    runEvery5Minutes("userPoll")
}

def getInititialDeviceInfo(){
	logDebug( "getInititialDeviceInfo" )
	getDeviceList();
	def children = getChildDevices()
	if(settings.devices) {
    settings.devices.each { device ->
      logDebug( "Devices Inspected ${device.inspect()}" )
      def item = device.tokenize('|')
      def deviceType = item[0]
      def deviceId = item[1]
      def deviceName = item[2]
      def existingDevices = children.find{ d -> d.deviceNetworkId.contains(deviceId + "|" + deviceType) }
      if(existingDevices) {
        existingDevices.getInitialDeviceinfo()
      }
	   }
  }

}
def getHubID(){
	def hubID
    if (myHub){
        hubID = myHub.id
    } else {
        logDebug( "hub type is ${location.hubs[0].type}" )
        def hubs = location.hubs.findAll{ it.type == "PHYSICAL" } 
        if (hubs.size() == 1){
            hubID = hubs[0].id
        }
    }
    logDebug( "Returning Hub ID: ${hubID}" )
    return hubID
}

def poll() {
	logDebug( "In Poll" )
	getDeviceList();
  def children = getChildDevices()
  if(settings.devices) {
    settings.devices.each { device ->
      logDebug( "Devices Inspected ${device.inspect()}" )
      def item = device.tokenize('|')
      def deviceType = item[0]
      def deviceId = item[1]
      def deviceName = item[2]
      def existingDevices = children.find{ d -> d.deviceNetworkId.contains(deviceId + "|" + deviceType) }
      if(existingDevices) {
        existingDevices.poll()
      }
	}
  }
}

def userPoll() {
	logDebug( "In UserPoll" )
    def children = getChildDevices();
    if(settings.users) {
    	settings.users.each { user ->
    		logDebug( "Devices Inspected ${user.inspect()}" )
			def item = user.tokenize('|')
        	def userId = item[0]
        	def userName = item[1]
        	def existingUsers = children.find{ d -> d.deviceNetworkId.contains(userId + "|" + userName) }
        	logDebug( "existingUsers Inspected ${existingUsers.inspect()}" )
    		if(existingUsers) {
          		existingUsers.poll()
        	}
     	}
   }
}
        
def createChildDevice(deviceFile, dni, name, label) {
	logDebug( "In createChildDevice" )
    try{
		def childDevice = addChildDevice("fuzzysb", deviceFile, dni, getHubID(), [name: name, label: label, completedSetup: true])
	} catch (e) {
		log.error "Error creating device: ${e}"
	}
}

private sendCommand(method,childDevice,args = []) {
  def methods = [
		'getid': [
        			uri: apiUrl(),
                    path: "/api/v2/me",
                    requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                    ],
    'gettempunit': [
        			uri: apiUrl(),
                    path: "/api/v2/homes/${state.homeId}",
                    requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                    ],
    'getzones': [
             uri: apiUrl(),
                    path: "/api/v2/homes/" + state.homeId + "/zones",
                    requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                    ],
	'getMobileDevices': [
             uri: apiUrl(),
                    path: "/api/v2/homes/" + state.homeId + "/mobileDevices",
                    requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                    ],
    'getcapabilities': [
        			uri: apiUrl(),
                    path: "/api/v2/homes/" + state.homeId + "/zones/" + args[0] + "/capabilities",
                    requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                    ],
    'status': [
        			uri: apiUrl(),
                    path: "/api/v2/homes/" + state.homeId + "/zones/" + args[0] + "/state",
                    requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                    ],
	'userStatus': [
             		uri: apiUrl(),
                    path: "/api/v2/homes/" + state.homeId + "/mobileDevices",
                    requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                    ],
	'temperature': [
        			uri: apiUrl(),
        			path: "/api/v2/homes/" + state.homeId + "/zones/" + args[0] + "/overlay",
        			requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ],
                  	body: args[1]
                   	],
	'weatherStatus': [
        			uri: apiUrl(),
        			path: "/api/v2/homes/" + state.homeId + "/weather",
        			requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                   	],
    'deleteEntry': [
        			uri: apiUrl(),
        			path: "/api/v2/homes/" + state.homeId + "/zones/" + args[0] + "/overlay",
        			requestContentType: "application/json",
                    headers: ["Authorization": "Bearer " + state.accessToken ]
                   	]
	]
    
	def request = methods.getAt(method)    
        if(refreshAccessToken()) {
		    refreshToken();
	    }
      logDebug( "Http Params ("+request+")" )
      try{
        logDebug( "Executing 'sendCommand' for method" + " " + method )
          if (method == "getid"){
            httpGet(request) { resp ->
                parseMeResponse(resp)
            }
          }else if (method == "gettempunit"){
            httpGet(request) { resp ->
                parseTempResponse(resp)
            }
          }else if (method == "getzones"){
            httpGet(request) { resp ->
                parseZonesResponse(resp)
            }
          }else if (method == "getMobileDevices"){
            httpGet(request) { resp ->
                parseMobileDevicesResponse(resp)
            }
       	  }else if (method == "getcapabilities"){
            httpGet(request) { resp ->
                parseCapabilitiesResponse(resp,childDevice)
            }
          }else if (method == "status"){
            httpGet(request) { resp ->
                parseResponse(resp,childDevice)
            }
          }else if (method == "userStatus"){
            httpGet(request) { resp ->
                parseUserResponse(resp,childDevice)
            }
		  }else if (method == "temperature"){
            httpPut(request) { resp ->
                parseputResponse(resp,childDevice)
            }
          }else if (method == "weatherStatus"){
            logDebug( "calling weatherStatus Method" )
            httpGet(request) { resp ->
                parseweatherResponse(resp,childDevice)
            }
          }else if (method == "deleteEntry"){
            httpDelete(request) { resp ->
                parsedeleteResponse(resp,childDevice)
            }
        }else{
            httpGet(request)
        }
    } catch(Exception e){
        log.error("Exception: " + e)
    }
}

// Parse incoming device messages to generate events
private parseMeResponse(resp) {
    logDebug( "Executing parseMeResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
    if(resp.status == 200) {
    	logDebug( "Executing parseMeResponse.successTrue")
        state.homeId = resp.data.homes[0].id
        logDebug( "Got HomeID Value: " + state.homeId)

    }else if(resp.status == 201){
        logDebug( "Something was created/updated")
    }
}

private parseputResponse(resp,childDevice) {
	logDebug( "Executing parseputResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
}

private parsedeleteResponse(resp,childDevice) {
	logDebug( "Executing parsedeleteResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
}

private parseUserResponse(resp,childDevice) {
  	def item = (childDevice.device.deviceNetworkId).tokenize('|')
  	def userId = item[0]
  	def userName = item[1]
    logDebug( "Executing parseUserResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
    if(resp.status == 200) {
      def restUsers = resp.data
      logDebug( "Executing parseUserResponse.successTrue")
      logDebug( "UserId is ${userId} and userName is ${userName}")
      for (TadoUser in restUsers) {
      	logDebug( "TadoUserId is ${TadoUser.id}")
      	if ((TadoUser.id).toString() == (userId).toString())
        {
         logDebug( "Entering presence Assesment for User Id: ${userId}")
         if (TadoUser.settings.geoTrackingEnabled == true)
         {
         	logDebug( "GeoTracking is Enabled for User Id: ${userId}")
        	if (TadoUser.location.atHome == true)
            {	
            	logDebug( "Send presence Home Event Fired")
               	childDevice?.sendEvent(name:"presence",value: "present")
            } else if (TadoUser.location.atHome == false)
            {
            	logDebug( "Send presence Away Event Fired")
            	childDevice?.sendEvent(name:"presence",value: "not present")
            }
        }
            
        }
      }
    } else if(resp.status == 201){
        logDebug( "Something was created/updated")
    }
}

private parseResponse(resp,childDevice) {
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  if (deviceType == "AIR_CONDITIONING")
  {
    logDebug( "Executing parseResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
    def temperatureUnit = state.tempunit
    logDebug( "Temperature Unit is ${temperatureUnit}")
    def humidityUnit = "%"
    def ACMode
    def ACFanSpeed
    def ACFanMode = "off"
    def thermostatSetpoint
    def tOperatingState
    if(resp.status == 200) {
        logDebug( "Executing parseResponse.successTrue")
        def temperature
        if (temperatureUnit == "C") {
        	temperature = (Math.round(resp.data.sensorDataPoints.insideTemperature.celsius *10 ) / 10)
        }
        else if(temperatureUnit == "F"){
        	temperature = (Math.round(resp.data.sensorDataPoints.insideTemperature.fahrenheit * 10) / 10)
        }
        logDebug( "Read temperature: " + temperature)
        childDevice?.sendEvent(name:"temperature",value:temperature,unit:temperatureUnit)
        logDebug( "Send Temperature Event Fired")
        def autoOperation = "OFF"
        if(resp.data.overlayType == null){
        	autoOperation = resp.data.tadoMode
        }
        else if(resp.data.overlayType == "NO_FREEZE"){
        	autoOperation = "OFF"
        }else if(resp.data.overlayType == "MANUAL"){
        	autoOperation = "MANUAL"
        }
        logDebug( "Read tadoMode: " + autoOperation)
        childDevice?.sendEvent(name:"tadoMode",value:autoOperation)
        logDebug( "Send thermostatMode Event Fired")

        def humidity
        if (resp.data.sensorDataPoints.humidity.percentage != null){
        	humidity = resp.data.sensorDataPoints.humidity.percentage
        }else{
        	humidity = "--"
        }
        logDebug( "Read humidity: " + humidity)
        childDevice?.sendEvent(name:"humidity",value:humidity,unit:humidityUnit)

    	if (resp.data.setting.power == "OFF"){
            tOperatingState = "idle"
            ACMode = "off"
            ACFanMode = "off"
            logDebug( "Read thermostatMode: " + ACMode)
            ACFanSpeed = "OFF"
            logDebug( "Read tadoFanSpeed: " + ACFanSpeed)
            thermostatSetpoint = "--"
            logDebug( "Read thermostatSetpoint: " + thermostatSetpoint)
      }
      else if (resp.data.setting.power == "ON"){
        ACMode = (resp.data.setting.mode).toLowerCase()
        logDebug( "thermostatMode: " + ACMode)
        ACFanSpeed = resp.data.setting.fanSpeed
        if (ACFanSpeed == null) {
          ACFanSpeed = "--"
        }
        if (resp.data.overlay != null){
          if (resp.data.overlay.termination.type == "TIMER"){
            if (resp.data.overlay.termination.durationInSeconds == "3600"){
              ACMode = "emergency heat"
              logDebug( "thermostatMode is heat, however duration shows the state is: " + ACMode)
            }
          }
        }
            switch (ACMode) {
				case "off":
        			tOperatingState = "idle"
        		break
    			case "heat":
        			tOperatingState = "heating"
        		break
    			case "emergency heat":
        			tOperatingState = "heating"
        		break
        		case "cool":
        			tOperatingState = "cooling"
        		break
                case "dry":
        			tOperatingState = "drying"
        		break
                case "fan":
        			tOperatingState = "fan only"
        		break
                case "auto":
        			tOperatingState = "heating|cooling"
        		break
			}
            logDebug( "Read thermostatOperatingState: " + tOperatingState)
        	logDebug( "Read tadoFanSpeed: " + ACFanSpeed)

        if (ACMode == "dry" || ACMode == "auto" || ACMode == "fan"){
        	thermostatSetpoint = "--"
        }else if(ACMode == "fan") {
        	ACFanMode = "auto"
        }else{
       		if (temperatureUnit == "C") {
        		thermostatSetpoint = Math.round(resp.data.setting.temperature.celsius)
        	}
        	else if(temperatureUnit == "F"){
        		thermostatSetpoint = Math.round(resp.data.setting.temperature.fahrenheit)
        	}
        }
        logDebug( "Read thermostatSetpoint: " + thermostatSetpoint)
      }
    }else{
        logDebug( "Executing parseResponse.successFalse")
    }
    childDevice?.sendEvent(name:"thermostatOperatingState",value:tOperatingState)
    logDebug( "Send thermostatOperatingState Event Fired")
    childDevice?.sendEvent(name:"tadoFanSpeed",value:ACFanSpeed)
    logDebug( "Send tadoFanSpeed Event Fired")
    childDevice?.sendEvent(name:"thermostatFanMode",value:ACFanMode)
    logDebug( "Send thermostatFanMode Event Fired")
    childDevice?.sendEvent(name:"thermostatMode",value:ACMode)
    logDebug( "Send thermostatMode Event Fired")
    childDevice?.sendEvent(name:"thermostatSetpoint",value:thermostatSetpoint,unit:temperatureUnit)
    logDebug( "Send thermostatSetpoint Event Fired")
    childDevice?.sendEvent(name:"heatingSetpoint",value:thermostatSetpoint,unit:temperatureUnit)
    logDebug( "Send heatingSetpoint Event Fired")
    childDevice?.sendEvent(name:"coolingSetpoint",value:thermostatSetpoint,unit:temperatureUnit)
    logDebug( "Send coolingSetpoint Event Fired")
  }
  if (deviceType == "HEATING")
  {
    logDebug( "Executing parseResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
    def temperatureUnit = state.tempunit
    logDebug( "Temperature Unit is ${temperatureUnit}")
    def humidityUnit = "%"
    def ACMode
    def ACFanSpeed
    def thermostatSetpoint
    def tOperatingState
    if(resp.status == 200) {
        logDebug( "Executing parseResponse.successTrue")
        def temperature
        if (temperatureUnit == "C") {
        	temperature = (Math.round(resp.data.sensorDataPoints.insideTemperature.celsius * 10 ) / 10)
        }
        else if(temperatureUnit == "F"){
        	temperature = (Math.round(resp.data.sensorDataPoints.insideTemperature.fahrenheit * 10) / 10)
        }
        logDebug( "Read temperature: " + temperature)
        childDevice?.sendEvent(name: 'temperature', value: temperature, unit: temperatureUnit)
        logDebug( "Send Temperature Event Fired")
        def autoOperation = "OFF"
        if(resp.data.overlayType == null){
        	autoOperation = resp.data.tadoMode
        }
        else if(resp.data.overlayType == "NO_FREEZE"){
        	autoOperation = "OFF"
        }else if(resp.data.overlayType == "MANUAL"){
        	autoOperation = "MANUAL"
        }
        logDebug( "Read tadoMode: " + autoOperation)
        childDevice?.sendEvent(name: 'tadoMode', value: autoOperation)

		if (resp.data.setting.power == "ON"){
			childDevice?.sendEvent(name: 'thermostatMode', value: "heat")
			childDevice?.sendEvent(name: 'thermostatOperatingState', value: "heating")
			logDebug( "Send thermostatMode Event Fired")
			if (temperatureUnit == "C") {
				thermostatSetpoint = resp.data.setting.temperature.celsius
			}
			else if(temperatureUnit == "F"){
				thermostatSetpoint = resp.data.setting.temperature.fahrenheit
			}
			logDebug( "Read thermostatSetpoint: " + thermostatSetpoint)
		} else if(resp.data.setting.power == "OFF"){
			thermostatSetpoint = "--"
			childDevice?.sendEvent(name: 'thermostatMode', value: "off")
			childDevice?.sendEvent(name: 'thermostatOperatingState', value: "idle")
			logDebug( "Send thermostatMode Event Fired")
		}

        def humidity
        if (resp.data.sensorDataPoints.humidity.percentage != null){
        	humidity = resp.data.sensorDataPoints.humidity.percentage
        }else{
        	humidity = "--"
        }
        logDebug( "Read humidity: " + humidity)

        childDevice?.sendEvent(name: 'humidity', value: humidity,unit: humidityUnit)

	}

	else{
        logDebug( "Executing parseResponse.successFalse")
    }

    childDevice?.sendEvent(name: 'thermostatSetpoint', value: thermostatSetpoint, unit: temperatureUnit)
    logDebug( "Send thermostatSetpoint Event Fired")
    childDevice?.sendEvent(name: 'heatingSetpoint', value: thermostatSetpoint, unit: temperatureUnit)
    logDebug( "Send heatingSetpoint Event Fired")
  }
  if (deviceType == "HOT_WATER")
  {
    logDebug( "Executing parseResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
    def temperatureUnit = state.tempunit
    logDebug( "Temperature Unit is ${temperatureUnit}")
    def humidityUnit = "%"
    def ACMode
    def ACFanSpeed
    def thermostatSetpoint
    def tOperatingState
    if(resp.status == 200) {
    logDebug( "Executing parseResponse.successTrue")
    def temperature
    if (state.supportsWaterTempControl == "true" && resp.data.tadoMode != null && resp.data.setting.power != "OFF"){
    if (temperatureUnit == "C") {
      temperature = (Math.round(resp.data.setting.temperature.celsius * 10 ) / 10)
    }
    else if(temperatureUnit == "F"){
      temperature = (Math.round(resp.data.setting.temperature.fahrenheit * 10) / 10)
    }
    logDebug( "Read temperature: " + temperature)
    childDevice?.sendEvent(name: 'temperature', value: temperature, unit: temperatureUnit)
    logDebug( "Send Temperature Event Fired")
    } else {
      childDevice?.sendEvent(name: 'temperature', value: "--", unit: temperatureUnit)
      logDebug( "Send Temperature Event Fired")
    }
    def autoOperation = "OFF"
    if(resp.data.overlayType == null){
      autoOperation = resp.data.tadoMode
    }
    else if(resp.data.overlayType == "NO_FREEZE"){
      autoOperation = "OFF"
    }else if(resp.data.overlayType == "MANUAL"){
      autoOperation = "MANUAL"
    }
    logDebug( "Read tadoMode: " + autoOperation)
    childDevice?.sendEvent(name: 'tadoMode', value: autoOperation)

    if (resp.data.setting.power == "ON"){
      childDevice?.sendEvent(name: 'thermostatMode', value: "heat")
      childDevice?.sendEvent(name: 'thermostatOperatingState', value: "heating")
      logDebug( "Send thermostatMode Event Fired")
      } else if(resp.data.setting.power == "OFF"){
        childDevice?.sendEvent(name: 'thermostatMode', value: "off")
        childDevice?.sendEvent(name: 'thermostatOperatingState', value: "idle")
        logDebug( "Send thermostatMode Event Fired")
      }
      logDebug( "Send thermostatMode Event Fired")
      if (state.supportsWaterTempControl == "true" && resp.data.tadoMode != null && resp.data.setting.power != "OFF"){
        if (temperatureUnit == "C") {
          thermostatSetpoint = resp.data.setting.temperature.celsius
        }
        else if(temperatureUnit == "F"){
          thermostatSetpoint = resp.data.setting.temperature.fahrenheit
        }
        logDebug( "Read thermostatSetpoint: " + thermostatSetpoint)
        } else {
          thermostatSetpoint = "--"
        }
      }

      else{
        logDebug( "Executing parseResponse.successFalse")
      }

      childDevice?.sendEvent(name: 'thermostatSetpoint', value: thermostatSetpoint, unit: temperatureUnit)
      logDebug( "Send thermostatSetpoint Event Fired")
      childDevice?.sendEvent(name: 'heatingSetpoint', value: thermostatSetpoint, unit: temperatureUnit)
      logDebug( "Send heatingSetpoint Event Fired")
  }
}

private parseTempResponse(resp) {
    logDebug( "Executing parseTempResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
    if(resp.status == 200) {
    	logDebug( "Executing parseTempResponse.successTrue")
        def tempunitname = resp.data.temperatureUnit
        if (tempunitname == "CELSIUS") {
        	logDebug( "Setting Temp Unit to C")
        	state.tempunit = "C"
        }
        else if(tempunitname == "FAHRENHEIT"){
        	logDebug( "Setting Temp Unit to F")
        	state.tempunit = "F"
        }
    }else if(resp.status == 201){
        logDebug( "Something was created/updated")
    }
}

private parseZonesResponse(resp) {
    logDebug( "Executing parseZonesResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
    if(resp.status == 200) {
      def restDevices = resp.data
      def TadoDevices = []
      logDebug( "Executing parseZoneResponse.successTrue")
      restDevices.each { Tado -> TadoDevices << ["${Tado.type}|${Tado.id}|${Tado.name}":"${Tado.name}"] }
      logDebug( TadoDevices)
      return TadoDevices
    }else if(resp.status == 201){
        logDebug( "Something was created/updated")
    }
}

private parseMobileDevicesResponse(resp) {
    logDebug( "Executing parseMobileDevicesResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
    if(resp.status == 200) {
      def restUsers = resp.data
      def TadoUsers = []
      logDebug( "Executing parseMobileDevicesResponse.successTrue")
      restUsers.each { TadoUser -> 
      	if (TadoUser.settings.geoTrackingEnabled == true)
        {
        	TadoUsers << ["${TadoUser.id}|${TadoUser.name}":"${TadoUser.name}"]
        }
      }
      logDebug(TadoUsers)
      return TadoUsers
    }else if(resp.status == 201){
        logDebug( "Something was created/updated")
    }
}

private parseCapabilitiesResponse(resp,childDevice) {
    logDebug( "Executing parseCapabilitiesResponse: "+resp.data)
    logDebug( "Output status: " + resp.status)
    if(resp.status == 200) {
    	try
      {
    	logDebug( "Executing parseResponse.successTrue")
       	childDevice?.setCapabilitytadoType(resp.data.type)
        logDebug( "Tado Type is ${resp.data.type}")
        if(resp.data.type == "AIR_CONDITIONING")
        {
          try
          {
            if(resp.data.AUTO || (resp.data.AUTO).toString() == "[:]"){
              logDebug( "settingautocapability state true")
              childDevice?.setCapabilitySupportsAuto("true")
            } else {
              logDebug( "settingautocapability state false")
              childDevice?.setCapabilitySupportsAuto("false")
            }
            if(resp.data.AUTO.swings || (resp.data.AUTO.swings).toString() == "[:]")
            {
              logDebug( "settingautoswingcapability state true")
            childDevice?.setCapabilitySupportsAutoSwing("true")
            }
            else
            {
              logDebug( "settingautoswingcapability state false")
              childDevice?.setCapabilitySupportsAutoSwing("false")
            }
          }
          catch(Exception e)
          {
            logDebug( "___exception parsing Auto Capabiity: " + e)
          }
          try
          {
              if(resp.data.COOL || (resp.data.COOL).toString() == "[:]"){
              logDebug( "setting COOL capability state true")
              childDevice?.setCapabilitySupportsCool("true")
                def coolfanmodelist = resp.data.COOL.fanSpeeds
                if(resp.data.COOL.swings || (resp.data.COOL.swings).toString() == "[:]")
                {
                  logDebug( "settingcoolswingcapability state true")
                  childDevice?.setCapabilitySupportsCoolSwing("true")
                }
                else
                {
                  logDebug( "settingcoolswingcapability state false")
                  childDevice?.setCapabilitySupportsCoolSwing("false")
                }
                if(resp.data.COOL.fanSpeeds || (resp.data.COOL.fanSpeeds).toString() == "[:]")
                {
                  childDevice?.setCapabilitySupportsCoolFanSpeed("true")
                }
                else
                {
                  childDevice?.setCapabilitySupportsCoolFanSpeed("false")
                }
                if(coolfanmodelist.find { it == 'AUTO' }){
                  logDebug( "setting COOL Auto Fan Speed capability state true")
                  childDevice?.setCapabilitySupportsCoolAutoFanSpeed("true")
                } else {
                  logDebug( "setting COOL Auto Fan Speed capability state false")
                  childDevice?.setCapabilitySupportsCoolAutoFanSpeed("false")
                }
                if (state.tempunit == "C"){
                  childDevice?.setCapabilityMaxCoolTemp(resp.data.COOL.temperatures.celsius.max)
                  childDevice?.setCapabilityMinCoolTemp(resp.data.COOL.temperatures.celsius.min)
                } else if (state.tempunit == "F") {
                  childDevice?.setCapabilityMaxCoolTemp(resp.data.COOL.temperatures.fahrenheit.max)
                  childDevice?.setCapabilityMinCoolTemp(resp.data.COOL.temperatures.fahrenheit.min)
                }
            } else {
              logDebug( "setting COOL capability state false")
              childDevice?.setCapabilitySupportsCool("false")
            }
          }
          catch(Exception e)
          {
            logDebug( "___exception parsing Cool Capabiity: " + e)
          }
          try
          {
            if(resp.data.DRY || (resp.data.DRY).toString() == "[:]"){
              logDebug( "setting DRY capability state true")
              childDevice?.setCapabilitySupportsDry("true")
            } else {
              logDebug( "setting DRY capability state false")
              childDevice?.setCapabilitySupportsDry("false")
            }
            if(resp.data.DRY.swings || (resp.data.DRY.swings).toString() == "[:]")
            {
              logDebug( "settingdryswingcapability state true")
            childDevice?.setCapabilitySupportsDrySwing("true")
            }
            else
            {
              logDebug( "settingdryswingcapability state false")
              childDevice?.setCapabilitySupportsDrySwing("false")
            }
          }
          catch(Exception e)
          {
            logDebug( "___exception parsing Dry Capabiity: " + e)
          }
          try
          {
            if(resp.data.FAN || (resp.data.FAN).toString() == "[:]"){
              logDebug( "setting FAN capability state true")
              childDevice?.setCapabilitySupportsFan("true")
            } else {
              logDebug( "setting FAN capability state false")
              childDevice?.setCapabilitySupportsFan("false")
            }
            if(resp.data.FAN.swings || (resp.data.FAN.swings).toString() == "[:]")
            {
              logDebug( "settingfanswingcapability state true")
            childDevice?.setCapabilitySupportsFanSwing("true")
            }
            else
            {
              logDebug( "settingfanswingcapability state false")
              childDevice?.setCapabilitySupportsFanSwing("false")
            }
          }
          catch(Exception e)
          {
            logDebug( "___exception parsing Fan Capabiity: " + e)
          }
          try
          {
            if(resp.data.HEAT || (resp.data.HEAT).toString() == "[:]"){
              logDebug( "setting HEAT capability state true")
              childDevice?.setCapabilitySupportsHeat("true")
                def heatfanmodelist = resp.data.HEAT.fanSpeeds
                if(resp.data.HEAT.swings || (resp.data.HEAT.swings).toString() == "[:]")
                {
                  logDebug( "settingheatswingcapability state true")
                  childDevice?.setCapabilitySupportsHeatSwing("true")
                }
                else
                {
                  logDebug( "settingheatswingcapability state false")
                  childDevice?.setCapabilitySupportsHeatSwing("false")
                }
                if(resp.data.HEAT.fanSpeeds || (resp.data.HEAT.fanSpeeds).toString() == "[:]")
                {
                  childDevice?.setCapabilitySupportsHeatFanSpeed("true")
                }
                else
                {
                  childDevice?.setCapabilitySupportsHeatFanSpeed("false")
                }
                if(heatfanmodelist.find { it == 'AUTO' }){
                  logDebug( "setting HEAT Auto Fan Speed capability state true")
                  childDevice?.setCapabilitySupportsHeatAutoFanSpeed("true")
                } else {
                  logDebug( "setting HEAT Auto Fan Speed capability state false")
                  childDevice?.setCapabilitySupportsHeatAutoFanSpeed("false")
                }
                if (state.tempunit == "C"){
                  childDevice?.setCapabilityMaxHeatTemp(resp.data.HEAT.temperatures.celsius.max)
                  childDevice?.setCapabilityMinHeatTemp(resp.data.HEAT.temperatures.celsius.min)
                } else if (state.tempunit == "F") {
                  childDevice?.setCapabilityMaxHeatTemp(resp.data.HEAT.temperatures.fahrenheit.max)
                  childDevice?.setCapabilityMinHeatTemp(resp.data.HEAT.temperatures.fahrenheit.min)
                }
            } else {
              logDebug( "setting HEAT capability state false")
              childDevice?.setCapabilitySupportsHeat("false")
            }
          }catch(Exception e)
          {
            logDebug( "___exception parsing Heat Capabiity: " + e)
          }
        }
        if(resp.data.type == "HEATING")
        {
          if(resp.data.type == "HEATING")
          {
          	logDebug( "setting HEAT capability state true")
          	childDevice?.setCapabilitySupportsHeat("true")
            if (state.tempunit == "C")
            {
              childDevice?.setCapabilityMaxHeatTemp(resp.data.temperatures.celsius.max)
              childDevice?.setCapabilityMinHeatTemp(resp.data.temperatures.celsius.min)
            }
            else if (state.tempunit == "F")
            {
              childDevice?.setCapabilityMaxHeatTemp(resp.data.temperatures.fahrenheit.max)
              childDevice?.setCapabilityMinHeatTemp(resp.data.temperatures.fahrenheit.min)
            }
          }
          else
          {
          	logDebug( "setting HEAT capability state false")
          	childDevice?.setCapabilitySupportsHeat("false")
          }
        }
        if(resp.data.type == "HOT_WATER")
        {
            if(resp.data.type == "HOT_WATER"){
              logDebug( "setting WATER capability state true")
              dchildDevice?.setCapabilitySupportsWater("true")
              if (resp.data.canSetTemperature == true){
                childDevice?.setCapabilitySupportsWaterTempControl("true")
                if (state.tempunit == "C")
                {
                  childDevice?.setCapabilityMaxHeatTemp(resp.data.temperatures.celsius.max)
                  childDevice?.setCapabilityMinHeatTemp(resp.data.temperatures.celsius.min)
                }
                else if (state.tempunit == "F")
                {
                  childDevice?.setCapabilityMaxHeatTemp(resp.data.temperatures.fahrenheit.max)
                  childDevice?.setCapabilityMinHeatTemp(resp.data.temperatures.fahrenheit.min)
                }
              }
              else
              {
                childDevice?.setCapabilitySupportsWaterTempControl("false")
              }
            }
            else
            {
            logDebug( "setting Water capability state false")
            childDevice?.setCapabilitySupportsWater("false")
            }
        }
      }
      catch(Exception e)
      {
        log.error("___exception: " + e)
      }
    }
    else if(resp.status == 201)
    {
      logDebug( "Something was created/updated")
    }
}
3 Likes

Code part 2/2:

private parseweatherResponse(resp,childDevice) {
    logDebug( "Executing parseweatherResponse: "+resp.data)
    logDebug( "Output status: "+resp.status)
	def temperatureUnit = state.tempunit
    logDebug( "Temperature Unit is ${temperatureUnit}")
    if(resp.status == 200) {
    	logDebug( "Executing parseResponse.successTrue")
        def outsidetemperature
        if (temperatureUnit == "C") {
        	outsidetemperature = resp.data.outsideTemperature.celsius
        }
        else if(temperatureUnit == "F"){
        	outsidetemperature = resp.data.outsideTemperature.fahrenheit
        }
        logDebug( "Read outside temperature: " + outsidetemperature)
        childDevice?.sendEvent(name: 'outsidetemperature', value: outsidetemperature, unit: temperatureUnit)
        logDebug( "Send Outside Temperature Event Fired")
        return result

    }else if(resp.status == 201){
        logDebug( "Something was created/updated")
    }
}

def getidCommand(){
	logDebug( "Executing 'sendCommand.getidCommand'" )
	sendCommand("getid",null,[])
}

def getTempUnitCommand(){
	logDebug( "Executing 'sendCommand.getidCommand'" )
	sendCommand("gettempunit",null,[])
}

def getZonesCommand(){
	logDebug( "Executing 'sendCommand.getzones'" )
	sendCommand("getzones",null,[])
}

def getMobileDevicesCommand(){
	logDebug( "Executing 'sendCommand.getMobileDevices'" )
	sendCommand("getMobileDevices",null,[])
}

def weatherStatusCommand(childDevice){
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
	logDebug( "Executing 'sendCommand.weatherStatusCommand'" )
	def result = sendCommand("weatherStatus",childDevice,[deviceId])
}

def getCapabilitiesCommand(childDevice, deviceDNI){
	logDebug("childDevice is: " + childDevice.inspect())
	logDebug("deviceDNI is: " + deviceDNI.inspect())
	def item = deviceDNI.tokenize('|')
	def deviceId = item[0]
	def deviceType = item[1]
	def deviceToken = item[2]
	logDebug("Executing 'sendCommand.getcapabilities'")
	sendCommand("getcapabilities",childDevice,[deviceId])
}

private removeChildDevices(delete) {
	try {
    	delete.each {
        	deleteChildDevice(it.deviceNetworkId)
            log.info "Successfully Removed Child Device: ${it.displayName} (${it.deviceNetworkId})"
    		}
   		}
    catch (e) { log.error "There was an error (${e}) when trying to delete the child device" }
}

def parseCapabilityData(Map results){
  logDebug("in parseCapabilityData")
  def result
  results.each { name, value ->
    
    if (name == "value")
    {
    logDebug("Map Name Returned, ${name} and Value is ${value}")
    result = value.toString()
    logDebug("Result is ${result}")
    //return result
    }
  }
  return result
}

// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Device Commands Below Here
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

def autoCommand(childDevice){
  logDebug("Executing 'sendCommand.autoCommand' on device ${childDevice.device.name}")
  def terminationmode = settings.manualmode
  def traperror
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  if (deviceType == "AIR_CONDITIONING")
  {
    def capabilitySupportsAuto = parseCapabilityData(childDevice.getCapabilitySupportsAuto())
    def capabilitySupportsAutoSwing = parseCapabilityData(childDevice.getCapabilitySupportsAutoSwing())
    def capabilitysupported = capabilitySupportsAuto
    if (capabilitysupported == "true"){
    logDebug("Executing 'sendCommand.autoCommand' on device ${childDevice.device.name}")
    def jsonbody
   	if (capabilitySupportsAutoSwing == "true")
    {
        jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"AUTO", power:"ON", swing:"OFF", type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    } 
    else
    {
      	jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"AUTO", power:"ON", type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    }
    sendCommand("temperature",dchildDevice,[deviceId,jsonbody])
    statusCommand(device)
    } else {
      logDebug("Sorry Auto Capability not supported on device ${childDevice.device.name}")
    }
  }
  if(deviceType == "HEATING")
  {
    def initialsetpointtemp
    if(childDevice.device.currentValue("thermostatSetpoint"))
    {
        traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    }
    else
    {
       logDebug("Existing Setpoint is not set")
       traperror = 0 
    }
    if(traperror == 0){
      initialsetpointtemp = settings.defHeatingTemp
    } else {
    	initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
    }
  	def jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[celsius:initialsetpointtemp], type:"HEATING"], termination:[type:terminationmode]])
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
    statusCommand(childDevice)
  }
  if (deviceType == "HOT_WATER")
  {
    logDebug("Executing 'sendCommand.autoCommand'")
    def initialsetpointtemp
    def jsonbody
    def capabilitySupportsWaterTempControl = parseCapabilityData(childDevice.getCapabilitySupportsWaterTempControl())
    if(capabilitySupportsWaterTempControl == "true"){
    if(childDevice.device.currentValue("thermostatSetpoint"))
    {
        traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    }
    else
    {
       logDebug("Existing Setpoint is not set")
       traperror = 0 
    }
      if(traperror == 0){
        initialsetpointtemp = settings.defHeatingTemp
      } else {
        initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
      }
      jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[celsius:initialsetpointtemp], type:"HOT_WATER"], termination:[type:terminationmode]])
    } else {
      jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", type:"HOT_WATER"], termination:[type:terminationmode]])
    }
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
    statusCommand(childDevice)
  }
}

def dryCommand(childDevice){
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  def capabilitySupportsDry = parseCapabilityData(childDevice.getCapabilitySupportsDry())
  def capabilitySupportsDrySwing = parseCapabilityData(childDevice.getCapabilitySupportsDrySwing())
  def capabilitysupported = capabilitySupportsDry
  if (capabilitysupported == "true"){
  	def terminationmode = settings.manualmode
  	logDebug("Executing 'sendCommand.dryCommand' on device ${childDevice.device.name}")
  	def jsonbody
      	if (capabilitySupportsDrySwing == "true")
        {
			jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"DRY", power:"ON", swing:"OFF", type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        } 
        else
        {
        	jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"DRY", power:"ON", type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }
  	sendCommand("temperature",childDevice,[deviceId,jsonbody])
  	statusCommand(childDevice)
  } else {
    logDebug("Sorry Dry Capability not supported on device ${childDevice.device.name}")
  }
}

def fanAuto(childDevice){
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  def capabilitySupportsFan = parseCapabilityData(childDevice.getCapabilitySupportsFan())
  def capabilitySupportsFanSwing = parseCapabilityData(childDevice.getCapabilitySupportsFanSwing())
  def capabilitysupported = capabilitySupportsFan
  if (capabilitysupported == "true"){
    def terminationmode = settings.manualmode
		logDebug("Executing 'sendCommand.fanAutoCommand' on device ${childDevice.device.name}")
      def jsonbody
      	if (capabilitySupportsFanSwing == "true")
        {
			jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"FAN", power:"ON", swing:"OFF", type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        } 
        else
        {
        	jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"FAN", power:"ON", type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }
    
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
  	statusCommand(childDevice)
  } else {
    logDebug("Sorry Fan Capability not supported by your HVAC Device")
  }
}

def endManualControl(childDevice){
	logDebug("Executing 'sendCommand.endManualControl' on device ${childDevice.device.name}")
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
	sendCommand("deleteEntry",childDevice,[deviceId])
	statusCommand(childDevice)
}

def cmdFanSpeedAuto(childDevice){
  def supportedfanspeed
  def terminationmode = settings.manualmode
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  def jsonbody
  def capabilitySupportsCool = parseCapabilityData(childDevice.getCapabilitySupportsCool())
  def capabilitysupported = capabilitySupportsCool
  def capabilitySupportsCoolAutoFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsCoolAutoFanSpeed())
  def fancapabilitysupported = capabilitySupportsCoolAutoFanSpeed
  if (fancapabilitysupported == "true"){
    supportedfanspeed = "AUTO"
    } else {
      supportedfanspeed = "HIGH"
    }
	def curSetTemp = (childDevice.device.currentValue("thermostatSetpoint"))
	def curMode = ((childDevice.device.currentValue("thermostatMode")).toUpperCase())
	if (curMode == "COOL" || curMode == "HEAT"){
    	if (capabilitySupportsCoolSwing == "true" || capabilitySupportsHeatSwing == "true")
        {
    		if (state.tempunit == "C") {
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", swing:"OFF", temperature:[celsius:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
    		else if(state.tempunit == "F"){
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", swing:"OFF", temperature:[fahrenheit:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
        } 
        else
        {
        	if (state.tempunit == "C") {
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", temperature:[celsius:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
    		else if(state.tempunit == "F"){
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", temperature:[fahrenheit:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
        }
		logDebug("Executing 'sendCommand.fanSpeedAuto' to ${supportedfanspeed}")
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
    statusCommand(childDevice)
	}
}

def cmdFanSpeedHigh(childDevice){
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  def jsonbody
  def supportedfanspeed = "HIGH"
  def terminationmode = settings.manualmode
	def curSetTemp = (childDevice.device.currentValue("thermostatSetpoint"))
	def curMode = ((childDevice.device.currentValue("thermostatMode")).toUpperCase())
	if (curMode == "COOL" || curMode == "HEAT"){
    	if (capabilitySupportsCoolSwing == "true" || capabilitySupportsHeatSwing == "true")
        {
    		if (state.tempunit == "C") {
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", swing:"OFF", temperature:[celsius:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
    		else if(state.tempunit == "F"){
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", swing:"OFF", temperature:[fahrenheit:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
        } 
        else
        {
        	if (state.tempunit == "C") {
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", temperature:[celsius:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
    		else if(state.tempunit == "F"){
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", temperature:[fahrenheit:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
        }
		logDebug("Executing 'sendCommand.fanSpeedAuto' to ${supportedfanspeed}")
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
    statusCommand(childDevice)
	}
}

def cmdFanSpeedMid(childDevice){
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  def supportedfanspeed = "MIDDLE"
  def terminationmode = settings.manualmode
  def jsonbody
	def curSetTemp = (childDevice.device.currentValue("thermostatSetpoint"))
	def curMode = ((childDevice.device.currentValue("thermostatMode")).toUpperCase())
	if (curMode == "COOL" || curMode == "HEAT"){
    	if (capabilitySupportsCoolSwing == "true" || capabilitySupportsHeatSwing == "true")
        {
    		if (state.tempunit == "C") {
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", swing:"OFF", temperature:[celsius:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
    		else if(state.tempunit == "F"){
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", swing:"OFF", temperature:[fahrenheit:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
        } 
        else
        {
        	if (state.tempunit == "C") {
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", temperature:[celsius:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
    		else if(state.tempunit == "F"){
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", temperature:[fahrenheit:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
        }
		logDebug("Executing 'sendCommand.fanSpeedMid' to ${supportedfanspeed}")
		sendCommand("temperature",childDevice,[deviceId,jsonbody])
    statusCommand(childDevice)
	}
}

def cmdFanSpeedLow(childDevice){
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  def capabilitySupportsCoolSwing = parseCapabilityData(childDevice.getCapabilitySupportsCoolSwing())
  def capabilitySupportsHeatSwing = parseCapabilityData(childDevice.getCapabilitySupportsHeatSwing())
  def supportedfanspeed = "LOW"
  def terminationmode = settings.manualmode
  def jsonbody
	def curSetTemp = (childDevice.device.currentValue("thermostatSetpoint"))
	def curMode = ((childDevice.device.currentValue("thermostatMode")).toUpperCase())
	if (curMode == "COOL" || curMode == "HEAT"){
    	if (capabilitySupportsCoolSwing == "true" || capabilitySupportsHeatSwing == "true")
        {
    		if (state.tempunit == "C") {
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", swing:"OFF", temperature:[celsius:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
    		else if(state.tempunit == "F"){
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", swing:"OFF", temperature:[fahrenheit:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
        } 
        else
        {
        	if (state.tempunit == "C") {
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", temperature:[celsius:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
    		else if(state.tempunit == "F"){
      			jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:curMode, power:"ON", temperature:[fahrenheit:curSetTemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    		}
        }
		logDebug("Executing 'sendCommand.fanSpeedLow' to ${supportedfanspeed}")
		sendCommand("temperature",childDevice,[deviceId,jsonbody])
    statusCommand(childDevice)
	}
}

def setCoolingTempCommand(childDevice,targetTemperature){
  def terminationmode = settings.manualmode
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  def supportedfanspeed
  def capabilitySupportsCool = parseCapabilityData(childDevice.getCapabilitySupportsCool())
  def capabilitySupportsCoolSwing = parseCapabilityData(childDevice.getCapabilitySupportsCoolSwing())
  def capabilitysupported = capabilitySupportsCool
  def capabilitySupportsCoolFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsCoolFanSpeed())
  def capabilitySupportsCoolAutoFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsCoolAutoFanSpeed())
  def fancapabilitysupported = capabilitySupportsCoolAutoFanSpeed
  def jsonbody
    if (fancapabilitysupported == "true"){
    	supportedfanspeed = "AUTO"
    } else {
        supportedfanspeed = "HIGH"
    }
    if (capabilitySupportsCoolSwing == "true" && capabilitySupportsCoolFanSpeed == "true")
    {
 		if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"COOL", power:"ON", swing:"OFF", temperature:[celsius:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
            jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"COOL", power:"ON", swing:"OFF", temperature:[fahrenheit:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
    else if(capabilitySupportsCoolSwing == "true" && capabilitySupportsCoolFanSpeed == "false"){
      if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"COOL", power:"ON", swing:"OFF", temperature:[celsius:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
            jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"COOL", power:"ON", swing:"OFF", temperature:[fahrenheit:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
    else if(capabilitySupportsCoolSwing == "false" && capabilitySupportsCoolFanSpeed == "false"){
      if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"COOL", power:"ON", temperature:[celsius:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
            jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"COOL", power:"ON", temperature:[fahrenheit:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
    else
    {
 		if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"COOL", power:"ON", temperature:[celsius:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"COOL", power:"ON", temperature:[fahrenheit:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }

	logDebug("Executing 'sendCommand.setCoolingTempCommand' to ${targetTemperature} on device ${childDevice.device.name}")
	sendCommand("temperature",childDevice,[deviceId,jsonbody])
}

def setHeatingTempCommand(childDevice,targetTemperature){
  def terminationmode = settings.manualmode
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  if(deviceType == "AIR_CONDITIONING")
  {
    def capabilitySupportsHeat = parseCapabilityData(childDevice.getCapabilitySupportsHeat())
    def capabilitysupported = capabilitySupportsHeat
    def capabilitySupportsHeatSwing = parseCapabilityData(childDevice.getCapabilitySupportsHeatSwing())
    def capabilitySupportsHeatAutoFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsHeatAutoFanSpeed())
    def capabilitySupportsHeatFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsHeatFanSpeed())
    def fancapabilitysupported = capabilitySupportsHeatAutoFanSpeed
    def supportedfanspeed
    def jsonbody
    if (fancapabilitysupported == "true")
    {
      supportedfanspeed = "AUTO"
    }
    else
    {
      supportedfanspeed = "HIGH"
    }
    if (capabilitySupportsHeatSwing == "true" && capabilitySupportsHeatFanSpeed == "true")
    {
 		if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", swing:"OFF", temperature:[celsius:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
            jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", swing:"OFF", temperature:[fahrenheit:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
    else if(capabilitySupportsHeatSwing == "true" && capabilitySupportsHeatFanSpeed == "false"){
      if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", swing:"OFF", temperature:[celsius:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
            jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", swing:"OFF", temperature:[fahrenheit:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
    else if(capabilitySupportsHeatSwing == "false" && capabilitySupportsHeatFanSpeed == "false"){
      if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", temperature:[celsius:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
            jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", temperature:[fahrenheit:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
    else
    {
 		if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", temperature:[celsius:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", temperature:[fahrenheit:targetTemperature], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
  	logDebug("Executing 'sendCommand.setHeatingTempCommand' to ${targetTemperature} on device ${childDevice.device.name}")
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
  }
  if(deviceType == "HEATING")
  {
    def jsonbody
    if (state.tempunit == "C") {
      jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[celsius:targetTemperature], type:"HEATING"], termination:[type:terminationmode]])
    }
    else if(state.tempunit == "F"){
      jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[fahrenheit:targetTemperature], type:"HEATING"], termination:[type:terminationmode]])
    }
    logDebug("Executing 'sendCommand.setHeatingTempCommand' to ${targetTemperature} on device ${childDevice.device.name}")
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
  }
  if(deviceType == "HOT_WATER")
  {
    def jsonbody
    def capabilitySupportsWaterTempControl = parseCapabilityData(childDevice.getCapabilitySupportsWaterTempControl())
    if(capabilitySupportsWaterTempControl == "true"){
      if (state.tempunit == "C") {
        jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[celsius:targetTemperature], type:"HOT_WATER"], termination:[type:terminationmode]])
			}
			else if(state.tempunit == "F"){
				jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[fahrenheit:targetTemperature], type:"HOT_WATER"], termination:[type:terminationmode]])
			}
		logDebug("Executing 'sendCommand.setHeatingTempCommand' to ${targetTemperature} on device ${childDevice.device.name}")
		sendCommand("temperature",[jsonbody])
	  } else {
		    logDebug( "Hot Water Temperature Capability Not Supported on device ${childDevice.device.name}" )
	  }
  }
}

def offCommand(childDevice){
	logDebug("Executing 'sendCommand.offCommand' on device ${childDevice.device.name}")
  def terminationmode = settings.manualmode
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  def jsonbody = new groovy.json.JsonOutput().toJson([setting:[type:deviceType, power:"OFF"], termination:[type:terminationmode]])
  sendCommand("temperature",childDevice,[deviceId,jsonbody])
}

def onCommand(childDevice){
  logDebug("Executing 'sendCommand.onCommand'")
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  if(deviceType == "AIR_CONDITIONING")
  {
    coolCommand(childDevice)
  }
  if(deviceType == "HEATING" || deviceType == "HOT_WATER")
  {
    heatCommand(childDevice)
  }
}

def coolCommand(childDevice){
	logDebug("Executing 'sendCommand.coolCommand'")
    def terminationmode = settings.manualmode
    def item = (childDevice.device.deviceNetworkId).tokenize('|')
    def deviceId = item[0]
    def deviceType = item[1]
    def deviceToken = item[2]
    def initialsetpointtemp
    def supportedfanspeed
    def capabilitySupportsCool = parseCapabilityData(childDevice.getCapabilitySupportsCool())
    def capabilitySupportsCoolSwing = parseCapabilityData(childDevice.getCapabilitySupportsCoolSwing())
    def capabilitysupported = capabilitySupportsCool
    def capabilitySupportsCoolAutoFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsCoolAutoFanSpeed())
    def capabilitySupportsCoolFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsCoolFanSpeed())
    def fancapabilitysupported = capabilitySupportsCoolAutoFanSpeed
    def traperror
	if(childDevice.device.currentValue("thermostatSetpoint"))
    {
        traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    }
    else
    {
       logDebug("Existing Setpoint is not set")
       traperror = 0 
    }
    if (fancapabilitysupported == "true"){
    	supportedfanspeed = "AUTO"
        } else {
        supportedfanspeed = "HIGH"
        }
    if(traperror == 0){
    	initialsetpointtemp = settings.defCoolingTemp
    } else {
    	initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
    }
    def jsonbody
    if (capabilitySupportsCoolSwing == "true" && capabilitySupportsCoolFanSpeed == "true")
    {
    	if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"COOL", power:"ON", swing:"OFF", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    	}
    	else if (state.tempunit == "F"){
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"COOL", power:"ON", swing:"OFF", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    	}    
    }
    else if(capabilitySupportsCoolSwing == "true" && capabilitySupportsCoolFanSpeed == "false"){
      if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"COOL", power:"ON", swing:"OFF", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
            jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"COOL", power:"ON", swing:"OFF", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
    else if(capabilitySupportsCoolSwing == "false" && capabilitySupportsCoolFanSpeed == "false"){
      if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"COOL", power:"ON", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}
  		else if(state.tempunit == "F"){
            jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"COOL", power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
  		}    
    }
    else
    {
    	if (state.tempunit == "C") {
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"COOL", power:"ON", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    	}
    	else if (state.tempunit == "F"){
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"COOL", power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
    	}
    }
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
}

def heatCommand(childDevice){
  logDebug("Executing 'sendCommand.heatCommand' on device ${childDevice.device.name}")
  def terminationmode = settings.manualmode
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  if(deviceType == "AIR_CONDITIONING")
    {
      def initialsetpointtemp
      def supportedfanspeed
      def traperror
      def capabilitySupportsHeat = parseCapabilityData(childDevice.getCapabilitySupportsHeat())
      def capabilitySupportsHeatSwing = parseCapabilityData(childDevice.getCapabilitySupportsHeatSwing())
      def capabilitysupported = capabilitySupportsHeat
      def capabilitySupportsHeatAutoFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsHeatAutoFanSpeed())
      def capabilitySupportsHeatFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsHeatFanSpeed())
      def fancapabilitysupported = capabilitySupportsHeatAutoFanSpeed
      if(childDevice.device.currentValue("thermostatSetpoint"))
    	{
        	traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    	}
    	else
    	{
       		logDebug( "Existing Setpoint is not set" )
       		traperror = 0 
    	}
      if (fancapabilitysupported == "true")
      {
        supportedfanspeed = "AUTO"
      }
      else
      {
        supportedfanspeed = "HIGH"
      }
      if(traperror == 0)
      {
        initialsetpointtemp = settings.defHeatingTemp
      }
      else
      {
        initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
      }
      def jsonbody
      if (capabilitySupportsHeatSwing == "true" && capabilitySupportsHeatFanSpeed == "true")
      {
      	if (state.tempunit == "C") {
      		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", swing:"OFF", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
      	}
      	else if (state.tempunit == "F"){
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", swing:"OFF", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
      	}
      }
      else if(capabilitySupportsHeatSwing == "true" && capabilitySupportsHeatFanSpeed == "false"){
        if (state.tempunit == "C") {
          jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", swing:"OFF", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }
        else if(state.tempunit == "F"){
              jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", swing:"OFF", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }    
      }
      else if(capabilitySupportsHeatSwing == "false" && capabilitySupportsHeatFanSpeed == "false"){
        if (state.tempunit == "C") {
          jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }
        else if(state.tempunit == "F"){
              jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }    
      } 
      else
      {
      	if (state.tempunit == "C") {
      		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
      	}
      	else if (state.tempunit == "F"){
    		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
      	}      
      }
      
      sendCommand("temperature",childDevice,[deviceId,jsonbody])
    }
    if(deviceType == "HEATING")
    {
      def initialsetpointtemp
      def traperror
      if(childDevice.device.currentValue("thermostatSetpoint"))
    	{
        	traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    	}
    	else
    	{
       		logDebug("Existing Setpoint is not set")
       		traperror = 0 
    	}
        if(traperror == 0)
        {
          initialsetpointtemp = settings.defHeatingTemp
        }
        else
        {
          initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
        }
        def jsonbody
        if (state.tempunit == "C") {
      		jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[celsius:initialsetpointtemp], type:"HEATING"], termination:[type:terminationmode]])
      	}
        else if (state.tempunit == "F"){
        	jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"HEATING"], termination:[type:terminationmode]])
      	}
        sendCommand("temperature",childDevice,[deviceId,jsonbody])
    }
    if(deviceType == "HOT_WATER")
    {
      def jsonbody
      def initialsetpointtemp
      def traperror
      def capabilitySupportsWaterTempControl = parseCapabilityData(childDevice.getCapabilitySupportsWaterTempControl())
      if(capabilitySupportsWaterTempControl == "true"){
        if(childDevice.device.currentValue("thermostatSetpoint"))
    	{
        	traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    	}
    	else
    	{
       		logDebug("Existing Setpoint is not set")
       		traperror = 0 
    	}
        if(traperror == 0){
          initialsetpointtemp = settings.defHeatingTemp
        } else {
          initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
        }
        if (state.tempunit == "C") {
      		jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[celsius:initialsetpointtemp], type:"HOT_WATER"], termination:[type:terminationmode]])
      	}
        else if (state.tempunit == "F"){
        	jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"HOT_WATER"], termination:[type:terminationmode]])
      	}
      } else {
        jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", type:"HOT_WATER"], termination:[type:terminationmode]])
      }
      sendCommand("temperature",childDevice,[deviceId,jsonbody])
    }
}

def emergencyHeat(childDevice){
  logDebug("Executing 'sendCommand.heatCommand' on device ${childDevice.device.name}")
  def traperror
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
  if(deviceType == "AIR_CONDITIONING")
  {
    def capabilitySupportsHeat = parseCapabilityData(childDevice.getCapabilitySupportsHeat())
    def capabilitysupported = capabilitySupportsHeat
    def capabilitySupportsHeatSwing = parseCapabilityData(childDevice.getCapabilitySupportsHeatSwing())
    def capabilitySupportsHeatAutoFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsHeatAutoFanSpeed())
    def capabilitySupportsHeatFanSpeed = parseCapabilityData(childDevice.getCapabilitySupportsHeatFanSpeed())
    def fancapabilitysupported = capabilitySupportsHeatAutoFanSpeed
    if(childDevice.device.currentValue("thermostatSetpoint"))
    {
        traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    }
    else
    {
       logDebug("Existing Setpoint is not set")
       traperror = 0 
    }
    if (capabilitysupported == "true")
    {
      def initialsetpointtemp
      def supportedfanspeed
      if (fancapabilitysupported == "true")
      {
        supportedfanspeed = "AUTO"
      }
      else
      {
        supportedfanspeed = "HIGH"
      }
      if(traperror == 0)
      {
        initialsetpointtemp = settings.defHeatingTemp
      }
      else
      {
        initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
      }
      def jsonbody
	  if (capabilitySupportsHeatSwing == "true" && capabilitySupportsHeatFanSpeed == "true")
      {
      	if (state.tempunit == "C") {
      		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", swing:"OFF", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[durationInSeconds:"3600", type:"TIMER"]])
      	}
      	else if (state.tempunit == "F"){
      		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", swing:"OFF", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[durationInSeconds:"3600", type:"TIMER"]])
      	}
      }
      else if(capabilitySupportsHeatSwing == "true" && capabilitySupportsHeatFanSpeed == "false"){
        if (state.tempunit == "C") {
          jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", swing:"OFF", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }
        else if(state.tempunit == "F"){
              jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", swing:"OFF", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }    
      }
      else if(capabilitySupportsHeatSwing == "false" && capabilitySupportsHeatFanSpeed == "false"){
        if (state.tempunit == "C") {
          jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }
        else if(state.tempunit == "F"){
              jsonbody = new groovy.json.JsonOutput().toJson([setting:[mode:"HEAT", power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[type:terminationmode]])
        }    
      } 
      else
      {
		if (state.tempunit == "C") {
      		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", temperature:[celsius:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[durationInSeconds:"3600", type:"TIMER"]])
      	}
      	else if (state.tempunit == "F"){
      		jsonbody = new groovy.json.JsonOutput().toJson([setting:[fanSpeed:supportedfanspeed, mode:"HEAT", power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"AIR_CONDITIONING"], termination:[durationInSeconds:"3600", type:"TIMER"]])
      	}
      }
      sendCommand("temperature",childDevice,[deviceId,jsonbody])
      statusCommand(device)
    }
    else
    {
      logDebug("Sorry Heat Capability not supported on device ${childDevice.device.name}")
    }
  }
  if(deviceType == "HEATING")
  {
      def initialsetpointtemp
      if(childDevice.device.currentValue("thermostatSetpoint"))
    	{
        	traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    	}
    	else
    	{
       		logDebug( "Existing Setpoint is not set" )
       		traperror = 0 
    	}
      if(traperror == 0)
      {
        initialsetpointtemp = settings.defHeatingTemp
      }
      else
      {
        initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
      }
      def jsonbody
      if (state.tempunit == "C") {
      	jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[celsius:initialsetpointtemp], type:"HEATING"], termination:[durationInSeconds:"3600", type:"TIMER"]])
      }
      else if (state.tempunit == "F"){
      	jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"HEATING"], termination:[durationInSeconds:"3600", type:"TIMER"]])
      }
      sendCommand("temperature",childDevice,[deviceId,jsonbody])
      statusCommand(childDevice)
  }
  (deviceType == "HOT_WATER")
  {
    def initialsetpointtemp
    def jsonbody
    def capabilitySupportsWaterTempControl = parseCapabilityData(childDevice.getCapabilitySupportsWaterTempControl())
    if(capabilitySupportsWaterTempControl == "true"){
      if(childDevice.device.currentValue("thermostatSetpoint"))
    	{
        	traperror = ((childDevice.device.currentValue("thermostatSetpoint")).intValue())
    	}
    	else
    	{
       		logDebug("Existing Setpoint is not set")
       		traperror = 0 
    	}
      if(traperror == 0)
      {
        initialsetpointtemp = settings.defHeatingTemp
      }
      else
      {
        initialsetpointtemp = childDevice.device.currentValue("thermostatSetpoint")
      }
      if (state.tempunit == "C") {
      	jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[celsius:initialsetpointtemp], type:"HOT_WATER"], termination:[durationInSeconds:"3600", type:"TIMER"]])
      }
      else if (state.tempunit == "F"){
      	jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", temperature:[fahrenheit:initialsetpointtemp], type:"HOT_WATER"], termination:[durationInSeconds:"3600", type:"TIMER"]])
      }
    }
    else
    {
      jsonbody = new groovy.json.JsonOutput().toJson([setting:[power:"ON", type:"HOT_WATER"], termination:[durationInSeconds:"3600", type:"TIMER"]])
    }
    sendCommand("temperature",childDevice,[deviceId,jsonbody])
    statusCommand(childDevice)
  }
}

def statusCommand(childDevice){
  def item = (childDevice.device.deviceNetworkId).tokenize('|')
  def deviceId = item[0]
  def deviceType = item[1]
  def deviceToken = item[2]
	logDebug("Executing 'sendCommand.statusCommand'")
	sendCommand("status",childDevice,[deviceId])
}

def userStatusCommand(childDevice){
	try{
		logDebug("Executing 'sendCommand.userStatusCommand'")
		sendCommand("userStatus",childDevice,[])
    	} catch(Exception e) { log.error("Failed in setting userStatusCommand: " + e)
    }
}

// -------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Log methods
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------

def logDebug(message) {
    
    if (isDebugLogActive()){
        log.debug message }
    
}

def openForcedDebugLog(seconds) {
    if (seconds == 0){ seconds = getDefaultLogForceSecs() }    	
    def forceLogRequestedUntil = now() + (seconds * 1000)   
    if (state.debugLogForcedUntil < forceLogRequestedUntil) {
        state.debugLogForcedUntil = forceLogRequestedUntil }
}

def isDebugLogActive() {
    
    if (now() < state.debugLogForcedUntil || getDebugLogStatus() == "On" ) {
        return true }
    else {
        return false }

}

// -------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Password Grant methods
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------

def initiateDeviceCodeFlow() {
    def result = false
        
    logDebug("Initiating device code flow")
    
        	def params = [
                uri: getTadoLoginUri(),
                path: getDeviceCodePath(),          
				body: [					
                    client_id: getClientId(),
                    scope: "offline_access"                   
				]
    ]
    
            try {                
               
                logDebug("Parameters for initiating device code flow:" + " " + params)
                
                httpPost(params)
                { resp ->
                logDebug("Response data:" + " " + resp.data)
                logDebug("Respones succes:" + " " + resp.success)         
    			if (resp && resp.data && resp.success) { 
                    logDebug("Device Code Received")
                    state.deviceCode = resp.data.device_code
                    state.userCode = resp.data.user_code
                    state.deviceCodeExpiresIn = resp.data.expires_in
                    state.deviceCodeExpires = (now() + (resp.data.expires_in * 1000))   
                    state.deviceCodeCheckInterval = resp.data.interval
                    state.deviceCodeVerificationUri = resp.data.verification_uri
                    state.deviceCodeVerificationUriComplete = resp.data.verification_uri_complete
                    logDebug("User Code:" + " " + resp.data.user_code)
                    logDebug("Device Code Verification URL:" + " " + state.deviceCodeVerificationUriComplete)
                    logDebug("Device code expires:" + " " + state.deviceCodeExpires)
                    result = true
                } else { log.error "Failed to get Device Code" }
            }
		} 
		catch (e) {
            log.error "Device Code Retreival Error: ${e}"            
        }
    
    return result
 }

def getDeviceAccessToken() {
    def result = false
    
    logDebug( "Initiating get Device Access Token" )
    
        	def params = [
                uri: getTadoLoginUri(),
                path: getDeviceTokenPath(),          
				body: [					
                    client_id: getClientId(),
                    device_code: state.deviceCode,
                    grant_type: "urn:ietf:params:oauth:grant-type:device_code"                  
				]
    ]
    
            try {                
               
                logDebug( "Parameters for initiating get Device Access Token:" + " " + params )
                
                httpPost(params)
                { resp ->
                logDebug( "Response data:" + " " + resp.data )
                logDebug( "Respones succes:" + " " + resp.success )                  
    			if (resp && resp.data && resp.success) { 
                    logDebug( "Access Token Received" )
                    state.accessToken = resp.data.access_token
                    state.accessTokenRefreshed = now()
                    state.accessTokenExpires = (now() + (resp.data.expires_in * 1000))
                    state.nextAccessTokenRefresh = now() + (resp.data.expires_in * 1000) - getTokenExpOffset()   
                    state.accessTokenTimeToLive = resp.data.expires_in
                    state.refreshToken = resp.data.refresh_token
                    state.tokenScope = resp.data.scope
                    state.tokenType = resp.data.token_type
                    state.userId = resp.data.userId                    
                    logDebug( "Access Token:" + " " + resp.data.access_token )
                    logDebug( "Refresh Token:" + " " + resp.data.refresh_token ) 
                    logDebug( "User ID:" + " " + state.userId )
                    logDebug( "Token expires in:" + " " + resp.data.expires_in )
                    logDebug( "Token expires:" + " " + state.accessTokenExpires )
                    result = true
                } else { log.error "Failed to get access code"
                         log.error( "Parameters for get access code:" + " " + params )
                         if(resp){ log.error( "Response:" + " " + resp.data ) }
                         if(resp.data){ log.error( "Response data:" + " " + resp.data ) }
                         if(resp.success){ log.error( "Respones succes:" + " " + resp.success ) }  
                         state.accessToken = null
                         state.refreshToken = null }
            }
		} 
		catch (e) {
            log.error "Device Access Code Retreival Error: ${e}"  
            if(resp){ log.error( "Response:" + " " + resp.data ) 
            	if(resp.data){ log.error( "Response data:" + " " + resp.data ) }
                if(resp.success){ log.error( "Respones succes:" + " " + resp.success ) } }
            state.accessToken = null        
            state.refreshToken = null
        }
    
    return result
 }

def refreshAccessToken() {
 
    if (!state.accessTokenExpires || state.nextAccessTokenRefresh <= now()) { return true } else { return false }
        
}

def isAccessTokenExpired() { 
     if (!state.accessTokenExpires || state.accessTokenExpires <= now()) { return true }  else { return false }    
}

def refreshToken() {	
    def result = false
    
    logDebug( "Refreshing Access token" )
    
    //Open debug log if access token is cleared previously
    if (isAccessTokenExpired() && settings.debugLog != "On" ) { 
        def debugTurnedOn = true
        settings.debugLog = "On" }
    
	try {
	
        def params = [
                uri: getAccessTokenUri(),
                path: getAccessTokenPath(),          
				body: [					
                    client_id: getClientId(),                                        
                    grant_type: "refresh_token",
                    refresh_token: getRefreshToken()                                       
				] ]
        
        logDebug( "Parameters for token refresh:" + " " + params )
        
		httpPost(params) { resp -> 
            logDebug( "Response data:" + " " + resp.data )
            logDebug( "Respones succes:" + " " + resp.success )
			if (resp && resp.data && resp.success) {                
				logDebug( "Token refreshed successfully" )
                state.accessToken = resp.data.access_token
                state.accessTokenRefreshed = now()
                state.accessTokenExpires = now() + (resp.data.expires_in * 1000)     
                state.nextAccessTokenRefresh = now() + (resp.data.expires_in * 1000) - getTokenExpOffset()   
                state.accessTokenTimeToLive = resp.data.expires_in
                state.refreshToken = resp.data.refresh_token                
                logDebug( "Access Token:" + " " + resp.data.access_token )
                logDebug( "Access Token Saved:" + " " + state.accessToken )
                logDebug( "Refresh Token:" + " " + resp.data.refresh_token )
                logDebug( "Refresh Token Saved:" + " " + state.refreshToken )
                logDebug( "User ID:" + " " + state.userId )
                logDebug( "Token expires in:" + " " + resp.data.expires_in )
                logDebug( "Token expires:" + " " + state.accessTokenExpires )
				result = true                
			}
			else {
                log.error( "Failed to refresh access token using refresh token" + " " + state.refreshToken )
                log.error( "Parameters for token refresh:" + " " + params )
                if(resp){ log.error( "Response:" + " " + resp.data ) 
                		 if(resp.data){ log.error( "Response data:" + " " + resp.data ) }
                         if(resp.success){ log.error( "Respones succes:" + " " + resp.success ) } }                
				result = false
			}
		}
	}
	catch (e) {
        log.error "Failed to refresh access token (HTTP error): ${e}"   
        if(resp){ log.error( "Response:" + " " + resp.data ) 
        		if(resp.data){ log.error( "Response data:" + " " + resp.data ) }
                if(resp.success){ log.error( "Respones succes:" + " " + resp.success ) } }
		result = false
	}
	
    if (debugTurnedOn) { 
       def debugTurnedOn = false
       settings.debugLog = "Off" }
    
    return result
      
}
2 Likes

Thank you, will let you know how it goes, so far I'm getting data and control back :slight_smile:

Hi
How's it going with the code above? Any updates?
Did anyone try to replace the existing code to avoid having to update automations based on tado devices?
:pray:t2:

I'm still operational with the new code. I merged some of my previous changes in, as use heatingPower reporting, so needed that metric back.

I made a copy of the existing Connect code in a new app, then replaced the code in my existing Tado Connect app, enabled and logged in. Bingo, all devices now report status again.
And I got presence back, so the house knowns when we're home again. :-).

I too get some auth errors every so often, and looking at the timings, maybe some race condition, but doesn't affect operation. Will have a go at debugging sometime when I get time lol,

I posted my current version on GitHub, public/Tado-Connect-2025 at main · tstretton/public · GitHub

Super thankful for user3860 for getting us working again.

2 Likes