HubAction Return for Protocol.RAW_LAN

I am trying to use the HubAction Object shown below to control a device and receive a return. It utilizes Encoding.HexString and I was expecting a HexString as a response.

  • Expected Response: 000003F9D0F281F88BFF..........
  • Actual Response: MDAwMDAyM0REMEYyODFG.........

Hub Command:

	def myHubAction = new hubitat.device.HubAction(
		outputXOR(command),
		hubitat.device.Protocol.RAW_LAN,
		[
			type: hubitat.device.HubAction.Type.LAN_TYPE_RAW,
			destinationAddress: "${getDataValue("deviceIP")}:9999",
			encoding: hubitat.device.HubAction.Encoding.HEX_STRING,
			timeout: 2
		])
	sendHubCommand(myHubAction)

Notes:

  • outputXOR(command) returns a hex string that is decoced by the device. The device return is simlarly encoded response.
  • the udp version of the command returns a proper response.

What I have tried:

  • Change "Protocol.RAW_LAN" to "Protocol.LAN". Same result
  • Remove "encoding" line - device does not respond.
  • Convert the response to a byte array then to hex - incorrect response.

Any assistance would be appreciated.

Mind if I ask how you converted to hex specifically? Also, I think that some of the responses to actions are base64 encoded as well... or at least the response is if it's an error or something like that. I don't remember for sure and of course I didn't leave myself notes in the drivers where I do this kind of thing.

What is the response.type? If it's error-looking you might have to:

response.payload.decodeBase64()

To see the exception message is. I've never done it with Protocol.RAW_LAN though. I've just done that with Protocol.LAN for type HubAction.Type.LAN_TYPE_UDPCLIENT, and all the HTTP ones.

1 Like

I’m not at a pc so grabbing this on my phone. I’ll look closer tomorrow. I use raw lan in my Kohler dtv+ driver. I have to get the payload like this to decode a json response.

parseJsonFromBase64(parseLanMessage(hubResponse).payload)

1 Like

Just for fun don't base64 decode the message unless you know it's an error. And if it is an error... And if that doesn't fix it also just for fun instead of using parseJsonFromBase64... try:

parseLanMessage(response).payload.decodeBase64()

I only base64 decode error messages when using the UDP action. Maybe the RAW_LAN action is the same way and only base64 encodes error messages. So, maybe no decoding required.

1 Like

I was experimenting out of desparation. Converted the string (resp) to a byte array then used hexutils to convert the byte array to hex. It did not return the correct hex string.

Byte[] respArray = resp.getBytes("ASCII")
log.debug respArray
log.debug hubitat.helper.HexUtils.byteArrayToHexString(respArray)

Well, hold on. Why are you going ASCII? You didn't say you needed to get into ASCII.
Do you know it's ASCII coming back? Maybe it's not 1 byte characters but 2... UTF-8 or something.

I do this to convert out of hex because my characters are 2 bytes each (take 2 at a time). Here's the hold method for convenience:

private String unhexify(String hexStr) {
  StringBuilder output = new StringBuilder("");

  for (int i = 0; i < hexStr.length(); i += 2) {
    String str = hexStr.substring(i, i + 2);
    output.append((char) Integer.parseInt(str, 16));
  }

  return output.toString();
}
1 Like

For completeness here is my handler for UDP responses just in case it is similar to RAW_LAN.

def discoverHandler(response) {
  logDebug "discoverHandler(response)"
  logTrace "response: $response"
  def resp = parseLanMessage(response)
  logTrace "resp: $resp"
  
  if (resp.type == "LAN_TYPE_UDPCLIENT_ERROR") {
    def msg = new String(resp.payload.decodeBase64())
    if (msg == "SocketTimeoutException: Receive timed out") {
      logTrace "No grill found at ${convertHexToIP(resp.ip)}"
    }
    else {
      log.warn "Unhandled error: ${msg}"
    }
  }
  else if (resp.type == "LAN_TYPE_UDPCLIENT") {
    def msg = unhexify(resp.payload)
    logDebug("discoverHandler: ${convertHexToIP(resp.ip)} // ${msg}")

    if (msg.startsWith("GMG")) {
      logInfo "Found a grill at ${convertHexToIP(resp.ip)}.  Please refresh the device edit screen to see the new settings."
      state.serial = msg
      device.updateSetting("ipadd", [value: convertHexToIP(resp.ip), type: "text"])
      device.updateSetting("port", [value: convertHexToInt(resp.port), type: "text"])
    }
  }
  else {
    log.warn "unhandled type: ${resp.type}"
  }
}

As I noted previously, I only base64 decode if it was an error. Otherwise, it's just out of hex.

If this approach isn't working let's mention Chuck.

1 Like

Thanks to all for the help. The below works. Your responses led me to this solution. The response is not an error message, just not converted back to Hex as it is in the UDP messages when Hex encoded.

def parse(response) {
	//	Parse the response, extract the payload, and convert to Byte Array
	Byte[] respArray = parseLanMessage(response).payload.decodeBase64()
	//	Send response to the XOR decrypter and create a JSON Output
	//	Note that String(respArray) is the Hex string response from the device.
	def cmdResponse = parseJson(inputXOR(new String(respArray)))
	//	Result is the expected response from the device.
	log.debug "Return message is ${cmdResponse}"
}

The result is the decoded response in JSON format.

Again, thanks.

dave

3 Likes