[broadlink] Fixes RM3 Mini not working correctly with newer firmware (#18856)

* Fixed bug in documentation for migrating old configurations.

Signed-off-by: AntonJansen <gradius@fmf.nl>
This commit is contained in:
Anton Jansen
2025-07-04 08:51:02 +02:00
committed by GitHub
parent b7841b8e90
commit 83d28e22ab
3 changed files with 47 additions and 6 deletions
@@ -3,6 +3,7 @@
This binding supports sending infrared (IR) and radio frequency (RF) commands using a range of devices for made by (and occasionally OEM licensed from) [Broadlink](https://www.ibroadlink.com/).
The highlevel overview is:
1. learn codes from your existing IR (and RF) remote controls, associating each of them with a command that you choose such as `AC_OFF`;
2. making openHAB rules that send the command e.g. `AC_OFF` to the device;
3. the binding will look up the learned code associated with your command and then send it.
@@ -92,7 +92,7 @@ public abstract class BroadlinkRemoteHandler extends BroadlinkBaseThingHandler {
return sendCommand(commandByte, new byte[0], purpose);
}
private byte @Nullable [] sendCommand(byte commandByte, byte[] codeBytes, String purpose) {
protected byte @Nullable [] sendCommand(byte commandByte, byte[] codeBytes, String purpose) {
try {
ByteArrayOutputStream outputStream = buildCommandMessage(commandByte, codeBytes);
byte[] padded = Utils.padTo(outputStream.toByteArray(), 16);
@@ -146,15 +146,13 @@ public abstract class BroadlinkRemoteHandler extends BroadlinkBaseThingHandler {
return;
}
updateState(BroadlinkBindingConstants.LEARNING_CONTROL_CHANNEL,
new StringType(message + irCommand + "..."));
byte[] response = sendCommand(COMMAND_BYTE_CHECK_LEARNT_DATA, "send learnt code check command");
if (response == null) {
logger.warn("Got nothing back while getting learnt code");
updateState(BroadlinkBindingConstants.LEARNING_CONTROL_CHANNEL, new StringType("NULL"));
} else {
logger.debug("Received response with length {}", response.length);
String hexString = Utils.toHexString(extractResponsePayload(response));
String cmdLabel = null;
if (replacement) {
@@ -181,7 +179,7 @@ public abstract class BroadlinkRemoteHandler extends BroadlinkBaseThingHandler {
}
}
} catch (IOException e) {
logger.warn("Exception while attempting to check learnt code: {}", e.getMessage());
logger.warn("Exception while attempting to check learnt code: {}", e.getMessage(), e);
updateState(BroadlinkBindingConstants.LEARNING_CONTROL_CHANNEL, new StringType("NULL"));
}
}
@@ -209,6 +207,8 @@ public abstract class BroadlinkRemoteHandler extends BroadlinkBaseThingHandler {
updateState(BroadlinkBindingConstants.LEARNING_CONTROL_CHANNEL,
new StringType(BroadlinkBindingConstants.LEARNING_CONTROL_COMMAND_LEARN));
sendCommand(COMMAND_BYTE_ENTER_LEARNING, "enter remote code learning mode");
updateState(BroadlinkBindingConstants.LEARNING_CONTROL_CHANNEL,
new StringType(BroadlinkBindingConstants.LEARNING_CONTROL_COMMAND_LEARN + " done"));
break;
}
case BroadlinkBindingConstants.LEARNING_CONTROL_COMMAND_CHECK: {
@@ -12,8 +12,15 @@
*/
package org.openhab.binding.broadlink.internal.handler;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.broadlink.internal.BroadlinkBindingConstants;
import org.openhab.binding.broadlink.internal.BroadlinkRemoteDynamicCommandDescriptionProvider;
import org.openhab.binding.broadlink.internal.Utils;
import org.openhab.core.library.types.StringType;
import org.openhab.core.storage.StorageService;
import org.openhab.core.thing.Thing;
@@ -21,13 +28,46 @@ import org.openhab.core.thing.Thing;
* Supports quirks in V44057 firmware.
*
* @author Stewart Cossey - Initial contribution
* @author Anton Jansen - revised based on community feedback
*/
@NonNullByDefault
public class BroadlinkRemoteModel3V44057Handler extends BroadlinkRemoteModel4MiniHandler {
public class BroadlinkRemoteModel3V44057Handler extends BroadlinkRemoteHandler {
public BroadlinkRemoteModel3V44057Handler(Thing thing,
BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider,
StorageService storageService) {
super(thing, commandDescriptionProvider, storageService);
}
@Override
protected byte @Nullable [] sendCommand(byte commandByte, byte[] codeBytes, String purpose) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// We start using an unsigned int (2 bytes) that indicates the size of the command (4 bytes) and the length
// of the codeBytes
int length = codeBytes.length + 4;
length = length & 0xffff; // truncate, ensure we have an unsigned short int value
outputStream.write((byte) (length & 0xFF)); // We have an unsigned int with little Endian
outputStream.write((byte) ((length >> 8) & 0xFF)); // So the larger part goes later
buildCommandMessage(commandByte, codeBytes).writeTo(outputStream);
byte[] padded = Utils.padTo(outputStream.toByteArray(), 16);
byte[] message = buildMessage((byte) 0x6a, padded);
return sendAndReceiveDatagram(message, purpose);
} catch (IOException e) {
updateState(BroadlinkBindingConstants.LEARNING_CONTROL_CHANNEL,
new StringType("Error found during when entering IR learning mode"));
logger.warn("Exception while sending command", e);
}
return null;
}
@Override
protected byte[] extractResponsePayload(byte[] responseBytes) throws IOException {
byte decryptedResponse[] = decodeDevicePacket(responseBytes);
// Interesting stuff begins at the sixth byte, as we now have the extra short unsigned int in the response
// as compared to the "standard" devices
return Utils.slice(decryptedResponse, 6, decryptedResponse.length);
}
}