It would be easy to modify the driver code to add that as a command instead of just a preference, but we can't get the built-in code. I'm not sure how open you are to AI drivers, but Gemini says that this is Parameter 13.
As usual, AI is confident it can write a complete driver for the Zen12 that has this parameter change as an exposed command. If I had a Zen12 I would test it and give you a working driver, but I don't have one. Anyway, I had AI write a driver.
After it gave me the code, I told it to check itself. It found and fixed errors. Then I had it check its code again, and it fixed one more thing. It thinks it will work (it probably will, mostly, but there will probably be an error or two it will need to fix)
/**
* Zooz ZEN12 Motion Dimmer Advanced Automator (Verified Production)
*
* Supports S2 Security Encapsulation, Supervision Confirmation,
* Real-time Motion/Lux/Switch reporting, and programmatic Parameter 13 overrides.
*/
import groovy.transform.Field
@Field static Map commandClassVersions = [
0x20: 1, // Basic
0x25: 1, // Switch Binary
0x26: 3, // Switch Multilevel
0x31: 3, // Sensor Multilevel (Illuminance)
0x6C: 1, // Supervision
0x70: 1, // Configuration
0x71: 3, // Notification (Motion)
0x5B: 3, // Central Scene (Button)
0x98: 1, // Security S0
0x9F: 1 // Security S2
]
metadata {
definition (name: "Zooz ZEN12 Advanced Automator", namespace: "custom", author: "Community", importUrl: "") {
capability "Switch"
capability "SwitchLevel"
capability "MotionSensor"
capability "IlluminanceMeasurement"
capability "Button"
capability "Refresh"
capability "Configuration"
capability "Actuator"
// Exposed custom commands for Rule Machine
command "enableMotionTrigger"
command "disableMotionTrigger"
}
preferences {
input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
}
}
// MAIN PARSE ENGINE: Intercepts and unpacks raw hardware packets
def parse(String description) {
if (logEnable) log.debug "ZEN12 incoming raw packet: ${description}"
hubitat.zwave.Command cmd = zwave.parse(description, commandClassVersions)
if (cmd) {
zwaveEvent(cmd)
}
}
// SECURITY ENCAPSULATION PARSERS
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
hubitat.zwave.Command encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions)
if (encapsulatedCmd) zwaveEvent(encapsulatedCmd)
}
def zwaveEvent(hubitat.zwave.commands.securityv2.SecurityMessageEncapsulation cmd) {
hubitat.zwave.Command encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions)
if (encapsulatedCmd) zwaveEvent(encapsulatedCmd)
}
// SUPERVISION ENCAPSULATION PARSER (Essential for modern 800-series firmware)
def zwaveEvent(hubitat.zwave.commands.supervisionv1.SupervisionGet cmd) {
if (logEnable) log.debug "SupervisionGet received. SessionID: ${cmd.sessionID}"
// Acknowledge the command immediately back to the device to keep the link clear
def report = zwave.supervisionV1.supervisionReport(sessionID: cmd.sessionID, status: 0xFF, duration: 0)
sendHubCommand(new hubitat.device.HubAction(secureResponse(report), hubitat.device.Protocol.ZWAVE))
hubitat.zwave.Command encapsulatedCmd = cmd.encapsulatedCommand(commandClassVersions)
if (encapsulatedCmd) zwaveEvent(encapsulatedCmd)
}
// STATE REPORTERS
def zwaveEvent(hubitat.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
def value = (cmd.value == 0xFF) ? "on" : "off"
sendEvent(name: "switch", value: value, descriptionText: "Switch turned ${value}")
}
def zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) {
def value = (cmd.value > 0) ? "on" : "off"
sendEvent(name: "switch", value: value)
sendEvent(name: "level", value: cmd.value, unit: "%", descriptionText: "Dimmer level set to ${cmd.value}%")
}
def zwaveEvent(hubitat.zwave.commands.notificationv3.NotificationReport cmd) {
if (cmd.notificationType == 0x07) { // Home Security
if (cmd.event == 0x08) { // Motion Active
sendEvent(name: "motion", value: "active", descriptionText: "Motion detected")
} else if (cmd.event == 0x00) { // Motion Idle
sendEvent(name: "motion", value: "inactive", descriptionText: "Motion cleared")
}
}
}
def zwaveEvent(hubitat.zwave.commands.sensormultilevelv3.SensorMultilevelReport cmd) {
if (cmd.sensorType == 0x03) { // Illuminance
sendEvent(name: "illuminance", value: cmd.scaledSensorValue, unit: "lux", descriptionText: "Illuminance is ${cmd.scaledSensorValue} lux")
}
}
def zwaveEvent(hubitat.zwave.commands.centralscenev3.CentralSceneNotification cmd) {
def btnNum = cmd.sceneNumber
def action = "pushed"
if (cmd.keyAttributes == 1) action = "released"
else if (cmd.keyAttributes == 2) action = "held"
else if (cmd.keyAttributes == 3) action = "doubleTapped"
sendEvent(name: action, value: btnNum, isStateChange: true, descriptionText: "Button ${btnNum} was ${action}")
}
def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
if (logEnable) log.info "ZEN12 Parameter ${cmd.parameterNumber} verified over-the-air. Current value: ${cmd.configurationValue}"
}
def zwaveEvent(hubitat.zwave.Command cmd) {
if (logEnable) log.debug "Ignored/Unhandled Z-Wave packet payload: ${cmd}"
}
// CAPABILITY COMMAND METHODS (Returns cleanly to Hubitat execution layer)
def on() {
if (logEnable) log.debug "Sending On payload"
return secureResponse(zwave.switchMultilevelv3.switchMultilevelSet(value: 0xFF, dimmingDuration: 0))
}
def off() {
if (logEnable) log.debug "Sending Off payload"
return secureResponse(zwave.switchMultilevelv3.switchMultilevelSet(value: 0x00, dimmingDuration: 0))
}
def setLevel(level, duration = 0) {
if (logEnable) log.debug "Sending SetLevel payload to ${level}%"
def targetLevel = Math.min(Math.max(level.toInteger(), 0), 99)
return secureResponse(zwave.switchMultilevelv3.switchMultilevelSet(value: targetLevel, dimmingDuration: duration))
}
def refresh() {
if (logEnable) log.debug "Requesting state refresh from device..."
List<String> cmds = [
zwave.switchMultilevelv3.switchMultilevelGet().format(),
zwave.sensorMultilevelv3.sensorMultilevelGet(sensorType: 0x03).format()
]
return delayBetween(cmds.collect { zwaveSecureEncap(it) }, 400)
}
def configure() {
if (logEnable) log.info "Mapping Hub Z-Wave Lifeline association to Group 1"
return secureResponse(zwave.associationV2.associationSet(groupingIdentifier: 1, nodeId: [zwaveHubNodeId]))
}
// RULE ENGINE ENTRY POINTS (Dispatches explicitly out to Z-Wave radio)
def enableMotionTrigger() {
if (logEnable) log.info "Rule Request: Restoring hardware motion activation linking (Param 13 = 0)"
def cmd = zwave.configurationV1.configurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: 0)
sendHubCommand(new hubitat.device.HubAction(secureResponse(cmd), hubitat.device.Protocol.ZWAVE))
}
def disableMotionTrigger() {
if (logEnable) log.info "Rule Request: Decoupling load relay from motion sensor loops (Param 13 = 1)"
def cmd = zwave.configurationV1.configurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: 1)
sendHubCommand(new hubitat.device.HubAction(secureResponse(cmd), hubitat.device.Protocol.ZWAVE))
}
// SYSTEM SECURE ENCAPSULATION WRAPPERS
private String secureResponse(hubitat.zwave.Command cmd) {
return zwaveSecureEncap(cmd.format())
}
Edit: The first thing I would do is paste this code back into Gemini, or any other AI chat, and have it check the code again. Then once you start testing the code, use that session to feedback any errors from logs. Be sure to press configure after changing the driver type in the device.