Example #1
0
        private void ZwaveMessageReceived(object sender, ZWaveMessageReceivedEventArgs args)
        {
            // discard repeated messages within last 2 seconds time range
            bool repeated = false;

            if (lastMessage != null)
            {
                var elapsed = (DateTime.UtcNow - lastMessageTimestamp);
                if (elapsed.TotalSeconds <= 2 && lastMessage.SequenceEqual(args.Message))
                {
                    //Utility.DebugLog(DebugMessageType.Information, " lastMessage: " + Utility.ByteArrayToString(lastMessage));
                    //Utility.DebugLog(DebugMessageType.Information, "args.Message: " + Utility.ByteArrayToString(args.Message));
                    repeated = true;
                }
            }
            lastMessageTimestamp = DateTime.UtcNow;
            lastMessage          = new byte[args.Message.Length];
            //Utility.DebugLog(DebugMessageType.Information, " lastMessage2: " + Utility.ByteArrayToString(lastMessage));
            //Utility.DebugLog(DebugMessageType.Information, "args.Message2: " + Utility.ByteArrayToString(args.Message));
            Buffer.BlockCopy(args.Message, 0, lastMessage, 0, args.Message.Length * sizeof(byte));
            if (repeated)
            {
                Utility.DebugLog(DebugMessageType.Warning, "Repeated message discarded.");
                return;
            }
            //
            int length = args.Message.Length;

            try
            {
                MessageHeader zwaveHeader = (MessageHeader)args.Message[0];
                switch (zwaveHeader)
                {
                case MessageHeader.CAN:
                    // RESEND
                    //Utility.DebugLog(DebugMessageType.Warning, "Received CAN, resending last message");
                    //zp.ResendLastMessage();
                    break;

                case MessageHeader.ACK:
                    break;

                case MessageHeader.SOF: // start of zwave frame
                    //
                    // parse frame headers
                    //
                    //int msgLength = (int)args.Message[1];
                    var  msgType       = (MessageType)args.Message[2];
                    var  function      = (args.Message.Length > 3 ? (Function)args.Message[3] : 0);
                    byte sourceNodeId  = 0;
                    byte nodeOperation = 0;
                    //
                    switch (msgType)
                    {
                    case MessageType.Request:

                        if (devices.Count == 0)
                        {
                            break;
                        }

                        switch (function)
                        {
                        case Function.None:
                            break;

                        case Function.NodeAdd:

                            nodeOperation = args.Message[5];
                            if (nodeOperation == (byte)NodeFunctionStatus.AddNodeAddingSlave)
                            {
                                nodeOperationIdCheck = args.Message[6];
                                var newNode = CreateDevice(nodeOperationIdCheck, 0x00);
                                // Extract node information frame
                                int nodeInfoLength = (int)args.Message[7];
                                // we don't need to exclude the last 2 CommandClasses
                                byte[] nodeInfo = new byte[nodeInfoLength];
                                Array.Copy(args.Message, 8, nodeInfo, 0, nodeInfoLength);
                                newNode.NodeInformationFrame = nodeInfo;

                                newNode.BasicClass    = args.Message[8];
                                newNode.GenericClass  = args.Message[9];
                                newNode.SpecificClass = args.Message[10];
                                devices.Add(newNode);

                                if (newNode.SupportCommandClass(CommandClass.Security))
                                {
                                    var nodeSecurityData = Security.GetSecurityData(newNode);
                                    nodeSecurityData.IsAddingNode = true;

                                    Security.GetScheme(newNode);
                                }
                                else
                                {
                                    gotNodeUpdateInformation(newNode);
                                }
                            }
                            else if (nodeOperation == (byte)NodeFunctionStatus.AddNodeProtocolDone /* || nodeOperation == (byte)NodeFunctionStatus.AddNodeDone */)
                            {
                                if (nodeOperationIdCheck == args.Message[6])
                                {
                                    Thread.Sleep(500);
                                    GetNodeCapabilities(args.Message[6]);
                                    var newNode = devices.Find(n => n.Id == args.Message[6]);
                                    if (newNode != null)
                                    {
                                        ManufacturerSpecific.Get(newNode);
                                    }
                                }
                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.DiscoveryEnd));
                            }
                            else if (nodeOperation == (byte)NodeFunctionStatus.AddNodeFailed)
                            {
                                Utility.DebugLog(DebugMessageType.Warning, "ADDING NODE FAILED (" + args.Message[6] + ")");
                            }
                            break;

                        case Function.NodeRemove:

                            nodeOperation = args.Message[5];
                            if (nodeOperation == (byte)NodeFunctionStatus.RemoveNodeRemovingSlave)
                            {
                                nodeOperationIdCheck = args.Message[6];
                            }
                            else if (nodeOperation == (byte)NodeFunctionStatus.RemoveNodeDone)
                            {
                                if (nodeOperationIdCheck == args.Message[6])
                                {
                                    RemoveDevice(args.Message[6]);
                                }
                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.DiscoveryEnd));
                            }
                            else if (nodeOperation == (byte)NodeFunctionStatus.RemoveNodeFailed)
                            {
                                Utility.DebugLog(DebugMessageType.Warning, "REMOVING NODE FAILED (" + args.Message[6] + ")");
                            }
                            break;

                        case Function.ApplicationCommand:

                            sourceNodeId = args.Message[5];
                            var node = devices.Find(n => n.Id == sourceNodeId);
                            if (node != null)
                            {
                                try
                                {
                                    node.MessageRequestHandler(args.Message);
                                }
                                catch (Exception ex)
                                {
                                    Utility.DebugLog(DebugMessageType.Error, "Exception occurred in node.MessageRequestHandler: " + ex.Message + "\n" + ex.StackTrace);
                                }
                            }
                            else
                            {
                                Utility.DebugLog(DebugMessageType.Error, "Unknown node id " + sourceNodeId);
                            }
                            break;

                        case Function.SendData:

                            byte commandId = args.Message[4];
                            if (commandId == 0x01) // SEND DATA OK
                            {
                                // TODO: ... what does that mean?
                            }
                            else if (args.Message[5] == 0x00)
                            {
                                // Messaging complete, remove callbackid
                                zwavePort.PendingMessages.RemoveAll(zm => zm.CallbackId == commandId);
                            }
                            else if (args.Message[5] == 0x01)
                            {
                                var  unsentMessage = zwavePort.PendingMessages.Find(zm => zm.CallbackId == commandId);
                                byte nodeID        = zwavePort.ResendLastMessage(commandId);
                                if (nodeID != 0)
                                {
                                    // Resend timed out
                                    OnControllerEvent(new ControllerEventArgs(nodeID, ControllerStatus.NodeError));
                                    // Check if node supports WakeUp class, and add message to wake up message queue
                                    if (unsentMessage != null)
                                    {
                                        var sleepingNode = devices.Find(n => n.Id == nodeID);
                                        if (sleepingNode != null && sleepingNode.SupportCommandClass(CommandClass.WakeUp))
                                        {
                                            WakeUp.ResendOnWakeUp(sleepingNode, unsentMessage.Message);
                                        }
                                    }
                                }
                            }
                            break;

                        case Function.NodeUpdateInfo:

                            sourceNodeId = args.Message[5];
                            int nifLength = (int)args.Message[6];
                            var znode     = devices.Find(n => n.Id == sourceNodeId);
                            if (znode != null)
                            {
                                // we don't need to exclude the last 2 CommandClasses
                                byte[] nodeInfo = new byte[nifLength];
                                Array.Copy(args.Message, 7, nodeInfo, 0, nifLength);
                                znode.NodeInformationFrame = nodeInfo;
                                if (znode.SupportCommandClass(CommandClass.Security))
                                {
                                    // ask the node what security command classes are supported
                                    Security.GetSupported(znode);
                                }
                                else
                                {
                                    gotNodeUpdateInformation(znode);
                                }
                            }
                            break;

                        default:
                            Utility.DebugLog(DebugMessageType.Warning, "Unhandled REQUEST " + Utility.ByteArrayToString(args.Message));
                            break;
                        }

                        break;

                    case MessageType.Response:

                        switch (function)
                        {
                        case Function.DiscoveryNodes:
                            MessageResponseNodeBitMaskHandler(args.Message);
                            break;

                        case Function.GetNodeProtocolInfo:
                            MessageResponseNodeCapabilityHandler(args.Message);
                            break;

                        case Function.RequestNodeInfo:
                            // TODO: shall we do something here?
                            break;

                        case Function.SendData:
                            // TODO: shall we do something here?
                            break;

                        default:
                            Utility.DebugLog(DebugMessageType.Warning, "Unhandled RESPONSE " + Utility.ByteArrayToString(args.Message));
                            break;
                        }

                        break;

                    default:
                        Utility.DebugLog(DebugMessageType.Warning, "Unhandled MESSAGE TYPE " + Utility.ByteArrayToString(args.Message));
                        break;
                    }

                    break;
                }
            }
            catch (Exception ex)
            {
                Utility.DebugLog(DebugMessageType.Error, "Exception occurred :" + ex.Message + "\n" + ex.StackTrace);
            }
        }
