All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zsmartsystems.zigbee.console.ZigBeeConsoleDeviceFingerprintCommand 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.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.concurrent.ExecutionException;

import com.zsmartsystems.zigbee.CommandResult;
import com.zsmartsystems.zigbee.ZigBeeDeviceType;
import com.zsmartsystems.zigbee.ZigBeeEndpoint;
import com.zsmartsystems.zigbee.ZigBeeEndpointAddress;
import com.zsmartsystems.zigbee.ZigBeeNetworkManager;
import com.zsmartsystems.zigbee.ZigBeeNode;
import com.zsmartsystems.zigbee.ZigBeeProfileType;
import com.zsmartsystems.zigbee.ZigBeeStatus;
import com.zsmartsystems.zigbee.transaction.ZigBeeTransactionMatcher;
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
import com.zsmartsystems.zigbee.zcl.ZclCluster;
import com.zsmartsystems.zigbee.zcl.ZclCommand;
import com.zsmartsystems.zigbee.zcl.ZclFrameType;
import com.zsmartsystems.zigbee.zcl.ZclStatus;
import com.zsmartsystems.zigbee.zcl.clusters.ZclBasicCluster;
import com.zsmartsystems.zigbee.zcl.clusters.general.ReadAttributesResponse;
import com.zsmartsystems.zigbee.zcl.field.ReadAttributeStatusRecord;
import com.zsmartsystems.zigbee.zcl.protocol.ZclDataType;
import com.zsmartsystems.zigbee.zdo.ZdoCommand;
import com.zsmartsystems.zigbee.zdo.ZdoStatus;
import com.zsmartsystems.zigbee.zdo.command.IeeeAddressRequest;
import com.zsmartsystems.zigbee.zdo.command.ManagementBindRequest;
import com.zsmartsystems.zigbee.zdo.command.ManagementLqiRequest;
import com.zsmartsystems.zigbee.zdo.command.ManagementRoutingRequest;
import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor;
import com.zsmartsystems.zigbee.zdo.field.PowerDescriptor;

/**
 * Gets device information from the device
 *
 * @author Chris Jackson
 *
 */
public class ZigBeeConsoleDeviceFingerprintCommand extends ZigBeeConsoleAbstractCommand {
    @Override
    public String getCommand() {
        return "fingerprint";
    }

    @Override
    public String getDescription() {
        return "Get detailed information about a device";
    }

    @Override
    public String getSyntax() {
        return "ADDRESS";
    }

    @Override
    public String getHelp() {
        return "";
    }

