/* Radio Thermostat Zwave Hubitat driver
Hubitat driver for radio thermostat
Hubitat driver for Iris CT101 Thermostat
Radio Thermostat Company of America (RTC)
Building a better thermostat driver that just works.....
brand: Radio Thermostat
manufacturer: 152
model: CT30,CT32,CT50,CT80,CT100,CT101,CT110,CT200
Supports
poll chron, time set chron,humidity,heat or cool only,C-wire,Diff,Mans detection
Google Home
C/F notice your hub must match your thermostats settings no conversion is done.
Go to Hub Settings set C/F then go to thermostat and set C/F to match
______ _ _ _____ _ _ _
| ___ \ | (_) |_ _| | | | | |
| |_/ /__ _ __| |_ ___ | | | |__ ___ _ __ _ __ ___ ___ ___| |_ __ _| |_
| // _` |/ _` | |/ _ \ | | | '_ \ / _ \ '__| '_ ` _ \ / _ \/ __| __/ _` | __|
| |\ \ (_| | (_| | | (_) | | | | | | | __/ | | | | | | | (_) \__ \ || (_| | |_
\_| \_\__,_|\__,_|_|\___/ \_/ |_| |_|\___|_| |_| |_| |_|\___/|___/\__\__,_|\__|
No battery is needed on these thrmostats if using C Wire. The driver will restore settings on reboot.
Unneeded batteries cost money so you can stop using them. Set driver to ignore battery
Polling chron ends the need to use rouines to refreash the thermostat as some models just dont report
temp and setpoints to the hub unless polled.
Versions of the same model act diffrently depending on firmware. Some ct101 report some dont.
Heating Colling only supports using the thermostat only for heaters or ac units. Prevents the blocked mode
commans and removes blocked modes from the options in scripts.
Driver was written to fix the many problems with internal drivers not supporting fully the ct101
and the ct30 thermostats. The thermostats have bugs that need special programming.
Tested on....
USNAP Module RTZW-01 n
fingerprint mfr:0098 prod:6501 model:000C ct101 Iris version
fingerprint mfr:0098 prod:1E12 model:015C ct30e rev v1 C-wire report
If you have version that identifies as UNKNOWN please send me your fingerprint and the version on the thermostat.
If your version has a version # that doesnt match the fingerprints bellow please send me your fingerprint and version.
If any of the settings dont work on your thermostat please let me know.
CT30e [0098-0001-001E] USNAP Module RTZW-01 (tested) protocolVersion: 2.78 applicationVersion: 5.0
Has defective firmware
Displays REMOTE CONTROL box when paired.
False operating states. Claims its running all the time
never reports idle unless in OFF mode. Causes dashboard color to stay red or blue.
Doesnt support modes other CT30s do. Wont reply to bat request.
May report energySaveHeat:true, energySaveCool: true Then report False.
Firmware fix for ct30 ct32 units that dont report states corectaly
ZWAVE SPECIFIC_TYPE_THERMOSTAT_GENERAL_V2
===================================================================================================
v5.7.9 03/26/2023 New firmware version ident routine. Fix bad firmware dec order
v5.7.8 03/24/2023 Bug fix in scale in setpoint. Last update broke it
v5.7.7 03/24/2023 Bug in scale detection causing errors in the log
v5.7.6 03/17/2023 CT30 was corrupting modes. Mode setup rewritten with bug checking
v5.7.5 03/13/2023 get rid of nulls in database fields
v5.7.4 03/13/2023 error detection for c/f mismatch
v5.7.3 03/10/2023 Rewrote C/F routines.
v5.7.2 02/19/2023 Simulated ct30 state dupes removed.Better log. Event codes reordered
Google Home support added
Error checking to stop google from sending dec .5 values.
v5.7.1 02/18/2023 New simulated fan and operating states for CT30/CT32 units with bad firmware.
v5.7.0 02/16/2023 minor cleanup/logging changes. CT110 fingerprint added. 2 Stage Diff reporting fixed
New testing for supported functions. Non supported functions now hidden and never sent.
v5.6.9 02/11/2023 Fan Operating State now simulated when not sent from therm. Minor changes to improve reporting
v5.6.8 02/10/2023 Total Rewrite of MODE code and tracing logging, Last update broke things, fixed
v5.6.7 02/07/2023 Extra trace logging for sent commands
v5.6.6 02/06/2023 BUG FIX setpoints now wait for therm to report back before setting. Delays changed
v5.6.5 02/05/2023 2-stage diff reports not working, Config changes,Dashboard improvements
v5.6.4 12/26/2022 Bug fix supportedFanModes. Thermostat modes fix
v5.6.0 12/26/2022 Upgrade thermostat modes with double quotes to comply with new firmware 2.3.4.123 change
v5.5.6 12/14/2022 Ignore bat option for mains only. No bat is actualy needed
v5.5.5 12/05/2022 ManufacturerSpecificReport parsing added
v5.5.4 11/23/2022 Bug fix in recovery error counter getting reset/Bug in heat reset was resetting cool
v5.5.3 11/18/2022 extra polling times added
v5.5.2 11/12/2022 Logging module update. Autofix installed
v5.5.1 10/20/2022 Null on line 401. Error checking added/ Swing and DIff auto saved
v5.5.0 10/15/2022 Null detection added in event 11
v5.4.2 10/10/2022 Split info logs
v5.4.1 09/28/2022 Loging for chron human form
v5.4 09/19/2022 Rewrote logging routines.
v5.3.5 08/17/2022 Bug fix Last update broke the clock fixed
v5.3.4 08/16/2022 Added Recovery mode
v5.3.1 08/15/2022 Added Swing
v5.3 08/14/2022 Added 2 stage differential
v5.2.7 08/11/2022 Bug fixes. to many to list
v5.2 08/07/2022 mode bug fixed
v5.1 08/05/2022 Changes to manufacturerSpecificGet. Heat or Cool Only working
v4.8 08/04/2022 First major release out of beta working code.
v3.3 07/30/2022 Improvements and debuging code.
v3.1 07/30/2022 Total rewrite of event storage and Parsing.
v3.0 07/29/2022 Release - Major fixes and log conversion
----- Missing numbers are beta working local versions never released.
===================================================================================================
Notes
Paring. Bring hub to thermostat or thermostat to hub connect 24 volts AC between C and RC. (AC ONLY).
Be sure you get paired in c-wire mode.
CT101 will work in battery mode or c-wire mode. However I havent done much testing in battery mode.
Models with the Radio Thermostat Z-Wave USNAP Module RTZW-01 Require C-Wire or they will go to sleep
never to rewake. Some will take commands in sleep some wont. c-wire is required.
Do not even atempt to use battery mode.
Some models report C-Wire status some dont. Some models report Diff some take the command but report back 6
There are many diffrent versions of the ct30 some with bad firmware and some that dont support all commands.
======================================================================================================
Copyright [2022] [tmaster winnfreenet.com]
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.
=======================================================================================================
Contains a lot of orginal code created by me
and some code from these drivers
None of these drivers work right on radio Thermostat they all have problems.
Orginal smartthings driver:
https://github.com/SmartThingsCommunity/SmartThingsPublic/blob/master/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy
These are all forks from the above.
https://github.com/MarioHudds/hubitat/blob/master/Enhanced%20Z-Wave%20Thermostat
https://community.hubitat.com/t/port-enhanced-z-wave-thermostat-ct-100-w-humidity-and-time-update/4743
https://github.com/motley74/SmartThingsPublic/blob/master/devicetypes/motley74/ct100-thermostat-custom.src/ct100-thermostat-custom.groovy
some google home code comes from
https://raw.githubusercontent.com/Botched1/Hubitat/master/Drivers/Vivint%20CT-200/vivint_ct200.groovy
May use some open source code from sources listed here.
https://raw.githubusercontent.com/tmastersmart/hubitat-code/main/opensource_links.txt
*/
def clientVersion() {
TheVersion="5.7.9"
if (state.version != TheVersion){
logging("Upgrading ! ${state.version} to ${TheVersion}", "warn")
state.version = TheVersion
runIn(10,configure)// Forces config on updates
}
}
metadata {
definition (name: "Radio Thermostat Zwave", namespace: "tmastersmart", author: "tmaster", importUrl: "https://raw.githubusercontent.com/tmastersmart/hubitat-code/main/radio_thermostat_zwave.groovy") {
capability "Actuator"
capability "Configuration"
capability "Polling"
capability "Sensor"
capability "Refresh"
capability "Battery"
capability "PowerSource"
capability "Thermostat"
capability "TemperatureMeasurement"
capability "ThermostatMode"
capability "ThermostatFanMode"
capability "ThermostatSetpoint"
capability "ThermostatCoolingSetpoint"
capability "ThermostatHeatingSetpoint"
capability "ThermostatOperatingState"
capability "RelativeHumidityMeasurement"
capability "HealthCheck"
attribute "thermostatFanState", "string"
attribute "SetClock", "string"
attribute "SetCool", "string"
attribute "SetHeat", "string"
attribute "temperatureSwing", "string"
attribute "recovery", "string"
attribute "recoveryTempDiffHeat", "string"
attribute "recoveryTempDiffCool", "string"
command "setDiff"
command "setSwing"
command "unschedule"
command "uninstall"
command "setClock"
command "setRecovery"
// command "saveSettings"
fingerprint deviceId: "0x08"
fingerprint inClusters: "0x43,0x40,0x44,0x31"
fingerprint inClusters: "0x20,0x87,0x72,0x31,0x40,0x42,0x44,0x43,0x86"// * ct-30e Z-Wave USNAP Module RTZW-01
fingerprint inClusters: "0x20,0x87,0x72,0x31,0x40,0x44,0x43,0x42,0x86,0x70,0x80,0x88" // * ct-30 private lable alarm
fingerprint inClusters: "0x20,0x81,0x87,0x72,0x31,0x40,0x44,0x43,0x42,0x86,0x70,0x80,0x88" //* ct-30e rev v1 Z-Wave USNAP Module RTZW-01
fingerprint inClusters: "0x20,0x81,0x87,0x72,0x31,0x40,0x42,0x44,0x45,0x43,0x86,0x70,0x80,0x85,0x60" // ct-100 & (ct-101 iris)
fingerprint inClusters: "0x20,0x81,0x87,0x72,0x31,0x40,0x42,0x44,0x45,0x43,0x86,0x70,0x80,0x85,0x5D,0x60"// ct-101
// hubitat ignores deviceJoinName only included for ref notes
// https://www.opensmarthouse.org/zwavedatabase/94
fingerprint type:"0806", mfr:"0098", prod:"1E10", model:"0158",manufacturer: "Radio Thermostat", deviceJoinName:"CT-30 Radio Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"0000", model:"0000",manufacturer: "Radio Thermostat", deviceJoinName:"CT-30 Radio Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"1E12", model:"015C",manufacturer: "Radio Thermostat", deviceJoinName:"CT-30e Radio Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"1E12", model:"015E",manufacturer: "Radio Thermostat", deviceJoinName:"CT-30 v1 Radio Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"0001", model:"001E",manufacturer: "Radio Thermostat", deviceJoinName:"CT-30e Radio Thermostat" //https://products.z-wavealliance.org/products/158?selectedFrequencyId=2
fingerprint type:"0806", mfr:"0098", prod:"0001", model:"0000",manufacturer: "Radio Thermostat", deviceJoinName:"CT-30 Z-Wave Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"0001", model:"00FF",manufacturer: "Radio Thermostat", deviceJoinName:"CT-30 Z-Wave Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"0001", model:"00FF",manufacturer: "Radio Thermostat", deviceJoinName:"CT-30 Z-Wave Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"2002", model:"0100",manufacturer: "Radio Thermostat", deviceJoinName:"CT-32 Z-Wave Thermostat" //https://products.z-wavealliance.org/products/1330?selectedFrequencyId=2 https://products.z-wavealliance.org/products/1046?selectedFrequencyId=2
fingerprint type:"0806", mfr:"0098", prod:"0002", model:"0100",manufacturer: "Radio Thermostat", deviceJoinName:"CT-32 Z-Wave Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"2002", model:"0102",manufacturer: "Radio Thermostat", deviceJoinName:"CT-32 Z-Wave Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"3200", model:"015E",manufacturer: "Radio Thermostat", deviceJoinName:"CT-50 Filtrete 3M-50 Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"5003", model:"0109",manufacturer: "Radio Thermostat", deviceJoinName:"CT-80 Radio Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"5003", model:"01FD",manufacturer: "Radio Thermostat", deviceJoinName:"CT-80 Radio Thermostat"
// There are 4 diffrent versions 8.4,8.7,9,9.1
fingerprint type:"0806", mfr:"0098", prod:"6401", model:"0015",manufacturer: "Radio Thermostat", deviceJoinName:"CT-100 v8.7 Radio Thermostat"// https://products.z-wavealliance.org/products/646?selectedFrequencyId=2
fingerprint type:"0806", mfr:"0098", prod:"6401", model:"0107",manufacturer: "Radio Thermostat", deviceJoinName:"CT-100 Radio Thermostat"//also 2gig
fingerprint type:"0806", mfr:"0098", prod:"6401", model:"0106",manufacturer: "Radio Thermostat", deviceJoinName:"CT-100 v9.1 Vivint Thermostat"// https://products.z-wavealliance.org/products/795?selectedFrequencyId=2
fingerprint type:"0806", mfr:"0098", prod:"6402", model:"0100",manufacturer: "Radio Thermostat", deviceJoinName:"CT-100 Plus Radio Thermostat"//https://products.z-wavealliance.org/products/1798?selectedFrequencyId=2
// https://www.opensmarthouse.org/zwavedatabase/98
fingerprint type:"0806", mfr:"0098", prod:"6501", model:"00FD",manufacturer: "Radio Thermostat", deviceJoinName:"CT-101 Radio Thermostat"//https://products.z-wavealliance.org/products/1301?selectedFrequencyId=2
fingerprint type:"0806", mfr:"0098", prod:"6501", model:"000B",manufacturer: "Radio Thermostat", deviceJoinName:"CT-101 Lowes Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"6501", model:"000C",manufacturer: "Radio Thermostat", deviceJoinName:"CT-101 Iris Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"6E01", model:"0000",manufacturer: "Radio Thermostat", deviceJoinName:"CT-110 Thermostat" //https://products.z-wavealliance.org/products/1333
fingerprint type:"0806", mfr:"0098", prod:"C801", model:"001D",manufacturer: "Radio Thermostat", deviceJoinName:"CT-200 Vivint Element Thermostat"
fingerprint type:"0806", mfr:"0098", prod:"C801", model:"0022",manufacturer: "Radio Thermostat", deviceJoinName:"CT-200X Vivint Element Thermostat"
// 6402:0100
// Tested on....
// fingerprint mfr:0098 prod:6501 model:000C ct101 Iris versio-Wave USNAP Module RTZW-01 n
// fingerprint mfr:0098 prod:1E12 model:015C ct30e rev v1 C-wire report
// fingerprint mfr:0098 prod:0001 model:001E ct30e Displays REMOTE CONTROL box when paired - No c-wire report
}
}
preferences {
updateParameters()
input name: "infoLogging", type: "bool", title: "Enable info logging", description: "Recomended info level" ,defaultValue: true,required: true
input name: "info2Logging", type: "bool", title: "Enable info Extra logging", description: "Recomended info2 level. Full info level." ,defaultValue: true,required: true
input name: "debugLogging", type: "bool", title: "Enable debug logging", description: "Programming Debug logs" ,defaultValue: false,required: true
input name: "traceLogging", type: "bool", title: "Enable trace logging", description: "Insane HIGH level", defaultValue: false,required: true
if (state.parameter[8]){
input( "heatDiff", "number", title: "2 Stage Heat differential", description: "Only for 2 stage ElectHeat or HeatPumps. 2nd stage engages when x above setpoint.(2 to 6)", defaultValue: 2,required: true)
input( "coolDiff", "number", title: "2 Stage Cool differential", description: "Only for 2 stage HeatPumps. (ignore if not using)(2 to 6)", defaultValue: 2,required: true)
}
if (state.parameter[7]){
input( "swing", "enum", title: "Temperature Swing", description: "Number of degrees above (for cooling) and below (for heating) the temp will fluctuate before cycling back on.", options: ["0.5","1.0","1.5","2.0","2.5","3.0","3.5","4.0"], defaultValue: "1.0", multiple: false, required: true)
}
if (state.parameter[9]){
input name: "recovery", type: "enum", title: "Recovery mode", description: "Fast or economy. ", options: ["fast", "economy"], defaultValue: "economy",required: true
}
input name: "onlyMode", type: "enum", title: "Mode Bypass", description: "Heat or Cool only mode", options: ["off", "heatonly","coolonly"], defaultValue: "off",required: true
input( "polling", "enum", title: "Polling minutes", description: "Polling Chron. Press Config after changing ", options: ["5","10","15","20","25","30","35","40","45","50","55",],defaultValue: 15,required: true)
input name: "autocorrect", type: "bool", title: "Auto Correct setpoints", description: "Keep thermostat settings matching hub (this will overide local changes)", defaultValue: false,required: true
input( "autocorrectNum", "number", title: "Auto Correct errors", description: "send auto corect after number of errors detected. ", defaultValue: 5,required: true)
if (state.parameter[19]){
input name: "FirmwareFix", type: "bool", title: "Simulate States", description: "Bad Firmware Fix. Simulates fan and operating states. Fixes dashboard staying red or blue when not running.", defaultValue: false,required: false
}
input name: "ignorebat", type: "bool", title: "Ignore Bat reports", description: "If no batteries inserted. Batteries are not needed if main powered.", defaultValue: false,required: true
}
def installed(){
logging("Radio Thermostat Paired!", "info")
cleanState()
configure()
}
// Runs on reboot
def initialize(){
logging("Radio Thermostat Initialize ", "debug")
randomSixty = Math.abs(new Random().nextInt() % 180)
runIn(randomSixty,refresh)
}
void cleanState(){
state.remove("paypal")
state.remove("pendingRefresh")
state.remove("precision")
state.remove("scale")
state.remove("size")
state.remove("version")
state.remove("supportedFanModes")
state.remove("supportedModes")
state.remove("lastbatt")
state.remove("LastTimeSet")
state.remove("lastTriedMode")
state.remove("lastTriedFanMode")
state.remove("lastClockSet")
state.remove("lastBattery")
state.remove("lastMode")
state.remove("lastBatteryGet")
state.remove("lastOpState")
state.remove("initialized")
state.remove("configUpdated")
state.remove("model")
state.remove("icon")
state.remove("donate")
state.remove("fingerprint")
state.remove("model")
state.remove("setCool")
state.remove("setHeat")
state.remove("cwire")
state.remove("error")
// no longer used
state.remove("lastClockSet")
state.remove("supportedFanModes")
state.remove("supportedModes")
state.remove("lastBatteryGet")
removeDataValue("thermostatSetpoint")
removeDataValue("SetCool")
removeDataValue("coolingSetpoint")
removeDataValue("SetHeat")
removeDataValue("supportedFanModes")
// Clear crap from other drivers
updateDataValue("hardwareVersion", "")
updateDataValue("protocolVersion", "")
updateDataValue("lastRunningMode", "")
updateDataValue("zwNNUR", "")
logging("Garbage Collection.", "info")
}
def uninstall() {
unschedule()
cleanState()
logging("Uninstalled", "info")
}
def configure() {
unschedule()
getIcons()
setClock()
updateParameters()
logging("Configure Driver v${state.version}", "info")
fanAuto() // set default
updated()
state.cwire =0
state.remove("lastBatteryGet")
logging("Sending >> configurationSet (parameterNumber: 4, size: 1, configurationValue: [2])", "trace")
logging("Sending >> configurationGet (4,7,8,9 = cwire,swing,diff,recovery) NodeID:${zwaveHubNodeId}", "trace")
logging("Sending >> get request (man,mode,FanMode) ", "trace")
delayBetween([
zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:1).format(), // get reports without polling
zwave.manufacturerSpecificV2.manufacturerSpecificGet().format(),// fingerprint
zwave.versionV1.versionGet().format(),
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format(),
zwave.configurationV2.configurationSet(parameterNumber: 4, size: 1, configurationValue: [2]).format(), // cwire enabled
zwave.configurationV2.configurationGet(parameterNumber: 4).format(), // is cwire 1=true 2=false
zwave.configurationV2.configurationGet(parameterNumber: 7).format(), // swing
zwave.configurationV2.configurationGet(parameterNumber: 8).format(), // is diff
zwave.configurationV2.configurationGet(parameterNumber: 9).format(), // is fast recovery on ? 1on 0 off
], 3500)
}
def updated() {
updateParameters()
if (!polling){polling=15} // Poll the device every x min
// options: ["10","15","20","30","40","50"]
int checkEveryMinutes = Integer.parseInt(polling)
randomSixty = Math.abs(new Random().nextInt() % 60)
schedule("${randomSixty} 0/${checkEveryMinutes} * * * ? *", poll)
schedule("${randomSixty} 0 12 * * ? *", setTheClock)
logging("Setting Chron Poll: every ${checkEveryMinutes}mins Clock: 12:${randomSixty}", "info")
loggingUpdate()
logging("Sending >> get request (mode,temp,state) ", "trace")
saveSettings()
delayBetween([
zwave.thermostatModeV2.thermostatModeGet().format(),// get mode
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(),// get state
zwave.sensorMultilevelV3.sensorMultilevelGet().format(), // current temperature
zwave.batteryV1.batteryGet().format()
], 3500)
}
def ping() {
logging("Ping", "info")
logging("Sending >> get request (mode,temp,state) ", "trace")
updateParameters()
delayBetween([
zwave.thermostatModeV2.thermostatModeGet().format(),// get mode
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(),// get state
zwave.sensorMultilevelV3.sensorMultilevelGet().format(), // current temperature
zwave.batteryV1.batteryGet().format()
], 3500)
}
def pollDevice() {
logging("pollDevice", "info")
poll()
}
def refresh() {
logging("refresh", "info")
poll()
}
def poll() {
updateParameters()
def nowCal = Calendar.getInstance(location.timeZone)
Timecheck = "${nowCal.getTime().format("EEE MMM dd", location.timeZone)}"
logging("Poll E=Event# ${Timecheck} v${state.version}", "info")
//zwave.sensorMultilevelV5.sensorMultilevelGet().format(), // testing
//zwave.batteryV1.batteryGet().format(),
//zwave.commands.versionv2.VersionReport
//zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
//zwave.manufacturerSpecificV2.manufacturerSpecificGet().format(),
logging("Sending >> get request (temp,Hum,Setpoint 1&2,mode,FanMode,state,battery) ", "trace")
logging("Sending >> configurationGet (4,7,8,9 = cwire,swing,diff,recovery", "trace")
delayBetween([
zwave.sensorMultilevelV3.sensorMultilevelGet().format(),// current temperature
zwave.multiInstanceV1.multiInstanceCmdEncap(instance: 2).encapsulate(zwave.sensorMultilevelV2.sensorMultilevelGet()).format(), // CT-100/101 Humidity
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format(),
zwave.thermostatModeV2.thermostatModeGet().format(),
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format(),
zwave.configurationV2.configurationGet(parameterNumber: 1).format(),// get Temperature Reporting Threshold
zwave.configurationV2.configurationGet(parameterNumber: 2).format(), // HVAC Settings
zwave.configurationV2.configurationGet(parameterNumber: 4).format(),// get cwire
zwave.configurationV2.configurationGet(parameterNumber: 5).format(), // Humidity Reporting Threshold
zwave.configurationV2.configurationGet(parameterNumber: 6).format(),// get emergency aux
zwave.configurationV2.configurationGet(parameterNumber: 7).format(),// temp swing
zwave.configurationV2.configurationGet(parameterNumber: 8).format(),// is temp diff
zwave.configurationV2.configurationGet(parameterNumber: 9).format(),// is fast recovery
zwave.batteryV1.batteryGet().format()
// zwave.configurationV2.configurationGet(parameterNumber: 11).format(),// Get UI mode
], 3500)// delay increased to allow therm to respond.
// zwave.configurationV2.configurationGet(parameterNumber: 10).format(),// reports data what is it
// These are documented
// zwave.configurationV2.configurationGet(parameterNumber: 3).format(), // Utility Lock
// zwave.configurationV2.configurationGet(parameterNumber: 11).format(),// get UI mode
// zwave.configurationV2.configurationSet(parameterNumber: 11, size: 1, configurationValue: 1) // simple UI enabled 1 on 2 off
// zwave.configurationV1.configurationSet(scaledConfigurationValue: value, parameterNumber: 15, size: 1), //fan timmer CT200
// zwave.configurationV1.configurationSet(scaledConfigurationValue: value, parameterNumber: 17, size: 1), //sensor cal CT200
// zwave.configurationV1.configurationSet(parameterNumber: 18, size: 1, scaledConfigurationValue: paramValue)// display units
}
def updateParameters(){// set the info line
text =""
// build the database
if(!state.parameter) {state.parameter=[]}
if(!state.parameter[1]) {state.parameter[1]=0}
if(!state.parameter[2]) {state.parameter[2]=0}
if(!state.parameter[3]) {state.parameter[3]=0}
if(!state.parameter[4]) {state.parameter[4]=0}
if(!state.parameter[5]) {state.parameter[5]=0}
if(!state.parameter[6]) {state.parameter[6]=0}
if(!state.parameter[7]) {state.parameter[7]=0}
if(!state.parameter[8]) {state.parameter[8]=0}
if(!state.parameter[7]) {state.parameter[7]=0}
if(!state.parameter[8]) {state.parameter[8]=0}
if(!state.parameter[9]) {state.parameter[9]=0}
if(!state.parameter[10]) {state.parameter[10]=0}
if(!state.parameter[11]) {state.parameter[11]=0}
if(!state.parameter[12]) {state.parameter[12]=0}
if(!state.parameter[13]) {state.parameter[13]=0}
if(!state.parameter[14]) {state.parameter[14]=0}
if(!state.parameter[15]) {state.parameter[15]=0}
if(!state.parameter[16]) {state.parameter[16]=0}
if(!state.parameter[17]) {state.parameter[17]=0}
if(!state.parameter[18]) {state.parameter[18]=0}
if(!state.parameter[19]) {state.parameter[19]=0}
// build the info line from the database
if (state.parameter[1]){text +="TempReportThreshold,"}
if (state.parameter[2]){text +="HVAC,"}
if (state.parameter[3]){text +="Lock,"}
if (state.parameter[4]){text +="CWIRE,"}
if (state.parameter[5]){text +="HumReportThreshold,"}
if (state.parameter[6]){text +="AuxHeat,"}
if (state.parameter[7]){text +="Swing,"}
if (state.parameter[8]){text +="Diff,"}
if (state.parameter[9]){text +="Recovery,"}
// if (state.parameter[10]){text +="unknown,"}
if (state.parameter[11]){text +="UI,"}
if (state.parameter[12]){text +="Temp,"}
if (state.parameter[13]){text +="Hum,"}
if (state.parameter[14]){text +="Battery,"}
if (state.parameter[15]){text +="Clock,"}
if (state.parameter[16]){text +="FanState,"}
if (state.parameter[17]){text +="energySaveHeat,"}
if (state.parameter[18]){text +="energySaveCool"}
if (state.parameter[19]){text +="Firmwarefix"}
state.info ="Supported Parameters: ${text}"
}
def parse(String description)
{
// 0x20:1
// 0x31:3 Sensor Multilevel <--
// 0x40:2 Mode
// 0x42:1 Operating State <--
// 0x43:2 Setpoint <--
// 0x44:3 Fan Mode <--
// 0x45:1 Fan State
// 0x59:1
// 0x5A:1
// 0x5D:1
// 0x5E:2
// 0x60:3 Multi channel
// 0x70:2 Config
// 0x72:2 Manufacturer Specific
// 0x80:1 Battery
// 0x81:1 Clock
// 0x85:1 Association
// 0x86:1 Version
// 0x87:1 Indicator
// 0x8F:3
// 0x98:1 Security
clientVersion()
CommandClassCapabilities = [0x31:3,0x40:2,0x42:1,0x43:2,0x44:3,0x45:1,0x60:3,0x70:2,0x72:2,0x80:1,0x81:1,0x85:1,0x86:1,0x87:1,0x98:1]
hubitat.zwave.Command map = zwave.parse(description, CommandClassCapabilities)
if (!map) {
logging("Unable to Parse ${description}", "error")
return
}
def result = [map]
logging("Raw:${description}", "trace")
logging("Parse ${map}", "debug")
zwaveEvent(map)
}
// Event Generation
// event E1
// Termostat setpoints -------------------------------------------------------
def zwaveEvent(hubitat.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd)
{
if (!cmd){
logging("E1 Received NULL", "warn")
return
}
logging("E1 Received ${cmd}", "debug")
state.scale = cmd.scale // Device scale
if (cmd.scale == 1){scale="F"}
else {scale="C"}
logging("E1 Received setpointType:${cmd.setpointType} Value:${cmd.scaledValue} Precision:${cmd.precision} Scale:${scale} /${cmd.scale} ","trace")
// def cmdScale = cmd.scale == 1 ? "F" : "C"
// map.value = convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision)
// map.unit = getTemperatureScale()
switch (cmd.setpointType) {
case 1:
name = "heatingSetpoint"
tempCheck = state.SetHeat
break;
case 2:
if(heatonly == true){return}
name = "coolingSetpoint"
tempCheck = state.SetCool
break;
default:
logging("error Unknown SetpointType:${cmd.setpointType}", "warn")
return [:]
}
logging("E1 ${name} ${cmd.scaledValue} ${scale}", "info")
sendEvent(name: name , value: cmd.scaledValue ,unit: scale,descriptionText:"${name} ${cmd.scaledValue} ${scale} ${state.version}", isStateChange:true)
tempCheck2 = cmd.scaledValue.toDouble()
if(tempCheck){ // needed in case of no last setpoints set
if(tempCheck == tempCheck2){
logging("E1 ${name} Set Points Match Last:${tempCheck}=Current:${tempCheck2}", "debug") //moved to debug
//state.error = 0
}
if(tempCheck != tempCheck2 & autocorrect == true){
if(!state.error){state.error=0}
state.error = state.error + 1
logging("E1 ${map.name} Last Point does not match Last:${tempCheck}<>Current:${tempCheck2} error:${state.error} fixOn:${autocorrectNum}", "warn")
if (state.error >= autocorrectNum ){
runIn(1,FixHeat)
runIn(5,FixCool)
logging("Resetting cool:${state.SetCool}/Heat:${state.SetHeat}", "info")
state.error = 0
}
}
}// end if not null
// set the current setpoint
OpeTest = device.currentValue("thermostatOperatingState")
modeTest = device.currentValue("thermostatMode")
setpoint = 0
if (OpeTest == "heating" || modeTest =="heat" || modeTest=="emergency heat") {setpoint= state.SetHeat}
if (OpeTest == "cooling" || modeTest =="cool") {setpoint= state.SetCool}
if (setpoint!=0){
updateDataValue("thermostatSetpoint", setpoint.toString())
logging("E1.1 Update thermostatSetpoint:${setpoint} for Google Home", "debug")
sendEvent([name: "thermostatSetpoint", value: setpoint, unit: scale, descriptionText:"thermostatSetpoint ${setpoint} ${scale}${state.version}",isStateChange:true])
}
// stored so we can use on send
state.size = cmd.size
state.scale = cmd.scale
state.precision = cmd.precision
if (FirmwareFix){ct30OperatingFix()}
}
// E2
def zwaveEvent(hubitat.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
{
logging("E2 Received sensorMultilevelv2", "debug")
logging("E2 Received sensorType:${cmd.sensorType} scaledSensorValue:${cmd.scaledSensorValue} scale:${cmd.scale}","trace")
if (cmd.sensorType == 0) {return } // ct30 (fixed in rev1)
if (cmd.sensorType == 1) {
if (cmd.scale == 1){scale="F"}
else {scale="C"}
state.scale = cmd.scale
logging("E2 Device Scale is ${scale}/${state.scale}", "info2")
value = cmd.scaledSensorValue
name = "temperature"
state.parameter[12]=1
logging("E2 ${name} ${value} ${scale}", "info")
sendEvent(name:name ,value:value ,unit: scale, descriptionText:"${name} ${value} ${scale} ${state.version}", isStateChange: true)
return
} else if (cmd.sensorType == 5) {
value = cmd.scaledSensorValue
unit = "%"
name = "humidity"
state.parameter[13]=1
logging("E2 ${name} ${value} ${unit}", "info")
sendEvent(name:name ,value:value ,unit: unit, descriptionText:"${name} ${value} ${unit} ${state.version}", isStateChange: true)
return
}
logging("E2 Unknown data ${cmd}", "warn")
if (FirmwareFix){ct30OperatingFix()}
}
// E3
def zwaveEvent(hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport cmd)
{
logging("E3 Received Operating State ${cmd.operatingState}", "debug")
if (FirmwareFix){
ct30OperatingFix()
return
}
value = "idle"
switch (cmd.operatingState) {
case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_IDLE:
value = "idle"
break
case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_HEATING:
value = "heating"
break
case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_COOLING:
value = "cooling"
break
case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_FAN_ONLY:
value = "fan only"
break
case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_PENDING_HEAT:
value = "pending heat"
break
case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_PENDING_COOL:
value = "pending cool"
break
case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_VENT_ECONOMIZER:
value = "vent economizer"
break
}
logging("E3 Operating State - ${value} ", "info2")
sendEvent(name: "thermostatOperatingState", value: value,descriptionText: "Operating State ${value} ${state.version}", isStateChange:true)
GoogleHome()
fanStateFix()
}
// Google Home support.
private GoogleHome(){
OpeTest = device.currentValue("thermostatOperatingState")
value="idle"
name ="lastRunningMode"
if (state.scale == 1){scale="F"}
else {scale="C"}
if (OpeTest == "heating") { value="heat" }
if (OpeTest == "cooling") { value="cool" }
if (value !="idle"){
updateDataValue("lastRunningMode", value)
sendEvent(name:name ,value:value ,unit: scale, descriptionText:"${name} ${value} ${scale} ${state.version}", isStateChange: true)
logging("E3.2 Update LastRunningMode:${value} for Google Home", "debug")
}
}
// --------------simulate fan state for ct sending bad data--------------------
private fanStateFix(){
fanTest = device.currentValue("thermostatFanMode")
fanSTest = device.currentValue("thermostatFanState")
OpeTest = device.currentValue("thermostatOperatingState")
if(fanTest == "fanAuto"){ // fan should follow operating state if in auto
if (OpeTest == "idle"){ value = "idle"}
else {value = "running"}
}
else if (fanTest == "fanOn"){value = "running"}
if (fanSTest == value){return}// all is ok just exit
logging("E4.2 Fan State Simulated: ${value} ", "info2")
sendEvent(name: "thermostatFanState", value: value,descriptionText: "Simulated Fan State ${value} ${state.version}", isStateChange:true)
}
private ct30OperatingFix(){
fanTest = device.currentValue("thermostatFanMode")
fanSTest = device.currentValue("thermostatFanState")
modeTest = device.currentValue("thermostatMode")
tempTest = device.currentValue("temperature")
OpeTest = device.currentValue("thermostatOperatingState")
// set the operating state
value="idle"
if (modeTest =="heat"){
if (tempTest < state.SetHeat){value="heating"}
}
if (modeTest =="cool"){
if (tempTest > state.SetCool){value="cooling"}
}
if(OpeTest != value){
logging("E3.1 Operating State Simulated: ${value} ", "info2")
sendEvent(name: "thermostatOperatingState", value: value,descriptionText: "Simulated Operating State ${value} ${state.version}", isStateChange:true)
GoogleHome()
}
// set the fan operating state
valueF="idle"
if(fanTest == "fanOn" || value == "heating" || value=="cooling"){ valueF="running"}
if ( fanSTest != valueF){
logging("E4.1 Fan State Simulated: ${valueF} ", "info2")
sendEvent(name: "thermostatFanState", valueF: value,descriptionText: "Simulated Fan State ${valueF} ${state.version}", isStateChange:true)
}
logging("E3.1 Syncing Simulated States. fanState:${valueF} OperatingState:${value}", "debug")
}
// Fan State Report
def zwaveEvent(hubitat.zwave.commands.thermostatfanstatev1.ThermostatFanStateReport cmd) {
logging("E4 Received Fan State ${cmd.fanOperatingState}", "debug")
state.parameter[16]=1
if(cmd.fanOperatingState ==0){value = "idle"}
else if(cmd.fanOperatingState ==1){value = "running"}
else if(cmd.fanOperatingState ==2){value = "running high"}
else {
logging("E4 Received Unknown Fan State :${cmd.fanOperatingState} ", "warn")
return
}
logging("E4 Received Fan State :${value} ", "info2")
sendEvent(name: "thermostatFanState", value: value,descriptionText: "Fan State ${value} ${state.version}", isStateChange:true)
}
//off, heat, cool, auto, auxiliaryemergencyHeat, resume, fanOnly, furnace, energySaveHeat, energySaveCool, away
def zwaveEvent(hubitat.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) {
def map = [:]
logging("E5 Received Mode:${cmd.mode}", "debug")
map.name = "thermostatMode"
map.value = "unknown"
switch (cmd.mode) {
case hubitat.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_OFF:
map.value = "off"
break
case hubitat.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_HEAT:
map.value = "heat"
break
case hubitat.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUXILIARY_HEAT:
map.value = "emergency heat"
break
case hubitat.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_COOL:
map.value = "cool"
break
case hubitat.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUTO:
map.value = "auto"
break
}
logging("E5 ${map.name} - ${map.value} ", "info")
sendEvent(name: map.name, value: map.value,descriptionText: "${map.name} ${map.value} ${state.version}", isStateChange:true)
}
// auto, low, autoHigh, high, autoMedium, medium, circulation, humidityCirculation
def zwaveEvent(hubitat.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport cmd) {
def map = [:]
logging("E6 Received FanMode:${cmd.fanMode}", "debug")
map.name = "thermostatFanMode"
map.value = "unknown"
switch (cmd.fanMode) {
case hubitat.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW:// =0
map.value = "fanAuto"
break
case hubitat.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_HIGH:
map.value = "fanAuto"
break
case hubitat.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW: // =1
map.value = "fanOn"
break
case hubitat.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_HIGH:
map.value = "fanOn"
break
case hubitat.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION:// Dont thinmk rT supports this
map.value = "fanCirculate"
break
}
logging("E6 ${map.name} - ${map.value} ", "info2")
sendEvent(name: map.name, value: map.value,descriptionText: "${map.name} ${map.value} ${state.version}", isStateChange:true)
fanStateFix()
}
// --------read the MODES from Thermostat ----------
// off:true, heat:true, cool:true, auto:true, auxiliaryemergencyHeat:true, resume:false, fanOnly:false, furnace:false, energySaveHeat:false, energySaveCool: false, away:false
// autoChangeover dryAir moistAir resume
// new firmware update requires quotes ["off", "heat", "cool", "auto", "emergency heat"]
// Bug fix for CT30 bad reports energySaveHeat & energySaveCool then reports it doesnt have them?
// Ignore energySave and treat it as cool heat
def zwaveEvent(hubitat.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) {
def supportedModes = '"off"'// force off as the first mode
logging("E7 Received ${cmd}", "debug")
if(cmd.energySaveHeat) { state.parameter[17]=1 }
if(cmd.energySaveCool) { state.parameter[18]=1 }
// if(cmd.off) { supportedModes += '"off"' }
if(cmd.heat || cmd.energySaveHeat) { supportedModes += ',"heat"'
if(cmd.auxiliaryemergencyHeat) { supportedModes += ',"emergency heat"' }
}
if(cmd.cool || cmd.energySaveCool) { supportedModes += ',"cool"' }
if(cmd.auto) { supportedModes += ',"auto"' }
if(onlyMode == "coolonly"){supportedModes = '"off","cool"'}// custom setup for AC only
if(onlyMode == "heatonly"){supportedModes = '"off","heat"' // custom setup for HEAT only
if(cmd.auxiliaryemergencyHeat) { supportedModes += ',"emergency heat"' }
}
logging("E7 supportedModes [${supportedModes}]", "info2")
sendEvent(name: "supportedThermostatModes", value: "[${supportedModes}]",descriptionText: "${supportedModes} ${state.version}", isStateChange:true)
}
// auto:true, low: true, autoHigh: false, high: false autoMedium:false, medium:false circulation:false, humidityCirculation:false
def zwaveEvent(hubitat.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
def supportedFanModes = '' // ["Auto","On"]
logging("E8 Received ${cmd}", "debug")
if(cmd.auto) { supportedFanModes += '"Auto",' }
if(cmd.low) { supportedFanModes += '"On"' }
if(cmd.circulation) { supportedFanModes += ',"Circulate",' } // not used
if(cmd.humidityCirculation){supportedFanModes += "HumCirculate, " } // not used
if(cmd.high) { supportedFanModes += "High," } // not used
logging("E8 supportedFanModes[${supportedFanModes}]", "info2")
sendEvent(name: "supportedThermostatFanModes", value: "[${supportedFanModes}]",descriptionText: "${supportedFanModes} ${state.version}", isStateChange:true)
//supportedThermostatFanModes/
}
// these are untrapped log them...
def zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd) {
logging("E9 Received ${cmd}", "debug")
}
def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
logging("E10 Received ${cmd}", "debug")
if(!state.parameter){state.parameter=[]}
if (cmd.parameterNumber== 1){//0 to 4 This is not working on my ct101
state.parameter[1]=1
def value = cmd.scaledConfigurationValue
// def test = cmd2Integer(cmd.configurationValue)
if (value <=5 && value >=0){logging("E10-1 Temp Report Threshold ${value}", "info2")}
else {
if (debugLogging){logging("E10-1 ERROR Temp Report Threshold must be 0-4 value:${cmd.configurationValue} Scaled:${cmd.scaledConfigurationValue} Not a valid value", "warn")}
}
return
}
//2 4 HVAC Settings 1 to 2147483647 Byte 1: normal (1) or heat pump (2). Byte 2, Bits 7-4: Gas (1) or Electric (2). Byte 2, Bits 3-0: # of Auxiliary Stages.
// Byte 3: # of Heat Pump Stages. Byte 4: # of Cool Stages. value:[1, 34, 0, 1] Scaled:19005441
else if (cmd.parameterNumber== 2){
state.parameter[2]=1
if(cmd.size == 4){
mode = cmd.configurationValue[0]
gas = cmd.configurationValue[1] // dont yet know how to seperate bits 7-4 and 3-0 need help...(34= electric and 2 stages.)
pump = cmd.configurationValue[2]
cool = cmd.configurationValue[3]
modet="Normal"
gasT=""
if (mode == 2){modet="Heat Pump"}
if (gas == 34){gasT= "2 Stage Electric"}
if (gas == 33){gasT= "Backup Electric"}
logging("E10-2 HVAC Settings mode:${modet} ${gasT} HeatPumpStages:${pump} CoolStages:${cool}", "info2")
}
else {// size 3 is not in the spec but I get 1,1,1 from a ct30
mode = cmd.configurationValue[0]
modet="Normal"
if (mode == 2){modet="Heat Pump"}
logging("E10-2 HVAC Settings mode:${modet}", "info2")
}
logging("E10-2 HVAC Settings value:${cmd.configurationValue} Scaled:${cmd.scaledConfigurationValue}", "debug")
}
// ConfigurationReport(parameterNumber: 4, size: 1, configurationValue: [1], scaledConfigurationValue: 1)
else if (cmd.parameterNumber== 4){
state.parameter[4]=1
// state.cwire = cmd.configurationValue[0]
state.cwire = cmd.scaledConfigurationValue
if (state.cwire == 1){
logging("E10-4 C-Wire :TRUE PowerSouce :mains", "info2")
sendEvent(name: "powerSource", value: "mains",descriptionText: "Power Mains ${state.version}", isStateChange: true)
}
if (state.cwire == 2){
logging("E10-4 C-Wire :FALSE PowerSouce :battery", "info2")
sendEvent(name: "powerSource", value: "battery",descriptionText: "Power Battery ${state.version}", isStateChange: true)
}
}
// Humidity Reporting Threshold 0 to 3 0 = Disabled, 1 = 3% RH, 2 = 5% RH, 3 = 10% RH
// E10 Received ConfigurationReport(parameterNumber: 5, size: 1, configurationValue: [2], scaledConfigurationValue: 2)
else if (cmd.parameterNumber== 5){
state.parameter[5]=1
if (cmd.scaledConfigurationValue == 0){report="Disabled"}
if (cmd.scaledConfigurationValue == 1){report="3% RH"}
if (cmd.scaledConfigurationValue == 2){report="5% RH"}
if (cmd.scaledConfigurationValue == 3){report="10% RH"}
logging(" E10-5 Humidity Reporting Threshold :${report} ", "info2")
}
// Auxiliary/Emergency Mode 0 = Disabled, 1 = Enabled
else if (cmd.parameterNumber== 6){
state.parameter[6]=1
if (cmd.configurationValue == 1){logging("E10-6 Auxiliary/Emergency TRUE", "info2")}
else { logging("E10-6 Auxiliary/Emergency FALSE", "info2")}
}
// ConfigurationReport(parameterNumber: 7, size: 1, configurationValue:
else if (cmd.parameterNumber== 7){
state.parameter[7]=1
def test = cmd.scaledConfigurationValue
def value = 2
def locationScale = getTemperatureScale()
if (test == 1){value = "0.5"}
if (test == 2){value = "1.0"}
if (test == 3){value = "1.5"}
if (test == 4){value = "2.0"}
if (test == 5){value = "2.5"}
if (test == 6){value = "3.0"}
if (test == 7){value = "3.5"}
if (test == 8){value = "4.0"}
state.swing = value
logging("E10-7 Temp Swing :${state.swing} ${locationScale} - #${test}", "info2")
sendEvent(name: "temperatureSwing", value: state.swing, descriptionText: "${state.swing}${locationScale} - #${test} ${state.version}",displayed: true, isStateChange:true)
}
// 2 to 6(Default) The thermostat differential temperature is in units of 0.5 degrees Fahrenheit.
else if (cmd.parameterNumber== 8){
state.parameter[8]=1
def testHeat = cmd.configurationValue[0] * 0.5
def testCool = cmd.configurationValue[1] * 0.5
logging("E10-8 DiffReport Heat:${testCool}° Cool:${testHeat}° [RawHeat:${cmd.configurationValue[1]} RawCool:${cmd.configurationValue[1]}] ", "debug")
// -------------heat
if (state.heatDiff == testHeat) {
logging("E10-8-0 (2 stage Heat Differential) :${testHeat} °", "info2")
sendEvent(name: "recoveryTempDiffHeat", value: "${testHeat}",descriptionText: "heat ${testHeat}° ${state.version}",displayed: true, isStateChange:true)
}
else {
if (debugLogging){
logging("E10-8-0 Report ERROR (2 stage Differential) Heat:${testHeat} [should be ${state.heatDiff}]", "warn")
}
}
// ------------cool
if (state.coolDiff == testCool) {
logging("E10-8-1 (2 stage Cool Differential) :${testCool} °", "info2")
sendEvent(name: "recoveryTempDiffCool", value: "${testCool}", descriptionText: "cool ${testCool} ${state.version}",displayed: true, isStateChange:true)
}
else {
if (debugLogging){
logging("E10-8-1 Report ERROR (2 stage Differential) Cool:${testCool} [should be ${state.coolDiff}]", "warn")
}
}
}
// ConfigurationReport(parameterNumber: 9, size: 1, configurationValue: [2], scaledConfigurationValue: 2) Fast Recovery
else if (cmd.parameterNumber== 9){
state.parameter[9]=1
if (cmd.configurationValue[0] == 1){state.fastrecovery = "fast"}
if (cmd.configurationValue[0] == 2){state.fastrecovery = "economy"}
logging(" E10-9 Recovery :${state.fastrecovery} #${cmd.configurationValue[0]}", "info2")
sendEvent(name: "recovery", value: "${state.fastrecovery}", descriptionText: "${state.fastrecovery} ${state.version}",displayed: true, isStateChange:true)
}
else {logging("E10 Untraped parameterNumber:${cmd.parameterNumber}", "warn")}
updateParameters()
}
/**
* zwaveEvent( COMMAND_CLASS_MANUFACTURER_SPECIFIC V2 (0x72) : MANUFACTURER_SPECIFIC_REPORT (0x05) )
*
* Manufacturer-Specific Reports are used to advertise manufacturer-specific information, such as product number
* and serial number.
**/
def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
logging("${cmd} ", "debug")
def map = [:]
map.mfr = hubitat.helper.HexUtils.integerToHexString(cmd.manufacturerId, 2)
map.model = hubitat.helper.HexUtils.integerToHexString(cmd.productId, 2)
map.type = hubitat.helper.HexUtils.integerToHexString(cmd.productTypeId, 2)
logging("E11 fingerprint mfr:${map.mfr} prod:${map.type} model:${map.model}", "debug")
// state.remove("fingerprint")
state.model ="unknown"
state.parameter[19] =0 // disable the Firmware fix
if (map.type=="1E12" | map.type=="1E10" | map.type=="0000" | map.type=="0001"){
state.model ="CT30"
state.parameter[19] =1 // Allow the Firmware fix
if (map.model=="015E") {state.model ="CT30e rev.01"}
if (map.model=="015C") {state.model ="CT30e"}
if (map.model=="001E") {state.model ="CT30e bad"}
}
if (map.type=="2002" || map.type=="0002"){
state.model ="CT32"
state.parameter[19] =1 // Allow the Firmware fix
}
if (map.type=="3200" ){ state.model ="CT50"}
if (map.type=="5003" ){ state.model ="CT80"}
if (map.type=="6401" || map.type=="6402" || map.type=="0015"){ state.model ="CT100"}
if (map.type=="6402" || map.type=="0100"){ state.model ="CT100 Plus"}
if (map.type=="6501"){
state.model ="CT101"
if (map.model=="000B") {state.model ="CT101 iris"}
}
if (map.type=="C801"){
state.model = "CT200"
if(map.model =="001D"){state.model ="CT200 Vivant"}
if(map.model =="0022"){state.model = "CT200x Vivant"}
}
if (map.type=="6E01"){state.model = "CT110"} // model=0000
logging("E11 Fingerprint ${state.model} [${map.mfr}-${map.type}-${map.model}] ", "info")
if (!getDataValue("manufacturer")) {updateDataValue("manufacturer", map.mfr)}
if (!getDataValue("brand")){ updateDataValue("brand", "Radio Thermostat")}
if (state.model =="unknown"){
state.fingerprint = "Report fingerprint [${map.mfr}-${map.type}-${map.model}]"
return
}
if (!getDataValue("model")){ updateDataValue("model", state.model)}
if (!getDataValue("deviceId")){ updateDataValue("deviceId", map.model)}
if (!getDataValue("deviceType")){ updateDataValue("deviceType", map.type)}
}
// We get v1 reports not v2
def zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
logging("E12 Received versionv1.VersionReport", "debug")
Double firmware0Version = cmd.applicationVersion + (cmd.applicationSubVersion/ 100)
Double protocolVersion = cmd.zWaveProtocolVersion + (cmd.zWaveProtocolSubVersion / 100)
logging("E12 Version Report - FirmwareVersion: ${firmware0Version}, ProtocolVersion: ${protocolVersion} ${state.model} ","info2")
device.updateDataValue("firmwareVersion", "${firmware0Version}")
device.updateDataValue("protocolVersion", "${protocolVersion}")
device.removeDataValue("hardwareVersion")// We dont get any hardware reports
state.firmwareVersion = firmware0Version
}
def zwaveEvent(hubitat.zwave.Command cmd ){
if (debugLogging){logging("E12.2 Received command Untrapped (${cmd})", "warn")}
}
// we dont get v2 reports but this is stock code for it
def zwaveEvent(hubitat.zwave.commands.versionv2.VersionReport cmd) {
logging("E12.3 Received versionv2.VersionReport", "debug")
}
//==================heating
def FixHeat(){
//state.SetCool
logging("Recovery HEATing Setpoint", "warn")
setHeatingSetpoint(state.SetHeat)
}
def setHeatingSetpoint(degrees, delay = 30000) {
setHeatingSetpoint(degrees.toDouble(), delay)
}
def setHeatingSetpoint(Double degrees, Integer delay = 30000) {
if(onlyMode == "coolonly"){
coolOnly()
return
}
if (state.scale == 1){
scale="F"
deviceScale = 1
}
else {
scale="C"
deviceScale = 0
}
// def deviceScale = state.scale ?: 1
// def deviceScaleString = deviceScale == 2 ? "C" : "F"
def locationScale = getTemperatureScale()
def p = (state.precision == null) ? 1 : state.precision
logging("E14 Hub Scale:${locationScale} Device Scale:${scale}/${state.scale}", "debug")
if (scale !=locationScale){logging("E14 ERROR Hub is set to scale:${locationScale} and thermostat is set to Scale:${scale} Both Must match", "error")}
// def convertedDegrees
// if (locationScale == "C" && deviceScaleString == "F") {
// convertedDegrees = celsiusToFahrenheit(degrees)
// } else if (locationScale == "F" && deviceScaleString == "C") {
// convertedDegrees = fahrenheitToCelsius(degrees)
// } else {
// convertedDegrees = degrees
// }
// state.SetHeat = convertedDegrees
state.SetHeat = Math.round(degrees)// Google is sending 70.1 and RT must be rounded
if(state.SetHeat !=degrees && info2Logging){
logging("*E14 Set Heat Setpoint ${degrees} not supported! Rounded to ${state.SetHeat}", "warn")
}
logging("E14 Set Heat Setpoint ${state.SetHeat} ${scale} --- Reset Last to ${state.SetHeat} ", "info")
sendEvent(name: "SetHeat", value: state.SetHeat, unit:scale ,descriptionText: "Reset Last to ${state.SetHeat} ${state.version}", isStateChange:true)
logging("E14 Sending >> Set (heat type=1) Rounded:${state.SetHeat} scale:#${deviceScale}/${scale} precision:${p} scaledValue:${degrees}- get(temp)", "trace")
delayBetween([
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: deviceScale, precision: p, scaledValue: degrees).format(),
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: deviceScale, precision: p, scaledValue: degrees).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format(),
zwave.sensorMultilevelV3.sensorMultilevelGet().format(),// current temperature
zwave.thermostatModeV2.thermostatModeGet().format(),// mode update dashboard
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(),
], 2500)
}
//==================cooling
def FixCool(){
//state.SetCool
logging("Recovery COOLing Setpoint", "warn")
setCoolingSetpoint(state.SetCool)
}
def setCoolingSetpoint(degrees, delay = 30000) {
logging("Set Cool Setpoint ${degrees} delay:${delay}", "debug")
setCoolingSetpoint(degrees.toDouble(), delay)
}
def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
if(onlyMode == "heatonly"){
heatingOnly()
}
if (state.scale == 1){
scale="F"
deviceScale = 1
}
else {
scale="C"
deviceScale = 0
}
def locationScale = getTemperatureScale()
def p = (state.precision == null) ? 1 : state.precision
logging("E15 Hub Scale:${locationScale} Device Scale:${scale}/${state.scale}", "debug")
if (scale !=locationScale){logging("E15 ERROR Hub is set to scale:${locationScale} and thermostat is set to Scale:${scale} Both Must match", "error")}
// def convertedDegrees
// if (locationScale == "C" && deviceScaleString == "F") {
// convertedDegrees = celsiusToFahrenheit(degrees)
// } else if (locationScale == "F" && deviceScaleString == "C") {
// convertedDegrees = fahrenheitToCelsius(degrees)
// } else {
// convertedDegrees = degrees
// }
// state.SetCool = convertedDegrees
state.SetCool = Math.round(degrees)// Google is sending 70.1 and RT must be rounded
if(state.SetCool !=degrees && info2Logging){
logging("E15 Set Cool Setpoint ${degrees} not supported! Rounded to ${state.SetCool}", "warn")
}
logging("E15 Set Cool Setpoint ${state.SetCool} ${scale} --- Reset Last to ${state.SetCool} ", "info")
sendEvent(name: "SetCool", value: degrees, unit:scale ,descriptionText: "Reset Last to ${state.SetCool} ${scale}${state.version}", isStateChange:true)
logging("E15 Sending >> Set (cool type=2) Rounded:${state.SetCool} scale:#${deviceScale}/${scale} precision:${p} scaledValue:${degrees}- get(temp)", "trace")
delayBetween([
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 2, scale: deviceScale, precision: p, scaledValue: degrees).format(),
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 2, scale: deviceScale, precision: p, scaledValue: degrees).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format(),
zwave.sensorMultilevelV3.sensorMultilevelGet().format(),// current temperature
zwave.thermostatModeV2.thermostatModeGet().format(),// mode update dashboard
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(),
], 2500)
}
def getDataByName(String name) {
state[name] ?: device.getDataValue(name)
}
// receives Hub mode command
def setThermostatMode(String value) {
logging("E16 setThermostatMode ${value}", "debug")
if(value == "off"){ set= 0}
else if(value == "heat"){ set = 1}
else if(value == "cool"){ set = 2}
else if(value == "auto"){ set = 3}
else if(value == "energySaveHeat"){set = 1}
else if(value == "energySaveCool"){set = 2}
else if(value == "emergency heat"){set = 4}
// not working test code
// else if(value == "emergency heat"){
// Etest = device.currentValue("supportedThermostatModes")
// if ("emergency heat" in Etest ){ set = 4}
// else{
// set = 1
// logging("E20 emergency heat not supported", "warn")
// }
// }
// process heat cool or only
else if(value == "heat" && onlyMode == "coolonly"){
coolOnly()
return
}
else if(value == "emergency heat" && onlyMode == "coolonly"){
coolOnly()
return
}
else if(value == "cool" && onlyMode == "heatonly"){
heatingOnly()
return
}
else if(value == "auto"){
if(onlyMode == "heatonly" || onlyMode =="coolonly"){
noAuto()
return
}
}
else {return}
logging("Sending >> thermostatModeSet ${set} Mode:${value} Get(mode,temp)", "trace")
logging("E16 SetMode:${value}", "info")
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: set).format(),
zwave.thermostatModeV2.thermostatModeGet().format(),
zwave.sensorMultilevelV3.sensorMultilevelGet().format(),// current temp
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(),
], 2500)
}
// -------------------------------------mode setting ------------------
// "onlyMode" ["off", "heatonly","coolonly"]
void coolOnly(){
logging("Cooling Only Heat disabled", "info")
state.setHeat = ""
removeDataValue("heatingSetpoint")
removeDataValue("SetHeat")
state.remove("setHeat")
}
void heatingOnly(){
logging("Heating Only Cool disabled", "info")
state.setCool = ""
removeDataValue("coolingSetpoint")
removeDataValue("SetCool")
state.remove("setCool")
}
void noAuto(){logging("When in ${onlyMode} auto disabled", "info") }
def off() {setThermostatMode("off")}
def heat() {setThermostatMode("heat")}
def cool() {setThermostatMode("cool")}
def auto() {setThermostatMode("auto")}
def emergencyHeat() {setThermostatMode("emergency heat")}
def fanOn() {setThermostatFanMode("On")}
def fanAuto() {setThermostatFanMode("Auto")}
def fanCirculate() {setThermostatFanMode("Circulate")}// not supported
// fan settings------------------------------
def setThermostatFanMode(String value) {
logging("E17 setThermostatFanMode ${value}", "debug")
if(value == "Auto"){ set=0}
else if(value == "On"){set=1}
else {
runIn(10,configure) // Unsupported We need to reconfig
return
}
logging("E17 SetFanMode:${value}", "info")
logging("Sending >> thermostatFanModeSet ${set} Mode:${value} Get(FanMode,temp)", "trace")
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: set).format(),
zwave.thermostatModeV2.thermostatModeGet().format(),// mode Do first to set simulated fan state
zwave.thermostatFanModeV3.thermostatFanModeGet().format(),// fan mode
zwave.sensorMultilevelV3.sensorMultilevelGet().format(),// current temp
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(),
], 2500)
}
// Decapsulate command
def zwaveEvent(hubitat.zwave.commands.multiinstancev1.MultiInstanceCmdEncap cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 2])
if (encapsulatedCommand) {
logging("E18 ${encapsulatedCommand}", "debug")
return zwaveEvent(encapsulatedCommand)
}
else {logging("E18 No encapsulatedCommand found", "debug")}
}
// E15
def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
logging("E19 battery ${cmd}", "debug")
state.parameter[14]=1
if (cmd.batteryLevel == 0xFF){ // I have never seen this but its in the spec.
logging("E19 - Power Restored -", "info")
sendEvent(name: "powerSource", value: "mains",descriptionText: "Power Mains ${state.version}", isStateChange: true)
return
}
if(ignorebat==true){
logging("E19 Ignoring battery ${cmd.batteryLevel}% Set to 100%", "debug")
sendEvent(name: "battery", value: 100 ,unit: "%", descriptionText: "${cmd.batteryLevel}% ${state.version}", isStateChange:true)
return
}
logging("E19 battery ${cmd.batteryLevel}% ", "info")
sendEvent(name: "battery", value: cmd.batteryLevel ,unit: "%", descriptionText: "${cmd.batteryLevel}% ${state.version}", isStateChange:true)
}
def setTheClock(){
//logging("${device} : Chron Seting the clock", "debug")
setClock()
}
// Auto set clock code (improved)
// Day is not visiable in ct101 but is on ct30
private setClock() {
// def ageInMinutes = state.lastClockSet ? (nowTime - state.lastClockSet)/60000 : 1440
// if (ageInMinutes >= 60) { // once a hr
// state.lastClockSet = nowTime
def nowTime = new Date().time
def nowCal = Calendar.getInstance(location.timeZone) // get current location timezone
state.LastTimeSet = "${nowCal.getTime().format("EEE MMM dd HH:mm z", location.timeZone)}"
weekday = "${nowCal.getTime().format("EEE", location.timeZone)}" // gives weekday name
// weekdayNo = "${nowCal.getTime().format("V", location.timeZone)}" // gives wekday 1 = mon
// setDay(nowCal.get(Calendar.DAY_OF_WEEK)) // gives us weekday name
theTime ="${weekday} ${nowCal.get(Calendar.HOUR_OF_DAY)}:${nowCal.get(Calendar.MINUTE)}"
weekdayZ = nowCal.get(Calendar.DAY_OF_WEEK) -1 // Gives us zwave weekday code (-1)
if (weekdayZ <1){weekdayZ = 7} // rotate to up 7=sunday
logging("E20 Adjusting clock (${theTime}) ${state.LastTimeSet}", "info")
logging("E20 Sending >> clockSet (hour: ${nowCal.get(Calendar.HOUR_OF_DAY)}, minute: ${nowCal.get(Calendar.MINUTE)}, weekday: ${weekdayZ}) Get(clock,bat)", "trace")
sendEvent(name: "SetClock", value: theTime, descriptionText: "${theTime} ${state.version}",displayed: true, isStateChange:true)
delayBetween([
zwave.clockV1.clockSet(hour: nowCal.get(Calendar.HOUR_OF_DAY), minute: nowCal.get(Calendar.MINUTE), weekday: weekdayZ).format(),
zwave.clockV1.clockGet().format(),
zwave.batteryV1.batteryGet().format()
], 2500)
}
void setDay(day){
// This is the Zwave format day
// The zwave day is 1 less than the hub
if (day==1){weekday="Mon"}
if (day==2){weekday="Tue"}
if (day==3){weekday="Wed"}
if (day==4){weekday="Thu"}
if (day==5){weekday="Fri"}
if (day==6){weekday="Sat"}
if (day==7){weekday="Sun"}
}
def zwaveEvent(hubitat.zwave.commands.clockv1.ClockReport cmd) {
state.parameter[15]=1
setDay(cmd.weekday)
def nowCal = Calendar.getInstance(location.timeZone) // get current location timezone
Timecheck = "${nowCal.getTime().format("EEE MMM dd yyyy HH:mm:ss z", location.timeZone)}"
daycheck = "${nowCal.getTime().format("EEE", location.timeZone)}"
setclock= false
if (weekday != daycheck){
setclock=true
error = "${weekday} <> ${daycheck }"
}
if (cmd.hour != nowCal.get(Calendar.HOUR_OF_DAY)){
setclock=true
error = "${cmd.hour} <> ${nowCal.get(Calendar.HOUR_OF_DAY)} "
}
if (cmd.minute != nowCal.get(Calendar.MINUTE)){
setclock=true
error = "${cmd.minute} <> ${nowCal.get(Calendar.MINUTE)} "
}
if (setclock == false) {logging("E21 Rec clock (${weekday} ${cmd.hour}:${cmd.minute}) ok", "info")}
if (setclock == true) { logging("E21 Rec clock ${weekday} ${cmd.hour}:${cmd.minute}) (out of sync) ${error}", "warn")}
}
def saveSettings(){
logging("Updating Settings", "debug")
runIn(2,setDiff)
runIn(4,setSwing)
runIn(6,setRecovery)
runIn(10,setTheClock)
}
def setDiff(cmd){
if (!state.parameter[8]){ return}
// 2 stage differential (2 to 6) default
coolDiff = (coolDiff as Integer)
heatDiff = (heatDiff as Integer)
if (!coolDiff){coolDiff = 2}
if (!heatDiff){heatDiff = 2}
if (coolDiff >6){coolDiff =2}
if (heatDiff >6){coolDiff =2}
if (coolDiff >2){coolDiff =2}
if (heatDiff >2){coolDiff =2}
state.heatDiff = heatDiff
state.coolDiff = coolDiff
logging("E22 Set (2 stage Differential) Heat:${heatDiff} Cool:${coolDiff}", "info")
logging("E22 Sending >> configurationSet (parameterNumber: 8, size: 2, configurationValue: [0x00, ${heatDiff}]) ", "trace")
logging("E22 Sending >> configurationSet (parameterNumber: 8, size: 2, configurationValue: [0x01, ${coolDiff}]) Get(config 8)", "trace")
delayBetween([
zwave.configurationV2.configurationSet(parameterNumber: 8, size: 2, configurationValue: [0x00, heatDiff]).format(),
zwave.configurationV2.configurationSet(parameterNumber: 8, size: 2, configurationValue: [0x01, coolDiff]).format(),
zwave.configurationV2.configurationGet(parameterNumber: 8).format(),
], 2500)
}
def setSwing(cmd){
if (!state.parameter[7]){ return}
// options: ["0.5","1.0","1.5","2.0","2.5","3.0","3.5","4.0"]
def value = 2
def locationScale = getTemperatureScale()
if (swing == "0.5"){value = 1}
if (swing == "1.0"){value = 2}
if (swing == "1.5"){value = 3}
if (swing == "2.0"){value = 4}
if (swing == "2.5"){value = 5}
if (swing == "3.0"){value = 6}
if (swing == "3.5"){value = 7}
if (swing == "4.0"){value = 8}
logging("E23 Set Temp Swing:${swing} ${locationScale}", "info")
logging("E23 Sending >> configurationSet (parameterNumber: 7, size: 1, configurationValue: [${value}]) Get(config 7)", "trace")
delayBetween([
zwave.configurationV2.configurationSet(parameterNumber: 7, size: 1, configurationValue: [value]).format(),
zwave.configurationV2.configurationGet(parameterNumber: 7).format(),
], 2500)
}
def setRecovery(cmd){
if (!state.parameter[9]){ return}
// ConfigurationReport(parameterNumber: 9, size: 1, configurationValue: [2], scaledConfigurationValue: 2) Fast Recovery
if(!recovery){recovery = 2}
if (recovery == "fast"){value = 1}
if (recovery == "economy"){value = 2}
logging("E24 Set Recovery to:${recovery} ", "info")
logging("E24 Sending >> configurationSet (parameterNumber: 9, size: 1, configurationValue: [${value}]) Get(config 9)", "trace")
delayBetween([
zwave.configurationV2.configurationSet(parameterNumber: 9, size: 1, configurationValue: [value]).format(),
zwave.configurationV2.configurationGet(parameterNumber: 9).format(),
], 2500)
}
//// works with CT200
// ManualFanTimer
// zwave.configurationV1.configurationSet(scaledConfigurationValue: value, parameterNumber: 15, size: 1),
// zwave.configurationV1.configurationGet(parameterNumber: 15),
// zwave.thermostatFanModeV1.thermostatFanModeGet(),
// zwave.thermostatFanStateV1.thermostatFanStateGet()
// SensorCal
// zwave.configurationV1.configurationSet(scaledConfigurationValue: value, parameterNumber: 17, size: 1),
// zwave.configurationV1.configurationGet(parameterNumber: 17)
void getIcons(){
state.icon ="
"
if(state.model =="CT30" || state.model =="CT30e rev.01" || state.model =="CT30e"){state.icon ="
CT30 Info"}
if(state.model =="CT30e bad" ){state.icon ="
CT30e bad Info Bad Firmware"}
if(state.model =="CT32"){state.icon ="
CT32 Info "}
if(state.model =="CT50"){state.icon ="
CT50 Manual " }
if(state.model =="CT80"){state.icon ="
CT80 Info "}
if(state.model =="CT100" || state.model =="CT100 Plus"){state.icon ="
CT100 Info"}
if(state.model =="CT101" || state.model =="CT101 iris"){state.icon ="
CT101 Info"}
if(state.model =="CT110"){state.icon ="
CT110 Info"}// add image
if(state.model =="CT200" || state.model =="CT200 Vivant" || state.model == "CT200x Vivant"){state.icon ="
CT200 Info"}
if(state.model =="CT200x Vivant"){state.icon ="
CT200x Info"}
state.donate="
"
}
// Logging block v4.1
// 4 mode logging mod
void loggingUpdate() {
logging("Logging Info:[${infoLogging}] Debug:[${debugLogging}] Trace:[${traceLogging}]", "infoBypass")
// Only do this when its needed
if (debugLogging){
logging("Debug log:off in 3000s", "warn")
runIn(3000,debugLogOff)
}
if (traceLogging){
logging("Trace log: off in 1800s", "warn")
runIn(1800,traceLogOff)
}
}
void traceLogOff(){
device.updateSetting("traceLogging",[value:"false",type:"bool"])
log.trace "${device} : Trace Logging : Automatically Disabled"
}
void debugLogOff(){
device.updateSetting("debugLogging",[value:"false",type:"bool"])
log.debug "${device} : Debug Logging : Automatically Disabled"
}
private logging(String message, String level) {
if (level == "infoBypass"){log.info "${device} : $message"}
if (level == "error"){ log.error "${device} : $message"}
if (level == "warn") { log.warn "${device} : $message"}
if (level == "trace" && traceLogging) {log.trace "${device} : $message"}
if (level == "debug" && debugLogging) {log.debug "${device} : $message"}
if (level == "info" && infoLogging) {log.info "${device} : $message"}
if (level == "info2" && info2Logging) {log.info "${device} :* $message"}
}
/*
Building a better thermostat driver that just works.....
Radio Thermostat CT30 hubitat driver
Radio Thermostat CT32 hubitat driver
Radio Thermostat CT50 hubitat driver
Radio Thermostat CT80 hubitat driver
Radio Thermostat CT100 hubitat driver
Radio Thermostat CT101 hubitat driver
Radio Thermostat CT110 hubitat driver
Radio Thermostat CT200 hubitat driver
*/