Example #2
0
        private void ZwaveMessageReceived(object sender, ZWaveMessageReceivedEventArgs args)
        {
            // discard repeated messages within last 2 seconds time range
            bool repeated = false;

            if (lastMessage != null)
            {
                var elapsed = (DateTime.UtcNow - lastMessageTimestamp);
                if (elapsed.TotalSeconds <= 2 && lastMessage.SequenceEqual(args.Message))
                {
                    repeated = true;
                }
            }
            lastMessageTimestamp = DateTime.UtcNow;
            lastMessage          = new byte[args.Message.Length];
            Buffer.BlockCopy(args.Message, 0, lastMessage, 0, args.Message.Length * sizeof(byte));
            if (repeated)
            {
                zwavePort.SendAck();
                Console.WriteLine("ZWaveLib: repeated message discarded.");
                return;
            }
            //
            int length = args.Message.Length;

            try
            {
                MessageHeader zwaveHeader = (MessageHeader)args.Message[0];
                switch (zwaveHeader)
                {
                case MessageHeader.CAN:
                    zwavePort.SendAck();
                    // RESEND
                    //Console.WriteLine("ZWaveLib: received CAN, resending last message");
                    //zp.ResendLastMessage();
                    break;

                case MessageHeader.ACK:
                    zwavePort.SendAck();
                    break;

                case MessageHeader.SOF: // start of zwave frame
                    //
                    // parse frame headers
                    //
                    //int msgLength = (int)args.Message[1];
                    var  msgType       = (MessageType)args.Message[2];
                    var  function      = (args.Message.Length > 3 ? (Function)args.Message[3] : 0);
                    byte sourceNodeId  = 0;
                    byte nodeOperation = 0;
                    //
                    switch (msgType)
                    {
                    case MessageType.Request:
                        zwavePort.SendAck();

                        if (devices.Count == 0)
                        {
                            break;
                        }

                        switch (function)
                        {
                        case Function.None:
                            break;

                        case Function.NodeAdd:

                            nodeOperation = args.Message[5];
                            if (nodeOperation == (byte)NodeFunctionStatus.AddNodeAddingSlave)
                            {
                                //Console.WriteLine("\n\nADDING NODE SLAVE {0}\n     ->   ", zp.ByteArrayToString(args.Message));
                                nodeOperationIdCheck = args.Message[6];
                                var newNode = CreateDevice(nodeOperationIdCheck, 0x00);
                                // Extract node information frame
                                int    nodeInfoLength = (int)args.Message[7];
                                byte[] nodeInfo       = new byte[nodeInfoLength - 2];
                                Array.Copy(args.Message, 8, nodeInfo, 0, nodeInfoLength - 2);
                                newNode.NodeInformationFrame = nodeInfo;
                                RaiseUpdateParameterEvent(new ZWaveEvent(newNode, EventParameter.NodeInfo, Utility.ByteArrayToString(nodeInfo), 0));
                                SaveNodesConfig();
                            }
                            else if (nodeOperation == (byte)NodeFunctionStatus.AddNodeProtocolDone /* || nodeOperation == (byte)NodeFunctionStatus.AddNodeDone */)
                            {
                                if (nodeOperationIdCheck == args.Message[6])
                                {
                                    //Console.WriteLine("\n\nADDING NODE DONE {0} {1}\n\n", args.Message[6], callbackid);
                                    Thread.Sleep(500);
                                    GetNodeCapabilities(args.Message[6]);
                                    var newNode = devices.Find(n => n.Id == args.Message[6]);
                                    if (newNode != null)
                                    {
                                        ManufacturerSpecific.Get(newNode);
                                    }
                                }
                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.DiscoveryEnd));
                            }
                            else if (nodeOperation == (byte)NodeFunctionStatus.AddNodeFailed)
                            {
                                //Console.WriteLine("\n\nADDING NODE FAIL {0}\n\n", args.Message[6]);
                            }
                            break;

                        case Function.NodeRemove:

                            nodeOperation = args.Message[5];
                            if (nodeOperation == (byte)NodeFunctionStatus.RemoveNodeRemovingSlave)
                            {
                                //Console.WriteLine("\n\nREMOVING NODE SLAVE {0}\n\n", args.Message[6]);
                                nodeOperationIdCheck = args.Message[6];
                            }
                            else if (nodeOperation == (byte)NodeFunctionStatus.RemoveNodeDone)
                            {
                                if (nodeOperationIdCheck == args.Message[6])
                                {
                                    //Console.WriteLine("\n\nREMOVING NODE DONE {0} {1}\n\n", args.Message[6], callbackid);
                                    RemoveDevice(args.Message[6]);
                                }
                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.DiscoveryEnd));
                            }
                            else if (nodeOperation == (byte)NodeFunctionStatus.RemoveNodeFailed)
                            {
                                //Console.WriteLine("\n\nREMOVING NODE FAIL {0}\n\n", args.Message[6]);
                            }
                            break;

                        case Function.ApplicationCommand:

                            sourceNodeId = args.Message[5];
                            var node = devices.Find(n => n.Id == sourceNodeId);
                            if (node == null)
                            {
                                CreateDevice(sourceNodeId, 0x00);
                                GetNodeCapabilities(sourceNodeId);
                            }
                            try
                            {
                                node.MessageRequestHandler(args.Message);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("# " + ex.Message + "\n" + ex.StackTrace);
                            }
                            break;

                        case Function.SendData:

                            byte commandId = args.Message[4];
                            if (commandId == 0x01) // SEND DATA OK
                            {
                                // TODO: ... what does that mean?
                            }
                            else if (args.Message[5] == 0x00)
                            {
                                // Messaging complete, remove callbackid
                                zwavePort.PendingMessages.RemoveAll(zm => zm.CallbackId == commandId);
                            }
                            else if (args.Message[5] == 0x01)
                            {
                                var  unsentMessage = zwavePort.PendingMessages.Find(zm => zm.CallbackId == commandId);
                                byte nodeID        = zwavePort.ResendLastMessage(commandId);
                                if (nodeID != 0)
                                {
                                    // Resend timed out
                                    OnControllerEvent(new ControllerEventArgs(nodeID, ControllerStatus.NodeError));
                                    // Check if node supports WakeUp class, and add message to wake up message queue
                                    if (unsentMessage != null)
                                    {
                                        var sleepingNode = devices.Find(n => n.Id == nodeID);
                                        if (sleepingNode != null && sleepingNode.SupportCommandClass(CommandClass.WakeUp))
                                        {
                                            WakeUp.ResendOnWakeUp(sleepingNode, unsentMessage.Message);
                                        }
                                    }
                                }
                            }
                            break;

                        case Function.NodeUpdateInfo:

                            sourceNodeId = args.Message[5];
                            int nifLength = (int)args.Message[6];
                            var znode     = devices.Find(n => n.Id == sourceNodeId);
                            if (znode != null)
                            {
                                byte[] nodeInfo = new byte[nifLength - 2];
                                //Console.WriteLine(ByteArrayToString(args.Message));
                                Array.Copy(args.Message, 7, nodeInfo, 0, nifLength - 2);
                                znode.NodeInformationFrame = nodeInfo;
                                //
                                RaiseUpdateParameterEvent(new ZWaveEvent(znode, EventParameter.NodeInfo, Utility.ByteArrayToString(nodeInfo), 0));
                                RaiseUpdateParameterEvent(new ZWaveEvent(znode, EventParameter.WakeUpNotify, "1", 0));
                                SaveNodesConfig();
                            }
                            break;

                        default:
                            Console.WriteLine("\nUNHANDLED Z-Wave REQUEST\n     " + Utility.ByteArrayToString(args.Message) + "\n");
                            break;
                        }

                        break;

                    case MessageType.Response:

                        switch (function)
                        {
                        case Function.DiscoveryNodes:
                            MessageResponseNodeBitMaskHandler(args.Message);
                            break;

                        case Function.GetNodeProtocolInfo:
                            MessageResponseNodeCapabilityHandler(args.Message);
                            break;

                        case Function.RequestNodeInfo:
                            // TODO: shall we do something here?
                            break;

                        case Function.SendData:
                            // TODO: shall we do something here?
                            break;

                        default:
                            Console.WriteLine("\nUNHANDLED Z-Wave RESPONSE\n     " + Utility.ByteArrayToString(args.Message) + "\n");
                            break;
                        }

                        break;

                    default:
                        Console.WriteLine("\nUNHANDLED Z-Wave message TYPE\n     " + Utility.ByteArrayToString(args.Message) + "\n");
                        break;
                    }

                    break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
            }
        }