    @Override
    public void process(ZigBeeNetworkManager networkManager, String[] args, PrintStream out)
            throws IllegalArgumentException {
        if (args.length != 2) {
            throw new IllegalArgumentException("Invalid number of arguments");
        }

        // Use a separate stream so we can print all output at once
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        final String utf8 = StandardCharsets.UTF_8.name();
        PrintStream writer;
        try {
            writer = new PrintStream(baos, true, utf8);
        } catch (UnsupportedEncodingException e) {
            out.println("Error creating print writer");
            return;
        }

        ZigBeeNode node = getNode(networkManager, args[1]);
        NodeDescriptor nodeDescriptor = node.getNodeDescriptor();
        PowerDescriptor powerDescriptor = node.getPowerDescriptor();
        writer.println("|>| Node Descriptor");
        if (nodeDescriptor == null) {
            writer.println("| |> Not Set");
        } else {
            writer.println("| |> Logical Type               " + nodeDescriptor.getLogicalType());
            writer.println("| |> MAC Capabilities           " + nodeDescriptor.getMacCapabilities());
            writer.println("| |> Stack Compliance           " + nodeDescriptor.getStackCompliance());
            writer.println("| |> Server Capabilities        " + nodeDescriptor.getServerCapabilities());
            writer.println("| |> Buffer Size                " + nodeDescriptor.getBufferSize());
            writer.println("| |> Incoming Transfer Size     " + nodeDescriptor.getIncomingTransferSize());
            writer.println("| |> Outgoing Transfer Size     " + nodeDescriptor.getOutGoingTransferSize());
        }

        writer.println("|");
        writer.println("|>| Power Descriptor");
        if (powerDescriptor == null) {
            writer.println("| |> Not Set");
        } else {
            writer.println("| |> Available Power Sources    " + powerDescriptor.getAvailablePowerSources());
            writer.println("| |> Current Power Source       " + powerDescriptor.getCurrentPowerSource());
            writer.println("| |> Current Power Mode         " + powerDescriptor.getCurrentPowerMode());
            writer.println("| |> Power Level                " + powerDescriptor.getPowerLevel());
        }

        writer.println("|");
        writer.println("|>| ZDO");
        writer.println("| |> ManagementBindRequest      "
                + checkZdoSupported(out, networkManager, node.getNetworkAddress(), new ManagementBindRequest(0)));
        writer.println("| |> IeeeAddressRequest         "
                + checkZdoSupported(out, networkManager, node.getNetworkAddress(),
                        new IeeeAddressRequest(node.getNetworkAddress(), 1, 0)));
        writer.println("| |> ManagementLqiRequest       "
                + checkZdoSupported(out, networkManager, node.getNetworkAddress(),
                        new ManagementLqiRequest(0)));
        writer.println("| |> ManagementRoutingRequest   "
                + checkZdoSupported(out, networkManager, node.getNetworkAddress(),
                        new ManagementRoutingRequest(0)));

        for (ZigBeeEndpoint endpoint : node.getEndpoints()) {
            ZclCluster cluster = endpoint.getInputCluster(ZclBasicCluster.CLUSTER_ID);
            if (cluster != null) {
                writer.println("|");
                writer.println("|>| Basic Information");
                getBasicInformation(writer, cluster);
                break;
            }
        }

        for (ZigBeeEndpoint endpoint : node.getEndpoints()) {
            getEndpointInfo(writer, networkManager, endpoint);
        }

        out.println(baos.toString());
    }

