Ejemplo n.º 1
0
        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();

            builder.Append("CommandResult [");

            if (IsSuccess())
            {
                builder.Append("SUCCESS, ")
                .Append(Response.ToString());
            }
            else if (IsTimeout())
            {
                builder.Append("TIMEOUT");
            }
            else
            {
                ZclStatus status = (ZclStatus)GetStatusCode();

                builder.Append("ERROR (")
                .Append(status.ToString())
                .Append(string.Format(",0x{0}), ", ((int)status).ToString("X2")))
                .Append(Response);
            }

            builder.Append(']');
            return(builder.ToString());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// The Default Response
        ///
        /// The default response command is generated when a device receives a unicast       /// command, there is no other relevant response specified for the command, and       /// either an error results or the Disable default response bit of its Frame control field       /// is set to 0.       ///
        /// @param commandIdentifier {@link byte} Command identifier
        /// @param statusCode {@link ZclStatus} Status code
        /// @return the Task<CommandResult> command result Task
        /// </summary>
        public Task <CommandResult> DefaultResponse(byte commandIdentifier, ZclStatus statusCode)
        {
            DefaultResponse command = new DefaultResponse();

            // Set the fields
            command.CommandIdentifier = commandIdentifier;
            command.StatusCode        = statusCode;

            return(Send(command));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// The Write Attributes Structured Command
        ///
        /// The write attributes structured command is generated when a device wishes to       /// change the values of one or more attributes located on another device. Each write       /// attribute record shall contain the identifier and the actual value of the attribute, or       /// element thereof, to be written.       ///
        /// @param status {@link ZclStatus} Status
        /// @param attributeSelectors {@link object} Attribute selectors
        /// @return the Task<CommandResult> command result Task
        /// </summary>
        public Task <CommandResult> WriteAttributesStructuredCommand(ZclStatus status, object attributeSelectors)
        {
            WriteAttributesStructuredCommand command = new WriteAttributesStructuredCommand();

            // Set the fields
            command.Status             = status;
            command.AttributeSelectors = attributeSelectors;

            return(Send(command));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// The Write Attributes Structured Response
        ///
        /// The write attributes structured response command is generated in response to a       /// write attributes structured command.       ///
        /// @param status {@link ZclStatus} Status
        /// @param records {@link List<WriteAttributeStatusRecord>} Records
        /// @return the Task<CommandResult> command result Task
        /// </summary>
        public Task <CommandResult> WriteAttributesStructuredResponse(ZclStatus status, List <WriteAttributeStatusRecord> records)
        {
            WriteAttributesStructuredResponse command = new WriteAttributesStructuredResponse();

            // Set the fields
            command.Status  = status;
            command.Records = records;

            return(Send(command));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// The Remove All Scenes Response
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="groupId" <see cref="ushort"> Group ID</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> RemoveAllScenesResponse(ZclStatus status, ushort groupId)
        {
            RemoveAllScenesResponse command = new RemoveAllScenesResponse();

            // Set the fields
            command.Status  = status;
            command.GroupId = groupId;

            return(Send(command));
        }
Ejemplo n.º 6
0
        /// <summary>
        /// The Configure Reporting Response
        ///
        /// The Configure Reporting Response command is generated in response to a       /// Configure Reporting command.       ///
        /// @param status {@link ZclStatus} Status
        /// @param records {@link List<AttributeStatusRecord>} Records
        /// @return the Task<CommandResult> command result Task
        /// </summary>
        public Task <CommandResult> ConfigureReportingResponse(ZclStatus status, List <AttributeStatusRecord> records)
        {
            ConfigureReportingResponse command = new ConfigureReportingResponse();

            // Set the fields
            command.Status  = status;
            command.Records = records;

            return(Send(command));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// The Add Group Response
        ///
        /// The add group response is sent by the groups cluster server in response to an add
        /// group command.
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="groupId" <see cref="ushort"> Group ID</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> AddGroupResponse(ZclStatus status, ushort groupId)
        {
            AddGroupResponse command = new AddGroupResponse();

            // Set the fields
            command.Status  = status;
            command.GroupId = groupId;

            return(Send(command));
        }
Ejemplo n.º 8
0
        /// <summary>
        /// The View Group Response
        ///
        /// The view group response command is sent by the groups cluster server in response to a
        /// view group command.
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="groupId" <see cref="ushort"> Group ID</ param >
        /// <param name="groupName" <see cref="string"> Group Name</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> ViewGroupResponse(ZclStatus status, ushort groupId, string groupName)
        {
            ViewGroupResponse command = new ViewGroupResponse();

            // Set the fields
            command.Status    = status;
            command.GroupId   = groupId;
            command.GroupName = groupName;

            return(Send(command));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// The Copy Scene Response
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="groupId" <see cref="ushort"> Group ID</ param >
        /// <param name="sceneId" <see cref="byte"> Scene ID</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> CopySceneResponse(ZclStatus status, ushort groupId, byte sceneId)
        {
            CopySceneResponse command = new CopySceneResponse();

            // Set the fields
            command.Status  = status;
            command.GroupId = groupId;
            command.SceneId = sceneId;

            return(Send(command));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// The Upgrade End Command
        ///
        /// Upon reception all the image data, the client should verify the image to ensure its
        /// integrity and validity. If the device requires signed images it shall examine the
        /// image and verify the signature. Clients may perform additional manufacturer
        /// specific integrity checks to validate the image, for example, CRC check on the
        /// actual file data. <br> If the image fails any integrity checks, the client shall
        /// send an Upgrade End Request command to the upgrade server with a status of
        /// INVALID_IMAGE. In this case, the client may reinitiate the upgrade process in
        /// order to obtain a valid OTA upgrade image. The client shall not upgrade to the bad
        /// image and shall discard the downloaded image data. <br> If the image passes all
        /// integrity checks and the client does not require additional OTA upgrade image
        /// file, it shall send back an Upgrade End Request with a status of SUCCESS. However, if
        /// the client requires multiple OTA upgrade image files before performing an
        /// upgrade, it shall send an Upgrade End Request command with status
        /// REQUIRE_MORE_IMAGE. This shall indicate to the server that it cannot yet upgrade
        /// the image it received. <br> If the client decides to cancel the download process for
        /// any other reasons, it has the option of sending Upgrade End Request with status of
        /// ABORT at anytime during the download process. The client shall then try to
        /// reinitiate the download process again at a later time.
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="manufacturerCode" <see cref="ushort"> Manufacturer Code</ param >
        /// <param name="imageType" <see cref="ushort"> Image Type</ param >
        /// <param name="fileVersion" <see cref="uint"> File Version</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> UpgradeEndCommand(ZclStatus status, ushort manufacturerCode, ushort imageType, uint fileVersion)
        {
            UpgradeEndCommand command = new UpgradeEndCommand();

            // Set the fields
            command.Status           = status;
            command.ManufacturerCode = manufacturerCode;
            command.ImageType        = imageType;
            command.FileVersion      = fileVersion;

            return(Send(command));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Sends a default response to the client
        ///
        /// <param name="transactionId">the transaction ID to use in the response</param>
        /// <param name="commandIdentifier">the command identifier to which this is a response</param>
        /// <param name="status">the ZclStatus to send in the response</param>
        /// </summary>
        public void SendDefaultResponse(byte transactionId, byte commandIdentifier, ZclStatus status)
        {
            DefaultResponse defaultResponse = new DefaultResponse();

            defaultResponse.TransactionId      = transactionId;
            defaultResponse.CommandIdentifier  = commandIdentifier;
            defaultResponse.DestinationAddress = _zigbeeEndpoint.GetEndpointAddress();
            defaultResponse.ClusterId          = _clusterId;
            defaultResponse.StatusCode         = status;

            _zigbeeEndpoint.SendTransaction(defaultResponse);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// The Get Scene Membership Response
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="capacity" <see cref="byte"> Capacity</ param >
        /// <param name="groupId" <see cref="ushort"> Group ID</ param >
        /// <param name="sceneCount" <see cref="byte"> Scene Count</ param >
        /// <param name="sceneList" <see cref="List<byte>"> Scene List</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> GetSceneMembershipResponse(ZclStatus status, byte capacity, ushort groupId, byte sceneCount, List <byte> sceneList)
        {
            GetSceneMembershipResponse command = new GetSceneMembershipResponse();

            // Set the fields
            command.Status     = status;
            command.Capacity   = capacity;
            command.GroupId    = groupId;
            command.SceneCount = sceneCount;
            command.SceneList  = sceneList;

            return(Send(command));
        }
Ejemplo n.º 13
0
        /// <summary>
        /// The Query Specific File Response
        ///
        /// The server sends Query Specific File Response after receiving Query Specific File
        /// Request from a client. The server shall determine whether it first supports the
        /// Query Specific File Request command. Then it shall determine whether it has the
        /// specific file being requested by the client using all the information included in
        /// the request. The upgrade server sends a Query Specific File Response with one of the
        /// following status: SUCCESS, NO_IMAGE_AVAILABLE or NOT_AUTHORIZED. <br> A status
        /// of NO_IMAGE_AVAILABLE indicates that the server currently does not have the
        /// device specific file available for the client. A status of NOT_AUTHORIZED
        /// indicates the server is not authorized to send the file to the client.
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="manufacturerCode" <see cref="ushort"> Manufacturer Code</ param >
        /// <param name="imageType" <see cref="ushort"> Image Type</ param >
        /// <param name="fileVersion" <see cref="uint"> File Version</ param >
        /// <param name="imageSize" <see cref="uint"> Image Size</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> QuerySpecificFileResponse(ZclStatus status, ushort manufacturerCode, ushort imageType, uint fileVersion, uint imageSize)
        {
            QuerySpecificFileResponse command = new QuerySpecificFileResponse();

            // Set the fields
            command.Status           = status;
            command.ManufacturerCode = manufacturerCode;
            command.ImageType        = imageType;
            command.FileVersion      = fileVersion;
            command.ImageSize        = imageSize;

            return(Send(command));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// The Enhanced View Scene Response
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="groupId" <see cref="ushort"> Group ID</ param >
        /// <param name="sceneId" <see cref="byte"> Scene ID</ param >
        /// <param name="transitionTime" <see cref="ushort"> Transition Time</ param >
        /// <param name="sceneName" <see cref="string"> Scene Name</ param >
        /// <param name="extensionFieldSets" <see cref="List<ExtensionFieldSet>"> Extension Field Sets</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> EnhancedViewSceneResponse(ZclStatus status, ushort groupId, byte sceneId, ushort transitionTime, string sceneName, List <ExtensionFieldSet> extensionFieldSets)
        {
            EnhancedViewSceneResponse command = new EnhancedViewSceneResponse();

            // Set the fields
            command.Status             = status;
            command.GroupId            = groupId;
            command.SceneId            = sceneId;
            command.TransitionTime     = transitionTime;
            command.SceneName          = sceneName;
            command.ExtensionFieldSets = extensionFieldSets;

            return(Send(command));
        }
Ejemplo n.º 15
0
        /// <summary>
        /// The Image Block Response
        ///
        /// Upon receipt of an Image Block Request command the server shall generate an Image
        /// Block Response. If the server is able to retrieve the data for the client and does not
        /// wish to change the image download rate, it will respond with a status of SUCCESS and
        /// it will include all the fields in the payload. The use of file offset allows the
        /// server to send packets with variable data size during the upgrade process. This
        /// allows the server to support a case when the network topology of a client may change
        /// during the upgrade process, for example, mobile client may move around during the
        /// upgrade process. If the client has moved a few hops away, the data size shall be
        /// smaller. Moreover, using file offset eliminates the need for data padding since
        /// each Image Block Response command may contain different data size. A simple server
        /// implementation may choose to only support largest possible data size for the
        /// worst-case scenario in order to avoid supporting sending packets with variable
        /// data size. <br> The server shall respect the maximum data size value requested by
        /// the client and shall not send the data with length greater than that value. The
        /// server may send the data with length smaller than the value depending on the network
        /// topology of the client. For example, the client may be able to receive 100 bytes of
        /// data at once so it sends the request with 100 as maximum data size. But after
        /// considering all the security headers (perhaps from both APS and network levels)
        /// and source routing overhead (for example, the client is five hops away), the
        /// largest possible data size that the server can send to the client shall be smaller
        /// than 100 bytes.
        ///
        /// <param name="status" <see cref="ZclStatus"> Status</ param >
        /// <param name="manufacturerCode" <see cref="ushort"> Manufacturer Code</ param >
        /// <param name="imageType" <see cref="ushort"> Image Type</ param >
        /// <param name="fileVersion" <see cref="uint"> File Version</ param >
        /// <param name="fileOffset" <see cref="uint"> File Offset</ param >
        /// <param name="imageData" <see cref="ByteArray"> Image Data</ param >
        /// <returns> the command result Task </returns>
        /// </summary>
        public Task <CommandResult> ImageBlockResponse(ZclStatus status, ushort manufacturerCode, ushort imageType, uint fileVersion, uint fileOffset, ByteArray imageData)
        {
            ImageBlockResponse command = new ImageBlockResponse();

            // Set the fields
            command.Status           = status;
            command.ManufacturerCode = manufacturerCode;
            command.ImageType        = imageType;
            command.FileVersion      = fileVersion;
            command.FileOffset       = fileOffset;
            command.ImageData        = imageData;

            return(Send(command));
        }
Ejemplo n.º 16
0
        static void Main(string[] args)
        {
            // Configure Serilog
            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.Debug()
                         .WriteTo.Console()
                         .CreateLogger();

            try
            {
                Console.Write("Enter COM Port: ");

                string port = Console.ReadLine();

                ZigBeeSerialPort zigbeePort = new ZigBeeSerialPort(port);

                IZigBeeTransportTransmit dongle = new ZigBeeDongleTiCc2531(zigbeePort);

                ZigBeeNetworkManager networkManager = new ZigBeeNetworkManager(dongle);

                JsonNetworkSerializer deviceSerializer = new JsonNetworkSerializer("devices.json");
                networkManager.NetworkStateSerializer = deviceSerializer;

                ZigBeeDiscoveryExtension discoveryExtension = new ZigBeeDiscoveryExtension();
                discoveryExtension.SetUpdatePeriod(60);
                networkManager.AddExtension(discoveryExtension);

                // Initialise the network
                networkManager.Initialize();

                networkManager.AddCommandListener(new ZigBeeNetworkDiscoverer(networkManager));
                //networkManager.AddCommandListener(new ZigBeeNodeServiceDiscoverer(networkManager));
                networkManager.AddCommandListener(new ZigBeeTransaction(networkManager));
                networkManager.AddCommandListener(new ConsoleCommandListener());
                networkManager.AddNetworkNodeListener(new ConsoleNetworkNodeListener());

                networkManager.AddSupportedCluster(0x06);
                networkManager.AddSupportedCluster(0x08);
                networkManager.AddSupportedCluster(0x0300);

                ((ZigBeeDongleTiCc2531)dongle).SetLedMode(1, false); // green led
                ((ZigBeeDongleTiCc2531)dongle).SetLedMode(2, false); // red led

                ZigBeeStatus startupSucceded = networkManager.Startup(false);

                if (startupSucceded == ZigBeeStatus.SUCCESS)
                {
                    Log.Logger.Information("ZigBee console starting up ... [OK]");
                }
                else
                {
                    Log.Logger.Information("ZigBee console starting up ... [FAIL]");
                    return;
                }

                ZigBeeNode coord = networkManager.GetNode(0);


                Console.WriteLine("Joining enabled...");

                string cmd = Console.ReadLine();

                while (cmd != "exit")
                {
                    Console.WriteLine(networkManager.Nodes.Count + " node(s)");

                    if (cmd == "join")
                    {
                        coord.PermitJoin(true);
                    }
                    else if (cmd == "unjoin")
                    {
                        coord.PermitJoin(false);
                    }
                    else if (!string.IsNullOrEmpty(cmd))
                    {
                        Console.WriteLine("Destination Address: ");
                        string nwkAddr = Console.ReadLine();

                        if (ushort.TryParse(nwkAddr, out ushort addr))
                        {
                            var node = networkManager.GetNode(addr);

                            if (node != null)
                            {
                                ZigBeeEndpointAddress endpointAddress = null;
                                var endpoint = node.Endpoints.Values.FirstOrDefault();

                                if (endpoint != null)
                                {
                                    endpointAddress = endpoint.GetEndpointAddress();
                                }

                                if (endpointAddress == null)
                                {
                                    Console.WriteLine("No endpoint found");

                                    continue;
                                }

                                try
                                {
                                    if (cmd == "toggle")
                                    {
                                        networkManager.Send(endpointAddress, new ToggleCommand()).GetAwaiter().GetResult();
                                    }
                                    else if (cmd == "level")
                                    {
                                        Console.WriteLine("Level between 0 and 255: ");
                                        string level = Console.ReadLine();

                                        Console.WriteLine("time between 0 and 65535: ");
                                        string time = Console.ReadLine();

                                        var command = new MoveToLevelWithOnOffCommand()
                                        {
                                            Level          = byte.Parse(level),
                                            TransitionTime = ushort.Parse(time)
                                        };

                                        networkManager.Send(endpointAddress, command).GetAwaiter().GetResult();
                                    }
                                    else if (cmd == "move")
                                    {
                                        networkManager.Send(endpointAddress, new MoveCommand()
                                        {
                                            MoveMode = 1, Rate = 100
                                        }).GetAwaiter().GetResult();
                                    }
                                    else if (cmd == "on")
                                    {
                                        networkManager.Send(endpointAddress, new OnCommand()).GetAwaiter().GetResult();
                                    }
                                    else if (cmd == "off")
                                    {
                                        networkManager.Send(endpointAddress, new OffCommand()).GetAwaiter().GetResult();
                                    }
                                    else if (cmd == "effect")
                                    {
                                        networkManager.Send(endpointAddress, new OffCommand()).GetAwaiter().GetResult();

                                        bool state = false;
                                        for (int i = 0; i < 10; i++)
                                        {
                                            if (state)
                                            {
                                                networkManager.Send(endpointAddress, new OffCommand()).GetAwaiter().GetResult();
                                            }
                                            else
                                            {
                                                networkManager.Send(endpointAddress, new OnCommand()).GetAwaiter().GetResult();
                                            }

                                            state = !state;
                                            System.Threading.Thread.Sleep(1000);
                                        }
                                    }
                                    else if (cmd == "desc")
                                    {
                                        NodeDescriptorRequest nodeDescriptorRequest = new NodeDescriptorRequest()
                                        {
                                            DestinationAddress = endpointAddress,
                                            NwkAddrOfInterest  = addr
                                        };
                                        networkManager.SendTransaction(nodeDescriptorRequest);
                                    }
                                    else if (cmd == "color")
                                    {
                                        Console.WriteLine("Red between 0 and 255: ");
                                        string r = Console.ReadLine();

                                        Console.WriteLine("Green between 0 and 255: ");
                                        string g = Console.ReadLine();

                                        Console.WriteLine("Blue between 0 and 255: ");
                                        string b = Console.ReadLine();

                                        if (int.TryParse(r, out int _r) && int.TryParse(g, out int _g) && int.TryParse(b, out int _b))
                                        {
                                            CieColor xyY = ColorConverter.RgbToCie(_r, _g, _b);

                                            MoveToColorCommand command = new MoveToColorCommand()
                                            {
                                                ColorX         = xyY.X,
                                                ColorY         = xyY.Y,
                                                TransitionTime = 10
                                            };

                                            networkManager.Send(endpointAddress, command).GetAwaiter().GetResult();
                                        }
                                    }
                                    else if (cmd == "hue")
                                    {
                                        Console.WriteLine("Red between 0 and 255: ");
                                        string hue = Console.ReadLine();

                                        if (byte.TryParse(hue, out byte _hue))
                                        {
                                            MoveToHueCommand command = new MoveToHueCommand()
                                            {
                                                Hue            = _hue,
                                                Direction      = 0,
                                                TransitionTime = 10
                                            };

                                            networkManager.Send(endpointAddress, command).GetAwaiter().GetResult();
                                        }
                                    }
                                    else if (cmd == "read")
                                    {
                                        //var value = ((ZclOnOffCluster)endpoint.GetInputCluster(6)).GetAttribute(ZclOnOffCluster.ATTR_ONOFF);

                                        var result = ((ZclColorControlCluster)endpoint.GetInputCluster(ZclColorControlCluster.CLUSTER_ID)).Read(ZclColorControlCluster.ATTR_CURRENTY).Result;

                                        if (result.IsSuccess())
                                        {
                                            ReadAttributesResponse response = result.GetResponse <ReadAttributesResponse>();
                                            if (response.Records.Count == 0)
                                            {
                                                Console.WriteLine("No records returned");
                                                continue;
                                            }

                                            ZclStatus statusCode = response.Records[0].Status;
                                            if (statusCode == ZclStatus.SUCCESS)
                                            {
                                                Console.WriteLine("Cluster " + string.Format("%04X", response.ClusterId) + ", Attribute "
                                                                  + response.Records[0].AttributeIdentifier + ", type "
                                                                  + response.Records[0].AttributeDataType + ", value: "
                                                                  + response.Records[0].AttributeValue);
                                            }
                                            else
                                            {
                                                Console.WriteLine("Attribute value read error: " + statusCode);
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Log.Logger.Error(ex, "{Error}");
                                }
                            }
                            else
                            {
                                Console.WriteLine($"Node {addr} not found");
                            }
                        }
                    }

                    cmd = Console.ReadLine();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
Ejemplo n.º 17
0
 public override void Deserialize(ZclFieldDeserializer deserializer)
 {
     CommandIdentifier = deserializer.Deserialize <byte>(ZclDataType.Get(DataType.UNSIGNED_8_BIT_INTEGER));
     StatusCode        = deserializer.Deserialize <ZclStatus>(ZclDataType.Get(DataType.ZCL_STATUS));
 }
Ejemplo n.º 18
0
        static async Task Main(string[] args)
        {
            // Configure Serilog
            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.Debug()
                         .WriteTo.Console()
                         .CreateLogger();

            bool         showHelp     = false;
            ZigBeeDongle zigBeeDongle = ZigBeeDongle.TiCc2531;

            OptionSet options = new OptionSet
            {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "zbd|zigbeeDongle=", "the zigbee dongle to use. 0 = TiCc2531 | 1 = DigiXBee", (ZigBeeDongle zbd) => zigBeeDongle = zbd }
            };

            try
            {
                IList <string> extraArgs = options.Parse(args);
                foreach (string extraArg in extraArgs)
                {
                    Console.WriteLine($"Error: Unknown option: {extraArg}");
                    showHelp = true;
                }

                Console.Write("Enter COM Port: ");

                string port = Console.ReadLine();

                ZigBeeSerialPort zigbeePort = new ZigBeeSerialPort(port);

                IZigBeeTransportTransmit dongle;
                switch (zigBeeDongle)
                {
                case ZigBeeDongle.TiCc2531:
                {
                    dongle = new ZigBeeDongleTiCc2531(zigbeePort);
                }
                break;

                case ZigBeeDongle.DigiXbee:
                {
                    dongle = new ZigBeeDongleXBee(zigbeePort);
                }
                break;

                default:
                {
                    dongle = new ZigBeeDongleTiCc2531(zigbeePort);
                }
                break;
                }

                ZigBeeNetworkManager networkManager = new ZigBeeNetworkManager(dongle);

                JsonNetworkSerializer deviceSerializer = new JsonNetworkSerializer("devices.json");
                //networkManager.NetworkStateSerializer = deviceSerializer;

                ZigBeeDiscoveryExtension discoveryExtension = new ZigBeeDiscoveryExtension();
                discoveryExtension.SetUpdatePeriod(60);
                networkManager.AddExtension(discoveryExtension);

                // Initialise the network
                networkManager.Initialize();

                /* Network (de)serialization */
                //networkManager.AddCommandListener(new ZigBeeNetworkDiscoverer(networkManager));
                //networkManager.AddCommandListener(new ZigBeeNodeServiceDiscoverer(networkManager));

                networkManager.AddCommandListener(new ZigBeeTransaction(networkManager));
                networkManager.AddCommandListener(new ConsoleCommandListener());

                networkManager.AddNetworkNodeListener(new ConsoleNetworkNodeListener());

                networkManager.AddSupportedCluster(ZclOnOffCluster.CLUSTER_ID);
                networkManager.AddSupportedCluster(ZclColorControlCluster.CLUSTER_ID);
                networkManager.AddSupportedCluster(ZclTouchlinkCluster.CLUSTER_ID);

                networkManager.AddExtension(new ZigBeeBasicServerExtension());

                if (zigBeeDongle == ZigBeeDongle.TiCc2531)
                {
                    ((ZigBeeDongleTiCc2531)dongle).SetLedMode(1, false); // green led
                    ((ZigBeeDongleTiCc2531)dongle).SetLedMode(2, false); // red led
                }

                ZigBeeStatus startupSucceded = networkManager.Startup(false);

                if (startupSucceded == ZigBeeStatus.SUCCESS)
                {
                    Log.Logger.Information("ZigBee console starting up ... [OK]");
                }
                else
                {
                    Log.Logger.Information("ZigBee console starting up ... [FAIL]");
                    Log.Logger.Information("Press any key to exit...");
                    Console.ReadKey();
                    return;
                }

                ZigBeeNode coord = networkManager.GetNode(0);

                Console.WriteLine("Joining enabled...");

                string cmd = string.Empty;

                while (cmd != "exit")
                {
                    Console.WriteLine(networkManager.Nodes.Count + " node(s)" + Environment.NewLine);

                    if (cmd == "join")
                    {
                        coord.PermitJoin(true);
                    }
                    else if (cmd == "unjoin")
                    {
                        coord.PermitJoin(false);
                    }
                    else if (!string.IsNullOrEmpty(cmd))
                    {
                        var tmp = Console.ForegroundColor;
                        Console.ForegroundColor = ConsoleColor.DarkGreen;
                        Console.Write("Destination Address: ");
                        Console.ForegroundColor = tmp;
                        string nwkAddr = Console.ReadLine();

                        if (ushort.TryParse(nwkAddr, out ushort addr))
                        {
                            var node = networkManager.GetNode(addr);

                            if (node != null)
                            {
                                ZigBeeEndpointAddress endpointAddress = null;
                                var endpoint = node.Endpoints.Values.FirstOrDefault();

                                if (endpoint != null)
                                {
                                    endpointAddress = endpoint.GetEndpointAddress();
                                }

                                if (endpointAddress == null)
                                {
                                    Console.WriteLine("No endpoint found");

                                    continue;
                                }

                                try
                                {
                                    if (cmd == "toggle")
                                    {
                                        await networkManager.Send(endpointAddress, new ToggleCommand());
                                    }
                                    else if (cmd == "level")
                                    {
                                        Console.WriteLine("Level between 0 and 255: ");
                                        string level = Console.ReadLine();

                                        Console.WriteLine("time between 0 and 65535: ");
                                        string time = Console.ReadLine();

                                        var command = new MoveToLevelWithOnOffCommand()
                                        {
                                            Level          = byte.Parse(level),
                                            TransitionTime = ushort.Parse(time)
                                        };

                                        await networkManager.Send(endpointAddress, command);
                                    }
                                    else if (cmd == "move")
                                    {
                                        await networkManager.Send(endpointAddress, new MoveCommand()
                                        {
                                            MoveMode = 1, Rate = 100
                                        });
                                    }
                                    else if (cmd == "on")
                                    {
                                        await networkManager.Send(endpointAddress, new OnCommand());
                                    }
                                    else if (cmd == "off")
                                    {
                                        await networkManager.Send(endpointAddress, new OffCommand());
                                    }
                                    else if (cmd == "effect")
                                    {
                                        await networkManager.Send(endpointAddress, new OffCommand());

                                        bool state = false;
                                        for (int i = 0; i < 10; i++)
                                        {
                                            if (state)
                                            {
                                                await networkManager.Send(endpointAddress, new OffCommand());
                                            }
                                            else
                                            {
                                                await networkManager.Send(endpointAddress, new OnCommand());
                                            }

                                            state = !state;
                                            await Task.Delay(1000);
                                        }
                                    }
                                    else if (cmd == "stress")
                                    {
                                        await networkManager.Send(endpointAddress, new OffCommand());

                                        bool state = false;
                                        for (int i = 0; i < 100; i++)
                                        {
                                            if (state)
                                            {
                                                await networkManager.Send(endpointAddress, new OffCommand());
                                            }
                                            else
                                            {
                                                await networkManager.Send(endpointAddress, new OnCommand());
                                            }

                                            state = !state;

                                            await Task.Delay(1);
                                        }
                                    }
                                    else if (cmd == "desc")
                                    {
                                        NodeDescriptorRequest nodeDescriptorRequest = new NodeDescriptorRequest()
                                        {
                                            Destination       = endpointAddress,
                                            NwkAddrOfInterest = addr
                                        };

                                        networkManager.SendTransaction(nodeDescriptorRequest);
                                    }
                                    else if (cmd == "color")
                                    {
                                        Console.WriteLine("Red between 0 and 255: ");
                                        string r = Console.ReadLine();

                                        Console.WriteLine("Green between 0 and 255: ");
                                        string g = Console.ReadLine();

                                        Console.WriteLine("Blue between 0 and 255: ");
                                        string b = Console.ReadLine();

                                        if (int.TryParse(r, out int _r) && int.TryParse(g, out int _g) && int.TryParse(b, out int _b))
                                        {
                                            CieColor xyY = ColorConverter.RgbToCie(_r, _g, _b);

                                            MoveToColorCommand command = new MoveToColorCommand()
                                            {
                                                ColorX         = xyY.X,
                                                ColorY         = xyY.Y,
                                                TransitionTime = 10
                                            };

                                            await networkManager.Send(endpointAddress, command);
                                        }
                                    }
                                    else if (cmd == "hue")
                                    {
                                        Console.WriteLine("Red between 0 and 255: ");
                                        string hue = Console.ReadLine();

                                        if (byte.TryParse(hue, out byte _hue))
                                        {
                                            MoveToHueCommand command = new MoveToHueCommand()
                                            {
                                                Hue            = _hue,
                                                Direction      = 0,
                                                TransitionTime = 10
                                            };

                                            await networkManager.Send(endpointAddress, command);
                                        }
                                    }
                                    else if (cmd == "read")
                                    {
                                        var result = await((ZclElectricalMeasurementCluster)endpoint.GetInputCluster(ZclElectricalMeasurementCluster.CLUSTER_ID)).Read(ZclElectricalMeasurementCluster.ATTR_MEASUREMENTTYPE);

                                        if (result.IsSuccess())
                                        {
                                            ReadAttributesResponse response = result.GetResponse <ReadAttributesResponse>();
                                            if (response.Records.Count == 0)
                                            {
                                                Console.WriteLine("No records returned");
                                                continue;
                                            }

                                            ZclStatus statusCode = response.Records[0].Status;
                                            if (statusCode == ZclStatus.SUCCESS)
                                            {
                                                Console.WriteLine("Cluster " + response + ", Attribute "
                                                                  + response.Records[0].AttributeIdentifier + ", type "
                                                                  + response.Records[0].AttributeDataType + ", value: "
                                                                  + response.Records[0].AttributeValue);
                                            }
                                            else
                                            {
                                                Console.WriteLine("Attribute value read error: " + statusCode);
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Log.Logger.Error(ex, "{Error}");
                                }
                            }
                            else
                            {
                                Console.WriteLine($"Node {addr} not found");
                            }
                        }
                    }

                    var currentForeGroundColor = Console.ForegroundColor;
                    Console.ForegroundColor = ConsoleColor.DarkGreen;
                    Console.Write("cmd> ");
                    Console.ForegroundColor = currentForeGroundColor;
                    cmd = Console.ReadLine();
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            if (showHelp)
            {
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }
        }