Example #3
0
        private void ZwaveMessageReceived(object sender, ZWaveMessageReceivedEventArgs args)
        {
            // discard repeated messages within last 2 seconds time range
            bool repeated = false;

            if (lastMessage != null)
            {
                var elapsed = (DateTime.UtcNow - lastMessageTimestamp);
                if (elapsed.TotalSeconds <= 2 && lastMessage.SequenceEqual(args.Message))
                {
                    //Utility.DebugLog(DebugMessageType.Information, " lastMessage: " + Utility.ByteArrayToString(lastMessage));
                    //Utility.DebugLog(DebugMessageType.Information, "args.Message: " + Utility.ByteArrayToString(args.Message));
                    repeated = true;
                }
            }
            lastMessageTimestamp = DateTime.UtcNow;
            lastMessage          = new byte[args.Message.Length];
            //Utility.DebugLog(DebugMessageType.Information, " lastMessage2: " + Utility.ByteArrayToString(lastMessage));
            //Utility.DebugLog(DebugMessageType.Information, "args.Message2: " + Utility.ByteArrayToString(args.Message));
            Buffer.BlockCopy(args.Message, 0, lastMessage, 0, args.Message.Length * sizeof(byte));
            if (repeated)
            {
                Utility.DebugLog(DebugMessageType.Warning, "Repeated message discarded.");
                return;
            }
            //
            int length = args.Message.Length;

            try
            {
                MessageHeader zwaveHeader = (MessageHeader)args.Message[0];
                switch (zwaveHeader)
                {
                case MessageHeader.CAN:
                    // RESEND ?!?!
                    break;

                case MessageHeader.ACK:
                    break;

                case MessageHeader.SOF: // start of zwave frame
                    var messageType = MessageType.None;
                    Enum.TryParse(args.Message[2].ToString(), out messageType);
                    var functionType = Function.None;
                    Enum.TryParse(args.Message[3].ToString(), out functionType);

                    switch (messageType)
                    {
                    case MessageType.Request:

                        if (devices.Count == 0)
                        {
                            break;
                        }

                        switch (functionType)
                        {
                        case Function.None:
                            break;

                        case Function.NodeAdd:

                            var nodeAddStatus = NodeFunctionStatus.None;
                            Enum.TryParse(args.Message[5].ToString(), out nodeAddStatus);
                            switch (nodeAddStatus)
                            {
                            case NodeFunctionStatus.AddNodeAddingSlave:

                                nodeOperationIdCheck = args.Message[6];
                                var newNode = CreateDevice(nodeOperationIdCheck, 0x00);
                                // Extract node information frame
                                int nodeInfoLength = (int)args.Message[7];
                                // we don't need to exclude the last 2 CommandClasses
                                byte[] nodeInfo = new byte[nodeInfoLength];
                                Array.Copy(args.Message, 8, nodeInfo, 0, nodeInfoLength);
                                newNode.NodeInformationFrame = nodeInfo;

                                newNode.BasicClass    = args.Message[8];
                                newNode.GenericClass  = args.Message[9];
                                newNode.SpecificClass = args.Message[10];
                                devices.Add(newNode);

                                if (newNode.SupportCommandClass(CommandClass.Security))
                                {
                                    var nodeSecurityData = Security.GetSecurityData(newNode);
                                    nodeSecurityData.IsAddingNode = true;

                                    Security.GetScheme(newNode);
                                }
                                else
                                {
                                    NodeInformationFrameComplete(newNode);
                                }
                                break;

                            //case NodeFunctionStatus.AddNodeDone:
                            case NodeFunctionStatus.AddNodeProtocolDone:

                                if (nodeOperationIdCheck == args.Message[6])
                                {
                                    Thread.Sleep(500);
                                    GetNodeCapabilities(args.Message[6]);
                                    var addedNode = devices.Find(n => n.Id == args.Message[6]);
                                    if (addedNode != null)
                                    {
                                        ManufacturerSpecific.Get(addedNode);
                                    }
                                }
                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.NodeAdded));
                                // force refresh of nodelist sending DiscoverEnd event
                                // TODO: deprecate this and update the Web UI to refresh modules list on NodeAdded event
                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.DiscoveryEnd));
                                break;

                            case NodeFunctionStatus.AddNodeFailed:

                                Utility.DebugLog(DebugMessageType.Warning, "ADDING NODE FAILED (" + args.Message[6] + ")");
                                break;
                            }
                            break;

                        case Function.NodeRemove:

                            var nodeRemoveStatus = NodeFunctionStatus.None;
                            Enum.TryParse(args.Message[5].ToString(), out nodeRemoveStatus);
                            switch (nodeRemoveStatus)
                            {
                            case NodeFunctionStatus.RemoveNodeRemovingSlave:

                                nodeOperationIdCheck = args.Message[6];
                                break;

                            case NodeFunctionStatus.RemoveNodeDone:

                                if (nodeOperationIdCheck == args.Message[6])
                                {
                                    RemoveDevice(nodeOperationIdCheck);
                                }
                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.NodeRemoved));
                                // force refresh of nodelist sending DiscoverEnd event
                                // TODO: deprecate this and update the Web UI to refresh modules list on NodeRemoved event
                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.DiscoveryEnd));
                                break;

                            case NodeFunctionStatus.RemoveNodeFailed:

                                OnControllerEvent(new ControllerEventArgs(0x00, ControllerStatus.NodeError));
                                Utility.DebugLog(DebugMessageType.Warning, "REMOVING NODE FAILED (" + args.Message[6] + ")");
                                break;
                            }
                            break;

                        case Function.ApplicationCommandHandler:

                            var node = devices.Find(n => n.Id == args.Message[5]);
                            if (node != null)
                            {
                                try
                                {
                                    node.ApplicationCommandHandler(args.Message);
                                }
                                catch (Exception ex)
                                {
                                    Utility.DebugLog(DebugMessageType.Error, "Exception occurred in node.ApplicationCommandHandler: " + ex.Message + "\n" + ex.StackTrace);
                                }
                            }
                            else
                            {
                                Utility.DebugLog(DebugMessageType.Error, "Unknown node id " + args.Message[5]);
                            }
                            break;

                        case Function.SendData:

                            byte callbackId = args.Message[4];
                            if (callbackId == 0x01) // 0x01 is "SEND DATA OK"
                            {
                                // TODO: ... is there anything to be done here?
                            }
                            else
                            {
                                var status = CallbackStatus.Nack;
                                Enum.TryParse(args.Message[5].ToString(), out status);
                                switch (status)
                                {
                                case CallbackStatus.Ack:
                                    // Messaging complete, remove callbackid
                                    zwavePort.NodeRequestAck(callbackId);
                                    break;

                                case CallbackStatus.Nack:
                                    var pendingMessage = zwavePort.NodeRequestNack(callbackId);
                                    if (pendingMessage != null && pendingMessage.ResendCount >= ZWaveMessage.ResendMaxAttempts)
                                    {
                                        // Resend timed out
                                        OnControllerEvent(new ControllerEventArgs(pendingMessage.Node.Id, ControllerStatus.NodeError));
                                        // Check if node supports WakeUp class, and add message to wake up message queue
                                        if (pendingMessage != null)
                                        {
                                            var sleepingNode = pendingMessage.Node;
                                            if (sleepingNode != null && sleepingNode.SupportCommandClass(CommandClass.WakeUp))
                                            {
                                                WakeUp.ResendOnWakeUp(sleepingNode, pendingMessage.Message);
                                            }
                                        }
                                    }
                                    break;

                                case CallbackStatus.NeighborUpdateStarted:
                                    // Neighbour Update Options STARTED
                                    //var message = zwavePort.GetPendingMessage(commandId);
                                    // TODO: don't know what to do here...
                                    break;

                                case CallbackStatus.NeighborUpdateDone:
                                    var message = zwavePort.GetPendingMessage(callbackId);
                                    if (message != null)
                                    {
                                        RequestNeighborsUpdate(message.Node);
                                        // send ack so the message is removed from the pending message list
                                        zwavePort.NodeRequestAck(callbackId);
                                    }
                                    break;
                                }
                            }
                            break;

                        case Function.ApplicationUpdate:

                            int nifLength = (int)args.Message[6];
                            var znode     = devices.Find(n => n.Id == args.Message[5]);
                            if (znode != null)
                            {
                                // we don't need to exclude the last 2 CommandClasses
                                byte[] nodeInfo = new byte[nifLength];
                                Array.Copy(args.Message, 7, nodeInfo, 0, nifLength);
                                znode.NodeInformationFrame = nodeInfo;
                                if (znode.SupportCommandClass(CommandClass.Security))
                                {
                                    // ask the node what security command classes are supported
                                    Security.GetSupported(znode);
                                }
                                else
                                {
                                    NodeInformationFrameComplete(znode);
                                }
                            }
                            break;

                        case Function.RequestNodeNeighborsUpdateOptions:
                        case Function.RequestNodeNeighborsUpdate:

                            var neighborUpdateStatus = NeighborsUpdateStatus.None;
                            Enum.TryParse(args.Message[5].ToString(), out neighborUpdateStatus);
                            var pm = zwavePort.GetPendingMessage(args.Message[4]);
                            switch (neighborUpdateStatus)
                            {
                            case NeighborsUpdateStatus.NeighborsUpdateStared:

                                OnControllerEvent(new ControllerEventArgs(pm.Node.Id, ControllerStatus.NeighborUpdateStarted));
                                break;

                            case NeighborsUpdateStatus.NeighborsUpdateDone:

                                nodeOperationIdCheck = pm.Node.Id;
                                OnControllerEvent(new ControllerEventArgs(nodeOperationIdCheck, ControllerStatus.NeighborUpdateDone));
                                GetNeighborsRoutingInfo(pm.Node);
                                if (pm != null)
                                {
                                    zwavePort.NodeRequestAck(pm.CallbackId);
                                }
                                break;

                            case NeighborsUpdateStatus.NeighborsUpdateFailed:

                                OnControllerEvent(new ControllerEventArgs(pm.Node.Id, ControllerStatus.NeighborUpdateFailed));
                                if (pm != null)
                                {
                                    zwavePort.NodeRequestNack(pm.CallbackId);
                                }
                                break;

                            default:
                                Utility.DebugLog(DebugMessageType.Warning, "Unhandled Node Neighbor Update REQUEST " + Utility.ByteArrayToString(args.Message));
                                break;
                            }
                            break;

                        default:
                            Utility.DebugLog(DebugMessageType.Warning, "Unhandled REQUEST " + Utility.ByteArrayToString(args.Message));
                            break;
                        }

                        break;

                    case MessageType.Response:

                        switch (functionType)
                        {
                        case Function.DiscoveryNodes:
                            NodeBitMaskResponseHandler(args.Message);
                            break;

                        case Function.GetNodeProtocolInfo:
                            NodeCapabilitiesResponseHandler(args.Message);
                            break;

                        case Function.RequestNodeInfo:
                            // TODO: shall we do something here?
                            break;

                        case Function.SendData:
                            // TODO: shall we do something here?
                            break;

                        case Function.GetRoutingInfo:
                            var routingInfo = ExtractRoutingFromBitMask(args.Message);
                            if (routingInfo.Count > 0)
                            {
                                var routedNode = devices.Find(n => n.Id == nodeOperationIdCheck);
                                if (routedNode != null)
                                {
                                    //
                                    routedNode.RaiseUpdateParameterEvent(new ZWaveEvent(routedNode, EventParameter.RoutingInfo, String.Join(" ", routingInfo), 0));
                                }
                            }
                            else
                            {
                                Utility.DebugLog(DebugMessageType.Warning, "No routing nodes reported.");
                            }
                            break;

                        default:
                            Utility.DebugLog(DebugMessageType.Warning, "Unhandled RESPONSE " + Utility.ByteArrayToString(args.Message));
                            break;
                        }

                        break;

                    default:
                        Utility.DebugLog(DebugMessageType.Warning, "Unhandled MESSAGE TYPE " + Utility.ByteArrayToString(args.Message));
                        break;
                    }

                    break;
                }
            }
            catch (Exception ex)
            {
                Utility.DebugLog(DebugMessageType.Error, "Exception occurred :" + ex.Message + "\n" + ex.StackTrace);
            }
        }