Beispiel #1
0
 /// <summary>
 /// Sends an INSTEON command to the device.
 /// </summary>
 /// <remarks>
 /// This is a non-blocking method that sends an INSTEON message to the target device and returns immediately (as long as another command is not already pending for the device).
 /// Only one command can be pending to an INSTEON device at a time. This method will block if a second command is sent while a first command is still pending.
 /// The <see cref="DeviceStatusChanged">DeviceStatusChanged</see> event will be invoked if the command is successful.
 /// The <see cref="DeviceCommandTimeout">DeviceCommandTimeout</see> event will be invoked if the device does not respond within the expected timeout period.
 /// </remarks>
 /// <param name="command">Specifies the INSTEON device command to be invoked.</param>
 /// <param name="value">A parameter value required by some commands.</param>
 internal void Command(InsteonDirectCommands command, byte value)
 {
     if (!TryCommand(command, value))
     {
         throw new IOException($"Failed to send command '{command}' for device '{Address}'");
     }
 }
 /// <summary>
 /// Sends an INSTEON command to the device.
 /// </summary>
 /// <remarks>
 /// This is a non-blocking method that sends an INSTEON message to the target device and returns immediately (as long as another command is not already pending for the device). 
 /// Only one command can be pending to an INSTEON device at a time. This method will block if a second command is sent while a first command is still pending.
 /// The <see cref="DeviceStatusChanged">DeviceStatusChanged</see> event will be invoked if the command is successful.
 /// The <see cref="DeviceCommandTimeout">DeviceCommandTimeout</see> event will be invoked if the device does not respond within the expected timeout period.
 /// </remarks>
 /// <param name="command">Specifies the INSTEON device command to be invoked.</param>
 /// <param name="value">A parameter value required by some commands.</param>
 internal void Command(InsteonDirectCommands command, byte value)
 {
     if (!TryCommand(command, value))
     {
         throw new IOException($"Failed to send command '{command}' for device '{Address}'");
     }
 }
Beispiel #3
0
        // blocks the current thread if a command is pending, then sets the current command as the pending command (note does not apply to all commands)
        private void WaitAndSetPendingCommand(InsteonDirectCommands command, byte value)
        {
            InsteonDirectCommands latchedPendingCommand;

            lock (pendingEvent)
            {
                if (pendingCommand == null)
                {
                    pendingCommand = command;
                    pendingValue   = value;
                    pendingRetry   = 0;
                    return;
                }
                latchedPendingCommand = pendingCommand.Value;
            }

            // block current thread if a command is pending
            logger.DebugFormat("Device {0} blocking command {1} for pending command {2}", Address.ToString(), command.ToString(), latchedPendingCommand.ToString());
            pendingEvent.Reset();
            if (!pendingEvent.WaitOne(Constants.deviceAckTimeout)) // wait at most deviceAckTimeout seconds
            {
                ClearPendingCommand();                             // break deadlock and warn
                logger.WarnFormat("Device {0} unblocking command {1} for pending command {2}", Address.ToString(), command.ToString(), latchedPendingCommand.ToString());
            }

            WaitAndSetPendingCommand(command, value); // try again
        }
Beispiel #4
0
        private bool TryCommandInternal(InsteonDirectCommands command, byte value)
        {
            var message = GetStandardMessage(Address, (byte)command, value);

            logger.DebugFormat("Device {0} Command(command:{1}, value:{2:X2})", Address.ToString(), command.ToString(), value);

            var status = network.Messenger.TrySend(message);

            if (status == EchoStatus.ACK)
            {
                ackTimer.Change(Constants.deviceAckTimeout, Timeout.Infinite); // start ACK timeout timer
                ClearPendingCommand();
                return(true);
            }
            ClearPendingCommand();
            return(false);
        }
Beispiel #5
0
        /// <summary>
        /// Gets a value that indicates the on-level of the device. (Status)
        /// </summary>
        /// <returns>
        /// A value indicating the on-level of the device. For a dimmer a value between 0 and 255 will be returned. For a non-dimmer a value 0 or 255 will be returned.
        /// </returns>
        /// <remarks>
        /// This is a blocking method that sends an INSTEON message to the target device and waits for a reply, or until the device command times out.
        /// </remarks>
        public bool TryGetStatus(out byte value, byte commandValue = 0x0)
        {
            const InsteonDirectCommands command = InsteonDirectCommands.StatusRequest;

            WaitAndSetPendingCommand(command, commandValue);
            logger.DebugFormat("Device {0} GetOnLevel", Address.ToString());
            var message = GetStandardMessage(Address, (byte)command, commandValue);
            Dictionary <PropertyKey, int> properties;
            var status = network.Messenger.TrySendReceive(message, true, (byte)InsteonModemSerialCommand.StandardMessage, null, out properties);  // on-level returned in cmd2 of ACK

            if (status == EchoStatus.ACK && properties != null)
            {
                value = (byte)properties[PropertyKey.Cmd2];
                logger.DebugFormat("Device {0} GetOnLevel returning {1:X2}", Address.ToString(), value);
                ClearPendingCommand();
                return(true);
            }
            ClearPendingCommand();
            value = 0;
            return(false);
        }
        // blocks the current thread if a command is pending, then sets the current command as the pending command (note does not apply to all commands)
        private void WaitAndSetPendingCommand(InsteonDirectCommands command, byte value)
        {
            InsteonDirectCommands latchedPendingCommand;

            lock (pendingEvent)
            {
                if (pendingCommand == null)
                {
                    pendingCommand = command;
                    pendingValue = value;
                    pendingRetry = 0;
                    return;
                }
                latchedPendingCommand = pendingCommand.Value;
            }

            // block current thread if a command is pending
            logger.DebugFormat("Device {0} blocking command {1} for pending command {2}", Address.ToString(), command.ToString(), latchedPendingCommand.ToString());
            pendingEvent.Reset();
            if (!pendingEvent.WaitOne(Constants.deviceAckTimeout)) // wait at most deviceAckTimeout seconds
            {
                ClearPendingCommand(); // break deadlock and warn
                logger.WarnFormat("Device {0} unblocking command {1} for pending command {2}", Address.ToString(), command.ToString(), latchedPendingCommand.ToString());
            }

            WaitAndSetPendingCommand(command, value); // try again
        }
        private bool TryCommandInternal(InsteonDirectCommands command, byte value)
        {
            var message = GetStandardMessage(Address, (byte)command, value);
            logger.DebugFormat("Device {0} Command(command:{1}, value:{2:X2})", Address.ToString(), command.ToString(), value);

            var status = network.Messenger.TrySend(message);
            if (status == EchoStatus.ACK)
            {
                ackTimer.Change(Constants.deviceAckTimeout, Timeout.Infinite); // start ACK timeout timer  
                ClearPendingCommand();
                return true;
            }
            ClearPendingCommand();
            return false;
        }
 /// <summary>
 /// Sends an INSTEON command to the device.
 /// </summary>
 /// <param name="command">Specifies the INSTEON device command to be invoked.</param>
 /// <param name="value">A parameter value required by some commands.</param>
 /// <remarks>
 /// This method does not throw an exception.
 /// This is a non-blocking method that sends an INSTEON message to the target device and returns immediately (as long as another command is not already pending for the device). 
 /// Only one command can be pending to an INSTEON device at a time. This method will block if a second command is sent while a first command is still pending.
 /// The <see cref="DeviceStatusChanged">DeviceStatusChanged</see> event will be invoked if the command is successful.
 /// The <see cref="DeviceCommandTimeout">DeviceCommandTimeout</see> event will be invoked if the device does not respond within the expected timeout period.
 /// </remarks>
 internal bool TryCommand(InsteonDirectCommands command, byte value)
 {
     WaitAndSetPendingCommand(command, value);
     return TryCommandInternal(command, value);
 }
Beispiel #9
0
 /// <summary>
 /// Sends an INSTEON command to the device.
 /// </summary>
 /// <param name="command">Specifies the INSTEON device command to be invoked.</param>
 /// <param name="value">A parameter value required by some commands.</param>
 /// <remarks>
 /// This method does not throw an exception.
 /// This is a non-blocking method that sends an INSTEON message to the target device and returns immediately (as long as another command is not already pending for the device).
 /// Only one command can be pending to an INSTEON device at a time. This method will block if a second command is sent while a first command is still pending.
 /// The <see cref="DeviceStatusChanged">DeviceStatusChanged</see> event will be invoked if the command is successful.
 /// The <see cref="DeviceCommandTimeout">DeviceCommandTimeout</see> event will be invoked if the device does not respond within the expected timeout period.
 /// </remarks>
 internal bool TryCommand(InsteonDirectCommands command, byte value)
 {
     WaitAndSetPendingCommand(command, value);
     return(TryCommandInternal(command, value));
 }