    private void getBasicInformation(PrintStream out, ZclCluster cluster) {
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_GENERICDEVICECLASS);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_GENERICDEVICETYPE);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_MANUFACTURERNAME);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_MODELIDENTIFIER);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_PRODUCTCODE);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_PRODUCTURL);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_DATECODE);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_APPLICATIONVERSION);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_SWBUILDID);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_HWVERSION);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_ZCLVERSION);
        getBasicAttribute(out, cluster, ZclBasicCluster.ATTR_STACKVERSION);
    }

    private void getEndpointInfo(PrintStream out, ZigBeeNetworkManager networkManager, ZigBeeEndpoint endpoint) {
        out.println("| |");
        out.println("| |>| Endpoint " + endpoint.getEndpointId());

        out.print("| | |> Profile                  " + String.format("%04X", endpoint.getProfileId()));
        if (ZigBeeProfileType.getByValue(endpoint.getProfileId()) != null) {
            out.print("  " + ZigBeeProfileType.getByValue(endpoint.getProfileId()).toString());
        }
        out.println();
        out.print("| | |> Device Type              " + String.format("%04X", endpoint.getDeviceId()));
        if (ZigBeeDeviceType.getByValue(endpoint.getDeviceId()) != null) {
            out.print("  " + ZigBeeDeviceType
                    .getByValue(ZigBeeProfileType.getByValue(endpoint.getProfileId()), endpoint.getDeviceId())
                    .toString());
        }
        out.println();

        out.println("| | |> Device Version           " + endpoint.getDeviceVersion());

        if (endpoint.getEndpointId() >= 242) {
            return;
        }

        Collection clusterIds;

        out.println("| | |");
        out.println("| | |>| Input Clusters");
        clusterIds = endpoint.getInputClusterIds();
        for (int clusterId : clusterIds) {
            getClusterInfo(out, networkManager, endpoint.getInputCluster(clusterId));
        }

        out.println("| | |");
        out.println("| | |>| Output Clusters");
        clusterIds = endpoint.getOutputClusterIds();
        for (int clusterId : clusterIds) {
            getClusterInfo(out, networkManager, endpoint.getOutputCluster(clusterId));
        }
    }

    private void getClusterInfo(PrintStream out, ZigBeeNetworkManager networkManager, ZclCluster cluster) {
        out.println("| | | |");
        out.println(
                "| | | |>| Cluster " + String.format("%04X", cluster.getClusterId()) + " " + cluster.getClusterName());
        out.println("| | | | |> Type                 " + (cluster.isClient() ? "Client [Output]" : "Server [Input]"));
        out.print("| | | | |> Manufacturer Spec.   " + (cluster.isManufacturerSpecific() ? "Yes" : "No"));
        if (cluster.isManufacturerSpecific()) {
            out.print(" [" + String.format("%04X", cluster.getManufacturerCode()) + "]");
        }
        out.println();

        if ((cluster.isClient() && !networkManager.isClientClusterSupported(cluster.getClusterId())) ||
                (cluster.isServer() && !networkManager.isServerClusterSupported(cluster.getClusterId()))) {
            out.println("| | | | |> Unsupported locally");
            return;
        }
        ZigBeeStatus success;
        try {
            success = cluster.discoverCommandsGenerated(true).get() ? ZigBeeStatus.SUCCESS : ZigBeeStatus.FAILURE;
        } catch (InterruptedException | ExecutionException e) {
            success = ZigBeeStatus.FATAL_ERROR;
        }
        out.println("| | | | |");
        out.println("| | | | |>| Commands Generated");
        if (success == ZigBeeStatus.SUCCESS) {
            for (int commandId : cluster.getSupportedCommandsGenerated()) {
                out.println(
                        "| | | | | |> " + String.format("%04X", commandId) + " " + getCommandName(cluster, commandId));
            }
        } else {
            out.println("| | | | | |> " + success);
        }

        try {
            success = cluster.discoverCommandsReceived(true).get() ? ZigBeeStatus.SUCCESS : ZigBeeStatus.FAILURE;
        } catch (InterruptedException | ExecutionException e) {
            success = ZigBeeStatus.FATAL_ERROR;
        }
        out.println("| | | | |");
        out.println("| | | | |>| Commands Received");
        if (success == ZigBeeStatus.SUCCESS) {
            for (int commandId : cluster.getSupportedCommandsReceived()) {
                out.println(
                        "| | | | | |> " + String.format("%04X", commandId) + " " + getCommandName(cluster, commandId));
            }
        } else {
            out.println("| | | | | |> " + success);
        }

        try {
            success = cluster.discoverAttributes(true).get() ? ZigBeeStatus.SUCCESS : ZigBeeStatus.FAILURE;
        } catch (InterruptedException | ExecutionException e) {
            success = ZigBeeStatus.FATAL_ERROR;
        }
        out.println("| | | | |");
        out.println("| | | | |>| Attributes Supported");
        if (success == ZigBeeStatus.SUCCESS) {
            getAttributes(out, cluster, cluster.getSupportedAttributes());
        } else {
            out.println("| | | | | |> " + success);
            out.println("| | | | |");
            out.println("| | | | |>| Attribute Values");
            if (success == ZigBeeStatus.SUCCESS) {
                getAttributes(out, cluster.getAttributes());
            } else {
                out.println("| | | | | |> " + success);
            }
        }
    }

    private String getCommandName(ZclCluster cluster, int commandId) {
        ZclCommand command = null;

        if (cluster.isClient()) {
            command = cluster.getCommandFromId(ZclFrameType.CLUSTER_SPECIFIC_COMMAND, commandId);
        } else {
            command = cluster.getCommandFromId(ZclFrameType.CLUSTER_SPECIFIC_COMMAND, commandId);
        }

        if (command == null) {
            return "Unknown";
        }

        return command.getClass().getSimpleName();
    }

    private void getAttributes(PrintStream out, ZclCluster cluster, Collection attributeIds) {
        for (int attributeId : attributeIds) {
            ZclAttribute attribute = cluster.getAttribute(attributeId);
            Object value = null;
            ZclDataType dataType = null;
            if (attribute != null && attribute.isReadable()) {
                value = attribute.readValue(60L);
                dataType = attribute.getDataType();
            } else {
                try {
                    CommandResult result = cluster.readAttribute(attributeId).get();
                    ReadAttributesResponse response = result.getResponse();
                    ReadAttributeStatusRecord attributeRecord = response.getRecords().get(0);
                    if (attributeRecord.getStatus() == ZclStatus.SUCCESS) {
                        value = attributeRecord.getAttributeValue();
                        dataType = attributeRecord.getAttributeDataType();
                    }

                } catch (InterruptedException | ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            out.println(String.format("| | | | | |> %04X  %-40s  >> %-30s  %s", attributeId,
                    (attribute == null ? ""
                            : attribute.getName()),
                    (dataType == null ? "" : dataType),
                    (value == null ? "" : value.toString())));
        }
    }

    private void getAttributes(PrintStream out, Collection attributes) {
        for (ZclAttribute attribute : attributes) {
            Object value = null;
            if (!attribute.isReadable()) {
                continue;
            }

            value = attribute.readValue(60L);
            if (value == null) {
                continue;
            }
            out.println(String.format("| | | | | |> %04X  %-50s  >> %-30s  %s", attribute.getId(), attribute.getName(),
                    attribute.getDataType(),
                    value.toString()));
        }
    }

    private void getBasicAttribute(PrintStream out, ZclCluster cluster, int attributeId) {
        ZclAttribute attribute = cluster.getAttribute(attributeId);
        String name;
        Object value = attribute.readValue(0);
        switch (attribute.getId()) {
            case ZclBasicCluster.ATTR_APPLICATIONVERSION:
                name = "Application Version        ";
                break;
            case ZclBasicCluster.ATTR_DATECODE:
                name = "Date Code                  ";
                break;
            case ZclBasicCluster.ATTR_GENERICDEVICECLASS:
                name = "Generic Device Class       ";
                break;
            case ZclBasicCluster.ATTR_GENERICDEVICETYPE:
                name = "Generic Device Type        ";
                break;
            case ZclBasicCluster.ATTR_HWVERSION:
                name = "Hardware Version           ";
                break;
            case ZclBasicCluster.ATTR_MANUFACTURERNAME:
                name = "Manufacturer Name          ";
                break;
            case ZclBasicCluster.ATTR_MODELIDENTIFIER:
                name = "Model Identifier           ";
                break;
            case ZclBasicCluster.ATTR_PRODUCTCODE:
                name = "Product Code               ";
                break;
            case ZclBasicCluster.ATTR_PRODUCTURL:
                name = "Product URL                ";
                break;
            case ZclBasicCluster.ATTR_STACKVERSION:
                name = "Stack Version              ";
                break;
            case ZclBasicCluster.ATTR_SWBUILDID:
                name = "Software Build ID          ";
                break;
            case ZclBasicCluster.ATTR_ZCLVERSION:
                name = "Zcl Version                ";
                break;
            default:
                return;
        }
        out.println("| |> " + name + (value == null ? "" : value.toString()));
    }

    private ZdoStatus checkZdoSupported(PrintStream out, ZigBeeNetworkManager networkManager, int address,
            ZdoCommand command) {
        command.setDestinationAddress(new ZigBeeEndpointAddress(address));

        CommandResult result;
        try {
            result = networkManager.sendTransaction(command, (ZigBeeTransactionMatcher) command).get();
        } catch (InterruptedException | ExecutionException e) {
            return ZdoStatus.TIMEOUT;
        }
        if (result.isTimeout()) {
            return ZdoStatus.TIMEOUT;
        }
        if (result.isSuccess()) {
            return ZdoStatus.SUCCESS;
        }

        if (ZdoStatus.getStatus(result.getStatusCode()) == null) {
            return ZdoStatus.UNKNOWN;
        }

        return ZdoStatus.getStatus(result.getStatusCode());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy