[RE-RELEASE] Nexia Thermostat Manager (Trane Home)

I took @thebearmay’s app (v1.0.3) and extended it (v1.1.0) to work with the Trane Link UX360 thermostat. It likely works with other newer Trane thermostats as well, but that is the only one I have to test with. I didn’t remove the existing functionality; it now has 2 distinct methods of thermostat discovery. It’s been a really long time since I’ve coded, so I relied heavily on Codex (chatGPT) to help me. This is the first time I’ve released Hubitat code as well.

The key changes are:

  • Updated app category for newer Hubitat releases to show under integrations instead of apps.
  • Added support for newer Trane Home thermostats.
  • Added setpoint range handling from thermostat-reported limits.
  • Added compressor speed as an optional attribute when reported by the thermostat.
  • Added configurable driver logging levels. Added info level logging and cleaned up the debug logging output a bit.
  • Slightly changed the way the emergency heat mode is handled. Now there is a preference that needs to be turned on to let the driver know your thermostat supports that mode change command. That mode seems to be built into Hubitat and shows up even if the mode is not specified as a supported mode. So if selected, it will only attempt to send if the preference is enabled.

The easiest and recommended way to install is through Hubitat Package Manager.

The code is also available in GitHub.

If you use this and find any issues, let me know. My ability to troubleshoot will be limited, but I’ll try.

What am I missing here? I attempted to install it from HPM but It didn’t seem to do anything. It didn’t create an app or device. I’m new so I assume I missed something but I didn’t see anything so I uninstalled and tried again but no change.

When you “install” an app using HPM, it just puts the code on your hub. You still have to go to apps (or in this case, Integrations) tab and click the “add user Integration” button and choose the app to install. That will put it in your list of installed apps.

Once installed, you’ll need to open it and enter your credentials and a device should get automatically created for the thermostat.

Here is the thread for HPM if you have any problems specific to it: [RELEASE] Hubitat Package Manager (HPM) -- HubitatCommunity

Thank You So Much! I didn’t check integrations, but it worked exactly as you said.

The original code was something I had tried a few years ago as my first device in Hubitat when I wanted to move away from ST and could never get anywhere with it. I never dove much further into Hubitat cause I couldn’t get anywhere with this. I recently decided to try again with my Zwave devices and that was going well but I assumed this darn thermostat would never work. You Rock!!

Just pushed a minor update. Now after a poll(), a new hub event is only published for values that change. If you were getting hub warnings about excessive events, this should fix that. Though, depending on how many values change it could still brush up against the default limit of 300 per hour if polling every minute. So if you notice com.hubitat.app.exception.LimitExceededException errors in your log, I might have to take further steps.

Is this still working for people? I'm getting these constantly:

Caught exception requesting thermostats com.hubitat.hub.executor.helpers.ExecutorHttpResponseException: status code: 401, reason phrase: Unauthorized

It's still working fine for me. Few questions:

  1. What model thermostat do you have?
  2. Do you have the Trane app setup?
  3. Is it the app or the driver that's throwing the exception in the log? I assume the app?

I'm about to head out the door to pick my kids up from school and can try to check it out later. But a 401 error means that the resource loaded, but for some reason was unable to authenticate. It could be incorrect credentials. It could be that the credentials are correct, but you don't have access to that specific resource.

I'm talking in general. But the issue seems related to you trying to log into your Trane account.

Thanks for you help.

To answer your questions.

  1. It's an XL824
  2. Yes

3a.The app is throwing this error every minute

Caught exception requesting thermostats com.hubitat.hub.executor.helpers.ExecutorHttpResponseException: status code: 401, reason phrase: Unauthorized

3b.The device is throwing this one.

ERROR: Device connection removed? No data found for 1623.4602706 after polling

I've double checked the credentials. They're correct.

I've tried removing the device and app and re-adding them. Here is what I'm seeing in the logs.

For the app

