SmartThings Community

Trying to modify code for virtual cooling thermistat

Hello all. I have attempted to modify a smart app and device handler (originally authored by Eliot S.), that was originally designed to be a virtual heating thermostat. I am trying to change it so that it works for cooling instead of for heating. I’ve taken some modifications suggested by others, and applied some of my own, but am now having some trouble.

When the desired temperature is set to a value lower than the temperature sensor reading, then the virtual switch turns on as expected. When, however, the desired temperature is set above the current temperature sensor reading, the virtual switch also gets a turn on command.
For some reason, no matter what I do, I cant get the virtual switch to turn off via this smart app. Any help here would be greatly appreciated.
Also, I’ve mostly left the original comments in place.

Here’s the smart app fork:

https://github.com/enishoca/SmartThings-VirtualThermostat-WithDTH/pull/1/commits/68961e42290800d834feccd7751fb9d31c4c7fab?file-filters%5B%5D=#diff-6b85cfbc4777d3b542e32b39fecd82ab

And here’s the device handler fork:
https://github.com/dantor19/SmartThings-VirtualThermostat-WithDTH/commit/9fd313aa120bf9a8298f51f5ce61ffab7dbadd3f

Take a very close look at this section (especially compare original code to your code). I’m not sure this is the problem, but this code is not symmetrical.

Thanks so much for lookkng into this. Yes, I had tried the following, looking at missed curly brackets and the extra “else” but it didn’t seem to fix the problem. Any thoughts? Am I missing something else here?

private evaluate(currentTemp, desiredTemp)

{
log.debug “EVALUATE($currentTemp, $desiredTemp)”
// heater

if ( (desiredTemp - currentTemp <= threshold)) {
	coolingOn()
} 
else if ( (currentTemp - desiredTemp <= threshold)) {
	coolingOff()
    }
  else if(state.current == "on") {
  updateTimings()
}

}

and:

private evaluate(currentTemp, desiredTemp)

{
log.debug “EVALUATE($currentTemp, $desiredTemp)”
// heater

if ( (desiredTemp - currentTemp <= threshold)) {
	coolingOn()
} 
if ( (currentTemp - desiredTemp <= threshold)) {
	coolingOff()
    }
  else if(state.current == "on") {
  updateTimings()
}

}

and:

private evaluate(currentTemp, desiredTemp)

{
log.debug “EVALUATE($currentTemp, $desiredTemp)”
// heater

if ( (desiredTemp - currentTemp <= threshold)) {
	coolingOn()
} 
if ( (currentTemp - desiredTemp <= threshold)) {
	coolingOff()
    }

}

Unfortunately, it’s difficult to analyze code (much easier to try to execute it).

At the very least, check-in your latest version to GitHub so that I can compare arbitrary versions.

Of course, you know that if Heating works, then Cooling should be symmetrical code. You should make sure you change the absolute minimum number of lines to achieve this, and only when it works should you make any additional changes.

If you make completely symmetrical changes, then a diff from your version to the original version should look very, very clean. If that new version doesn’t work, then … well, are you sure that the original Heating works?

Okay, so I’ve pasted in the original smart app and device handler code, and it works as expected, with the outlet turning on when the desired temperature is set above the current temp, and the outlet turning off when the desired temp is set below the current temp. I then changed the following two lines, to change it to cool instead of heat, and it now functions as needed with the opposite behavior as listed above.

That being said, as of right now, the UI is not correct for this change of function, and the code while functional, isn’t really accurate anymore in what its defining, which would make future troubleshooting/development much harder.

Going back to my original, more comprehensively modified code, I’ve literally gone line by line, character by character multiple times, comparing the original code against my modifications, and simply don’t see what it is that I’m changing that’s causing it to break. Super frustrating…

//if ( (desiredTemp - currentTemp >= threshold)) {
if ( (desiredTemp - currentTemp <= threshold)) {
	heatingOn()
}
//if ( (currentTemp - desiredTemp >= threshold)) {
else if ( (currentTemp - desiredTemp <= threshold)) {
	heatingOff()
}

