Groups Request - Add Fans

The edit device page? Not just the listing. The listing doesn't show anything.

GE Smart Fan Control

Okay...and now turn the master to Low and then show the device edit page for the GE again.

The master works and puts but only puts one slave in the selected setting.

Only the top device in the child app gets the command. I have tried all three fans in the first group, and also one fan in the first, and one in the second, like the image below.

Thanks for looking at this . I need to run a few errands so my response may be delayed.

Ok so I was doing this remotely, and now that I am in the location with this hub (my warehouse) I noticed the fans are responding as commanded, The problem is that only one is updating its current state. These switches are acting like the old standard Z wave. I guess they have to be constantly polled...

That shouldn't matter for commands issued from the Hub. It's local changes that won't be recognized in the hub when changes are made locally.

This is the edit device page for one that isn't working? It's status is on and speed is high. So, what's the problem?

As an example, this fan shows it is on high and it is physically off.

if I refresh the webpage it still shows as on, however, if I click the refresh button on the device it will update.

It's almost like the app works so quickly, only one of the devices is able to report back.

if I operate the devices individually they report fine. maybe adding a refresh command for a delay command between each device would fix?? just a guess, thinking the data coming all at once is colliding?

What state did the fan start in?!? You are REALLY confusing me.

I asked you to start with the fans off and use the master to set them to low. If you do something different then you have to give me a complete description of exactly what you did. What did you start with? Did everything match when you started? I'm really trying to help you here but you're not making it any easier on me.

I started them with off, then I turned them to low and only one fan showed the correct status, but they all physically did turn to low. . I then turned them off, only the one fan reported its correct physical state. I then I turned them to high and again only one fan showed the correct status. all fans will physically function. It is the reporting that is the issue.

I just tried the rule that I created in the past, and it had the same reporting issue where only one device would report correctly.

I then modified the rule to have a two second delay between turning each fan on, and this time it worked and everything is reporting according to the correct physical state of the fan.

So it seems in my mind that triggering three fans to turn on, off, etc.. at one split second, causes their state reply to get screwed up

Doesn't happen with my 4 fans. Of course, they are zigbee, not z-wave. So, I dunno. Feel free to modify the app if you think you need to.

Thanks Ryan, I will try to figure out the code to put a slight delay between each device.

All the best to you!

1 Like

Wish I could help...but I have no idea how to do what you're asking. Best of luck.

1 Like

Could there be something wrong with the capability.fanSpeed? Because in my current app I try to add it to but I get no results in the input field. I have created 6 devices with all different fan drivers... None appear in my app.

EDIT: let me rephrase, I'm building an app on my own and try to use a virtual fan in it. But I can't get it to pop up in the input.

Fans are not in the groups app. A more capable app called SwitchBindings was created by Jwetzel1492, that will do what you want. Joel has even created a virtual fan device driver that can be used as a master switch.

While the app works correctly, my setup uses zwave plus fan controllers which have a issue with any more than two switches reporting correctly. I think that all of my fans being signaled to turn on in a burst causes the reporting from the switches to overload the mesh or something when they report back to the hub causing the report to be lost. I created a rule that triggers a poll of each fan with a 1 second delay between each device as a workaround for the reporting issue.

I have a fan-sync app that goes from master to slaves instead of binding them all together. This might be easier for you.

Parent App:

/**
 *  ****************  Fan Sync Parent App  ****************
 *
 *  Design Usage:
 *  Keep Fans in sync
 *
 *  Code and ideas used from Jason Bottjen (JasonJoel on Hubitat forum)
 *  
 *-------------------------------------------------------------------------------------------------------------------
 *  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.
 *
 * ------------------------------------------------------------------------------------------------------------------------------
 *
 *  Changes:
 *
 *  V1.0.0 - 4/10/2019 - Initial release.
 *
 *
 *
 */

