Troubleshooting code on ST is driving me nuts. Help me understand?

I tried to make a small improvement to my smartapp so that you could actually view the status of the inputs that had been selected. @krlaframboise helped me use the correct syntax and the mobile app is working great in terms of it displaying the values of the display selected. YEA! But this new code (see below) is causing a new issue. It seems the new code may not be the issue but a parameter on a whole different page? Let me explain:

The problem is after after making my required inputs when I tap Done to save everything I should be getting the green confirmation “Evap Cooler Thermostat is now installed and automating” but for some reason I get a red error “An unexpected error occurred” .

This is the code that gives the ability to dynamically see the values of the user selected input of the smartapp. If I comment out this new code the smartapp will save properly and work. So I assumed I had something wrong, missing or improperly syntaxed on this little section of new code?

section("Current Conditions are"){	
        if (fanMotor) {  
    		paragraph ("${fanMotor.displayName} is ${fanMotor.currentSwitch}")
            }
        if (tempSensor) {  
    		paragraph ("${tempSensor.displayName} room temp is ${tempSensor.currentTemperature}° ")
            }
        if (fanPump) {  
    		paragraph ("${fanPump.displayName} is ${fanPump.currentSwitch} ")
			} 
        if (fanSpeed) {  
    		paragraph ("${fanSpeed.displayName} is ${fanSpeed.currentSwitch} ")
			}    
    	}

Here is the thing that is driving me nuts. As I was trying to troubleshoot the issue I randomly changed the parameter of “install” in the third page of my smartapp from true to false the error goes away?! :astonished:

