Can anyone assist me in modifying the custom driver I am using for the HomeSeer HS-FLS100+ Floodlight Sensor to convert the Lux Threshold Settings in the Preferences section of the device edit page to instead be a Command?
I pasted the existing Driver and elements I think might need to be modified below as a start, but don't know much about how to configure the Z-wave Commands in the driver to actually change the setting in the device and read the resulting setting back from the device.
Any help would be much appreciated!!!!
Let me explain what I am trying to do:
The reasoning is that this Preference controls the Level of the Lux reading below which a motion detection from the PIR sensor causes the device to send a Light On command for the device. The normal use case for me is to have this set at 30 Lux, and then when it's fairly dark, the light comes on with motion, and ceases to come on with motion when it is greater than 30 Lux.
This all works great to create a regular night only motion light, but there are occasions when I don't want the lights to come on with motion at all. To stop it from coming on with motion at all, I can do one of 2 things when using the existing Driver:
-
Set this Preference in each device to zero, one at a time, in the device edit page, which would probably be tolerable if I only had one, but there are currently 6 of them
-
A more draconian method is to cut the power to all the devices. Since these are mains powered devices that become Z-Wave repeaters, cutting the power knocks them out of the Z-wave mesh causing routing issues, and it also means the motion and Lux sensors become unavailable, which are used in many other rules, causing other issues.
So what I want to do is have a virtual switch on the dashboard that triggers a Rule Machine rule to change this Preference in each light to zero, which tells them to not send the Light On commands with motion. However since this is a Preference and not a Command, I don't believe I can access this Preference in Rule Machine, at least I don't see it available in the Custom Actions section for the device in Rule Machine. So I believe I need to convert this Preference to a Command.
I believe I can add an enumerated list as a Command in the driver with this syntax:
command(
"setLuxThreshold",
[
[
"name":"Lux Threshold",
"description":"Set the Lux level below which Motion sends a Light On command to the device. Range: 0,255,30-200. 0=Never Turn Light On with Motion, 255=Always Turn Light On with Motion (ignore Lux)",
"type":"ENUM",
"constraints":["0 (Never Turn On)","255 (Always Turn On)","30","40","50 (default)","60","70","80","90","100","110","120","130","140","150","160","170","190","190","200"]
]
]
);
From the existing driver and the Manual, I see that this is Parameter 2 that is being set with a size of 2. So I think I might be able to add the Command Z-Wave actions themselves with something like this, which I saw implemented in a GE Z-Wave Plus Motion Dimmer driver that has an enumerated Command:
void setLuxThreshold(value) {
if (logEnable) log.debug "Setting Lux Threshold value: ${value}"
def cmds = []
// "0 (Never Turn On)","255 (Always Turn On)","30","40","50 (default)","60","70","80","90","100","110","120","130","140","150","160","170","190","190","200"
switch (value) {
case "0 (Never Turn On)":
state.luxThreshold = "0 (Never Turn On)"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 0 , parameterNumber: 2, size: 2).format()
break
case "255":
state.luxThreshold = "255 (Always Turn On)"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 255 , parameterNumber: 2, size: 2).format()
break
case "30":
state.luxThreshold = "30"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 30 , parameterNumber: 2, size: 2).format()
break
case "40":
state.luxThreshold = "40"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 40 , parameterNumber: 2, size: 2).format()
break
case "50 (default)":
state.luxThreshold = "50 (default)"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 50 , parameterNumber: 2, size: 2).format()
break
case "40":
state.luxThreshold = "60"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 60 , parameterNumber: 2, size: 2).format()
break
case "70":
state.luxThreshold = "70"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 70 , parameterNumber: 2, size: 2).format()
break
case "80":
state.luxThreshold = "80"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 80 , parameterNumber: 2, size: 2).format()
break
case "90":
state.luxThreshold = "90"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 90 , parameterNumber: 2, size: 2).format()
break
case "100":
state.luxThreshold = "100"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 100 , parameterNumber: 2, size: 2).format()
break
case "110":
state.luxThreshold = "110"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 110 , parameterNumber: 2, size: 2).format()
break
case "120":
state.luxThreshold = "120"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 120 , parameterNumber: 2, size: 2).format()
break
case "130":
state.luxThreshold = "130"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 130 , parameterNumber: 2, size: 2).format()
break
case "140":
state.luxThreshold = "140"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 140 , parameterNumber: 2, size: 2).format()
break
case "150":
state.luxThreshold = "150"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 150 , parameterNumber: 2, size: 2).format()
break
case "160":
state.luxThreshold = "160"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 160 , parameterNumber: 2, size: 2).format()
break
case "170":
state.luxThreshold = "170"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 170 , parameterNumber: 2, size: 2).format()
break
case "180":
state.luxThreshold = "180"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 180 , parameterNumber: 2, size: 2).format()
break
case "190":
state.luxThreshold = "190"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 190 , parameterNumber: 2, size: 2).format()
break
case "200":
state.luxThreshold = "200"
cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: 200 , parameterNumber: 2, size: 2).format()
break
default:
return
}
cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
delayBetween(cmds, 500)
}
Then in that GE Z-Wave Plus Motion Dimmer driver, it might be using this type of syntax to get the value from the device, but I'm not sure, and I also realize that I only really have Case 2 here, which I thinkk might relate to Parameter 2, but I really have no idea?
void zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
if (logEnable) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} sent ${cmd}"
def config = cmd.scaledConfigurationValue.toInteger()
def result = []
def name = ""
def value = ""
def reportValue = config // cmd.configurationValue[0]
switch (cmd.parameterNumber) {
case 2:
name = "Lux Threshold"
// "0 (Never Turn On)","255 (Always Turn On)","30","40","50 (default)","60","70","80","90","100","110","120","130","140","150","160","170","190","190","200"
value = reportValue == 0 ? "0 (Never Turn On)" : reportValue == 255 ? "255 (Always Turn On)" : reportValue == 30 ? "30" : reportValue == 40 ? "40" : reportValue == 50 ? "50 (default)" : reportValue == 50 ? "50" : reportValue == 60 ? "60" : reportValue == 70 ? "70" : reportValue == 80 ? "80" : reportValue == 90 ? "90" : reportValue == 100 ? "100" : reportValue == 110 ? "110" : reportValue == 120 ? "120" : reportValue == 130 ? "130" : reportValue == 140 ? "140" : reportValue == 150 ? "150" : reportValue == 160 ? "160" : reportValue == 170 ? "170" : reportValue == 180 ? "180" : reportValue == 190 ? "190" : reportValue == 200 ? "200" : "error"
if (value == 0) {state.luxThreshold = "0 (Never Turn On)"}
else if (value == 255) {state.luxThreshold = "255 (Always Turn On)"}
else if (value == 30) {state.luxThreshold = "30"}
else if (value == 40) {state.luxThreshold = "40"}
else if (value == 50) {state.luxThreshold = "50 (default)"}
else if (value == 60) {state.luxThreshold = "60"}
else if (value == 70) {state.luxThreshold = "70"}
else if (value == 80) {state.luxThreshold = "80"}
else if (value == 90) {state.luxThreshold = "90"}
else if (value == 100) {state.luxThreshold = "100"}
else if (value == 110) {state.luxThreshold = "110"}
else if (value == 120) {state.luxThreshold = "120"}
else if (value == 130) {state.luxThreshold = "130"}
else if (value == 140) {state.luxThreshold = "140"}
else if (value == 150) {state.luxThreshold = "150"}
else if (value == 160) {state.luxThreshold = "160"}
else if (value == 170) {state.luxThreshold = "170"}
else if (value == 180) {state.luxThreshold = "180"}
else if (value == 190) {state.luxThreshold = "190"}
else if (value == 200) {state.luxThreshold = "200"}
break
}
result << createEvent([name: name, value: value, displayed: false])
return result
}
Lots of questions:
-
Are these the correct elements to adjust
-
Is it the correct syntax
-
Are they the correct Z-Wave commands to make the setting in the device
-
Will this also report back the setting that has been made and accepted by the device
-
Will this then show-up in Rule Machine as a Custom Action
-
Do I need to delete the line in the exisitng driver to now eliminate this as a Preference
2: [input: [name: "configParam2", type: "enum", title: "Lux Threshold Settings", description: "", defaultValue: 50, options:[0:"Always don't turn on light",255:"Turn Light on by PIR",30:"Turn light on @ 30 Lux",40:"Turn light on @ 40 lux",50:"Turn light on @ 50 lux", 60:"Turn light on @ 60 lux",70:"Turn light on @ 70 lux",80:"Turn light on @ 80 lux", 90:"Turn light on @ 90 lux", 100:"Turn light on @ 100 lux", 110:"Turn light on @ 110 lux", 120:"Turn light on @ 120 lux", 130:"Turn light on @ 130 lux", 140:"Turn light on @ 140 lux", 150:"Turn light on @ 150 lux", 160:"Turn light on @ 160 lux", 170:"Turn light on @ 170 lux", 180:"Turn light on @ 180 lux", 190:"Turn light on @ 190 lux", 200:"Turn light on @ 200 lux"]], parameterSize: 2],
Any help would be Greatly appreciated!!!
Full existing driver for reference:
/*
* HomeSeer HS-FLS100+ Floodlight Sensor
* version: 1.4
*/
import groovy.transform.Field
metadata {
definition (name: "HomeSeer HS-FLS100+ Floodlight Sensor", namespace: "djdizzyd", author: "Bryan Copeland", importUrl: "https://raw.githubusercontent.com/djdizzyd/hubitat/master/Drivers/HomeSeer/HS-FLS100-Floodlight-Sensor.groovy") {
capability "Switch"
capability "Refresh"
capability "Actuator"
capability "Sensor"
capability "Configuration"
capability "MotionSensor"
capability "IlluminanceMeasurement"
fingerprint mfr:"000C", prod:"0201", deviceId:"000B", inClusters:"0x5E,0x85,0x59,0x55,0x86,0x72,0x5A,0x73,0x9F,0x6C,0x7A,0x71,0x25,0x31,0x70,0x30", deviceJoinName: "HomeSeer HS-FLS100+"
}
preferences {
configParams.each { input it.value.input }
input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
input name: "txtEnable", type: "bool", title: "TXT Descriptive logging", defaultValue: false
}
}
@Field static Map configParams = [
1: [input: [name: "configParam1", type: "number", title: "PIR Trigger Off period", description: "seconds 8-720", defaultValue: 15, range:"8..720"], parameterSize: 2],
2: [input: [name: "configParam2", type: "enum", title: "Lux Threshold Settings", description: "", defaultValue: 50, options:[0:"Always don't turn on light",255:"Turn Light on by PIR",30:"Turn light on @ 30 Lux",40:"Turn light on @ 40 lux",50:"Turn light on @ 50 lux", 60:"Turn light on @ 60 lux",70:"Turn light on @ 70 lux",80:"Turn light on @ 80 lux", 90:"Turn light on @ 90 lux", 100:"Turn light on @ 100 lux", 110:"Turn light on @ 110 lux", 120:"Turn light on @ 120 lux", 130:"Turn light on @ 130 lux", 140:"Turn light on @ 140 lux", 150:"Turn light on @ 150 lux", 160:"Turn light on @ 160 lux", 170:"Turn light on @ 170 lux", 180:"Turn light on @ 180 lux", 190:"Turn light on @ 190 lux", 200:"Turn light on @ 200 lux"]], parameterSize: 2],
3: [input: [name: "configParam3", type: "number", title: "Lux level report", description: "minutes 0 to 1440 minutes", defaultValue: 10, range:"0..1440"], parameterSize: 2]
]
@Field static Map ZWAVE_NOTIFICATION_TYPES=[0:"Reserverd", 1:"Smoke", 2:"CO", 3:"CO2", 4:"Heat", 5:"Water", 6:"Access Control", 7:"Home Security", 8:"Power Management", 9:"System", 10:"Emergency", 11:"Clock", 12:"First"]
@Field static Map CMD_CLASS_VERS=[0x20:1,0x86:2,0x72:2,0x5B:3,0x70:1,0x85:2,0x59:1,0x31:5,0x71:4]
void logsOff(){
log.warn "debug logging disabled..."
device.updateSetting("logEnable",[value:"false",type:"bool"])
}
void configure() {
if (!state.initialized) initializeVars()
runIn(5,pollDeviceData)
}
void initializeVars() {
// first run only
state.initialized=true
runIn(5, refresh)
}
void updated() {
log.info "updated..."
log.warn "debug logging is: ${logEnable == true}"
unschedule()
if (logEnable) runIn(1800,logsOff)
List<hubitat.zwave.Command> cmds=[]
cmds.addAll(runConfigs())
sendToDevice(cmds)
}
List<hubitat.zwave.Command> runConfigs() {
List<hubitat.zwave.Command> cmds=[]
configParams.each { param, data ->
if (settings[data.input.name]) {
cmds.addAll(configCmd(param, data.parameterSize, settings[data.input.name]))
}
}
return cmds
}
List<hubitat.zwave.Command> pollConfigs() {
List<hubitat.zwave.Command> cmds=[]
configParams.each { param, data ->
if (settings[data.input.name]) {
cmds.add(zwave.configurationV1.configurationGet(parameterNumber: param.toInteger()))
}
}
return cmds
}
List<hubitat.zwave.Command> configCmd(parameterNumber, size, scaledConfigurationValue) {
List<hubitat.zwave.Command> cmds = []
cmds.add(zwave.configurationV1.configurationSet(parameterNumber: parameterNumber.toInteger(), size: size.toInteger(), scaledConfigurationValue: scaledConfigurationValue.toInteger()))
cmds.add(zwave.configurationV1.configurationGet(parameterNumber: parameterNumber.toInteger()))
return cmds
}
void zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
if(configParams[cmd.parameterNumber.toInteger()]) {
Map configParam=configParams[cmd.parameterNumber.toInteger()]
int scaledValue
cmd.configurationValue.reverse().eachWithIndex { v, index -> scaledValue=scaledValue | v << (8*index) }
device.updateSetting(configParam.input.name, [value: "${scaledValue}", type: configParam.input.type])
}
}
void pollDeviceData() {
List<hubitat.zwave.Command> cmds = []
cmds.add(zwave.versionV2.versionGet())
cmds.add(zwave.manufacturerSpecificV2.deviceSpecificGet(deviceIdType: 1))
cmds.addAll(processAssociations())
cmds.addAll(pollConfigs())
cmds.add(zwave.sensorMultilevelV5.sensorMultilevelGet(scale: 1, sensorType: 3))
cmds.add(zwave.notificationV4.notificationGet(notificationType: 7, event:0))
cmds.add(zwave.switchBinaryV1.switchBinaryGet())
sendToDevice(cmds)
}
void refresh() {
List<hubitat.zwave.Command> cmds=[]
cmds.add(zwave.switchBinaryV1.switchBinaryGet())
cmds.add(zwave.sensorMultilevelV5.sensorMultilevelGet(scale: 1, sensorType: 3))
cmds.add(zwave.notificationV4.notificationGet(notificationType: 7, event:0))
sendToDevice(cmds)
}
void installed() {
if (logEnable) log.debug "installed()..."
initializeVars()
}
void eventProcess(Map evt) {
if (device.currentValue(evt.name).toString() != evt.value.toString() || !eventFilter) {
evt.isStateChange=true
sendEvent(evt)
}
}
void zwaveEvent(hubitat.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
if (logEnable) log.debug "${cmd}"
Map evt = [isStateChange:false]
switch (cmd.sensorType) {
case 3:
evt.name = "illuminance"
evt.value = cmd.scaledSensorValue.toInteger()
evt.unit = "lux"
evt.isStateChange=true
evt.descriptionText="${device.displayName}: Illuminance report received: ${evt.value}"
break
}
if (evt.isStateChange) {
if (txtEnable) log.info evt.descriptionText
eventProcess(evt)
}
}
void zwaveEvent(hubitat.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd) {
if (logEnable) log.debug "Sensor binary report: ${cmd}"
// redundant and un-needed function
}
void zwaveEvent(hubitat.zwave.commands.notificationv4.NotificationReport cmd) {
Map evt = [isStateChange:false]
if (logEnable) log.info "Notification: " + ZWAVE_NOTIFICATION_TYPES[cmd.notificationType.toInteger()]
if (cmd.notificationType==7) {
// home security
switch (cmd.event) {
case 0:
// state idle
if (cmd.eventParametersLength > 0) {
switch (cmd.eventParameter[0]) {
case 7:
evt.name = "motion"
evt.value = "inactive"
evt.isStateChange = true
evt.descriptionText = "${device.displayName} motion became ${evt.value}"
break
case 8:
evt.name = "motion"
evt.value = "inactive"
evt.isStateChange = true
evt.descriptionText = "${device.displayName} motion became ${evt.value}"
break
}
} else {
evt.name = "motion"
evt.value = "inactive"
evt.descriptionText = "${device.displayName} motion became ${evt.value}"
evt.isStateChange = true
}
break
case 7:
// motion detected (location provided)
evt.name = "motion"
evt.value = "active"
evt.isStateChange = true
evt.descriptionText = "${device.displayName} motion became ${evt.value}"
break
case 8:
// motion detected
evt.name = "motion"
evt.value = "active"
evt.isStateChange = true
evt.descriptionText = "${device.displayName} motion became ${evt.value}"
break
case 254:
// unknown event/state
log.warn "Device sent unknown event / state notification"
break
}
}
if (evt.isStateChange) {
if (txtEnable) log.info evt.descriptionText
eventProcess(evt)
}
}
void zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd) {
if (logEnable) log.debug cmd
switchEvents(cmd)
}
private void switchEvents(hubitat.zwave.Command cmd) {
String value = (cmd.value ? "on" : "off")
String description = "${device.displayName} was turned ${value}"
if (txtEnable) log.info description
eventProcess(name: "switch", value: value, descriptionText: description, type: state.isDigital?"digital":"physical")
state.isDigital=false
}
void zwaveEvent(hubitat.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
if (logEnable) log.debug cmd
switchEvents(cmd)
}
void on() {
state.isDigital=true
sendToDevice(zwave.basicV1.basicSet(value: 0xFF))
}
void off() {
state.isDigital=true
sendToDevice(zwave.basicV1.basicSet(value: 0x00))
}
void zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
hubitat.zwave.Command encapsulatedCommand = cmd.encapsulatedCommand(CMD_CLASS_VERS)
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
}
void parse(String description) {
if (logEnable) log.debug "parse:${description}"
hubitat.zwave.Command cmd = zwave.parse(description, CMD_CLASS_VERS)
if (cmd) {
zwaveEvent(cmd)
}
}
void zwaveEvent(hubitat.zwave.commands.supervisionv1.SupervisionGet cmd) {
if (logEnable) log.debug "Supervision get: ${cmd}"
hubitat.zwave.Command encapsulatedCommand = cmd.encapsulatedCommand(CMD_CLASS_VERS)
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
sendToDevice(new hubitat.zwave.commands.supervisionv1.SupervisionReport(sessionID: cmd.sessionID, reserved: 0, moreStatusUpdates: false, status: 0xFF, duration: 0))
}
void zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
if (logEnable) log.debug "Device Specific Report: ${cmd}"
switch (cmd.deviceIdType) {
case 1:
// serial number
def serialNumber=""
if (cmd.deviceIdDataFormat==1) {
cmd.deviceIdData.each { serialNumber += hubitat.helper.HexUtils.integerToHexString(it & 0xff,1).padLeft(2, '0')}
} else {
cmd.deviceIdData.each { serialNumber += (char) it }
}
device.updateDataValue("serialNumber", serialNumber)
break
}
}
void zwaveEvent(hubitat.zwave.commands.versionv2.VersionReport cmd) {
if (logEnable) log.debug "version2 report: ${cmd}"
device.updateDataValue("firmwareVersion", "${cmd.firmware0Version}.${cmd.firmware0SubVersion}")
device.updateDataValue("protocolVersion", "${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}")
device.updateDataValue("hardwareVersion", "${cmd.hardwareVersion}")
}
void sendToDevice(List<hubitat.zwave.Command> cmds) {
sendHubCommand(new hubitat.device.HubMultiAction(commands(cmds), hubitat.device.Protocol.ZWAVE))
}
void sendToDevice(hubitat.zwave.Command cmd) {
sendHubCommand(new hubitat.device.HubAction(secureCommand(cmd), hubitat.device.Protocol.ZWAVE))
}
void sendToDevice(String cmd) {
sendHubCommand(new hubitat.device.HubAction(secureCommand(cmd), hubitat.device.Protocol.ZWAVE))
}
List<String> commands(List<hubitat.zwave.Command> cmds, Long delay=300) {
return delayBetween(cmds.collect{ secureCommand(it) }, delay)
}
String secureCommand(hubitat.zwave.Command cmd) {
secureCommand(cmd.format())
}
String secureCommand(String cmd) {
String encap=""
if (getDataValue("zwaveSecurePairingComplete") != "true") {
return cmd
} else {
encap = "988100"
}
return "${encap}${cmd}"
}
void zwaveEvent(hubitat.zwave.Command cmd) {
if (logEnable) log.debug "skip:${cmd}"
}
List<hubitat.zwave.Command> setDefaultAssociation() {
List<hubitat.zwave.Command> cmds=[]
cmds.add(zwave.associationV2.associationSet(groupingIdentifier: 1, nodeId: zwaveHubNodeId))
cmds.add(zwave.associationV2.associationGet(groupingIdentifier: 1))
return cmds
}
List<hubitat.zwave.Command> processAssociations(){
List<hubitat.zwave.Command> cmds = []
cmds.addAll(setDefaultAssociation())
if (logEnable) log.debug "processAssociations cmds: ${cmds}"
return cmds
}
void zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
if (logEnable) log.debug "${device.label?device.label:device.name}: ${cmd}"
List<String> temp = []
if (cmd.nodeId != []) {
cmd.nodeId.each {
temp.add(it.toString().format( '%02x', it.toInteger() ).toUpperCase())
}
}
updateDataValue("zwaveAssociationG${cmd.groupingIdentifier}", "$temp")
}
void zwaveEvent(hubitat.zwave.commands.associationv2.AssociationGroupingsReport cmd) {
if (logEnable) log.debug "${device.label?device.label:device.name}: ${cmd}"
log.info "${device.label?device.label:device.name}: Supported association groups: ${cmd.supportedGroupings}"
state.associationGroups = cmd.supportedGroupings
}
For reference here is the device edit screen with the exiting driver: