/*
* Eurotronic Spirit TRV driver for Hubitat
*
* Description:
*
*
* Information:
* https://community.hubitat.com/t/eurotronic-air-quality-and-z-wave-spirit-in-association/79841
*
* Credits:
*
* Licensing:
* Copyright 2020-2021 Ravil Rubashkin
* 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.
*
* Version Control:
* 1.0.0 2021-02-06 aelfot Initial version
* 1.1.0 2021-09-20 aelfot latest aelfot version on GitHub
* 2.0.0 2021-12-17 kkossev English language option and translation;
* 2.0.1 2021-12-17 kkossev Added Refresh and Initialize; added forceStateChange option
* 2.0.2 2021-12-17 kkossev Added refreshRate
* 2.0.3 2021-12-18 kkossev Added calibrate function
* 2.0.4 2021-12-18 kkossev calibrate optimization
* 2.0.5 2022-12-16 kkossev SwitchLevel capability removed
* 2.1.0 2023-11-10 kkossev VSC; merged latest aelfor changes; improved logDebug; added level attribute; calibrate retries bug fix; added refresh 30 and 60 minutes; made the polling after temperature change configurable;
* added calibrate as a mode; added logsOff; removed Initialize as capability; implemented health check; added driver vesion to the states;
*
* TODO: implement ping
* TODO: add [Refresh] in the events; add descriptions to the events
* TODO: add lastRunnimngMode ?
* TODO: do not start calibrate if the valve is fully opened or closed ?
*
*/
def version() { "2.1.0" }
def timeStamp() {"2023/11/10 11:59 AM"}
import groovy.transform.Field
import hubitat.helper.HexUtils
import hubitat.device.HubAction
metadata {
definition (name: "Eurotronic Spirit TRV", namespace: "aelfot", author: "Ravil Rubashkin", importUrl: "https://raw.githubusercontent.com/kkossev/hubitat-Aelfot-fork/development/EurotronicSpiritTRV.groovy", singleThreaded: true ) {
capability "Battery"
capability "Thermostat"
capability "Actuator"
capability "Sensor"
capability "TemperatureMeasurement"
capability "Polling"
capability "Refresh"
//capability "Initialize"
capability "HealthCheck"
attribute "healthStatus", "enum", ["offline", "online", "unknown"]
attribute "externeTemperatur", "string"
attribute "Notifity", "string"
attribute "deviceResetLocally", "bool"
attribute "level", "number" // valve position
attribute "lock", "enum", ["locked", "unlocked with timeout", "unlocked", "unknown"]
//command "SendTemperature", [[name: "Temperature", type: "NUMBER", description:""]]
command "initialize"
command "manual"
command "disableLocalOperations" //"lokaleBedinungDeaktiviert"
command "calibrate"
command "lock"
command "unlock"
fingerprint mfr:"0148", prod:"0003", deviceId:"0001", inClusters:"0x5E,0x55,0x98,0x9F"
fingerprint mfr:"0148", prod:"0003", deviceId:"0001", inClusters:"0x5E,0x85,0x59,0x86,0x72,0x5A,0x75,0x31,0x26,0x40,0x43,0x80,0x70,0x71,0x73,0x98,0x9F,0x55,0x6C,0x7A"
}
def batteriestatus = [:]
batteriestatus << [0 : englishLang==true ? "Event-driven" : "Eventgesteuert"]
batteriestatus << [1 : englishLang==true ? "Once per day" : "1 Mal täglich"]
def windowDetectOptions = [:]
windowDetectOptions << [0 : englishLang==true ? "Deactivated" : "Deaktiviert"]
windowDetectOptions << [1 : englishLang==true ? "Low sensitivity" : "Empfindlichkeit niedrig"]
windowDetectOptions << [2 : englishLang==true ? "Medium sensitivity" : "Empfindlichkeit mittel"]
windowDetectOptions << [3 : englishLang==true ? "High sensitivity" : "Empfindlichkeit hoch"]
def refreshRates = [:]
refreshRates << ["0" : englishLang==true ? "Disabled - Set temperature, valve & battery reports, if required" : "Deaktiviert – Temperatur, Valve und Batterieberichte einstellen, falls erforderlich"]
refreshRates << ["1" : englishLang==true ? "Refresh every minute (Not recommended)" : "Jede Minute aktualisieren (Nicht empfohlen)"]
refreshRates << ["5" : englishLang==true ? "Refresh every 5 minutes" : "Alle 5 Minuten aktualisieren"]
refreshRates << ["10" : englishLang==true ? "Refresh every 10 minutes" : "Alle 10 Minuten aktualisieren"]
refreshRates << ["15" : englishLang==true ? "Refresh every 15 minutes" : "Alle 15 Minuten aktualisieren"]
refreshRates << ["30" : englishLang==true ? "Refresh every 30 minutes" : "Alle 30 Minuten aktualisieren"]
refreshRates << ["60" : englishLang==true ? "Refresh every 60 minutes" : "Alle 60 Minuten aktualisieren"]
preferences {
input (name: "txtEnable", type: "bool", title: "Description text logging", description: "Display sensor states on HE log page. The recommended value is true", defaultValue: true)
input (name: "logEnable", type: "bool", title: "Debug logging", description: "Debug information, useful for troubleshooting. The recommended value is false", defaultValue: true)
input name:"englishLang", type:"bool", title: "English Language", description: "Default: Yes", defaultValue:true
if (englishLang==true) {
input name: "parameter1", type:"bool", title: "Invert LCD", description: "Default: No", defaultValue:false
input name: "parameter2", type:"number", title: "LCD Timeout (in secs)", description: "Default: 0-Always on, range 0..30", defaultValue:0, range: "0..30"
input name: "parameter3", type:"bool", title: "Backlight", description: "Default: Deactivated", defaultValue:false
input name: "parameter4", type:"enum", title: "Battery reporting", description: "Default: once a day", defaultValue:1, options: batteriestatus
input name: "parameter5", type:"number", title: "Temperature reporting", description: "Default: 0.5° change, range 0.0..5.0", defaultValue:0.5, range: "0.0..5.0"
input name: "parameter6", type:"number", title: "Valve reporting on % change", description: "Default: 1%, range: 0..100", defaultValue:1, range: "0..100"
input name: "parameter7", type:"enum", title: "Window Open Detection", description: "Default: Medium sensitivity", defaultValue:2, options: windowDetectOptions
input name: "parameter8", type:"number", title: "Temperature offset", description: "Default: no correction. range: -5.0..5.0", defaultValue:0, range: "-5.0..5.0"
input name: "parameter9", type:"bool", title: "Use external temperature sensor?", description: "Default: No", defaultValue:false
input name: "forceStateChange", type:"bool", title: "Force State Change", description: "Default: No (used for better graphs only)", defaultValue:false
input name: "forcePolling", type:"bool", title: "Force TRV polling after changes", description: "Default: No (used for faster status update)", defaultValue:false
input name: "refreshRate", type: "enum", title: "Refresh rate", description: "Select refresh rate", defaultValue: "0", required: false, options: refreshRates
}
else
{
input name: "parameter1", type:"bool", title: "Display invertieren?", description: "Default: Nein", defaultValue:false
input name: "parameter2", type:"number", title: "Display ausschalten nach", description: "Default: Immer an(0)", defaultValue:0, range: "0..30"
input name: "parameter3", type:"bool", title: "Hintergrundbeleuchtung", description: "Default: Deaktiviert", defaultValue:false
input name: "parameter4", type:"enum", title: "Batteryabfrage", description: "Default: 1 mal täglich", defaultValue:1, options: batteriestatus
input name: "parameter5", type:"number", title: "Meldung bei Temperaturdifferenz", description: "Default: bei Delta 0.5°", defaultValue:0.5, range: "0.0..5.0"
input name: "parameter6", type:"number", title: "Meldung bei Valvedifferenz", description: "Default: Deaktiviert", defaultValue:1, range: "0..100"
input name: "parameter7", type:"enum", title: "Fensteroffnungserkennung", description: "Default: Empfindlichkeit mittel", defaultValue:2, options: windowDetectOptions
input name: "parameter8", type:"number", title: "Temperature offset", description: "Default: Keine Korrektur", defaultValue:0, range: "-5.0..5.0"
input name: "parameter9", type:"bool", title: "Temperatur extern bereitgestellt?", description: "Default: Nein", defaultValue:false
input name: "forceStateChange", type:"bool", title: "Force State Change", description: "Default: Nein (nur für bessere Grafiken verwendet)", defaultValue:false
input name: "forcePolling", type:"bool", title: "TRV-Abfrage nach Änderungen erzwingen", description: "Default: Nein (wird für eine schnellere Statusaktualisierung verwendet)", defaultValue:false
input name: "refreshRate", type: "enum", title: "Aktualisierungsrate", description: "Default: Nein", defaultValue: "0", required: false, options: refreshRates
}
}
}
@Field static Map commandClassVersions = [
0x85:2, //Association
0x59:1, //Association Group Information
0x20:1, //Basic
0x80:1, //Battery
0x70:1, //Configuration
0x5A:1, //Device Reset Locally
0x7A:3, //Firmware Update Md V3
0x72:1, //Manufacturer Specific
0x31:5, //Multilevel Sensor
0x26:1, //Multilevel Switch
0x71:8, //Notifikation
0x73:1, //Power Level
0x75:1, //Protection
0x98:2, //Security ohne verschlüsselung
0x40:3, //Thermostat Mode
0x43:3, //Thermostat Setpoint
0x55:2, //Transport Service ohne verschlüsselung
0x86:2, //Version
0x5E:2 //Z-Wave Plus Info ohne verschlüsselung
]
@Field static final Integer pollTimer = 3 // seconds
@Field static final Integer presenceCountTreshold = 4
def parse(String description) {
checkDriverVersion()
setPresent()
def cmd = zwave.parse(description, commandClassVersions)
if (cmd) {
return zwaveEvent(cmd)
} else {
log.debug "Non-parsed event: ${description}"
}
}
void zwaveEvent (hubitat.zwave.commands.notificationv8.NotificationReport cmd) {
logDebug "received NotificationReport: ${cmd}"
def resultat = [:]
resultat.name = "Notifity"
resultat.displayed = true
switch (cmd.notificationType) {
case 0x08:
if (cmd.event == 0x0A) {
resultat.value = englishLang==true ? "Less than 25% battery remaining" : "25% Batterie verbleibend"
} else if (cmd.event == 0x0B) {
resultat.value = englishLang==true ? "Less than 15% battery remaining" : "15% Batterie verbleibend"
} else {
resultat.value = englishLang==true ? "battery was changed" : "Batterie gewechselt"
}
break;
case 0x09:
if (cmd.event == 0x03) {
if (cmd.eventParametersLength != 0) {
switch (cmd.eventParameter[0]) {
case 0x01:
resultat.value = englishLang==true ? "Motor movement not possible" : "Kein Schließpunkt gefunden"
break;
case 0x02:
resultat.value = englishLang==true ? "Not mounted on a valve" : "Keine Ventilbewegung möglich"
break;
case 0x03:
resultat.value = englishLang==true ? "Valve closing point could not be detected" : "Kein Ventilschließpunkt gefunden"
break;
case 0x04:
resultat.value = englishLang==true ? "Piston positioning failed" : "Positionierung fehlgeschlagen"
break;
}
} else {
resultat.value = englishLang==true ? "Valve problem was fixed" : "Der Fehler wurde gerade behoben"
}
}
break;
}
logInfo englishLang ? "Notifikaiton is ${resultat.value}" : "Notifikaiton ist ${resultat.value}"
if (forceStateChange==true) {resultat.isStateChange = true}
sendEvent(resultat)
}
void zwaveEvent (hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointReport cmd) {
logDebug "received ThermostatSetpointReport: ${cmd}"
def resultat = [:]
resultat.value = cmd.scaledValue
resultat.unit = getTemperatureScale()
resultat.displayed = true
if (cmd.setpointType == 0x01) {
resultat.name = "heatingSetpoint"
}
if (cmd.setpointType == 0x0B) {
resultat.name = "coolingSetpoint"
}
resultat.unit = cmd.scale == 1 ? "°F" : "°C"
logInfo englishLang ? "Thermostat report: ${resultat.name} is ${resultat.value} ${resultat.unit}" : "Thermostat hat den ${resultat.name} Report ${resultat.value} ${resultat.unit}"
if (forceStateChange==true) {resultat.isStateChange = true}
sendEvent(resultat)
}
void zwaveEvent (hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
logInfo englishLang ? "Battery report ${cmd.batteryLevel} %" : "batteryreport ist ${cmd.batteryLevel} %"
sendEvent(name:"battery", value: cmd.batteryLevel, unit: "%", displayed: true, isStateChange: true)
}
void zwaveEvent(hubitat.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
logWarn englishLang ? "Device Reset Locally" : "Device Reset Locally"
sendEvent(name:"deviceResetLocally", value: true, displayed = true, isStateChange: true)
sendEvent(name:"Notifity", value:"Deleted")
sendEvent(name:"thermostatMode", value:"off")
sendEvent(name:"level", value:0)
sendEvent(name:"temperature", value:0)
sendEvent(name:"thermostatOperatingState", value: "idle")
sendEvent(name:"coolingSetpoint", value:0)
sendEvent(name:"heatingSetpoint", value:0)
}
void zwaveEvent (hubitat.zwave.commands.protectionv1.ProtectionReport cmd) {
logDebug "received ProtectionReport: ${cmd}"
def resultat = [:]
resultat.name = "lock"
resultat.displayed = true
switch (cmd.protectionState) {
case 0:
resultat.value = "unlocked"
break;
case 1:
resultat.value = "locked"
break;
case 2:
resultat.value = englishLang==true ? "No local operation possible" : "lokale Bedinung deaktiviert"
break;
}
if (forceStateChange==true) {resultat.isStateChange = true}
if (resultat.value != null) {sendEvent(resultat)}
logInfo englishLang ? "protection report is ${resultat.value}" :"protection report ist ${resultat.value}"
}
void zwaveEvent (hubitat.zwave.commands.thermostatmodev3.ThermostatModeReport cmd) {
logDebug "received ThermostatModeReport: ${cmd}"
def resultat = [:]
resultat.name = "thermostatMode"
resultat.displayed = true
switch (cmd.mode) {
case 0:
resultat.value = "off"
break;
case 1:
resultat.value = "heat"
break;
case 11:
resultat.value = "cool"
break;
case 15:
resultat.value = "emergency heat"
break;
case 31:
resultat.value = "manual"
break;
default :
log.warn "Thermostat reported unknown mode ${cmd.mode}"
}
if (forceStateChange==true) {resultat.isStateChange = true}
sendEvent(resultat)
if (true /*parameter6 == 0*/) {
sendToDevice (new hubitat.zwave.commands.sensormultilevelv5.SensorMultilevelGet(sensorType:1)) // temperature
sendToDevice (new hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelGet()) // valve position
}
logInfo englishLang ? "Thermostat reported mode is ${resultat.value}" : "thermostat hat den mode gemeldet ${resultat.value}"
}
void zwaveEvent (hubitat.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
logDebug "received SensorMultilevelReport: ${cmd}"
def resultat = [:]
resultat.value = cmd.scaledSensorValue
// round to one decimal place
resultat.value = Math.round(resultat.value * 10) / 10
resultat.name = "temperature"
resultat.unit = cmd.scale == 1 ? "°F" : "°C"
resultat.displayed = true
logInfo englishLang ? "temperature is ${resultat.value} ${resultat.unit}" : "temperature ist ${resultat.value} ${resultat.unit}"
if (parameter6 == 0) {
def operatingstate = [:]
operatingstate.name = "thermostatOperatingState"
operatingstate.displayed = true
switch (device.currentValue("thermostatMode")) {
case "off":
operatingstate.value = "idle"
break;
case "heat":
if (cmd.scaledSensorValue < device.currentValue("heatingSetpoint").toFloat()) {
operatingstate.value = "heating"
} else if (cmd.scaledSensorValue > device.currentValue("heatingSetpoint").toFloat()) {
operatingstate.value = "cooling"
} else {
operatingstate.value = "idle"
}
break;
case "cool":
if (cmd.scaledSensorValue < device.currentValue("coolingSetpoint").toFloat()) {
operatingstate.value = "heating"
} else if (cmd.scaledSensorValue > device.currentValue("coolingSetpoint").toFloat()) {
operatingstate.value = "cooling"
} else {
operatingstate.value = "idle"
}
break;
case "emergency heat":
operatingstate.value = "pending heat"
break;
case "manual":
operatingstate.value = "vent economizer"
break;
}
sendEvent(operatingstate)
}
sendEvent(resultat)
}
void thermostatLevelAndOperatingStateEvents (valvePos)
{
logDebug "received thermostatLevelAndOperatingStateEvents: ${valvePos}"
def valvePosition = valvePos
def resultat = [:]
resultat.name = "thermostatOperatingState"
resultat.displayed = true
if (valvePosition == 0) {
resultat.value = "idle"
} else if (valvePosition < 10) {
resultat.value = "cooling"
} else {
resultat.value = "heating"
}
logInfo englishLang ? "Valve position is ${valvePosition} %" : "Valveposition ist ${valvePosition} %"
logInfo englishLang ? "Operating state is ${resultat.value}" : "Operating state ist ${resultat.value}"
if (forceStateChange==true) {resultat.isStateChange = true}
sendEvent(name:"level", value: valvePosition, isStateChange: true, unit: "%")
sendEvent(resultat)
}
void zwaveEvent (hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) {
logDebug "received SwitchMultilevelReport: ${cmd}"
thermostatLevelAndOperatingStateEvents(cmd.value)
}
void zwaveEvent(hubitat.zwave.Command cmd) {
logDebug "received Unhandled event ${cmd}"
log.debug englishLang==true ? "${device.displayName}: Unhandled: $cmd" : "${device.displayName}: Unhandled: $cmd"
}
void off() {
logDebug "off"
def cmds = []
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeSet(mode:0x00)
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeGet()
sendToDevice(cmds)
sendEvent(name:"thermostatOperatingState", value: "idle", isStateChange: true)
}
void heat() {
logDebug "heat"
def cmds = []
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeSet(mode:0x01)
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeGet()
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointGet(setpointType:0x01)
sendToDevice(cmds)
}
void cool() {
logDebug "cool"
def cmds = []
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeSet(mode:0x0B)
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeGet()
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointGet(setpointType:0x0B)
sendToDevice(cmds)
}
void emergencyHeat() {
logDebug "emergencyHeat"
def cmds = []
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeSet(mode:0x0F)
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeGet()
sendToDevice(cmds)
sendEvent(name:"thermostatOperatingState", value: "heating", isStateChange: true)
}
void manual() {
logDebug "manual"
def cmds = []
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeSet(mode:0x1F)
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeGet()
cmds << new hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet(value: 0)
cmds << new hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelGet()
sendToDevice(cmds)
}
void zwaveEvent (hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
logDebug "received ConfigurationReport: ${cmd}"
def cmds = []
switch (cmd.parameterNumber) {
case 1:
if ((parameter1 ? 0x01 : 0x00) != cmd.scaledConfigurationValue) {
logInfo englishLang ?"Parameter number ${cmd.parameterNumber} was not set, trying again" : "Parameter nummer ${cmd.parameterNumber} hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:1, size:1, scaledConfigurationValue: parameter1 ? 0x01 : 0x00)
} else {
logInfo englishLang ?"Parameter number ${cmd.parameterNumber} was successfuly set" : "Parameter nummer ${cmd.parameterNumber} hat den Wert erfolgreich übernommen"
}
break;
case 2:
if (Math.round(parameter2).toInteger() != cmd.scaledConfigurationValue) {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was not set, trying again" : "Parameter nummer ${cmd.parameterNumber} hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:2, size:1, scaledConfigurationValue: Math.round(parameter2).toInteger())
} else {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was successfuly set" : "Parameter nummer ${cmd.parameterNumber} hat den Wert erfolgreich übernommen"
state.parameter2 = parameter2
}
break;
case 3:
if ((parameter3 ? 0x01 : 0x00) != cmd.scaledConfigurationValue) {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was not set, trying again" : "Parameter nummer ${cmd.parameterNumber} hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:3, size:1, scaledConfigurationValue: parameter3 ? 0x01 : 0x00)
} else {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was successfuly set" : "Parameter nummer ${cmd.parameterNumber} hat den Wert erfolgreich übernommen"
state.parameter3 = parameter3
}
break;
case 4:
if (parameter4.toInteger() != cmd.scaledConfigurationValue) {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was not set, trying again" : "Parameter nummer ${cmd.parameterNumber} hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:4, size:1, scaledConfigurationValue: parameter4.toInteger())
} else {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was successfuly set" : "Parameter nummer ${cmd.parameterNumber} hat den Wert erfolgreich übernommen"
state.parameter4 = parameter4
}
break;
case 5:
if (Math.round(parameter5.toFloat() * 10).toInteger() != cmd.scaledConfigurationValue) {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was not set, trying again" : "Parameter nummer ${cmd.parameterNumber} hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:5, size:1, scaledConfigurationValue: Math.round(parameter5.toFloat() * 10).toInteger())
} else {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was successfuly set" : "Parameter nummer ${cmd.parameterNumber} hat den Wert erfolgreich übernommen"
state.parameter5 = parameter5
}
break;
case 6:
if (Math.round(parameter6).toInteger() != cmd.scaledConfigurationValue) {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was not set, trying again" : "Parameter nummer ${cmd.parameterNumber} hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:6, size:1, scaledConfigurationValue: Math.round(parameter6).toInteger())
} else {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was successfuly set" : "Parameter nummer ${cmd.parameterNumber} hat den Wert erfolgreich übernommen"
state.parameter6 = parameter6
}
break;
case 7:
if (parameter7.toInteger() != cmd.scaledConfigurationValue) {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was not set, trying again" : "Parameter nummer ${cmd.parameterNumber} hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:7, size:1, scaledConfigurationValue: parameter7.toInteger())
} else {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was successfuly set" : "Parameter nummer ${cmd.parameterNumber} hat den Wert erfolgreich übernommen"
state.parameter7 = parameter7
}
break;
case 8:
if (parameter9) {
if (cmd.scaledConfigurationValue != -128) {
logInfo englishLang ? "Parameter number 9 was not set, trying again" : "Parameter nummer 9 hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:8, size:1, scaledConfigurationValue: -128)
} else {
logInfo englishLang ? "Parameter number 8 was successfuly set" : "Parameter nummer 8 hat den Wert erfolgreich übernommen"
logInfo englishLang ? "Parameter number 9 was successfuly set" : "Parameter nummer 9 hat den Wert erfolgreich übernommen"
state.parameter8 = parameter8
state.parameter9 = parameter9
sendEvent (name: "externeTemperatur", value: "true")
}
} else {
if (cmd.scaledConfigurationValue != Math.round(parameter8.toFloat() * 10).toInteger()) {
logInfo englishLang ? "Parameter number ${cmd.parameterNumber} was not set, trying again" : "Parameter nummer ${cmd.parameterNumber} hat den Wert nich übernommen, erneter Versuch"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:8, size:1, scaledConfigurationValue: Math.round(parameter8.toFloat() * 10).toInteger())
} else {
logInfo englishLang ? "Parameter number 8 was successfuly set" : "Parameter nummer 8 hat den Wert erfolgreich übernommen"
logInfo englishLang ? "Parameter number 9 was successfuly set" : "Parameter nummer 9 hat den Wert erfolgreich übernommen"
state.parameter8 = parameter8
state.parameter9 = parameter9
sendEvent (name: "externeTemperatur", value: "false")
}
}
break;
}
if (cmds != []) {
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationGet(parameterNumber:cmd.parameterNumber)
sendToDevice(cmds)
}
}
void setLevel(nextLevel) {
logDebug "setLevel: ${nextLevel}"
def val = 0
try {
val = nextLevel.toInteger()
} catch (e) {
val = 0
}
if (val < 0) {val = 0}
if (val > 100) {val = 100}
if (device.currentValue("thermostatMode") == "manual") {
def cmds = []
cmds << new hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet(value: val)
cmds << new hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelGet()
sendToDevice(cmds)
logInfo englishLang ? "Valve was set to ${val} %" : "Die Valve wird auf den Wert ${val} gestellt"
} else {
sendToDevice(new hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelGet())
logInfo englishLang ? "Valve opening position can only be set in manual mode" : "Eine Einstellung der Valveöffnung ist nur im manual modus möglich"
}
}
void setCoolingSetpoint(temperature) {
logDebug "setCoolingSetpoint: ${temperature}"
def nextTemperature = getTemperature (temperature,"cool")
sendEvent(name: "coolingSetpoint", value: nextTemperature.toFloat(), displayed: true, unit: "°" + getTemperatureScale())
def cmds = []
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointSet(precision:1, scale:0, scaledValue: nextTemperature, setpointType: 0x0B)
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointGet(setpointType:0x0B)
sendToDevice(cmds)
if (forcePolling==true) {runIn(pollTimer, "poll", [overwrite: true])}
}
void setHeatingSetpoint(temperature) {
logDebug "setHeatingSetpoint: ${temperature}"
def nextTemperature = getTemperature (temperature,"heat")
sendEvent(name: "heatingSetpoint", value: nextTemperature.toFloat(), displayed: true, unit: "°" + getTemperatureScale())
def cmds = []
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointSet(precision:1, scale:0, scaledValue: nextTemperature, setpointType: 0x01)
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointGet(setpointType:0x01)
sendToDevice(cmds)
if (forcePolling==true) {runIn(pollTimer, "poll", [overwrite: true])}
}
private getTemperature (setTemperature, modus) {
logDebug "getTemperature: ${setTemperature} ${modus}"
def currentTemperature = 0
def BigDecimal nextTemperature = 0
if (modus == "cool") {
currentTemperature = device.currentValue("coolingSetpoint").toFloat()
} else {
currentTemperature = device.currentValue("heatingSetpoint").toFloat()
}
if ( Math.abs(currentTemperature - setTemperature) < 0.5 ) {
if (setTemperature > currentTemperature) {
nextTemperature = currentTemperature + 0.5
if (setTemperature >= 28) {
nextTemperature = 28.0
}
}
if (setTemperature < currentTemperature) {
nextTemperature = currentTemperature - 0.5
if (nextTemperature <= 8) {
nextTemperature = 8.0
}
}
if (setTemperature == currentTemperature) {
nextTemperature = setTemperature
}
} else {
def Integer temp = Math.round(setTemperature * 10)
def Integer modul = temp % 5
nextTemperature = temp - modul
if (modul >= 3) {
nextTemperature = nextTemperature + 5
}
nextTemperature = nextTemperature / 10
if (nextTemperature < 8) {nextTemperature = 8}
if (nextTemperature > 28){nextTemperature = 28}
}
return nextTemperature
}
void setThermostatMode(thermostatmode) {
logDebug "setThermostatMode: ${thermostatmode}"
switch (thermostatmode) {
case "emergency heat":
emergencyHeat()
break
case "cool":
cool()
break
case "heat":
heat()
break
case "off":
off()
break
case "auto":
auto()
break
case "manual":
manual()
break
case "calibrate":
calibrate()
break
default:
log.warn "Unknown thermostat mode ${thermostatmode}"
}
if (forcePolling==true) {runIn(pollTimer, "poll", [overwrite: true])}
}
void lock() {
logDebug "lock"
def cmds = []
cmds << new hubitat.zwave.commands.protectionv1.ProtectionSet(protectionState:0x01)
cmds << new hubitat.zwave.commands.protectionv1.ProtectionGet()
sendToDevice(cmds)
}
void unlock() {
logDebug "unlock"
def cmds = []
cmds << new hubitat.zwave.commands.protectionv1.ProtectionSet(protectionState:0x00)
cmds << new hubitat.zwave.commands.protectionv1.ProtectionGet()
sendToDevice(cmds)
}
void disableLocalOperations() {
logDebug "disableLocalOperations"
lokaleBedinungDeaktiviert()
}
void lokaleBedinungDeaktiviert () {
logDebug "lokaleBedinungDeaktiviert"
def cmds = []
cmds << new hubitat.zwave.commands.protectionv1.ProtectionSet(protectionState:0x02)
cmds << new hubitat.zwave.commands.protectionv1.ProtectionGet()
sendToDevice(cmds)
}
void sendConfigurationCommand (List zuErneuerndeParametern) {
logDebug "sendConfigurationCommand: ${zuErneuerndeParametern}"
def cmds = []
if (zuErneuerndeParametern) {
zuErneuerndeParametern.each { k ->
switch (k) {
case 1:
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:k, size:1, scaledConfigurationValue: parameter1 ? 0x01 : 0x00)
logDebug "Parameter 1 hat den Wert ${parameter1 ? 0x01 : 0x00} übermittelt bekommen"
break
case 2:
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:k, size:1, scaledConfigurationValue: Math.round(parameter2.toFloat()).toInteger())
logDebug "Parameter 2 hat den Wert ${Math.round(parameter2.toFloat()).toInteger()} übermittelt bekommen"
break
case 3:
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:k, size:1, scaledConfigurationValue: parameter3 ? 0x01 : 0x00)
logDebug "Parameter 3 hat den Wert ${parameter3 ? 0x01 : 0x00} übermittelt bekommen"
break
case 4:
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:k, size:1, scaledConfigurationValue: parameter4.toInteger())
logDebug "Parameter 4 hat den Wert ${parameter4.toInteger()} übermittelt bekommen"
break
case 5:
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:k, size:1, scaledConfigurationValue: Math.round(parameter5.toFloat() * 10).toInteger())
logDebug "Parameter 5 hat den Wert ${Math.round(parameter5.toFloat() * 10).toInteger()} übermittelt bekommen"
break
case 6:
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:k, size:1, scaledConfigurationValue: Math.round(parameter6.toFloat()).toInteger())
logDebug "Parameter 6 hat den Wert ${Math.round(parameter6.toFloat()).toInteger()} übermittelt bekommen"
break
case 7:
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:k, size:1, scaledConfigurationValue: parameter7.toInteger())
logDebug "Parameter 7 hat den Wert ${parameter7.toInteger()} übermittelt bekommen"
break
case 8:
if (parameter9) {
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:8, size:1, scaledConfigurationValue: -128)
logDebug "Parameter 8 hat den Wert -128 übermittelt bekommen"
} else {
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:8, size:1, scaledConfigurationValue: Math.round(parameter8.toFloat() * 10).toInteger())
logDebug "Parameter 8 hat den Wert ${Math.round(parameter8.toFloat() * 10).toInteger()} übermittelt bekommen"
}
break
default:
logWarn "Falsche Parameternummer für Configuration gesandt"
}
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationGet(parameterNumber:k)
}
sendToDevice(cmds)
}
}
// Constants
@Field static final Integer CALIBRATE_IDLE = 0
@Field static final Integer CALIBRATE_START = 1
@Field static final Integer CALIBRATE_TURN_OFF = 2
@Field static final Integer CALIBRATE_CHECK_IF_TURNED_OFF = 3
@Field static final Integer CALIBRATE_TURN_EMERGENCY_HEAT = 4
@Field static final Integer CALIBRATE_CHECK_IF_TURNED_EMERGENCY_HEAT = 5
@Field static final Integer CALIBRATE_TURN_HEAT = 6
@Field static final Integer CALIBRATE_CHECK_IF_TURNED_HEAT = 7
@Field static final Integer CALIBRATE_END = 8
@Field static final Integer CALIBRATE_RETRIES_NR = 2
def calibrate() {
logInfo "starting calibrate procedure for ${device.displayName} ..."
state.retries = 0
runIn (01, 'calibrateStateMachine', [data: ["state": CALIBRATE_START]])
}
def calibrateStateMachine( Map data ) {
switch (data.state) {
case CALIBRATE_IDLE :
state.retries = 0
logDebug "data.state IDLE"
break
case CALIBRATE_START : // 1 starting the calibration state machine
logDebug "data.state ($data.state) -> start"
state.retries = 0
runIn (01, 'calibrateStateMachine', [data: ["state": CALIBRATE_TURN_EMERGENCY_HEAT]])
break
case CALIBRATE_TURN_EMERGENCY_HEAT : // turn emergencyHeat
logInfo "turning emergency heat..."
log.trace "data.state ($data.state) -> now turning EMERGENCY_HEAT"
emergencyHeat() // open the valve 100%
runIn (10, calibrateStateMachine, [data: ["state": CALIBRATE_CHECK_IF_TURNED_EMERGENCY_HEAT]])
break
case CALIBRATE_CHECK_IF_TURNED_EMERGENCY_HEAT :
if (device.currentValue("thermostatMode") == "emergency heat" ) { // TRV has been successfuly swithed to emergency heat in the previous step
state.retries = 0
runIn (1, calibrateStateMachine, [data: ["state": CALIBRATE_TURN_OFF]])
} else if (state.retries < CALIBRATE_RETRIES_NR) { // retry
state.retries = state.retries +1
logWarn "ERROR turning emergency heat - retrying...($state.retries)"
runIn (5, calibrateStateMachine, [data: ["state": CALIBRATE_TURN_EMERGENCY_HEAT]])
} else {
log.error "ERROR turning emergency heat - GIVING UP!... state is($data.state)"
state.retries = 0
runIn (3, calibrateStateMachine, [data: ["state": CALIBRATE_TURN_HEAT]])
}
break
case CALIBRATE_TURN_OFF : // turn off
logInfo "turning off..."
off() // close the valve 100%
logDebug "data.state ($data.state) -> now turning OFF"
runIn (10, calibrateStateMachine, [data: ["state": CALIBRATE_CHECK_IF_TURNED_OFF]])
break
case CALIBRATE_CHECK_IF_TURNED_OFF :
if (device.currentValue("thermostatMode") == "off" ) { // TRV was successfuly turned off in the previous step
state.retries = 0
runIn (1, calibrateStateMachine, [data: ["state": CALIBRATE_TURN_HEAT]])
}
else if (state.retries < CALIBRATE_RETRIES_NR) { // retry
state.retries = state.retries + 1
logWarn "ERROR turning OFF - retrying...($state.retries )"
runIn (5, calibrateStateMachine, [data: ["state": CALIBRATE_TURN_OFF]])
}
else {
log.error "ERROR turning OFF - GIVING UP!...state is ($data.state)"
state.retries = 0
runIn (3, calibrateStateMachine, [data: ["state": CALIBRATE_TURN_HEAT]])
}
break
case CALIBRATE_TURN_HEAT : // turn heat (auto)
logInfo "restoring back to heat/auto..."
logDebug "data.state ($data.state) -> now turning heat/auto"
heat() // back to heat mode
runIn (10, calibrateStateMachine, [data: ["state": CALIBRATE_CHECK_IF_TURNED_HEAT]])
break
case CALIBRATE_CHECK_IF_TURNED_HEAT :
if (device.currentValue("thermostatMode") == "heat" ) { // TRV has been successfuly turned to heat mode in the previous step
state.retries = 0
runIn (1, calibrateStateMachine, [data: ["state": CALIBRATE_END]])
}
else if (state.retries < CALIBRATE_RETRIES_NR ) { // retry
state.retries = state.retries +1
logWarn "ERROR turning heat - retrying...($state.retries)"
runIn (5, calibrateStateMachine, [data: ["state": CALIBRATE_TURN_HEAT]])
}
else {
state.retries = 0
log.error "ERROR turning emergencyHeat - GIVING UP !... state is($data.state)"
runIn (3, calibrateStateMachine, [data: ["state": CALIBRATE_END]])
}
break
case CALIBRATE_END : // verify if back to heat (auto)
if (device.currentValue("thermostatMode") == "heat" ) { // TRV has been successfuly turned to heat/auto
logInfo "calibratrion finished successfuly"
logDebug "data.state ($data.state) -> finished successfuly"
}
else {
log.error "ERROR CALIBRATE_END - GIVING UP!... state is ($data.state)"
}
state.retries = 0
unschedule(calibrateStateMachine)
break
default :
log.error "state calibrate UNKNOWN = ${data.state}"
state.retries = 0
unschedule(calibrateStateMachine)
break
}
}
void updated() {
log.info "Device ${device.label?device.label:device.name} is updated"
scheduleDeviceHealthCheck()
if (logEnable==true) {
runIn(86400, logsOff, [overwrite: true]) // turn off debug logging after 24 hours
logInfo "Debug logging will be turned off after 24 hours"
}
else {
unschedule(logsOff)
}
def cmds = []
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:1, size:1, scaledConfigurationValue: parameter1 ? 0x01 : 0x00)
logInfo englishLang ? "Parameter 1 will be set to ${parameter1 ? 0x01 : 0x00}" : "Parameter 1 hat den Wert ${parameter1 ? 0x01 : 0x00} übermittelt bekommen"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:2, size:1, scaledConfigurationValue: Math.round(parameter2.toFloat()).toInteger())
logInfo englishLang ? "Parameter 2 will be set to ${Math.round(parameter2.toFloat()).toInteger()}" : "Parameter 2 hat den Wert ${Math.round(parameter2.toFloat()).toInteger()} übermittelt bekommen"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:3, size:1, scaledConfigurationValue: parameter3 ? 0x01 : 0x00)
logInfo englishLang ? "Parameter 3 will be set to ${parameter3 ? 0x01 : 0x00}" : "Parameter 3 hat den Wert ${parameter3 ? 0x01 : 0x00} übermittelt bekommen"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:4, size:1, scaledConfigurationValue: parameter4.toInteger())
logInfo englishLang ? "Parameter 4 will be set to ${parameter4.toInteger()}" : "Parameter 4 hat den Wert ${parameter4.toInteger()} übermittelt bekommen"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:5, size:1, scaledConfigurationValue: Math.round(parameter5.toFloat() * 10).toInteger())
logInfo englishLang ? "Parameter 5 will be set to ${Math.round(parameter5.toFloat() * 10).toInteger()}" : "Parameter 5 hat den Wert ${Math.round(parameter5.toFloat() * 10).toInteger()} übermittelt bekommen"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:6, size:1, scaledConfigurationValue: Math.round(parameter6.toFloat()).toInteger())
logInfo englishLang ? "Parameter 6 will be set to ${Math.round(parameter6.toFloat()).toInteger()}" : "Parameter 6 hat den Wert ${Math.round(parameter6.toFloat()).toInteger()} übermittelt bekommen"
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:7, size:1, scaledConfigurationValue: parameter7.toInteger())
logInfo englishLang ? "Parameter 7 will be set to ${parameter7.toInteger()}" : "Parameter 7 hat den Wert ${parameter7.toInteger()} übermittelt bekommen"
if (parameter9) {
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:8, size:1, scaledConfigurationValue: -128)
logInfo englishLang ? "Parameter 8 will be set to -128" : "Parameter 8 hat den Wert -128 übermittelt bekommen"
} else {
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber:8, size:1, scaledConfigurationValue: Math.round(parameter8.toFloat() * 10).toInteger())
logInfo englishLang ? "Parameter 8 will be set to ${Math.round(parameter8.toFloat() * 10).toInteger()}" : "Parameter 8 hat den Wert ${Math.round(parameter8.toFloat() * 10).toInteger()} übermittelt bekommen"
}
for (int i=1 ; i<=8 ; i++) {
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationGet(parameterNumber: i)
}
sendToDevice(cmds)
autoRefresh()
}
void installed() {
log.info "Device ${device.label?device.label:device.name} is installed"
sendEvent(name:"Notifity", value:"Installed", displayed: true)
sendEvent(name:"deviceResetLocally", value:false, displayed: true)
sendEvent(name:"supportedThermostatFanModes", value: groovy.json.JsonOutput.toJson(["circulate"]), isStateChange: true)
sendEvent(name:"supportedThermostatModes", value: groovy.json.JsonOutput.toJson(["off", "heat", "emergency heat", "cool", "manual", "calibrate"]), isStateChange: true)
def cmds = []
cmds << new hubitat.zwave.commands.protectionv1.ProtectionGet()
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointGet(setpointType:0x01)
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointGet(setpointType:0x0B)
cmds << new hubitat.zwave.commands.batteryv1.BatteryGet()
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeGet()
cmds << new hubitat.zwave.commands.sensormultilevelv5.SensorMultilevelGet(sensorType:1)
for (int i=1 ; i<=8 ; i++) {
cmds << new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber: i, defaultValue: true)
logInfo englishLang ? "Parameter number ${i} is reset" : "Parameter nummer ${i} ist zurückgesetzt"
}
sendToDevice(cmds)
}
def setDeviceLimits() { // for google and amazon compatability
sendEvent(name:"minHeatingSetpoint", value: settings.tempMin ?: 8, unit: "°C", isStateChange: true, displayed: false)
sendEvent(name:"maxHeatingSetpoint", value: settings.tempMax ?: 28, unit: "°C", isStateChange: true, displayed: false)
logDebug "setDeviceLimits - device max/min set"
}
def logsOff(){
if (settings?.logEnable) log.info "${device.displayName} debug logging disabled..."
device.updateSetting("logEnable",[value:"false",type:"bool"])
}
def initialize() {
log.info "initialize..."
state.retries = 0
setDeviceLimits()
installed()
}
void sendToDevice(List cmds, Long delay=1000) {
logDebug "sendToDevice: $cmds"
sendHubCommand(new hubitat.device.HubMultiAction(commands(cmds, delay), hubitat.device.Protocol.ZWAVE))
}
void sendToDevice(hubitat.zwave.Command cmd, Long delay=1000) {
logDebug "sendToDevice: $cmd"
sendHubCommand(new hubitat.device.HubAction(zwaveSecureEncap(cmd.format()), hubitat.device.Protocol.ZWAVE))
}
List commands(List cmds, Long delay=1000) {
logDebug "sendToDevice: $cmds"
return delayBetween(cmds.collect{ zwaveSecureEncap(it.format()) }, delay)
}
void fanOn() {
logDebug "fanOn"
sendToDevice (new hubitat.zwave.commands.batteryv1.BatteryGet())
logInfo "Battery wird abgefragt"
}
void auto() {
logWarn "auto is not implemented!"
}
void fanAuto() {
logWarn "fanAuto is not implemented!"
}
void fanCirculate() {
logDebug "fanCirculate"
sendEvent(name: "thermostatFanMode", value: "circulate", displayed: true)
}
void setThermostatFanMode(fanmode) {
logDebug "setThermostatFanMode: ${fanmode}"
sendEvent(name: "thermostatFanMode", value: "circulate", displayed: true)
}
void ExternalSensorTemperature(temperature) {
logDebug "ExternalSensorTemperature: ${temperature}"
def Integer x = Math.round(temperature * 100) % 256
def Integer y = (Math.round(temperature * 100) - x) / 256
sendToDevice(new hubitat.zwave.commands.sensormultilevelv10.SensorMultilevelReport(precision:2,scale:0,sensorType:1,sensorValue:[y,x],size:2,scaledSensorValue:(Math.round(temperature * 100)/100).toBigDecimal()))
}
void poll() {
logDebug "poll"
def cmds = []
cmds << new hubitat.zwave.commands.batteryv1.BatteryGet()
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeGet()
cmds << new hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelGet()
sendToDevice(cmds)
}
void refresh() {
def cmds = []
cmds << new hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelGet() // valve + simulated OperatingState calculation depending on valve % open
cmds << new hubitat.zwave.commands.sensormultilevelv5.SensorMultilevelGet(sensorType:1) // temperature
cmds << new hubitat.zwave.commands.thermostatmodev3.ThermostatModeGet() // operation mode (heat, cool, ...)
cmds << new hubitat.zwave.commands.thermostatsetpointv3.ThermostatSetpointGet(setpointType:0x01) // heatingSetpoint
sendToDevice(cmds)
logInfo "Refreshing..."
}
void autoRefresh() {
logDebug "autoRefresh"
unschedule(refresh)
if (refreshRate != null ) {
switch(refreshRate) {
case "1" :
runEvery1Minute(refresh)
break
case "5" :
runEvery5Minutes(refresh)
break
case "10" :
runEvery10Minutes(refresh)
break
case "15" :
runEvery15Minutes(refresh)
break
case "30" :
runEvery30Minutes(refresh)
break
case "60" :
runEvery1Hour(refresh)
break
case "0" :
default :
unschedule(refresh)
log.info "Auto Refresh off"
return
}
logInfo "Refresh Scheduled for every ${refreshRate} minutes"
}
}
def driverVersionAndTimeStamp() {version()+' '+timeStamp()}
def checkDriverVersion() {
if (state.driverVersion == null || driverVersionAndTimeStamp() != state.driverVersion) {
logInfo "updating the settings from the current driver version ${state.driverVersion} to the new version ${driverVersionAndTimeStamp()}"
scheduleDeviceHealthCheck()
state.driverVersion = driverVersionAndTimeStamp()
}
}
void scheduleDeviceHealthCheck() {
Random rnd = new Random()
//schedule("1 * * * * ? *", 'deviceHealthCheck') // for quick test
schedule("${rnd.nextInt(59)} ${rnd.nextInt(59)} 1/3 * * ? *", 'deviceHealthCheck')
}
// called when any event was received from the Zigbee device in parse() method..
def setPresent() {
if ((device.currentValue("healthStatus") ?: "unknown") != "online") {
sendHealthStatusEvent("online")
logInfo "is present"
}
state.notPresentCounter = 0
}
def deviceHealthCheck() {
state.notPresentCounter = (state.notPresentCounter ?: 0) + 1
if (state.notPresentCounter > presenceCountTreshold) {
if ((device.currentValue("healthStatus", true) ?: "unknown") != "offline" ) {
sendHealthStatusEvent("offline")
if (settings?.txtEnable) { log.warn "${device.displayName} is not present!" }
// TODO - send alarm ?
}
}
else {
logDebug "deviceHealthCheck - online (notPresentCounter=${state.notPresentCounter})"
}
}
def sendHealthStatusEvent(value) {
sendEvent(name: "healthStatus", value: value, descriptionText: "${device.displayName} healthStatus set to $value")
}
def logDebug(msg) {
if (settings?.logEnable) {
log.debug "${device.displayName} " + msg
}
}
def logInfo(msg) {
if (settings?.txtEnable) {
log.info "${device.displayName} " + msg
}
}
def logWarn(msg) {
if (settings?.txtEnable) {
log.warn "${device.displayName} " + msg
}
}