app:16382026-09-02 12:45:24.009 pmerrorCaught exception requesting thermostats groovy.lang.MissingMethodException: No signature of method: static com.hubitat.hub.executor.helpers.ExecutorHttpClient5.size() is applicable for argument types: () values: [] Possible solutions: is(java.lang.Object), find(), sleep(long), find(groovy.lang.Closure), with(groovy.lang.Closure), use([Ljava.lang.Object;)
app:16382026-09-02 12:45:23.910 pmdebugrequestThermostats(null)
app:16382026-09-02 12:45:23.908 pmerrorCaught exception determining thermostats path groovy.lang.MissingMethodException: No signature of method: static com.hubitat.hub.executor.helpers.ExecutorHttpClient5.getAt() is applicable for argument types: (java.lang.Integer) values: [0] Possible solutions: getAt(java.lang.String), putAt(java.lang.String, java.lang.Object), wait(), grep(), getClass(), wait(long)
app:16382026-09-02 12:45:23.835 pmerrorCaught exception refreshing auth token groovy.lang.MissingMethodException: No signature of method: static com.hubitat.hub.executor.helpers.ExecutorHttpClient5.getAt() is applicable for argument types: (java.lang.Integer) values: [0] Possible solutions: getAt(java.lang.String), putAt(java.lang.String, java.lang.Object), wait(), grep(), getClass(), wait(long)
app:16382026-09-02 12:45:23.831 pmdebugCookie updated: _SchlagePortal_session
app:16382026-09-02 12:45:23.670 pminfoAttempting Trane Home login
app:16382026-09-02 12:45:23.668 pmdebugrefreshAuthToken()
app:16382026-09-02 12:45:23.667 pmdebuginitialize()
app:16382026-09-02 12:45:23.664 pmdebugupdated()

For the Device

dev:15142026-09-02 12:49:12.015 pmerrorjava.lang.NullPointerException: Cannot invoke method pollChild() on null object on line 214 (method poll)
dev:15142026-09-02 12:49:12.012 pmdebugpoll()
dev:15142026-09-02 12:48:20.968 pmerrorjava.lang.NullPointerException: Cannot invoke method setCoolingSetpoint() on null object on line 350 (method setCoolingSetpoint)
dev:15142026-09-02 12:48:20.960 pmdebugsetCoolingSetpoint(76)
dev:15142026-09-02 12:48:20.958 pminfoSending cooling setpoint command: 76
dev:15142026-09-02 12:48:14.546 pmerrorjava.lang.NullPointerException: Cannot invoke method pollChild() on null object on line 214 (method poll)
dev:15142026-09-02 12:48:14.542 pmdebugpoll()
dev:15142026-09-02 12:48:12.244 pmerrorjava.lang.NullPointerException: Cannot invoke method pollChild() on null object on line 214 (method refresh)
dev:15142026-09-02 12:48:12.240 pmdebugpoll()
dev:15142026-09-02 12:48:12.239 pmdebugrefresh()

Also, I've been trying to update / reinstall this from HPM, but I can't find it in HPM. What do I need to search for?

In the meantime, I've just been using the github links and updating it manually.

Okay. I have a theory on the issue. When I forked this app from thebearmay, I didn't touch his code. I discovered that Trane had implemented a different way to request the list of thermostats attached to a user's account. But this was only for newer thermostats. My assumption was this was to maintain compatibility with either the thermostats themselves, or people using an older version of the app on their phone. I figured this out because I moved and my old house has an XL850 and worked fine and the system at my new house had a newer thermostat and didn't work.

So the code basically goes "Is the thermostat X, then run the original code. Otherwise, run my new code." I however had no way to test that. So it could be something simple like I just need a different way to determine which method to use. It could be that Trane updated their infrastructure and the old method doesn't work at all now.

If you're willing to try some things, we can probably figure it out. As for why it's not showing up in HPM, I have no idea. I don't see it either when I search. I can go to my HPM settings and it shows in the list of apps/drivers it's managing, but I don't find it when I search to install. I will look into that too.

Actually, before doing anything with the code, can you tell me what version your hub is running? There was an HTTP GET regression recently and one of the recent updates fixes it. I can't say for sure that issue would have affected my app, but I think it very likely.

If you're between version .142 and .152, update to the latest version. I'd probably remove the thermostat device and have the app try and recreate it.

I'm on 2.5.1.174

@chowell Try logging into Trane Home on the web. Make sure to use a private/incognito window so it requires a fresh login and doesn't use any existing cookies or authentication tokens.

The website is what I used to test against while updating this integration. If you can log in, make sure you can see your thermostat, it displays current readings, and that your thermostat responds to changes from the web.

If the website asks for any kind of verification code, forces you to accept terms of use, forces you to update/change you password or prompts you to make any kind of changes to your account, let me know.

What's interesting though is the failure is happening before the app attempts to log in. At the moment, I don't have any reason to believe the above won't work, but it'll save time later. It does highlight some error handling that I missed. If it fails before login, it skips attempting to log in, but still creates a device. But that device will be useless. So I can at least prevent that from happening. I'm also going to add in some more output to the debug logging in hopes of it telling me exactly what is failing.

I'll have a version for you to test soonish.

Okay, so those changes weren't so bad. Hopefully this will give us more information to pinpoint the failure point. My app should be back in HPM, or at least will be soon... but for now I've created a testing branch and have a new URL for you to use to import. For now, the driver code is unchanged. Go into the app code and change the import URL to

https://raw.githubusercontent.com/waterboysh/hubitat/testing/trane-home-thermostat/nexiaThermostatManager.groovy

If there is a thermostat device that currently exists, I would delete it before running the app. Make sure to toggle debug logging on before attempting to log in. This will likely still fail... I haven't really changed any code yet; just added more logging.

Looks like there's a class expansion in the code that HE doesn't like. I get this when I try to save the newly imported code.

I tried this. It worked just fine. No accepting terms, no verification code. Just U/P and go.

Hey... don't spend any more time on this. I pointed Claude at this problem and got it resolved. I'll share my code soon.

ok, here's my fork. I'm happy to put in a pull request if you like. Claude moved a few things around, so I have not idea if it broke the functionality for the newer thermostats. All I can verify is that its working well for me and my XL824.

https://raw.githubusercontent.com/howellcc/waterboysh_hubitat/refs/heads/fixes-for-xl824-and-reauthentication/trane-home-thermostat/nexiaThermostatManager.groovy

I merged the fix from Claude into my test branch if you want to try importing it and trying again.