/* groovylint-disable NglParseError, ImplicitReturnStatement, InsecureRandom, MethodReturnTypeRequired, MethodSize, ParameterName, PublicMethodsBeforeNonPublicMethods, StaticMethodsBeforeInstanceMethods, UnnecessaryGroovyImport, UnnecessaryObjectReferences, UnusedImport, VariableName *//**
* Tuya Zigbee Rain Sensor - driver for Hubitat Elevation
*
* https://community.hubitat.com/t/dynamic-capabilities-commands-and-attributes-for-drivers/98342
*
* 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.
*
* ver. 3.0.0 2024-08-08 kkossev - first test version
* ver. 3.0.1 2024-08-09 kkossev - added capability 'WaterSensor'; rainSensorVoltage scale 1000; illuminance changed to illuminanceVoltage and scale 1000;
* ver. 3.0.2 2024-09-15 kkossev - fixed exception in resetPreferencesToDefaults(); refresh using queryAllTuyaDP(); force 2 minutes health check interval; illuminanceVoltage event bug fix;
*
* TODO: HPM
*/
static String version() { "3.0.2" }
static String timeStamp() {"2024/09/15 10:22 AM"}
@Field static final Boolean _DEBUG = false
@Field static final Boolean _TRACE_ALL = false // trace all messages, including the spammy ones
@Field static final Boolean DEFAULT_DEBUG_LOGGING = false // disable it for production
import groovy.transform.Field
import groovy.transform.CompileStatic
deviceType = "RainSensor"
@Field static final String DEVICE_TYPE = "RainSensor"
metadata {
definition (
name: 'Tuya Zigbee Rain Sensor',
importUrl: 'https://raw.githubusercontent.com/kkossev/Hubitat/development/Drivers/Tuya%20Zigbee%20Rain%20Sensor/Tuya_Zigbee_Rain_Sensor_lib_included.groovy',
namespace: 'kkossev', author: 'Krassimir Kossev', singleThreaded: true )
{
capability "WaterSensor"
attribute 'dropletDetectionState', 'enum', ['off', 'on']
attribute 'battery', 'number'
attribute 'illuminanceVoltage', 'number'
attribute 'averageLightIntensity20mins', 'number'
attribute 'todaysMaxLightIntensity', 'number'
attribute 'cleaningReminder', 'enum', ['off', 'on']
attribute 'rainSensorVoltage', 'number'
// no commands
// itterate through all the figerprints and add them on the fly
deviceProfilesV3.each { profileName, profileMap ->
if (profileMap.fingerprints != null) {
if (profileMap.device?.isDepricated != true) {
profileMap.fingerprints.each {
fingerprint it
}
}
}
}
}
preferences {
if (device) {
// input(name: 'info', type: 'hidden', title: "For more info, click on this link to visit the WiKi page")
}
input name: 'txtEnable', type: 'bool', title: 'Enable descriptionText logging', defaultValue: true, description: 'Enables events logging.'
input name: 'logEnable', type: 'bool', title: 'Enable debug logging', defaultValue: DEFAULT_DEBUG_LOGGING, description: 'Turns on debug logging for 24 hours.'
// the rest of the preferences are inputIt from the deviceProfileLib and from the included libraries
}
}
@Field static String ttStyleStr = ''
@Field static final Map deviceProfilesV3 = [
// https://www.aliexpress.us/item/3256807083309300.html
// https://www.aliexpress.com/item/1005007269233710.html
// https://community.hubitat.com/t/new-tuya-zigbee-light-and-rain-sensor/141057/6?u=kkossev
// https://github.com/Koenkk/zigbee2mqtt/issues/23532
'TUYA_RAIN_SENSOR' : [
description : 'Tuya Zigbee Rain Sensor',
models : ['TS0601'],
device : [type: 'Sensor', isIAS:true, powerSource: 'battery', isSleepy:true], // check powerSource
capabilities : ['Battery': true],
preferences : [:],
commands : ['resetStats':'resetStats', 'refresh':'refresh', 'initialize':'initialize', 'updateAllPreferences': 'updateAllPreferences', 'resetPreferencesToDefaults':'resetPreferencesToDefaults', 'validateAndFixPreferences':'validateAndFixPreferences', 'printFingerprints':'printFingerprints', 'printPreferences':'printPreferences'],
fingerprints : [
[profileId:"0104", endpointId:"01", inClusters:"0000,0004,0005,0001,0500,EF00", outClusters:"0003,0004,0006,1000,000A,0019", model:"TS0207", manufacturer:"_TZ3210_tgvtvdoc", controllerType: "ZGB", deviceJoinName: 'Tuya Zigbee Rain Sensor'],
],
tuyaDPs: [
[dp:1, name:'dropletDetectionState', type:'enum', rw: 'ro', defVal:'0', map:[0:'off', 1:'on'], description:'Droplet Detection State'],
[dp:4, name:'battery', type:'number', rw: 'ro', unit:'%', description:'Battery level'],
[dp:101, name:'illuminanceVoltage', type:'decimal', rw: 'ro', unit:'V', scale:1000, description:'Illuminance voltage'],
[dp:102, name:'averageLightIntensity20mins', type:'decimal', rw: 'ro', unit:'V', scale:1000, description:'20 mins average light intensity'],
[dp:103, name:'todaysMaxLightIntensity', type:'decimal', rw: 'ro', unit:'V', scale:1000, description:'Todays max light intensity'],
[dp:104, name:'cleaningReminder', type:'enum', rw: 'ro', defVal:'0', map:[0:'off', 1:'on'], description:'Cleaning reminder'],
[dp:105, name:'rainSensorVoltage', type:'decimal', rw: 'ro', unit:'V', scale:1000, description:'Rain Sensor Voltage'],
],
refresh: ['queryAllTuyaDP'],
configuration : ['battery': false],
deviceJoinName: 'Tuya Zigbee Rain Sensor'
]
]
// called from standardProcessTuyaDP in the commonLib for each Tuya dp report in a Zigbee message
// should always return true, as we are processing all the dp reports here
boolean customProcessTuyaDp(final Map descMap, final int dp, final int dp_id, final int fncmd, final int dp_len=0) {
logDebug "customProcessTuyaDp: dp=${dp} dp_id=${dp_id} fncmd=${fncmd} dp_len=${dp_len} descMap.data = ${descMap?.data}"
if (processTuyaDPfromDeviceProfile(descMap, dp, dp_id, fncmd, dp_len) == true) {
return true // sucessfuly processed from the deviceProfile
}
logWarn "NOT PROCESSED from deviceProfile Tuya cmd: dp=${dp} value=${fncmd} descMap.data = ${descMap?.data}"
localProcessTuyaDP(descMap, dp, dp_id, fncmd, dp_len)
return true
}
void localProcessTuyaDP(final Map descMap, final int dp, final int dp_id, final int fncmd, final int dp_len) {
switch (dp) {
default :
logDebug "NOT PROCESSED Tuya cmd: dp=${dp} value=${fncmd} descMap.data = ${descMap?.data}"
break
}
}
// called from processFoundItem in the deviceProfileLib
void customProcessDeviceProfileEvent(final Map descMap, final String name, valueScaled, final String unitText, final String descText) {
logTrace "customProcessDeviceProfileEvent(${name}, ${valueScaled}) called"
Map eventMap = [name: name, value: valueScaled, unit: unitText, descriptionText: descText, type: 'physical', isStateChange: true]
switch (name) {
default :
sendEvent(name : name, value : valueScaled, unit:unitText, descriptionText: descText, type: 'physical', isStateChange: true) // attribute value is changed - send an event !
logTrace "event ${name} sent w/ value ${valueScaled}"
logInfo "${descText}" // TODO - send info log only if the value has changed? // TODO - check whether Info log will be sent also for spammy clusterAttribute ?
break
}
}
public void customParseIasMessage(final String description) {
Map zs = zigbee.parseZoneStatusChange(description)
if (zs == null) {
logWarn "customParseIasMessage: zs is null!"
return
}
if (zs.alarm1Set == true) {
logDebug "customParseIasMessage: Alarm 1 is set"
sendWaterEvent('wet')
}
else {
logDebug "customParseIasMessage: Alarm 1 is cleared"
sendWaterEvent('dry')
}
}
void sendWaterEvent( String value, boolean isDigital=false) {
def type = isDigital == true ? "digital" : "physical"
String descriptionText
switch (value) {
case 'checking' :
descriptionText = "${device.displayName} checking"
break
case 'tested' :
descriptionText = "${device.displayName} is tested"
break
case 'wet' :
// send 'wet' without delays and additional checks
descriptionText = "${device.displayName} is wet"
break
case 'dry' :
descriptionText = "${device.displayName} is dry"
break
case 'unknown' :
// 'unknown' is sent when the water leak sensor healthStatus goes in offline state
descriptionText = "${device.displayName} status is unknown"
break
default :
log.warn "sendWaterEvent: unprocessed water event '${value}'"
return
}
if (isDigital == true) descriptionText += " [digital]"
if (settings?.txtEnable==true) log.info "$descriptionText" // includes deviceName
sendEvent(name: "water", value: value, descriptionText: descriptionText, type: type , isStateChange: true)
}
List customRefresh() {
logDebug "customRefresh()"
List cmds = []
List devProfCmds = refreshFromDeviceProfileList()
if (devProfCmds != null && !devProfCmds.isEmpty()) {
cmds += devProfCmds
}
return cmds
}
void customUpdated() {
logDebug "customUpdated()"
List cmds = []
if (settings?.forcedProfile != null) {
if (this.respondsTo('getProfileKey') == false) {
logWarn "getProfileKey() is not defined in the driver"
}
else {
logDebug "current state.deviceProfile=${state.deviceProfile}, settings.forcedProfile=${settings?.forcedProfile}, getProfileKey()=${getProfileKey(settings?.forcedProfile)}"
if (getProfileKey(settings?.forcedProfile) != state.deviceProfile) {
logInfo "changing the device profile from ${state.deviceProfile} to ${getProfileKey(settings?.forcedProfile)}"
state.deviceProfile = getProfileKey(settings?.forcedProfile)
initializeVars(fullInit = false)
resetPreferencesToDefaults(debug = true)
logInfo 'press F5 to refresh the page'
}
}
}
/* groovylint-disable-next-line EmptyElseBlock */
else {
logDebug "forcedProfile is not set"
}
// Itterates through all settings
updateAllPreferences() // defined in deviceProfileLib - calls setPar; returns void!
if (cmds != null && !cmds.isEmpty()) {
sendZigbeeCommands(cmds)
}
}
void customInitializeVars(final boolean fullInit=false) {
logDebug "customInitializeVars(${fullInit})"
if (state.deviceProfile == null || state.deviceProfile == '' || state.deviceProfile == 'UNKNOWN') {
setDeviceNameAndProfile('TS0207', '_TZ3210_tgvtvdoc') // in deviceProfileiLib.groovy
initEventsDeviceProfile() // fix the powerSource
}
if (fullInit == true) {
device.updateSetting('healthCheckInterval', [value: '2', type: 'enum']) // force 2 minutes health check interval
resetPreferencesToDefaults()
}
}
void customInitEvents(final boolean fullInit=false) {
logDebug "customInitEvents()"
if ((device.currentState('dropletDetectionState')?.value == null)) { sendEvent(name: 'dropletDetectionState', value: 'off', type:'digital') }
if ((device.currentState('battery')?.value == null)) { sendEvent(name: 'battery', value: 0, unit:'%', type:'digital') }
if ((device.currentState('illuminanceVoltage')?.value == null)) { sendEvent(name: 'illuminanceVoltage', value: 0.0, unit:'V', type:'digital') }
if ((device.currentState('averageLightIntensity20mins')?.value == null)) { sendEvent(name: 'averageLightIntensity20mins', value: 0.0, unit:'V', type:'digital') }
if ((device.currentState('todaysMaxLightIntensity')?.value == null)) { sendEvent(name: 'todaysMaxLightIntensity', value: 0.0, unit:'V', type:'digital') }
if ((device.currentState('cleaningReminder')?.value == null)) { sendEvent(name: 'cleaningReminder', value: 'off', type:'digital') }
if ((device.currentState('rainSensorVoltage')?.value == null)) { sendEvent(name: 'rainSensorVoltage', value: 0.0, unit:'V', type:'digital') }
if ((device.currentState('water')?.value == null)) { sendEvent(name: 'water', value: 'unknown', unit:'', type:'digital') }
}
void test(String par) {
long startTime = now()
logDebug "test() started at ${startTime}"
//parse('catchall: 0104 EF00 01 01 0040 00 7770 01 00 0000 02 01 00556701000100')
def parpar = 'catchall: 0104 EF00 01 01 0040 00 7770 01 00 0000 02 01 00556701000100'
for (int i=0; i<100; i++) {
testFunc(parpar)
}
long endTime = now()
logDebug "test() ended at ${endTime} (duration ${endTime - startTime}ms)"
}
// /////////////////////////////////////////////////////////////////// Libraries //////////////////////////////////////////////////////////////////////
// ~~~~~ start include (142) kkossev.deviceProfileLib ~~~~~
/* groovylint-disable CompileStatic, CouldBeSwitchStatement, DuplicateListLiteral, DuplicateNumberLiteral, DuplicateStringLiteral, ImplicitClosureParameter, ImplicitReturnStatement, Instanceof, LineLength, MethodCount, MethodSize, NestedBlockDepth, NoDouble, NoFloat, NoWildcardImports, ParameterName, PublicMethodsBeforeNonPublicMethods, UnnecessaryElseStatement, UnnecessaryGetter, UnnecessaryPublicModifier, UnnecessarySetter, UnusedImport */ // library marker kkossev.deviceProfileLib, line 1
library( // library marker kkossev.deviceProfileLib, line 2
base: 'driver', author: 'Krassimir Kossev', category: 'zigbee', description: 'Device Profile Library', name: 'deviceProfileLib', namespace: 'kkossev', // library marker kkossev.deviceProfileLib, line 3
importUrl: 'https://raw.githubusercontent.com/kkossev/hubitat/development/libraries/deviceProfileLib.groovy', documentationLink: '', // library marker kkossev.deviceProfileLib, line 4
version: '3.3.4' // library marker kkossev.deviceProfileLib, line 5
) // library marker kkossev.deviceProfileLib, line 6
/* // library marker kkossev.deviceProfileLib, line 7
* Device Profile Library // library marker kkossev.deviceProfileLib, line 8
* // library marker kkossev.deviceProfileLib, line 9
* Licensed Virtual the Apache License, Version 2.0 (the "License"); you may not use this file except // library marker kkossev.deviceProfileLib, line 10
* in compliance with the License. You may obtain a copy of the License at: // library marker kkossev.deviceProfileLib, line 11
* // library marker kkossev.deviceProfileLib, line 12
* http://www.apache.org/licenses/LICENSE-2.0 // library marker kkossev.deviceProfileLib, line 13
* // library marker kkossev.deviceProfileLib, line 14
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed // library marker kkossev.deviceProfileLib, line 15
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License // library marker kkossev.deviceProfileLib, line 16
* for the specific language governing permissions and limitations under the License. // library marker kkossev.deviceProfileLib, line 17
* // library marker kkossev.deviceProfileLib, line 18
* ver. 1.0.0 2023-11-04 kkossev - added deviceProfileLib (based on Tuya 4 In 1 driver) // library marker kkossev.deviceProfileLib, line 19
* ver. 3.0.0 2023-11-27 kkossev - fixes for use with commonLib; added processClusterAttributeFromDeviceProfile() method; added validateAndFixPreferences() method; inputIt bug fix; signedInt Preproc method; // library marker kkossev.deviceProfileLib, line 20
* ver. 3.0.1 2023-12-02 kkossev - release candidate // library marker kkossev.deviceProfileLib, line 21
* ver. 3.0.2 2023-12-17 kkossev - inputIt moved to the preferences section; setfunction replaced by customSetFunction; Groovy Linting; // library marker kkossev.deviceProfileLib, line 22
* ver. 3.0.4 2024-03-30 kkossev - more Groovy Linting; processClusterAttributeFromDeviceProfile exception fix; // library marker kkossev.deviceProfileLib, line 23
* ver. 3.1.0 2024-04-03 kkossev - more Groovy Linting; deviceProfilesV3, enum pars bug fix; // library marker kkossev.deviceProfileLib, line 24
* ver. 3.1.1 2024-04-21 kkossev - deviceProfilesV3 bug fix; tuyaDPs list of maps bug fix; resetPreferencesToDefaults bug fix; // library marker kkossev.deviceProfileLib, line 25
* ver. 3.1.2 2024-05-05 kkossev - added isSpammyDeviceProfile() // library marker kkossev.deviceProfileLib, line 26
* ver. 3.1.3 2024-05-21 kkossev - skip processClusterAttributeFromDeviceProfile if cluster or attribute or value is missing // library marker kkossev.deviceProfileLib, line 27
* ver. 3.2.0 2024-05-25 kkossev - commonLib 3.2.0 allignment; // library marker kkossev.deviceProfileLib, line 28
* ver. 3.2.1 2024-06-06 kkossev - Tuya Multi Sensor 4 In 1 (V3) driver allignment (customProcessDeviceProfileEvent); getDeviceProfilesMap bug fix; forcedProfile is always shown in preferences; // library marker kkossev.deviceProfileLib, line 29
* ver. 3.3.0 2024-06-29 kkossev - empty preferences bug fix; zclWriteAttribute delay 50 ms; added advanced check in inputIt(); fixed 'Cannot get property 'rw' on null object' bug; fixed enum attributes first event numeric value bug; // library marker kkossev.deviceProfileLib, line 30
* ver. 3.3.1 2024-07-06 kkossev - added powerSource event in the initEventsDeviceProfile // library marker kkossev.deviceProfileLib, line 31
* ver. 3.3.2 2024-08-18 kkossev - release 3.3.2 // library marker kkossev.deviceProfileLib, line 32
* ver. 3.3.3 2024-08-18 kkossev - sendCommand and setPar commands commented out; must be declared in the main driver where really needed // library marker kkossev.deviceProfileLib, line 33
* ver. 3.3.4 2024-09-14 kkossev - (dev.branch) fixed exceptions in resetPreferencesToDefaults() and initEventsDeviceProfile() // library marker kkossev.deviceProfileLib, line 34
* // library marker kkossev.deviceProfileLib, line 35
* TODO - remove the 2-in-1 patch ! // library marker kkossev.deviceProfileLib, line 36
* TODO - add defaults for profileId:'0104', endpointId:'01', inClusters, outClusters, in the deviceProfilesV3 map // library marker kkossev.deviceProfileLib, line 37
* TODO - add updateStateUnknownDPs (from the 4-in-1 driver) // library marker kkossev.deviceProfileLib, line 38
* TODO - when [refresh], send Info logs for parameters that are not events or preferences // library marker kkossev.deviceProfileLib, line 39
* TODO: refactor sendAttribute ! sendAttribute exception bug fix for virtual devices; check if String getObjectClassName(Object o) is in 2.3.3.137, can be used? // library marker kkossev.deviceProfileLib, line 40
* TODO: add _DEBUG command (for temporary switching the debug logs on/off) // library marker kkossev.deviceProfileLib, line 41
* TODO: allow NULL parameters default values in the device profiles // library marker kkossev.deviceProfileLib, line 42
* TODO: handle preferences of a type TEXT // library marker kkossev.deviceProfileLib, line 43
* // library marker kkossev.deviceProfileLib, line 44
*/ // library marker kkossev.deviceProfileLib, line 45
static String deviceProfileLibVersion() { '3.3.4' } // library marker kkossev.deviceProfileLib, line 47
static String deviceProfileLibStamp() { '2024/09/15 10:22 AM' } // library marker kkossev.deviceProfileLib, line 48
import groovy.json.* // library marker kkossev.deviceProfileLib, line 49
import groovy.transform.Field // library marker kkossev.deviceProfileLib, line 50
import hubitat.zigbee.clusters.iaszone.ZoneStatus // library marker kkossev.deviceProfileLib, line 51
import hubitat.zigbee.zcl.DataType // library marker kkossev.deviceProfileLib, line 52
import java.util.concurrent.ConcurrentHashMap // library marker kkossev.deviceProfileLib, line 53
import groovy.transform.CompileStatic // library marker kkossev.deviceProfileLib, line 55
metadata { // library marker kkossev.deviceProfileLib, line 57
// no capabilities // library marker kkossev.deviceProfileLib, line 58
// no attributes // library marker kkossev.deviceProfileLib, line 59
/* // library marker kkossev.deviceProfileLib, line 60
// copy the following commands to the main driver, if needed // library marker kkossev.deviceProfileLib, line 61
command 'sendCommand', [ // library marker kkossev.deviceProfileLib, line 62
[name:'command', type: 'STRING', description: 'command name', constraints: ['STRING']], // library marker kkossev.deviceProfileLib, line 63
[name:'val', type: 'STRING', description: 'command parameter value', constraints: ['STRING']] // library marker kkossev.deviceProfileLib, line 64
] // library marker kkossev.deviceProfileLib, line 65
command 'setPar', [ // library marker kkossev.deviceProfileLib, line 66
[name:'par', type: 'STRING', description: 'preference parameter name', constraints: ['STRING']], // library marker kkossev.deviceProfileLib, line 67
[name:'val', type: 'STRING', description: 'preference parameter value', constraints: ['STRING']] // library marker kkossev.deviceProfileLib, line 68
] // library marker kkossev.deviceProfileLib, line 69
*/ // library marker kkossev.deviceProfileLib, line 70
preferences { // library marker kkossev.deviceProfileLib, line 71
if (device) { // library marker kkossev.deviceProfileLib, line 72
// itterate over DEVICE.preferences map and inputIt all // library marker kkossev.deviceProfileLib, line 73
if (DEVICE != null && DEVICE?.preferences != null && DEVICE?.preferences != [:] && DEVICE?.device?.isDepricated != true) { // library marker kkossev.deviceProfileLib, line 74
(DEVICE?.preferences).each { key, value -> // library marker kkossev.deviceProfileLib, line 75
Map inputMap = inputIt(key) // library marker kkossev.deviceProfileLib, line 76
if (inputMap != null && inputMap != [:]) { // library marker kkossev.deviceProfileLib, line 77
input inputMap // library marker kkossev.deviceProfileLib, line 78
} // library marker kkossev.deviceProfileLib, line 79
} // library marker kkossev.deviceProfileLib, line 80
} // library marker kkossev.deviceProfileLib, line 81
//if (advancedOptions == true) { // library marker kkossev.deviceProfileLib, line 82
input(name: 'forcedProfile', type: 'enum', title: 'Device Profile', description: 'Manually change the Device Profile, if the model/manufacturer was not recognized automatically.
Warning! Manually setting a device profile may not always work!', options: getDeviceProfilesMap()) // library marker kkossev.deviceProfileLib, line 83
//} // library marker kkossev.deviceProfileLib, line 84
} // library marker kkossev.deviceProfileLib, line 85
} // library marker kkossev.deviceProfileLib, line 86
} // library marker kkossev.deviceProfileLib, line 87
private boolean is2in1() { return getDeviceProfile().contains('TS0601_2IN1') } // patch removed 05/29/2024 // library marker kkossev.deviceProfileLib, line 89
public String getDeviceProfile() { state?.deviceProfile ?: 'UNKNOWN' } // library marker kkossev.deviceProfileLib, line 91
public Map getDEVICE() { deviceProfilesV3 != null ? deviceProfilesV3[getDeviceProfile()] : deviceProfilesV2 != null ? deviceProfilesV2[getDeviceProfile()] : [:] } // library marker kkossev.deviceProfileLib, line 92
public Set getDeviceProfiles() { deviceProfilesV3 != null ? deviceProfilesV3?.keySet() : deviceProfilesV2 != null ? deviceProfilesV2?.keySet() : [] } // library marker kkossev.deviceProfileLib, line 93
//List getDeviceProfilesMap() { deviceProfilesV3 != null ? deviceProfilesV3.values().description as List : deviceProfilesV2.values().description as List } // library marker kkossev.deviceProfileLib, line 94
public List getDeviceProfilesMap() { // library marker kkossev.deviceProfileLib, line 96
if (deviceProfilesV3 == null) { // library marker kkossev.deviceProfileLib, line 97
if (deviceProfilesV2 == null) { return [] } // library marker kkossev.deviceProfileLib, line 98
return deviceProfilesV2.values().description as List // library marker kkossev.deviceProfileLib, line 99
} // library marker kkossev.deviceProfileLib, line 100
List activeProfiles = [] // library marker kkossev.deviceProfileLib, line 101
deviceProfilesV3.each { profileName, profileMap -> // library marker kkossev.deviceProfileLib, line 102
if ((profileMap.device?.isDepricated ?: false) != true) { // library marker kkossev.deviceProfileLib, line 103
activeProfiles.add(profileMap.description ?: '---') // library marker kkossev.deviceProfileLib, line 104
} // library marker kkossev.deviceProfileLib, line 105
} // library marker kkossev.deviceProfileLib, line 106
return activeProfiles // library marker kkossev.deviceProfileLib, line 107
} // library marker kkossev.deviceProfileLib, line 108
// ---------------------------------- deviceProfilesV3 helper functions -------------------------------------------- // library marker kkossev.deviceProfileLib, line 110
/** // library marker kkossev.deviceProfileLib, line 112
* Returns the profile key for a given profile description. // library marker kkossev.deviceProfileLib, line 113
* @param valueStr The profile description to search for. // library marker kkossev.deviceProfileLib, line 114
* @return The profile key if found, otherwise null. // library marker kkossev.deviceProfileLib, line 115
*/ // library marker kkossev.deviceProfileLib, line 116
String getProfileKey(final String valueStr) { // library marker kkossev.deviceProfileLib, line 117
if (deviceProfilesV3 != null) { return deviceProfilesV3.find { _, profileMap -> profileMap.description == valueStr }?.key } // library marker kkossev.deviceProfileLib, line 118
else if (deviceProfilesV2 != null) { return deviceProfilesV2.find { _, profileMap -> profileMap.description == valueStr }?.key } // library marker kkossev.deviceProfileLib, line 119
else { return null } // library marker kkossev.deviceProfileLib, line 120
} // library marker kkossev.deviceProfileLib, line 121
/** // library marker kkossev.deviceProfileLib, line 123
* Finds the preferences map for the given parameter. // library marker kkossev.deviceProfileLib, line 124
* @param param The parameter to find the preferences map for. // library marker kkossev.deviceProfileLib, line 125
* @param debug Whether or not to output debug logs. // library marker kkossev.deviceProfileLib, line 126
* @return returns either tuyaDPs or attributes map, depending on where the preference (param) is found // library marker kkossev.deviceProfileLib, line 127
* @return empty map [:] if param is not defined for this device. // library marker kkossev.deviceProfileLib, line 128
*/ // library marker kkossev.deviceProfileLib, line 129
Map getPreferencesMapByName(final String param, boolean debug=false) { // library marker kkossev.deviceProfileLib, line 130
Map foundMap = [:] // library marker kkossev.deviceProfileLib, line 131
if (!(param in DEVICE?.preferences)) { if (debug) { log.warn "getPreferencesMapByName: preference ${param} not defined for this device!" } ; return [:] } // library marker kkossev.deviceProfileLib, line 132
/* groovylint-disable-next-line NoDef, VariableTypeRequired */ // library marker kkossev.deviceProfileLib, line 133
def preference // library marker kkossev.deviceProfileLib, line 134
try { // library marker kkossev.deviceProfileLib, line 135
preference = DEVICE?.preferences["$param"] // library marker kkossev.deviceProfileLib, line 136
if (debug) { log.debug "getPreferencesMapByName: preference ${param} found. value is ${preference}" } // library marker kkossev.deviceProfileLib, line 137
if (preference in [true, false]) { // library marker kkossev.deviceProfileLib, line 138
// find the preference in the tuyaDPs map // library marker kkossev.deviceProfileLib, line 139
logDebug "getPreferencesMapByName: preference ${param} is boolean" // library marker kkossev.deviceProfileLib, line 140
return [:] // no maps for predefined preferences ! // library marker kkossev.deviceProfileLib, line 141
} // library marker kkossev.deviceProfileLib, line 142
if (safeToInt(preference, -1) > 0) { //if (preference instanceof Number) { // library marker kkossev.deviceProfileLib, line 143
int dp = safeToInt(preference) // library marker kkossev.deviceProfileLib, line 144
//if (debug) log.trace "getPreferencesMapByName: param ${param} preference ${preference} is number (${dp})" // library marker kkossev.deviceProfileLib, line 145
foundMap = DEVICE?.tuyaDPs.find { it.dp == dp } // library marker kkossev.deviceProfileLib, line 146
} // library marker kkossev.deviceProfileLib, line 147
else { // cluster:attribute // library marker kkossev.deviceProfileLib, line 148
//if (debug) { log.trace "${DEVICE?.attributes}" } // library marker kkossev.deviceProfileLib, line 149
foundMap = DEVICE?.attributes.find { it.at == preference } // library marker kkossev.deviceProfileLib, line 150
} // library marker kkossev.deviceProfileLib, line 151
// TODO - could be also 'true' or 'false' ... // library marker kkossev.deviceProfileLib, line 152
} catch (e) { // library marker kkossev.deviceProfileLib, line 153
if (debug) { log.warn "getPreferencesMapByName: exception ${e} caught when getting preference ${param} !" } // library marker kkossev.deviceProfileLib, line 154
return [:] // library marker kkossev.deviceProfileLib, line 155
} // library marker kkossev.deviceProfileLib, line 156
if (debug) { log.debug "getPreferencesMapByName: foundMap = ${foundMap}" } // library marker kkossev.deviceProfileLib, line 157
return foundMap // library marker kkossev.deviceProfileLib, line 158
} // library marker kkossev.deviceProfileLib, line 159
Map getAttributesMap(String attribName, boolean debug=false) { // library marker kkossev.deviceProfileLib, line 161
Map foundMap = [:] // library marker kkossev.deviceProfileLib, line 162
List