mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[insteon] Add modem database backup restore console commands (#17958)
Signed-off-by: jsetton <jeremy.setton@gmail.com>
This commit is contained in:
parent
36cff511b9
commit
d54a51b732
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.insteon.internal;
|
package org.openhab.binding.insteon.internal;
|
||||||
|
|
||||||
import java.io.File;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -34,7 +34,7 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class InsteonBindingConstants {
|
public class InsteonBindingConstants {
|
||||||
public static final String BINDING_ID = "insteon";
|
public static final String BINDING_ID = "insteon";
|
||||||
public static final String BINDING_DATA_DIR = OpenHAB.getUserDataFolder() + File.separator + BINDING_ID;
|
public static final Path BINDING_DATA_DIR = Path.of(OpenHAB.getUserDataFolder(), BINDING_ID);
|
||||||
|
|
||||||
// List of all thing type uids
|
// List of all thing type uids
|
||||||
public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device");
|
public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device");
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
package org.openhab.binding.insteon.internal.command;
|
package org.openhab.binding.insteon.internal.command;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -27,7 +27,6 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.insteon.internal.InsteonBindingConstants;
|
|
||||||
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
||||||
import org.openhab.binding.insteon.internal.device.InsteonScene;
|
import org.openhab.binding.insteon.internal.device.InsteonScene;
|
||||||
import org.openhab.binding.insteon.internal.device.X10Address;
|
import org.openhab.binding.insteon.internal.device.X10Address;
|
||||||
@ -71,7 +70,7 @@ public class DebugCommand extends InsteonCommand implements PortListener {
|
|||||||
|
|
||||||
private static final String ALL_OPTION = "--all";
|
private static final String ALL_OPTION = "--all";
|
||||||
|
|
||||||
private static final String MSG_EVENTS_FILE_PREFIX = "messageEvents";
|
private static final String MSG_EVENTS_FILE_PREFIX = "message-events";
|
||||||
|
|
||||||
private static enum MessageType {
|
private static enum MessageType {
|
||||||
STANDARD,
|
STANDARD,
|
||||||
@ -195,9 +194,16 @@ public class DebugCommand extends InsteonCommand implements PortListener {
|
|||||||
} else if (cursorArgumentIndex == 1) {
|
} else if (cursorArgumentIndex == 1) {
|
||||||
switch (args[0]) {
|
switch (args[0]) {
|
||||||
case START_MONITORING:
|
case START_MONITORING:
|
||||||
|
strings = monitorAllDevices ? List.of()
|
||||||
|
: Stream.concat(Stream.of(ALL_OPTION),
|
||||||
|
getModem().getDB().getDevices().stream()
|
||||||
|
.filter(address -> !monitoredAddresses.contains(address))
|
||||||
|
.map(InsteonAddress::toString))
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
case STOP_MONITORING:
|
case STOP_MONITORING:
|
||||||
strings = Stream.concat(Stream.of(ALL_OPTION),
|
strings = monitorAllDevices ? List.of(ALL_OPTION)
|
||||||
getModem().getDB().getDevices().stream().map(InsteonAddress::toString)).toList();
|
: monitoredAddresses.stream().map(InsteonAddress::toString).toList();
|
||||||
break;
|
break;
|
||||||
case SEND_BROADCAST_MESSAGE:
|
case SEND_BROADCAST_MESSAGE:
|
||||||
strings = getModem().getDB().getBroadcastGroups().stream().map(String::valueOf).toList();
|
strings = getModem().getDB().getBroadcastGroups().stream().map(String::valueOf).toList();
|
||||||
@ -251,40 +257,25 @@ public class DebugCommand extends InsteonCommand implements PortListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getMsgEventsFileName(String address) {
|
private Path getMsgEventsFilePath(String address) {
|
||||||
return MSG_EVENTS_FILE_PREFIX + "-" + address.replace(".", "") + ".log";
|
return getBindingDataFilePath(MSG_EVENTS_FILE_PREFIX + "-" + address.toLowerCase().replace(".", "") + ".log");
|
||||||
}
|
|
||||||
|
|
||||||
private String getMsgEventsFilePath(String address) {
|
|
||||||
return InsteonBindingConstants.BINDING_DATA_DIR + File.separator + getMsgEventsFileName(address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearMonitorFiles(String address) {
|
private void clearMonitorFiles(String address) {
|
||||||
File folder = new File(InsteonBindingConstants.BINDING_DATA_DIR);
|
String prefix = ALL_OPTION.equals(address) ? MSG_EVENTS_FILE_PREFIX
|
||||||
String prefix = ALL_OPTION.equals(address) ? MSG_EVENTS_FILE_PREFIX : getMsgEventsFileName(address);
|
: getMsgEventsFilePath(address).getFileName().toString();
|
||||||
|
|
||||||
if (folder.isDirectory()) {
|
getBindingDataFilePaths(prefix).map(Path::toFile).forEach(File::delete);
|
||||||
Arrays.asList(folder.listFiles()).stream().filter(file -> file.getName().startsWith(prefix))
|
|
||||||
.forEach(File::delete);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logMessageEvent(InsteonAddress address, Msg msg) {
|
private void logMessageEvent(InsteonAddress address, Msg msg) {
|
||||||
String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date());
|
String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date());
|
||||||
String pathname = getMsgEventsFilePath(address.toString());
|
String line = timestamp + " " + msg + System.lineSeparator();
|
||||||
|
Path path = getMsgEventsFilePath(address.toString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File file = new File(pathname);
|
Files.createDirectories(path.getParent());
|
||||||
File parent = file.getParentFile();
|
Files.writeString(path, line, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
|
||||||
if (parent == null) {
|
|
||||||
throw new IOException(pathname + " does not name a parent directory");
|
|
||||||
}
|
|
||||||
parent.mkdirs();
|
|
||||||
file.createNewFile();
|
|
||||||
|
|
||||||
PrintStream ps = new PrintStream(new FileOutputStream(file, true));
|
|
||||||
ps.println(timestamp + " " + msg.toString());
|
|
||||||
ps.close();
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("failed to write to message event file", e);
|
logger.warn("failed to write to message event file", e);
|
||||||
}
|
}
|
||||||
@ -307,7 +298,7 @@ public class DebugCommand extends InsteonCommand implements PortListener {
|
|||||||
monitorAllDevices = true;
|
monitorAllDevices = true;
|
||||||
monitoredAddresses.clear();
|
monitoredAddresses.clear();
|
||||||
console.println("Started monitoring all devices.");
|
console.println("Started monitoring all devices.");
|
||||||
console.println("Message events logged in " + InsteonBindingConstants.BINDING_DATA_DIR);
|
console.println("Message events logged in " + getBindingDataDirPath());
|
||||||
clearMonitorFiles(address);
|
clearMonitorFiles(address);
|
||||||
} else {
|
} else {
|
||||||
console.println("Already monitoring all devices.");
|
console.println("Already monitoring all devices.");
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.insteon.internal.command;
|
package org.openhab.binding.insteon.internal.command;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@ -20,6 +23,7 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.insteon.internal.InsteonBindingConstants;
|
||||||
import org.openhab.binding.insteon.internal.device.Device;
|
import org.openhab.binding.insteon.internal.device.Device;
|
||||||
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
||||||
import org.openhab.binding.insteon.internal.device.InsteonDevice;
|
import org.openhab.binding.insteon.internal.device.InsteonDevice;
|
||||||
@ -171,4 +175,21 @@ public abstract class InsteonCommand implements ConsoleCommandCompleter {
|
|||||||
InsteonDevice device = getInsteonDevice(thingId);
|
InsteonDevice device = getInsteonDevice(thingId);
|
||||||
return device != null ? device.getInsteonEngine() : InsteonEngine.UNKNOWN;
|
return device != null ? device.getInsteonEngine() : InsteonEngine.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Path getBindingDataDirPath() {
|
||||||
|
return InsteonBindingConstants.BINDING_DATA_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Path getBindingDataFilePath(String filename) {
|
||||||
|
return InsteonBindingConstants.BINDING_DATA_DIR.resolve(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Stream<Path> getBindingDataFilePaths(String prefix) {
|
||||||
|
try {
|
||||||
|
return Files.list(InsteonBindingConstants.BINDING_DATA_DIR)
|
||||||
|
.filter(path -> path.getFileName().toString().startsWith(prefix));
|
||||||
|
} catch (IOException e) {
|
||||||
|
return Stream.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.insteon.internal.command;
|
package org.openhab.binding.insteon.internal.command;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -20,6 +26,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
||||||
import org.openhab.binding.insteon.internal.device.ProductData;
|
import org.openhab.binding.insteon.internal.device.ProductData;
|
||||||
|
import org.openhab.binding.insteon.internal.device.database.ModemDBChange;
|
||||||
import org.openhab.binding.insteon.internal.device.database.ModemDBEntry;
|
import org.openhab.binding.insteon.internal.device.database.ModemDBEntry;
|
||||||
import org.openhab.binding.insteon.internal.device.database.ModemDBRecord;
|
import org.openhab.binding.insteon.internal.device.database.ModemDBRecord;
|
||||||
import org.openhab.binding.insteon.internal.handler.InsteonBridgeHandler;
|
import org.openhab.binding.insteon.internal.handler.InsteonBridgeHandler;
|
||||||
@ -41,6 +48,8 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
private static final String LIST_ALL = "listAll";
|
private static final String LIST_ALL = "listAll";
|
||||||
private static final String LIST_DATABASE = "listDatabase";
|
private static final String LIST_DATABASE = "listDatabase";
|
||||||
private static final String RELOAD_DATABASE = "reloadDatabase";
|
private static final String RELOAD_DATABASE = "reloadDatabase";
|
||||||
|
private static final String BACKUP_DATABASE = "backupDatabase";
|
||||||
|
private static final String RESTORE_DATABASE = "restoreDatabase";
|
||||||
private static final String ADD_DATABASE_CONTROLLER = "addDatabaseController";
|
private static final String ADD_DATABASE_CONTROLLER = "addDatabaseController";
|
||||||
private static final String ADD_DATABASE_RESPONDER = "addDatabaseResponder";
|
private static final String ADD_DATABASE_RESPONDER = "addDatabaseResponder";
|
||||||
private static final String DELETE_DATABASE_RECORD = "deleteDatabaseRecord";
|
private static final String DELETE_DATABASE_RECORD = "deleteDatabaseRecord";
|
||||||
@ -48,16 +57,19 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
private static final String CLEAR_DATABASE_CHANGES = "clearDatabaseChanges";
|
private static final String CLEAR_DATABASE_CHANGES = "clearDatabaseChanges";
|
||||||
private static final String ADD_DEVICE = "addDevice";
|
private static final String ADD_DEVICE = "addDevice";
|
||||||
private static final String REMOVE_DEVICE = "removeDevice";
|
private static final String REMOVE_DEVICE = "removeDevice";
|
||||||
|
private static final String RESET = "reset";
|
||||||
private static final String SWITCH = "switch";
|
private static final String SWITCH = "switch";
|
||||||
|
|
||||||
private static final List<String> SUBCMDS = List.of(LIST_ALL, LIST_DATABASE, RELOAD_DATABASE,
|
private static final List<String> SUBCMDS = List.of(LIST_ALL, LIST_DATABASE, RELOAD_DATABASE, BACKUP_DATABASE,
|
||||||
ADD_DATABASE_CONTROLLER, ADD_DATABASE_RESPONDER, DELETE_DATABASE_RECORD, APPLY_DATABASE_CHANGES,
|
RESTORE_DATABASE, ADD_DATABASE_CONTROLLER, ADD_DATABASE_RESPONDER, DELETE_DATABASE_RECORD,
|
||||||
CLEAR_DATABASE_CHANGES, ADD_DEVICE, REMOVE_DEVICE, SWITCH);
|
APPLY_DATABASE_CHANGES, CLEAR_DATABASE_CHANGES, ADD_DEVICE, REMOVE_DEVICE, RESET, SWITCH);
|
||||||
|
|
||||||
private static final String CONFIRM_OPTION = "--confirm";
|
private static final String CONFIRM_OPTION = "--confirm";
|
||||||
private static final String FORCE_OPTION = "--force";
|
private static final String FORCE_OPTION = "--force";
|
||||||
private static final String RECORDS_OPTION = "--records";
|
private static final String RECORDS_OPTION = "--records";
|
||||||
|
|
||||||
|
private static final String MODEM_DATABASE_FILE_PREFIX = "modem-database";
|
||||||
|
|
||||||
public ModemCommand(InsteonCommandExtension commandExtension) {
|
public ModemCommand(InsteonCommandExtension commandExtension) {
|
||||||
super(NAME, DESCRIPTION, commandExtension);
|
super(NAME, DESCRIPTION, commandExtension);
|
||||||
}
|
}
|
||||||
@ -69,6 +81,9 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
buildCommandUsage(LIST_DATABASE + " [" + RECORDS_OPTION + "]",
|
buildCommandUsage(LIST_DATABASE + " [" + RECORDS_OPTION + "]",
|
||||||
"list all-link database summary or records and pending changes for the Insteon modem"),
|
"list all-link database summary or records and pending changes for the Insteon modem"),
|
||||||
buildCommandUsage(RELOAD_DATABASE, "reload all-link database from the Insteon modem"),
|
buildCommandUsage(RELOAD_DATABASE, "reload all-link database from the Insteon modem"),
|
||||||
|
buildCommandUsage(BACKUP_DATABASE, "backup all-link database from the Insteon modem to a file"),
|
||||||
|
buildCommandUsage(RESTORE_DATABASE + " <filename> " + CONFIRM_OPTION,
|
||||||
|
"restore all-link database to the Insteon modem from a specific file"),
|
||||||
buildCommandUsage(ADD_DATABASE_CONTROLLER + " <address> <group> [<devCat> <subCat> <firmware>]",
|
buildCommandUsage(ADD_DATABASE_CONTROLLER + " <address> <group> [<devCat> <subCat> <firmware>]",
|
||||||
"add a controller record to all-link database for the Insteon modem"),
|
"add a controller record to all-link database for the Insteon modem"),
|
||||||
buildCommandUsage(ADD_DATABASE_RESPONDER + " <address> <group>",
|
buildCommandUsage(ADD_DATABASE_RESPONDER + " <address> <group>",
|
||||||
@ -83,6 +98,7 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
"add an Insteon device to the modem, optionally providing its address"),
|
"add an Insteon device to the modem, optionally providing its address"),
|
||||||
buildCommandUsage(REMOVE_DEVICE + " <address> [" + FORCE_OPTION + "]",
|
buildCommandUsage(REMOVE_DEVICE + " <address> [" + FORCE_OPTION + "]",
|
||||||
"remove an Insteon device from the modem"),
|
"remove an Insteon device from the modem"),
|
||||||
|
buildCommandUsage(RESET + " " + CONFIRM_OPTION, "reset the Insteon modem to factory defaults"),
|
||||||
buildCommandUsage(SWITCH + " <thingId>",
|
buildCommandUsage(SWITCH + " <thingId>",
|
||||||
"switch Insteon modem bridge to use if more than one configured and enabled"));
|
"switch Insteon modem bridge to use if more than one configured and enabled"));
|
||||||
}
|
}
|
||||||
@ -118,6 +134,20 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
printUsage(console, args[0]);
|
printUsage(console, args[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case BACKUP_DATABASE:
|
||||||
|
if (args.length == 1) {
|
||||||
|
backupDatabase(console);
|
||||||
|
} else {
|
||||||
|
printUsage(console, args[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RESTORE_DATABASE:
|
||||||
|
if (args.length == 2 || args.length == 3 && CONFIRM_OPTION.equals(args[2])) {
|
||||||
|
restoreDatabase(console, args[1], args.length == 3);
|
||||||
|
} else {
|
||||||
|
printUsage(console, args[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ADD_DATABASE_CONTROLLER:
|
case ADD_DATABASE_CONTROLLER:
|
||||||
if (args.length == 3 || args.length == 6) {
|
if (args.length == 3 || args.length == 6) {
|
||||||
addDatabaseRecord(console, args, true);
|
addDatabaseRecord(console, args, true);
|
||||||
@ -167,6 +197,13 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
printUsage(console, args[0]);
|
printUsage(console, args[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case RESET:
|
||||||
|
if (args.length == 1 || args.length == 2 && CONFIRM_OPTION.equals(args[1])) {
|
||||||
|
resetModem(console, args.length == 2);
|
||||||
|
} else {
|
||||||
|
printUsage(console, args[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SWITCH:
|
case SWITCH:
|
||||||
if (args.length == 2) {
|
if (args.length == 2) {
|
||||||
switchModem(console, args[1]);
|
switchModem(console, args[1]);
|
||||||
@ -191,6 +228,10 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
case LIST_DATABASE:
|
case LIST_DATABASE:
|
||||||
strings = List.of(RECORDS_OPTION);
|
strings = List.of(RECORDS_OPTION);
|
||||||
break;
|
break;
|
||||||
|
case RESTORE_DATABASE:
|
||||||
|
strings = getBindingDataFilePaths(MODEM_DATABASE_FILE_PREFIX).map(Path::getFileName)
|
||||||
|
.map(Path::toString).toList();
|
||||||
|
break;
|
||||||
case ADD_DATABASE_CONTROLLER:
|
case ADD_DATABASE_CONTROLLER:
|
||||||
case ADD_DATABASE_RESPONDER:
|
case ADD_DATABASE_RESPONDER:
|
||||||
case REMOVE_DEVICE:
|
case REMOVE_DEVICE:
|
||||||
@ -200,6 +241,10 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
strings = getModem().getDB().getRecords().stream().map(record -> record.getAddress().toString())
|
strings = getModem().getDB().getRecords().stream().map(record -> record.getAddress().toString())
|
||||||
.distinct().toList();
|
.distinct().toList();
|
||||||
break;
|
break;
|
||||||
|
case APPLY_DATABASE_CHANGES:
|
||||||
|
case RESET:
|
||||||
|
strings = List.of(CONFIRM_OPTION);
|
||||||
|
break;
|
||||||
case SWITCH:
|
case SWITCH:
|
||||||
strings = getBridgeHandlers().map(InsteonBridgeHandler::getThingId).toList();
|
strings = getBridgeHandlers().map(InsteonBridgeHandler::getThingId).toList();
|
||||||
break;
|
break;
|
||||||
@ -207,6 +252,9 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
} else if (cursorArgumentIndex == 2) {
|
} else if (cursorArgumentIndex == 2) {
|
||||||
InsteonAddress address = InsteonAddress.isValid(args[1]) ? new InsteonAddress(args[1]) : null;
|
InsteonAddress address = InsteonAddress.isValid(args[1]) ? new InsteonAddress(args[1]) : null;
|
||||||
switch (args[0]) {
|
switch (args[0]) {
|
||||||
|
case RESTORE_DATABASE:
|
||||||
|
strings = List.of(CONFIRM_OPTION);
|
||||||
|
break;
|
||||||
case DELETE_DATABASE_RECORD:
|
case DELETE_DATABASE_RECORD:
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
strings = getModem().getDB().getRecords(address).stream()
|
strings = getModem().getDB().getRecords(address).stream()
|
||||||
@ -242,7 +290,8 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
} else if (entries.isEmpty()) {
|
} else if (entries.isEmpty()) {
|
||||||
console.println("The all-link database for modem " + address + " is empty");
|
console.println("The all-link database for modem " + address + " is empty");
|
||||||
} else {
|
} else {
|
||||||
console.println("The all-link database for modem " + address + " contains " + entries.size() + " devices:");
|
console.println("The all-link database for modem " + address + " contains " + entries.size() + " devices:"
|
||||||
|
+ (!getModem().getDB().isComplete() ? " (Partial)" : ""));
|
||||||
print(console, entries);
|
print(console, entries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,7 +304,8 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
} else if (records.isEmpty()) {
|
} else if (records.isEmpty()) {
|
||||||
console.println("The all-link database for modem " + address + " is empty");
|
console.println("The all-link database for modem " + address + " is empty");
|
||||||
} else {
|
} else {
|
||||||
console.println("The all-link database for modem " + address + " contains " + records.size() + " records:");
|
console.println("The all-link database for modem " + address + " contains " + records.size() + " records:"
|
||||||
|
+ (!getModem().getDB().isComplete() ? " (Partial)" : ""));
|
||||||
print(console, records);
|
print(console, records);
|
||||||
listDatabaseChanges(console);
|
listDatabaseChanges(console);
|
||||||
}
|
}
|
||||||
@ -263,7 +313,7 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
|
|
||||||
private void listDatabaseChanges(Console console) {
|
private void listDatabaseChanges(Console console) {
|
||||||
InsteonAddress address = getModem().getAddress();
|
InsteonAddress address = getModem().getAddress();
|
||||||
List<String> changes = getModem().getDB().getChanges().stream().map(String::valueOf).toList();
|
List<String> changes = getModem().getDB().getChanges().stream().map(ModemDBChange::toString).toList();
|
||||||
if (InsteonAddress.UNKNOWN.equals(address)) {
|
if (InsteonAddress.UNKNOWN.equals(address)) {
|
||||||
console.println("No modem found!");
|
console.println("No modem found!");
|
||||||
} else if (!changes.isEmpty()) {
|
} else if (!changes.isEmpty()) {
|
||||||
@ -285,6 +335,73 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void backupDatabase(Console console) {
|
||||||
|
InsteonAddress address = getModem().getAddress();
|
||||||
|
if (InsteonAddress.UNKNOWN.equals(address)) {
|
||||||
|
console.println("No modem found!");
|
||||||
|
} else if (!getModem().getDB().isComplete()) {
|
||||||
|
console.println("The all-link database for modem " + address + " is not loaded yet.");
|
||||||
|
} else if (getModem().getDB().getRecords().isEmpty()) {
|
||||||
|
console.println("The all-link database for modem " + address + " is empty");
|
||||||
|
} else {
|
||||||
|
String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date());
|
||||||
|
String id = address.toString().toLowerCase().replace(".", "");
|
||||||
|
Path path = getBindingDataFilePath(MODEM_DATABASE_FILE_PREFIX + "-" + id + "-" + timestamp + ".dmp");
|
||||||
|
byte[] bytes = getModem().getDB().getRecordDump();
|
||||||
|
int count = bytes.length / ModemDBRecord.SIZE;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
Files.write(path, bytes);
|
||||||
|
console.println("Backed up " + count + " database records from modem " + address + " to " + path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
console.println("Failed to write backup file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreDatabase(Console console, String filename, boolean isConfirmed) {
|
||||||
|
InsteonAddress address = getModem().getAddress();
|
||||||
|
if (InsteonAddress.UNKNOWN.equals(address)) {
|
||||||
|
console.println("No modem found!");
|
||||||
|
} else if (!getModem().getDB().isComplete()) {
|
||||||
|
console.println("The all-link database for modem " + address + " is not loaded yet.");
|
||||||
|
} else {
|
||||||
|
Path path = Path.of(filename);
|
||||||
|
if (!path.isAbsolute()) {
|
||||||
|
path = getBindingDataFilePath(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!Files.isReadable(path)) {
|
||||||
|
console.println("The restore file " + path + " does not exist or is not readable.");
|
||||||
|
} else if (Files.size(path) == 0) {
|
||||||
|
console.println("The restore file " + path + " is empty.");
|
||||||
|
} else {
|
||||||
|
InputStream stream = Files.newInputStream(path);
|
||||||
|
List<ModemDBRecord> records = ModemDBRecord.fromRecordDump(stream);
|
||||||
|
if (!isConfirmed) {
|
||||||
|
console.println(
|
||||||
|
"The restore file " + path + " contains " + records.size() + " database records:");
|
||||||
|
print(console, records.stream().map(ModemDBRecord::toString).toList());
|
||||||
|
console.println("Please run the same command with " + CONFIRM_OPTION
|
||||||
|
+ " option to have these database records restored to modem " + address + ".");
|
||||||
|
} else {
|
||||||
|
console.println("Restoring " + records.size() + " database records to modem " + address
|
||||||
|
+ " from " + path + "...");
|
||||||
|
records.forEach(record -> getModem().getDB().markRecordForAddOrModify(record.getAddress(),
|
||||||
|
record.getGroup(), record.isController(), record.getData()));
|
||||||
|
getModem().getDB().update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
console.println("The restore file " + path + " is invalid.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
console.println("Failed to read restore file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addDatabaseRecord(Console console, String[] args, boolean isController) {
|
private void addDatabaseRecord(Console console, String[] args, boolean isController) {
|
||||||
if (!getModem().getDB().isComplete()) {
|
if (!getModem().getDB().isComplete()) {
|
||||||
console.println("The modem database is not loaded yet.");
|
console.println("The modem database is not loaded yet.");
|
||||||
@ -313,7 +430,6 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
ModemDBRecord record = getModem().getDB().getRecord(address, group, isController);
|
ModemDBRecord record = getModem().getDB().getRecord(address, group, isController);
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
getModem().getDB().markRecordForAdd(address, group, isController, data);
|
getModem().getDB().markRecordForAdd(address, group, isController, data);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
getModem().getDB().markRecordForModify(record, data);
|
getModem().getDB().markRecordForModify(record, data);
|
||||||
}
|
}
|
||||||
@ -405,6 +521,19 @@ public class ModemCommand extends InsteonCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetModem(Console console, boolean isConfirmed) {
|
||||||
|
InsteonAddress address = getModem().getAddress();
|
||||||
|
if (InsteonAddress.UNKNOWN.equals(address)) {
|
||||||
|
console.println("No modem found!");
|
||||||
|
} else if (!isConfirmed) {
|
||||||
|
console.println("Please run the same command with " + CONFIRM_OPTION + " option to reset modem " + address
|
||||||
|
+ " to factory defaults.");
|
||||||
|
} else {
|
||||||
|
console.println("Resetting modem " + address + " to factory defaults...");
|
||||||
|
getModem().reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void switchModem(Console console, String thingId) {
|
private void switchModem(Console console, String thingId) {
|
||||||
InsteonBridgeHandler handler = getBridgeHandler(thingId);
|
InsteonBridgeHandler handler = getBridgeHandler(thingId);
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
|
@ -153,7 +153,6 @@ public class SceneCommand extends InsteonCommand {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (cursorArgumentIndex == 4) {
|
} else if (cursorArgumentIndex == 4) {
|
||||||
InsteonDevice device = getInsteonDevice(args[2]);
|
InsteonDevice device = getInsteonDevice(args[2]);
|
||||||
DeviceFeature feature = device != null ? device.getFeature(args[3]) : null;
|
DeviceFeature feature = device != null ? device.getFeature(args[3]) : null;
|
||||||
|
@ -980,7 +980,7 @@ public class InsteonDevice extends BaseDevice<InsteonAddress, InsteonDeviceHandl
|
|||||||
device.setFlags(deviceType.getFlags());
|
device.setFlags(deviceType.getFlags());
|
||||||
}
|
}
|
||||||
int location = productData.getFirstRecordLocation();
|
int location = productData.getFirstRecordLocation();
|
||||||
if (location != LinkDBRecord.LOCATION_ZERO) {
|
if (location != 0) {
|
||||||
device.getLinkDB().setFirstRecordLocation(location);
|
device.getLinkDB().setFirstRecordLocation(location);
|
||||||
}
|
}
|
||||||
device.setProductData(productData);
|
device.setProductData(productData);
|
||||||
|
@ -270,6 +270,26 @@ public class InsteonModem extends BaseDevice<InsteonAddress, InsteonBridgeHandle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
try {
|
||||||
|
Msg msg = Msg.makeMessage("ResetIM");
|
||||||
|
writeMessage(msg);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("error sending modem reset query", e);
|
||||||
|
} catch (InvalidMessageTypeException e) {
|
||||||
|
logger.warn("invalid message ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleModemReset() {
|
||||||
|
logger.debug("modem reset initiated");
|
||||||
|
|
||||||
|
InsteonBridgeHandler handler = getHandler();
|
||||||
|
if (handler != null) {
|
||||||
|
handler.reset(RESET_TIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void logDeviceStatistics() {
|
public void logDeviceStatistics() {
|
||||||
logger.debug("devices: {} configured, {} polling, msgs received: {}", getDevices().size(),
|
logger.debug("devices: {} configured, {} polling, msgs received: {}", getDevices().size(),
|
||||||
getPollManager().getSizeOfQueue(), msgsReceived);
|
getPollManager().getSizeOfQueue(), msgsReceived);
|
||||||
@ -384,18 +404,6 @@ public class InsteonModem extends BaseDevice<InsteonAddress, InsteonBridgeHandle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies that the modem reset process has been initiated
|
|
||||||
*/
|
|
||||||
public void resetInitiated() {
|
|
||||||
logger.debug("modem reset initiated");
|
|
||||||
|
|
||||||
InsteonBridgeHandler handler = getHandler();
|
|
||||||
if (handler != null) {
|
|
||||||
handler.reset(RESET_TIME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the modem port has disconnected
|
* Notifies that the modem port has disconnected
|
||||||
*/
|
*/
|
||||||
@ -462,8 +470,12 @@ public class InsteonModem extends BaseDevice<InsteonAddress, InsteonBridgeHandle
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleIMMessage(Msg msg) throws FieldException {
|
private void handleIMMessage(Msg msg) throws FieldException {
|
||||||
if (msg.getCommand() == 0x60) {
|
if (msg.getCommand() == 0x60 && msg.isReplyAck()) {
|
||||||
|
// we got an im info reply ack
|
||||||
handleModemInfo(msg);
|
handleModemInfo(msg);
|
||||||
|
} else if (msg.getCommand() == 0x55 || msg.getCommand() == 0x67 && msg.isReplyAck()) {
|
||||||
|
// we got a user reset detected message or im reset reply ack
|
||||||
|
handleModemReset();
|
||||||
} else {
|
} else {
|
||||||
handleMessage(msg);
|
handleMessage(msg);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import org.openhab.binding.insteon.internal.utils.HexUtils;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class DatabaseRecord {
|
public class DatabaseRecord {
|
||||||
public static final int LOCATION_ZERO = 0;
|
public static final int SIZE = 8;
|
||||||
|
|
||||||
private final int location;
|
private final int location;
|
||||||
private final RecordType type;
|
private final RecordType type;
|
||||||
@ -42,12 +42,12 @@ public class DatabaseRecord {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DatabaseRecord(RecordType type, int group, InsteonAddress address, byte[] data) {
|
||||||
|
this(0, type, group, address, data);
|
||||||
|
}
|
||||||
|
|
||||||
public DatabaseRecord(DatabaseRecord record) {
|
public DatabaseRecord(DatabaseRecord record) {
|
||||||
this.location = record.location;
|
this(record.location, record.type, record.group, record.address, record.data);
|
||||||
this.type = record.type;
|
|
||||||
this.group = record.group;
|
|
||||||
this.address = record.address;
|
|
||||||
this.data = record.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLocation() {
|
public int getLocation() {
|
||||||
@ -114,7 +114,7 @@ public class DatabaseRecord {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String s = "";
|
String s = "";
|
||||||
if (location != LOCATION_ZERO) {
|
if (location != 0) {
|
||||||
s += HexUtils.getHexString(location, 4) + " ";
|
s += HexUtils.getHexString(location, 4) + " ";
|
||||||
}
|
}
|
||||||
s += address + " " + type;
|
s += address + " " + type;
|
||||||
|
@ -36,8 +36,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class LinkDB {
|
public class LinkDB {
|
||||||
public static final int RECORD_BYTE_SIZE = 8;
|
|
||||||
|
|
||||||
private static enum DatabaseStatus {
|
private static enum DatabaseStatus {
|
||||||
EMPTY,
|
EMPTY,
|
||||||
COMPLETE,
|
COMPLETE,
|
||||||
@ -258,7 +256,7 @@ public class LinkDB {
|
|||||||
*/
|
*/
|
||||||
public int getNextAvailableLocation() {
|
public int getNextAvailableLocation() {
|
||||||
return getRecords().stream().filter(LinkDBRecord::isAvailable).map(LinkDBRecord::getLocation).findFirst()
|
return getRecords().stream().filter(LinkDBRecord::isAvailable).map(LinkDBRecord::getLocation).findFirst()
|
||||||
.orElse(Math.min(getLastRecordLocation(), getLastChangeLocation() - RECORD_BYTE_SIZE));
|
.orElse(Math.min(getLastRecordLocation(), getLastChangeLocation() - LinkDBRecord.SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -355,7 +353,7 @@ public class LinkDB {
|
|||||||
LinkDBRecord prevRecord = records.put(record.getLocation(), record);
|
LinkDBRecord prevRecord = records.put(record.getLocation(), record);
|
||||||
// move last record if overwritten
|
// move last record if overwritten
|
||||||
if (prevRecord != null && prevRecord.isLast()) {
|
if (prevRecord != null && prevRecord.isLast()) {
|
||||||
int location = prevRecord.getLocation() - RECORD_BYTE_SIZE;
|
int location = prevRecord.getLocation() - LinkDBRecord.SIZE;
|
||||||
records.put(location, LinkDBRecord.withNewLocation(location, prevRecord));
|
records.put(location, LinkDBRecord.withNewLocation(location, prevRecord));
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("moved last record for {} to location {}", device.getAddress(),
|
logger.trace("moved last record for {} to location {}", device.getAddress(),
|
||||||
@ -531,7 +529,7 @@ public class LinkDB {
|
|||||||
|
|
||||||
int firstLocation = records.firstKey();
|
int firstLocation = records.firstKey();
|
||||||
int lastLocation = records.lastKey();
|
int lastLocation = records.lastKey();
|
||||||
int expected = (firstLocation - lastLocation) / RECORD_BYTE_SIZE + 1;
|
int expected = (firstLocation - lastLocation) / LinkDBRecord.SIZE + 1;
|
||||||
if (firstLocation != getFirstRecordLocation()) {
|
if (firstLocation != getFirstRecordLocation()) {
|
||||||
logger.debug("got unexpected first record location for {}", device.getAddress());
|
logger.debug("got unexpected first record location for {}", device.getAddress());
|
||||||
setStatus(DatabaseStatus.PARTIAL);
|
setStatus(DatabaseStatus.PARTIAL);
|
||||||
|
@ -229,12 +229,12 @@ public class LinkDBReader implements PortListener {
|
|||||||
stream.write(b);
|
stream.write(b);
|
||||||
// get next peek byte if stream size below the record byte size
|
// get next peek byte if stream size below the record byte size
|
||||||
// otherwise add record and get next peek record if not done
|
// otherwise add record and get next peek record if not done
|
||||||
if (stream.size() < LinkDB.RECORD_BYTE_SIZE) {
|
if (stream.size() < LinkDBRecord.SIZE) {
|
||||||
getNextPeekByte();
|
getNextPeekByte();
|
||||||
} else {
|
} else {
|
||||||
addRecord(LinkDBRecord.fromRecordData(stream.toByteArray(), location));
|
addRecord(LinkDBRecord.fromRecordData(stream.toByteArray(), location));
|
||||||
if (!done) {
|
if (!done) {
|
||||||
location -= LinkDB.RECORD_BYTE_SIZE;
|
location -= LinkDBRecord.SIZE;
|
||||||
getNextPeekRecord();
|
getNextPeekRecord();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ public class LinkDBWriter implements PortListener {
|
|||||||
private void setNextAllLinkRecord() {
|
private void setNextAllLinkRecord() {
|
||||||
LinkDBChange change = device.getLinkDB().pollNextChange();
|
LinkDBChange change = device.getLinkDB().pollNextChange();
|
||||||
if (change == null) {
|
if (change == null) {
|
||||||
logger.trace("all link db changes written using standard mode for {}", device.getAddress());
|
logger.debug("all link db changes written using standard mode for {}", device.getAddress());
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
setAllLinkRecord(change.getRecord());
|
setAllLinkRecord(change.getRecord());
|
||||||
@ -123,7 +123,7 @@ public class LinkDBWriter implements PortListener {
|
|||||||
private void setNextPokeRecord() {
|
private void setNextPokeRecord() {
|
||||||
LinkDBChange change = device.getLinkDB().pollNextChange();
|
LinkDBChange change = device.getLinkDB().pollNextChange();
|
||||||
if (change == null) {
|
if (change == null) {
|
||||||
logger.trace("all link db changes written using peek/poke mode for {}", device.getAddress());
|
logger.debug("all link db changes written using peek/poke mode for {}", device.getAddress());
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
setPokeRecord(change.getRecord());
|
setPokeRecord(change.getRecord());
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.insteon.internal.device.database;
|
package org.openhab.binding.insteon.internal.device.database;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -83,6 +84,14 @@ public class ModemDB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getRecordDump() {
|
||||||
|
return getRecords().stream().distinct().map(ModemDBRecord::getBytes)
|
||||||
|
.flatMapToInt(bytes -> IntStream.range(0, bytes.length).map(i -> bytes[i]))
|
||||||
|
.collect(ByteArrayOutputStream::new, ByteArrayOutputStream::write,
|
||||||
|
(out1, out2) -> out1.write(out2.toByteArray(), 0, out2.size()))
|
||||||
|
.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
private Stream<ModemDBRecord> getRecords(@Nullable InsteonAddress address, @Nullable Integer group,
|
private Stream<ModemDBRecord> getRecords(@Nullable InsteonAddress address, @Nullable Integer group,
|
||||||
@Nullable Boolean isController) {
|
@Nullable Boolean isController) {
|
||||||
return getRecords().stream()
|
return getRecords().stream()
|
||||||
|
@ -175,9 +175,6 @@ public class ModemDBReader implements PortListener {
|
|||||||
} else if (msg.getCommand() == 0x53) {
|
} else if (msg.getCommand() == 0x53) {
|
||||||
// we got a linking completed message
|
// we got a linking completed message
|
||||||
handleLinkingCompleted(msg);
|
handleLinkingCompleted(msg);
|
||||||
} else if (msg.getCommand() == 0x55 || msg.getCommand() == 0x67 && msg.isReplyAck()) {
|
|
||||||
// we got a user reset detected message or im reset reply ack
|
|
||||||
handleIMReset();
|
|
||||||
} else if (msg.getCommand() == 0x57) {
|
} else if (msg.getCommand() == 0x57) {
|
||||||
// we got a link record response
|
// we got a link record response
|
||||||
handleLinkRecord(msg);
|
handleLinkRecord(msg);
|
||||||
@ -305,8 +302,4 @@ public class ModemDBReader implements PortListener {
|
|||||||
productQueries.remove(address);
|
productQueries.remove(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleIMReset() {
|
|
||||||
modem.resetInitiated();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.insteon.internal.device.database;
|
package org.openhab.binding.insteon.internal.device.database;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
||||||
import org.openhab.binding.insteon.internal.transport.message.FieldException;
|
import org.openhab.binding.insteon.internal.transport.message.FieldException;
|
||||||
@ -26,7 +31,7 @@ import org.openhab.binding.insteon.internal.transport.message.Msg;
|
|||||||
public class ModemDBRecord extends DatabaseRecord {
|
public class ModemDBRecord extends DatabaseRecord {
|
||||||
|
|
||||||
public ModemDBRecord(RecordType type, int group, InsteonAddress address, byte[] data) {
|
public ModemDBRecord(RecordType type, int group, InsteonAddress address, byte[] data) {
|
||||||
super(LOCATION_ZERO, type, group, address, data);
|
super(type, group, address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModemDBRecord(DatabaseRecord record) {
|
public ModemDBRecord(DatabaseRecord record) {
|
||||||
@ -99,6 +104,34 @@ public class ModemDBRecord extends DatabaseRecord {
|
|||||||
return new ModemDBRecord(type, group, address, data);
|
return new ModemDBRecord(type, group, address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for creating a list of ModemDBRecord from an Insteon record dump
|
||||||
|
*
|
||||||
|
* @param stream the Insteon record dump input stream to use
|
||||||
|
* @return the list of modem db records
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static List<ModemDBRecord> fromRecordDump(InputStream stream) throws IllegalArgumentException, IOException {
|
||||||
|
List<ModemDBRecord> records = new ArrayList<>();
|
||||||
|
|
||||||
|
if (stream.available() % ModemDBRecord.SIZE != 0) {
|
||||||
|
throw new IllegalArgumentException("Invalid record dump length");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (stream.available() > 0) {
|
||||||
|
byte[] buf = stream.readNBytes(ModemDBRecord.SIZE);
|
||||||
|
RecordType type = new RecordType(Byte.toUnsignedInt(buf[0]));
|
||||||
|
int group = Byte.toUnsignedInt(buf[1]);
|
||||||
|
InsteonAddress address = new InsteonAddress(buf[2], buf[3], buf[4]);
|
||||||
|
byte[] data = new byte[] { buf[5], buf[6], buf[7] };
|
||||||
|
|
||||||
|
records.add(new ModemDBRecord(type, group, address, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method for creating a new ModemDBRecord from another instance with new data
|
* Factory method for creating a new ModemDBRecord from another instance with new data
|
||||||
*
|
*
|
||||||
|
@ -94,7 +94,7 @@ public class ModemDBWriter implements PortListener {
|
|||||||
private void manageNextModemLinkRecord() {
|
private void manageNextModemLinkRecord() {
|
||||||
ModemDBChange change = modem.getDB().pollNextChange();
|
ModemDBChange change = modem.getDB().pollNextChange();
|
||||||
if (change == null) {
|
if (change == null) {
|
||||||
logger.trace("all modem database changes written");
|
logger.debug("all modem database changes written");
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
ModemDBRecord record = change.getRecord();
|
ModemDBRecord record = change.getRecord();
|
||||||
|
Loading…
Reference in New Issue
Block a user