Skip to content

Instantly share code, notes, and snippets.

@jtp10181
Last active February 23, 2024 01:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jtp10181/3e07242e08d35e7a73fe9a6c5c8226e0 to your computer and use it in GitHub Desktop.
Save jtp10181/3e07242e08d35e7a73fe9a6c5c8226e0 to your computer and use it in GitHub Desktop.
Hubitat Enhanced Virtual Fan Controller
/**
* Enhanced Virtual Fan Controller
*
* Copyright 2019 Joel Wetzel
* Copyright 2022 Jeff Page
*
* 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.
*
*/
import groovy.transform.Field
@Field static Map<Integer, List> supportedSpeed =
[
3: ["low","medium","high","on","off"],
4: ["low","medium-low","medium-high","high","on","off"],
5: ["low","medium-low","medium","medium-high","high","on","off"]
]
metadata {
definition (name: "Enhanced Virtual Fan Controller", namespace: "joelwetzel", author: "Joel Wetzel", description: "A virtual fan controller that also behaves as a switch.") {
capability "Actuator"
capability "Switch"
capability "Fan Control"
capability "Switch Level"
//command "setSpeed", [ [name:"Fan speed*", type: "ENUM", constraints: supportedSpeed[3]] ]
}
preferences {
input "numSpeeds", "enum", title: "Set Number of Speeds Supported",
defaultValue: "3", options: ["3", "4", "5"],
required: true
//Logging options similar to other Hubitat drivers
input "txtEnable", "bool", title: "Enable Description Text Logging?", defaultValue: true
input "debugEnable", "bool", title: "Enable Debug Logging?", defaultValue: false
}
}
void installed () {
initialize()
logWarn "installed()"
}
void updated () {
//initialize()
logInfo "updated()"
sendEvent(name: "supportedFanSpeeds", value: supportedSpeed[numSpeeds as Integer])
}
void initialize() {
logInfo "initialize()"
setSpeed("off")
}
void on() {
logDebug "on()"
setSpeed(state.lastSpeed ?: "low")
}
void off() {
logDebug "off()"
setSpeed("off")
}
void setSpeed(speed) {
logDebug "setSpeed($speed)"
String adjustedSpeed = restrictSpeedLevels(speed) // Only allow certain speed settings. For example, don't allow "medium-high".
Integer adjustedLevel = convertSpeedToLevel(adjustedSpeed) // Some fan controllers depend on speed, some depend on level. Convert the speed to a level.
String adjustedSwitch = (adjustedSpeed == "off") ? "off" : "on" // If speed is "off", then turn off the switch too.
// Keep track of the last speed while on. Then if the fan is off, and
// we turn it back on, we can go back to the last on speed.
if (adjustedSpeed != "off") {
state.lastSpeed = adjustedSpeed
}
sendEvent(name: "switch", value: adjustedSwitch)
sendEvent(name: "speed", value: adjustedSpeed)
sendEvent(name: "level", value: adjustedLevel)
}
void cycleSpeed() {
logWarn "cycleSpeed() NOT SUPPORTED"
}
// If our input is level, convert it to a speed input.
void setLevel(level) {
logDebug "setLevel($level)"
String requestedSpeed = convertLevelToSpeed(level)
setSpeed(requestedSpeed)
}
// This converts speeds back into levels. These values correspond well to a GE
// Z-Wave Plus Fan Controller, but might need to change for other smart fan
// controllers.
Number convertSpeedToLevel(speed) {
switch (speed) {
case "off":
return 0
case "low":
return 33
case "medium":
return 66
case "high":
return 100
default:
return 0
}
}
// This restricts allowed speed levels. The GE Z-Wave Plus Smart Fan
// Controller doesn't support medium-low, medium-high, or auto, so
// this converts them into something else.
String restrictSpeedLevels(speed) {
switch (speed) {
case "on":
case "auto":
return state.lastSpeed
case "medium-low":
return "low"
case "medium-high":
return "medium"
default:
return speed
}
}
// This maps ranges of levels into speed values. Right now it's set for just
// three speeds and off.
String convertLevelToSpeed(level) {
if (level == 0) {
return "off"
} else if (level < 50) {
return "low"
} else if (level < 99) {
return "medium"
} else {
return "high"
}
}
/*******************************************************************
***** Logging Functions
********************************************************************/
void logWarn(String msg) {
log.warn "${device.displayName}: ${msg}"
}
void logInfo(String msg) {
if (txtEnable) log.info "${device.displayName}: ${msg}"
}
void logDebug(String msg) {
if (debugEnable) log.debug "${device.displayName}: ${msg}"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment