public static CommandEventArgs BuildCommandArgs(string topic, string msg)
        {
            string[] topicArgs = topic.Split('/');
            if (topicArgs.Length < 5)
                return null;

            CommandEventArgs args = new CommandEventArgs();
            args.HouseCode = topicArgs[1];
            args.DeviceCode = topicArgs[2];
            args.LocationCode = topicArgs[3];
            args.Command = topicArgs[4];
            args.CommandValue = msg;

            return args;
        }
        void _turnOffDoorbellIndicatorTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            _turnOffDoorbellIndicatorTimer.Enabled = false;
            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<HomeSecurityHub>();
            CommandEventArgs args = new CommandEventArgs("house1", "externaldoor", "front", "doorbell", "off");
            context.Clients.All.updateCommand(args);

            args = new CommandEventArgs("house1", "externaldoor", "back", "doorbell", "off");
            context.Clients.All.updateCommand(args);

            args = new CommandEventArgs("house1", "externaldoor", "side", "doorbell", "off");
            context.Clients.All.updateCommand(args);
        }
        public bool ProcessCommand(CommandEventArgs args)
        {
            if (!(args == null ||
                string.IsNullOrEmpty(args.HouseCode) ||
                string.IsNullOrEmpty(args.DeviceCode) ||
                string.IsNullOrEmpty(args.Command) ||
                string.IsNullOrEmpty(args.CommandValue)))
            {
                IHubContext context = GlobalHost.ConnectionManager.GetHubContext<HomeSecurityHub>();

                switch (args.DeviceCode)
                {
                    case "externaldoor":
                        if (args.Command.Equals("code"))
                        {
                            context.Clients.All.updateCommand(args);

                            if (UnLockDoor(args))
                                DisarmAlarm(args);
                        }
                        if (args.Command.Equals("doorbell"))
                        {
                            _turnOffDoorbellIndicatorTimer.Enabled = true;
                            context.Clients.All.updateCommand(args);
                        }
                        if (args.Command.Equals("door"))
                        {
                            context.Clients.All.updateCommand(args);

                            ProcessSensorStateChange(args);
                        }
                        if (args.Command.Equals("window"))
                        {
                            context.Clients.All.updateCommand(args);

                            ProcessSensorStateChange(args);
                        }
                        if (args.Command.Equals("motion"))
                        {
                            context.Clients.All.updateCommand(args);

                            ProcessSensorStateChange(args);
                        }
                        if (args.Command.Equals("lock"))
                        {
                            context.Clients.All.updateCommand(args);

                            ProcessLockStateChange(args);
                        }
                        break;
                    case "alarmpanel":
                        if (args.Command.Equals("alarmstate"))
                        {
                            context.Clients.All.updateCommand(args);

                            SetAlarmState(args);
                        }
                        if (args.Command.Equals("setalarmstate"))
                        {
                            context.Clients.All.updateCommand(args);
                        }
                        if (args.Command.Equals("emergency"))
                        {
                            context.Clients.All.updateCommand(args);

                            SoundBurglarAlarm(args);
                        }
                        if (args.Command.Equals("code"))
                        {
                            context.Clients.All.updateCommand(args);

                            DisarmAlarm(args);
                        }
                        if (args.Command.Equals("door"))
                        {
                            context.Clients.All.updateCommand(args);

                            ProcessSensorStateChange(args);
                        }
                        if (args.Command.Equals("window"))
                        {
                            context.Clients.All.updateCommand(args);

                            ProcessSensorStateChange(args);
                        }
                        if (args.Command.Equals("motion"))
                        {
                            context.Clients.All.updateCommand(args);

                            ProcessSensorStateChange(args);
                        }
                        if (args.Command.Equals("burglar"))
                        {
                            context.Clients.All.updateCommand(args);
                        }
                        break;
                }
            }
            else
                return false;
            return true;
        }
        private void SoundBurglarAlarm(CommandEventArgs args)
        {
            _alarmSounding = true;
            CommandEventArgs newArgs = null;
            if (args.DeviceCode.Equals("externaldoor"))
            {
                // Map all external door breakins to the first floor alarm panel
                newArgs = new CommandEventArgs
                {
                    HouseCode = args.HouseCode,
                    DeviceCode = "alarmpanel",
                    LocationCode = "firstfloor",
                    Command = "burglar",
                    CommandValue = "on"
                };
            }
            else
            {
                newArgs = new CommandEventArgs
                {
                    HouseCode = args.HouseCode,
                    DeviceCode = args.DeviceCode,
                    LocationCode = args.LocationCode,
                    Command = args.Command,
                    CommandValue = args.CommandValue
                };
            }

            // Use the args to determine where to send the alarm burglar trigger command
            string topic = string.Format("/{0}/{1}/{2}/{3}", newArgs.HouseCode, newArgs.DeviceCode, newArgs.LocationCode, "burglar");
            _client.Publish(topic, new MqttPayload("on"), QoS.BestEfforts, false);
        }
        private bool UnLockDoor(CommandEventArgs args)
        {
            bool unlockedDoor = false;

            string topic = string.Format("/{0}/{1}/{2}/{3}", args.HouseCode, args.DeviceCode, args.LocationCode, "codevalid");
            if (args.CommandValue.Equals(_secretCode))
            {
                _client.Publish(topic, new MqttPayload("true"), QoS.BestEfforts, false);
                topic = string.Format("/{0}/{1}/{2}/{3}", args.HouseCode, args.DeviceCode, args.LocationCode, "setlock");
                _client.Publish(topic, new MqttPayload("unlock"), QoS.BestEfforts, false);
                unlockedDoor = true;
            }
            else
                _client.Publish(topic, new MqttPayload("false"), QoS.BestEfforts, false);

            return unlockedDoor;
        }
        private void SetAlarmState(CommandEventArgs args)
        {
            AlarmState newState = ParseAlarmState(args.CommandValue);
            if (newState == _currentState)
                return;

            if (_currentState == AlarmState.Off)
            {
                // You cant set the alarm if any of the windows, doors or motion detectors are currently open
                int openedSensorCount = _sensors.Where(s => s.SensorValue == "opened").Count();
                if (openedSensorCount > 0)
                {
                    _client.Publish(string.Format("/{0}/{1}/{2}/{3}", args.HouseCode, args.DeviceCode, args.LocationCode, "alarmstatevalid"), new MqttPayload("false"), QoS.BestEfforts, false);
                }
                else
                {
                    _client.Publish(string.Format("/{0}/{1}/{2}/{3}", args.HouseCode, args.DeviceCode, args.LocationCode, "alarmstatevalid"), new MqttPayload("true"), QoS.BestEfforts, false);
                    _currentState = newState;
                    SendAlarmStateChange(args.HouseCode, _currentState);
                    if (_currentState == AlarmState.Sleep)
                        LockAllDoors();
                    else if (_currentState == AlarmState.Away)
                    {
                        _giveMeTimeToExit = true;
                        _timeRemainingInSeconds = _giveMeTimeToExitInMilliseconds / 1000;
                        _giveMeTimeToExitTimer.Enabled = true;
                    }
                }
            }
        }
        private void ProcessSensorStateChange(CommandEventArgs args)
        {
            if (args == null || args.CommandValue == null || !(args.CommandValue.Equals("opened") || args.CommandValue.Equals("closed")))
                return;

            // Set the new state of the sensors
            var sensor = _sensors.Where(s => s.HouseCode == args.HouseCode
                && s.DeviceCode == args.DeviceCode
                && s.LocationCode == args.LocationCode && s.Sensor == args.Command).FirstOrDefault();
            if (sensor != null)
            {
                sensor.SensorValue = args.CommandValue;
            }

            if (args.CommandValue.Equals("opened"))
            {
                if (_currentState == AlarmState.Sleep)
                {
                    SoundBurglarAlarm(args);
                }

                if (_currentState == AlarmState.Away && _giveMeTimeToEnterTimer.Enabled == false && _giveMeTimeToExit==false)
                {
                    _alarmComandEventArgs = args;
                    // Start a timer that allows the user to get in the door and disarm the alarm before it fires
                    _timeRemainingInSeconds = _giveMeTimeToEnterInMilliseconds / 1000;
                    _giveMeTimeToEnterTimer.Interval = 1000;
                    _giveMeTimeToEnterTimer.Enabled = true;
                }
            }
        }
        private void ProcessLockStateChange(CommandEventArgs args)
        {
            if (args == null || args.CommandValue == null || !(args.CommandValue.Equals("locked") || args.CommandValue.Equals("unlocked")))
                return;

            // Set the new state of the sensors
            var doorLock = _lockState.Where(s => s.HouseCode == args.HouseCode
                && s.DeviceCode == args.DeviceCode
                && s.LocationCode == args.LocationCode && s.Actuator == args.Command).FirstOrDefault();
            if (doorLock != null)
            {
                doorLock.ActuatorValue = args.CommandValue;
            }
        }
        private bool DisarmAlarm(CommandEventArgs args)
        {
            bool disarmed=false;

            if (args.CommandValue.Equals(_secretCode))
            {
                _giveMeTimeToEnterTimer.Enabled = false;
                _currentState = AlarmState.Off;
                SendAlarmStateChange(args.HouseCode, _currentState);
                SilenceBurglarAlarm();
                _giveMeTimeToExitTimer.Enabled = false;
                _giveMeTimeToExit = false;
                disarmed = true;

                _client.Publish(string.Format("/{0}/{1}/{2}/{3}", args.HouseCode, args.DeviceCode, args.LocationCode, "codevalid"), new MqttPayload("true"), QoS.BestEfforts, false);
            }
            else
            {
                _client.Publish(string.Format("/{0}/{1}/{2}/{3}", args.HouseCode, args.DeviceCode, args.LocationCode, "codevalid"), new MqttPayload("false"), QoS.BestEfforts, false);
            }
            return disarmed;
        }
        public void PublishState()
        {
            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<HomeSecurityHub>();

            CommandEventArgs args = null;

            // Send the current Sensor state
            foreach (SecuritySensor sensor in _sensors)
            {
                args = new CommandEventArgs
                {
                    HouseCode = sensor.HouseCode,
                    DeviceCode = sensor.DeviceCode,
                    LocationCode = sensor.LocationCode,
                    Command = sensor.Sensor,
                    CommandValue = sensor.SensorValue,
                };

                context.Clients.All.updateCommand(args);
            }

            // Send the current state of the alarm
            args = new CommandEventArgs
            {
                HouseCode = "house1",
                DeviceCode = "alarmpanel",
                LocationCode = "masterbedroom",
                Command = "setalarmstate",
                CommandValue = GetAlarmState(_currentState) };
            context.Clients.All.updateCommand(args);

            // Send the door lock state
            foreach (SecurityActuator actuator in _lockState)
            {
                args = new CommandEventArgs
                {
                    HouseCode = actuator.HouseCode,
                    DeviceCode = actuator.DeviceCode,
                    LocationCode = actuator.LocationCode,
                    Command = actuator.Actuator,
                    CommandValue = actuator.ActuatorValue,
                };

                context.Clients.All.updateCommand(args);

            }

            // TODO send the state of the Alarm Horns
        }