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

[RFC] thing actions #373

Open
wants to merge 1 commit into
base: 2.5.x
Choose a base branch
from
Open
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
@@ -0,0 +1,43 @@
/**
* Copyright (c) 2010-2019 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.zigbee;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* The {@link ZigBeeCommandParameter} class represents a single pre-defined parameter to a ZigBee command.
*
* @author Thomas Weißschuh - Initial contribution
*/
@NonNullByDefault
public final class ZigBeeCommandParameter<T> {
private final String name;
private final Class<T> type;

public static final ZigBeeCommandParameter<Integer> TRANSITION_TIME =
new ZigBeeCommandParameter<>(Integer.class, "transitionTime");

ZigBeeCommandParameter(final Class<T> type, final String name) {
this.type = type;
this.name = name;
}

public Class<T> getType() {
return type;
}

@Override
public String toString() {
return name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2019 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.zigbee;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.zigbee.internal.ZigBeeCommandParametersImpl;

import java.util.Collection;
import java.util.Optional;

/**
* The {@link ZigBeeCommandParameters} interface represents a collection of parameters to pass to a ZigBee command.
*
* @author Thomas Weißschuh - Initial contribution
*/
@NonNullByDefault
public interface ZigBeeCommandParameters {
static ZigBeeCommandParameters empty() {
return new ZigBeeCommandParametersImpl();
}

<T> ZigBeeCommandParameters add(final ZigBeeCommandParameter<T> param, final T value);
<T> Optional<T> get(final ZigBeeCommandParameter<T> param);
Collection<ZigBeeCommandParameter<?>> setParameters();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Copyright (c) 2010-2019 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.zigbee;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.binding.ThingActions;
import org.eclipse.smarthome.core.thing.binding.ThingActionsScope;
import org.eclipse.smarthome.core.thing.binding.ThingHandler;
import org.eclipse.smarthome.core.types.Command;
import org.openhab.binding.zigbee.handler.ZigBeeThingHandler;
import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.RuleAction;

import static org.eclipse.jdt.annotation.Checks.requireNonNull;

/**
* The {@link ZigBeeThingActions} defines actions to be triggered by rules.
* It allows the specification of parameters to commands which is not possible via normal OH commands.
*
* @author Thomas Weißschuh - Initial contribution
*/
@SuppressWarnings("unused")
@ThingActionsScope(name="zigbee")
@NonNullByDefault
public final class ZigBeeThingActions implements ThingActions {
private @Nullable ZigBeeThingHandler handler;

@Override
public void setThingHandler(@Nullable final ThingHandler handler) {
this.handler = (ZigBeeThingHandler) handler;
}

@Override
public @Nullable ThingHandler getThingHandler() {
return handler;
}

@RuleAction(label = "sendCommand")
public void sendCommand(
@ActionInput(name = "channelId", required = true) final String channelId,
@ActionInput(name = "command", required = true) final Command command,
@ActionInput(name = "params") @Nullable final ZigBeeCommandParameters params
) {
handleCommand(getChannel(channelId), command, params != null ? params : ZigBeeCommandParameters.empty());
}

private void handleCommand(final ChannelUID channel, final Command command, final ZigBeeCommandParameters params) {
requireNonNull(handler).handleCommand(channel, command, params);
}

private ChannelUID getChannel(final String channelId) {
return new ChannelUID(requireNonNull(handler).getThing().getUID(), channelId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -34,6 +35,7 @@
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.StateDescription;
import org.openhab.binding.zigbee.ZigBeeBindingConstants;
import org.openhab.binding.zigbee.ZigBeeCommandParameters;
import org.openhab.binding.zigbee.handler.ZigBeeCoordinatorHandler;
import org.openhab.binding.zigbee.handler.ZigBeeThingHandler;
import org.slf4j.Logger;
Expand Down Expand Up @@ -251,7 +253,7 @@ public void handleRefresh() {
*
* @param command the {@link Command} to send
*/
public void handleCommand(final Command command) {
public void handleCommand(final Command command, final ZigBeeCommandParameters params) {
// Overridable if a channel can be commanded
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.ThingStatusInfo;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.thing.binding.ThingHandlerService;
import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder;
import org.eclipse.smarthome.core.thing.binding.firmware.Firmware;
import org.eclipse.smarthome.core.thing.binding.firmware.FirmwareUpdateHandler;
Expand All @@ -59,11 +60,15 @@
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.StateDescription;
import org.openhab.binding.zigbee.ZigBeeBindingConstants;
import org.openhab.binding.zigbee.ZigBeeCommandParameter;
import org.openhab.binding.zigbee.ZigBeeCommandParameters;
import org.openhab.binding.zigbee.converter.ZigBeeBaseChannelConverter;
import org.openhab.binding.zigbee.converter.ZigBeeChannelConverterFactory;
import org.openhab.binding.zigbee.discovery.ZigBeeNodePropertyDiscoverer;
import org.openhab.binding.zigbee.internal.ZigBeeCommandParametersImpl;
import org.openhab.binding.zigbee.internal.ZigBeeConfigDescriptionParameters;
import org.openhab.binding.zigbee.internal.ZigBeeDeviceConfigHandler;
import org.openhab.binding.zigbee.ZigBeeThingActions;
import org.openhab.binding.zigbee.internal.converter.config.ZclClusterConfigFactory;
import org.openhab.binding.zigbee.internal.converter.config.ZclClusterConfigHandler;
import org.openhab.binding.zigbee.internal.converter.config.ZclReportingConfig;
Expand Down Expand Up @@ -694,6 +699,10 @@ public void handleConfigurationUpdate(Map<String, Object> configurationParameter

@Override
public void handleCommand(final ChannelUID channelUID, final Command command) {
handleCommand(channelUID, command, ZigBeeCommandParameters.empty());
}

public void handleCommand(final ChannelUID channelUID, final Command command, final ZigBeeCommandParameters params) {
logger.debug("{}: Command for channel {} --> {} [{}]", nodeIeeeAddress, channelUID, command,
command.getClass().getSimpleName());

Expand All @@ -718,7 +727,12 @@ public void run() {
if (command == RefreshType.REFRESH) {
handler.handleRefresh();
} else {
handler.handleCommand(command);
ZigBeeCommandParametersImpl.UsageTracker parameterTracker = new ZigBeeCommandParametersImpl.UsageTracker(params);
handler.handleCommand(command, parameterTracker);
Set<ZigBeeCommandParameter<?>> unusedParams = parameterTracker.unusedParams();
if (!unusedParams.isEmpty() && logger.isWarnEnabled()) {
logger.warn("Handler {} did not use given parameters {}", handler, unusedParams);
}
}
} catch (Exception e) {
logger.debug("{}: Exception sending command to channel {}", nodeIeeeAddress, channelUID, e);
Expand Down Expand Up @@ -1006,4 +1020,9 @@ public boolean isUpdateExecutable() {
// Always allow the firmware to be updated
return true;
}

@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(ZigBeeThingActions.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2010-2019 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.zigbee.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.zigbee.ZigBeeCommandParameter;
import org.openhab.binding.zigbee.ZigBeeCommandParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
* The {@link ZigBeeCommandParametersImpl} class provides a stateless and a usage-tracking
* implementations of {@link ZigBeeCommandParameters}.
*
* @author Thomas Weißschuh - Initial contribution
*/
@NonNullByDefault
public class ZigBeeCommandParametersImpl implements ZigBeeCommandParameters {
private static final Logger logger = LoggerFactory.getLogger(ZigBeeCommandParametersImpl.class);

private final Map<ZigBeeCommandParameter<?>, Object> params = new HashMap<>();

@Override
public <T> ZigBeeCommandParameters add(final ZigBeeCommandParameter<T> param, final T value) {
params.put(param, value);
return this;
}

@Override
public <T> Optional<T> get(final ZigBeeCommandParameter<T> param) {
@Nullable Object v = params.get(param);
if (v == null) {
return Optional.empty();
} else if (!param.getType().isInstance(v)) {
logger.warn("Can not retrieve param {}: object of type {} ({}) can not be casted to {}",
param, v.getClass(), v, param.getType()
);
return Optional.empty();
} else {
return Optional.of(param.getType().cast(v));
}
}

@Override
public Collection<ZigBeeCommandParameter<?>> setParameters() {
return Collections.unmodifiableSet(params.keySet());
}

public static class UsageTracker implements ZigBeeCommandParameters {
private final Set<ZigBeeCommandParameter<?>> usedParams = new HashSet<>();
private final ZigBeeCommandParameters delegate;

public UsageTracker(ZigBeeCommandParameters delegate) {
this.delegate = delegate;
}

public Set<ZigBeeCommandParameter<?>> unusedParams() {
Set<ZigBeeCommandParameter<?>> unusedParams = new HashSet<>(setParameters());
unusedParams.removeAll(usedParams);
return Collections.unmodifiableSet(unusedParams);
}

@Override
public <T> ZigBeeCommandParameters add(ZigBeeCommandParameter<T> param, T value) {
return delegate.add(param, value);
}

@Override
public <T> Optional<T> get(ZigBeeCommandParameter<T> param) {
usedParams.add(param);
return delegate.get(param);
}

@Override
public Collection<ZigBeeCommandParameter<?>> setParameters() {
return delegate.setParameters();
}
}
}
Loading