definition(
    name:"Fan Sync",
    namespace: "ryancasler",
    author: "Ryan Casler",
    description: "Keep Fans in sync - ON/OFF",
    category: "Convenience",
    iconUrl: "",
    iconX2Url: "",
    iconX3Url: "",
)

preferences {
     page name: "mainPage", title: "", install: true, uninstall: true
} 

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

def updated() {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    initialize()
}

def initialize() {
    log.info "There are ${childApps.size()} child apps"
    childApps.each {child ->
    log.info "Child app: ${child.label}"
    }
}

def mainPage() {
    dynamicPage(name: "mainPage") {
    	installCheck()
		if(state.appInstalled == 'COMPLETE'){
			section(getFormat("title", "${app.label}")) {
				paragraph "<div style='color:#00CED1'>Keep Fans in sync - ON/OFF</div>"
				paragraph getFormat("line")
			}
			section("Instructions:", hideable: true, hidden: true) {
				paragraph "<b>Notes:</b>"
				paragraph "- Add master and slave fanes to keep in sync.<br>"
			}
  			section(getFormat("header-darkcyan", " Child Apps")) {
				app(name: "anyOpenApp", appName: "Fan Sync Child", namespace: "ryancasler", title: "<b>Add a new 'Fan Sync' child</b>", multiple: true)
  			}
 			section(getFormat("header-darkcyan", " General")) {
       				label title: "Enter a name for parent app (optional)", required: false
 			}
			display()
		}
	}
}

def installCheck(){         
	state.appInstalled = app.getInstallationState() 
	if(state.appInstalled != 'COMPLETE'){
		section{paragraph "Please hit 'Done' to install '${app.label}' parent app "}
  	}
  	else{
    	log.info "Parent Installed OK"
  	}
}

def getFormat(type, myText=""){
	if(type == "header-green") return "<div style='color:#ffffff;font-weight: bold;background-color:#81BC00;border: 1px solid;box-shadow: 2px 3px #A9A9A9'>${myText}</div>"
	if(type == "header-darkcyan") return "<div style='color:#ffffff;font-weight: bold;background-color:#008B8B;border: 1px solid;box-shadow: 2px 3px #A9A9A9'>${myText}</div>"
	if(type == "line") return "\n<hr style='background-color:#00CED1; height: 1px; border: 0;'></hr>"
	if(type == "title") return "<h2 style='color:#00CED1;font-weight: bold;font-style: italic'>${myText}</h2>"
}

def display(){
	section() {
		paragraph getFormat("line")
		paragraph "<div style='color:#00CED1;text-align:center'>Fan Sync - App Version: 1.0.0</div>"
	}       
}          

Child App:

/**
 *  ****************  Fan Sync Child App  ****************
 *

 *  Design Usage:
 *  Keep Fans in sync
 *
 *  Code and ideas used from Jason Bottjen (JasonJoel on Hubitat forum)
 *  
 *-------------------------------------------------------------------------------------------------------------------
 *  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.
 *
 * ------------------------------------------------------------------------------------------------------------------------------
 *
 *  Changes:
 *
 *  V1.0.0 - 4/10/19 - Initial release.
 *
 */

definition(
    name:"Fan Sync Child",
    namespace: "ryancasler",
    author: "Ryan Casler",
    description: "Keep Fans in sync",
    category: "",

	parent: "ryancasler:Fan Sync",
    
    iconUrl: "",
    iconX2Url: "",
    iconX3Url: "",
)

preferences {
    page(name: "pageConfig")
}

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

def updated() {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    initialize()
}

def initialize() {
	setDefaults()
	if(pause1==false){subscribeNow()}
}

