Compare commits

..

3 Commits

6 changed files with 116 additions and 122 deletions

View File

@@ -120,7 +120,7 @@ def setInstallSmartApp(value){
} }
def parse(String description) { def parse(String description) {
log.debug description
def description_map = parseDescriptionAsMap(description) def description_map = parseDescriptionAsMap(description)
def event_name = "" def event_name = ""
def measurement_map = [ def measurement_map = [
@@ -129,10 +129,7 @@ def parse(String description) {
zigbeedeviceid: device.zigbeeId, zigbeedeviceid: device.zigbeeId,
created: new Date().time /1000 as int created: new Date().time /1000 as int
] ]
if (description_map.cluster == "0000"){ if (description_map.cluster == "0001"){
/* version number, not used */
} else if (description_map.cluster == "0001"){
/* battery voltage in mV (device needs minimium 2.1v to run) */ /* battery voltage in mV (device needs minimium 2.1v to run) */
log.debug "PlantLink - id ${device.zigbeeId} battery ${description_map.value}" log.debug "PlantLink - id ${device.zigbeeId} battery ${description_map.value}"
event_name = "battery_status" event_name = "battery_status"
@@ -158,6 +155,10 @@ def parse(String description) {
def parseDescriptionAsMap(description) { def parseDescriptionAsMap(description) {
(description - "read attr - ").split(",").inject([:]) { map, param -> (description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":") def nameAndValue = param.split(":")
if(nameAndValue.length == 2){
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()] map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}else{
map += []
}
} }
} }

View File

@@ -30,7 +30,6 @@ metadata {
command "lowerSetpoint" command "lowerSetpoint"
command "resumeProgram" command "resumeProgram"
command "switchMode" command "switchMode"
command "switchFanMode"
attribute "thermostatSetpoint","number" attribute "thermostatSetpoint","number"
attribute "thermostatStatus","string" attribute "thermostatStatus","string"
@@ -64,9 +63,10 @@ metadata {
state "updating", label:"Working", icon: "st.secondary.secondary" state "updating", label:"Working", icon: "st.secondary.secondary"
} }
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") { standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
state "auto", action:"switchFanMode", nextState: "updating", icon: "st.thermostat.fan-auto" state "auto", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "on"
state "on", action:"switchFanMode", nextState: "updating", icon: "st.thermostat.fan-on" state "on", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "off"
state "updating", label:"Working", icon: "st.secondary.secondary" state "off", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "circulate"
state "circulate", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "auto"
} }
standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") { standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
state "setpoint", action:"raiseSetpoint", icon:"st.thermostat.thermostat-up" state "setpoint", action:"raiseSetpoint", icon:"st.thermostat.thermostat-up"
@@ -96,14 +96,14 @@ metadata {
state "default", action:"refresh.refresh", icon:"st.secondary.refresh" state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
} }
standardTile("resumeProgram", "device.resumeProgram", inactiveLabel: false, decoration: "flat") { standardTile("resumeProgram", "device.resumeProgram", inactiveLabel: false, decoration: "flat") {
state "resume", action:"resumeProgram", nextState: "updating", label:'Resume', icon:"st.samsung.da.oven_ic_send" state "resume", action:"resumeProgram", nextState: "updating", label:'Resume Schedule', icon:"st.samsung.da.oven_ic_send"
state "updating", label:"Working", icon: "st.secondary.secondary" state "updating", label:"Working", icon: "st.secondary.secondary"
} }
valueTile("humidity", "device.humidity", decoration: "flat") { valueTile("humidity", "device.humidity", decoration: "flat") {
state "humidity", label:'${currentValue}%' state "humidity", label:'${currentValue}% humidity'
} }
main "temperature" main "temperature"
details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","resumeProgram", "humidity", "refresh"]) details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "resumeProgram", "refresh", "humidity"])
} }
preferences { preferences {
@@ -154,9 +154,6 @@ def generateEvent(Map results) {
} else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){ } else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){
isChange = isStateChange(device, name, value.toString()) isChange = isStateChange(device, name, value.toString())
event << [value: value.toString(), isStateChange: isChange, displayed: false] event << [value: value.toString(), isStateChange: isChange, displayed: false]
} else if (name=="thermostatFanMode"){
isChange = isStateChange(device, name, value.toString())
event << [value: value.toString(), isStateChange: isChange, displayed: false]
} else if (name=="humidity") { } else if (name=="humidity") {
isChange = isStateChange(device, name, value.toString()) isChange = isStateChange(device, name, value.toString())
event << [value: value.toString(), isStateChange: isChange, displayed: false, unit: "%"] event << [value: value.toString(), isStateChange: isChange, displayed: false, unit: "%"]
@@ -204,11 +201,11 @@ private getThermostatDescriptionText(name, value, linkText) {
void setHeatingSetpoint(setpoint) { void setHeatingSetpoint(setpoint) {
log.debug "***heating setpoint $setpoint" log.debug "***heating setpoint $setpoint"
def heatingSetpoint = setpoint def heatingSetpoint = setpoint.toDouble()
def coolingSetpoint = device.currentValue("coolingSetpoint") def coolingSetpoint = device.currentValue("coolingSetpoint").toDouble()
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint") def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint").toDouble()
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint") def minHeatingSetpoint = device.currentValue("minHeatingSetpoint").toDouble()
//enforce limits of heatingSetpoint //enforce limits of heatingSetpoint
if (heatingSetpoint > maxHeatingSetpoint) { if (heatingSetpoint > maxHeatingSetpoint) {
@@ -241,11 +238,11 @@ void setHeatingSetpoint(setpoint) {
void setCoolingSetpoint(setpoint) { void setCoolingSetpoint(setpoint) {
log.debug "***cooling setpoint $setpoint" log.debug "***cooling setpoint $setpoint"
def heatingSetpoint = device.currentValue("heatingSetpoint") def heatingSetpoint = device.currentValue("heatingSetpoint").toDouble()
def coolingSetpoint = setpoint def coolingSetpoint = setpoint.toDouble()
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint") def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint").toDouble()
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint") def minCoolingSetpoint = device.currentValue("minCoolingSetpoint").toDouble()
if (coolingSetpoint > maxCoolingSetpoint) { if (coolingSetpoint > maxCoolingSetpoint) {
@@ -306,7 +303,7 @@ def modes() {
} }
def fanModes() { def fanModes() {
["on", "auto"] ["off", "on", "auto", "circulate"]
} }
def switchMode() { def switchMode() {
@@ -335,15 +332,17 @@ def switchFanMode() {
def returnCommand def returnCommand
switch (currentFanMode) { switch (currentFanMode) {
case "on": case "fanAuto":
returnCommand = switchToFanMode("auto") returnCommand = switchToFanMode("fanOn")
break break
case "auto": case "fanOn":
returnCommand = switchToFanMode("on") returnCommand = switchToFanMode("fanCirculate")
break
case "fanCirculate":
returnCommand = switchToFanMode("fanAuto")
break break
} }
if(!currentFanMode) { returnCommand = switchToFanMode("auto") } if(!currentFanMode) { returnCommand = switchToFanMode("fanOn") }
returnCommand returnCommand
} }
@@ -352,20 +351,25 @@ def switchToFanMode(nextMode) {
log.debug "switching to fan mode: $nextMode" log.debug "switching to fan mode: $nextMode"
def returnCommand def returnCommand
if(nextMode == "auto") { if(nextMode == "fanAuto") {
if(!fanModes.contains("auto")) { if(!fanModes.contains("fanAuto")) {
returnCommand = fanAuto() returnCommand = fanAuto()
} else { } else {
returnCommand = switchToFanMode("on") returnCommand = switchToFanMode("fanOn")
} }
} else if(nextMode == "on") { } else if(nextMode == "fanOn") {
if(!fanModes.contains("on")) { if(!fanModes.contains("fanOn")) {
returnCommand = fanOn() returnCommand = fanOn()
} else { } else {
returnCommand = switchToFanMode("auto") returnCommand = switchToFanMode("fanCirculate")
}
} else if(nextMode == "fanCirculate") {
if(!fanModes.contains("fanCirculate")) {
returnCommand = fanCirculate()
} else {
returnCommand = switchToFanMode("fanAuto")
} }
} }
returnCommand returnCommand
} }
@@ -375,10 +379,13 @@ def getDataByName(String name) {
def setThermostatMode(String value) { def setThermostatMode(String value) {
log.debug "setThermostatMode({$value})" log.debug "setThermostatMode({$value})"
} }
def setThermostatFanMode(String value) { def setThermostatFanMode(String value) {
log.debug "setThermostatFanMode({$value})" log.debug "setThermostatFanMode({$value})"
} }
def generateModeEvent(mode) { def generateModeEvent(mode) {
@@ -465,44 +472,22 @@ def auto() {
def fanOn() { def fanOn() {
log.debug "fanOn" log.debug "fanOn"
String fanMode = "on" // parent.setFanMode (this,"on")
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint")
def deviceId = device.deviceNetworkId.split(/\./).last()
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
if (parent.setFanMode(this, heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
generateFanModeEvent(fanMode)
} else {
log.debug "Error setting new mode."
def currentFanMode = device.currentState("thermostatFanMode")?.value
generateModeEvent(currentFanMode) // reset the tile back
}
} }
def fanAuto() { def fanAuto() {
log.debug "fanAuto" log.debug "fanAuto"
String fanMode = "auto" // parent.setFanMode (this,"auto")
def heatingSetpoint = device.currentValue("heatingSetpoint") }
def coolingSetpoint = device.currentValue("coolingSetpoint")
def deviceId = device.deviceNetworkId.split(/\./).last()
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite" def fanCirculate() {
log.debug "fanCirculate"
// parent.setFanMode (this,"circulate")
}
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint def fanOff() {
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint log.debug "fanOff"
// parent.setFanMode (this,"off")
if (parent.setFanMode(this, heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
generateFanModeEvent(fanMode)
} else {
log.debug "Error setting new mode."
def currentFanMode = device.currentState("thermostatFanMode")?.value
generateModeEvent(currentFanMode) // reset the tile back
}
} }
def generateSetpointEvent() { def generateSetpointEvent() {
@@ -533,7 +518,6 @@ def generateSetpointEvent() {
coolingSetpoint = roundC(coolingSetpoint) coolingSetpoint = roundC(coolingSetpoint)
} }
sendEvent("name":"maxHeatingSetpoint", "value":maxHeatingSetpoint, "unit":location.temperatureScale) sendEvent("name":"maxHeatingSetpoint", "value":maxHeatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"maxCoolingSetpoint", "value":maxCoolingSetpoint, "unit":location.temperatureScale) sendEvent("name":"maxCoolingSetpoint", "value":maxCoolingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"minHeatingSetpoint", "value":minHeatingSetpoint, "unit":location.temperatureScale) sendEvent("name":"minHeatingSetpoint", "value":minHeatingSetpoint, "unit":location.temperatureScale)

View File

@@ -29,7 +29,6 @@ metadata {
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326-L", deviceJoinName: "Iris Motion Sensor"
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor"
} }

View File

@@ -27,7 +27,6 @@ metadata {
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300-S" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300-S"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3320-L", deviceJoinName: "Iris Contact Sensor"
} }
simulator { simulator {

View File

@@ -25,7 +25,6 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "Outlet"
} }
tiles(scale: 2) { tiles(scale: 2) {

View File

@@ -257,16 +257,21 @@ def getEcobeeThermostats() {
} }
} else { } else {
log.debug "http status: ${resp.status}" log.debug "http status: ${resp.status}"
} //refresh the auth token
} if (resp.data.status.code == 14) {
} catch (groovyx.net.http.HttpResponseException e) { log.debug "Storing the failed action to try later"
log.trace "Exception polling children: " + e.response.data.status
if (e.response.data.status.code == 14) {
atomicState.action = "getEcobeeThermostats" atomicState.action = "getEcobeeThermostats"
log.debug "Refreshing your auth_token!" log.debug "Refreshing your auth_token!"
refreshAuthToken() refreshAuthToken()
} else {
log.error "Authentication error, invalid authentication method, lack of credentials, etc."
} }
} }
}
} catch(Exception e) {
log.debug "___exception getEcobeeThermostats(): " + e
refreshAuthToken()
}
atomicState.thermostats = stats atomicState.thermostats = stats
return stats return stats
} }
@@ -417,8 +422,7 @@ def pollChildren(child = null) {
heatingSetpoint: stat.runtime.desiredHeat / 10, heatingSetpoint: stat.runtime.desiredHeat / 10,
coolingSetpoint: stat.runtime.desiredCool / 10, coolingSetpoint: stat.runtime.desiredCool / 10,
thermostatMode: stat.settings.hvacMode, thermostatMode: stat.settings.hvacMode,
humidity: stat.runtime.actualHumidity, humidity: stat.runtime.actualHumidity
thermostatFanMode: stat.runtime.desiredFanMode
] ]
if (location.temperatureScale == "F") if (location.temperatureScale == "F")
@@ -445,15 +449,23 @@ def pollChildren(child = null) {
} }
result = true result = true
log.debug "updated ${atomicState.thermostats?.size()} stats: ${atomicState.thermostats}" log.debug "updated ${atomicState.thermostats?.size()} stats: ${atomicState.thermostats}"
} } else {
} log.error "polling children & got http status ${resp.status}"
} catch (groovyx.net.http.HttpResponseException e) {
log.trace "Exception polling children: " + e.response.data.status //refresh the auth token
if (e.response.data.status.code == 14) { if (resp.data.status.code == 14) {
atomicState.action = "pollChildren" atomicState.action = "pollChildren"
log.debug "Refreshing your auth_token!" log.debug "Refreshing your auth_token!"
refreshAuthToken() refreshAuthToken()
} }
else {
log.error "Authentication error, invalid authentication method, lack of credentials, etc."
}
}
}
} catch(Exception e) {
log.debug "___exception polling children: " + e
refreshAuthToken()
} }
return result return result
} }
@@ -629,14 +641,16 @@ private refreshAuthToken() {
} }
atomicState.action = "" atomicState.action = ""
} else {
log.debug "refresh failed ${resp.status} : ${resp.status.code}"
} }
} }
} catch (groovyx.net.http.HttpResponseException e) { } catch (groovyx.net.http.HttpResponseException e) {
log.error "refreshAuthToken() >> Error: e.statusCode ${e.statusCode}" log.error "refreshAuthToken() >> Error: e.statusCode ${e.statusCode}"
def reAttemptPeriod = 300 // in sec def reAttemptPeriod = 300 // in sec
if (e.statusCode != 401) { // this issue might comes from exceed 20sec app execution, connectivity issue etc. if (e.statusCode != 401) { //this issue might comes from exceed 20sec app execution, connectivity issue etc.
runIn(reAttemptPeriod, "refreshAuthToken") runIn(reAttemptPeriod, "refreshAuthToken")
} else if (e.statusCode == 401) { // unauthorized } else if (e.statusCode == 401) { //refresh token is expired
atomicState.reAttempt = atomicState.reAttempt + 1 atomicState.reAttempt = atomicState.reAttempt + 1
log.warn "reAttempt refreshAuthToken to try = ${atomicState.reAttempt}" log.warn "reAttempt refreshAuthToken to try = ${atomicState.reAttempt}"
if (atomicState.reAttempt <= 3) { if (atomicState.reAttempt <= 3) {
@@ -662,19 +676,9 @@ def setHold(child, heating, cooling, deviceId, sendHoldType) {
int h = heating * 10 int h = heating * 10
int c = cooling * 10 int c = cooling * 10
def jsonRequestBody = '{"selection":{"selectionType":"thermostats","selectionMatch":"' + deviceId + '","includeRuntime":true},"functions": [{ "type": "setHold", "params": { "coolHoldTemp": '+c+',"heatHoldTemp": '+h+', "holdType": '+sendHoldType+' } } ]}' def jsonRequestBody = '{"selection":{"selectionType":"thermostats","selectionMatch":"' + deviceId + '","includeRuntime":true},"functions": [{ "type": "setHold", "params": { "coolHoldTemp": '+c+',"heatHoldTemp": '+h+', "holdType": '+sendHoldType+' } } ]}'
def result = sendJson(child, jsonRequestBody)
return result
}
def setFanMode(child, heating, cooling, deviceId, sendHoldType, fanMode) {
int h = heating * 10
int c = cooling * 10
def jsonRequestBody = '{"selection":{"selectionType":"thermostats","selectionMatch":"' + deviceId + '","includeRuntime":true},"functions": [{ "type": "setHold", "params": { "coolHoldTemp": '+c+',"heatHoldTemp": '+h+', "holdType": '+sendHoldType+', "fan": '+fanMode+' } } ]}'
def result = sendJson(child, jsonRequestBody) def result = sendJson(child, jsonRequestBody)
return result return result
} }
@@ -709,21 +713,29 @@ def sendJson(child = null, String jsonBody) {
log.debug "Error return code = ${resp.data.status.code}" log.debug "Error return code = ${resp.data.status.code}"
debugEvent("Error return code = ${resp.data.status.code}") debugEvent("Error return code = ${resp.data.status.code}")
} }
} } else {
} log.error "sent Json & got http status ${resp.status} - ${resp.status.code}"
} catch (groovyx.net.http.HttpResponseException e) { debugEvent ("sent Json & got http status ${resp.status} - ${resp.status.code}")
log.trace "Exception Sending Json: " + e.response.data.status
debugEvent ("sent Json & got http status ${e.statusCode} - ${e.response.data.status.code}") //refresh the auth token
if (e.response.data.status.code == 14) { if (resp.status.code == 14) {
atomicState.action = "pollChildren"
log.debug "Refreshing your auth_token!" log.debug "Refreshing your auth_token!"
debugEvent ("Refreshing OAUTH Token")
refreshAuthToken() refreshAuthToken()
} return false
else { } else {
debugEvent("Authentication error, invalid authentication method, lack of credentials, etc.") debugEvent ("Authentication error, invalid authentication method, lack of credentials, etc.")
log.error "Authentication error, invalid authentication method, lack of credentials, etc." log.error "Authentication error, invalid authentication method, lack of credentials, etc."
return false
} }
} }
}
} catch(Exception e) {
log.debug "Exception Sending Json: " + e
debugEvent ("Exception Sending JSON: " + e)
refreshAuthToken()
return false
}
if (returnStatus == 0) if (returnStatus == 0)
return true return true