Пример #1
0
    def _handle_sensor_device_state_change_event(self, event):
        body = event.body
        device_name = body[Evts.SensorDeviceBodyItem.DeviceName]
        state = body[Evts.SensorDeviceBodyItem.State]

        triggered = bool(state == 1)
        state_str = "opened" if triggered else "closed"

        # If the alarm is deactived then ignore the sensor state change after
        # logging the change for reference.
        if self._current_alarm_state == self.AlarmState.Deactivated:
            log_msg = f"{device_name} was {state_str}, although alarm isn't on"
            self._logger.Log(LogType.Info, log_msg)
            return

        # If the trigger has has already been triggered then opening or closing
        # a door etc. would change the alarm state, although we should log that
        # the even occurred.
        if self._current_alarm_state == self.AlarmState.Triggered:
            log_msg = f"{device_name} was {state_str}, alarm already triggered"
            self._logger.Log(LogType.Info, log_msg)
            return

        if self._current_alarm_state == self.AlarmState.Activated:
            log_msg = f"Activity on {device_name} ({state_str}) has triggerd " +\
                "the alarm!"
            self._logger.Log(LogType.Info, log_msg)
            self._current_alarm_state = self.AlarmState.Triggered

            evt = Event(Evts.EvtType.ActivateSiren, None)
            self._event_mgr.QueueEvent(evt)
Пример #2
0
 def _generate_device_state_change_evt(self):
     evt_body = {
         Evts.SensorDeviceBodyItem.DeviceType: self.SensorName,
         Evts.SensorDeviceBodyItem.DeviceName: self._device_name,
         Evts.SensorDeviceBodyItem.State: self._is_triggered
     }
     evt = Event(Evts.EvtType.SensorDeviceStateChange, evt_body)
     self._event_mgr.QueueEvent(evt)
Пример #3
0
    def _trigger_alarm(self, no_grace_time=False):
        self._current_alarm_state = self.AlarmState.Activated

        alarm_set_evt_body = {
            'activationTimestamp': time.time(),
            'noGraceTime': no_grace_time
        }

        activate_event = Event(Evts.EvtType.AlarmActivated, alarm_set_evt_body)
        self._event_mgr.QueueEvent(activate_event)
Пример #4
0
    def _please_respond_to_keypad(self):
        # Validate the request to ensure that the auth key is firstly present,
        # then if it's valid.  None is returned if successful.
        validate_return = self._validate_auth_key()
        if validate_return is not None:
            return validate_return

        send_alive_ping_evt = Event(Evts.EvtType.KeypadApiSendAlivePing)
        self._event_mgr.QueueEvent(send_alive_ping_evt)

        return self._endpoint.response_class(response='Ok',
                                             status=HTTPStatusCode.OK,
                                             mimetype=MIMEType.Text)
Пример #5
0
    def _receive_key_code(self):

        # Check for that the message body ia of type application/json and that
        # there is one, if not report a 400 error status with a human-readable.
        body = request.get_json()
        if not body:
            err_msg = 'Missing/invalid json body'
            response = self._endpoint.response_class(
                response=err_msg,
                status=HTTPStatusCode.BadRequest,
                mimetype=MIMEType.Text)
            return response

        # Validate the request to ensure that the auth key is firstly present,
        # then if it's valid.  None is returned if successful.
        validate_return = self._validate_auth_key()
        if validate_return is not None:
            return validate_return

        # Validate that the json body conforms to the expected schema.
        # If the message isn't valid then a 400 error should be generated.
        try:
            jsonschema.validate(instance=body,
                                schema=schemas.ReceiveKeyCode.Schema)

        except jsonschema.exceptions.ValidationError:
            err_msg = 'Message body validation failed.'
            return self._endpoint.response_class(
                response=err_msg,
                status=HTTPStatusCode.BadRequest,
                mimetype='text')

        evt = Event(Evts.EvtType.KeypadKeyCodeEntered, body)
        self._event_mgr.QueueEvent(evt)

        return self._endpoint.response_class(response='Ok',
                                             status=HTTPStatusCode.OK,
                                             mimetype=MIMEType.Text)
Пример #6
0
    def _deactivate_alarm(self):
        self._current_alarm_state = self.AlarmState.Deactivated
        self._failed_entry_attempts = 0

        evt = Event(Evts.EvtType.AlarmDeactivated)
        self._event_mgr.QueueEvent(evt)