def pageConfig() {
    dynamicPage(name: "pageConfig", title: "<h2 style='color:#00CED1;font-weight: bold'>Fan Sync</h2>", nextPage: null, install: true, uninstall: true, refreshInterval:0) {	
	display()
    
	section("Instructions:", hideable: true, hidden: true) {
		paragraph "<b>Notes:</b>"
		paragraph "- Select master and slave fans you want to keep in sync<br>- The slave(s) will follow the master."
	}
		
	section(getFormat("header-darkcyan", " Select Master Fan Device")) {
		input "masterFan", "capability.fanControl", title: "Select Master Fan Device", submitOnChange: true, hideWhenEmpty: true, required: true, multiple: false
	}
	section(getFormat("header-darkcyan", " Select Slave Fan Device(s)")) {
		input "slaveFan", "capability.fanControl", title: "Select Slave Fan Device(s)", submitOnChange: true, hideWhenEmpty: true, required: true, multiple: true
	}
	section(getFormat("header-darkcyan", " Select Slave Fan Device(s)")) {
		input "slaveSwitch", "capability.switch", title: "Select Slave Switch Device(s)", submitOnChange: true, hideWhenEmpty: true, required: false, multiple: true
	}
	section(getFormat("header-darkcyan", " General")) {label title: "Enter a name for this child app", required: false}
	section() {
		input(name: "logEnable", type: "bool", defaultValue: "true", title: "Enable Debug Logging", description: "Enable extra logging for debugging.")
   	}
	display2()
	}
}

def display() {
	section() {
		paragraph getFormat("line")
		input "pause1", "bool", title: "Pause This App", required: true, submitOnChange: true, defaultValue: false
	}
}

def display2() {
	section() {
		paragraph getFormat("line")
		paragraph "<div style='color:#00CED1;text-align:center'>Fan Sync - App Version: 1.0.0</div>"
	}
}

def getFormat(type, myText=""){
	if(type == "header-green") return "<div style='color:#ffffff;font-weight: bold;background-color:#81BC00;border: 1px solid;box-shadow: 2px 3px #A9A9A9'>${myText}</div>"
	if(type == "header-darkcyan") return "<div style='color:#ffffff;font-weight: bold;background-color:#008B8B;border: 1px solid;box-shadow: 2px 3px #A9A9A9'>${myText}</div>"
    if(type == "line") return "\n<hr style='background-color:#00CED1; height: 1px; border: 0;'></hr>"
	if(type == "title") return "<div style='color:#00CED1;font-weight: bold; font-style: italic'>${myText}</div>"
}

def LOGDEBUG(txt){
    try {
		if (settings.logEnable) { log.debug("${app.label} - ${txt}") }
    } catch(ex) {
    	log.error("${app.label} - LOGDEBUG unable to output requested data!")
    }
}

def pauseOrNot(){
	LOGDEBUG("In pauseOrNot...")
    state.pauseNow = pause1
        if(state.pauseNow == true){
            state.pauseApp = true
            if(app.label){
            if(app.label.contains('red')){
                log.warn "Paused"}
            else{app.updateLabel(app.label + ("<font color = 'red'> (Paused) </font>" ))
              LOGDEBUG("App Paused - state.pauseApp = $state.pauseApp ")   
            }
            }
        }
     if(state.pauseNow == false){
         state.pauseApp = false
         if(app.label){
     if(app.label.contains('red')){ app.updateLabel(app.label.minus("<font color = 'red'> (Paused) </font>" ))
     	LOGDEBUG("App Released - state.pauseApp = $state.pauseApp ")                          
        }
     }
  }    
}

def setDefaults(){
    pauseOrNot()
    if(pause1 == null){pause1 = false}
    if(state.pauseApp == null){state.pauseApp = false}
	if(logEnable == null){logEnable = false}
}

def subscribeNow() {
	unsubscribe()
	subscribe(masterFan, "speed", masterFANHandler)
}

def masterFANHandler(evt){
	LOGDEBUG("Event Value: " + evt.value)
		slaveFan.each{
			it.setSpeed(evt.value)
		}
		slaveSwitch.each{
		if (evt.value == "off")
			it.off()
		else
			it.on()
		}
}

Thanks for the tip. I had to find the code elsewhere for it to work for me also.

1 Like