From 3f74e25548b5dacd82ea0c4d07be0af7792deee3 Mon Sep 17 00:00:00 2001 From: Rafael de Medeiros Borja Gomes Date: Mon, 29 Jul 2019 21:12:08 -0400 Subject: [PATCH 1/9] Working version for new app. Light device is being replicated twice --- ...e-fan-controller-light-child-device.groovy | 93 ++++++++++++------- .../kof-zigbee-fan-controller.groovy | 39 +++++--- 2 files changed, 87 insertions(+), 45 deletions(-) diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy index 3b1b8ac..b5be6bd 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy @@ -13,7 +13,7 @@ * 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. */ - def version() {return "ver 0.2.170515a"} + def version() {return "ver 0.2.170515"} /* a- added valueTile for rangeValue; forced to use 2x2 or bug in device handler makes font unreadably small so modified controlTile 4x2 to match up rangeValue tile size, shorten ver to increase font in tile @@ -34,62 +34,87 @@ 2017 Year */ metadata { - definition (name: "KOF Zigbee Fan Controller - Light Child Device", namespace: "dcoffing", author: "Stephan Hackett") { + definition (name: "KOF Zigbee Fan Controller - Light Child Device", namespace: "dcoffing", author: "Stephan Hackett", mnmn: "SmartThings", vid: "generic-switch", runLocally: true, executeCommandsLocally: true) { capability "Actuator" + +// capability "Actuator" capability "Switch" capability "Switch Level" - capability "Light" - capability "Sensor" +// capability "Light" +// capability "Sensor" } tiles(scale: 2) { - //multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { - // tileAttribute ("switch", key: "PRIMARY_CONTROL") { - // attributeState "off", label:"off", action: "on", icon: getIcon()+"light_grey.png", backgroundColor: "#ffffff", nextState: "turningOn" - // attributeState "on", label: "on", action: "off", icon: getIcon()+"lightH.png", backgroundColor: "#00A0DC", nextState: "turningOff" - // attributeState "turningOn", label:"TURNING ON", action: "on", icon: getIcon()+"lightI.png", backgroundColor: "#2179b8", nextState: "turningOn" - // attributeState "turningOff", label:"TURNING OFF", action:"off", icon: getIcon()+"lightI.png", backgroundColor:"#2179b8", nextState: "turningOff" - // } - // tileAttribute ("device.level", key: "SLIDER_CONTROL") { - // attributeState "level", action: "setLevel" - // } - //} + + multiAttributeTile(name: "switch", type: "lighting", width: 1, height: 1, canChangeIcon: true) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState("on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff") + attributeState("off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn") + attributeState("turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff") + attributeState("turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn") + } + + + tileAttribute ("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action:"switch level.setLevel" + } + + // controlTile ("level", "level", "slider", width: 4, height: 2) { + // state "level", action: "setLevel" + // } + + // state "off", label:"OFF", action: "on", icon: getIcon()+"light_grey.png", backgroundColor: "#ffffff", nextState: "turningOn" + // state "on", label: "ON", action: "off", icon: getIcon()+"lightH.png", backgroundColor: "#00A0DC", nextState: "turningOff" + // state "turningOn", label:"TURNING ON", action: "on", icon: getIcon()+"lightI.png", backgroundColor: "#2179b8", nextState: "turningOn" + // state "turningOff", label:"TURNING OFF", action:"off", icon: getIcon()+"lightI.png", backgroundColor:"#2179b8", nextState: "turningOff" + } - standardTile("switch", "switch", decoration: "flat", width: 6, height: 4, canChangeIcon: true) { - state "off", label:"OFF", action: "on", icon: getIcon()+"light_grey.png", backgroundColor: "#ffffff", nextState: "turningOn" - state "on", label: "ON", action: "off", icon: getIcon()+"lightH.png", backgroundColor: "#00A0DC", nextState: "turningOff" - state "turningOn", label:"TURNING ON", action: "on", icon: getIcon()+"lightI.png", backgroundColor: "#2179b8", nextState: "turningOn" - state "turningOff", label:"TURNING OFF", action:"off", icon: getIcon()+"lightI.png", backgroundColor:"#2179b8", nextState: "turningOff" - } - controlTile ("level", "level", "slider", width: 4, height: 2) { - state "level", action: "setLevel" - } - valueTile("rangeValue", "device.level", width: 2, height: 2) { - state "range", label:'${currentValue}%', defaultState: true - } - valueTile("version", "version", width: 6, height: 2) { - state "version", label:"\n Light Child \n" + version()+"\n" - } + + controlTile("levelSliderControl", "device.level", "slider", width: 6, height: 1) { + state "level", action:"switch level.setLevel" + } + + main(["switch"]) - details(["switch", "rangeValue", "level", "version"]) + details(["switch", "levelSliderControl", "slider"]) } } -def getIcon() { - return "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/" -} def on() { parent.lightOn() + parent.childOn(device.deviceNetworkId) sendEvent(name: "switch", value: "on") } def off() { parent.lightOff() sendEvent(name: "switch", value: "off") + parent.childOff(device.deviceNetworkId) } def setLevel(val) { parent.lightLevel(val) sendEvent(name: "level", value: val) +} + +def ping() { + log.debug "ping().." + refresh() +} + +def refresh() { + log.debug "refresh()" +} + +def installed() { + initialize() +} + +def updated() { + initialize() +} + +def initialize() { + state.version = version() } \ No newline at end of file diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy index 0c364c1..f25e61c 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy @@ -25,7 +25,7 @@ def version() {"ver 0.2.170515"} //update as needed def currVersions(child) { //Let's user know if running the child versions that corresponds to this parent version if(child=="fan") {return "ver 0.2.170515"} //manually enter the version of the FAN child that matches the parent version above -if(child=="light") {return "ver 0.2.170515a"} //manually enter the version of the LIGHT child that matches the parent version above +if(child=="light") {return "ver 0.2.170515"} //manually enter the version of the LIGHT child that matches the parent version above } /* @@ -56,13 +56,13 @@ if(child=="light") {return "ver 0.2.170515a"} //manually enter the version of th */ metadata { definition (name: "KOF Zigbee Fan Controller", namespace: "dcoffing", author: "Stephan Hackett, Ranga Pedamallu, Dale Coffing") { - capability "Actuator" + // capability "Actuator" capability "Configuration" capability "Refresh" capability "Switch" - capability "Light" - capability "Sensor" - capability "Polling" + // capability "Light" + // capability "Sensor" + // capability "Polling" //capability "Health Check" command "lightOn" @@ -79,6 +79,11 @@ metadata { attribute "FchildCurr", "string" //stores color of version check fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0202", outClusters: "0003, 0019", model: "HDC52EastwindFan" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0202", outClusters: "0003, 0019", model: "HDC52EastwindFan", manufacturer: "King Of Fans, Inc." + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 020" + + + } preferences { @@ -216,7 +221,7 @@ def updated() { } def initialize() { - log.info "Initializing" + log.info "Initializing" if(refreshChildren) { deleteChildren() device.updateSetting("refreshChildren", false) @@ -249,8 +254,8 @@ def createFanChild() { it.device.deviceNetworkId == "${device.deviceNetworkId}-0${i}" } if (!childDevice && i != 5) { - childDevice = addChildDevice("KOF Zigbee Fan Controller - Fan Speed Child Device", "${device.deviceNetworkId}-0${i}", null,[completedSetup: true, - label: "${device.displayName} ${getFanName()["0${i}"]}", isComponent: true, componentName: "fanMode${i}", + childDevice = addChildDevice("KOF Zigbee Fan Controller - Fan Speed Child Device", "${device.deviceNetworkId}-0${i}", null,[completedSetup: false, + label: "${device.displayName} ${getFanName()["0${i}"]}", isComponent: false, componentLabel: "${getFanName()["0${i}"]}", "data":["speedVal":"0${i}","parent version":version()]]) log.info "Creating child fan mode ${childDevice}" } @@ -268,10 +273,15 @@ def createLightChild() { it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" } if (!childDevice) { - childDevice = addChildDevice("KOF Zigbee Fan Controller - Light Child Device", "${device.deviceNetworkId}-Light", null,[completedSetup: true, - label: "${device.displayName} Light", isComponent: false, componentName: "fanLight", + log.debug "That's the hub id ${device.hub.id}" + + childDevice = addChildDevice("KOF Zigbee Fan Controller - Light Child Device", "${device.deviceNetworkId}-1", null,[completedSetup: false, + label: "${device.displayName} Light", isComponent: false, componentLabel: "Light", "data":["parent version":version()]]) - log.info "Creating child light ${childDevice}" + + + + log.info "Created child light ${childDevice}" } else { log.info "Child already exists" @@ -403,3 +413,10 @@ def getChildVer() { LchildDevice.version() != currVersions("light")?sendEvent(name:"LchildCurr", value: 1):sendEvent(name:"LchildCurr", value: 2) } } + +void childOn(String dni) { + onOffCmd(0xFF, channelNumber(dni)) +} +void childOff(String dni) { + onOffCmd(0, channelNumber(dni)) +} \ No newline at end of file From 2675cce201debc3a9e0cdbd34ac5e555b1436e37 Mon Sep 17 00:00:00 2001 From: Rafael de Medeiros Borja Gomes Date: Mon, 29 Jul 2019 23:34:22 -0400 Subject: [PATCH 2/9] Functional version for new app. Still pending better response feedback for turn on and turn of child light, but version works well --- ...e-fan-controller-light-child-device.groovy | 109 ++++++++++-------- .../kof-zigbee-fan-controller.groovy | 41 ++----- 2 files changed, 71 insertions(+), 79 deletions(-) diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy index b5be6bd..101eb55 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy @@ -13,7 +13,7 @@ * 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. */ - def version() {return "ver 0.2.170515"} + def version() {return "ver 0.2.170516a"} /* a- added valueTile for rangeValue; forced to use 2x2 or bug in device handler makes font unreadably small so modified controlTile 4x2 to match up rangeValue tile size, shorten ver to increase font in tile @@ -34,87 +34,96 @@ 2017 Year */ metadata { - definition (name: "KOF Zigbee Fan Controller - Light Child Device", namespace: "dcoffing", author: "Stephan Hackett", mnmn: "SmartThings", vid: "generic-switch", runLocally: true, executeCommandsLocally: true) { - capability "Actuator" - -// capability "Actuator" + definition (name: "KOF Zigbee Fan Controller - Light Child Device", namespace: "dcoffing", author: "Stephan Hackett", mnmn: "SmartThings", + ocfDeviceType: "oic.d.light", vid: "generic-dimmer", minHubCoreVersion: '000.021.00001',runLocally: true, executeCommandsLocally: true) { + capability "Actuator" + capability "Configuration" + capability "Refresh" + capability "Sensor" capability "Switch" capability "Switch Level" -// capability "Light" -// capability "Sensor" + capability "Polling" + capability "Light" + + command "on" + command "off" + command "setLevel" } tiles(scale: 2) { - - multiAttributeTile(name: "switch", type: "lighting", width: 1, height: 1, canChangeIcon: true) { - tileAttribute("device.switch", key: "PRIMARY_CONTROL") { - attributeState("on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff") - attributeState("off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn") - attributeState("turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff") - attributeState("turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn") - } - + //multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + // tileAttribute ("switch", key: "PRIMARY_CONTROL") { + // attributeState "off", label:"off", action: "on", icon: getIcon()+"light_grey.png", backgroundColor: "#ffffff", nextState: "turningOn" + // attributeState "on", label: "on", action: "off", icon: getIcon()+"lightH.png", backgroundColor: "#00A0DC", nextState: "turningOff" + // attributeState "turningOn", label:"TURNING ON", action: "on", icon: getIcon()+"lightI.png", backgroundColor: "#2179b8", nextState: "turningOn" + // attributeState "turningOff", label:"TURNING OFF", action:"off", icon: getIcon()+"lightI.png", backgroundColor:"#2179b8", nextState: "turningOff" + // } + // tileAttribute ("device.level", key: "SLIDER_CONTROL") { + // attributeState "level", action: "setLevel" + // } + //} + multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', action:"off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" + attributeState "off", label:'${name}', action:"on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', action:"off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn" + } - tileAttribute ("device.level", key: "SLIDER_CONTROL") { - attributeState "level", action:"switch level.setLevel" + tileAttribute ("device.level", key: "SLIDER_CONTROL", width: 4, height: 2) { + attributeState "level", action:"setLevel" } - - // controlTile ("level", "level", "slider", width: 4, height: 2) { - // state "level", action: "setLevel" - // } - - // state "off", label:"OFF", action: "on", icon: getIcon()+"light_grey.png", backgroundColor: "#ffffff", nextState: "turningOn" - // state "on", label: "ON", action: "off", icon: getIcon()+"lightH.png", backgroundColor: "#00A0DC", nextState: "turningOff" - // state "turningOn", label:"TURNING ON", action: "on", icon: getIcon()+"lightI.png", backgroundColor: "#2179b8", nextState: "turningOn" - // state "turningOff", label:"TURNING OFF", action:"off", icon: getIcon()+"lightI.png", backgroundColor:"#2179b8", nextState: "turningOff" - } + } - - controlTile("levelSliderControl", "device.level", "slider", width: 6, height: 1) { + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh" + } + + // controlTile ("level", "level", "slider", width: 4, height: 2) { + // state "level", action: "setLevel" + // } + controlTile("levelSliderControl", "device.level", "slider", width: 6, height: 1) { state "level", action:"switch level.setLevel" } - - + main(["switch"]) - details(["switch", "levelSliderControl", "slider"]) + details(["switch", "refresh"]) } } - def on() { parent.lightOn() + log.debug("Fan light turned on") parent.childOn(device.deviceNetworkId) - sendEvent(name: "switch", value: "on") + sendEvent(name: "switch", value: "on") } def off() { parent.lightOff() + log.debug("Fan light turned off") sendEvent(name: "switch", value: "off") parent.childOff(device.deviceNetworkId) } def setLevel(val) { + log.debug("Set level called") parent.lightLevel(val) sendEvent(name: "level", value: val) } -def ping() { - log.debug "ping().." - refresh() -} - -def refresh() { - log.debug "refresh()" -} -def installed() { - initialize() +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + log.debug("Ping called") + log.debug(parent.refresh()) + return } -def updated() { - initialize() -} -def initialize() { - state.version = version() +def refresh() { + log.debug("Refresh called") + log.debug(parent.getLevel()) + return parent.getLevel() } \ No newline at end of file diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy index f25e61c..07adf7c 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy @@ -25,7 +25,7 @@ def version() {"ver 0.2.170515"} //update as needed def currVersions(child) { //Let's user know if running the child versions that corresponds to this parent version if(child=="fan") {return "ver 0.2.170515"} //manually enter the version of the FAN child that matches the parent version above -if(child=="light") {return "ver 0.2.170515"} //manually enter the version of the LIGHT child that matches the parent version above +if(child=="light") {return "ver 0.2.170516a"} //manually enter the version of the LIGHT child that matches the parent version above } /* @@ -55,14 +55,14 @@ if(child=="light") {return "ver 0.2.170515"} //manually enter the version of the 04/19 added version tile to help in troubleshooting with users */ metadata { - definition (name: "KOF Zigbee Fan Controller", namespace: "dcoffing", author: "Stephan Hackett, Ranga Pedamallu, Dale Coffing") { - // capability "Actuator" + definition (name: "KOF Zigbee Fan Controller", namespace: "dcoffing", author: "Stephan Hackett, Ranga Pedamallu, Dale Coffing", mnmn: "SmartThings", vid: "generic-switch", runLocally: true, executeCommandsLocally: true, ocfDeviceType: "oic.d.fan") { + capability "Actuator" capability "Configuration" capability "Refresh" capability "Switch" - // capability "Light" - // capability "Sensor" - // capability "Polling" + capability "Light" + capability "Sensor" + capability "Polling" //capability "Health Check" command "lightOn" @@ -79,11 +79,6 @@ metadata { attribute "FchildCurr", "string" //stores color of version check fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0202", outClusters: "0003, 0019", model: "HDC52EastwindFan" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0202", outClusters: "0003, 0019", model: "HDC52EastwindFan", manufacturer: "King Of Fans, Inc." - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 020" - - - } preferences { @@ -221,7 +216,7 @@ def updated() { } def initialize() { - log.info "Initializing" + log.info "Initializing" if(refreshChildren) { deleteChildren() device.updateSetting("refreshChildren", false) @@ -254,8 +249,8 @@ def createFanChild() { it.device.deviceNetworkId == "${device.deviceNetworkId}-0${i}" } if (!childDevice && i != 5) { - childDevice = addChildDevice("KOF Zigbee Fan Controller - Fan Speed Child Device", "${device.deviceNetworkId}-0${i}", null,[completedSetup: false, - label: "${device.displayName} ${getFanName()["0${i}"]}", isComponent: false, + childDevice = addChildDevice("KOF Zigbee Fan Controller - Fan Speed Child Device", "${device.deviceNetworkId}-0${i}", null,[completedSetup: true, + label: "${device.displayName} ${getFanName()["0${i}"]}", isComponent: true, componentName: "fanMode${i}", componentLabel: "${getFanName()["0${i}"]}", "data":["speedVal":"0${i}","parent version":version()]]) log.info "Creating child fan mode ${childDevice}" } @@ -273,15 +268,10 @@ def createLightChild() { it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" } if (!childDevice) { - log.debug "That's the hub id ${device.hub.id}" - - childDevice = addChildDevice("KOF Zigbee Fan Controller - Light Child Device", "${device.deviceNetworkId}-1", null,[completedSetup: false, - label: "${device.displayName} Light", isComponent: false, + childDevice = addChildDevice("KOF Zigbee Fan Controller - Light Child Device", "${device.deviceNetworkId}-Light", null,[completedSetup: true, + label: "${device.displayName} Light", isComponent: false, componentName: "fanLight", componentLabel: "Light", "data":["parent version":version()]]) - - - - log.info "Created child light ${childDevice}" + log.info "Creating child light ${childDevice}" } else { log.info "Child already exists" @@ -412,11 +402,4 @@ def getChildVer() { sendEvent(name:"LchildVer", value: LchildDevice.version()) LchildDevice.version() != currVersions("light")?sendEvent(name:"LchildCurr", value: 1):sendEvent(name:"LchildCurr", value: 2) } -} - -void childOn(String dni) { - onOffCmd(0xFF, channelNumber(dni)) -} -void childOff(String dni) { - onOffCmd(0, channelNumber(dni)) } \ No newline at end of file From f7c3364e101b7b652ed74a91676b3e1bc0bb9c02 Mon Sep 17 00:00:00 2001 From: Rafael de Medeiros Borja Gomes Date: Tue, 30 Jul 2019 12:04:10 -0400 Subject: [PATCH 3/9] Fan controllers available in new app --- ...e-fan-controller-fan-speed-child-device.groovy | 4 ++-- .../kof-zigbee-fan-controller.groovy | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller-fan-speed-child-device.src/kof-zigbee-fan-controller-fan-speed-child-device.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller-fan-speed-child-device.src/kof-zigbee-fan-controller-fan-speed-child-device.groovy index 1f3aa40..554e082 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller-fan-speed-child-device.src/kof-zigbee-fan-controller-fan-speed-child-device.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller-fan-speed-child-device.src/kof-zigbee-fan-controller-fan-speed-child-device.groovy @@ -17,7 +17,7 @@ KNOWN ISSUES - fan and light child device views are only available in iOS mobile app - Fan child device view can't change name when using gear icon like you can in Light child device */ - def version() {return "ver 0.2.170515"} + def version() {return "ver 0.2.18"} /* ; shorten ver to increase font size 05/15 pull request merge with Stephan and Ranga changes, Changed Comfort Breeze label from "enable" to "breeze" @@ -41,7 +41,7 @@ KNOWN ISSUES */ metadata { - definition (name: "KOF Zigbee Fan Controller - Fan Speed Child Device", namespace: "dcoffing", author: "Stephan Hackett") { + definition (name: "KOF Zigbee Fan Controller - Fan Speed Child Device", namespace: "dcoffing", author: "Stephan Hackett", mnmn: "SmartThings", vid: "generic-switch", runLocally: true, executeCommandsLocally: true, ocfDeviceType: "oic.d.fan") { capability "Actuator" capability "Switch" capability "Light" diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy index 07adf7c..7d680de 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy @@ -20,12 +20,12 @@ * 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. */ -def version() {"ver 0.2.170515"} //update as needed +def version() {"ver 0.2.21"} //update as needed def currVersions(child) { //Let's user know if running the child versions that corresponds to this parent version -if(child=="fan") {return "ver 0.2.170515"} //manually enter the version of the FAN child that matches the parent version above -if(child=="light") {return "ver 0.2.170516a"} //manually enter the version of the LIGHT child that matches the parent version above +if(child=="fan") {return "ver 0.2.21"} //manually enter the version of the FAN child that matches the parent version above +if(child=="light") {return "ver 0.2.21"} //manually enter the version of the LIGHT child that matches the parent version above } /* @@ -78,7 +78,12 @@ metadata { attribute "LchildCurr", "string" //stores color of version check attribute "FchildCurr", "string" //stores color of version check - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0202", outClusters: "0003, 0019", model: "HDC52EastwindFan" + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0202", outClusters: "0003,0019", model: "HDC52EastwindFan", deviceJoinName: "King Of Fans, Inc." + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0202", outClusters: "0019", manufacturer: "King Of Fans, Inc.", model: "HDC52EastwindFan", deviceJoinName: "King Of Fans, Inc." + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0202", outClusters: "0003,0019", deviceJoinName: "King Of Fans, Inc." + + + } preferences { @@ -250,7 +255,7 @@ def createFanChild() { } if (!childDevice && i != 5) { childDevice = addChildDevice("KOF Zigbee Fan Controller - Fan Speed Child Device", "${device.deviceNetworkId}-0${i}", null,[completedSetup: true, - label: "${device.displayName} ${getFanName()["0${i}"]}", isComponent: true, componentName: "fanMode${i}", + label: "${device.displayName} ${getFanName()["0${i}"]}", isComponent: false, componentName: "fanMode${i}", componentLabel: "${getFanName()["0${i}"]}", "data":["speedVal":"0${i}","parent version":version()]]) log.info "Creating child fan mode ${childDevice}" } From aa607736c31b8609c6830bd613b7c88ba6909291 Mon Sep 17 00:00:00 2001 From: Rafael de Medeiros Borja Gomes Date: Tue, 30 Jul 2019 12:04:13 -0400 Subject: [PATCH 4/9] Fan controllers available in new app From 2fd7bd2519b565fcb4db0387aa086cc20fe51918 Mon Sep 17 00:00:00 2001 From: Rafael de Medeiros Borja Gomes Date: Tue, 30 Jul 2019 21:52:39 -0400 Subject: [PATCH 5/9] Rolling back changes to original version and simply adding support for new app. Functional, but actions feedback is not reflecting the icons on the app. --- ...ee-fan-controller-light-child-device.groovy | 4 ++-- .../kof-zigbee-fan-controller.groovy | 18 +++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy index 101eb55..3c5aba1 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller-light-child-device.src/kof-zigbee-fan-controller-light-child-device.groovy @@ -13,7 +13,7 @@ * 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. */ - def version() {return "ver 0.2.170516a"} + def version() {return "ver 0.2.18a"} /* a- added valueTile for rangeValue; forced to use 2x2 or bug in device handler makes font unreadably small so modified controlTile 4x2 to match up rangeValue tile size, shorten ver to increase font in tile @@ -35,7 +35,7 @@ */ metadata { definition (name: "KOF Zigbee Fan Controller - Light Child Device", namespace: "dcoffing", author: "Stephan Hackett", mnmn: "SmartThings", - ocfDeviceType: "oic.d.light", vid: "generic-dimmer", minHubCoreVersion: '000.021.00001',runLocally: true, executeCommandsLocally: true) { + ocfDeviceType: "oic.d.light", vid: "generic-rgbw-color-bulb", minHubCoreVersion: '000.021.00001',runLocally: true, executeCommandsLocally: true) { capability "Actuator" capability "Configuration" capability "Refresh" diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy index 7d680de..5471e38 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller.src/kof-zigbee-fan-controller.groovy @@ -20,12 +20,12 @@ * 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. */ -def version() {"ver 0.2.21"} //update as needed +def version() {"ver 0.2.18"} //update as needed def currVersions(child) { //Let's user know if running the child versions that corresponds to this parent version -if(child=="fan") {return "ver 0.2.21"} //manually enter the version of the FAN child that matches the parent version above -if(child=="light") {return "ver 0.2.21"} //manually enter the version of the LIGHT child that matches the parent version above +if(child=="fan") {return "ver 0.2.18"} //manually enter the version of the FAN child that matches the parent version above +if(child=="light") {return "ver 0.2.18a"} //manually enter the version of the LIGHT child that matches the parent version above } /* @@ -55,7 +55,8 @@ if(child=="light") {return "ver 0.2.21"} //manually enter the version of the LIG 04/19 added version tile to help in troubleshooting with users */ metadata { - definition (name: "KOF Zigbee Fan Controller", namespace: "dcoffing", author: "Stephan Hackett, Ranga Pedamallu, Dale Coffing", mnmn: "SmartThings", vid: "generic-switch", runLocally: true, executeCommandsLocally: true, ocfDeviceType: "oic.d.fan") { + definition (name: "KOF Zigbee Fan Controller", namespace: "dcoffing", author: "Stephan Hackett, Ranga Pedamallu, Dale Coffing", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb", ocfDeviceType: "oic.d.fan") { + /// runLocally: true, executeCommandsLocally: true, capability "Actuator" capability "Configuration" capability "Refresh" @@ -78,12 +79,7 @@ metadata { attribute "LchildCurr", "string" //stores color of version check attribute "FchildCurr", "string" //stores color of version check - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0202", outClusters: "0003,0019", model: "HDC52EastwindFan", deviceJoinName: "King Of Fans, Inc." - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0202", outClusters: "0019", manufacturer: "King Of Fans, Inc.", model: "HDC52EastwindFan", deviceJoinName: "King Of Fans, Inc." - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0202", outClusters: "0003,0019", deviceJoinName: "King Of Fans, Inc." - - - + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0202", outClusters: "0003,0019" //, model: "HDC52EastwindFan" } preferences { @@ -151,7 +147,7 @@ metadata { } def parse(String description) { - //log.debug "Parse description $description" + log.debug "Parse description $description" def event = zigbee.getEvent(description) if (event) { log.info "Light event detected on controller: ${event}" From 03c89d925f728478392164e48fedec07d5ccb184 Mon Sep 17 00:00:00 2001 From: Rafael de Medeiros Borja Gomes Date: Fri, 3 Apr 2020 22:29:55 -0400 Subject: [PATCH 6/9] Refactoring to use a main device for fan control and a child device for light control. First functional version --- ...n-controller-fan-speed-child-device.groovy | 1 + ...-fans-zigbee-fan-light-child-device.groovy | 121 +++ .../king-of-fans-zwave-fan-controller.groovy | 770 ++++++++++++++++++ 3 files changed, 892 insertions(+) create mode 100644 devicetypes/smartthings/king-of-fans-zigbee-fan-light-child-device.src/king-of-fans-zigbee-fan-light-child-device.groovy create mode 100644 devicetypes/smartthings/king-of-fans-zwave-fan-controller.src/king-of-fans-zwave-fan-controller.groovy diff --git a/devicetypes/dcoffing/kof-zigbee-fan-controller-fan-speed-child-device.src/kof-zigbee-fan-controller-fan-speed-child-device.groovy b/devicetypes/dcoffing/kof-zigbee-fan-controller-fan-speed-child-device.src/kof-zigbee-fan-controller-fan-speed-child-device.groovy index 554e082..bce3e03 100644 --- a/devicetypes/dcoffing/kof-zigbee-fan-controller-fan-speed-child-device.src/kof-zigbee-fan-controller-fan-speed-child-device.groovy +++ b/devicetypes/dcoffing/kof-zigbee-fan-controller-fan-speed-child-device.src/kof-zigbee-fan-controller-fan-speed-child-device.groovy @@ -83,6 +83,7 @@ def getIcon() { } def off() { + log.info "CHILD ${getDataValue('speedVal')} TURNED ON" parent.off() } diff --git a/devicetypes/smartthings/king-of-fans-zigbee-fan-light-child-device.src/king-of-fans-zigbee-fan-light-child-device.groovy b/devicetypes/smartthings/king-of-fans-zigbee-fan-light-child-device.src/king-of-fans-zigbee-fan-light-child-device.groovy new file mode 100644 index 0000000..73d64d9 --- /dev/null +++ b/devicetypes/smartthings/king-of-fans-zigbee-fan-light-child-device.src/king-of-fans-zigbee-fan-light-child-device.groovy @@ -0,0 +1,121 @@ +/** + * King Of Fans Zigbee Fan Controller - Light Child Device + * + * Copyright 2017 Stephan Hackett + * in collaboration with Ranga Pedamallu, Dale Coffing + * + * 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. + */ + def version() {return "ver 0.2.18a"} +/* + a- added valueTile for rangeValue; forced to use 2x2 or bug in device handler makes font unreadably small + so modified controlTile 4x2 to match up rangeValue tile size, shorten ver to increase font in tile + 05/15 pull request merge with Stephan and Ranga changes, to allow flat look in parent, changed from multiAttribute to Standard/Control Tile functionality + 05/10 decoration: "flat" added to tile for consistancy across all childs + 05/05 edit Zigbee to proper ZigBee trademark + 05/04 clean up display in iOS child version, smaller text and center version + 05/03 tweak to icons for ON to match the lighter grey LED look + 05/02 replaced blue rays on icon to be grey when TurningOnOff + b- changed light TurningON/OFF icon to light_blue + a- changed light ON icon from light_blue to lightH for Stephan + 05/01 added version tile for iOS child device view, light icon ON with blue rays + 04/30a move Stephack latest changes over in a copy/paste; change namespace + 04/29 larger matching icon; used URL shortcut https://cdn.rawgit.com/ and located to /resources/images/ + 04/26 moved icons to KOF repo and renamed for final release + 04/20 modified version tile + 04/19 added version tile to help in troubleshooting with users + 2017 Year +*/ +metadata { + definition (name: "King of Fans Zigbee Fan - Light Child Device", namespace: "smartthings", ocfDeviceType:"oic.d.light", author: "Stephan Hackett", vid: "generic-dimmer") { + capability "Switch" + capability "Actuator" + capability "Sensor" + capability "Refresh" + } + + // Zemismart HGZB-42 + fingerprint profileId: "C05E", deviceId: "0000", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "3A Smart Home DE", model: "LXN-2S27LX1.0", deviceJoinName: "ZigBee Smart Switch" + fingerprint profileId: "C05E", deviceId: "0000", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "FeiBit", model: "FNB56-ZSW02LX2.0", deviceJoinName: "ZigBee Smart Switch" + + // Zemismart HGZB-43 + fingerprint profileId: "C05E", deviceId: "0000", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "3A Smart Home DE", model: "LXN-3S27LX1.0", deviceJoinName: "ZigBee Smart Switch" + fingerprint profileId: "C05E", deviceId: "0000", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "FeiBit", model: "FNB56-ZSW03LX2.0", deviceJoinName: "ZigBee Smart Switch" + + tiles(scale: 2) { + standardTile ("switch", "device.switch", width: 2, height: 2, canChangeIcon: true, decoration: "flat") { + state ("off", label: '${name}', action: "on", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "turningOn") + state ("on", label: '${name}', action: "off", icon: "st.switches.light.on", backgroundColor: "#00a0dc", nextState: "turningOff") + state ("turningOff", label: '${name}', action: "on", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "turningOn") + state ("turningOn", label: '${name}', action: "off", icon: "st.switches.light.on", backgroundColor: "#00a0dc", nextState: "turningOff") + } + + controlTile("level", "device.level", "slider", range:"(1..9)", height: 2, width: 2, canChangeIcon: true, decoration: "flat", inactiveLabel: false) { + state "level", action: "setLevel" + } + + main("switch") + details(["switch", "level"]) + } +} + +void on() { + log.info "on()" + parent.on(device) + //sendEvent(name: "device.switch", value: "on") + //sendEvent(name: "switch", value: "on") +} + +void off() { + log.info "off()" + parent.off(device) + //sendEvent(name: "switch", value: "off") + // sendEvent(name: "device.switch", value: "off") +} + +void refresh() { + log.debug "refresh()" + parent.refresh(device) + parent.childRefresh(device.deviceNetworkId) +} + + +def createAndSendEvent(map) { + log.debug "child[ ${device.endpointId} ].sendEvent($map)" + sendEvent(map) + return map +} + +def parse(description) { + log.debug "Parse Child: $description" +} + +def setLevel(value, rate = 10) { parent.setLevel(device, value, rate) } + +def poll() { + log.debug "poll()" + parent.poll(device) +} + +def ping() { + log.debug "ping()" + parent.ping(device) +} + +def installed () { + log.debug "installed() - parent $parent" + + sendEvent(name: "checkInterval", value: 10, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +} + +def uninstalled () { + log.debug "uninstalled()" + //parent.delete() +} \ No newline at end of file diff --git a/devicetypes/smartthings/king-of-fans-zwave-fan-controller.src/king-of-fans-zwave-fan-controller.groovy b/devicetypes/smartthings/king-of-fans-zwave-fan-controller.src/king-of-fans-zwave-fan-controller.groovy new file mode 100644 index 0000000..bac1e10 --- /dev/null +++ b/devicetypes/smartthings/king-of-fans-zwave-fan-controller.src/king-of-fans-zwave-fan-controller.groovy @@ -0,0 +1,770 @@ +/** + Contributions from https://github.com/DavinKD/SmartThings/blob/master/devicetypes/davindameron/tasmota-fan.src/tasmota-fan.groovy + + * + King Of Fans Zigbee Fan Controller + * + * To be used with Ceiling Fan Remote Controller Model MR101Z receiver by Chungear Industrial Co. Ltd + * at Home Depot Gardinier 52" Ceiling Fan, Universal Ceiling Fan/Light Premier Remote Model #99432 + * + * Copyright 2017 Ranga Pedamallu, Stephan Hackett, Dale Coffing + * + * Contributing Authors: + Ranga Pedamallu; initial release and zigbee parsing mastermind! + + Stephan Hackett; new composite (child) device type genius! + Dale Coffing; icons, multiAttribute fan, code maintenance flunky + * + * 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. + */ +// def version() {"ver 0.2.18"} //update as needed + + +//def currVersions(child) { //Let's user know if running the child versions that corresponds to this parent version +// if(child=="fan") {return "ver 0.2.18"} //manually enter the version of the FAN child that matches the parent version above +// if(child=="light") {return "ver 0.2.18a"} //manually enter the version of the LIGHT child that matches the parent version above +// } + +/* + + 05/15 added GRN=OK RED=Update to version tile, changed parent tile version to fill empty space, shorten ver to increase font in tile + a- fixed line 225 -Light + 05/05 modified Refresh text to Delete&Recreate + b- test new label Speed 1 (LOW) technique + a- evaluating new Speed 1,2,3,4 for ease of voice and look, it matches the fan speed bar icons instead of Lo, Med, Hi + 05/04 Modified labels lowercase,Comfort Breeze™ , getFanName() to be longer names vs abbr + 05/03 renamed LAMP to LIGHT in all instances to conform to ST standards + 05/01 fixed bug when recreated child names didn't use the new name but the original name; def createFanChild() + c- added TurningBreezeOff attributeState to match the Breeze icon + b- added CeilingFanParent in version, added new grey OFF icons + a- move Stephack latest changes;(one step child delete/create, etc) over in a copy/paste; change namespace + 04/30 Moved refresh()Configure() from child creation method to initialize, added individual icons for fan child + 04/29 new icons with fanspeed bar indication + e- added changes from Stephan to fix createChild error + d- go back to orginal code on line 182 + c- createFanChild code added line 182 ChildDevice this part is the BUG that wont' create all fanChild devices + b- details for childVer, added getChildVer() & def getChildVer() + a- attribute LchildVer, FchildVer + 04/28 reverted back to 0426 and added new revision labeling to parent + 04/26 label changes to read naturally, CAP light to match child speeds + 04/25 label changes; Breeze color #008B64 + 0.2.1b parent on-off states sync with any child state for ActionTiles + 04/19 added version tile to help in troubleshooting with users +*/ +metadata { + definition(name: "King of Fans Z-Wave Fan Controller", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.fan", genericHandler: "Zigbee") { + // definition (cstHandler: true, name: "AKOF Zigbee Fan Controller 1", namespace: "smartthings", author: "Stephan Hackett, Ranga Pedamallu, Dale Coffing, Rafael Borja", + //ocfDeviceType: "oic.d.fan", genericHandler: "Zigbee") { + capability "Switch Level" + capability "Switch" + capability "Fan Speed" + capability "Health Check" + capability "Actuator" + capability "Refresh" + capability "Sensor" + + command "low" + command "medium" + command "high" + command "raiseFanSpeed" + command "lowerFanSpeed" + + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0003,0019" /*,0202" /, outClusters: "0003,0019" , model: "HDC52EastwindFan" */ + } + + tiles(scale: 2) { + multiAttributeTile(name: "fanSpeed", type: "generic", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.fanSpeed", key: "PRIMARY_CONTROL") { + attributeState "0", label: "off", action: "switch.on", icon: "st.thermostat.fan-off", backgroundColor: "#ffffff" + attributeState "1", label: "low", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "2", label: "medium", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "3", label: "high", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + } + tileAttribute("device.fanSpeed", key: "VALUE_CONTROL") { + attributeState "VALUE_UP", action: "raiseFanSpeed" + attributeState "VALUE_DOWN", action: "lowerFanSpeed" + } + } + + standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh" + } + main "fanSpeed" + details(["fanSpeed", "refresh"]) + + + + + + + /* runLocally: true, executeCommandsLocally: true, ocfDeviceType: "oic.d.fan", vid: "generic-switch" /*, vid: "generic-rgbw-color-bulb", genericHandler: "Zigbee" ) { + // ocfDeviceType: "oic.d.fan" vid: "generic-rgbw-color-bulb" + /// runLocally: true, executeCommandsLocally: true, + /* capability "Actuator" + capability "Configuration" + capability "Refresh" + capability "Switch" + capability "Light" + capability "Sensor" + capability "Polling" + capability "Switch Level" + //capability "Health Check" + capability "Button" + capability "Fan Speed" + + capability "Switch Level" + capability "Switch" + capability "Fan Speed" + capability "Health Check" + capability "Actuator" + capability "Refresh" + capability "Sensor"*/ + + // capability "Switch Level" + // capability "Switch" + + // capability "Health Check" + // capability "Actuator" + // capability "Refresh" + // capability "Sensor" + // capability "Light" + //capability "Fan Speed" + + /* + + command "low" + command "medium" + command "high" + command "raiseFanSpeed" + command "lowerFanSpeed" + + capability "Stateless Fanspeed Button" + capability "Stateless Fanspeed Mode Button" + capability "Stateless Power Button" + + command "lightOn" + command "lightOff" + command "lightLevel" + command "setFanSpeed" + + command "low" + command "medium" + command "high" + command "raiseFanSpeed" + command "lowerFanSpeed" + + + attribute "fanMode", "string" //stores fanspeed + attribute "lightBrightness", "number" //stores brightness level + attribute "lastFanMode", "string" //used to restore previous fanmode + attribute "LchildVer", "string" //stores light child version + attribute "FchildVer", "string" //stores fan child version + attribute "LchildCurr", "string" //stores color of version check + attribute "FchildCurr", "string" //stores color of version check + */ + /* + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0003,0019" /*,0202" /, outClusters: "0003,0019" , model: "HDC52EastwindFan" */ + // fingerprint profileId: "0104", inClusters: "*", outClusters: "0003,0019", model: "HDC52EastwindFan" + // } + + + + /* + + tiles(scale: 2) { + + multiAttributeTile(name: "fanSpeed", type: "generic", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.fanSpeed", key: "PRIMARY_CONTROL") { + attributeState "0", label: "off", action: "switch.on", icon: "st.thermostat.fan-off", backgroundColor: "#ffffff" + attributeState "1", label: "low", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "2", label: "medium", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "3", label: "high", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + } + tileAttribute("device.fanSpeed", key: "VALUE_CONTROL") { + attributeState "VALUE_UP", action: "raiseFanSpeed" + attributeState "VALUE_DOWN", action: "lowerFanSpeed" + } + + + } /* + + controlTile("levelSliderControl", "device.level", "slider", height: 1, + width: 2, inactiveLabel: false, range:"(0..100)") { + state "level", action:"switch level.setLevel" + } + + standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh" + } + main "fanSpeed" + details(["fanSpeed", "refresh"]) */ + } + + + + /* + tiles(scale: 2) { + multiAttributeTile(name: "switch", type: "generic", width: 6, height: 4) { + tileAttribute ("fanMode", key: "PRIMARY_CONTROL") { + attributeState "04", label:"aaaaHIGH", action:"off", icon:getIcon()+"fan4h.png", backgroundColor:"#79b821", nextState: "turningOff" + attributeState "03", label:"MED-HI", action:"off", icon:getIcon()+"fan3h.png", backgroundColor:"#79b821", nextState: "turningOff" + attributeState "02", label:"MED", action:"off", icon:getIcon()+"fan2h.png", backgroundColor:"#79b821", nextState: "turningOff" + attributeState "01", label:"LOW", action:"off", icon:getIcon()+"fan1h.png", backgroundColor:"#79b821", nextState: "turningOff" + attributeState "06", label:"BREEZEAAAA", action:"off", icon:getIcon()+"breeze4h_blk.png", backgroundColor:"#008B64", nextState: "turningBreezeOff" + attributeState "00", label:"FAN OFF", action:"on", icon:getIcon()+"fan00h_grey.png", backgroundColor:"#ffffff", nextState: "turningOn" + attributeState "turningOn", action:"on", label:"TURNING ON", icon:getIcon()+"fan0h.png", backgroundColor:"#2179b8", nextState: "turningOn" + attributeState "turningOff", action:"off", label:"TURNING OFF", icon:getIcon()+"fan0h_grey.png", backgroundColor:"#2179b8", nextState: "turningOff" + attributeState "turningBreezeOff", action:"off", label:"TURNING OFF", icon:getIcon()+"breeze4h_teal.png", backgroundColor:"#2179b8", nextState: "turningOff" + } + tileAttribute ("lightBrightness", key: "SLIDER_CONTROL") { + attributeState "lightBrightness", action:"lightLevel" + } + } + + standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "configure", label:'', action:"configure", icon:"st.secondary.configure" + } + + + standardTile("refresh", "refresh", decoration: "flat", width: 2, height: 3) { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + valueTile("aaaaversion", "version", width:4, height:1) { + state "version", label:"Ceiling Fan Parent\n"+ version() + } + valueTile("FchildVer", "FchildVer", width:3, height:1) { + state "FchildVer", label: "Fan Child "+'${currentValue}'+"\nGRN=OK RED=Update" + } + valueTile("LchildVer", "LchildVer", width:3, height:1) { + state "LchildVer", label:"Light Child "+'${currentValue}'+"\nGRN=OK RED=Update" + } + valueTile("FchildCurr", "FchildCurr", width:1, height:1) { + state "FchildCurr", label: "", backgroundColors:[ + [value: 1, color: "#FF0000"], + [value: 2, color: "#3EAE40"] + ] + } + valueTile("LchildCurr", "LchildCurr", width:1, height:1) { + state "LchildCurr", label:"", backgroundColors:[ + [value: 1, color: "#FF0000"], + [value: 2, color: "#3EAE40"] + ] + } + + //childDeviceTiles("fanSpeeds", height: 1, width: 6) + childDeviceTile("fanMode1", "fanMode1", height: 2, width: 2) + childDeviceTile("fanMode2", "fanMode2", height: 2, width: 2) + childDeviceTile("fanMode3", "fanMode3", height: 2, width: 2) + childDeviceTile("fanMode4", "fanMode4", height: 2, width: 2) + childDeviceTile("fanMode6", "fanMode6", height: 2, width: 2) + childDeviceTile("fanLight", "fanLight", height: 2, width: 2) + + main(["switch", "configure", "fanLight", "fanMode1", "fanMode2", "fanMode6", "fanMode3", "fanMode4"]) + details(["switch", "configu", "fanLight", "fanMode1", "fanMode2", "fanMode6", "fanMode3", "fanMode4", "refresh", "FchildVer", "FchildCurr", "LchildVer", "LchildCurr", "version"]) + } */ +} + +def parse(String description) { + log.info "Parse description $description" + def event = zigbee.getEvent(description) + if (event) { + "Sample 0104 0006 01 01 0000 00 D42D 00 00 0000 01 01 010086" + + + log.info "Parse description ${description}" + log.info "Light event detected on controller (event): ${event}" + + + def childDevice = getChildDevices()?.find { //find light child device + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + childDevice.sendEvent(event) //send light events to light child device and update lightBrightness attribute + if(event.value != "on" && event.value != "off") { + log.debug "sendEvent lightBrightness" + sendEvent(name: "lightBrightness", value: event.value) + sendEvent(name: "levelSliderControl", value: event.value) + sendEvent(name: "level", value: event.value) + sendEvent(name: "switch level", value: event.value) + } else { + log.debug "not sending lightBrightness" + } + } + else { + "Sample: 0104 0006 01 01 0000 00 D42D 00 00 0000 07 01 86000100" + "Sample: 0104 0006 01 01 0000 00 D42D 00 00 0000 07 01 00" + "Sample: D42D0102020800003000, dni: D42D, endpoint: 01, cluster: 0202, size: 8, attrId: 0000, result: success, encoding: 30, value: 00" + log.info "Fan event detected on controller" + def map = [:] + if (description?.startsWith("read attr -")) { + def descMap = zigbee.parseDescriptionAsMap(description) + log.debug "descMap in parse $descMap" + if (descMap.cluster == "0202" && descMap.attrId == "0000") { // Fan Control Cluster Attribute Read Response + map.name = "fanMode" + map.value = descMap.value + fanSync(descMap.value) + } + } // End of Read Attribute Response + def result = null + if (map) { + result = createEvent(map) + } else { + log.debug("parse: event map is null") + } + log.debug "Parse returned $map" + + return result + } +} + +def getIcon() { + return "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/" +} + +def getFanName() { + [ + "00":"Off", + "01":"Low", + "02":"Med", + "03":"Med-Hi", + "04":"High", + "05":"Off", + "06":"Comfort Breeze™", + "07":"Light" + ] +} + +def getFanNameAbbr() { + [ + "00":"Off", + "01":"Low", + "02":"Med", + "03":"Med-Hi", + "04":"High", + "05":"Off", + "06":"Breeze™", + "07":"Light" + ] +} + +/* +def installed() { + + initialize() +} +*/ + +def updated() { + if(state.oldLabel != device.label) {updateChildLabel()} + initialize() +} + +def initialize() { + log.info "Initializing" + if(refreshChildren) { + deleteChildren() + device.updateSetting("refreshChildren", false) + } + else { + createFanChild() + createLightChild() + response(refresh() + configure()) + } +} + +def updateChildLabel() { + log.info "UPDATE LABEL" + for(i in 1..6) { + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-0${i}" + } + if (childDevice && i != 5) {childDevice.label = "${device.displayName} ${getFanName()["0${i}"]}"} // rename with new label + } + + def childDeviceL = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if (childDeviceL) {childDeviceL.label = "${device.displayName}-Light"} // rename with new label +} +def createFanChild() { + state.oldLabel = device.label //save the label for reference if it ever changes + for(i in 1..6) { + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-0${i}" + } + if (!childDevice && i != 5) { + childDevice = addChildDevice("KOF Zigbee Fan Controller - Fan Speed Child Device", "${device.deviceNetworkId}-0${i}", null,[completedSetup: true, + label: "${device.displayName} ${getFanName()["0${i}"]}", isComponent: false, componentName: "fanMode${i}", + componentLabel: "${getFanName()["0${i}"]}", "data":["speedVal":"0${i}","parent version":version()]]) + log.info "Creating child fan mode ${childDevice}" + } + else { + log.info "Child already exists" + } + } +} + + + + +def createLightChild() { + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if (!childDevice) { + childDevice = addChildDevice("KOF Zigbee Fan Controller - Light Child Device", "${device.deviceNetworkId}-Light", null,[completedSetup: true, + label: "${device.displayName} Light", isComponent: false, componentName: "fanLight", + componentLabel: "Light", "data":["parent version":version()]]) + log.info "Creating child light ${childDevice}" + } + else { + log.info "Child already exists" + } +} + +def deleteChildren() { + def children = getChildDevices() + children.each {child-> + deleteChildDevice(child.deviceNetworkId) + } + log.info "Deleting children" +} + + +// Filename: printAllMethodsExample.groovy +void printAllMethods( obj ){ + if( !obj ){ + println( "Object is null\r\n" ); + return; + } + if( !obj.metaClass && obj.getClass() ){ + printAllMethods( obj.getClass() ); + return; + } + def str = "class ${obj.getClass().name} functions:\r\n"; + obj.metaClass.methods.name.unique().each{ + str += it+"(); "; + } + log.debug "${str}\r\n"; +} + + +def configure() { + log.info "Configuring Reporting and Bindings." + log.info zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) + log.info zigbee.configureReporting(0x0006, 0x00011, 0x10, 0, 600, null) + + log.debug device.dump() + log.debug this.dump() + + "[zdo bind 0xD42D 0x01 0x01 0x0006 {0022A3000016B5F4} {}, delay 2000, st cr 0xD42D 0x01 0x0006 0x0000 0x10 0x0000 0x0258 {}, delay 2000]" + /*def configure() { + configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) +} + sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) +*/ + + + def cmd = + [ + //Set long poll interval + "raw 0x0020 {11 00 02 02 00 00 00}", "delay 100", + "send 0x${device.deviceNetworkId} 1 1", "delay 100", + //Bindings for Fan Control + // "zdo bind 0x${device.deviceNetworkId} 1 0 0x006 {${device.zigbeeId}} {}", "delay 100", + + "zdo bind 0x${device.deviceNetworkId} 1 1 0x006 {${device.zigbeeId}} {}", "delay 100", + "zdo bind 0x${device.deviceNetworkId} 1 1 0x008 {${device.zigbeeId}} {}", "delay 100", + "zdo bind 0x${device.deviceNetworkId} 1 1 0x202 {${device.zigbeeId}} {}", "delay 100", + //Fan Control - Configure Report + "zcl global send-me-a-report 0x006 0 0x10 1 300 {}", "delay 100", + "send 0x${device.deviceNetworkId} 0 1", "delay 100", + // Light? + "zcl global send-me-a-report 0x006 1 0x10 1 300 {}", "delay 100", + "send 0x${device.deviceNetworkId} 1 1", "delay 100", + + "zcl global send-me-a-report 0x008 0 0x20 1 300 {}", "delay 100", + "send 0x${device.deviceNetworkId} 1 1", "delay 100", + "zcl global send-me-a-report 0x202 0 0x30 1 300 {}", "delay 100", + "send 0x${device.deviceNetworkId} 1 1", "delay 100", + //Light Control - Configure Report + //Update values + "st rattr 0x${device.deviceNetworkId} 1 0x006 0", "delay 100", + "st rattr 0x${device.deviceNetworkId} 1 0x006 1", "delay 100", // Light? + "st rattr 0x${device.deviceNetworkId} 1 0x008 0", "delay 100", + "st rattr 0x${device.deviceNetworkId} 1 0x202 0", "delay 100", + + //Set long poll interval + "raw 0x0020 {11 00 02 1C 00 00 00}", "delay 100", + "send 0x${device.deviceNetworkId} 1 1", "delay 100", + zigbee.configureReporting(0x0006, 0x00011, 0x10, 0, 600, null), + ] + return cmd + refresh() +} + + +def off (physicalgraph.device.cache.DeviceDTO child) { lightOn(child) } + +def on (physicalgraph.device.cache.DeviceDTO child) { lightOff(String id) } + + +def on() { + log.info "Resuming Previous Fan Speed" + def lastFan = device.currentValue("lastFanMode") //resumes previous fanspeed + return setFanSpeed("$lastFan") + +} + +def off() { + def fanNow = device.currentValue("fanMode") //save fanspeed before turning off so it can be resumed when turned back on + if(fanNow != "00") sendEvent("name":"lastFanMode", "value":fanNow) //do not save lastfanmode if fan is already off + def cmds=[ + "st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {00}" + ] + log.info "Turning fan Off" + return cmds +} + +def lightOn(String dni) { + log.info "Turning Light On" + zigbee.on() + + log.debug "Loading childlights" + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if (childDevice) { + log.debug "Sending event to child" + log.debug childDevice + childDevice.sendEvent(name: "device.switch", value: "on") + childDevice.sendEvent(name: "switch", value: "on") + childDevice.createEvent(childDevice.createAndSendEvent(name: "switch", value: "on")) + } +} + +def lightOff(String id) { + log.info "Turning Light Off" + zigbee.off() +} + +/* +void childOn(String dni) { + onOffCmd(0xFF, channelNumber(dni)) +} +void childOff(String dni) { + onOffCmd(0, channelNumber(dni)) +}*/ + +def lightLevel(val) { + log.info "Adjusting Light Brightness - called lightLevel on parent" + zigbee.setLevel(val) + (val?.toInteger() > 1 ? zigbee.on() : []) + sendEvent(name:"level",value: val) + + log.debug "Loading childlights" + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if (childDevice) { + log.debug "Sending event to child" + log.debug childDevice + //childDevice.sendEvent(name: "device.value", value: val) + // childDevice.sendEvent(name: "device.switch", value: "on", isStatusChange: true) + childDevice.sendEvent(name: "switch", value: isDeviceOn? "on": "off", isStatusChange: true) + childDevice.sendEvent(name: "value", value: val, isStatusChange: true) + childDevice.createEvent(childDevice.createAndSendEvent(name: "level", value: value)) + + } +} + +/** + * Called from APP when sliding light dimmer + */ +def setLevel(val, rate = null) { + log.info "Adjusting Light Brightness via setlevel on parent: {$val}" + + // sendEvent(name:"level",value: val) + + def isDeviceOn = val?.toInteger() > 1 + def cmds = zigbee.setLevel(val.toInteger(), 1) + refresh() // + refresh() (isDeviceOn ? zigbee.on() : []) + + log.debug "cmds {$cmds}" + + return cmds + + /* + log.debug "Loading childlights" + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if (childDevice) { + log.debug "Sending event to child" + log.debug childDevice + //childDevice.sendEvent(name: "device.value", value: val) + // childDevice.sendEvent(name: "device.switch", value: "on", isStatusChange: true) + childDevice.sendEvent(name: "switch", value: isDeviceOn? "on": "off", isStatusChange: true) + childDevice.sendEvent(name: "value", value: val, isStatusChange: true) + + } + + + return zigbee.command(0x0006, 0x01) */ +} + +def poll() { + log.debug("####POLL HAS BEEN CALLED") +} + +def setFanSpeed(speed) { + def cmds=[ + "st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {${speed}}" + ] + log.info "Adjusting Fan Speed to "+ getFanName()[speed] + return cmds +} + +def fanSync(whichFan) { + def children = getChildDevices() + children.each {child-> + def childSpeedVal = child.getDataValue('speedVal') + if(childSpeedVal == whichFan) { //send ON event to corresponding child fan + child.sendEvent(name:"switch",value:"on") + child.sendEvent(name:"fanSpeed", value:"on${childSpeedVal}") //custom icon code + sendEvent(name:"switch",value:"on") //send ON event to Fan Parent + } + else { + if(childSpeedVal!=null){ + //log.info childSpeedVal + child.sendEvent(name:"switch",value:"off") //send OFF event to all other child fans + child.sendEvent(name:"fanSpeed", value:"off${childSpeedVal}") //custom icon code + } + } + } + if(whichFan == "00") sendEvent(name:"switch",value:"off") //send OFF event to Fan Parent + +} + +def ping() { + log.debug("#####PING HAS BEN CALLED!!!!!") + return zigbee.onOffRefresh() +} + +def refresh() { + log.info "Refresh called" + + getChildVer() + + return zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(0x0202, 0x0000) + zigbee.readAttribute(0x0006, 0x0000) + + zigbee.readAttribute(0x0202, 0x0000) + zigbee.readAttribute(0x0202, 0x0001) + zigbee.readAttribute(0x0006, 0x0001) + zigbee.readAttribute(0x0006, 0x0000) + zigbee.readAttribute(0x0008, 0x0004) +} + + +def getChildVer() { + def FchildDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-01" + } + if(FchildDevice){ //find a fan device, 1. get version info and store in FchildVer, 2. check child version is current and set color accordingly + sendEvent(name:"FchildVer", value: FchildDevice.version()) + FchildDevice.version() != currVersions("fan")?sendEvent(name:"FchildCurr", value: 1):sendEvent(name:"FchildCurr", value: 2) + } + + def LchildDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if(LchildDevice) { //find the light device, get version info and store in LchildVer + sendEvent(name:"LchildVer", value: LchildDevice.version()) + LchildDevice.version() != currVersions("light")?sendEvent(name:"LchildCurr", value: 1):sendEvent(name:"LchildCurr", value: 2) + } +} + + + +def installed() { + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + response(refresh()) +} + + + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + fanEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { + fanEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) { + fanEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) { + fanEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { + log.debug "received hail from device" +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + // Handles all Z-Wave commands we aren't interested in + log.debug "Unhandled: ${cmd.toString()}" + [:] +} + +def fanEvents(physicalgraph.zwave.Command cmd) { + def rawLevel = cmd.value as int + def result = [] + + if (0 <= rawLevel && rawLevel <= 100) { + def value = (rawLevel ? "on" : "off") + result << createEvent(name: "switch", value: value, isStateChange: true) + result << createEvent(name: "level", value: rawLevel == 99 ? 100 : rawLevel, isStateChange: true) + + def fanLevel = 0 + + // The GE, Honeywell, and Leviton treat 33 as medium, so account for that + if (1 <= rawLevel && rawLevel <= 32) { + fanLevel = 1 + } else if (33 <= rawLevel && rawLevel <= 66) { + fanLevel = 2 + } else if (67 <= rawLevel && rawLevel <= 100) { + fanLevel = 3 + } + result << createEvent(name: "fanSpeed", value: fanLevel, isStateChange: true) + } + + return result +} + +def getDelay() { + // the leviton is comparatively well-behaved, but the GE and Honeywell devices are not + zwaveInfo.mfr == "001D" ? 2000 : 5000 +} + + +def raiseFanSpeed() { + setFanSpeed(Math.min((device.currentValue("fanSpeed") as Integer) + 1, 3)) +} + +def lowerFanSpeed() { + setFanSpeed(Math.max((device.currentValue("fanSpeed") as Integer) - 1, 0)) +} + +def low() { + setLevel(32) +} + +def medium() { + setLevel(66) +} + +def high() { + setLevel(99) +} + From 85871a0bf3b165d546d89c3c0b5473484082ced5 Mon Sep 17 00:00:00 2001 From: Rafael de Medeiros Borja Gomes Date: Fri, 3 Apr 2020 22:29:59 -0400 Subject: [PATCH 7/9] Refactoring to use a main device for fan control and a child device for light control. First functional version From 7605be66aa4692578bb73c719b5c4bd6192080b5 Mon Sep 17 00:00:00 2001 From: Rafael Borja <5069188+rafaelborja@users.noreply.github.com> Date: Mon, 6 Apr 2020 20:26:33 -0400 Subject: [PATCH 8/9] First fully functional version Fully functional version with child device acting and responding to events. Dimmer also function. Needs some code cleaning. --- .../king-of-fans-zwave-fan-controller.groovy | 363 +++++++++++------- 1 file changed, 216 insertions(+), 147 deletions(-) diff --git a/devicetypes/smartthings/king-of-fans-zwave-fan-controller.src/king-of-fans-zwave-fan-controller.groovy b/devicetypes/smartthings/king-of-fans-zwave-fan-controller.src/king-of-fans-zwave-fan-controller.groovy index bac1e10..b3eae92 100644 --- a/devicetypes/smartthings/king-of-fans-zwave-fan-controller.src/king-of-fans-zwave-fan-controller.groovy +++ b/devicetypes/smartthings/king-of-fans-zwave-fan-controller.src/king-of-fans-zwave-fan-controller.groovy @@ -1,4 +1,4 @@ -/** + /** Contributions from https://github.com/DavinKD/SmartThings/blob/master/devicetypes/davindameron/tasmota-fan.src/tasmota-fan.groovy * @@ -24,13 +24,13 @@ * 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. */ -// def version() {"ver 0.2.18"} //update as needed +def version() {"ver 0.2.18"} //update as needed -//def currVersions(child) { //Let's user know if running the child versions that corresponds to this parent version -// if(child=="fan") {return "ver 0.2.18"} //manually enter the version of the FAN child that matches the parent version above -// if(child=="light") {return "ver 0.2.18a"} //manually enter the version of the LIGHT child that matches the parent version above -// } +def currVersions(child) { //Let's user know if running the child versions that corresponds to this parent version + if(child=="fan") {return "ver 0.2.18"} //manually enter the version of the FAN child that matches the parent version above + if(child=="light") {return "ver 0.2.18a"} //manually enter the version of the LIGHT child that matches the parent version above +} /* @@ -59,7 +59,7 @@ 04/19 added version tile to help in troubleshooting with users */ metadata { - definition(name: "King of Fans Z-Wave Fan Controller", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.fan", genericHandler: "Zigbee") { + definition(name: "King of Fans Zigbee Fan Controller", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.fan", genericHandler: "Zigbee") { // definition (cstHandler: true, name: "AKOF Zigbee Fan Controller 1", namespace: "smartthings", author: "Stephan Hackett, Ranga Pedamallu, Dale Coffing, Rafael Borja", //ocfDeviceType: "oic.d.fan", genericHandler: "Zigbee") { capability "Switch Level" @@ -75,17 +75,19 @@ metadata { command "high" command "raiseFanSpeed" command "lowerFanSpeed" + + attribute "lastFanMode", "string" // Last fan speed value - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0003,0019" /*,0202" /, outClusters: "0003,0019" , model: "HDC52EastwindFan" */ + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0003,0019,0202", outClusters: "0003,0019" , model: "HDC52EastwindFan" } tiles(scale: 2) { multiAttributeTile(name: "fanSpeed", type: "generic", width: 6, height: 4, canChangeIcon: true) { tileAttribute("device.fanSpeed", key: "PRIMARY_CONTROL") { - attributeState "0", label: "off", action: "switch.on", icon: "st.thermostat.fan-off", backgroundColor: "#ffffff" - attributeState "1", label: "low", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" - attributeState "2", label: "medium", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" - attributeState "3", label: "high", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "0", label: "Off", action: "switch.on", icon: "st.thermostat.fan-off", backgroundColor: "#ffffff" + attributeState "1", label: "Low", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "2", label: "Medium", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" + attributeState "3", label: "High", action: "switch.off", icon: "st.thermostat.fan-on", backgroundColor: "#00a0dc" } tileAttribute("device.fanSpeed", key: "VALUE_CONTROL") { attributeState "VALUE_UP", action: "raiseFanSpeed" @@ -272,26 +274,35 @@ metadata { } def parse(String description) { - log.info "Parse description $description" + log.info "parse($description)" def event = zigbee.getEvent(description) if (event) { "Sample 0104 0006 01 01 0000 00 D42D 00 00 0000 01 01 010086" - log.info "Parse description ${description}" log.info "Light event detected on controller (event): ${event}" - def childDevice = getChildDevices()?.find { //find light child device - it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" - } - childDevice.sendEvent(event) //send light events to light child device and update lightBrightness attribute + log.debug "parse() child device found" + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + event.displayed = true + event.isStateChange = true + + childDevice.createAndSendEvent(event) + childDevice.createAndSendEvent(description) + childDevice.sendEvent(event) + childDevice.parse(description) + + //send light events to light child device and update lightBrightness attribute if(event.value != "on" && event.value != "off") { log.debug "sendEvent lightBrightness" - sendEvent(name: "lightBrightness", value: event.value) - sendEvent(name: "levelSliderControl", value: event.value) - sendEvent(name: "level", value: event.value) - sendEvent(name: "switch level", value: event.value) + + sendEvent(name: "lightBrightness", value: event.value, displayed: true, isStateChange: true) + sendEvent(name: "levelSliderControl", value: event.value, displayed: true, isStateChange: true) + sendEvent(name: "level", value: event.value, displayed: true, isStateChange: true) + sendEvent(name: "switch level", value: event.value, displayed: true, isStateChange: true) + } else { log.debug "not sending lightBrightness" } @@ -308,7 +319,7 @@ def parse(String description) { if (descMap.cluster == "0202" && descMap.attrId == "0000") { // Fan Control Cluster Attribute Read Response map.name = "fanMode" map.value = descMap.value - fanSync(descMap.value) + return fanEvents(descMap.value.toInteger()) } } // End of Read Attribute Response def result = null @@ -323,75 +334,84 @@ def parse(String description) { } } -def getIcon() { - return "https://cdn.rawgit.com/dcoffing/KOF-CeilingFan/master/resources/images/" +/* + * Returns the string representing speed value: + */ +def speedToLabel(speed) { + def labelMap = [ + "0":"Off", + "1":"Low", + "2":"Medium", + "3":"Medium-Hi", + "4":"High", + "5":"Off", + "6":"Comfort Breeze™", + "7":"Light" + ] + + return labelMap["${speed}"] } -def getFanName() { - [ - "00":"Off", - "01":"Low", - "02":"Med", - "03":"Med-Hi", - "04":"High", - "05":"Off", - "06":"Comfort Breeze™", - "07":"Light" - ] +/** + * Creates events for Fan based on speed value (switch, level and fan level) + */ +def fanEvents(speed) { + log.trace "fanEvents(${speed})" + + def value = (speed ? "on" : "off") + def result = [createEvent(name: "switch", value: value)] + // result << createEvent(name: "level", value: speed == 99 ? 100 : speed) + result << createEvent(name: "fanSpeed", value: speed) + + log.trace "fanEvents(${speed}) returning ${result}" + + return result } -def getFanNameAbbr() { - [ - "00":"Off", - "01":"Low", - "02":"Med", - "03":"Med-Hi", - "04":"High", - "05":"Off", - "06":"Breeze™", - "07":"Light" - ] -} -/* def installed() { - + log.debug "installed()" initialize() } -*/ + def updated() { - if(state.oldLabel != device.label) {updateChildLabel()} + log.debug "updated()" + / * if(state.oldLabel != device.label) {updateChildLabel()} */ // TODO DEV ONLY initialize() } def initialize() { - log.info "Initializing" - if(refreshChildren) { - deleteChildren() - device.updateSetting("refreshChildren", false) - } - else { - createFanChild() - createLightChild() - response(refresh() + configure()) - } + log.info "initialize()" + if(refreshChildren) { + deleteChildren() + device.updateSetting("refreshChildren", false) + refresh() + } + else { + // createFanChild() + createLightChild() + response(refresh() + configure()) + } } +// TODO update to rename only lights and breeze, and reverse def updateChildLabel() { - log.info "UPDATE LABEL" - for(i in 1..6) { + log.info "updateChildLabel()" + /*for(i in 1..6) { def childDevice = getChildDevices()?.find { it.device.deviceNetworkId == "${device.deviceNetworkId}-0${i}" } if (childDevice && i != 5) {childDevice.label = "${device.displayName} ${getFanName()["0${i}"]}"} // rename with new label - } + }*/ def childDeviceL = getChildDevices()?.find { it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" } if (childDeviceL) {childDeviceL.label = "${device.displayName}-Light"} // rename with new label -} +} + +/* def createFanChild() { state.oldLabel = device.label //save the label for reference if it ever changes for(i in 1..6) { @@ -408,19 +428,21 @@ def createFanChild() { log.info "Child already exists" } } -} +} */ def createLightChild() { + log.debug "createLightChild()" def childDevice = getChildDevices()?.find { it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" } if (!childDevice) { - childDevice = addChildDevice("KOF Zigbee Fan Controller - Light Child Device", "${device.deviceNetworkId}-Light", null,[completedSetup: true, - label: "${device.displayName} Light", isComponent: false, componentName: "fanLight", - componentLabel: "Light", "data":["parent version":version()]]) + + childDevice = addChildDevice("King of Fans Zigbee Fan - Light Child Device", "${device.deviceNetworkId}-Light", null,[completedSetup: true, + label: "${device.displayName} Light" ]) /*, isComponent: false, componentName: "fanLight", + componentLabel: "Light", "data":["parent version":version()]]) */ log.info "Creating child light ${childDevice}" } else { @@ -436,40 +458,10 @@ def deleteChildren() { log.info "Deleting children" } - -// Filename: printAllMethodsExample.groovy -void printAllMethods( obj ){ - if( !obj ){ - println( "Object is null\r\n" ); - return; - } - if( !obj.metaClass && obj.getClass() ){ - printAllMethods( obj.getClass() ); - return; - } - def str = "class ${obj.getClass().name} functions:\r\n"; - obj.metaClass.methods.name.unique().each{ - str += it+"(); "; - } - log.debug "${str}\r\n"; -} - - def configure() { - log.info "Configuring Reporting and Bindings." - log.info zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) - log.info zigbee.configureReporting(0x0006, 0x00011, 0x10, 0, 600, null) - - log.debug device.dump() - log.debug this.dump() + log.info "configure() Configuring Reporting and Bindings." - "[zdo bind 0xD42D 0x01 0x01 0x0006 {0022A3000016B5F4} {}, delay 2000, st cr 0xD42D 0x01 0x0006 0x0000 0x10 0x0000 0x0258 {}, delay 2000]" - /*def configure() { - configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) -} - sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) -*/ - + // Sample "[zdo bind 0xD42D 0x01 0x01 0x0006 {0022A3000016B5F4} {}, delay 2000, st cr 0xD42D 0x01 0x0006 0x0000 0x10 0x0000 0x0258 {}, delay 2000]" def cmd = [ @@ -509,31 +501,86 @@ def configure() { } -def off (physicalgraph.device.cache.DeviceDTO child) { lightOn(child) } +def getEndpoint (child) { + log.debug "getEndpoint (${child})" + + def endpoint = child.deviceNetworkId == device.deviceNetworkId?getInitialEndpoint():child.deviceNetworkId.minus("-Light") + + log.debug "getEndpoint (${child}): {endpoint}" + + return endpoint +} + +def off (physicalgraph.device.cache.DeviceDTO child) { + log.debug "off (physicalgraph.device.cache.DeviceDTO child ${child})" + + + + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if (childDevice) { + log.debug "Sending event to child $childDevice" + log.debug childDevice + childDevice.createAndSendEvent(name: "switch", value: "off", displayed: true, isStateChange: true) // childDevice.sendEvent(name: "device.switch", value: "off", displayed: true, isStateChange: true) + + // childDevice.sendEvent(name: "switch", value: "off", displayed: true, isStateChange: true) + + // childDevice.createAndSendEvent(name: "switch", value: "off", displayed: true, isStateChange: true) + } + + lightOff(getEndpoint(child)) +} -def on (physicalgraph.device.cache.DeviceDTO child) { lightOff(String id) } +def on (physicalgraph.device.cache.DeviceDTO child) { + log.debug "on (physicalgraph.device.cache.DeviceDTO child ${child})" + + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if (childDevice) { + log.debug "Sending event to child $childDevice" + log.debug childDevice + + childDevice.createAndSendEvent(name: "switch", value: "on", displayed: true, isStateChange: true) // childDevice.sendEvent(name: "device.switch", value: "on", displayed: true, isStateChange: true) + + //childDevice.sendEvent(name: "switch", value: "on", displayed: true, isStateChange: true) + + + } + + lightOn(getEndpoint(child)) +} +/* + * Called from child device + */ +def ping(physicalgraph.device.cache.DeviceDTO child) { + log.debug "ping(${child})" + return ping() + child.refresh() +} def on() { + log.debug "on()" log.info "Resuming Previous Fan Speed" def lastFan = device.currentValue("lastFanMode") //resumes previous fanspeed return setFanSpeed("$lastFan") - } def off() { - def fanNow = device.currentValue("fanMode") //save fanspeed before turning off so it can be resumed when turned back on - if(fanNow != "00") sendEvent("name":"lastFanMode", "value":fanNow) //do not save lastfanmode if fan is already off - def cmds=[ + log.debug "off()" + def fanNow = device.currentValue("fanSpeed") //save fanspeed before turning off so it can be resumed when turned back on + log.debug "off(): Current fan speed: $fanNow" + if (fanNow != "00") { + //do not save lastfanmode if fan is already off + sendEvent("name":"lastFanMode", "value":fanNow) + } + + def cmds=[ "st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {00}" ] - log.info "Turning fan Off" + log.info "off(): Turning fan Off" return cmds } def lightOn(String dni) { - log.info "Turning Light On" - zigbee.on() + log.info "lightOn(${dni})" log.debug "Loading childlights" def childDevice = getChildDevices()?.find { @@ -542,27 +589,51 @@ def lightOn(String dni) { if (childDevice) { log.debug "Sending event to child" log.debug childDevice - childDevice.sendEvent(name: "device.switch", value: "on") - childDevice.sendEvent(name: "switch", value: "on") - childDevice.createEvent(childDevice.createAndSendEvent(name: "switch", value: "on")) + childDevice.sendEvent(name: "device.switch", value: "on", displayed: true, isStateChange: true) + childDevice.sendEvent(name: "switch", value: "on", displayed: true, isStateChange: true) + childDevice.createEvent(childDevice.createAndSendEvent(name: "switch", value: "on", displayed: true, isStateChange: true )) } + + return zigbee.on() + + } def lightOff(String id) { - log.info "Turning Light Off" - zigbee.off() + log.info "lightOff(${id})" + + log.debug "Loading childlights" + def childDevice = getChildDevices()?.find { + it.device.deviceNetworkId == "${device.deviceNetworkId}-Light" + } + if (childDevice) { + log.debug "Sending event to child" + log.debug childDevice + childDevice.sendEvent(name: "device.switch", value: "off", displayed: true, isStateChange: true) + childDevice.sendEvent(name: "switch", value: "off", displayed: true, isStateChange: true) + childDevice.createEvent(childDevice.createAndSendEvent(name: "switch", value: "off", displayed: true, isStateChange: true )) + } + + return zigbee.off() + + } -/* + void childOn(String dni) { - onOffCmd(0xFF, channelNumber(dni)) + log.debug "childOn(String ${dni})" + lightOn(null) + // onOffCmd(0xFF, channelNumber(dni)) } void childOff(String dni) { - onOffCmd(0, channelNumber(dni)) -}*/ + log.debug "childOff(String ${dni})" + lightOff(null) + // onOffCmd(0, channelNumber(dni)) +} def lightLevel(val) { - log.info "Adjusting Light Brightness - called lightLevel on parent" + log.debug "lightLevel(${val})" + zigbee.setLevel(val) + (val?.toInteger() > 1 ? zigbee.on() : []) sendEvent(name:"level",value: val) @@ -575,17 +646,17 @@ def lightLevel(val) { log.debug childDevice //childDevice.sendEvent(name: "device.value", value: val) // childDevice.sendEvent(name: "device.switch", value: "on", isStatusChange: true) - childDevice.sendEvent(name: "switch", value: isDeviceOn? "on": "off", isStatusChange: true) - childDevice.sendEvent(name: "value", value: val, isStatusChange: true) - childDevice.createEvent(childDevice.createAndSendEvent(name: "level", value: value)) - + childDevice.sendEvent(name: "switch", value: isDeviceOn? "on": "off", isStatusChange: true, display: true) + childDevice.sendEvent(name: "value", value: val, isStatusChange: true, display: true) + childDevice.createEvent(childDevice.createAndSendEvent(name: "level", value: value, isStatusChange: true, display: true)) } } /** * Called from APP when sliding light dimmer */ -def setLevel(val, rate = null) { +def setLevel(val, rate = null, device=null) { + log.debug "setLevel(${val}, ${rate})" log.info "Adjusting Light Brightness via setlevel on parent: {$val}" // sendEvent(name:"level",value: val) @@ -617,17 +688,21 @@ def setLevel(val, rate = null) { } def poll() { - log.debug("####POLL HAS BEEN CALLED") + log.debug("poll()") } -def setFanSpeed(speed) { +// Called from main device from app to set fan speed +def setFanSpeed(speed) { + log.debug "setFanSpeed(${speed})" + def cmds=[ "st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {${speed}}" ] - log.info "Adjusting Fan Speed to "+ getFanName()[speed] + log.info "Adjusting Fan Speed to "+ speedToLabel(speed) return cmds } +/* def fanSync(whichFan) { def children = getChildDevices() children.each {child-> @@ -646,21 +721,20 @@ def fanSync(whichFan) { } } if(whichFan == "00") sendEvent(name:"switch",value:"off") //send OFF event to Fan Parent - } +*/ def ping() { - log.debug("#####PING HAS BEN CALLED!!!!!") + log.debug("ping()") return zigbee.onOffRefresh() } -def refresh() { - log.info "Refresh called" - - getChildVer() +def refresh(physicalgraph.device.cache.DeviceDTO child=null) { + log.info "refresh($child) called " return zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(0x0202, 0x0000) + zigbee.readAttribute(0x0006, 0x0000) + - zigbee.readAttribute(0x0202, 0x0000) + zigbee.readAttribute(0x0202, 0x0001) + zigbee.readAttribute(0x0006, 0x0001) + zigbee.readAttribute(0x0006, 0x0000) + zigbee.readAttribute(0x0008, 0x0004) + zigbee.readAttribute(0x0202, 0x0000) + zigbee.readAttribute(0x0202, 0x0001) + zigbee.readAttribute(0x0006, 0x0001) + zigbee.readAttribute(0x0006, 0x0000) + + zigbee.readAttribute(0x0008, 0x0004) + zigbee.readAttribute(0x0008, 0x0004) } @@ -683,13 +757,13 @@ def getChildVer() { } - +/* def installed() { sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) response(refresh()) -} - +}*/ +/* def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { fanEvents(cmd) @@ -715,8 +789,9 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { // Handles all Z-Wave commands we aren't interested in log.debug "Unhandled: ${cmd.toString()}" [:] -} +} */ +/* def fanEvents(physicalgraph.zwave.Command cmd) { def rawLevel = cmd.value as int def result = [] @@ -740,12 +815,7 @@ def fanEvents(physicalgraph.zwave.Command cmd) { } return result -} - -def getDelay() { - // the leviton is comparatively well-behaved, but the GE and Honeywell devices are not - zwaveInfo.mfr == "001D" ? 2000 : 5000 -} +}*/ def raiseFanSpeed() { @@ -767,4 +837,3 @@ def medium() { def high() { setLevel(99) } - From 908017ce6678066b3d1e156e34f1340834916080 Mon Sep 17 00:00:00 2001 From: Rafael Borja <5069188+rafaelborja@users.noreply.github.com> Date: Mon, 6 Apr 2020 20:28:22 -0400 Subject: [PATCH 9/9] First fully functional version Fully functional version with child device acting and responding to events. Dimmer also function. Needs some code cleaning. --- ...-fans-zigbee-fan-light-child-device.groovy | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/devicetypes/smartthings/king-of-fans-zigbee-fan-light-child-device.src/king-of-fans-zigbee-fan-light-child-device.groovy b/devicetypes/smartthings/king-of-fans-zigbee-fan-light-child-device.src/king-of-fans-zigbee-fan-light-child-device.groovy index 73d64d9..85c8054 100644 --- a/devicetypes/smartthings/king-of-fans-zigbee-fan-light-child-device.src/king-of-fans-zigbee-fan-light-child-device.groovy +++ b/devicetypes/smartthings/king-of-fans-zigbee-fan-light-child-device.src/king-of-fans-zigbee-fan-light-child-device.groovy @@ -39,6 +39,11 @@ metadata { capability "Actuator" capability "Sensor" capability "Refresh" + capability "Switch Level" + + command "off" + command "on" + } // Zemismart HGZB-42 @@ -68,16 +73,20 @@ metadata { void on() { log.info "on()" - parent.on(device) - //sendEvent(name: "device.switch", value: "on") - //sendEvent(name: "switch", value: "on") + sendEvent(name: "device.switch", value: "on", displayed: true, isStateChange: true) + sendEvent(name: "switch", value: "on", displayed: true, isStateChange: true) + parent.on(device) + + } void off() { log.info "off()" + sendEvent(name: "switch", value: "off", displayed: true, isStateChange: true) + sendEvent(name: "device.switch", value: "off", displayed: true, isStateChange: true) + parent.off(device) - //sendEvent(name: "switch", value: "off") - // sendEvent(name: "device.switch", value: "off") + } void refresh() { @@ -88,16 +97,24 @@ void refresh() { def createAndSendEvent(map) { - log.debug "child[ ${device.endpointId} ].sendEvent($map)" - sendEvent(map) - return map + log.debug "child[ ${device.deviceNetworkId} ].createAndSendEvent($map)" + results.each { name, value -> + sendEvent(name: name, value: value) + } + return null } def parse(description) { - log.debug "Parse Child: $description" + log.debug "PARSE IN Child: $description" + + //def event = zigbee.getEvent(description) + //sendEvent(description) + // return sendEvent(event) + + } -def setLevel(value, rate = 10) { parent.setLevel(device, value, rate) } +def setLevel(value, rate = 10) { parent.setLevel(value, rate, device) } def poll() { log.debug "poll()" @@ -112,10 +129,10 @@ def ping() { def installed () { log.debug "installed() - parent $parent" - sendEvent(name: "checkInterval", value: 10, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "checkInterval", value: 5, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } def uninstalled () { log.debug "uninstalled()" //parent.delete() -} \ No newline at end of file +}