Skip to content

Commit

Permalink
[insteon] add console commands to help with troubleshooting (openhab#…
Browse files Browse the repository at this point in the history
…7251)

Signed-off-by: Rob Nielsen <rob.nielsen@yahoo.com>
Signed-off-by: Eugen Freiter <freiter@gmx.de>
  • Loading branch information
robnielsen authored and Eugen Freiter committed Apr 27, 2020
1 parent 3f1b51a commit 85ddfd3
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 103 deletions.
154 changes: 84 additions & 70 deletions bundles/org.openhab.binding.insteon/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

Expand All @@ -44,7 +46,7 @@
import org.openhab.binding.insteon.internal.driver.DriverListener;
import org.openhab.binding.insteon.internal.driver.ModemDBEntry;
import org.openhab.binding.insteon.internal.driver.Poller;
import org.openhab.binding.insteon.internal.handler.InsteonDeviceHandler;
import org.openhab.binding.insteon.internal.driver.Port;
import org.openhab.binding.insteon.internal.handler.InsteonNetworkHandler;
import org.openhab.binding.insteon.internal.message.FieldException;
import org.openhab.binding.insteon.internal.message.Msg;
Expand Down Expand Up @@ -309,7 +311,7 @@ private int checkIfInModemDatabase(InsteonDevice dev) {
HashMap<InsteonAddress, @Nullable ModemDBEntry> dbes = driver.lockModemDBEntries();
if (dbes.containsKey(addr)) {
if (!dev.hasModemDBEntry()) {
logger.debug("device {} found in the modem database and {}.", addr, getLinkInfo(dbes, addr));
logger.debug("device {} found in the modem database and {}.", addr, getLinkInfo(dbes, addr, true));
dev.setHasModemDBEntry(true);
}
} else {
Expand All @@ -323,6 +325,21 @@ private int checkIfInModemDatabase(InsteonDevice dev) {
}
}

public Map<String, String> getDatabaseInfo() {
try {
Map<String, String> databaseInfo = new HashMap<>();
HashMap<InsteonAddress, @Nullable ModemDBEntry> dbes = driver.lockModemDBEntries();
for (InsteonAddress addr : dbes.keySet()) {
String a = addr.toString();
databaseInfo.put(a, a + ": " + getLinkInfo(dbes, addr, false));
}

return databaseInfo;
} finally {
driver.unlockModemDBEntries();
}
}

/**
* Everything below was copied from Insteon PLM v1
*/
Expand Down Expand Up @@ -350,42 +367,55 @@ public void shutdown() {
return (dev);
}

private String getLinkInfo(HashMap<InsteonAddress, @Nullable ModemDBEntry> dbes, InsteonAddress a) {
private String getLinkInfo(HashMap<InsteonAddress, @Nullable ModemDBEntry> dbes, InsteonAddress a, boolean prefix) {
ModemDBEntry dbe = dbes.get(a);
ArrayList<Byte> controls = dbe.getControls();
ArrayList<Byte> responds = dbe.getRespondsTo();

StringBuilder buf = new StringBuilder("the modem");
if (!controls.isEmpty()) {
buf.append(" controls groups [");
buf.append(toGroupString(controls));
buf.append("]");
}

if (!responds.isEmpty()) {
if (!controls.isEmpty()) {
buf.append(" and");
Port port = dbe.getPort();
String deviceName = port.getDeviceName();
String s = deviceName.startsWith("/hub") ? "hub" : "plm";
StringBuilder buf = new StringBuilder();
if (port.isModem(a)) {
if (prefix) {
buf.append("it is the ");
}

buf.append(" responds to groups [");
buf.append(s);
buf.append(" (");
buf.append(Utils.redactPassword(deviceName));
buf.append(")");
} else {
if (prefix) {
buf.append("the ");
}
buf.append(s);
buf.append(" controls groups (");
buf.append(toGroupString(controls));
buf.append(") and responds to groups (");
buf.append(toGroupString(responds));
buf.append("]");
buf.append(")");
}

return buf.toString();
}

private String toGroupString(ArrayList<Byte> group) {
ArrayList<Byte> sorted = new ArrayList<>(group);
Collections.sort(sorted);
Collections.sort(sorted, new Comparator<Byte>() {
@Override
public int compare(Byte b1, Byte b2) {
int i1 = b1 & 0xFF;
int i2 = b2 & 0xFF;
return i1 < i2 ? -1 : i1 == i2 ? 0 : 1;
}
});

StringBuilder buf = new StringBuilder();
for (Byte b : sorted) {
if (buf.length() > 0) {
buf.append(",");
}
buf.append("0x");
buf.append(Utils.getHexString(b));
buf.append(b & 0xFF);
}

return buf.toString();
Expand Down Expand Up @@ -450,7 +480,8 @@ public void driverCompletelyInitialized() {
} else {
if (!dev.hasModemDBEntry()) {
addrs.add(a);
logger.debug("device {} found in the modem database and {}.", a, getLinkInfo(dbes, a));
logger.debug("device {} found in the modem database and {}.", a,
getLinkInfo(dbes, a, true));
dev.setHasModemDBEntry(true);
}
if (dev.getStatus() != DeviceStatus.POLLING) {
Expand All @@ -462,7 +493,7 @@ public void driverCompletelyInitialized() {
for (InsteonAddress k : dbes.keySet()) {
if (!addrs.contains(k) && !k.equals(dbes.get(k).getPort().getAddress())) {
logger.debug("device {} found in the modem database, but is not configured as a thing and {}.",
k, getLinkInfo(dbes, k));
k, getLinkInfo(dbes, k, true));

missing.add(k.toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public class InsteonHandlerFactory extends BaseThingHandlerFactory {
.unmodifiableSet(Stream.of(DEVICE_THING_TYPE, NETWORK_THING_TYPE).collect(Collectors.toSet()));

private final Map<ThingUID, @Nullable ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
private final Map<ThingUID, @Nullable ServiceRegistration<?>> serviceRegs = new HashMap<>();

private @Nullable SerialPortManager serialPortManager;

Expand All @@ -77,7 +78,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {

if (NETWORK_THING_TYPE.equals(thingTypeUID)) {
InsteonNetworkHandler insteonNetworkHandler = new InsteonNetworkHandler((Bridge) thing, serialPortManager);
registerDeviceDiscoveryService(insteonNetworkHandler);
registerServices(insteonNetworkHandler);

return insteonNetworkHandler;
} else if (DEVICE_THING_TYPE.equals(thingTypeUID)) {
Expand All @@ -90,14 +91,23 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
@Override
protected synchronized void removeHandler(ThingHandler thingHandler) {
if (thingHandler instanceof InsteonNetworkHandler) {
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.remove(thingHandler.getThing().getUID());
if (serviceReg != null) {
serviceReg.unregister();
ThingUID uid = thingHandler.getThing().getUID();
ServiceRegistration<?> serviceRegs = this.serviceRegs.remove(uid);
if (serviceRegs != null) {
serviceRegs.unregister();
}

ServiceRegistration<?> discoveryServiceRegs = this.discoveryServiceRegs.remove(uid);
if (discoveryServiceRegs != null) {
discoveryServiceRegs.unregister();
}
}
}

private synchronized void registerDeviceDiscoveryService(InsteonNetworkHandler handler) {
private synchronized void registerServices(InsteonNetworkHandler handler) {
this.serviceRegs.put(handler.getThing().getUID(),
bundleContext.registerService(InsteonNetworkHandler.class.getName(), handler, new Hashtable<>()));

InsteonDeviceDiscoveryService discoveryService = new InsteonDeviceDiscoveryService(handler);
this.discoveryServiceRegs.put(handler.getThing().getUID(),
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.insteon.internal.command;

import java.util.Arrays;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.io.console.Console;
import org.eclipse.smarthome.io.console.extensions.AbstractConsoleCommandExtension;
import org.eclipse.smarthome.io.console.extensions.ConsoleCommandExtension;
import org.openhab.binding.insteon.internal.handler.InsteonNetworkHandler;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;

/**
*
* Console commands for the Insteon binding
*
* @author Rob Nielsen - Initial contribution
*/
@NonNullByDefault
@Component(service = ConsoleCommandExtension.class)
public class InsteonCommandExtension extends AbstractConsoleCommandExtension {
private static final String DISPLAY_DEVICES = "display_devices";
private static final String DISPLAY_CHANNELS = "display_channels";
private static final String DISPLAY_LOCAL_DATABASE = "display_local_database";

@Nullable
private InsteonNetworkHandler handler;

public InsteonCommandExtension() {
super("insteon", "Interact with the Insteon integration.");
}

@Override
public void execute(String[] args, Console console) {
if (args.length > 0) {
InsteonNetworkHandler handler = this.handler; // fix eclipse warnings about nullable
if (handler == null) {
console.println("No Insteon network bridge configured.");
printUsage(console);
} else {
String subCommand = args[0];
switch (subCommand) {
case DISPLAY_DEVICES:
handler.displayDevices(console);
break;
case DISPLAY_CHANNELS:
handler.displayChannels(console);
break;
case DISPLAY_LOCAL_DATABASE:
handler.displayLocalDatabase(console);
break;
default:
console.println("Unknown command '" + subCommand + "'");
printUsage(console);
break;
}
}
} else {
printUsage(console);
}
}

@Override
public List<String> getUsages() {
return Arrays.asList(new String[] {
buildCommandUsage(DISPLAY_DEVICES, "display devices that are online, along with available channels"),
buildCommandUsage(DISPLAY_CHANNELS,
"display channels that are linked, along with configuration information"),
buildCommandUsage(DISPLAY_LOCAL_DATABASE, "display Insteon PLM or hub database details") });
}

@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
public void setInsteonNetworkHandler(InsteonNetworkHandler handler) {
this.handler = handler;
}

public void unsetInsteonNetworkHandler(InsteonNetworkHandler handler) {
this.handler = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ public Port(String devName, Driver d, @Nullable SerialPortManager serialPortMana
this.mdbb = new ModemDBBuilder(this);
}

public boolean isModem(InsteonAddress a) {
return modem.getAddress().equals(a);
}

public synchronized boolean isModemDBComplete() {
return (modemDBComplete);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,17 @@ public void initialize() {
if (!channels.isEmpty()) {
updateThing(editThing().withChannels(channels).build());

logger.debug("{} address = {} productKey = {} channels = {}", thingId, address, productKey,
channelList.toString());
StringBuilder builder = new StringBuilder(thingId);
builder.append(" address = ");
builder.append(address);
builder.append(" productKey = ");
builder.append(productKey);
builder.append(" channels = ");
builder.append(channelList.toString());
String msg = builder.toString();
logger.debug("{}", msg);

getInsteonNetworkHandler().initialized(getThing().getUID(), msg);

updateStatus(ThingStatus.ONLINE);
} else {
Expand Down Expand Up @@ -250,6 +259,8 @@ public void dispose() {
logger.debug("removed {} address = {}", getThing().getUID().getAsString(), address);
}

getInsteonNetworkHandler().disposed(getThing().getUID());

super.dispose();
}

Expand Down Expand Up @@ -322,18 +333,30 @@ public void channelLinked(ChannelUID channelUID) {
new InsteonAddress(config.getAddress()), productKey, params);
getInsteonBinding().addFeatureListener(bindingConfig);

logger.debug("channel {} linked with the feature: {} parameters: {}", channelUID.getAsString(), feature,
params);
StringBuilder builder = new StringBuilder(channelUID.getAsString());
builder.append(" feature = ");
builder.append(feature);
builder.append(" parameters = ");
builder.append(params);
String msg = builder.toString();
logger.debug("{}", msg);

getInsteonNetworkHandler().linked(channelUID, msg);
}

@Override
public void channelUnlinked(ChannelUID channelUID) {
getInsteonBinding().removeFeatureListener(channelUID);
getInsteonNetworkHandler().unlinked(channelUID);

logger.debug("channel {} unlinked ", channelUID.getAsString());
}

private @Nullable InsteonNetworkHandler getInsteonNetworkHandler() {
return (InsteonNetworkHandler) getBridge().getHandler();
}

private @Nullable InsteonBinding getInsteonBinding() {
return ((InsteonNetworkHandler) getBridge().getHandler()).getInsteonBinding();
return getInsteonNetworkHandler().getInsteonBinding();
}
}
Loading

0 comments on commit 85ddfd3

Please sign in to comment.