3 Speed Fan based on temp

Great work @Shane_pcs @spalexander68 - found it very useful. I was having a similar problem with my child apps. Wonder why it worked in ST, I guess they never honored the flag. Anyway thanks for the post.

PS you may to clean up the parent/child apps put them in the first proper post with instructions as well as the issue resolution.

Whelp, not sure how I missed that one, but I found it. Thanks!

Hi....i think the problem you are having is because Dale, like many devs in ST, is using a hybrid method that allows you to merge the child and parent apps into one "hybrid" app. You will need to split the app into 2 separate apps for it to work in HE.

This app works great as designed. Now that summer is here however, and the app is really kicking in, it turns the fans on whether you want it or not. How can I mod it to only run when the fan has been turned using another means like a switch or app. i.e. don't turn the fan on/off only control the speed.

Any one fix this to work?

[dcoffing/KOF-CeilingFan/blob/master/smartapps/dcoffing/4-speed-ceiling-fan-thermostat-zigbee.src/4-speed-ceiling-fan-thermostat-zigbee.groovy ]

First time posting and thought I was tagging @dcoffing on the other thread. SO is there a way to make this one you modified for 4 speed?

Quoting a tag like you did in the other thread does not also tag the person again. How you did it in the post above is the correct way. A quote only alerts the person you are quoting directly. A tag (@username) alerts that person directly. I'm not sure how active Dale is in the forums these days so hopefully he chimes in to assist.

Funny, I forgot that I helped someone with this app so far back. At that time Dale was not a part of the Hubitat community. My assistance above was merely a structural fix that allowed that app to work with HE. I have no idea how anything else works within it. I also no longer use HE and hang around primarily to support my non-deprecated apps and drivers....so I would be unable to correct and test the 4 speed app you linked to above.

Cross your fingers that someone else has already done this or that Dale sees your tag above and helps out.

Stephan

2 Likes

Joe,

I took a stab at making the same tweaks @stephack made for the 3-speed to the 4-speed version. I haven't tested it, but it does at least load on the hub and you can create a child app without throwing errors.

At this point, I am not sure I can be much more help. I hope this gets you what you need!

Here is the Parent code

//   ZigBee 4 Speed Ceiling Fan Thermostat Control
   
  def version() {return "v0.1b.20170609" }    
/*  Change Log
 2017-06-09 removed the delay line for LOW speed start until ST platform issues are resolved
 2017-06-01 removed singleInstance since we don't use a Service Manager, move Version Info, User Guide to Parent screen
 2017-05-04 fixed user manual title to 4Speed, icons moved to KOF repo, user manual content revised
  bugfix, even though published and I load this from MyApps it still is using the older version code from zwave parent/child
 2017-04-27  starting modifications for zigbee
 2017-04-11 Added 10.0 selection for Fan Differential Temp to mimic single speed control
 2016-10-19 Ver2 Parent / Child app to allow for multiple use cases with a single install - @ericvitale
  
*/
definition(
    name: "4 Speed Ceiling Fan Thermostat - ZigBee - Parent",
    namespace: "dcoffing",
    author: "Dale Coffing",
    description: "Thermostat control for ZigBee 4 Speed Ceiling Fan device (Home Decorators Ceiling Fan/Light Controller MR101Z) staging each speeds with any temperature sensor.",
    category: "My Apps",
	iconUrl: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/3scft125x125.png", 
   	iconX2Url: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/3scft250x250.png",
	iconX3Url: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/3scft250x250.png",
)

preferences {
        page(name: "parentPage")
        page(name: "aboutPage")
}

def parentPage() {   
    return dynamicPage(name: "parentPage", title: "", nextPage: "", install: true, uninstall: true) {
        section("Create a new fan automation.") {
            app(name: "childApps", appName: "4 Speed Ceiling Fan Thermostat - ZigBee", namespace: "dcoffing", title: "New ZigBee Ceiling Fan Automation", multiple: true)
        }

        section("Version Info, User's Guide") {
	        href (name: "aboutPage", 
		    title: "4 Speed Ceiling Fan Thermostat \n"+ version() +" \n"+"Copyright © 2017 Dale Coffing", 
		    description: "Tap for SmartApp info & User's Guide",
		    image: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/3scft125x125.png",
		    required: false,
		    page: "aboutPage"
		    )
	    }
    }
}

