The vehiclePresent device is custom hardware with a Zigbee "radio" and custom driver.
I wrote it some time ago and the system seemed to work. Recently I started working on why there was a delay.
The rule "asks" for an update measurement. and vehiclePresent should be forced to "null" after the asked for measurement was sent.
You will see I'm not a good groovy coder, so my code is likely far from optimum.
/**
* Garage Ultrasonic Sensor
*
* 2020-12-25 - v02b - "saves" in hubitat and can request measurement via device page button.
* able to compare rec'd distance value to threshold
* v02c - add events putting results in db
* v02e - release candidate, still needs testing.
* with v02e everything seems to work.
* v02f - added distance status
* v02g - converted to PresenceSensor due to issues with RM and (bool?) custom attributes
* v02h - Changed the variable echo to echo for clarity.
* v02j - added runin to clear Distance and Presence after 5 minutes (as they could be invalid)
* won't work. We will have to count #OK.
* send @. to make measurement
* v03 - Add variable to count number of measurements made
* v04a - distance was an integer
*
* todo - transfer initial configure to Hub instead of Arduino.
* - add ability to change "ping." in cc2430 and #OK. in Arduino.
* -
* - clean up some of the log commands etc
* Change vehicle present to enum present, not present, null
*
*/
import hubitat.device.HubAction
import hubitat.device.HubMultiAction
import hubitat.device.Protocol
metadata {
definition (name: "Garage Ultrasonic v04a", namespace: "johnrob", author: "various") {
capability "Actuator" // our device has commands...
capability "Sensor" // our device has attributes...
capability "PresenceSensor" // ENUM["present", "not present"]
capability "Configuration" // capability "Configuration" commands: configure()
command "requestMeasRM"
attribute "vehiclePresent", "enum", ["present", "not present","null"]
//attribute "someOtherName", "enum", ["light", "dark"]
attribute "lastActivity", "String"
attribute "distance", "number"
}
preferences { // see: Hubitat Notes (HTTP, driver and app).docx for more input options (there are lots of them)
input name: "threshold", type: "num", title: "Presence Threshold (cm)", defaultValue: 200, range: "50..250", required: false
input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
input name: "txtEnable", type: "bool", title: "Enable descriptionecho logging", defaultValue: true
}
}
// Parse incoming device messages to generate events
def parse(String description) {
if (logEnable) log.debug " description is $description"
state.lastRan = now()
// runIn(300, clearOldData) //seconds, watchdogAlarm,[overwrite: true]) // [] because overwrite is a map
Map map = [:]
def event = zigbee.getEvent(description)
if (event) {
if (txtEnable) log.debug " parsed zigbee event = '${event}"
sendEvent(event)
}
else if (description?.startsWith("catchall:")) {
if (logEnable) log.debug " catchall is $description"
}
else if (description?.startsWith("read attr -")) { // our returned measurement is in this Map
def descMap = zigbee.parseDescriptionAsMap(description)
if (logEnable) log.debug " Desc Map: $descMap"
if (descMap.clusterInt == 0) {
def echo = descMap.value // def = define untyped variable
if (txtEnable) log.info " parsing '${echo}'"
echo = echo.replace(".","").trim()
if (echo.startsWith("!")) {
echo = echo.replace("!","")
sendEvent(name: "distance", value: echo, isStateChange: true, unit: "cm")
int echoValue = Integer.parseInt(echo)
int threshold = Integer.parseInt(threshold)
if (txtEnable) log.info "echo=${echoValue}"
if (echoValue > threshold) {
vehState = "not present"
log.info " > threshold}"
}
else{
vehState = "present"
if (txtEnable) log.info "${echo} < threshold}"
}
return sendEvent(name: "vehiclePresent", value: vehState, isStateChange: true)
}
if (echo.startsWith("ping")) return // trailing . removed above
else if (echo.startsWith("#OK")){
clearOldData() // by the time we get the next OK, the data will be obsolete.
return
}
else log.warn "Not an attribute we can decode"
}
} // --- 2nd else if ---
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"
if (logEnable) log.debug zigbee.parseDescriptionAsMap(description)
}
} // --- parse ---
//def getecho(){ // read some attribute string from the device
// if (txtEnable) log.info "gettext"
// //zigbee.readAttribute(0x000, 0x0006) // gets the last thing the device tried to send to us
// zigbee.readAttribute(0x000, 0x0010) // gets the last command the device heard us send
//}
def requestMeasRM() {
sendHubCommand(new HubAction(sendtodevice("@."), Protocol.ZIGBEE))
}
def sendtodevice(String mystr){
if (txtEnable) log.info "sending '${mystr}'"
mystr=mystr.padRight(16,".") // mystr should be 16 bytes!
def packed = hubitat.helper.HexUtils.byteArrayToHexString(mystr.getBytes())
if (logEnable) log.info "sending '${mystr}', packed is ${packed}"
def commandtosend = "he wattr 0x${device.deviceNetworkId} 8 0x000 0x010 0x42 {10"+packed+"}" // SAMPLELIGHT_ENDPOINT is defined as 8 in device code // the 10 on the end means 16 bytes length
if (logEnable) log.debug "$commandtosend"
return commandtosend
}
def sendCommand(String msg) {
if (txtEnable) log.info "sendCommand - ${msg}"
sendHubCommand(new HubAction(sendtodevice(msg), Protocol.ZIGBEE)) // "new" Creates a new HubAction object
}
def configure() {
if (txtEnable) log.info "Configuring Reporting and Bindings."
zigbee.onOffRefresh() + zigbee.onOffConfig()
}
def installed() {
if (txtEnable) log.info "Executing 'installed()'"
updated()
}
def initialize() {
if (txtEnable) log.info "Executing 'initialize()'"
}
def updated() {
if (txtEnable) log.info "Executing 'updated()'"
if (logEnable) {
log.info "Enabling Debug Logging for 30 minutes"
runIn(1800,logsOff)
} else {
unschedule(logsoff)
}
}
def now() {
if(location.timeZone)
now = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
else
now = new Date().format("yyyy MMM dd EEE h:mm:ss a")
sendEvent(name: "lastActivity", value: now, displayed:false)
result
}
def clearOldData() {
sendEvent(name: "distance", value: "null", isStateChange: true, unit: "cm")
sendEvent(name: "vehiclePresent", value: "null", isStateChange: true)
}
// --- eof ---