You may want to take some inspiration from my alarm clock device handler… It’s basically a bunch of simulated switches cobbled into a single device, feeding data to webCoRE which is the brain of things. Snooze duration is set via the device settings page, so that is another option for you to look at.
You can set alarm times, snooze duration, active days etc…
I’m also running custom handlers for various bathroom fans, to set trigger type (lights or humidity), required humidity level, overrun time, current temperature and humidity. Again, just a bunch of simulated switches and dimmers for sending data to webCoRE.
metadata {
definition (name: "Switch Child Device - Fan", namespace: "RobinWinbourne", author: "RobinWinbourne", vid: "generic-switch") {
capability "Switch"
capability "Actuator"
capability "Sensor"
capability "Refresh"
capability "Momentary"
capability "Button"
attribute "currentTemp", "string"
attribute "currentHumidity", "string"
attribute "mode", "string"
attribute "humidityLevel", "string"
attribute "overrunLevel", "string"
attribute "switch2", "string"
command "setCurrentHumidity"
command "setCurrentTemp"
command "setHumidity"
command "setLightMode"
command "setHumidityMode"
command "setManualMode"
command "setMode"
command "setHumidity"
command "setOverrun"
command "on2"
command "off2"
}
tiles(scale: 2) {
//multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: false){
// tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
// attributeState "off", label: '${name}', action: "switch.on", icon: "https://cdn.rawgit.com/RobinWinbourne/devicetypes/master/fan3.png", backgroundColor: "#ffffff", nextState:"turningOn"
// attributeState "on", label: '${name}', action: "switch.off", icon: "https://cdn.rawgit.com/RobinWinbourne/devicetypes/master/fan3.png", backgroundColor: "#ff9900", nextState:"turningOff"
// attributeState "turningOn", label:'${name}', action:"switch.off", icon:"https://cdn.rawgit.com/RobinWinbourne/devicetypes/master/fan3.png", backgroundColor:"#ff9900", nextState:"turningOff"
// attributeState "turningOff", label:'${name}', action:"switch.on", icon:"https://cdn.rawgit.com/RobinWinbourne/devicetypes/master/fan3.png", backgroundColor:"#ffffff", nextState:"turningOn"
// }
// }
standardTile("Title1", "device.Title1", inactiveLabel: false, width: 2, height: 1, decoration: "flat", wordWrap: false) {
state "default", label:'Fan'
}
standardTile("Title2", "device.Title2", inactiveLabel: false, width: 2, height: 1, decoration: "flat", wordWrap: false) {
state "default", label:'Humidity'
}
standardTile("Title3", "device.Title3", inactiveLabel: false, width: 2, height: 1, decoration: "flat", wordWrap: false) {
state "default", label:'Temperature'
}
standardTile("switch", "device.switch", inactiveLabel: false, width: 2, height: 2, decoration: "flat", canChangeIcon: false) {
state "off", label: '${name}', action: "switch.on", icon: "https://cdn.rawgit.com/RobinWinbourne/devicetypes/master/fan3.png", backgroundColor: "#ffffff", nextState:"turningOn"
state "on", label: '${name}', action: "switch.off", icon: "https://cdn.rawgit.com/RobinWinbourne/devicetypes/master/fan3.png", backgroundColor: "#ff9900", nextState:"turningOff"
state "turningOn", label:'${name}', action:"switch.off", icon:"https://cdn.rawgit.com/RobinWinbourne/devicetypes/master/fan3.png", backgroundColor:"#ff9900", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"https://cdn.rawgit.com/RobinWinbourne/devicetypes/master/fan3.png", backgroundColor:"#ffffff", nextState:"turningOn"
}
valueTile("currentTemp", "device.currentTemp", inactiveLabel: true, width: 2, height: 2, decoration: "flat", wordWrap: true) {
state ("default", label:'${currentValue}\u00b0', backgroundColors:[
[value: "error", color: "#ff0000"],
[value: 0, color: "#153591"],
[value: 7, color: "#1e9cbb"],
[value: 15, color: "#90d2a7"],
[value: 23, color: "#44b621"],
[value: 28, color: "#f1d801"],
[value: 35, color: "#d04e00"],
[value: 37, color: "#bc2323"]
]
)
}
valueTile("currentHumidity", "device.currentHumidity", inactiveLabel: false, width: 2, height: 2, decoration: "flat", wordWrap: true) {
state ("default", label:'${currentValue}%', backgroundColors:[
[value: "error", color: "#ff0000"],
[value: 20, color: "#153591"],
[value: 30, color: "#1e9cbb"],
[value: 40, color: "#90d2a7"],
[value: 50, color: "#44b621"],
[value: 60, color: "#f1d801"],
[value: 70, color: "#d04e00"],
[value: 80, color: "#bc2323"]
]
)
}
standardTile("Title4", "device.Title4", inactiveLabel: false, width: 2, height: 1, decoration: "flat", wordWrap: false) {
state "default", label:'Mode'
}
standardTile("Title5", "device.Title5", inactiveLabel: false, width: 2, height: 1, decoration: "flat", wordWrap: false) {
state "default", label:'Req. Humidity'
}
standardTile("Title6", "device.Title6", inactiveLabel: false, width: 2, height: 1, decoration: "flat", wordWrap: false) {
state "default", label:'Overrun Time'
}
standardTile("mode", "device.mode", width: 2, height: 2, decoration: "flat", inactiveLabel: false) {
state "humidityMode", label: "Humidity", action: "setLightMode", icon: "st.Weather.weather12", backgroundColor: "#00a0dc", nextState:"lightMode"
state "lightMode", label: "Light", action: "setManualMode", icon: "st.Lighting.light11", backgroundColor: "#f1d801", nextState:"manualMode"
state "manualMode", label: "Manual", action: "setHumidityMode", icon: "st.sonos.pause-icon", backgroundColor: "#FFFFFF", nextState:"humidityMode"
}
controlTile("humidityLevel", "device.humidityLevel", "slider", height: 2, width: 2, range: "(0..100)", inactiveLabel: false) {
state "default", action:"setHumidity", backgroundColor:"#AF1586"
}
controlTile("overrunLevel", "device.overrunLevel", "slider", height: 2, width: 2, range: "(0..100)", inactiveLabel: false) {
state "default", action:"setOverrun", backgroundColor:"#AF1586"
}
standardTile("switch2", "device.switch2", width: 2, height: 2, decoration: "flat", inactiveLabel: false) {
state "on2", label: "Pushed", action: "off2", icon: "st.alarm.water.dry", backgroundColor: "#999900"
state "Run Now", label: '${currentValue}', action: "on2", icon: "st.Health & Wellness.health7", backgroundColor: "#ffffff", nextState: "on2"
state "Stop", label: '${currentValue}', action: "on2", icon: "st.Health & Wellness.health7", backgroundColor: "#ffffff", nextState: "on2"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main(["switch"])
details(["Title1","Title2","Title3","switch","currentHumidity","currentTemp","Title4","Title5","Title6","mode","humidityLevel","overrunLevel","switch2","refresh"])
}
}
def installed() {
log.debug "installed()"
configure()
}
def updated() {
log.debug "updated()"
configure()
}
def configure() {
log.debug "configure()"
sendEvent(name: "numberOfButtons", value: 1, displayed: true)
}
void on() {
parent.childOn(device.deviceNetworkId)
sendEvent(name: "switch2", value: "Stop", isStateChange: true, displayed: false)
}
void off() {
parent.childOff(device.deviceNetworkId)
sendEvent(name: "switch2", value: "Run Now", isStateChange: true, displayed: false)
}
void refresh() {
parent.childRefresh(device.deviceNetworkId)
}
def setCurrentTemp (param) {
sendEvent("name":"currentTemp", "value":param)
}
def setCurrentHumidity (param) {
sendEvent("name":"currentHumidity", "value":param)
}
def setLightMode() {
log.trace "Executing 'light'"
sendEvent(name: "mode", value: "lightMode")
// state.lastHumidity = device.currentValue("humidityLevel")
// setHumidity(0)
}
def setHumidityMode() {
log.trace "Executing 'humidity'"
sendEvent(name: "mode", value: "humidityMode")
// setHumidity(state.lastHumidity)
// setOverrun(state.lastOverrun)
}
def setManualMode() {
log.trace "Executing 'manual'"
sendEvent(name: "mode", value: "manualMode")
// state.lastOverrun = device.currentValue("overrunLevel")
// setOverrun(0)
}
def setMode(param) {
log.error "set mode to $param"
if (param == "humidityMode") {setHumidityMode()}
if (param == "lightMode") {setLightMode()}
if (param == "manualMode") {setManualMode()}
}
def setHumidity(value) {
log.trace "Executing setLevel Humidity $value"
Map levelEventMap = buildSetLevelEvent(value)
sendEvent(levelEventMap)
}
def setOverrun(value) {
log.trace "Executing setLevel Overrun $value"
Map levelEventMap = buildSetLevelEvent2(value)
sendEvent(levelEventMap)
}
private Map buildSetLevelEvent(value) {
def intValue = value as Integer
def newLevel = Math.max(Math.min(intValue, 100), 0)
Map eventMap = [name: "humidityLevel", value: newLevel, unit: "%"]
return eventMap
}
private Map buildSetLevelEvent2(value) {
def intValue = value as Integer
def newLevel = Math.max(Math.min(intValue, 100), 0)
Map eventMap = [name: "overrunLevel", value: newLevel, unit: "%"]
return eventMap
}
def push() {
sendEvent(name: "switch2", value: "on2", isStateChange: true, displayed: false)
sendEvent(name: "switch2", value: "Run Now", isStateChange: true, displayed: false)
sendEvent(name: "momentary", value: "pushed", isStateChange: true)
sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "$device.displayName button 1 was pushed", isStateChange: true)
}
def on2() {
push()
}
def off2() {
sendEvent(name: "switch2", value: "Run Now", isStateChange: true, displayed: false)
}
And I may have gone a little bit too far with this one lol: