示例#1
0
 private UdpClient GetConnectedClient(LifxCommand command, IPEndPoint endPoint)
 {
     if (mSendCommandClient == null)
     {
         return(CreateClient(command, endPoint));
     }
     else
     {
         if (command.IsBroadcastCommand)
         {
             if (mSendCommandClient.Client.EnableBroadcast)
             {
                 return(mSendCommandClient);
             }
             else
             {
                 mSendCommandClient.Close();
                 return(CreateClient(command, endPoint));
             }
         }
         else
         {
             if (mSendCommandClient.Client.EnableBroadcast)
             {
                 mSendCommandClient.Close();
                 return(CreateClient(command, endPoint));
             }
             else
             {
                 return(mSendCommandClient);
             }
         }
     }
 }
示例#2
0
        public LifxDataPacket(LifxCommand messageToPackage)
        {
            mPacketData = new byte[messageToPackage.GetRawMessage().Length + 36];
            Size        = (ushort)(messageToPackage.GetRawMessage().Length + 36);
            Protocol    = STANDARD_PROTOCOL;

            PacketType = messageToPackage.PacketType;
            Payload    = messageToPackage.GetRawMessage();
        }
        public LifxDataPacket(LifxCommand messageToPackage)
        {
            mPacketData = new byte[messageToPackage.GetRawMessage().Length + 36];
            Size        = (ushort)(messageToPackage.GetRawMessage().Length + 36);
            Protocol    = STANDARD_PROTOCOL;

            PacketType = (ushort)messageToPackage.CommandPacketType;
            //PacketTimestamp = messageToPackage.TimeStamp; // breaks everything... maybe a fix in the firmware update?
            Payload = messageToPackage.GetRawMessage();
        }
示例#4
0
        /// <summary>
        /// Sends the command to the device specified
        /// </summary>
        /// <param name="command">The command to send</param>
        /// <param name="bulbMacAddress">The MAC address of the bulb that will receive the command (used for mesh networking)</param>
        /// <param name="panControllerMacAddress">The pan controller MAC address that will receive the command (used for mesh networking)</param>
        /// <param name="remoteIPAddress">The IP address that will physically receive the command first</param>
        /// <returns>Returns false if the command couldn't be sent for whatever reason</returns>
        private async Task <bool> SendCommandRaw(LifxCommand command, string bulbMacAddress, string panControllerMacAddress, string remoteIPAddress)
        {
            try
            {
                LifxDataPacket packet = new LifxDataPacket(command);
                packet.TargetMac        = LifxHelper.StringToByteArray(bulbMacAddress);
                packet.PanControllerMac = LifxHelper.StringToByteArray(panControllerMacAddress);

                using (var stream = await new DatagramSocket().GetOutputStreamAsync(new HostName(remoteIPAddress), LifxHelper.LIFX_PORT.ToString()))
                {
                    using (var writer = new DataWriter(stream))
                    {
                        writer.WriteBytes(packet.PacketData);
                        await writer.StoreAsync();
                    }
                }

                return(true);
            }
            catch (Exception)
            {
                return(false);
            }
        }