def aboutPage() {
	dynamicPage(name: "aboutPage", title: none, install: true, uninstall: true) {
     	section("User's Guide; 4 Speed Ceiling Fan Thermostat - ZigBee") {
        	paragraph textHelp()
 		}
	}
}

def installed() {
	initialize()
}

def initialize() {
    log.debug "Parent Initialized"
}

def initParent() {
	log.debug "Parent Initialized"
}

private def textHelp() {
	def text =
	
    	"This smartapp provides automatic control of 4 speeds on a"+
		" ZigBee ceiling fan using any temperature sensor based on its' temperature setpoint"+
        " turning on each speed automatically in 1 degree differential increments."+
        " For example, if the desired room temperature setpoint is 72, speed 1 (low)"+
        " turns on at 73, then speed 2 (medium) at 74, then speed 3 (med-high) at 75, then"+
        " speed 4 (high) at 76. And vice versa on decreasing temperature until at 72 the ceiling"+
        " fan turns off. The differential is adjustable from 0.5 to 2.0 in half degree increments. \n\n" +
        "A notable feature is when low speed is initially requested from"+
        " the off condition, high speed is turned on briefly to overcome the startup load"+
        " then low speed is engaged. This mimics the pull chain switches that most"+
        " manufacturers use by always starting in high speed. \n\n"+
      	"A motion option turns off automatic mode when no motion is detected. A thermostat"+
        " mode option will disable the smartapp and pass control to manual control.\n\n"+
        "This app written specifically for the 'KOF ZigBee Fan Controller Custom Device Handler' used"+
        " in the Hampton Bay Wink Ceiling Fan MR101Z receiver in the Gardinier 52' Ceiling Fan or"+
        " Universal Ceiling Fan Premier Remote from Home Depot."
    
    }

and here is the Child code


//   ZigBee 4 Speed Ceiling Fan Thermostat Control
   
  def version() {return "v0.1b.20170609" }    
/*  Change Log
 2017-06-09 removed the delay line for LOW speed start until ST platform issues are resolved
 2017-06-01 removed singleInstance since we don't use a Service Manager, move Version Info, User Guide to Parent screen
 2017-05-04 fixed user manual title to 4Speed, icons moved to KOF repo, user manual content revised
  bugfix, even though published and I load this from MyApps it still is using the older version code from zwave parent/child
 2017-04-27  starting modifications for zigbee
 2017-04-11 Added 10.0 selection for Fan Differential Temp to mimic single speed control
 2016-10-19 Ver2 Parent / Child app to allow for multiple use cases with a single install - @ericvitale
  
*/
definition(
    name: "4 Speed Ceiling Fan Thermostat - ZigBee",
    namespace: "dcoffing",
    author: "Dale Coffing",
    description: "Thermostat control for ZigBee 4 Speed Ceiling Fan device (Home Decorators Ceiling Fan/Light Controller MR101Z) staging each speeds with any temperature sensor.",
    category: "My Apps",
    parent: "dcoffing:4 Speed Ceiling Fan Thermostat - ZigBee - Parent",
    singleInstance: false,
	iconUrl: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/3scft125x125.png", 
   	iconX2Url: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/3scft250x250.png",
	iconX3Url: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/3scft250x250.png",
)

preferences {
        page(name: "childStartPage")
        page(name: "optionsPage")
        page(name: "aboutPage")
}


