* * fixed refresh handing due `channelLinked` not called anymore on startup for example (similar to https://github.com/openhab/openhab-core/issues/1707),
* "Impacted Modules" can be empty if button is configured as "standalone" and does not impact modules,
* minor doc fix
* * check if configured impacted module for `impactedModules` is referencing an existing thing,
* fixed warnings
* Fixed review comment.
Signed-off-by: Boris Krivonog <boris.krivonog@inova.si>
import static org.openhab.binding.nikobus.internal.NikobusBindingConstants.CHANNEL_OUTPUT_PREFIX;
-import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openhab.binding.nikobus.internal.protocol.NikobusCommand;
import org.openhab.binding.nikobus.internal.protocol.SwitchModuleCommandFactory;
import org.openhab.binding.nikobus.internal.protocol.SwitchModuleGroup;
+import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
private final EnumSet<SwitchModuleGroup> pendingRefresh = EnumSet.noneOf(SwitchModuleGroup.class);
private final Logger logger = LoggerFactory.getLogger(NikobusModuleHandler.class);
private final Map<String, Integer> cachedStates = new HashMap<>();
- private final List<ChannelUID> linkedChannels = new ArrayList<>();
protected NikobusModuleHandler(Thing thing) {
super(thing);
}
+ @Override
+ public void initialize() {
+ super.initialize();
+
+ if (thing.getStatus() != ThingStatus.OFFLINE) {
+ // Fetch all linked channels to get initial values.
+ thing.getChannels().forEach(channel -> refreshChannel(channel.getUID()));
+ }
+ }
+
@Override
public void dispose() {
super.dispose();
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
+ logger.debug("handleCommand '{}' for channel '{}'", command, channelUID.getId());
+
if (command instanceof RefreshType) {
refreshChannel(channelUID);
} else {
updateGroup(SwitchModuleGroup.mapFromChannel(channelUID));
}
- @Override
- public void channelLinked(ChannelUID channelUID) {
- synchronized (linkedChannels) {
- linkedChannels.add(channelUID);
- }
- super.channelLinked(channelUID);
- }
-
- @Override
- public void channelUnlinked(ChannelUID channelUID) {
- synchronized (linkedChannels) {
- linkedChannels.remove(channelUID);
- }
- super.channelUnlinked(channelUID);
- }
-
public void refreshModule() {
Set<SwitchModuleGroup> groups = new HashSet<>();
- synchronized (linkedChannels) {
- for (ChannelUID channelUID : linkedChannels) {
+ for (Channel channel : thing.getChannels()) {
+ ChannelUID channelUID = channel.getUID();
+ if (isLinked(channelUID)) {
groups.add(SwitchModuleGroup.mapFromChannel(channelUID));
}
}
impactedModules.clear();
- try {
- ThingUID bridgeUID = thing.getBridgeUID();
- if (bridgeUID == null) {
- throw new IllegalArgumentException("Bridge does not exist!");
+ Object impactedModulesObject = getConfig().get(CONFIG_IMPACTED_MODULES);
+ if (impactedModulesObject != null) {
+ try {
+ Bridge bridge = getBridge();
+ if (bridge == null) {
+ throw new IllegalArgumentException("Bridge does not exist!");
+ }
+
+ ThingUID bridgeUID = thing.getBridgeUID();
+ if (bridgeUID == null) {
+ throw new IllegalArgumentException("Unable to read BridgeUID!");
+ }
+
+ String[] impactedModulesString = impactedModulesObject.toString().split(",");
+ for (String impactedModuleString : impactedModulesString) {
+ ImpactedModuleUID impactedModuleUID = new ImpactedModuleUID(impactedModuleString.trim());
+ ThingTypeUID thingTypeUID = new ThingTypeUID(bridgeUID.getBindingId(),
+ impactedModuleUID.getThingTypeId());
+ ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, impactedModuleUID.getThingId());
+
+ if (!bridge.getThings().stream().anyMatch(thing -> thing.getUID().equals(thingUID))) {
+ throw new IllegalArgumentException(
+ "Impacted module " + thingUID + " not found for '" + impactedModuleString + "'");
+ }
+
+ impactedModules.add(new ImpactedModule(thingUID, impactedModuleUID.getGroup()));
+ }
+ } catch (RuntimeException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
+ return;
}
- String[] impactedModulesString = getConfig().get(CONFIG_IMPACTED_MODULES).toString().split(",");
- for (String impactedModuleString : impactedModulesString) {
- ImpactedModuleUID impactedModuleUID = new ImpactedModuleUID(impactedModuleString.trim());
- ThingTypeUID thingTypeUID = new ThingTypeUID(bridgeUID.getBindingId(),
- impactedModuleUID.getThingTypeId());
- ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, impactedModuleUID.getThingId());
- impactedModules.add(new ImpactedModule(thingUID, impactedModuleUID.getGroup()));
- }
- } catch (RuntimeException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
- return;
+ logger.debug("Impacted modules for {} = {}", thing.getUID(), impactedModules);
}
- logger.debug("Impacted modules for {} = {}", thing.getUID(), impactedModules);
-
NikobusPcLinkHandler pcLink = getPcLink();
if (pcLink != null) {
pcLink.addListener(getAddress(), this::commandReceived);
updateState(CHANNEL_BUTTON, OnOffType.ON);
- Utils.cancel(requestUpdateFuture);
- requestUpdateFuture = scheduler.schedule(this::update, 400, TimeUnit.MILLISECONDS);
+ if (!impactedModules.isEmpty()) {
+ Utils.cancel(requestUpdateFuture);
+ requestUpdateFuture = scheduler.schedule(this::update, 400, TimeUnit.MILLISECONDS);
+ }
}
private void update() {
*/
package org.openhab.binding.nikobus.internal.utils;
-import org.apache.commons.lang.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.util.HexUtils;
/**
* @author Davy Vanherbergen - Initial contribution
* @author Boris Krivonog - Removed dependency to javax.xml.bind.DatatypeConverter
*/
+@NonNullByDefault
public class CRCUtil {
private static final int CRC_INIT = 0xFFFF;
* String representing hex numbers.
* @return input string + CRC.
*/
- public static String appendCRC(String input) {
+ public static @Nullable String appendCRC(@Nullable String input) {
if (input == null) {
return null;
}
}
check = check & CRC_INIT;
- String checksum = StringUtils.leftPad(Integer.toHexString(check), 4, "0");
+ String checksum = leftPadWithZeros(Integer.toHexString(check), 4);
return (input + checksum).toUpperCase();
}
}
}
- return input + StringUtils.leftPad(Integer.toHexString(check), 2, "0").toUpperCase();
+ return input + leftPadWithZeros(Integer.toHexString(check), 2).toUpperCase();
+ }
+
+ private static String leftPadWithZeros(String text, int size) {
+ StringBuilder builder = new StringBuilder(text);
+ while (builder.length() < size) {
+ builder.insert(0, '0');
+ }
+ return builder.toString();
}
}
import java.util.concurrent.Future;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
/**
* The {@link Utils} class defines commonly used utility functions.
*
* @author Boris Krivonog - Initial contribution
*/
+@NonNullByDefault
public class Utils {
- public static void cancel(Future<?> future) {
+ public static void cancel(@Nullable Future<?> future) {
if (future != null) {
future.cancel(true);
}
</parameter>
<parameter name="impactedModules" type="text">
<label>Impacted Modules</label>
- <description>Comma separated list of impacted modules, i.e. 4C6C-1,4C6C-2</description>
+ <description>Comma separated list of impacted modules, i.e. switch-module:s1:1</description>
</parameter>
</config-description>
</thing-type>