示例#5
0
        private UdpClient CreateClient(LifxCommand command, IPEndPoint endPoint)
        {
            if (command.IsBroadcastCommand)
            {
                mSendCommandClient = new UdpClient();

                mSendCommandClient.EnableBroadcast = true;
                mSendCommandClient.Client.SetSocketOption(
                    SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

                mSendCommandClient.Connect(new IPEndPoint(IPAddress.Broadcast, LIFX_PORT));
                return(mSendCommandClient);
            }
            else
            {
                mSendCommandClient = new UdpClient();

                mSendCommandClient.Client.SetSocketOption(
                    SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

                mSendCommandClient.Connect(endPoint);
                return(mSendCommandClient);
            }
        }
示例#6
0
        /// <summary>
        /// Sends a command to the specified IP address
        /// </summary>
        /// <param name="command">The command to send</param>
        /// <param name="bulbMacAddress">The MAC address of the bulb that will receive the command (used for mesh networking)</param>
        /// <param name="panControllerMacAddress">The pan controller MAC address that will receive the command (used for mesh networking)</param>
        /// <param name="remoteIPAddress">The IP address that will physically receive the command first</param>
        /// <returns>Returns a message if the command is expecting one, otherwise will return null <see cref="LifxCommand.ExpectedReturnMessagePacketType"/></returns>
        private async Task <LifxMessage> SendCommand(LifxCommand command, string bulbMacAddress, string panControllerMacAddress, string remoteIPAddress)
        {
            if (!IsInitialized)
            {
                throw new InvalidOperationException("The communicator needs to be initialized before sending a command.");
            }

            // If the command requires a reply message handle it accordingly (TCP over UDP essentially) otherwise just send the command
            if (command.ExpectedReturnMessagePacketType != MessagePacketType.Unknown)
            {
                // This locks and sets up the variable
                lock (commandsAwaitingResponse)
                {
                    // If it contains a key already don't create a new one, use an old one
                    // TODO: This is to ensure for example if a user spams a GetLightState command, if we receive one LightStateMessage all the commands that are waiting will be dropped
                    // bar one, that returns the message
                    if (!commandsAwaitingResponse.ContainsKey(command.ExpectedReturnMessagePacketType))
                    {
                        commandsAwaitingResponse.Add(command.ExpectedReturnMessagePacketType, null);
                        messageResumer.Add(command.ExpectedReturnMessagePacketType, new SemaphoreSlim(0));
                    }
                }

                do
                {
                    LifxMessage   returnedMessage  = null;
                    SemaphoreSlim resumerSemaphore = null;
                    lock (commandsAwaitingResponse)
                    {
                        commandsAwaitingResponse.TryGetValue(command.ExpectedReturnMessagePacketType, out returnedMessage);
                        messageResumer.TryGetValue(command.ExpectedReturnMessagePacketType, out resumerSemaphore);
                    }

                    // Send command then wait for reply. If Semephore times out then subtract one from retry count and send again
                    // Otherwise if there is a response heard from the device remove the values from the varaibles and return the message received
                    if (returnedMessage == null)// && resumerSemaphore != null)
                    {
                        if (await SendCommandRaw(command, bulbMacAddress, panControllerMacAddress, remoteIPAddress))
                        {
                            // If a response has come in then the wait command will return true
                            if (!resumerSemaphore.Wait(command.WaitTimeBetweenRetry))
                            {
                                command.RetryCount--;
                            }
                        }

                        // If the retry count reaches 0 and the command is required to, or want a reply and none is heard from then throw an exception
                        if (command.RetryCount == 0 && command.NeedReplyMessage)
                        {
                            throw new TimeoutException("No response heard from light in required time");
                        }
                    }
                    else
                    {
                        commandsAwaitingResponse.Remove(command.ExpectedReturnMessagePacketType);
                        messageResumer.Remove(command.ExpectedReturnMessagePacketType);

                        return(returnedMessage);
                    }
                } while (command.RetryCount > 0); // Continue to loop if no response is head and the reply count is not zero yet
            }
            else
            {
                await SendCommandRaw(command, bulbMacAddress, panControllerMacAddress, remoteIPAddress);

                return(null);
            }

            return(null);
        }
示例#7
0
 /// <summary>
 /// Tells the comminucator to send a command to the pan controller specified
 /// </summary>
 /// <param name="command">The command to send to the pan controller</param>
 /// <param name="bulb">The pan controller to send the command to</param>
 /// <returns>Returns a message if the command is expecting one, otherwise will return null <see cref="LifxCommand.ExpectedReturnMessagePacketType"/></returns>
 public async Task <LifxMessage> SendCommand(LifxCommand command, LifxPanController panController)
 {
     return(await SendCommand(command, "", panController.MACAddress, panController.IPAddress));
 }
示例#8
0
 /// <summary>
 /// Tells the comminucator to send a command to the bulb specified
 /// </summary>
 /// <param name="command">The command to send to the bulb</param>
 /// <param name="bulb">The bulb to send the command to</param>
 /// <returns>Returns a message if the command is expecting one, otherwise will return null <see cref="LifxCommand.ExpectedReturnMessagePacketType"/></returns>
 public async Task <LifxMessage> SendCommand(LifxCommand command, LifxBulb bulb)
 {
     return(await SendCommand(command, bulb.MACAddress, bulb.PanController.MACAddress, bulb.IPAddress));
 }
示例#9
0
        /// <summary>
        /// Sends command to a bulb
        /// </summary>
        /// <param name="command"></param>
        /// <param name="bulb">The bulb to send the command to.</param>
        /// <returns>Returns the response message. If the command does not trigger a response it will reurn null. </returns>
        public LifxReceivedMessage SendCommand(LifxCommand command, string macAddress, string panController, IPEndPoint endPoint)
        {
            if (!IsInitialized)
            {
                throw new InvalidOperationException("The communicator needs to be initialized before sending a command.");
            }


            UdpClient client = GetConnectedClient(command, endPoint);


            LifxDataPacket packet = new LifxDataPacket(command);

            packet.TargetMac        = LifxHelper.StringToByteArray(macAddress);
            packet.PanControllerMac = LifxHelper.StringToByteArray(panController);

            client.Send(packet.PacketData, packet.PacketData.Length);

            DateTime commandSentTime = DateTime.Now;

            if (command.ReturnMessage == null)
            {
                return(null);
            }

            while ((DateTime.Now - commandSentTime).TotalMilliseconds < mTimeoutMilliseconds)
            {
                if (mIncomingQueue.Count != 0)
                {
                    IncomingMessage mess           = mIncomingQueue.Dequeue();
                    LifxDataPacket  receivedPacket = mess.Data;


                    if (receivedPacket.PacketType == LifxPANGatewayStateMessage.PACKET_TYPE)
                    {
                        //Panhandler identified
                        LifxPANGatewayStateMessage panGateway = new LifxPANGatewayStateMessage();
                        panGateway.ReceivedData = receivedPacket;

                        AddDiscoveredPanHandler(new LifxPanController(
                                                    LifxHelper.ByteArrayToString(receivedPacket.TargetMac),
                                                    mess.BulbAddress));
                    }
                    else if (receivedPacket.PacketType == LifxLightStatusMessage.PACKET_TYPE && command.IsDiscoveryCommand)
                    {
                        //Panhandler identified
                        LifxLightStatusMessage panGateway = new LifxLightStatusMessage();
                        panGateway.ReceivedData = receivedPacket;

                        AddDiscoveredBulb(
                            LifxHelper.ByteArrayToString(receivedPacket.TargetMac),
                            LifxHelper.ByteArrayToString(receivedPacket.PanControllerMac));
                    }
                    else if (receivedPacket.PacketType == command.ReturnMessage.PacketType)
                    {
                        command.ReturnMessage.ReceivedData = receivedPacket;
                        mIncomingQueue.Clear();
                        return(command.ReturnMessage);
                    }
                }
                Thread.Sleep(30);
            }

            if (command.IsDiscoveryCommand)
            {
                return(null);
            }

            if (command.RetryCount > 0)
            {
                command.RetryCount -= 1;

                //Recurssion
                return(SendCommand(command, macAddress, panController, endPoint));
            }
            else
            {
                throw new TimeoutException("Did not get a reply from bulb in a timely fashion");
            }
        }
示例#10
0
 public LifxReceivedMessage SendCommand(LifxCommand command, LifxPanController panController)
 {
     return(SendCommand(command, "", panController.MacAddress, panController.IpEndpoint));
 }
示例#11
0
 public LifxReceivedMessage SendCommand(LifxCommand command, LifxBulb bulb)
 {
     return(SendCommand(command, bulb.MacAddress, bulb.PanHandler, bulb.IpEndpoint));
 }