Пример #7
0
    def _handle_key_code_entered_event(self, event):
        body = event.body

        key_sequence = body[schemas.ReceiveKeyCode.BodyElement.KeySeq]

        # Read the key code detail from the database.
        details = self._database.get_keycode_details(key_sequence)

        if details is not None:
            if self._current_alarm_state == self.AlarmState.Triggered:
                self._logger.Log(LogType.Info,
                                 'A triggered alarm has been deactivated')
                self._current_alarm_state = self.AlarmState.Deactivated
                self._failed_entry_attempts = 0
                evt = Event(Evts.EvtType.DeactivateSiren, None)
                self._event_mgr.QueueEvent(evt)
                self._deactivate_alarm()

            elif self._current_alarm_state == self.AlarmState.Deactivated:
                self._logger.Log(LogType.Info, 'The alarm has been activated')
                self._current_alarm_state = self.AlarmState.Activated
                self._failed_entry_attempts = 0
                self._trigger_alarm()

            elif self._current_alarm_state == self.AlarmState.Activated:
                self._logger.Log(LogType.Info,
                                 'The alarm has been deactivated')
                self._current_alarm_state = self.AlarmState.Deactivated
                self._failed_entry_attempts = 0
                self._deactivate_alarm()

        else:
            self._logger.Log(LogType.Info,
                             'An invalid key code was entered on keypad')
            self._failed_entry_attempts += 1

            attempts = self._failed_entry_attempts

            # If the attempt failed then send the response of type
            # receiveKeyCodeResponseAction_KeycodeIncorrect along with any
            # response actions that have been defined in the configuraution
            # file.
            if attempts in self._config.failed_attempt_responses:
                responses = self._config.failed_attempt_responses[attempts]

                for response in responses:

                    if response == 'disableKeyPad':
                        lock_event_body = {
                            keypadApi.KeypadLockRequest.BodyElement.LockTime:
                            round(time.time()) +
                            int(responses[response]['lockTime'])
                        }
                        lock_event = Event(
                            Evts.EvtType.KeypadApiSendKeypadLock,
                            lock_event_body)
                        self._event_mgr.QueueEvent(lock_event)

                    elif response == 'triggerAlarm':
                        if self._current_alarm_state != self.AlarmState.Triggered:
                            self._logger.Log(LogType.Info,
                                             '|=> Alarm has been triggered!')
                            self._trigger_alarm(no_grace_time=True)

                    elif response == 'resetAttemptAccount':
                        self._failed_entry_attempts = 0
    def start_app(self):
        # pylint: disable=too-many-statements
        self._logger.WriteToConsole = True
        self._logger.ExternalLogger = self
        self._logger.Initialise()

        signal.signal(signal.SIGINT, self._signal_handler)

        self._logger.Log(LogType.Info, 'Secure Shed Central Controller V%s',
                         VERSION)
        self._logger.Log(LogType.Info,
                         'Copyright %s Secure Shed Project Dev Team',
                         COPYRIGHT)
        self._logger.Log(LogType.Info,
                         'Licensed under the Apache License, Version 2.0')

        config_manger = ConfigurationManager()

        configuration = config_manger.parse_config_file(self._config_file)
        if not configuration:
            self._logger.Log(LogType.Error, 'Parse failed, last message : %s',
                             config_manger.last_error_msg)
            sys.exit(1)

        self._logger.Log(LogType.Info, '=== Configuration Parameters ===')
        self._logger.Log(LogType.Info, 'Environment Variables:')
        self._logger.Log(LogType.Info, '|=> Configuration file       : %s',
                         self._config_file)
        self._logger.Log(LogType.Info, '|=> Database                 : %s',
                         self.__db)
        self._logger.Log(LogType.Info, '===================================')
        self._logger.Log(LogType.Info, '=== Configuration File Settings ===')
        self._logger.Log(LogType.Info, 'General Settings:')
        self._logger.Log(LogType.Info, '|=> Devices Config File      : %s',
                         configuration.general_settings.devicesConfigFile)
        self._logger.Log(LogType.Info, '|=> Device Types Config File : %s',
                         configuration.general_settings.deviceTypesConfigFile)
        self._logger.Log(LogType.Info, 'Keypad Controller Settings:')
        self._logger.Log(LogType.Info, '|=> Authentication Key       : %s',
                         configuration.keypad_controller.authKey)
        self._logger.Log(LogType.Info, '|=> Endpoint                 : %s',
                         configuration.keypad_controller.endpoint)
        self._logger.Log(LogType.Info, 'Central Controller Settings:')
        self._logger.Log(LogType.Info, '|=> Authentication Key       : %s',
                         configuration.central_controller_api.authKey)
        self._logger.Log(LogType.Info, '|=> Network Port             : %s',
                         configuration.central_controller_api.networkPort)
        self._logger.Log(LogType.Info, '================================')

        self._event_manager = EventManager()

        controller_db = ControllerDBInterface()
        if not controller_db.connect(self.__db):
            self._logger.Log(LogType.Error, "Database '%s' is missing!",
                             self.__db)
            sys.exit(1)

        # Build state manager which manages the state of the alarm itself and
        # how states are changed due to hardware device(s) being triggered.
        self._state_mgr = StateManager(controller_db, configuration,
                                       self._event_manager, self._logger)

        # Attempt to load the device types plug-ins, if a plug-in cannot be
        # found or is invalid then a warning is logged and it's not loaded.
        device_type_mgr = DeviceTypeManager(self._logger)
        device_types_cfg = device_type_mgr.read_device_types_config(
            configuration.general_settings.deviceTypesConfigFile)
        if not device_types_cfg:
            self._logger.Log(LogType.Error, device_type_mgr.last_error_msg)
            sys.exit(1)

        device_type_mgr.load_device_types()

        # Load the devices configuration file which contains the devices
        # attached to the alarm.  The devices are matched to the device types
        # loaded above.
        devices_cfg = configuration.general_settings.devicesConfigFile
        devices_cfg_loader = DevicesConfigLoader()
        self._curr_devices = devices_cfg_loader.read_devices_config_file(
            devices_cfg)
        if not self._curr_devices:
            self._logger.Log(LogType.Error, devices_cfg_loader.last_error_msg)
            sys.exit(1)

        self._device_mgr = DeviceManager(device_type_mgr, self._event_manager,
                                         self._logger)
        dev_lst = self._curr_devices[devices_cfg_loader.JsonTopElement.Devices]
        self._device_mgr.load(dev_lst)
        self._device_mgr.initialise_hardware()

        self._register_event_callbacks()

        # Create the IO processing thread which handles IO requests from
        # hardware devices.
        self._worker_thread = WorkerThread(configuration, self._device_mgr,
                                           self._event_manager,
                                           self._state_mgr, self._logger)
        self._worker_thread.start()

        # pylint: disable=unused-variable
        api_controller = ApiController(self._event_manager, controller_db,
                                       configuration, self._endpoint,
                                       self._log_store, self._logger)

        send_alive_ping_evt = Event(Evts.EvtType.KeypadApiSendAlivePing)
        self._event_manager.QueueEvent(send_alive_ping_evt)