def childStartPage() {
	dynamicPage(name: "childStartPage", title: "Select your devices and settings", install: true, uninstall: true) {
    
        section("Select a room temperature sensor to control the fan..."){
			input "tempSensor", "capability.temperatureMeasurement", multiple:false, title: "Temperature Sensor", required: true, submitOnChange: true  
		}
        if (tempSensor) {  //protects from a null error
    		section("Enter the desired room temperature setpoint...\n" + "NOTE: ${tempSensor.displayName} room temp is ${tempSensor.currentTemperature}° currently"){
        		input "setpoint", "decimal", title: "Room Setpoint Temp", defaultValue: tempSensor.currentTemperature, required: true
    		}
        }
        else 
        	section("Enter the desired room temperature setpoint..."){
        		input "setpoint", "decimal", title: "Room Setpoint Temp", required: true
    		}       
       
        section("Select the Parent ceiling fan/light control hardware... (NOT the Light or Fan Speed Child )"){
        // fanDimmer
			input "fanSwitch", "capability.switch", multiple:false, title: "ZigBee Fan Control device", required: true
		}
        section("Optional Settings (Diff Temp, Timers, Motion, etc)") {
			href (name: "optionsPage", 
        	title: "Configure Optional settings", 
        	description: none,
        	image: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/settings250x250.png",
        	required: false,
        	page: "optionsPage"
        	)
        }
        
        section("Name") {
        	label(title: "Assign a name", required: false)
        }
        
/*        section("Version Info, User's Guide") {
// VERSION
			href (name: "aboutPage", 
			title: "4 Speed Ceiling Fan Thermostat \n"+ version() +" \n"+"Copyright © 2017 Dale Coffing", 
			description: "Tap to get user's guide.",
			image: "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/3scft125x125.png",
			required: false,
			page: "aboutPage"
			)
		}
*/	}
}      

def optionsPage() {
	dynamicPage(name: "optionsPage", title: "Configure Optional Settings", install: false, uninstall: false) {
       	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","10.0"], required: false
		}
		section("Enable ceiling fan 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 ceiling fan thermostat when there's been no motion detected for..."){
				input "minutesNoMotion", "number", title: "Minutes?", required: true
			}
		}
        section("Select ceiling fan operating mode desired (default to 'YES-Auto'..."){
			input "autoMode", "enum", title: "Enable Ceiling Fan Thermostat?", options: ["NO-Manual","YES-Auto"], required: false
		}
    	section ("Change SmartApp name, Mode selector") {
		mode title: "Set for specific mode(s)", required: false
		}
    }
}

def aboutPage() {
	dynamicPage(name: "aboutPage", title: none, install: true, uninstall: true) {
     	section("User's Guide; 4 Speed Ceiling Fan Thermostat - ZigBee") {
        	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
	if (motionSensor) {
		subscribe(motionSensor, "motion", motionHandler) //call the motionHandler method when there is any reported change to the "motion" attribute
	}   
}

                                   //Event Handler Methods                     
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 {
     	fanSwitch.off()
 	}
}

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 {
     	    fanSwitch.off()
		}
	}
}

private tempCheck(currentTemp, desiredTemp)
{
	log.debug "TEMPCHECK#1(CT=$currentTemp,SP=$desiredTemp,FS=$fanSwitch.currentSwitch,automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)"
    
    //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
	
    //if user doesn't select autoMode then default to "YES-Auto"
    def autoModeValue = (settings.autoMode != null && settings.autoMode != "") ? settings.autoMode : "YES-Auto"	
    
    def LowDiff = fanDiffTempValue*1 
    def MedDiff = fanDiffTempValue*2
    def MedHighDiff = fanDiffTempValue*3
    def HighDiff = fanDiffTempValue*4
	
	log.debug "TEMPCHECK#2(CT=$currentTemp,SP=$desiredTemp,FS=$fanSwitch.currentSwitch, automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)"
	if (autoModeValue == "YES-Auto") {
    	switch (currentTemp - desiredTemp) {
        case { it  >= HighDiff }:
        		// turn on fan HIGH speed4
       			fanSwitch.setSpeed(4) 
            	log.debug "HI speed(CT=$currentTemp, SP=$desiredTemp, FS=$fanSwitch.currentSwitch, Speed=$currentsetFanSpeed, HighDiff=$HighDiff)"
	        break 
        case { it  >= MedHighDiff }:
        		// turn on fan MED-HIGH speed3
       			fanSwitch.setSpeed(3) 
            	log.debug "HI speed(CT=$currentTemp, SP=$desiredTemp, FS=$fanSwitch.currentSwitch, Speed=$currentsetFanSpeed, HighDiff=$HighDiff)"
	        break 
		case { it >= MedDiff }:
            	// turn on fan MEDIUM speed2
            	fanSwitch.setSpeed(2) 
            	log.debug "MED speed(CT=$currentTemp, SP=$desiredTemp, FS=$fanSwitch.currentSwitch, MedDiff=$MedDiff)"
                break
       		case { it >= LowDiff }:
            	// turn on fan LOW speed1
            	if (fanSwitch.currentSwitch == "off") {		// if fan is OFF to make it easier on motor by   
//            		fanSwitch.setSpeed(4)					// starting fan in High speed temporarily then 
//                	fanSwitch.setSpeed(1, [delay: 500])	// change to Low speed after 1/2 second
                    fanSwitch.setSpeed(1)	            // took out Hi speed start delay until ST platform issues are resolved causing HI speed stuck on
                	log.debug "LO speed after HI 3secs(CT=$currentTemp, SP=$desiredTemp, FS=$fanSwitch.currentSwitch, LowDiff=$LowDiff)"
          		} else {
                	fanSwitch.setSpeed(1)	//fan is already running, not necessary to protect motor
            	}							//set Low speed immediately
            	log.debug "LO speed immediately(CT=$currentTemp, SP=$desiredTemp, FS=$fanSwitch.currentSwitch, 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, zero level
            		fanSwitch.off()
            		log.debug "below SP+Diff=fan OFF (CT=$currentTemp, SP=$desiredTemp, FS=$fanSwitch.currentSwitch, autoMode=$autoMode,)"
				} 
                log.debug "autoMode YES-MANUAL? else OFF(CT=$currentTemp, SP=$desiredTemp, FS=$fanSwitch.currentSwitch, autoMode=$autoMode,)"
        }	
	}	
}