This logic disturbs me at first glance, so let’s review it. I’m keeping it with Heating at the moment, because I’m insistent that symmetrical code for Cooling ought to be extremely obvious, even if being done just method by method.

Test scenario. Current temperature is 6 degrees less than desired temperature.
Assertion: Heating should be turned on.

threshold=5;
desiredTemp = 70; currentTemp = 64;
desiredTemp - currentTemp = 70 - 64 = 6

Is 6 <= threshold (5)? FALSE. Therefore will not run "heatingOn().

Assertion fails. Test fails.

This also confused the heck out of me, but I think the logic is sound. I actually rigged up a quick excel spreadsheet to more easily see it. In the example you provide where desired temp = 70, and current temp = 64, you are correct that heatingOn() will not run, but that’s exactly what I want. In the developers intended application, heatingOn() turns on an outlet connected to a space heater, but in my application, heatingOn() turns on an outlet connected to an AC. So in my application, if the desired temp is higher than the current temp, then I want the AC to turn off, not on.

Just so I’m sure we’re not misunderstanding each other, the code I included in my previous post, is what I have currently running, with the developers original code for the heating application commented out.

Yup - I misunderstood. Since it said “heatingOn()” I presumed it was the original Virtual Heater.

I recommend, please, starting again with the original code and making the minimal changes; but including renaming Heating to Cooling (etc.). Do not comment out code - instead, GitHub’s compare / diff is completely sufficient to determine all the differences.

All the differences should be very obvious and logical and minimal. I can skim those differences for any mistakes (like misplaced “elses” or less-thans instead of greater-thans).

So a really strange update here. I did as you suggested, and started over with the original code. I pasted in the original code and it worked as expected. With that, I then modified the above code that we’ve been discussing to appropriately work for my application. I tested that, and it worked as expected.
I then changed the UI colors and graphics, and then went through very carefully and replaced the word heat with the word cool in every instance where the word appeared. I was sure to maintain capital/lowercase, and not changing any of the syntax or other characters. I did this with a key word search, and now that search returns only the word “heat” from comments.
After doing this, I tested it, and it worked perfectly, but the setting an emergency temp doesn’t seem to work.
Realizing that I never tested it with the original code, I pasted the original code back in, and found that it did not work there either.
I then pasted back in my just previously checked code, and I found it now not working. It’s back producing the same issue that I mentioned in my first post, where any temperature change, or desired temp change results in the smart app sending the outlets the off command.
Am I perhaps doing something wrong procedurally with how I’m using the smartthings app? I’m using the classic app, and simply force close the app and reopen it after each re-publishing, and then simply reopen the virtual thermostat.
Also, just to clarify, with each revision, I’m always pasting in the matching versions of the smart app and device handler.

Frustrating, isn’t it?

The good thing about using GitHub (commit your work after every paste into SmartThings!) is that you can absolutely verify the changes between a working version and a new version. SmartThings only retains one prior revision (which is wiped out when you Publish For Me).

Be sure to Publish each time though.

And I have run into cases where perfect code just doesn’t work until pasted into a brand new SmartApp editor (change the SmartApp name slightly to avoid confusion - eg add v1.x).

Okay… so I tried creating a new Smart App pasting in the modified code that had worked previously, and changing the name to Virtual Thermostat With Device v1.1. I then went into the classic app, deleted the thermostat device created by the original smart app, went to the marketplace, selected “My Apps” and selected the newly created Smart App. I made all the same selections and saved, and then went into “My Home” . There I found the new virtual thermostat device, but when I opened it, and manipulated the desired temp, I found that it would not send any type of off or on commands to either of the two virtual switches I selected. Instead, these switches were still receiving commands from the original virtual thermostat.

With that, I figured I would just try to delete the original Smart App, but found that I was unable.
I tried to remove the Smart App from the classic app, but when I select “remove” it just clears the selections and then backs me out to the previous screen with the smart app still there. When I go into the Smart app section on the IDE, and select edit > delete, I get the error “This SmartApp can’t be deleted at this time because it is installed by one or more users”
I now get the same error message when I try deleting either the original or the newly created Smart App.
I’ve since contacted Samsung support to get some help in deleting these Smart Apps, but that was early on Friday, and still the Smart Apps remain.
This is obviously getting super frustrating… Any advice here would be very much appreciated.

