Modify sendHubCommand from ST?

I'm trying to figure out why my ported ST driver threw this error earlier today:

The code in question is:

private sendResponse(cmds) {
  logTrace "sendResponse $cmds"
  def actions = []
  cmds?.each { cmd ->
    actions << new hubitat.device.HubAction(cmd)
  } 
  sendHubCommand(actions)


  return []
}

Where the cmd array is built from calls like:

private wakeUpNoMoreInfoCmd() {
  return zwave.wakeUpV2.wakeUpNoMoreInformation().format()
}

I've modified it a bit to look more like other code I can find on the forums that calls sendHubCommand but I'm still learning driver development and need to figure out how to trigger it again.

Tagging @mike.maxwell, the Hubitat Driver Guru!

1 Like

It looks like you used one of my DTHs as a template and that particular handler was doing something that required hubaction, but your code doesn't need it. SmartThings released an update that broke the "response" command a long time ago which is why some of my older handlers use that sendResponse workaround.

In the wake up notification event you can replace sendResponse with response and everything should work as expected.

2 Likes

This is originally from https://homeseer.com/support/HS200-ST/HS-FS100_DeviceHandler.txt so I'm guessing they cribbed the base handler from you :slight_smile:

When you say:

You mean going from return sendResponse(result) to return response(result) which uses the Driver response API? Should I continue to have .format() called on the command object or does it matter since there is an overload for response that takes both String and Command?

Thanks for all the great handlers (I use a bunch of your ST stuff) and help!

I'm pretty sure format() has to be called on every command.

Since they copied most of my handler I thought all you'd have to do is replace "sendResponse" with "response", but that actually won't work.

In the original version, all of my methods like "batteryGetCmd()" wrap the command with "secureCmd" and that method calls the command's "format()" method, but they moved that into the sendResponse method.

I'm surprised the way they implemented it actually works because the delays between commands are strings and calling ".format()" on a string should throw an exception.

If you replace return sendResponse(result) with return response(result) you'll need to also add .format() to all the methods that return the zwave commands, like:

private batteryGetCmd() {
  return zwave.batteryV1.batteryGet().format()
}

I just checked the HomeSeer version and the sendResponse implementation doesn't match yours and all of the commands like batteryGetCmd() are already using format().

If you take the original version, replace physicalgraph with hubitat, and replace that return sendResponse(result) line with return response(result) the handler should work as-is.

Yeah, I had removed them when I saw the response overload thinking that I'd delay for the format call and let the hub API handle it. I'll re-add them and see how things go.

As for them cloning your code. Technically they should have left your copyright statement in the header of the file. They could have added their name as well but stripping your name isn't really okay since you still own the copyright on the bits of the code they didn't change. Probably not much you can do beyond sending Homeseer an email asking for correct attribution unless you happen to know a friendly lawyer.

I just noticed they didn't even write a complete handler. There is no code that handles water detection events.

I get the following events getting the cable wet and letting it dry out:

traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:0, sequence:false, eventParametersLength:1, eventParameter:[2])
traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:0, sequence:false, eventParametersLength:1, eventParameter:[2])
traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:0, sequence:false, eventParametersLength:1, eventParameter:[2])
traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:0, sequence:false, eventParametersLength:1, eventParameter:[2])
traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:0, sequence:false, eventParametersLength:1, eventParameter:[2])
traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:0, sequence:false, eventParametersLength:1, eventParameter:[2])
traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:2, sequence:false, eventParametersLength:0, eventParameter:[])
traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:0, sequence:false, eventParametersLength:1, eventParameter:[2])
traceNotificationReport: NotificationReport(v1AlarmType:0, v1AlarmLevel:0, reserved:0, notificationStatus:255, notificationType:5, event:2, sequence:false, eventParametersLength:0, eventParameter:[])

I guess I need to add something like this to def zwaveEvent(hubitat.zwave.commands.notificationv3.NotificationReport cmd) {

else if (cmd.notificationType == 0x05) {
    switch (cmd.event) {
      case 0:
        logDebug "Sensor No Water"        
        // TODO
        break
      case 2:
        logDebug "Sensor Detects Water"
        // TODO
        break
      default:
        logDebug "Sensor is ${cmd.event}"
    }
  }

Not sure what to return as a result here though.

You also have to add the "Water Sensor" capability to the top.

They implemented it in their Water Sensor handler, which also started as one of mine.