private hasBeenRecentMotion()
{
	def isActive = false
	if (motionSensor && minutes) {
		def deltaMinutes = minutes 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 of 4 speeds on a"+
		" ZigBee ceiling fan using any temperature sensor based on its' temperature setpoint"+
        " turning on each speed automatically in 1 degree differential increments."+
        " For example, if the desired room temperature setpoint is 72, speed 1 (low)"+
        " turns on at 73, then speed 2 (medium) at 74, then speed 3 (med-high) at 75, then"+
        " speed 4 (high) at 76. And vice versa on decreasing temperature until at 72 the ceiling"+
        " fan turns off. The differential is adjustable from 0.5 to 2.0 in half degree increments. \n\n" +
        "A notable feature is when low speed is initially requested from"+
        " the off condition, high speed is turned on briefly to overcome the startup load"+
        " then low speed is engaged. This mimics the pull chain switches that most"+
        " manufacturers use by always starting in high speed. \n\n"+
      	"A motion option turns off automatic mode when no motion is detected. A thermostat"+
        " mode option will disable the smartapp and pass control to manual control.\n\n"+
        "This app written specifically for the 'KOF ZigBee Fan Controller Custom Device Handler' used"+
        " in the Hampton Bay Wink Ceiling Fan MR101Z receiver in the Gardinier 52' Ceiling Fan or"+
        " Universal Ceiling Fan Premier Remote from Home Depot."
    
    }
2 Likes

Sweet! I’ll check it out. Thanks!

1 Like

Dan the man!

3 Likes

Awesome! it works, however the fan control device is not needed and doesn't show the fan in the drop down. the Zigbee fan control device does. I tried to modify the app without success.

Yep, that may have been a cut and paste error... I have removed it above.

Same result I got. It doesn't show in the app list, however it does show in use by on device page. Also I can only add one, when I try to add another it shows the previous settings.

I'm sure it's a simple menu option change. I'm not familiar with how to change it.

Sorry. I’ve been pretty busy and haven’t had time to look at it.

I get it. I’ve been fiddling around with it. If you do get to it please let me know what the change is. Thanks for your time.

Joe,

I have tweaked the Parent Code in my post above and I believe it might be working now. Please give it a try. I created a virtual Hampton Bay Fan Controller device on my development hub and I was able to select the Parent device for the Fan. Also, you can now properly click Done after adding a child.

Close. It now saves and shows up in the apps list now. But it won't let me create any more. When I try to create another it shows the previous child and only edits it.

@joe-hennessy - OK, I figured out why it only allowed one child. I have fixed that in the child app code posted above.

Please give it one more try.

That did it. All your time and work is very much appreciated.