Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[insteon] Fix missing links implementation #18274

Merged
merged 1 commit into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public class InsteonBindingConstants {
public static final String FEATURE_LED_ON_OFF = "ledOnOff";
public static final String FEATURE_LINK_FF_GROUP = "linkFFGroup";
public static final String FEATURE_LOW_BATTERY_THRESHOLD = "lowBatteryThreshold";
public static final String FEATURE_MONITOR_MODE = "monitorMode";
public static final String FEATURE_ON_LEVEL = "onLevel";
public static final String FEATURE_PING = "ping";
public static final String FEATURE_RAMP_RATE = "rampRate";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.openhab.binding.insteon.internal.device.InsteonDevice;
import org.openhab.binding.insteon.internal.device.ProductData;
import org.openhab.binding.insteon.internal.device.database.LinkDBRecord;
import org.openhab.binding.insteon.internal.device.database.ModemDBRecord;
import org.openhab.binding.insteon.internal.device.feature.FeatureEnums.KeypadButtonToggleMode;
import org.openhab.binding.insteon.internal.handler.InsteonDeviceHandler;
import org.openhab.binding.insteon.internal.handler.InsteonThingHandler;
Expand Down Expand Up @@ -465,9 +466,9 @@ private void listMissingLinks(Console console, String thingId) {
console.println("The modem database is not loaded yet.");
} else {
List<String> deviceLinks = device.getMissingDeviceLinks().entrySet().stream()
.map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue().getRecord())).toList();
.map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue())).toList();
List<String> modemLinks = device.getMissingModemLinks().entrySet().stream()
.map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue().getRecord())).toList();
.map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue())).toList();
if (deviceLinks.isEmpty() && modemLinks.isEmpty()) {
console.println("There are no missing links for device " + device.getAddress() + ".");
} else {
Expand Down Expand Up @@ -499,33 +500,33 @@ private void addMissingLinks(Console console, String thingId) {
console.println("The device " + thingId + " is not configured or enabled!");
} else if (!device.getLinkDB().isComplete()) {
console.println("The link database for device " + thingId + " is not loaded yet.");
} else if (!device.getLinkDB().getChanges().isEmpty()) {
console.println("The link database for device " + thingId + " has pending changes.");
} else if (!getModem().getDB().isComplete()) {
console.println("The modem database is not loaded yet.");
} else if (!getModem().getDB().getChanges().isEmpty()) {
console.println("The modem database has pending changes.");
} else {
int deviceLinkCount = device.getMissingDeviceLinks().size();
int modemLinkCount = device.getMissingModemLinks().size();
if (deviceLinkCount == 0 && modemLinkCount == 0) {
List<LinkDBRecord> deviceLinks = device.getMissingDeviceLinks().values().stream().toList();
List<ModemDBRecord> modemLinks = device.getMissingModemLinks().values().stream().toList();
if (deviceLinks.isEmpty() && modemLinks.isEmpty()) {
console.println("There are no missing links for device " + device.getAddress() + ".");
} else {
if (deviceLinkCount > 0) {
if (!deviceLinks.isEmpty()) {
if (!device.isAwake() || !device.isResponding()) {
console.println("Scheduling " + deviceLinkCount + " missing links for device "
console.println("Scheduling " + deviceLinks.size() + " missing links for device "
+ device.getAddress() + " to be added to its link database the next time it is "
+ (device.isBatteryPowered() ? "awake" : "online") + ".");
} else {
console.println("Adding " + deviceLinkCount + " missing links for device " + device.getAddress()
+ " to its link database...");
console.println("Adding " + deviceLinks.size() + " missing links for device "
+ device.getAddress() + " to its link database...");
}
device.addMissingDeviceLinks();
deviceLinks.forEach(record -> device.getLinkDB().markRecordForAddOrModify(record.getAddress(),
record.getGroup(), record.isController(), record.getData()));
device.getLinkDB().update();
}
if (modemLinkCount > 0) {
console.println("Adding " + modemLinkCount + " missing links for device " + device.getAddress()
if (!modemLinks.isEmpty()) {
console.println("Adding " + modemLinks.size() + " missing links for device " + device.getAddress()
+ " to the modem database...");
device.addMissingModemLinks();
modemLinks.forEach(record -> getModem().getDB().markRecordForAddOrModify(record.getAddress(),
record.getGroup(), record.isController(), record.getData()));
getModem().getDB().update();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@
*/
package org.openhab.binding.insteon.internal.device;

import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.insteon.internal.device.database.LinkDBRecord;
import org.openhab.binding.insteon.internal.device.database.ModemDBRecord;
import org.openhab.binding.insteon.internal.transport.message.Msg;

/**
* The {@link DefaultLink} represents a device default link
Expand All @@ -29,13 +26,11 @@ public class DefaultLink {
private String name;
private LinkDBRecord linkDBRecord;
private ModemDBRecord modemDBRecord;
private List<Msg> commands;

public DefaultLink(String name, LinkDBRecord linkDBRecord, ModemDBRecord modemDBRecord, List<Msg> commands) {
public DefaultLink(String name, LinkDBRecord linkDBRecord, ModemDBRecord modemDBRecord) {
this.name = name;
this.linkDBRecord = linkDBRecord;
this.modemDBRecord = modemDBRecord;
this.commands = commands;
}

public String getName() {
Expand All @@ -50,16 +45,8 @@ public ModemDBRecord getModemDBRecord() {
return modemDBRecord;
}

public List<Msg> getCommands() {
return commands;
}

@Override
public String toString() {
String s = name + "|linkDB:" + linkDBRecord + "|modemDB:" + modemDBRecord;
if (!commands.isEmpty()) {
s += "|commands:" + commands;
}
return s;
return name + "|linkDB:" + linkDBRecord + "|modemDB:" + modemDBRecord;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,13 @@ public int getGroup() {

public int getComponentId() {
int componentId = 0;
if (device instanceof InsteonDevice insteonDevice) {
if (device instanceof InsteonDevice insteonDevice && isControllerOrResponderFeature()) {
// use feature group as component id if device has more than one controller or responder feature,
// othewise use the component id of the link db first record
// set to 1 if device link db has a matching record, otherwise fall back to 0
if (insteonDevice.getControllerOrResponderFeatures().size() > 1) {
componentId = getGroup();
} else {
componentId = insteonDevice.getLinkDB().getFirstRecordComponentId();
} else if (insteonDevice.getLinkDB().hasComponentIdRecord(1, isControllerFeature())) {
componentId = 1;
}
}
return componentId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.insteon.internal.transport.message.FieldException;
import org.openhab.binding.insteon.internal.transport.message.InvalidMessageTypeException;
import org.openhab.binding.insteon.internal.transport.message.Msg;
import org.openhab.binding.insteon.internal.utils.HexUtils;

/**
Expand Down Expand Up @@ -175,7 +171,6 @@ public static class DefaultLinkEntry {
private boolean controller;
private int group;
private byte[] data;
private List<CommandEntry> commands = new ArrayList<>();

public DefaultLinkEntry(String name, boolean controller, int group, byte[] data) {
this.name = name;
Expand All @@ -196,14 +191,6 @@ public byte[] getData() {
return data;
}

public List<CommandEntry> getCommands() {
return commands;
}

public void addCommand(CommandEntry command) {
commands.add(command);
}

@Override
public String toString() {
String s = name + "->";
Expand All @@ -212,55 +199,6 @@ public String toString() {
s += "|data1:" + HexUtils.getHexString(data[0]);
s += "|data2:" + HexUtils.getHexString(data[1]);
s += "|data3:" + HexUtils.getHexString(data[2]);
if (!commands.isEmpty()) {
s += "|commands:" + commands;
}
return s;
}
}

/**
* Class that reflects a command entry
*/
public static class CommandEntry {
private String name;
private int ext;
private byte cmd1;
private byte cmd2;
private byte[] data;

public CommandEntry(String name, int ext, byte cmd1, byte cmd2, byte[] data) {
this.name = name;
this.ext = ext;
this.cmd1 = cmd1;
this.cmd2 = cmd2;
this.data = data;
}

public @Nullable Msg getMessage(InsteonDevice device) {
try {
if (ext == 0) {
return Msg.makeStandardMessage(device.getAddress(), cmd1, cmd2);
} else if (ext == 1) {
return Msg.makeExtendedMessage(device.getAddress(), cmd1, cmd2, data,
device.getInsteonEngine().supportsChecksum());
} else if (ext == 2) {
return Msg.makeExtendedMessageCRC2(device.getAddress(), cmd1, cmd2, data);
}
} catch (FieldException | InvalidMessageTypeException e) {
}
return null;
}

@Override
public String toString() {
String s = name + "->";
s += "ext:" + ext;
s += "|cmd1:" + HexUtils.getHexString(cmd1);
s += "|cmd2:" + HexUtils.getHexString(cmd2);
s += "|data1:" + HexUtils.getHexString(data[0]);
s += "|data2:" + HexUtils.getHexString(data[1]);
s += "|data3:" + HexUtils.getHexString(data[2]);
return s;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.insteon.internal.InsteonResourceLoader;
import org.openhab.binding.insteon.internal.device.DeviceType.CommandEntry;
import org.openhab.binding.insteon.internal.device.DeviceType.DefaultLinkEntry;
import org.openhab.binding.insteon.internal.device.DeviceType.FeatureEntry;
import org.openhab.binding.insteon.internal.utils.HexUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
Expand Down Expand Up @@ -249,52 +247,11 @@ private void parseDefaultLink(Element element, Map<String, DefaultLinkEntry> lin
getHexAttributeAsByte(element, "data3") };

DefaultLinkEntry link = new DefaultLinkEntry(name, isController, group, data);

NodeList nodes = element.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element child = (Element) node;
String nodeName = child.getNodeName();
if ("command".equals(nodeName)) {
link.addCommand(getDefaultLinkCommand(child));
}
}
}

if (links.putIfAbsent(name, link) != null) {
throw new SAXException("duplicate default link: " + name);
}
}

/**
* Returns a default link command
*
* @param element element to parse
* @return default link command
* @throws SAXException
*/
private CommandEntry getDefaultLinkCommand(Element element) throws SAXException {
String name = element.getAttribute("name");
if (name.isEmpty()) {
throw new SAXException("undefined default link command name");
}
int ext = getAttributeAsInteger(element, "ext");
if (ext < 0 || ext > 2) {
throw new SAXException("out of bound default link command ext argument: " + ext);
}
byte cmd1 = getHexAttributeAsByte(element, "cmd1");
if (cmd1 == 0) {
throw new SAXException("invalid default link command cmd1 argument: " + HexUtils.getHexString(cmd1));
}
byte cmd2 = getHexAttributeAsByte(element, "cmd2", (byte) 0x00);
byte[] data = { getHexAttributeAsByte(element, "data1", (byte) 0x00),
getHexAttributeAsByte(element, "data2", (byte) 0x00),
getHexAttributeAsByte(element, "data3", (byte) 0x00) };

return new CommandEntry(name, ext, cmd1, cmd2, data);
}

/**
* Singleton instance function
*
Expand Down
Loading