Well… If you get this message and cannot find any user-accessible way to delete the SmartApp, then you can perhaps try overwriting the SmartApp with null code (i.e., just empty update() method?).

But, you’re probably at the mercy of waiting for Support to clean up your Account.

Call them. It is much quicker.

Man… that was good advice. After calling Samsung support, I was able to get this sorted in minutes instead of days. They key to resolving this, was to open the new Smartthings app, even though I don’t really use it, navagate to “Automations”, select the 3 dots in the upper right corner, select “Delete”, and confirm. Once I did this, I went to the smartapp tab in the IDE, and selected the “edit properties” option next to the smart app, and then scrolled to the bottom and selected delete. This successufly removed the smart app.
Now, after doing this, I created a fresh smart app with my pasted code that worked previously, but once again, it wouldn’t work. This time, whenever any change is made to the desired temp, the “on” command is sent to each of the switches, regardless of whether or not the desired temp is above or below the current temp.
I’m really not sure where else to go with this… I’m just getting really frustrated that I don’t seem to be making any real progress here, and just don’t get what I’m missing.

Add log.debug("message $variable") statements to trace what is happening in Live Logging.

Thank you so very much. That was exactly the suggestion I needed. After adding log messages and studying the logs as I interacted with the Smart App, I found that there was an error occurring on line 196 that was throwing off the rest of the program.
The line
outlet.on()
Should have been
outlets.on()
Once I corrected this error I found that things started working more logically, but there was still some weird persistence with the outlets remaining on when the desired temp was raised above the current temp. I noticed in the logs that the outlets were being commanded on from the Emergency cooling logic, even though I never set a temperature in that field. Within the smart app, I selected smart apps, and opened the virtual thermostat. There I entered a temperature under the currently blank “Emergency Temp” field that was a bit higher than the current temp, and saved. When I then went back to the main smart app tab, I found that everything was working perfectly.

So, annoying that apparently you need to set an emergency temp, but I suppose if you didn’t really want to use that feature, then you could just set it to a very high value.

The next step here is to try and add a feature that would exclude one of the selected outlets from the rest of the smart app logic, but only if a virtual switch is closed.
We’ll see how that goes…

Okay…so I feel like I’m almost there, but have run into another snag. As mentioned in my previous reply, I’m trying to modify this code to allow for the user to exclude one of the selected outlets from the smart app, but only if a virtual switch is closed.
My thinking was that a relatively easy way to do this would be to just write two simple If statements to the effect of…

If Virtual_Exclusion_Switch on
then remove Virtual_Switch_1 from outlets
And
If Virtual_Exclusion_Switch off
then add Virtual_Switch_1 to outlets

After reading through the tutorials, it seems like changing which devices are included in the smart app from within the code is prohibited, but this is precisely what I’m trying to do. Is there some sort of workaround for this that would allow me to achieve this functionality without having to modify every other line of code in the smart app?

Thanks again for all your help. This has been quite the learning experience.

Preferences are immutable.

Your situation could be handled multiple ways.

  • Separate the special case Switches into a second input line (i.e., outletsMain, outletsSecondary)
  • or Instead of using outlets.on(), loop through the map manually and skip over the one(s) that you wish to exclude.

The first bullet is SmartThings specific.
The second bullet is simply Groovy coding.

Ok… so in your first suggestion, would I then have to go through and add an additional If statement nested into each of the existing logic blocks to include this second input?

And I’m sorry, but I honestly don’t understand any part of your second suggestion. Can you provide a bit more detail as to what you’re explaining here? I’m quite new to smart things and Groovy, and have minimal previous coding experience.

Unfortunately, I can’t teach Groovy via Forum posts.

Take a step back and find some basic, non-SmartThings Groovy tutorials. There are 1000 online.

You have to discover and understand what outlets.on() actually means and how to break it down into pieces.

I get it. I will surely have to do some more reading. That being said, to my first question regarding your first suggestion, in that scenario, where I have two different inputs, would I then have to add an additional logic statement for each section of code?