From 2a38b95c71fb601730cc8885ddecfdfffb45a0ac Mon Sep 17 00:00:00 2001 From: Jeremy Setton Date: Sat, 4 Jan 2025 19:52:33 -0500 Subject: [PATCH] [insteon] Add debug monitoring support for modem and x10 devices Signed-off-by: Jeremy Setton --- .../internal/command/DebugCommand.java | 133 +++++++++--------- 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/command/DebugCommand.java b/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/command/DebugCommand.java index 8a029fe79ff..1c502abc6c2 100644 --- a/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/command/DebugCommand.java +++ b/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/command/DebugCommand.java @@ -27,6 +27,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.insteon.internal.device.DeviceAddress; import org.openhab.binding.insteon.internal.device.InsteonAddress; import org.openhab.binding.insteon.internal.device.InsteonScene; import org.openhab.binding.insteon.internal.device.X10Address; @@ -82,7 +84,8 @@ public class DebugCommand extends InsteonCommand implements PortListener { private boolean monitoring = false; private boolean monitorAllDevices = false; - private Set monitoredAddresses = new HashSet<>(); + private Set monitoredAddresses = new HashSet<>(); + private @Nullable X10Address lastX10Address; public DebugCommand(InsteonCommandExtension commandExtension) { super(NAME, DESCRIPTION, commandExtension); @@ -90,11 +93,11 @@ public class DebugCommand extends InsteonCommand implements PortListener { @Override public List getUsages() { - return List.of(buildCommandUsage(LIST_MONITORED, "list monitored device(s)"), + return List.of(buildCommandUsage(LIST_MONITORED, "list monitored Insteon/X10 device(s)"), buildCommandUsage(START_MONITORING + " " + ALL_OPTION + "|
", - "start logging message events for device(s) in separate file(s)"), + "start logging message events for Insteon/X10 device(s) in separate file(s)"), buildCommandUsage(STOP_MONITORING + " " + ALL_OPTION + "|
", - "stop logging message events for device(s) in separate file(s)"), + "stop logging message events for Insteon/X10 device(s) in separate file(s)"), buildCommandUsage(SEND_BROADCAST_MESSAGE + " ", "send an Insteon broadcast message to a group"), buildCommandUsage(SEND_STANDARD_MESSAGE + "
", @@ -196,14 +199,15 @@ public class DebugCommand extends InsteonCommand implements PortListener { case START_MONITORING: strings = monitorAllDevices ? List.of() : Stream.concat(Stream.of(ALL_OPTION), - getModem().getDB().getDevices().stream() + Stream.concat(Stream.of(getModem().getAddress()), + getModem().getDB().getDevices().stream()) .filter(address -> !monitoredAddresses.contains(address)) .map(InsteonAddress::toString)) .toList(); break; case STOP_MONITORING: strings = monitorAllDevices ? List.of(ALL_OPTION) - : monitoredAddresses.stream().map(InsteonAddress::toString).toList(); + : monitoredAddresses.stream().map(DeviceAddress::toString).toList(); break; case SEND_BROADCAST_MESSAGE: strings = getModem().getDB().getBroadcastGroups().stream().map(String::valueOf).toList(); @@ -235,54 +239,65 @@ public class DebugCommand extends InsteonCommand implements PortListener { @Override public void messageReceived(Msg msg) { - try { - InsteonAddress address = msg.getInsteonAddress(msg.isReply() ? "toAddress" : "fromAddress"); - if (monitorAllDevices || monitoredAddresses.contains(address)) { - logMessageEvent(address, msg); - } - } catch (FieldException ignored) { - // ignore message with no address field - } + logMessageEvent(msg); } @Override public void messageSent(Msg msg) { - try { - InsteonAddress address = msg.getInsteonAddress("toAddress"); - if (monitorAllDevices || monitoredAddresses.contains(address)) { - logMessageEvent(address, msg); + logMessageEvent(msg); + } + + private DeviceAddress getMsgEventAddress(Msg msg) throws FieldException { + if (msg.isX10()) { + X10Address address = msg.isX10Address() ? msg.getX10Address() : lastX10Address; + if (address == null) { + throw new FieldException("unknown x10 address"); } - } catch (FieldException ignored) { - // ignore message with no address field + lastX10Address = address; + return address; + } else if (msg.isInsteon()) { + return msg.isInbound() && !msg.isReply() ? msg.getInsteonAddress("fromAddress") + : !msg.isAllLinkBroadcast() ? msg.getInsteonAddress("toAddress") : getModem().getAddress(); + } else { + return getModem().getAddress(); } } - private Path getMsgEventsFilePath(String address) { - return getBindingDataFilePath(MSG_EVENTS_FILE_PREFIX + "-" + address.toLowerCase().replace(".", "") + ".log"); + private Path getMsgEventsFilePath(DeviceAddress address) { + String name = address.toString().toLowerCase().replace(".", ""); + if (address instanceof X10Address) { + name = "x10-" + name; + } + return getBindingDataFilePath(MSG_EVENTS_FILE_PREFIX + "-" + name + ".log"); } - private void clearMonitorFiles(String address) { - String prefix = ALL_OPTION.equals(address) ? MSG_EVENTS_FILE_PREFIX + private void clearMonitorFiles(@Nullable DeviceAddress address) { + String prefix = address == null ? MSG_EVENTS_FILE_PREFIX : getMsgEventsFilePath(address).getFileName().toString(); getBindingDataFilePaths(prefix).map(Path::toFile).forEach(File::delete); } - private void logMessageEvent(InsteonAddress address, Msg msg) { - String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); - String line = timestamp + " " + msg + System.lineSeparator(); - Path path = getMsgEventsFilePath(address.toString()); - + private void logMessageEvent(Msg msg) { try { - Files.createDirectories(path.getParent()); - Files.writeString(path, line, StandardOpenOption.CREATE, StandardOpenOption.APPEND); + DeviceAddress address = getMsgEventAddress(msg); + if (monitorAllDevices || monitoredAddresses.contains(address)) { + String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); + String line = timestamp + " " + msg + System.lineSeparator(); + Path path = getMsgEventsFilePath(address); + + Files.createDirectories(path.getParent()); + Files.writeString(path, line, StandardOpenOption.CREATE, StandardOpenOption.APPEND); + } + } catch (FieldException e) { + logger.warn("failed to parse message", e); } catch (IOException e) { logger.warn("failed to write to message event file", e); } } private void listMonitoredDevices(Console console) { - String addresses = monitoredAddresses.stream().map(InsteonAddress::toString).collect(Collectors.joining(", ")); + String addresses = monitoredAddresses.stream().map(DeviceAddress::toString).collect(Collectors.joining(", ")); if (!addresses.isEmpty()) { console.println("The monitored device(s) are: " + addresses); } else if (monitorAllDevices) { @@ -292,30 +307,27 @@ public class DebugCommand extends InsteonCommand implements PortListener { } } - private void startMonitoring(Console console, String address) { - if (ALL_OPTION.equals(address)) { - if (!monitorAllDevices) { - monitorAllDevices = true; - monitoredAddresses.clear(); - console.println("Started monitoring all devices."); - console.println("Message events logged in " + getBindingDataDirPath()); - clearMonitorFiles(address); - } else { - console.println("Already monitoring all devices."); - } - } else if (InsteonAddress.isValid(address)) { - if (monitorAllDevices) { - console.println("Already monitoring all devices."); - } else if (monitoredAddresses.add(new InsteonAddress(address))) { + private void startMonitoring(Console console, String arg) { + if (monitorAllDevices) { + console.println("Already monitoring all devices."); + } else if (ALL_OPTION.equals(arg)) { + monitorAllDevices = true; + monitoredAddresses.clear(); + console.println("Started monitoring all devices."); + console.println("Message events logged in " + getBindingDataDirPath()); + clearMonitorFiles(null); + } else { + DeviceAddress address = InsteonAddress.isValid(arg) ? new InsteonAddress(arg) + : X10Address.isValid(arg) ? new X10Address(arg) : null; + if (address == null) { + console.println("Invalid device address argument: " + arg); + } else if (monitoredAddresses.add(address)) { console.println("Started monitoring the device " + address + "."); console.println("Message events logged in " + getMsgEventsFilePath(address)); clearMonitorFiles(address); } else { console.println("Already monitoring the device " + address + "."); } - } else { - console.println("Invalid device address" + address + "."); - return; } if (!monitoring) { @@ -324,31 +336,26 @@ public class DebugCommand extends InsteonCommand implements PortListener { } } - private void stopMonitoring(Console console, String address) { - if (!monitoring) { - console.println("Not monitoring any devices."); - return; - } - - if (ALL_OPTION.equals(address)) { + private void stopMonitoring(Console console, String arg) { + if (ALL_OPTION.equals(arg)) { if (monitorAllDevices) { monitorAllDevices = false; console.println("Stopped monitoring all devices."); } else { console.println("Not monitoring all devices."); } - } else if (InsteonAddress.isValid(address)) { + } else { + DeviceAddress address = InsteonAddress.isValid(arg) ? new InsteonAddress(arg) + : X10Address.isValid(arg) ? new X10Address(arg) : null; if (monitorAllDevices) { console.println("Not monitoring individual devices."); - } else if (monitoredAddresses.remove(new InsteonAddress(address))) { + } else if (address == null) { + console.println("Invalid device address argument: " + arg); + } else if (monitoredAddresses.remove(address)) { console.println("Stopped monitoring the device " + address + "."); } else { console.println("Not monitoring the device " + address + "."); - return; } - } else { - console.println("Invalid address device address " + address + "."); - return; } if (!monitorAllDevices && monitoredAddresses.isEmpty()) {