/** * Copyright 2020 Markus Liljergren (https://oh-lalabs.com) * * Version: v1.1.1.1123T * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * NOTE: This is an auto-generated file and most comments have been removed! * */ // BEGIN:getDefaultImports() import groovy.json.JsonSlurper import groovy.json.JsonOutput import java.security.MessageDigest // END: getDefaultImports() metadata { definition (name: "Tasmota - Universal Multi Sensor (Child)", namespace: "tasmota", author: "Markus Liljergren", filename: "tasmota-universal-multi-sensor-child", importUrl: "https://raw.githubusercontent.com/markus-li/Hubitat/release/drivers/expanded/tasmota-universal-multi-sensor-child-expanded.groovy") { capability "Sensor" capability "TemperatureMeasurement" capability "RelativeHumidityMeasurement" capability "PressureMeasurement" capability "IlluminanceMeasurement" capability "MotionSensor" capability "WaterSensor" capability "Refresh" // BEGIN:getMinimumChildAttributes() attribute "driver", "string" // END: getMinimumChildAttributes() attribute "dewPoint", "number" attribute "gas", "number" attribute "distance", "string" attribute "pressureWithUnit", "string" command "toggle" } preferences { // BEGIN:getDefaultMetadataPreferences() input(name: "debugLogging", type: "bool", title: styling_getLogo() + styling_addTitleDiv("Enable debug logging"), description: "" , defaultValue: false, submitOnChange: true, displayDuringSetup: false, required: false) input(name: "infoLogging", type: "bool", title: styling_addTitleDiv("Enable info logging"), description: "", defaultValue: true, submitOnChange: true, displayDuringSetup: false, required: false) // END: getDefaultMetadataPreferences() input(name: "hideMeasurementAdjustments", type: "bool", title: styling_addTitleDiv("Hide Measurement Adjustment Preferences"), description: "", defaultValue: false, displayDuringSetup: false, required: false) // BEGIN:getDefaultMetadataPreferencesForTHMonitor() input(name: "tempOffset", type: "decimal", title: styling_addTitleDiv("Temperature Offset"), description: styling_addDescriptionDiv("Adjust the temperature by this many degrees (in Celcius)."), displayDuringSetup: true, required: false, range: "*..*") input(name: "tempRes", type: "enum", title: styling_addTitleDiv("Temperature Resolution"), description: styling_addDescriptionDiv("Temperature sensor resolution (0..3 = maximum number of decimal places, default: 1)
NOTE: If the 3rd decimal is a 0 (eg. 24.720) it will show without the last decimal (eg. 24.72)."), options: ["0", "1", "2", "3"], defaultValue: "1") input(name: "tempUnitConversion", type: "enum", title: styling_addTitleDiv("Temperature Unit Conversion"), description: "", defaultValue: "1", required: true, multiple: false, options:[["1":"none"], ["2":"Celsius to Fahrenheit"], ["3":"Fahrenheit to Celsius"]]) input(name: "humidityOffset", type: "decimal", title: styling_addTitleDiv("Humidity Offset"), description: styling_addDescriptionDiv("Adjust the humidity by this many percent."), displayDuringSetup: true, required: false, range: "*..*") input(name: "humidityRes", type: "enum", title: styling_addTitleDiv("Humidity Resolution"), description: styling_addDescriptionDiv("Humidity sensor resolution (0..1 = maximum number of decimal places, default: 1)"), options: ["0", "1"], defaultValue: "1") input(name: "pressureOffset", type: "decimal", title: styling_addTitleDiv("Pressure Offset"), description: styling_addDescriptionDiv("Adjust the pressure value by this much."), displayDuringSetup: true, required: false, range: "*..*") input(name: "pressureRes", type: "enum", title: styling_addTitleDiv("Pressure Resolution"), description: styling_addDescriptionDiv("Pressure sensor resolution (0..1 = maximum number of decimal places, default: default)"), options: ["default", "0", "1", "2"], defaultValue: "default") input(name: "pressureUnitConversion", type: "enum", title: styling_addTitleDiv("Pressure Unit Conversion"), description: styling_addDescriptionDiv("(default: kPa)"), options: ["mbar", "kPa", "inHg", "mmHg", "atm"], defaultValue: "kPa") // END: getDefaultMetadataPreferencesForTHMonitor() } // BEGIN:getMetadataCustomizationMethods() metaDataExporter() if(isCSSDisabled() == false) { preferences { input(name: "hiddenSetting", description: "" + getDriverCSSWrapper(), title: "None", displayDuringSetup: false, type: "paragraph", element: "paragraph") } } // END: getMetadataCustomizationMethods() } // BEGIN:getDeviceInfoFunction() String getDeviceInfoByName(infoName) { Map deviceInfo = ['name': 'Tasmota - Universal Multi Sensor (Child)', 'namespace': 'tasmota', 'author': 'Markus Liljergren', 'filename': 'tasmota-universal-multi-sensor-child', 'importUrl': 'https://raw.githubusercontent.com/markus-li/Hubitat/release/drivers/expanded/tasmota-universal-multi-sensor-child-expanded.groovy'] return(deviceInfo[infoName]) } // END: getDeviceInfoFunction() /* These functions are unique to each driver */ void parse(List description) { description.each { switch(it.name) { case "illuminance": case "motion": case "water": case "distance": case "gas": logging(it.descriptionText, 100) sendEvent(it) break case "temperature": case "dewPoint": List res = sensor_data_getAdjustedTemp(new BigDecimal(it.value), true) it.unit = res[0] it.value = res[1] logging(it.descriptionText, 100) sendEvent(it) break case "humidity": it.value = sensor_data_getAdjustedHumidity(new BigDecimal(it.value)) logging(it.descriptionText, 100) sendEvent(it) break case "pressure": it.value = sensor_data_convertPressure(new BigDecimal(it.value)) if(pressureUnitConversion != null) { it.unit = pressureUnitConversion } else { it.unit = "kPa" } logging(it.descriptionText, 100) sendEvent(it) sendEvent(name: "pressureWithUnit", value: "$it.value $it.unit", isStateChange: false) break default: log.warn "Got '$it.name' attribute data, but doesn't know what to do with it! Did you choose the right device type?" } } } void updated() { log.info "updated()" // BEGIN:getChildComponentDefaultUpdatedContent() getDriverVersion() // END: getChildComponentDefaultUpdatedContent() refresh() } void installed() { log.info "installed()" device.removeSetting("logLevel") device.updateSetting("logLevel", "100") refresh() } void refresh() { // BEGIN:getChildComponentMetaConfigCommands() def metaConfig = clearThingsToHide() metaConfig = setDatasToHide(['metaConfig', 'isComponent', 'preferences', 'label', 'name'], metaConfig=metaConfig) // END: getChildComponentMetaConfigCommands() parent?.componentRefresh(this.device) if(hideMeasurementAdjustments == true) { metaConfig = setPreferencesToHide(["tempOffset", "tempRes", "tempUnitConversion", "humidityOffset", "pressureOffset", "pressureUnitConversion"], metaConfig=metaConfig) } } /** * ----------------------------------------------------------------------------- * Everything below here are LIBRARY includes and should NOT be edited manually! * ----------------------------------------------------------------------------- * --- Nothing to edit here, move along! --------------------------------------- * ----------------------------------------------------------------------------- */ // BEGIN:getDefaultFunctions() private String getDriverVersion() { comment = "" if(comment != "") state.comment = comment String version = "v1.1.1.1123T" logging("getDriverVersion() = ${version}", 100) sendEvent(name: "driver", value: version) updateDataValue('driver', version) return version } // END: getDefaultFunctions() // BEGIN:getHelperFunctions('all-default') boolean isDriver() { try { getDeviceDataByName('_unimportant') logging("This IS a driver!", 1) return true } catch (MissingMethodException e) { logging("This is NOT a driver!", 1) return false } } void deviceCommand(String cmd) { def jsonSlurper = new JsonSlurper() def cmds = jsonSlurper.parseText(cmd) r = this."${cmds['cmd']}"(*cmds['args']) updateDataValue('appReturn', JsonOutput.toJson(r)) } void setLogsOffTask(boolean noLogWarning=false) { if (debugLogging == true) { if(noLogWarning==false) { if(runReset != "DEBUG") { log.warn "Debug logging will be disabled in 30 minutes..." } else { log.warn "Debug logging will NOT BE AUTOMATICALLY DISABLED!" } } runIn(1800, "logsOff") } } void toggle() { if(device.currentValue('switch') == 'on') { off() } else { on() } } void logsOff() { if(runReset != "DEBUG") { log.warn "Debug logging disabled... " if(isDriver()) { device.clearSetting("logLevel") device.removeSetting("logLevel") device.updateSetting("logLevel", "0") state?.settings?.remove("logLevel") device.clearSetting("debugLogging") device.removeSetting("debugLogging") device.updateSetting("debugLogging", "false") state?.settings?.remove("debugLogging") } else { app.removeSetting("logLevel") app.updateSetting("logLevel", "0") app.removeSetting("debugLogging") app.updateSetting("debugLogging", "false") } } else { log.warn "OVERRIDE: Disabling Debug logging will not execute with 'DEBUG' set..." if (logLevel != "0" && logLevel != "100") runIn(1800, "logsOff") } } boolean isDeveloperHub() { return generateMD5(location.hub.zigbeeId as String) == "125fceabd0413141e34bb859cd15e067_disabled" } def getEnvironmentObject() { if(isDriver()) { return device } else { return app } } private def getFilteredDeviceDriverName() { def deviceDriverName = getDeviceInfoByName('name') if(deviceDriverName.toLowerCase().endsWith(' (parent)')) { deviceDriverName = deviceDriverName.substring(0, deviceDriverName.length()-9) } return deviceDriverName } private def getFilteredDeviceDisplayName() { def deviceDisplayName = device.displayName.replace(' (parent)', '').replace(' (Parent)', '') return deviceDisplayName } BigDecimal round2(BigDecimal number, Integer scale) { Integer pow = 10; for (Integer i = 1; i < scale; i++) pow *= 10; BigDecimal tmp = number * pow; return ( (Float) ( (Integer) ((tmp - (Integer) tmp) >= 0.5f ? tmp + 1 : tmp) ) ) / pow; } String generateMD5(String s) { if(s != null) { return MessageDigest.getInstance("MD5").digest(s.bytes).encodeHex().toString() } else { return "null" } } Integer extractInt(String input) { return input.replaceAll("[^0-9]", "").toInteger() } String hexToASCII(String hexValue) { StringBuilder output = new StringBuilder("") for (int i = 0; i < hexValue.length(); i += 2) { String str = hexValue.substring(i, i + 2) output.append((char) Integer.parseInt(str, 16) + 30) logging("${Integer.parseInt(str, 16)}", 10) } return output.toString() } // END: getHelperFunctions('all-default') // BEGIN:getHelperFunctions('driver-metadata') private Map getMetaConfig() { def metaConfig = getDataValue('metaConfig') if(metaConfig == null) { metaConfig = [:] } else { metaConfig = parseJson(metaConfig) } return metaConfig } boolean isCSSDisabled(Map metaConfig=null) { if(metaConfig==null) metaConfig = getMetaConfig() boolean disableCSS = false if(metaConfig.containsKey("disableCSS")) disableCSS = metaConfig["disableCSS"] return disableCSS } private void saveMetaConfig(Map metaConfig) { updateDataValue('metaConfig', JsonOutput.toJson(metaConfig)) } private Map setSomethingToHide(String type, List something, Map metaConfig=null) { if(metaConfig==null) metaConfig = getMetaConfig() def oldData = [] something = something.unique() if(!metaConfig.containsKey("hide")) { metaConfig["hide"] = [type:something] } else { if(metaConfig["hide"].containsKey(type)) { metaConfig["hide"][type].addAll(something) } else { metaConfig["hide"][type] = something } } saveMetaConfig(metaConfig) logging("setSomethingToHide() = ${metaConfig}", 1) return metaConfig } private Map clearTypeToHide(String type, Map metaConfig=null) { if(metaConfig==null) metaConfig = getMetaConfig() if(!metaConfig.containsKey("hide")) { metaConfig["hide"] = [(type):[]] } else { metaConfig["hide"][(type)] = [] } saveMetaConfig(metaConfig) logging("clearTypeToHide() = ${metaConfig}", 1) return metaConfig } Map clearThingsToHide(Map metaConfig=null) { metaConfig = setSomethingToHide("other", [], metaConfig=metaConfig) metaConfig["hide"] = [:] saveMetaConfig(metaConfig) logging("clearThingsToHide() = ${metaConfig}", 1) return metaConfig } Map setDisableCSS(boolean value, Map metaConfig=null) { if(metaConfig==null) metaConfig = getMetaConfig() metaConfig["disableCSS"] = value saveMetaConfig(metaConfig) logging("setDisableCSS(value = $value) = ${metaConfig}", 1) return metaConfig } Map setStateCommentInCSS(String stateComment, Map metaConfig=null) { if(metaConfig==null) metaConfig = getMetaConfig() metaConfig["stateComment"] = stateComment saveMetaConfig(metaConfig) logging("setStateCommentInCSS(stateComment = $stateComment) = ${metaConfig}", 1) return metaConfig } Map setCommandsToHide(List commands, Map metaConfig=null) { metaConfig = setSomethingToHide("command", commands, metaConfig=metaConfig) logging("setCommandsToHide(${commands})", 1) return metaConfig } Map clearCommandsToHide(Map metaConfig=null) { metaConfig = clearTypeToHide("command", metaConfig=metaConfig) logging("clearCommandsToHide(metaConfig=${metaConfig})", 1) return metaConfig } Map setStateVariablesToHide(List stateVariables, Map metaConfig=null) { metaConfig = setSomethingToHide("stateVariable", stateVariables, metaConfig=metaConfig) logging("setStateVariablesToHide(${stateVariables})", 1) return metaConfig } Map clearStateVariablesToHide(Map metaConfig=null) { metaConfig = clearTypeToHide("stateVariable", metaConfig=metaConfig) logging("clearStateVariablesToHide(metaConfig=${metaConfig})", 1) return metaConfig } Map setCurrentStatesToHide(List currentStates, Map metaConfig=null) { metaConfig = setSomethingToHide("currentState", currentStates, metaConfig=metaConfig) logging("setCurrentStatesToHide(${currentStates})", 1) return metaConfig } Map clearCurrentStatesToHide(Map metaConfig=null) { metaConfig = clearTypeToHide("currentState", metaConfig=metaConfig) logging("clearCurrentStatesToHide(metaConfig=${metaConfig})", 1) return metaConfig } Map setDatasToHide(List datas, Map metaConfig=null) { metaConfig = setSomethingToHide("data", datas, metaConfig=metaConfig) logging("setDatasToHide(${datas})", 1) return metaConfig } Map clearDatasToHide(Map metaConfig=null) { metaConfig = clearTypeToHide("data", metaConfig=metaConfig) logging("clearDatasToHide(metaConfig=${metaConfig})", 1) return metaConfig } Map setPreferencesToHide(List preferences, Map metaConfig=null) { metaConfig = setSomethingToHide("preference", preferences, metaConfig=metaConfig) logging("setPreferencesToHide(${preferences})", 1) return metaConfig } Map clearPreferencesToHide(Map metaConfig=null) { metaConfig = clearTypeToHide("preference", metaConfig=metaConfig) logging("clearPreferencesToHide(metaConfig=${metaConfig})", 1) return metaConfig } def metaDataExporter() { List filteredPrefs = getPreferences()['sections']['input'].name[0] if(filteredPrefs != []) updateDataValue('preferences', "${filteredPrefs}".replaceAll("\\s","")) } String getDriverCSSWrapper() { Map metaConfig = getMetaConfig() boolean disableCSS = isCSSDisabled(metaConfig=metaConfig) String defaultCSS = ''' /* This is part of the CSS for replacing a Command Title */ div.mdl-card__title div.mdl-grid div.mdl-grid .mdl-cell p::after { visibility: visible; position: absolute; left: 50%; transform: translate(-50%, 0%); width: calc(100% - 20px); padding-left: 5px; padding-right: 5px; margin-top: 0px; } /* This is general CSS Styling for the Driver page */ h3, h4, .property-label { font-weight: bold; } .preference-title { font-weight: bold; } .preference-description { font-style: italic; } ''' String r = "" return r } Integer getCommandIndex(String cmd) { List commands = device.getSupportedCommands().unique() Integer i = commands.findIndexOf{ "$it" == cmd}+1 return i } String getCSSForCommandHiding(String cmdToHide) { Integer i = getCommandIndex(cmdToHide) String r = "" if(i > 0) { r = "div.mdl-card__title div.mdl-grid div.mdl-grid .mdl-cell:nth-of-type($i){display: none;}" } return r } String getCSSForCommandsToHide(List commands) { String r = "" commands.each { r += getCSSForCommandHiding(it) } return r } String getCSSToChangeCommandTitle(String cmd, String newTitle) { Integer i = getCommandIndex(cmd) String r = "" if(i > 0) { r += "div.mdl-card__title div.mdl-grid div.mdl-grid .mdl-cell:nth-of-type($i) p {visibility: hidden;}" r += "div.mdl-card__title div.mdl-grid div.mdl-grid .mdl-cell:nth-of-type($i) p::after {content: '$newTitle';}" } return r } Integer getStateVariableIndex(String stateVariable) { def stateVariables = state.keySet() Integer i = stateVariables.findIndexOf{ "$it" == stateVariable}+1 return i } String getCSSForStateVariableHiding(String stateVariableToHide) { Integer i = getStateVariableIndex(stateVariableToHide) String r = "" if(i > 0) { r = "ul#statev li.property-value:nth-of-type($i){display: none;}" } return r } String getCSSForStateVariablesToHide(List stateVariables) { String r = "" stateVariables.each { r += getCSSForStateVariableHiding(it) } return r } String getCSSForCurrentStatesToHide(List currentStates) { String r = "" currentStates.each { r += "ul#cstate li#cstate-$it {display: none;}" } return r } Integer getDataIndex(String data) { def datas = device.getData().keySet() Integer i = datas.findIndexOf{ "$it" == data}+1 return i } String getCSSForDataHiding(String dataToHide) { Integer i = getDataIndex(dataToHide) String r = "" if(i > 0) { r = "table.property-list tr li.property-value:nth-of-type($i) {display: none;}" } return r } String getCSSForDatasToHide(List datas) { String r = "" datas.each { r += getCSSForDataHiding(it) } return r } Integer getPreferenceIndex(String preference, boolean returnMax=false) { def filteredPrefs = getPreferences()['sections']['input'].name[0] if(filteredPrefs == [] || filteredPrefs == null) { d = getDataValue('preferences') if(d != null && d.length() > 2) { try{ filteredPrefs = d[1..d.length()-2].tokenize(',') } catch(e) { } } } Integer i = 0 if(returnMax == true) { i = filteredPrefs.size() } else { i = filteredPrefs.findIndexOf{ "$it" == preference}+1 } return i } String getCSSForPreferenceHiding(String preferenceToHide, Integer overrideIndex=0) { Integer i = 0 if(overrideIndex == 0) { i = getPreferenceIndex(preferenceToHide) } else { i = overrideIndex } String r = "" if(i > 0) { r = "form[action*=\"preference\"] div.mdl-grid div.mdl-cell:nth-of-type($i) {display: none;} " }else if(i == -1) { r = "form[action*=\"preference\"] div.mdl-grid div.mdl-cell:nth-last-child(2) {display: none;} " } return r } String getCSSForPreferencesToHide(List preferences) { String r = "" preferences.each { r += getCSSForPreferenceHiding(it) } return r } String getCSSForHidingLastPreference() { return getCSSForPreferenceHiding(null, overrideIndex=-1) } // END: getHelperFunctions('driver-metadata') // BEGIN:getHelperFunctions('styling') String styling_addTitleDiv(title) { return '
' + title + '
' } String styling_addDescriptionDiv(description) { return '
' + description + '
' } String styling_makeTextBold(s) { if(isDriver()) { return "$s" } else { return "$s" } } String styling_makeTextItalic(s) { if(isDriver()) { return "$s" } else { return "$s" } } String styling_getDefaultCSS(boolean includeTags=true) { String defaultCSS = ''' /* This is part of the CSS for replacing a Command Title */ div.mdl-card__title div.mdl-grid div.mdl-grid .mdl-cell p::after { visibility: visible; position: absolute; left: 50%; transform: translate(-50%, 0%); width: calc(100% - 20px); padding-left: 5px; padding-right: 5px; margin-top: 0px; } /* This is general CSS Styling for the Driver page */ h3, h4, .property-label { font-weight: bold; } .preference-title { font-weight: bold; } .preference-description { font-style: italic; } ''' if(includeTags == true) { return "" } else { return defaultCSS } } String styling_getLogo() { String logoCSS = ''' #ohla_logo { display: block; width: 200px; height: 50px; position: absolute; top: 10px; right: 10px; } @media screen and (max-device-width:450px), screen and (max-width:450px) { #ohla_logo { width: 120px; top: 55px; } } ''' return "" } // END: getHelperFunctions('styling') // BEGIN:getHelperFunctions('sensor-data') private sensor_data_getAdjustedTemp(BigDecimal value, boolean returnUnit=false) { Integer res = 1 String degree = String.valueOf((char)(176)) String tempUnit = "${degree}C" if(tempRes != null && tempRes != '') { res = Integer.parseInt(tempRes) } if (tempUnitConversion == "2") { value = celsiusToFahrenheit(value) tempUnit = "${degree}F" } else if (tempUnitConversion == "3") { value = fahrenheitToCelsius(value) } BigDecimal r = null if (tempOffset != null) { r = (value + new BigDecimal(tempOffset)).setScale(res, BigDecimal.ROUND_HALF_UP) } else { r = value.setScale(res, BigDecimal.ROUND_HALF_UP) } if(returnUnit == false) { return r } else { return [tempUnit, r] } } private List sensor_data_getAdjustedTempAlternative(BigDecimal value) { Integer res = 1 BigDecimal rawValue = value if(tempRes != null && tempRes != '') { res = Integer.parseInt(tempRes) } String degree = String.valueOf((char)(176)) String tempUnit = "${degree}C" String currentTempUnitDisplayed = tempUnitDisplayed if(currentTempUnitDisplayed == null || currentTempUnitDisplayed == "0") { if(location.temperatureScale == "C") { currentTempUnitDisplayed = "1" } else { currentTempUnitDisplayed = "2" } } if (currentTempUnitDisplayed == "2") { value = celsiusToFahrenheit(value) tempUnit = "${degree}F" } else if (currentTempUnitDisplayed == "3") { value = value + 273.15 tempUnit = "${degree}K" } if (tempOffset != null) { return [tempUnit, (value + new BigDecimal(tempOffset)).setScale(res, BigDecimal.ROUND_HALF_UP), rawValue] } else { return [tempUnit, value.setScale(res, BigDecimal.ROUND_HALF_UP), rawValue] } } private BigDecimal currentTemperatureInCelsiusAlternative(BigDecimal providedCurrentTemp = null) { String currentTempUnitDisplayed = tempUnitDisplayed BigDecimal currentTemp = providedCurrentTemp != null ? providedCurrentTemp : device.currentValue('temperature') if(currentTempUnitDisplayed == null || currentTempUnitDisplayed == "0") { if(location.temperatureScale == "C") { currentTempUnitDisplayed = "1" } else { currentTempUnitDisplayed = "2" } } if (currentTempUnitDisplayed == "2") { currentTemp = fahrenheitToCelsius(currentTemp) } else if (currentTempUnitDisplayed == "3") { currentTemp = currentTemp - 273.15 } return currentTemp } void sendAbsoluteHumidityEvent(BigDecimal deviceTempInCelsius, BigDecimal relativeHumidity) { if(relativeHumidity != null && deviceTempInCelsius != null) { BigDecimal numerator = (6.112 * Math.exp((17.67 * deviceTempInCelsius) / (deviceTempInCelsius + 243.5)) * relativeHumidity * 2.1674) BigDecimal denominator = deviceTempInCelsius + 273.15 BigDecimal absHumidity = numerator / denominator String cubeChar = String.valueOf((char)(179)) absHumidity = absHumidity.setScale(1, BigDecimal.ROUND_HALF_UP) logging("Sending Absolute Humidity event (Absolute Humidity: ${absHumidity}g/m${cubeChar})", 100) sendEvent( name: "absoluteHumidity", value: absHumidity, unit: "g/m${cubeChar}", descriptionText: "Absolute Humidity Is ${absHumidity} g/m${cubeChar}" ) } } private BigDecimal sensor_data_getAdjustedHumidity(BigDecimal value) { Integer res = 1 if(humidityRes != null && humidityRes != '') { res = Integer.parseInt(humidityRes) } if (humidityOffset) { return (value + new BigDecimal(humidityOffset)).setScale(res, BigDecimal.ROUND_HALF_UP) } else { return value.setScale(res, BigDecimal.ROUND_HALF_UP) } } private BigDecimal sensor_data_getAdjustedPressure(BigDecimal value, Integer decimals=2) { Integer res = decimals if(pressureRes != null && pressureRes != '' && pressureRes != 'default') { res = Integer.parseInt(pressureRes) } if (pressureOffset) { return (value + new BigDecimal(pressureOffset)).setScale(res, BigDecimal.ROUND_HALF_UP) } else { return value.setScale(res, BigDecimal.ROUND_HALF_UP) } } private BigDecimal sensor_data_convertPressure(BigDecimal pressureInkPa) { BigDecimal pressure = pressureInkPa switch(pressureUnitConversion) { case null: case "kPa": pressure = sensor_data_getAdjustedPressure(pressure / 10) break case "inHg": pressure = sensor_data_getAdjustedPressure(pressure * 0.0295299) break case "mmHg": pressure = sensor_data_getAdjustedPressure(pressure * 0.75006157) break case "atm": pressure = sensor_data_getAdjustedPressure(pressure / 1013.25, 5) break default: pressure = sensor_data_getAdjustedPressure(pressure, 1) break } return pressure } // END: getHelperFunctions('sensor-data') // BEGIN:getLoggingFunction(specialDebugLevel=True) private boolean logging(message, level) { boolean didLogging = false Integer logLevelLocal = 0 if (infoLogging == null || infoLogging == true) { logLevelLocal = 100 } if (debugLogging == true) { logLevelLocal = 1 } if (logLevelLocal != 0){ switch (logLevelLocal) { case 1: if (level >= 1 && level < 99) { log.debug "$message" didLogging = true } else if (level == 100) { log.info "$message" didLogging = true } break case 100: if (level == 100 ) { log.info "$message" didLogging = true } break } } return didLogging } // END: getLoggingFunction(specialDebugLevel=True)