com.zsmartsystems.zigbee.console.ZigBeeConsoleAbstractCommand Maven / Gradle / Ivy
The newest version!
/**
* Copyright (c) 2016-2024 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.zsmartsystems.zigbee.console;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import com.zsmartsystems.zigbee.CommandResult;
import com.zsmartsystems.zigbee.IeeeAddress;
import com.zsmartsystems.zigbee.ZigBeeEndpoint;
import com.zsmartsystems.zigbee.ZigBeeNetworkManager;
import com.zsmartsystems.zigbee.ZigBeeNode;
import com.zsmartsystems.zigbee.groups.ZigBeeGroup;
import com.zsmartsystems.zigbee.zcl.ZclCluster;
import com.zsmartsystems.zigbee.zcl.field.ByteArray;
import com.zsmartsystems.zigbee.zcl.field.ZclArrayList;
import com.zsmartsystems.zigbee.zcl.protocol.ZclDataType;
/**
* Abstract class for ZigBee Console Commands
*
* @author Chris Jackson
*
*/
public abstract class ZigBeeConsoleAbstractCommand implements ZigBeeConsoleCommand {
protected static final String WILDCARD = "*";
/**
* Gets a {@link ZigBeeNode}
*
* @param networkManager the {@link ZigBeeNetworkManager}
* @param nodeId a {@link String} with the node Id
* @return the {@link ZigBeeNode}
* @throws IllegalArgumentException
*/
protected ZigBeeNode getNode(ZigBeeNetworkManager networkManager, final String nodeId)
throws IllegalArgumentException {
try {
Integer nwkAddress = getInteger(nodeId);
if (networkManager.getNode(nwkAddress) != null) {
return networkManager.getNode(nwkAddress);
}
} catch (Exception e) {
}
try {
IeeeAddress ieeeAddress = new IeeeAddress(nodeId);
if (networkManager.getNode(ieeeAddress) != null) {
return networkManager.getNode(ieeeAddress);
}
} catch (Exception e) {
}
throw new IllegalArgumentException("Node '" + nodeId + "' is not found.");
}
/**
* Gets {@link ZigBeeEndpoint} by device identifier.
*
* @param networkManager the {@link ZigBeeNetworkManager}
* @param endpointId the endpoint identifier
* @return the {@link ZigBeeEndpoint}
* @throws IllegalArgumentException
*/
protected ZigBeeEndpoint getEndpoint(final ZigBeeNetworkManager networkManager, final String endpointId)
throws IllegalArgumentException {
for (final ZigBeeNode node : networkManager.getNodes()) {
for (final ZigBeeEndpoint endpoint : node.getEndpoints()) {
if (endpointId.equals(node.getNetworkAddress() + "/" + endpoint.getEndpointId())) {
return endpoint;
}
}
}
throw new IllegalArgumentException("Endpoint '" + endpointId + "' is not found");
}
/**
* Parses a cluster ID as a string to an integer. The ID can be either a decimal or a hexadecimal literal (e..g, 11
* or 0xB).
*
* @param clusterId a {@link String} name of the cluster
* @return the cluster ID as an integer
* @throws IllegalArgumentException
*/
protected Integer parseClusterId(final String clusterId) throws IllegalArgumentException {
try {
return getInteger(clusterId);
} catch (final NumberFormatException e) {
throw new IllegalArgumentException("Cluster ID '" + clusterId + "' uses an invalid number format.");
}
}
/**
* Gets {@link ZigBeeGroup} by group identifier. A group ID must start with a hash (#). This method will return null
* if this is not a group ID starting with hash.
*
* @param networkManager the {@link ZigBeeNetworkManager}
* @param groupIdString the group identifier
* @return the {@link ZigBeeGroup} or null if this grouIdString is not a group ID starting with hash.
* @throws IllegalArgumentException
*/
protected ZigBeeGroup getGroup(final ZigBeeNetworkManager networkManager, final String groupIdString)
throws IllegalArgumentException {
if (!groupIdString.startsWith("#")) {
return null;
}
Integer groupId = getInteger(groupIdString.substring(1));
ZigBeeGroup group = networkManager.getGroup(groupId);
if (group == null) {
throw new IllegalArgumentException("Group '" + groupId + "' is not found");
}
return group;
}
/**
* Gets the cluster for a given endpoint, where the cluster is specified by a cluster specifier.
*
* The cluster specifier consists of the cluster ID (either in decimal, or in hex prefixed with 0x), optionally
* prepended with any of the prefixes 'in', 'out', 'client', or 'server'. The prefix indicates whether an input or
* an output cluster shall be returned. If no prefix is provided, then the method first tries to return an input
* cluster with the given id, and, if none is found, to return an output cluster.
*
* Examples for cluster specifiers:
*
* - 0x0B
*
- 11
*
- in:0xB
*
- server:11
*
*
* @param endpoint the ZigBee endpoint to get the cluster from (must be non-null)
* @param clusterSpecifier a cluster specified as described above (must be non-null)
* @return the specified cluster provided by the endpoint or null if no such cluster is found
* @throws IllegalArgumentException if the clusterSpecifier uses an invalid number format, or if no cluster is found
*/
protected ZclCluster getCluster(final ZigBeeEndpoint endpoint, final String clusterSpecifier)
throws IllegalArgumentException {
boolean isInput;
boolean isOutput;
String clusterIdString;
if (clusterSpecifier.contains(":")) {
String prefix = clusterSpecifier.substring(0, clusterSpecifier.indexOf(':'));
isInput = prefix.equalsIgnoreCase("in") || prefix.equalsIgnoreCase("server");
isOutput = prefix.equalsIgnoreCase("out") || prefix.equalsIgnoreCase("client");
if (!(isInput || isOutput)) {
throw new IllegalArgumentException(
"The prefix of the cluster specifier must be 'in', 'out', 'server', or 'client', but it was: "
+ prefix);
}
clusterIdString = clusterSpecifier.substring(clusterSpecifier.indexOf(':') + 1);
} else {
isInput = false;
isOutput = false;
clusterIdString = clusterSpecifier;
}
Integer clusterId = parseClusterId(clusterIdString);
ZclCluster result;
if (isInput) {
result = endpoint.getInputCluster(clusterId);
} else if (isOutput) {
result = endpoint.getOutputCluster(clusterId);
} else {
ZclCluster cluster = endpoint.getInputCluster(clusterId);
result = (cluster != null) ? cluster : endpoint.getOutputCluster(clusterId);
}
if (result != null) {
return result;
} else {
throw new IllegalArgumentException("A cluster specified by " + clusterSpecifier
+ " is not found for endpoint " + endpoint.getEndpointId());
}
}
/**
* Parses a attribute ID as a string to an integer
*
* @param attribute a {@link String} name of the attribute
* @return the attribute ID as an integer
* @throws IllegalArgumentException
*/
protected Integer parseAttribute(final String attribute) throws IllegalArgumentException {
try {
return getInteger(attribute);
} catch (final NumberFormatException e) {
throw new IllegalArgumentException("Attribute '" + attribute + "' uses an invalid number format.");
}
}
/**
* Parses an integer as a string to an integer
*
* @param integer a {@link String} of the integer
* @return the integer
* @throws IllegalArgumentException
*/
protected Integer parseInteger(final String integer) throws IllegalArgumentException {
try {
return getInteger(integer);
} catch (final NumberFormatException e) {
throw new IllegalArgumentException("Integer '" + integer + "' uses an invalid number format.");
}
}
/**
* Parses a percentage as a string to an integer. The string should be in the range 0-100, and the returned integer
* is in the range 0-254 as per the ZigBee standard.
*
* @param percentage a {@link String} of the percentage value
* @return the integer in the range 0-254 as per the ZigBee standard
* @throws IllegalArgumentException
*/
protected Integer parsePercentage(final String percentage) throws IllegalArgumentException {
int value = parseInteger(percentage);
return (int) (value * 254.0f / 100.0f + 0.5f);
}
/**
* Default processing for command result.
*
* @param result the command result
* @param out the output
* @return true if result is success
*/
protected boolean processDefaultResponse(CommandResult result, PrintStream out) {
if (result.isSuccess()) {
out.println("Success response received.");
return true;
} else {
out.println("Error executing command: " + result);
return true;
}
}
protected Object parseValue(String stringValue, ZclDataType zclDataType) {
if (stringValue.startsWith("[") && stringValue.endsWith("]")) {
switch (zclDataType) {
case OCTET_STRING:
case DATA_8_BIT:
break;
default:
throw new IllegalArgumentException("Array data type " + zclDataType + " is not supported.");
}
String[] stringValueArray = stringValue.substring(1, stringValue.length() - 1).split(" ");
List