def aboutPage() {
	dynamicPage(name: "aboutPage", title: none, install: false, uninstall: true) {
     	section("User's Guide for Evap Cooler Thermostat") {
        	paragraph textHelp()
 		}

So can anyone help me understand what is going on? Here is the entire code below

/*
   Virtual Thermostat for Evaporative Coolers .
   Copyright 2016 Dale Coffing, SmartThings
   
   This smartapp provides automatic control for Evaporative Coolers (single or two-speed) using 
   any temperature sensor. On a call for cooling the water pump is turned on and given two minutes
   to wet pads before fan low speed is enabled. The fan high speed is turned on if the temperature 
   continues to rise above the adjustable differential. There is an optional motion override.
   
   It requires these hardware devices; any temperature sensor, a switch for Fan On-Off, a switch
   for pump. For two speed control is desired another switch will be necessary.
   I suggest a Remotec ZFM-80 15amp relay for fan motor on-off, if you desired both pump and fan speed
   then Enerwave ZWN-RSM2 dual 10amp relays to control pump and the second relay to control hi-lo speed
   via Omoron LY1F SPDT 15amp relay. For only pump control any switch could work like the Enerwave ZWN-RSM1S
   or Monoprice #11989 Z-Wave In-Wall On/Off module
    

    
  Change Log
  2016-07-04  removed dynamic feedback section, bug preventing saving, minor grammitical edits
  	.. changed true to false install on dynamicPage(name: "aboutPage", title: none, install: false
  2016-07-02b. fixed mode bug not shutting of evap by changing mode technique, cleaned up code with shutdownEvap() 
  	a. modify dynamic feedback of inputs to be via paragraph technique
  2016-07-01 changed user select mode method, changed default delay-on to 1.5, removed the default setpoint because
  			ST still requires the user to make a change to get around Required input flag.
  2016-06-30 added dynamic temperature display readout to Room Setpoint Temp input for ease of troubleshooting
  2016-06-28 x.1 version update
  	f. added submitOnChange for motion so to skip minutes input next if no motion selected
	e. changed order of inputs for better logic flow
	d. added separate input page for only advanced options
	c. fixed bug in High Speed startup assuming fan/pump was already running
	b. renamed fanHiSpeed to fanSpeed for more generic use, added 0.0 on timer selection
	a. changed motion detector minutes input only if motion selected submitOnChange
  2016-06-22e added single speed default
	d. change user guide content
	c. modified icon to fan style, breeze style for comparison
	b. moved pump input to first position (required), made other selections not required	for those with single speed motor
    a. added icons
  2016-06-21 modify 3-speed-ceiling-fan-thermostat code for outlets

  
  Known Behavior from original Virtual Thermostat code
  -(fixed) when SP is updated, temp control isn't evaluated immediately, an event must trigger like change in temp, motion
  - if load is previously running when smartapp is loaded, it isn't evaluated immediately to turn off when SP>CT
 
   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: 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.

*/

definition(
    name: "Evap.. Cooler Thermostat",
    namespace: "dcoffing",
    author: "Dale Coffing, SmartThings",
    description: "Automatic control for an Evaporative Cooler with a 2-speed motor, water pump and any temp sensor.",
    category: "My Apps",
	iconUrl: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/evap-cooler-thermostat.src/ect125x125.png", 
   	iconX2Url: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/evap-cooler-thermostat.src/ect250x250.png",
	iconX3Url: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/evap-cooler-thermostat.src/ect250x250.png",
)

preferences {
	page(name: "mainPage", title: "")
    page(name: "optionsPage", title: "")
    page(name: "aboutPage", title: "")
}

def mainPage() {
	dynamicPage(name: "mainPage", title: "Select your devices and settings", install: true, uninstall: true){

		section("Select the Evap Cooler fan motor switch hardware..."){
			input "fanMotor", "capability.switch", 
	    	multiple:false, title: "Fan Motor On-Off Control device", required: true, submitOnChange: true  
		}   	
  
        section("Select a room temperature sensor to control the Evap Cooler..."){
			input "tempSensor", "capability.temperatureMeasurement", multiple:false, title: "Temperature Sensor", required: true, submitOnChange: true  
		}
        
        section("Enter the desired room temperature setpoint..."){
        	input "setpoint", "decimal", title: "Room Setpoint Temp", required: true
    	} 
		
// IS this little section below buggy or is it ST again? It won't let you save the app when clicking Done???
		
		section("Current Conditions are"){	//The 'if' statements used below prevent null error crash
        if (fanMotor) {  
    		paragraph ("${fanMotor.displayName} is ${fanMotor.currentSwitch}")
            }
        if (tempSensor) {  
    		paragraph ("${tempSensor.displayName} room temp is ${tempSensor.currentTemperature}° ")
            }
        if (fanPump) {  
    		paragraph ("${fanPump.displayName} is ${fanPump.currentSwitch} ")
			} 
        if (fanSpeed) {  
    		paragraph ("${fanSpeed.displayName} is ${fanSpeed.currentSwitch} ")
			}    
    	}

	
		section("Optional Settings (Fan Speed, Timers, Motion, etc)") {
			href (name: "optionsPage", 
        	title: "Configure Optional settings", 
        	description: none,
        	image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/evap-cooler-thermostat.src/settings250x250.png",
        	required: false,
        	page: "optionsPage"
        	)
        }
// VERSION
		section("Version Info, User's Guide") {
			href (name: "aboutPage", 
            title: "Evap Cooler Thermostat \n"+"Version: 1.0.160704 \n"+"Copyright © 2016 Dale Coffing", 
            description: "Tap to access user's guide.",
            image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/evap-cooler-thermostat.src/ect250x250.png",
            required: false,
            page: "aboutPage"
			)
   		}	
    }
}

def optionsPage() {
	dynamicPage(name: "optionsPage", title: "Configure Optional Settings", install: false, uninstall: false) {
    
		section("Select the Evap Cooler Fan 2-Speed switch control hardware (optional, leave blank for single speed)...."){
			input "fanSpeed", "capability.switch", 
	    	multiple:false, title: "Fan Hi-Lo 2-Speed Control device", required: false, submitOnChange: true  
		}

		section("Enter the desired differential temp between fan speeds (default=1.0)..."){
			input "fanDiffTempString", "enum", title: "Fan Differential Temp", options: ["0.5","1.0","1.5","2.0"], required: false
		}
        
        section("Select the Evap Cooler water pump switch hardware..."){
			input "fanPump", "capability.switch", 
	    	multiple:false, title: "Water Pump On-Off Control device", required: false, submitOnChange: true  
		}
    	section("Enter the desired minutes to delay start of fan to allow for wetting of pads. (default=1.5)..."){
			input "fanDelayOnString", "enum", title: "Fan Delay On Timer", options: ["0.0","0.5","1.0","1.5","2.0","2.5"], required: false
		}
		section("Enable Evap Cooler thermostat only if motion is detected at (optional, leave blank to not require motion)..."){
			input "motionSensor", "capability.motionSensor", title: "Select Motion device", required: false, submitOnChange: true
		}
        
        if (motionSensor) {
			section("Turn off Evap Cooler when there's been no motion detected for..."){
				input "minutesNoMotion", "number", title: "Minutes?", required: true
			}
        }
		
        section("Select Evap Cooler operating method desired (default to 'YES-Auto'..."){
			input "autoMode", "enum", title: "Enable Evap Cooler Thermostat?", options: ["NO-Manual","YES-Auto"], required: false
		}
        
		section ("Change SmartApp name, Mode selector") {
			label title: "Assign a name", required: false
//          mode(title: "Set for specific mode(s)"), required: false  //this technique for User mode fails tempHandler still executes for this smartapp?
            input "selectedModes", "mode", title:  "Select specific mode(s) to run (default is ALL modes)", multiple: true, required: false
			}      	
	}
  }

def aboutPage() {
	dynamicPage(name: "aboutPage", title: none, install: false, uninstall: true) {
     	section("User's Guide for Evap Cooler Thermostat") {
        	paragraph textHelp()
 		}
	}
}

def installed() {
	log.debug "def INSTALLED with settings: ${settings}"
	initialize()
}

def updated() {
	log.debug "def UPDATED with settings: ${settings}"
	unsubscribe()
	initialize()
    handleTemperature(tempSensor.currentTemperature) //call handleTemperature to bypass temperatureHandler method 
} 

def initialize() {
	log.debug "def INITIALIZE with settings: ${settings}"
	subscribe(tempSensor, "temperature", temperatureHandler) //call temperatureHandler method when any reported change to "temperature" attribute
	subscribe(location, "mode", modeChangedHandler) //call modeChangedHandler with any reported change to "mode" change attribute 
    if (motionSensor) {
		subscribe(motionSensor, "motion", motionHandler) //call the motionHandler method when there is any reported change to the "motion" attribute
	}   
}

def shutdownEvap() {
	fanMotor.off()
	fanPump.off()
	fanSpeed.off()
}

def temperatureHandler(evt) {
	log.debug "temperatureHandler called: $evt"	
    handleTemperature(evt.doubleValue)
	log.debug "temperatureHandler evt.doubleValue : $evt"
}

def handleTemperature(temp) {		//
	log.debug "handleTemperature called: $evt"	
	def isActive = hasBeenRecentMotion()
	if (isActive) {
		//motion detected recently
		tempCheck(temp, setpoint)
		log.debug "handleTemperature ISACTIVE($isActive)"
	} else {
     	shutdownEvap()
 	}
}    

def motionHandler(evt) {
	if (evt.value == "active") {
		//motion detected
		def lastTemp = tempSensor.currentTemperature
		log.debug "motionHandler ACTIVE($isActive)"
		if (lastTemp != null) {
			tempCheck(lastTemp, setpoint)
		}
	} else if (evt.value == "inactive") {		//testing to see if evt.value is indeed equal to "inactive" (vs evt.value to "active")
		//motion stopped
		def isActive = hasBeenRecentMotion()	//define isActive local variable to returned true or false
		log.debug "motionHandler INACTIVE($isActive)"
		if (isActive) {
			def lastTemp = tempSensor.currentTemperature
			if (lastTemp != null) {				//lastTemp not equal to null (value never been set) 
				tempCheck(lastTemp, setpoint)
			}
		} else {
			shutdownEvap()
		}
	}
}

private tempCheck(currentTemp, desiredTemp) {

	log.debug "TEMPCHECK#1(CT=$currentTemp, SP=$desiredTemp, FM=$fanMotor.currentSwitch, automode=$autoMode, FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)"
    
    //convert Fan Delay On input enum string to number value and if user doesn't select a Fan Delay On value, then default to 1.5 
    def fanDelayOnValue = (settings.fanDelayOnString != null && settings.fanDelayOnString != "") ? Double.parseDouble(settings.fanDelayOnString): 1.5
    
    //convert Fan Diff Temp input enum string to number value and if user doesn't select a Fan Diff Temp default to 1.0 
    def fanDiffTempValue = (settings.fanDiffTempString != null && settings.fanDiffTempString != "") ? Double.parseDouble(settings.fanDiffTempString): 1.0
    

    def autoModeValue = (settings.autoMode != null && settings.autoMode != "") ? settings.autoMode : "YES-Auto"	
    
    def LowDiff = fanDiffTempValue*1 
    def HighDiff = fanDiffTempValue*2

	log.debug "TEMPCHECK#2(CT=$currentTemp, SP=$desiredTemp, FM=$fanMotor.currentSwitch, automode=$autoMode, FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)"
	

	if (currentModeAllowed(settings.selectedModes)) {
	// Executes if current ST mode matches one of the user selected modes.
     
		if (autoModeValue == "YES-Auto") {
			switch (currentTemp - desiredTemp) {
				case { it  >= HighDiff }:
					// turn on fan high speed
					fanSpeed.on()			// set fan Hi speed
					if (fanMotor.currentSwitch == "off") {		// if fan is OFF turn everything on 
						fanPump.on()							// set water pump on 
						fanMotor.on([delay: (fanDelayOnValue*60*1000)])			// delay starting fan to allow pump to wet pads 
						log.debug "HI speed(CT=$currentTemp, SP=$desiredTemp,  HighDiff=$HighDiff, fanDelayOnValue=$fanDelayOnValue)"
					} else { //fan and pump already running 
						}
					break  //exit switch statement 
				case { it >= LowDiff }:
					// turn on fan low speed
					if (fanMotor.currentSwitch == "off") {		// if fan is OFF turn everything on 
						fanSpeed.off()						// set fan Lo speed
						fanPump.on()							// set water pump on 
						fanMotor.on([delay: (fanDelayOnValue*60*1000)])			// delay starting fan to allow pump to wet pads 
                		log.debug "Fan Lo speed in fanDelayOn min (CT=$currentTemp, SP=$desiredTemp,  LowDiff=$LowDiff)"
					} else {
						fanSpeed.off()	//fan is already running, set Low speed immediately
					}
					log.debug "LO speed skip pump (CT=$currentTemp, SP=$desiredTemp,  LowDiff=$LowDiff)"
					break
				default:
					// check to see if fan should be turned off
					if (desiredTemp - currentTemp >= 0 ) {	//below or equal to setpoint, turn off fan, 
						shutdownEvap()
						log.debug "below SP+Diff=fan OFF (CT=$currentTemp, SP=$desiredTemp, FD=$fanMotor.currentSwitch, autoMode=$autoMode,)"
					} 
					log.debug "autoMode YES-MANUAL? else OFF(CT=$currentTemp, SP=$desiredTemp, FD=$fanMotor.currentSwitch, autoMode=$autoMode,)"
			}	
		}

	} else {			// if current ST mode does NOT match one of the user selected modes.
	shutdownEvap()
	}
}

def currentModeAllowed(allowedModes) {
    return (!allowedModes || allowedModes?.find{it == location.mode}) 
}

private hasBeenRecentMotion() {
	def isActive = false
	if (motionSensor && minutesNoMotion) {
		def deltaMinutes = minutesNoMotion as Long
		if (deltaMinutes) {
			def motionEvents = motionSensor.eventsSince(new Date(now() - (60000 * deltaMinutes)))
			log.trace "Found ${motionEvents?.size() ?: 0} events in the last $deltaMinutes minutes"
			if (motionEvents.find { it.value == "active" }) {
				isActive = true
			}
		}
	} else {
		isActive = true
	}
	isActive
}

private def textHelp() {
	def text =
    "This smartapp provides automatic control for Evaporative Coolers (single or two-speed) using"+
   " any temperature sensor. On a call for cooling the water pump is turned on and given two minutes"+
   " to wet pads before fan low speed is enabled. The fan high speed is turned on if the temperature"+ 
   " continues to rise above the adjustable differential. There is an optional motion override.\n\n"+
   
   "It requires these hardware devices; any temperature sensor, a switch for Fan On-Off, a switch"+
   " for pump. If two speed control is desired another switch will be necessary.\n\n"+
   " You might consider using a Remotec ZFM-80 15amp relay for fan motor on-off, if you desire both"+
   " pump and fan speed then Enerwave ZWN-RSM2 dual 10amp relays to control pump and the second relay"+
   " to control hi-lo speed via Omoron LY1F SPDT 15amp relay. For only pump control any single switch could"+
   " work like the Enerwave ZWN-RSM1S or Monoprice #11989 Z-Wave In-Wall On/Off module. \n\n"+
   
   " To uninstall the smartapp simply tap REMOVE below"  
   
}
1 Like

There have been at least two other reports in the forum today of weird errors when trying to install any smart app. Even ones from the marketplace section of the mobile app.

I don’t see anything on the status page, but I’m wondering if there’s a platform error going on.

1 Like

Interesting… I will keep my eye on this and see if something gets up on the ST status page.

UPDATE: You may be on to something @JDRoberts
Now the error is back even with the change that worked this morning! ST is making me grow old faster :scream: Something is apparently going on behind the scenes that affects adding SmartApps

And of course the Status page is showing everything operational?!

2 Likes

The behavior of the SmartThings IDE and SmartApp / DTH install is quite frequently inexplicable.

I’ve sometimes had an error go away just by copying the code into a new blank SmartApp!

1 Like

Brother you have got to be kidding me!! I just tried your “trick” and it WORKED! :scream:

I have spent two days trying to chase down this weird behavior thinking it was in my newly modified code and all along it was ST? :fearful:

The good news is I can trick ST into loading the app but this trick messes up the GitHub integration… I wonder if GitHub may be a related underlying issue?

1 Like

It’s certainly possible.

Some people find the GitHub integration not particularly valuable to their environment, and someone even noticed that it really does slow down the loading of pages in the IDE.

Looking into this. Also submit support tickets because supporting from a forum is not ideal.

@dalec please PM me your account and which app this was happening on so I can expedite engineering’s effectiveness.

2 Likes

Thanks for responding and I will do! :relaxed:

FYI, Less than a week ago I submitted “bug” support tickets on a custom smartapp and I get the generic copy/paste blah-blah Have a great day! blanket statement below so that is why I didn’t even bother to submit.

On Thu, Jun 30, 2016 at 4:39 PM, SmartThings Support support@smartthings.com wrote:
In replies all text above this line is added to the ticket
Jason (SmartThings)
Jun 30, 3:39 PM MST

Hello Dale,

Thanks for reaching out to us. Unfortunately we can not assist with custom SmartApps or coding. However it looks like you have things figured out at this point from reading through the post. If you are experiencing problems with custom code, the community forums are always a great place to get assistance. Here is a link to our SmartThings Developer Documentation which has a lot of great information. If you do run into any issues down the road please let us know. Have a great day!

Kind Regards,
Jason

They truly aren’t equipped for helping with development questions. For help on development see our section on “getting help” in the docs.

http://docs.smartthings.com/en/latest/getting-started/getting-help.html

2 Likes

I didn’t realize there was a different support form to use for developer issues. I will get that one filled out. I would suggest to the email support team to change their blanket email response to point to that form to use.

Thanks Tim for looking into this for me I really do appreciate getting this ironed out. I actually have two different thermostat smartapps so this will be solving two issues at once. :grinning: I am thinking it is not all on ST but something my smartapp code end as well.

Even after I do the “trick” and save another copy and that does work to get the app installed it will fail later on when trying to make input changes on that installed smartapp putting me back into square one all over again.

2 Likes

@dalec where you putting your switches to automate your swamp cooler? (Both fan and pump??)

David, I am not sure of the question. The actual smart switches are going in a wall

I have pictures of the switches located in the discussion below if that helps?

Yes sorry. I’ve mostly been using ge zwave switches but putting more than on in a box is crowded so I was wondering how you got three in yours (or two).(one for pump, one for on/off blower, one for fan speed)
Or if you used something else?

V/R,
-David