Exemplo n.º 1
0
    def post(self):
        '''
            month will take the form of mon/year where mon and year are intengers
        '''
        args = self.threshold_parser.parse_args()
        val = args['val']
        month = args['month']

        if month:
            month = datetime.strptime(month, "%m/%Y")
        else:
            month = datetime.datetime.now().replace(day=1, 
                                                    hour=0,
                                                    minute=0, 
                                                    second=0,
                                                    microsecond=0)
            # if its current month -> recheck usage level
            n = Alerts()
            n.alert_usage_level()

        ret = db['monthly_summary'].update_one({"month": month}, 
                                                  {
                                                      "$set": {
                                                          "limit": val
                                                      },
                                                  }, upsert=True)
        
        data = {"month": month.strftime("%m/%Y"),
                "limit": val}

        return json.dumps(data), 201
Exemplo n.º 2
0
    def post(self):
        '''
            month will take the form of mon/year where mon and year are intengers
        '''
        args = self.threshold_parser.parse_args()
        val = args['val']
        month = args['month']

        if month:
            month = datetime.strptime(month, "%m/%Y")
        else:
            month = datetime.datetime.now().replace(day=1,
                                                    hour=0,
                                                    minute=0,
                                                    second=0,
                                                    microsecond=0)
            # if its current month -> recheck usage level
            n = Alerts()
            n.alert_usage_level()

        ret = db['monthly_summary'].update_one({"month": month}, {
            "$set": {
                "limit": val
            },
        },
                                               upsert=True)

        data = {"month": month.strftime("%m/%Y"), "limit": val}

        return json.dumps(data), 201
Exemplo n.º 3
0
def main():

    config = Config(BASE_DIR + '/configuration/')
    sqlite = Sqlite(BASE_DIR + '/storage/harvester.db', config.XMLconfiguration)
    pandadb = PandaDB(BASE_DIR + '/settings.ini')
    es = Es(BASE_DIR + '/settings.ini')

    metrics = pandadb.get_db_metrics()
    dictHarvesterHosts, dictHarvesterInstnaces = es.get_last_submittedtime()
    sqlite.instances_availability(dictHarvesterInstnaces, metrics)

    instances = sqlite.get_instances()

    for instance in instances:
        for harvesterhost in instances[instance]:
            if harvesterhost != 'none':
                availability = instances[instance][harvesterhost]['availability']
                notificated = instances[instance][harvesterhost]['notificated']
                contacts = instances[instance][harvesterhost]['contacts']
                text = instances[instance][harvesterhost]['errorsdesc']
                if (availability == 0 or availability == 10) and notificated == 0:
                    email = Notifications(text=text,
                                          subject='Service issues on {0} {1}'.format(instance, harvesterhost),
                                          to=contacts)
                    email.send_notification_email()
                    sqlite.update_field('notificated', 1, instance, harvesterhost)
                    email = {}
                elif availability == 100 and notificated == 1:
                    sqlite.update_field('notificated', 0, instance, harvesterhost)
                host = harvesterhost.split('.')[0]
                doc = ServiceDocument('harv_{0}_{1}'.format(instance, host), availability=availability, contact=','.join(contacts), availabilitydesc="PandaHarvester instance:{0}".format(instance), availabilityinfo="{0}".format(text))
                XSLSPublisher.send(doc)
                doc = {}
Exemplo n.º 4
0
    def run(self):
        workdir = os.path.dirname(os.path.realpath(__file__))

        # enable logging
        logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',
                            level=logging.INFO,
                            filename=workdir + '/output.log')

        try:
            # read config file
            config = yaml.load(open(workdir + '/config.yml'))

            client = FlowClient()
            client.login(config['POLAR_USER'], config['POLAR_PASS'])

            # get last 10 activities
            activities = sorted(filter(
                lambda a: a.type == "EXERCISE" and
                (a.distance and a.distance > 0), client.activities()),
                                key=lambda a: a.timestamp)
            activities = activities[-10:]

            stlib = SportsTrackerLib()
            stlib.login(config['SPORTSTRACKER_USER'],
                        config['SPORTSTRACKER_PASS'])

            synced = []
            p = re.compile('\[polar:[0-9]+\]', re.IGNORECASE)
            for workout in stlib.get_workouts():
                if ('description' in workout):
                    result = p.findall(workout['description'])
                    if len(result) > 0:
                        synced.append(int(result[0].split(':')[1][:-1]))

            logging.debug('len(synced) = {}'.format(len(synced)))

            added = 0
            for activity in activities:
                if (activity.listItemId not in synced):
                    sport_name = activity.sport().upper()
                    sportId = activitiesMapping[
                        sport_name] if sport_name in activitiesMapping else 1
                    stlib.add_workout(
                        str(activity.listItemId) + '.gpx', activity.gpx(),
                        sportId, '[polar:{}]'.format(activity.listItemId))
                    added = added + 1

            Notifications.display(
                config['SUCCESS_TITLE'],
                config['SUCCESS_SYNCED_MSG'].format(added)
                if added > 0 else config['SUCCESS_NOT_SYNCED_MSG'])

        except Exception as e:
            logging.error("type error: " + str(e))
            logging.error(traceback.format_exc())
            Notifications.display(config['FAILURE_TITLE'],
                                  config['FAILURE_MSG'])
Exemplo n.º 5
0
 def post(self):
     tasks = PushTask.query(PushTask.pending is True).fetch()
     if tasks:
         futures = []
         Notifications.send_ios_notifications(tasks)
         Notifications.send_channel_notifications(tasks)
         for task in tasks:
             task.pending = True
         for future in futures:
             future.get_result()
Exemplo n.º 6
0
 def __init__(self, access_token=''):
     self.Account = Account(access_token=access_token)
     self.Apps = Apps(access_token=access_token)
     self.Audio = Audio(access_token=access_token)
     self.Auth = Auth(access_token=access_token)
     self.Board = Board(access_token=access_token)
     self.Database = Database(access_token=access_token)
     self.Docs = Docs(access_token=access_token)
     self.Other = Other(access_token=access_token)
     self.Fave = Fave(access_token=access_token)
     self.Friends = Friends(access_token=access_token)
     self.Gifts = Gifts(access_token=access_token)
     self.Groups = Groups(access_token=access_token)
     self.Likes = Likes(access_token=access_token)
     self.Market = Market(access_token=access_token)
     self.Messages = Messages(access_token=access_token)
     self.Newsfeed = Newsfeed(access_token=access_token)
     self.Notes = Notes(access_token=access_token)
     self.Notifications = Notifications(access_token=access_token)
     self.Pages = Pages(access_token=access_token)
     self.Photos = Photos(access_token=access_token)
     self.Places = Places(access_token=access_token)
     self.Polls = Polls(access_token=access_token)
     self.Search = Search(access_token=access_token)
     self.Stats = Stats(access_token=access_token)
     self.Status = Status(access_token=access_token)
     self.Storage = Storage(access_token=access_token)
     self.Users = Users(access_token=access_token)
     self.Utils = Utils(access_token=access_token)
     self.Video = Video(access_token=access_token)
     self.Wall = Wall(access_token=access_token)
     self.Widgets = Widgets(access_token=access_token)
Exemplo n.º 7
0
	def get(self):
		self.response.headers["Content-Type"] = "application/json"
		try:
			user_id = self.request.GET["user"]
			seen = self.request.GET["seen"]
			notifications = Notifications()
			notifications_list = notifications.get_notifications(user_id, seen)
		except Exception:
			logging.exception("Failed looking for notifications")
			out = {"success": 0}
			self.response.write(json.dumps(out))
		else:
			if seen == 1:
				logging.info("Notifications retrieved successfully")
			out = {"success": 1, "notifications": notifications_list}
			self.response.write(json.dumps(out))
Exemplo n.º 8
0
    def __init__(self, host, port, username, password, logdir, logflg):

        self.connection = pika.BlockingConnection(
            pika.ConnectionParameters(host=host, port=port, credentials=pika.PlainCredentials(username, password)))
        self.channel = self.connection.channel()
        self.channel.exchange_declare(exchange='events', type='fanout')
        self.queue_name = self.channel.queue_declare(exclusive=True).method.queue
        self.channel.queue_bind(exchange='events', queue=self.queue_name)

        self.thread = threading.Thread(target=self.run, args=())
        self.thread.daemon = True

        self.nfs = Notifications()
        self.reg = Registrations()
        self.logflg = logflg
        self.newsqn = False
        self.badhard = False

        ts = time.strftime("%d-%b-%Y-%H-%M-%S", time.gmtime(time.time()))
        lgf = "%s/cosmicpi-logs/%s.log" % (logdir, ts)
        dir = os.path.dirname(lgf)
        if not os.path.exists(dir):
            os.makedirs(dir)
        try:
            self.log = open(lgf, "w")
        except Exception as e:
            msg = "Exception: Cant open log file: %s" % (e)
            print "Fatal: %s" % msg
            sys.exit(1)
Exemplo n.º 9
0
def scrape():
    with Scraper() as scrape:
        sender = None
        rawData = scrape.fetchData(args.hour, args.minute)
        extractedData = scrape.extractData(rawData)
        if args.nosql:
            with SQL() as sql:
                sql.insertIntoSQL(extractedData)
        for deal in scrape.searchDeals(extractedData):
            logger.info("Deal found: %s", deal[1]["title"])
            if sender == None:
                sender = Notifications()
            if args.noemail:
                sender.sendEmail(deal)
            if args.nosms:
                sender.sendSMS(deal)
            if args.nofb:
                sender.sendFB(deal)
            time.sleep(1)
Exemplo n.º 10
0
def app(config, logfile):
    # Setup global variables
    global cfg, log, notify

    # Load config
    from misc.config import Config
    cfg = Config(config_path=config, logfile=logfile).cfg

    # Load logger
    from misc.log import logger
    log = logger.get_logger('traktarr')

    # Load notifications
    from notifications import Notifications
    notify = Notifications()

    # Notifications
    init_notifications()
    def __init__(self, application):
        self.qt_application = application
        #self.qt_application.aboutToQuit.connect(self.destroy)
        self._relaunch = False
        self.exiting = False
        self.exit_complete = False

        logger.info('Loading BLACS ui')
        #self.ui = BLACSWindow(self).ui
        loader = UiLoader()
        loader.registerCustomWidget(QueueTreeview)
        #loader.registerCustomPromotion('BLACS',BLACSWindow)
        self.ui = loader.load(
            os.path.join(os.path.dirname(os.path.realpath(__file__)),
                         'main.ui'), BLACSWindow())
        logger.info('BLACS ui loaded')
        self.ui.blacs = self
        self.tab_widgets = {}
        self.exp_config = exp_config  # Global variable
        self.settings_path = settings_path  # Global variable
        self.connection_table = connection_table  # Global variable
        self.connection_table_h5file = self.exp_config.get(
            'paths', 'connection_table_h5')
        self.connection_table_labscript = self.exp_config.get(
            'paths', 'connection_table_py')

        # Setup the UI
        self.ui.main_splitter.setStretchFactor(0, 0)
        self.ui.main_splitter.setStretchFactor(1, 1)

        self.tablist = {}
        self.panes = {}
        self.settings_dict = {}

        # Setup progressbar monitoring status queue
        self.ui.TimeNext_progressBar.setRange(0, 100)

        self._countdown_queue = Queue.Queue()
        Queue_Receiver = QueueToSignal(self._countdown_queue)
        Queue_Receiver.mysignal.connect(self.ui.TimeNext_progressBar.setValue)
        thread = QThread()
        Queue_Receiver.moveToThread(thread)
        thread.started.connect(Queue_Receiver.run)
        thread.start()

        # Find which devices are connected to BLACS, and what their labscript class names are:
        logger.info('finding connected devices in connection table')
        self.attached_devices = self.connection_table.get_attached_devices()

        # Store the panes in a dictionary for easy access
        self.panes[
            'tab_top_vertical_splitter'] = self.ui.tab_top_vertical_splitter
        self.panes[
            'tab_bottom_vertical_splitter'] = self.ui.tab_bottom_vertical_splitter
        self.panes['tab_horizontal_splitter'] = self.ui.tab_horizontal_splitter
        self.panes['main_splitter'] = self.ui.main_splitter

        # Get settings to restore
        logger.info('Loading front panel settings')
        self.front_panel_settings = FrontPanelSettings(self.settings_path,
                                                       self.connection_table)
        self.front_panel_settings.setup(self)
        settings, question, error, tab_data = self.front_panel_settings.restore(
        )

        # TODO: handle question/error cases

        logger.info('restoring window data')
        self.restore_window(tab_data)

        #splash.update_text('Creating the device tabs...')
        # Create the notebooks
        logger.info('Creating tab widgets')
        for i in range(4):
            self.tab_widgets[i] = DragDropTabWidget(self.tab_widget_ids)
            getattr(self.ui,
                    'tab_container_%d' % i).addWidget(self.tab_widgets[i])

        logger.info('Instantiating devices')
        for device_name, labscript_device_class_name in self.attached_devices.items(
        ):
            self.settings_dict.setdefault(device_name,
                                          {"device_name": device_name})
            # add common keys to settings:
            self.settings_dict[device_name][
                "connection_table"] = self.connection_table
            self.settings_dict[device_name]["front_panel_settings"] = settings[
                device_name] if device_name in settings else {}
            self.settings_dict[device_name]["saved_data"] = tab_data[
                device_name]['data'] if device_name in tab_data else {}
            # Instantiate the device
            logger.info('instantiating %s' % device_name)
            TabClass = labscript_devices.get_BLACS_tab(
                labscript_device_class_name)
            self.tablist[device_name] = TabClass(
                self.tab_widgets[0], self.settings_dict[device_name])

        logger.info('reordering tabs')
        self.order_tabs(tab_data)

        logger.info('starting analysis submission thread')
        # setup analysis submission
        self.analysis_submission = AnalysisSubmission(self, self.ui)
        if 'analysis_data' not in tab_data['BLACS settings']:
            tab_data['BLACS settings']['analysis_data'] = {}
        else:
            tab_data['BLACS settings']['analysis_data'] = eval(
                tab_data['BLACS settings']['analysis_data'])
        self.analysis_submission.restore_save_data(
            tab_data['BLACS settings']["analysis_data"])

        logger.info('starting queue manager thread')
        # Setup the QueueManager
        self.queue = QueueManager(self, self.ui)
        if 'queue_data' not in tab_data['BLACS settings']:
            tab_data['BLACS settings']['queue_data'] = {}
        else:
            tab_data['BLACS settings']['queue_data'] = eval(
                tab_data['BLACS settings']['queue_data'])
        self.queue.restore_save_data(tab_data['BLACS settings']['queue_data'])

        logger.info('instantiating plugins')
        # setup the plugin system
        settings_pages = []
        self.plugins = {}
        plugin_settings = eval(
            tab_data['BLACS settings']['plugin_data']
        ) if 'plugin_data' in tab_data['BLACS settings'] else {}
        for module_name, module in plugins.modules.items():
            try:
                # instantiate the plugin
                self.plugins[module_name] = module.Plugin(
                    plugin_settings[module_name] if module_name in
                    plugin_settings else {})
            except Exception:
                logger.exception(
                    'Could not instantiate plugin \'%s\'. Skipping')

        blacs_data = {
            'exp_config': self.exp_config,
            'ui': self.ui,
            'set_relaunch': self.set_relaunch,
            'plugins': self.plugins,
            'connection_table_h5file': self.connection_table_h5file,
            'connection_table_labscript': self.connection_table_labscript,
            'experiment_queue': self.queue
        }

        def create_menu(parent, menu_parameters):
            if 'name' in menu_parameters:
                if 'menu_items' in menu_parameters:
                    child = parent.addMenu(menu_parameters['name'])
                    for child_menu_params in menu_parameters['menu_items']:
                        create_menu(child, child_menu_params)
                else:
                    child = parent.addAction(menu_parameters['name'])

                if 'action' in menu_parameters:
                    child.triggered.connect(menu_parameters['action'])

            elif 'separator' in menu_parameters:
                parent.addSeparator()

        # setup the Notification system
        logger.info('setting up notification system')
        self.notifications = Notifications(blacs_data)

        settings_callbacks = []
        for module_name, plugin in self.plugins.items():
            try:
                # Setup settings page
                settings_pages.extend(plugin.get_setting_classes())
                # Setup menu
                if plugin.get_menu_class():
                    # must store a reference or else the methods called when the menu actions are triggered
                    # (contained in this object) will be garbaged collected
                    menu = plugin.get_menu_class()(blacs_data)
                    create_menu(self.ui.menubar, menu.get_menu_items())
                    plugin.set_menu_instance(menu)

                # Setup notifications
                plugin_notifications = {}
                for notification_class in plugin.get_notification_classes():
                    self.notifications.add_notification(notification_class)
                    plugin_notifications[
                        notification_class] = self.notifications.get_instance(
                            notification_class)
                plugin.set_notification_instances(plugin_notifications)

                # Register callbacks
                callbacks = plugin.get_callbacks()
                # save the settings_changed callback in a separate list for setting up later
                if isinstance(callbacks,
                              dict) and 'settings_changed' in callbacks:
                    settings_callbacks.append(callbacks['settings_changed'])

            except Exception:
                logger.exception(
                    'Plugin \'%s\' error. Plugin may not be functional.' %
                    module_name)

        # setup the BLACS preferences system
        logger.info('setting up preferences system')
        self.settings = Settings(file=self.settings_path,
                                 parent=self.ui,
                                 page_classes=settings_pages)
        for callback in settings_callbacks:
            self.settings.register_callback(callback)

        # update the blacs_data dictionary with the settings system
        blacs_data['settings'] = self.settings

        for module_name, plugin in self.plugins.items():
            try:
                plugin.plugin_setup_complete(blacs_data)
            except Exception:
                # backwards compatibility for old plugins
                try:
                    plugin.plugin_setup_complete()
                    logger.warning(
                        'Plugin \'%s\' using old API. Please update Plugin.plugin_setup_complete method to accept a dictionary of blacs_data as the only argument.'
                        % module_name)
                except Exception:
                    logger.exception(
                        'Plugin \'%s\' error. Plugin may not be functional.' %
                        module_name)

        # Connect menu actions
        self.ui.actionOpenPreferences.triggered.connect(
            self.on_open_preferences)
        self.ui.actionSave.triggered.connect(self.on_save_front_panel)
        self.ui.actionOpen.triggered.connect(self.on_load_front_panel)

        # Connect the windows AppId stuff:
        if os.name == 'nt':
            self.ui.newWindow.connect(set_win_appusermodel)

        logger.info('showing UI')
        self.ui.show()
class BLACS(object):

    tab_widget_ids = 7

    def __init__(self, application):
        self.qt_application = application
        #self.qt_application.aboutToQuit.connect(self.destroy)
        self._relaunch = False
        self.exiting = False
        self.exit_complete = False

        logger.info('Loading BLACS ui')
        #self.ui = BLACSWindow(self).ui
        loader = UiLoader()
        loader.registerCustomWidget(QueueTreeview)
        #loader.registerCustomPromotion('BLACS',BLACSWindow)
        self.ui = loader.load(
            os.path.join(os.path.dirname(os.path.realpath(__file__)),
                         'main.ui'), BLACSWindow())
        logger.info('BLACS ui loaded')
        self.ui.blacs = self
        self.tab_widgets = {}
        self.exp_config = exp_config  # Global variable
        self.settings_path = settings_path  # Global variable
        self.connection_table = connection_table  # Global variable
        self.connection_table_h5file = self.exp_config.get(
            'paths', 'connection_table_h5')
        self.connection_table_labscript = self.exp_config.get(
            'paths', 'connection_table_py')

        # Setup the UI
        self.ui.main_splitter.setStretchFactor(0, 0)
        self.ui.main_splitter.setStretchFactor(1, 1)

        self.tablist = {}
        self.panes = {}
        self.settings_dict = {}

        # Setup progressbar monitoring status queue
        self.ui.TimeNext_progressBar.setRange(0, 100)

        self._countdown_queue = Queue.Queue()
        Queue_Receiver = QueueToSignal(self._countdown_queue)
        Queue_Receiver.mysignal.connect(self.ui.TimeNext_progressBar.setValue)
        thread = QThread()
        Queue_Receiver.moveToThread(thread)
        thread.started.connect(Queue_Receiver.run)
        thread.start()

        # Find which devices are connected to BLACS, and what their labscript class names are:
        logger.info('finding connected devices in connection table')
        self.attached_devices = self.connection_table.get_attached_devices()

        # Store the panes in a dictionary for easy access
        self.panes[
            'tab_top_vertical_splitter'] = self.ui.tab_top_vertical_splitter
        self.panes[
            'tab_bottom_vertical_splitter'] = self.ui.tab_bottom_vertical_splitter
        self.panes['tab_horizontal_splitter'] = self.ui.tab_horizontal_splitter
        self.panes['main_splitter'] = self.ui.main_splitter

        # Get settings to restore
        logger.info('Loading front panel settings')
        self.front_panel_settings = FrontPanelSettings(self.settings_path,
                                                       self.connection_table)
        self.front_panel_settings.setup(self)
        settings, question, error, tab_data = self.front_panel_settings.restore(
        )

        # TODO: handle question/error cases

        logger.info('restoring window data')
        self.restore_window(tab_data)

        #splash.update_text('Creating the device tabs...')
        # Create the notebooks
        logger.info('Creating tab widgets')
        for i in range(4):
            self.tab_widgets[i] = DragDropTabWidget(self.tab_widget_ids)
            getattr(self.ui,
                    'tab_container_%d' % i).addWidget(self.tab_widgets[i])

        logger.info('Instantiating devices')
        for device_name, labscript_device_class_name in self.attached_devices.items(
        ):
            self.settings_dict.setdefault(device_name,
                                          {"device_name": device_name})
            # add common keys to settings:
            self.settings_dict[device_name][
                "connection_table"] = self.connection_table
            self.settings_dict[device_name]["front_panel_settings"] = settings[
                device_name] if device_name in settings else {}
            self.settings_dict[device_name]["saved_data"] = tab_data[
                device_name]['data'] if device_name in tab_data else {}
            # Instantiate the device
            logger.info('instantiating %s' % device_name)
            TabClass = labscript_devices.get_BLACS_tab(
                labscript_device_class_name)
            self.tablist[device_name] = TabClass(
                self.tab_widgets[0], self.settings_dict[device_name])

        logger.info('reordering tabs')
        self.order_tabs(tab_data)

        logger.info('starting analysis submission thread')
        # setup analysis submission
        self.analysis_submission = AnalysisSubmission(self, self.ui)
        if 'analysis_data' not in tab_data['BLACS settings']:
            tab_data['BLACS settings']['analysis_data'] = {}
        else:
            tab_data['BLACS settings']['analysis_data'] = eval(
                tab_data['BLACS settings']['analysis_data'])
        self.analysis_submission.restore_save_data(
            tab_data['BLACS settings']["analysis_data"])

        logger.info('starting queue manager thread')
        # Setup the QueueManager
        self.queue = QueueManager(self, self.ui)
        if 'queue_data' not in tab_data['BLACS settings']:
            tab_data['BLACS settings']['queue_data'] = {}
        else:
            tab_data['BLACS settings']['queue_data'] = eval(
                tab_data['BLACS settings']['queue_data'])
        self.queue.restore_save_data(tab_data['BLACS settings']['queue_data'])

        logger.info('instantiating plugins')
        # setup the plugin system
        settings_pages = []
        self.plugins = {}
        plugin_settings = eval(
            tab_data['BLACS settings']['plugin_data']
        ) if 'plugin_data' in tab_data['BLACS settings'] else {}
        for module_name, module in plugins.modules.items():
            try:
                # instantiate the plugin
                self.plugins[module_name] = module.Plugin(
                    plugin_settings[module_name] if module_name in
                    plugin_settings else {})
            except Exception:
                logger.exception(
                    'Could not instantiate plugin \'%s\'. Skipping')

        blacs_data = {
            'exp_config': self.exp_config,
            'ui': self.ui,
            'set_relaunch': self.set_relaunch,
            'plugins': self.plugins,
            'connection_table_h5file': self.connection_table_h5file,
            'connection_table_labscript': self.connection_table_labscript,
            'experiment_queue': self.queue
        }

        def create_menu(parent, menu_parameters):
            if 'name' in menu_parameters:
                if 'menu_items' in menu_parameters:
                    child = parent.addMenu(menu_parameters['name'])
                    for child_menu_params in menu_parameters['menu_items']:
                        create_menu(child, child_menu_params)
                else:
                    child = parent.addAction(menu_parameters['name'])

                if 'action' in menu_parameters:
                    child.triggered.connect(menu_parameters['action'])

            elif 'separator' in menu_parameters:
                parent.addSeparator()

        # setup the Notification system
        logger.info('setting up notification system')
        self.notifications = Notifications(blacs_data)

        settings_callbacks = []
        for module_name, plugin in self.plugins.items():
            try:
                # Setup settings page
                settings_pages.extend(plugin.get_setting_classes())
                # Setup menu
                if plugin.get_menu_class():
                    # must store a reference or else the methods called when the menu actions are triggered
                    # (contained in this object) will be garbaged collected
                    menu = plugin.get_menu_class()(blacs_data)
                    create_menu(self.ui.menubar, menu.get_menu_items())
                    plugin.set_menu_instance(menu)

                # Setup notifications
                plugin_notifications = {}
                for notification_class in plugin.get_notification_classes():
                    self.notifications.add_notification(notification_class)
                    plugin_notifications[
                        notification_class] = self.notifications.get_instance(
                            notification_class)
                plugin.set_notification_instances(plugin_notifications)

                # Register callbacks
                callbacks = plugin.get_callbacks()
                # save the settings_changed callback in a separate list for setting up later
                if isinstance(callbacks,
                              dict) and 'settings_changed' in callbacks:
                    settings_callbacks.append(callbacks['settings_changed'])

            except Exception:
                logger.exception(
                    'Plugin \'%s\' error. Plugin may not be functional.' %
                    module_name)

        # setup the BLACS preferences system
        logger.info('setting up preferences system')
        self.settings = Settings(file=self.settings_path,
                                 parent=self.ui,
                                 page_classes=settings_pages)
        for callback in settings_callbacks:
            self.settings.register_callback(callback)

        # update the blacs_data dictionary with the settings system
        blacs_data['settings'] = self.settings

        for module_name, plugin in self.plugins.items():
            try:
                plugin.plugin_setup_complete(blacs_data)
            except Exception:
                # backwards compatibility for old plugins
                try:
                    plugin.plugin_setup_complete()
                    logger.warning(
                        'Plugin \'%s\' using old API. Please update Plugin.plugin_setup_complete method to accept a dictionary of blacs_data as the only argument.'
                        % module_name)
                except Exception:
                    logger.exception(
                        'Plugin \'%s\' error. Plugin may not be functional.' %
                        module_name)

        # Connect menu actions
        self.ui.actionOpenPreferences.triggered.connect(
            self.on_open_preferences)
        self.ui.actionSave.triggered.connect(self.on_save_front_panel)
        self.ui.actionOpen.triggered.connect(self.on_load_front_panel)

        # Connect the windows AppId stuff:
        if os.name == 'nt':
            self.ui.newWindow.connect(set_win_appusermodel)

        logger.info('showing UI')
        self.ui.show()

    def set_relaunch(self, value):
        self._relaunch = bool(value)

    def restore_window(self, tab_data):
        # read out position settings:
        try:
            # There are some dodgy hacks going on here to try and restore the window position correctly
            # Unfortunately Qt has two ways of measuring teh window position, one with the frame/titlebar
            # and one without. If you use the one that measures including the titlebar, you don't
            # know what the window size was when the window was UNmaximized.
            #
            # Anyway, no idea if this works cross platform (tested on windows 8)
            # Feel free to rewrite this, along with the code in front_panel_settings.py
            # which stores the values
            #
            # Actually this is a waste of time because if you close when maximized, reoopen and then
            # de-maximize, the window moves to a random position (not the position it was at before maximizing)
            # so bleh!
            self.ui.move(
                tab_data['BLACS settings']["window_xpos"] -
                tab_data['BLACS settings']['window_frame_width'] / 2,
                tab_data['BLACS settings']["window_ypos"] -
                tab_data['BLACS settings']['window_frame_height'] +
                tab_data['BLACS settings']['window_frame_width'] / 2)
            self.ui.resize(tab_data['BLACS settings']["window_width"],
                           tab_data['BLACS settings']["window_height"])

            if 'window_maximized' in tab_data['BLACS settings'] and tab_data[
                    'BLACS settings']['window_maximized']:
                self.ui.showMaximized()

            for pane_name, pane in self.panes.items():
                pane.setSizes(tab_data['BLACS settings'][pane_name])

        except Exception as e:
            logger.warning(
                "Unable to load window and notebook defaults. Exception:" +
                str(e))

    def order_tabs(self, tab_data):
        # Move the tabs to the correct notebook
        for device_name in self.attached_devices:
            notebook_num = 0
            if device_name in tab_data:
                notebook_num = int(tab_data[device_name]["notebook"])
                if notebook_num not in self.tab_widgets:
                    notebook_num = 0

            #Find the notebook the tab is in, and remove it:
            for notebook in self.tab_widgets.values():
                tab_index = notebook.indexOf(self.tablist[device_name]._ui)
                if tab_index != -1:
                    notebook.removeTab(tab_index)
                    self.tab_widgets[notebook_num].addTab(
                        self.tablist[device_name]._ui, device_name)
                    break

        # splash.update_text('restoring tab positions...')
        # # Now that all the pages are created, reorder them!
        for device_name in self.attached_devices:
            if device_name in tab_data:
                notebook_num = int(tab_data[device_name]["notebook"])
                if notebook_num in self.tab_widgets:
                    self.tab_widgets[notebook_num].tab_bar.moveTab(
                        self.tab_widgets[notebook_num].indexOf(
                            self.tablist[device_name]._ui),
                        int(tab_data[device_name]["page"]))

        # # Now that they are in the correct order, set the correct one visible
        for device_name, device_data in tab_data.items():
            if device_name == 'BLACS settings':
                continue
            # if the notebook still exists and we are on the entry that is visible
            if bool(device_data["visible"]) and int(
                    device_data["notebook"]) in self.tab_widgets:
                self.tab_widgets[int(
                    device_data["notebook"])].tab_bar.setCurrentIndex(
                        int(device_data["page"]))

    def update_all_tab_settings(self, settings, tab_data):
        for device_name, tab in self.tablist.items():
            self.settings_dict[device_name]["front_panel_settings"] = settings[
                device_name] if device_name in settings else {}
            self.settings_dict[device_name]["saved_data"] = tab_data[
                device_name]['data'] if device_name in tab_data else {}
            tab.update_from_settings(self.settings_dict[device_name])

    def on_load_front_panel(self, *args, **kwargs):
        # get the file:
        # create file chooser dialog
        dialog = QFileDialog(
            None, "Select file to load",
            self.exp_config.get('paths', 'experiment_shot_storage'),
            "HDF5 files (*.h5 *.hdf5)")
        dialog.setViewMode(QFileDialog.Detail)
        dialog.setFileMode(QFileDialog.ExistingFile)
        if dialog.exec_():
            selected_files = dialog.selectedFiles()
            filepath = str(selected_files[0])
            # Qt has this weird behaviour where if you type in the name of a file that exists
            # but does not have the extension you have limited the dialog to, the OK button is greyed out
            # but you can hit enter and the file will be selected.
            # So we must check the extension of each file here!
            if filepath.endswith('.h5') or filepath.endswith('.hdf5'):
                try:
                    # TODO: Warn that this will restore values, but not channels that are locked
                    message = QMessageBox()
                    message.setText(
                        """Warning: This will modify front panel values and cause device output values to update.
                    \nThe queue and files waiting to be sent for analysis will be cleared.
                    \n
                    \nNote: Channels that are locked will not be updated.\n\nDo you wish to continue?"""
                    )
                    message.setIcon(QMessageBox.Warning)
                    message.setWindowTitle("BLACS")
                    message.setStandardButtons(QMessageBox.Yes
                                               | QMessageBox.No)

                    if message.exec_() == QMessageBox.Yes:
                        front_panel_settings = FrontPanelSettings(
                            filepath, self.connection_table)
                        settings, question, error, tab_data = front_panel_settings.restore(
                        )
                        #TODO: handle question/error

                        # Restore window data
                        self.restore_window(tab_data)
                        self.order_tabs(tab_data)
                        self.update_all_tab_settings(settings, tab_data)

                        # restore queue data
                        if 'queue_data' not in tab_data['BLACS settings']:
                            tab_data['BLACS settings']['queue_data'] = {}
                        else:
                            tab_data['BLACS settings']['queue_data'] = eval(
                                tab_data['BLACS settings']['queue_data'])
                        self.queue.restore_save_data(
                            tab_data['BLACS settings']['queue_data'])
                        # restore analysis data
                        if 'analysis_data' not in tab_data['BLACS settings']:
                            tab_data['BLACS settings']['analysis_data'] = {}
                        else:
                            tab_data['BLACS settings']['analysis_data'] = eval(
                                tab_data['BLACS settings']['analysis_data'])
                        self.analysis_submission.restore_save_data(
                            tab_data['BLACS settings']["analysis_data"])
                except Exception as e:
                    logger.exception("Unable to load the front panel in %s." %
                                     (filepath))
                    message = QMessageBox()
                    message.setText(
                        "Unable to load the front panel. The error encountered is printed below.\n\n%s"
                        % str(e))
                    message.setIcon(QMessageBox.Information)
                    message.setWindowTitle("BLACS")
                    message.exec_()
                finally:
                    dialog.deleteLater()
            else:
                dialog.deleteLater()
                message = QMessageBox()
                message.setText(
                    "You did not select a file ending with .h5 or .hdf5. Please try again"
                )
                message.setIcon(QMessageBox.Information)
                message.setWindowTitle("BLACS")
                message.exec_()
                QTimer.singleShot(10, self.on_load_front_panel)

    def on_save_exit(self):
        # Save front panel
        data = self.front_panel_settings.get_save_data()

        # with h5py.File(self.settings_path,'r+') as h5file:
        # if 'connection table' in h5file:
        # del h5file['connection table']

        self.front_panel_settings.save_front_panel_to_h5(
            self.settings_path,
            data[0],
            data[1],
            data[2],
            data[3], {"overwrite": True},
            force_new_conn_table=True)
        logger.info('Destroying tabs')
        for tab in self.tablist.values():
            tab.destroy()

        #gobject.timeout_add(100,self.finalise_quit,time.time())
        QTimer.singleShot(100, lambda: self.finalise_quit(time.time()))

    def finalise_quit(self, initial_time):
        logger.info('finalise_quit called')
        tab_close_timeout = 2
        # Kill any tabs which didn't close themselves:
        for name, tab in self.tablist.items():
            if tab.destroy_complete:
                del self.tablist[name]
        if self.tablist:
            for name, tab in self.tablist.items():
                # If a tab has a fatal error or is taking too long to close, force close it:
                if (time.time() - initial_time >
                        tab_close_timeout) or tab.state == 'fatal error':
                    try:
                        tab.close_tab()
                    except Exception as e:
                        logger.error('Couldn\'t close tab:\n%s' % str(e))
                    del self.tablist[name]
        if self.tablist:
            QTimer.singleShot(100, lambda: self.finalise_quit(initial_time))
        else:
            self.exit_complete = True
            logger.info('quitting')

    def on_save_front_panel(self, *args, **kwargs):
        data = self.front_panel_settings.get_save_data()

        # Open save As dialog
        dialog = QFileDialog(
            None, "Save BLACS state",
            self.exp_config.get('paths', 'experiment_shot_storage'),
            "HDF5 files (*.h5)")
        try:
            dialog.setViewMode(QFileDialog.Detail)
            dialog.setFileMode(QFileDialog.AnyFile)
            dialog.setAcceptMode(QFileDialog.AcceptSave)

            if dialog.exec_():
                current_file = str(dialog.selectedFiles()[0])
                if not current_file.endswith('.h5'):
                    current_file += '.h5'
                self.front_panel_settings.save_front_panel_to_h5(
                    current_file, data[0], data[1], data[2], data[3])
        except Exception:
            raise
        finally:
            dialog.deleteLater()

    def on_open_preferences(self, *args, **kwargs):
        self.settings.create_dialog()
Exemplo n.º 13
0
def main():
    # Preparatory actions
    os.system("clear")
    os.chdir(".")
    Data.default_cwd = os.getcwd()
    Data.logs = []
    Data.fails = []
    Data.PROFILES_HISTORY_DIR_PATH = (os.path.expanduser("~") + os.sep +
                                      Data.PROFILES_HISTORY_DIR_PATH)

    # Getting deploy profiles from history
    deploy_profile = None
    is_hist_profile_selected = False
    if Data.USE_PROFILES_HISTORY_SEARCH:
        profiles_history = ProfilesHistory.get_profiles_paths_from_history()
        if len(profiles_history) > 0:
            print("[i] Found profiles in history:")
            print("0. Enter deploy profile path manually")
            profiles_history_counter = 0
            for one_hist_profile_path in profiles_history:
                profiles_history_counter = profiles_history_counter + 1
                print(
                    str(profiles_history_counter) + ". " +
                    one_hist_profile_path)
            selected_hist_profile_idx = input('Select variant: ')
            if selected_hist_profile_idx.isdigit():
                selected_hist_profile_idx = int(selected_hist_profile_idx)
                if len(profiles_history) >= selected_hist_profile_idx:
                    if selected_hist_profile_idx > 0:
                        is_hist_profile_selected = True
                        deploy_profile = Helpers.get_profile_file(
                            profiles_history[selected_hist_profile_idx - 1])
            else:
                exit("[X] Invalid input!")
    if not is_hist_profile_selected:
        # Reading deploy profile manually
        deploy_profile = Helpers.get_profile_file(None)
        if not deploy_profile:
            exit("[X] Invalid deploy profile or file not found!")

    start_time = datetime.datetime.now()

    # Profile validation
    profile_validation_res = Helpers.validate_profile(deploy_profile)
    if profile_validation_res != True:
        exit("[X] Profile validation error: " + str(profile_validation_res))

    # Project name
    project_name = deploy_profile["project_name"]
    print("=" * 40)
    print("[i] Selected project name: " + str(project_name))

    # Parsing profile environments
    print("[i] Found environments: " +
          str(Helpers.get_all_profile_envs(deploy_profile)))
    selected_profile_env = Helpers.select_profile_env(deploy_profile)
    if selected_profile_env == False:
        exit("[X] Unknown environment!")
    print("[i] Selected environment: " + selected_profile_env)

    # Processing stages
    print("[i] Processing stages...")
    deploy_stages = deploy_profile["environments"][selected_profile_env][
        "stages"]
    deploy_credentials = deploy_profile["environments"][selected_profile_env][
        "credentials"]
    stages_counter = 0
    for one_stage in deploy_stages:
        if one_stage["ignore"]:
            print("[i] " + str(stages_counter) + ". " +
                  str(one_stage["name"]) + " (IGNORED)")
            continue
        stages_counter = stages_counter + 1
        print("[i] " + str(stages_counter) + ". " + str(one_stage["print"]))
        result = Stages.run_stage(one_stage["name"], one_stage["details"],
                                  deploy_credentials)
        if result != True:
            print("[!] Current stage failed!\nResult:\n" + str(result) +
                  "\nContinue? (yes/no)")
            continue_or_not = input()
            if continue_or_not.replace(" ", "") != "yes":
                exit("[X] Exited with error!")

    # Saving current profile path to local history
    ProfilesHistory.save_profile_path_to_history(Data.curr_profile_path)

    end_time = datetime.datetime.now()
    print("[i] All done in " +
          str(int((end_time - start_time).total_seconds())) + " seconds!")
    print("=" * 40)

    # Slack notification
    print("Send notification slack? yes/no")
    send_notice_or_not = input()
    if send_notice_or_not.lower().replace(" ", "") == "yes":
        is_slack_bot_creds_valid = Notifications.validate_slack_bot_credentials(
            deploy_credentials)
        if is_slack_bot_creds_valid:
            print("Enter the message to send:")
            slack_msg_to_send = input()
            if slack_msg_to_send.lower().replace(" ", "") != "":
                slack_msg_to_send = (
                    "Backend update!" + "\n" + "Start time: " +
                    str(start_time) + "\n" + "End time: " + str(end_time) +
                    "\n" + "Elapsed time: " +
                    str(int((end_time - start_time).total_seconds())) +
                    " seconds\n" + "Environment: " + selected_profile_env +
                    "\n" + "Service: " + project_name + "\n" + "Message: " +
                    slack_msg_to_send)
                Notifications.send_msg_to_slack(
                    deploy_credentials["slack_bot"]["main"]["bot_token"],
                    deploy_credentials["slack_bot"]["main"]["project_channel"],
                    slack_msg_to_send,
                    deploy_credentials["slack_bot"]["main"]["icon_emoji"])
        else:
            print("[!] Invalid Slack credentials!")
Exemplo n.º 14
0
import serial

# Serial connection to LCD Module
lcd = serial.Serial(port='/dev/ttyAMA0',baudrate=9600)

# Format is 'message'; time to display,
NOTIFY_SETTINGS = {
	'status_date':	30,
	'status_torrents': 9,
	'status_email' : 10,
	'status_weather': 30,
	'status_disk':	9,
	}

# Initialize the notifications class
nt = Notifications()

# Set up the screen for first run
lcd.write(chr(12)) # Carriage Return (Clear any text)
sleep(1) # Necessary delay after clearing display
lcd.write(nt.startup())
lcd.write(chr(22)) # Display on, no cursor, no blink
lcd.write(chr(17)) # Backlight on
sleep(3)

# Loop through the list of settings and display
while True:
	for i, (TIMEOUT) in NOTIFY_SETTINGS.iteritems():
		msg = getattr(nt, i)()
		if len(msg):
			lcd.write(chr(12))
Exemplo n.º 15
0
 def notifications(self):
     return Notifications(self)
Exemplo n.º 16
0
class BLACS(object):

    tab_widget_ids = 7

    def __init__(self,application):
        self.qt_application = application
        #self.qt_application.aboutToQuit.connect(self.destroy)
        self._relaunch = False
        self.exiting = False
        self.exit_complete = False

        logger.info('Loading BLACS ui')
        #self.ui = BLACSWindow(self).ui
        loader = UiLoader()
        loader.registerCustomWidget(QueueTreeview)
        #loader.registerCustomPromotion('BLACS',BLACSWindow)
        self.ui = loader.load(os.path.join(os.path.dirname(os.path.realpath(__file__)),'main.ui'), BLACSWindow())
        logger.info('BLACS ui loaded')
        self.ui.blacs=self
        self.tab_widgets = {}
        self.exp_config = exp_config # Global variable
        self.settings_path = settings_path # Global variable
        self.connection_table = connection_table # Global variable
        self.connection_table_h5file = self.exp_config.get('paths','connection_table_h5')
        self.connection_table_labscript = self.exp_config.get('paths','connection_table_py')
        
        # Setup the UI
        self.ui.main_splitter.setStretchFactor(0,0)
        self.ui.main_splitter.setStretchFactor(1,1)

        self.tablist = {}
        self.panes = {}
        self.settings_dict = {}

        # Setup progressbar monitoring status queue
        self.ui.TimeNext_progressBar.setRange(0,100)

        self._countdown_queue = Queue.Queue()
        Queue_Receiver = QueueToSignal( self._countdown_queue)
        Queue_Receiver.mysignal.connect(self.ui.TimeNext_progressBar.setValue)
        thread = QThread()
        Queue_Receiver.moveToThread(thread)
        thread.started.connect(Queue_Receiver.run)
        thread.start()

        # Find which devices are connected to BLACS, and what their labscript class names are:
        logger.info('finding connected devices in connection table')
        self.attached_devices = self.connection_table.get_attached_devices()

        # Store the panes in a dictionary for easy access
        self.panes['tab_top_vertical_splitter'] = self.ui.tab_top_vertical_splitter
        self.panes['tab_bottom_vertical_splitter'] = self.ui.tab_bottom_vertical_splitter
        self.panes['tab_horizontal_splitter'] = self.ui.tab_horizontal_splitter
        self.panes['main_splitter'] = self.ui.main_splitter

        # Get settings to restore
        logger.info('Loading front panel settings')
        self.front_panel_settings = FrontPanelSettings(self.settings_path, self.connection_table)
        self.front_panel_settings.setup(self)
        settings,question,error,tab_data = self.front_panel_settings.restore()

        # TODO: handle question/error cases

        logger.info('restoring window data')
        self.restore_window(tab_data)

        #splash.update_text('Creating the device tabs...')
        # Create the notebooks
        logger.info('Creating tab widgets')
        for i in range(4):
            self.tab_widgets[i] = DragDropTabWidget(self.tab_widget_ids)
            getattr(self.ui,'tab_container_%d'%i).addWidget(self.tab_widgets[i])

        logger.info('Instantiating devices')
        for device_name, labscript_device_class_name in self.attached_devices.items():
            self.settings_dict.setdefault(device_name,{"device_name":device_name})
            # add common keys to settings:
            self.settings_dict[device_name]["connection_table"] = self.connection_table
            self.settings_dict[device_name]["front_panel_settings"] = settings[device_name] if device_name in settings else {}
            self.settings_dict[device_name]["saved_data"] = tab_data[device_name]['data'] if device_name in tab_data else {}
            # Instantiate the device
            logger.info('instantiating %s'%device_name)
            TabClass = labscript_devices.get_BLACS_tab(labscript_device_class_name)
            self.tablist[device_name] = TabClass(self.tab_widgets[0],self.settings_dict[device_name])

        logger.info('reordering tabs')
        self.order_tabs(tab_data)

        logger.info('starting analysis submission thread')
        # setup analysis submission
        self.analysis_submission = AnalysisSubmission(self,self.ui)
        if 'analysis_data' not in tab_data['BLACS settings']:
            tab_data['BLACS settings']['analysis_data'] = {}
        else:
            tab_data['BLACS settings']['analysis_data'] = eval(tab_data['BLACS settings']['analysis_data'])
        self.analysis_submission.restore_save_data(tab_data['BLACS settings']["analysis_data"])

        logger.info('starting queue manager thread')
        # Setup the QueueManager
        self.queue = QueueManager(self,self.ui)
        if 'queue_data' not in tab_data['BLACS settings']:
            tab_data['BLACS settings']['queue_data'] = {}
        else:
            tab_data['BLACS settings']['queue_data'] = eval(tab_data['BLACS settings']['queue_data'])
        self.queue.restore_save_data(tab_data['BLACS settings']['queue_data'])

        logger.info('instantiating plugins')
        # setup the plugin system
        settings_pages = []
        self.plugins = {}
        plugin_settings = eval(tab_data['BLACS settings']['plugin_data']) if 'plugin_data' in tab_data['BLACS settings'] else {}
        for module_name, module in plugins.modules.items():
            try:
                # instantiate the plugin
                self.plugins[module_name] = module.Plugin(plugin_settings[module_name] if module_name in plugin_settings else {})
            except Exception:
                logger.exception('Could not instantiate plugin \'%s\'. Skipping')

        blacs_data = {'exp_config':self.exp_config,
                      'ui':self.ui,
                      'set_relaunch':self.set_relaunch,
                      'plugins':self.plugins,
                      'connection_table_h5file':self.connection_table_h5file,
                      'connection_table_labscript':self.connection_table_labscript,
                      'experiment_queue':self.queue
                     }

        def create_menu(parent, menu_parameters):
            if 'name' in menu_parameters:
                if 'menu_items' in menu_parameters:
                    child = parent.addMenu(menu_parameters['name'])
                    for child_menu_params in menu_parameters['menu_items']:
                        create_menu(child,child_menu_params)
                else:
                    child = parent.addAction(menu_parameters['name'])

                if 'action' in menu_parameters:
                    child.triggered.connect(menu_parameters['action'])

            elif 'separator' in menu_parameters:
                parent.addSeparator()

        # setup the Notification system
        logger.info('setting up notification system')
        self.notifications = Notifications(blacs_data)

        settings_callbacks = []
        for module_name, plugin in self.plugins.items():
            try:
                # Setup settings page
                settings_pages.extend(plugin.get_setting_classes())
                # Setup menu
                if plugin.get_menu_class():
                    # must store a reference or else the methods called when the menu actions are triggered
                    # (contained in this object) will be garbaged collected
                    menu = plugin.get_menu_class()(blacs_data)
                    create_menu(self.ui.menubar,menu.get_menu_items())
                    plugin.set_menu_instance(menu)

                # Setup notifications
                plugin_notifications = {}
                for notification_class in plugin.get_notification_classes():
                    self.notifications.add_notification(notification_class)
                    plugin_notifications[notification_class] = self.notifications.get_instance(notification_class)
                plugin.set_notification_instances(plugin_notifications)

                # Register callbacks
                callbacks = plugin.get_callbacks()
                # save the settings_changed callback in a separate list for setting up later
                if isinstance(callbacks,dict) and 'settings_changed' in callbacks:
                    settings_callbacks.append(callbacks['settings_changed'])

            except Exception:
                logger.exception('Plugin \'%s\' error. Plugin may not be functional.'%module_name)


        # setup the BLACS preferences system
        logger.info('setting up preferences system')
        self.settings = Settings(file=self.settings_path, parent = self.ui, page_classes=settings_pages)
        for callback in settings_callbacks:
            self.settings.register_callback(callback)

        # update the blacs_data dictionary with the settings system
        blacs_data['settings'] = self.settings

        for module_name, plugin in self.plugins.items():
            try:
                plugin.plugin_setup_complete(blacs_data)
            except Exception:
                # backwards compatibility for old plugins
                try:
                    plugin.plugin_setup_complete()
                    logger.warning('Plugin \'%s\' using old API. Please update Plugin.plugin_setup_complete method to accept a dictionary of blacs_data as the only argument.'%module_name)
                except Exception:
                    logger.exception('Plugin \'%s\' error. Plugin may not be functional.'%module_name)

        # Connect menu actions
        self.ui.actionOpenPreferences.triggered.connect(self.on_open_preferences)
        self.ui.actionSave.triggered.connect(self.on_save_front_panel)
        self.ui.actionOpen.triggered.connect(self.on_load_front_panel)

        # Connect the windows AppId stuff:
        if os.name == 'nt':
            self.ui.newWindow.connect(set_win_appusermodel)

        logger.info('showing UI')
        self.ui.show()

    def set_relaunch(self,value):
        self._relaunch = bool(value)

    def restore_window(self,tab_data):
        # read out position settings:
        try:
            # There are some dodgy hacks going on here to try and restore the window position correctly
            # Unfortunately Qt has two ways of measuring teh window position, one with the frame/titlebar
            # and one without. If you use the one that measures including the titlebar, you don't
            # know what the window size was when the window was UNmaximized.
            #
            # Anyway, no idea if this works cross platform (tested on windows 8)
            # Feel free to rewrite this, along with the code in front_panel_settings.py
            # which stores the values
            #
            # Actually this is a waste of time because if you close when maximized, reoopen and then
            # de-maximize, the window moves to a random position (not the position it was at before maximizing)
            # so bleh!
            self.ui.move(tab_data['BLACS settings']["window_xpos"]-tab_data['BLACS settings']['window_frame_width']/2,tab_data['BLACS settings']["window_ypos"]-tab_data['BLACS settings']['window_frame_height']+tab_data['BLACS settings']['window_frame_width']/2)
            self.ui.resize(tab_data['BLACS settings']["window_width"],tab_data['BLACS settings']["window_height"])

            if 'window_maximized' in tab_data['BLACS settings'] and tab_data['BLACS settings']['window_maximized']:
                self.ui.showMaximized()

            for pane_name,pane in self.panes.items():
                pane.setSizes(tab_data['BLACS settings'][pane_name])

        except Exception as e:
            logger.warning("Unable to load window and notebook defaults. Exception:"+str(e))

    def order_tabs(self,tab_data):
        # Move the tabs to the correct notebook
        for device_name in self.attached_devices:
            notebook_num = 0
            if device_name in tab_data:
                notebook_num = int(tab_data[device_name]["notebook"])
                if notebook_num not in self.tab_widgets:
                    notebook_num = 0

            #Find the notebook the tab is in, and remove it:
            for notebook in self.tab_widgets.values():
                tab_index = notebook.indexOf(self.tablist[device_name]._ui)
                if tab_index != -1:
                    notebook.removeTab(tab_index)
                    self.tab_widgets[notebook_num].addTab(self.tablist[device_name]._ui,device_name)
                    break

        # splash.update_text('restoring tab positions...')
        # # Now that all the pages are created, reorder them!
        for device_name in self.attached_devices:
            if device_name in tab_data:
                notebook_num = int(tab_data[device_name]["notebook"])
                if notebook_num in self.tab_widgets:
                    self.tab_widgets[notebook_num].tab_bar.moveTab(self.tab_widgets[notebook_num].indexOf(self.tablist[device_name]._ui),int(tab_data[device_name]["page"]))

        # # Now that they are in the correct order, set the correct one visible
        for device_name,device_data in tab_data.items():
            if device_name == 'BLACS settings':
                continue
            # if the notebook still exists and we are on the entry that is visible
            if bool(device_data["visible"]) and int(device_data["notebook"]) in self.tab_widgets:
                self.tab_widgets[int(device_data["notebook"])].tab_bar.setCurrentIndex(int(device_data["page"]))

    def update_all_tab_settings(self,settings,tab_data):
        for device_name,tab in self.tablist.items():
            self.settings_dict[device_name]["front_panel_settings"] = settings[device_name] if device_name in settings else {}
            self.settings_dict[device_name]["saved_data"] = tab_data[device_name]['data'] if device_name in tab_data else {}
            tab.update_from_settings(self.settings_dict[device_name])

    def on_load_front_panel(self,*args,**kwargs):
        # get the file:
        # create file chooser dialog
        dialog = QFileDialog(None,"Select file to load", self.exp_config.get('paths','experiment_shot_storage'), "HDF5 files (*.h5 *.hdf5)")
        dialog.setViewMode(QFileDialog.Detail)
        dialog.setFileMode(QFileDialog.ExistingFile)
        if dialog.exec_():
            selected_files = dialog.selectedFiles()
            filepath = str(selected_files[0])
            # Qt has this weird behaviour where if you type in the name of a file that exists
            # but does not have the extension you have limited the dialog to, the OK button is greyed out
            # but you can hit enter and the file will be selected.
            # So we must check the extension of each file here!
            if filepath.endswith('.h5') or filepath.endswith('.hdf5'):
                try:
                    # TODO: Warn that this will restore values, but not channels that are locked
                    message = QMessageBox()
                    message.setText("""Warning: This will modify front panel values and cause device output values to update.
                    \nThe queue and files waiting to be sent for analysis will be cleared.
                    \n
                    \nNote: Channels that are locked will not be updated.\n\nDo you wish to continue?""")
                    message.setIcon(QMessageBox.Warning)
                    message.setWindowTitle("BLACS")
                    message.setStandardButtons(QMessageBox.Yes|QMessageBox.No)

                    if message.exec_() == QMessageBox.Yes:
                        front_panel_settings = FrontPanelSettings(filepath, self.connection_table)
                        settings,question,error,tab_data = front_panel_settings.restore()
                        #TODO: handle question/error

                        # Restore window data
                        self.restore_window(tab_data)
                        self.order_tabs(tab_data)
                        self.update_all_tab_settings(settings,tab_data)

                        # restore queue data
                        if 'queue_data' not in tab_data['BLACS settings']:
                            tab_data['BLACS settings']['queue_data'] = {}
                        else:
                            tab_data['BLACS settings']['queue_data'] = eval(tab_data['BLACS settings']['queue_data'])
                        self.queue.restore_save_data(tab_data['BLACS settings']['queue_data'])
                        # restore analysis data
                        if 'analysis_data' not in tab_data['BLACS settings']:
                            tab_data['BLACS settings']['analysis_data'] = {}
                        else:
                            tab_data['BLACS settings']['analysis_data'] = eval(tab_data['BLACS settings']['analysis_data'])
                        self.analysis_submission.restore_save_data(tab_data['BLACS settings']["analysis_data"])
                except Exception as e:
                    logger.exception("Unable to load the front panel in %s."%(filepath))
                    message = QMessageBox()
                    message.setText("Unable to load the front panel. The error encountered is printed below.\n\n%s"%str(e))
                    message.setIcon(QMessageBox.Information)
                    message.setWindowTitle("BLACS")
                    message.exec_()
                finally:
                    dialog.deleteLater()
            else:
                dialog.deleteLater()
                message = QMessageBox()
                message.setText("You did not select a file ending with .h5 or .hdf5. Please try again")
                message.setIcon(QMessageBox.Information)
                message.setWindowTitle("BLACS")
                message.exec_()
                QTimer.singleShot(10,self.on_load_front_panel)

    def on_save_exit(self):
        # Save front panel
        data = self.front_panel_settings.get_save_data()

        # with h5py.File(self.settings_path,'r+') as h5file:
           # if 'connection table' in h5file:
               # del h5file['connection table']

        self.front_panel_settings.save_front_panel_to_h5(self.settings_path,data[0],data[1],data[2],data[3],{"overwrite":True},force_new_conn_table=True)
        logger.info('Destroying tabs')
        for tab in self.tablist.values():
            tab.destroy()

        #gobject.timeout_add(100,self.finalise_quit,time.time())
        QTimer.singleShot(100,lambda: self.finalise_quit(time.time()))

    def finalise_quit(self,initial_time):
        logger.info('finalise_quit called')
        tab_close_timeout = 2
        # Kill any tabs which didn't close themselves:
        for name, tab in self.tablist.items():
            if tab.destroy_complete:
                del self.tablist[name]
        if self.tablist:
            for name, tab in self.tablist.items():
                # If a tab has a fatal error or is taking too long to close, force close it:
                if (time.time() - initial_time > tab_close_timeout) or tab.state == 'fatal error':
                    try:
                        tab.close_tab()
                    except Exception as e:
                        logger.error('Couldn\'t close tab:\n%s'%str(e))
                    del self.tablist[name]
        if self.tablist:
            QTimer.singleShot(100,lambda: self.finalise_quit(initial_time))
        else:
            self.exit_complete = True
            logger.info('quitting')

    def on_save_front_panel(self,*args,**kwargs):
        data = self.front_panel_settings.get_save_data()

        # Open save As dialog
        dialog = QFileDialog(None,"Save BLACS state", self.exp_config.get('paths','experiment_shot_storage'), "HDF5 files (*.h5)")
        try:
            dialog.setViewMode(QFileDialog.Detail)
            dialog.setFileMode(QFileDialog.AnyFile)
            dialog.setAcceptMode(QFileDialog.AcceptSave)

            if dialog.exec_():
                current_file = str(dialog.selectedFiles()[0])
                if not current_file.endswith('.h5'):
                    current_file += '.h5'
                self.front_panel_settings.save_front_panel_to_h5(current_file,data[0],data[1],data[2],data[3])
        except Exception:
            raise
        finally:
            dialog.deleteLater()

    def on_open_preferences(self,*args,**kwargs):
        self.settings.create_dialog()
Exemplo n.º 17
0
    def __init__(self,application):
        self.qt_application = application
        #self.qt_application.aboutToQuit.connect(self.destroy)
        self._relaunch = False
        self.exiting = False
        self.exit_complete = False

        logger.info('Loading BLACS ui')
        #self.ui = BLACSWindow(self).ui
        loader = UiLoader()
        loader.registerCustomWidget(QueueTreeview)
        #loader.registerCustomPromotion('BLACS',BLACSWindow)
        self.ui = loader.load(os.path.join(os.path.dirname(os.path.realpath(__file__)),'main.ui'), BLACSWindow())
        logger.info('BLACS ui loaded')
        self.ui.blacs=self
        self.tab_widgets = {}
        self.exp_config = exp_config # Global variable
        self.settings_path = settings_path # Global variable
        self.connection_table = connection_table # Global variable
        self.connection_table_h5file = self.exp_config.get('paths','connection_table_h5')
        self.connection_table_labscript = self.exp_config.get('paths','connection_table_py')
        
        # Setup the UI
        self.ui.main_splitter.setStretchFactor(0,0)
        self.ui.main_splitter.setStretchFactor(1,1)

        self.tablist = {}
        self.panes = {}
        self.settings_dict = {}

        # Setup progressbar monitoring status queue
        self.ui.TimeNext_progressBar.setRange(0,100)

        self._countdown_queue = Queue.Queue()
        Queue_Receiver = QueueToSignal( self._countdown_queue)
        Queue_Receiver.mysignal.connect(self.ui.TimeNext_progressBar.setValue)
        thread = QThread()
        Queue_Receiver.moveToThread(thread)
        thread.started.connect(Queue_Receiver.run)
        thread.start()

        # Find which devices are connected to BLACS, and what their labscript class names are:
        logger.info('finding connected devices in connection table')
        self.attached_devices = self.connection_table.get_attached_devices()

        # Store the panes in a dictionary for easy access
        self.panes['tab_top_vertical_splitter'] = self.ui.tab_top_vertical_splitter
        self.panes['tab_bottom_vertical_splitter'] = self.ui.tab_bottom_vertical_splitter
        self.panes['tab_horizontal_splitter'] = self.ui.tab_horizontal_splitter
        self.panes['main_splitter'] = self.ui.main_splitter

        # Get settings to restore
        logger.info('Loading front panel settings')
        self.front_panel_settings = FrontPanelSettings(self.settings_path, self.connection_table)
        self.front_panel_settings.setup(self)
        settings,question,error,tab_data = self.front_panel_settings.restore()

        # TODO: handle question/error cases

        logger.info('restoring window data')
        self.restore_window(tab_data)

        #splash.update_text('Creating the device tabs...')
        # Create the notebooks
        logger.info('Creating tab widgets')
        for i in range(4):
            self.tab_widgets[i] = DragDropTabWidget(self.tab_widget_ids)
            getattr(self.ui,'tab_container_%d'%i).addWidget(self.tab_widgets[i])

        logger.info('Instantiating devices')
        for device_name, labscript_device_class_name in self.attached_devices.items():
            self.settings_dict.setdefault(device_name,{"device_name":device_name})
            # add common keys to settings:
            self.settings_dict[device_name]["connection_table"] = self.connection_table
            self.settings_dict[device_name]["front_panel_settings"] = settings[device_name] if device_name in settings else {}
            self.settings_dict[device_name]["saved_data"] = tab_data[device_name]['data'] if device_name in tab_data else {}
            # Instantiate the device
            logger.info('instantiating %s'%device_name)
            TabClass = labscript_devices.get_BLACS_tab(labscript_device_class_name)
            self.tablist[device_name] = TabClass(self.tab_widgets[0],self.settings_dict[device_name])

        logger.info('reordering tabs')
        self.order_tabs(tab_data)

        logger.info('starting analysis submission thread')
        # setup analysis submission
        self.analysis_submission = AnalysisSubmission(self,self.ui)
        if 'analysis_data' not in tab_data['BLACS settings']:
            tab_data['BLACS settings']['analysis_data'] = {}
        else:
            tab_data['BLACS settings']['analysis_data'] = eval(tab_data['BLACS settings']['analysis_data'])
        self.analysis_submission.restore_save_data(tab_data['BLACS settings']["analysis_data"])

        logger.info('starting queue manager thread')
        # Setup the QueueManager
        self.queue = QueueManager(self,self.ui)
        if 'queue_data' not in tab_data['BLACS settings']:
            tab_data['BLACS settings']['queue_data'] = {}
        else:
            tab_data['BLACS settings']['queue_data'] = eval(tab_data['BLACS settings']['queue_data'])
        self.queue.restore_save_data(tab_data['BLACS settings']['queue_data'])

        logger.info('instantiating plugins')
        # setup the plugin system
        settings_pages = []
        self.plugins = {}
        plugin_settings = eval(tab_data['BLACS settings']['plugin_data']) if 'plugin_data' in tab_data['BLACS settings'] else {}
        for module_name, module in plugins.modules.items():
            try:
                # instantiate the plugin
                self.plugins[module_name] = module.Plugin(plugin_settings[module_name] if module_name in plugin_settings else {})
            except Exception:
                logger.exception('Could not instantiate plugin \'%s\'. Skipping')

        blacs_data = {'exp_config':self.exp_config,
                      'ui':self.ui,
                      'set_relaunch':self.set_relaunch,
                      'plugins':self.plugins,
                      'connection_table_h5file':self.connection_table_h5file,
                      'connection_table_labscript':self.connection_table_labscript,
                      'experiment_queue':self.queue
                     }

        def create_menu(parent, menu_parameters):
            if 'name' in menu_parameters:
                if 'menu_items' in menu_parameters:
                    child = parent.addMenu(menu_parameters['name'])
                    for child_menu_params in menu_parameters['menu_items']:
                        create_menu(child,child_menu_params)
                else:
                    child = parent.addAction(menu_parameters['name'])

                if 'action' in menu_parameters:
                    child.triggered.connect(menu_parameters['action'])

            elif 'separator' in menu_parameters:
                parent.addSeparator()

        # setup the Notification system
        logger.info('setting up notification system')
        self.notifications = Notifications(blacs_data)

        settings_callbacks = []
        for module_name, plugin in self.plugins.items():
            try:
                # Setup settings page
                settings_pages.extend(plugin.get_setting_classes())
                # Setup menu
                if plugin.get_menu_class():
                    # must store a reference or else the methods called when the menu actions are triggered
                    # (contained in this object) will be garbaged collected
                    menu = plugin.get_menu_class()(blacs_data)
                    create_menu(self.ui.menubar,menu.get_menu_items())
                    plugin.set_menu_instance(menu)

                # Setup notifications
                plugin_notifications = {}
                for notification_class in plugin.get_notification_classes():
                    self.notifications.add_notification(notification_class)
                    plugin_notifications[notification_class] = self.notifications.get_instance(notification_class)
                plugin.set_notification_instances(plugin_notifications)

                # Register callbacks
                callbacks = plugin.get_callbacks()
                # save the settings_changed callback in a separate list for setting up later
                if isinstance(callbacks,dict) and 'settings_changed' in callbacks:
                    settings_callbacks.append(callbacks['settings_changed'])

            except Exception:
                logger.exception('Plugin \'%s\' error. Plugin may not be functional.'%module_name)


        # setup the BLACS preferences system
        logger.info('setting up preferences system')
        self.settings = Settings(file=self.settings_path, parent = self.ui, page_classes=settings_pages)
        for callback in settings_callbacks:
            self.settings.register_callback(callback)

        # update the blacs_data dictionary with the settings system
        blacs_data['settings'] = self.settings

        for module_name, plugin in self.plugins.items():
            try:
                plugin.plugin_setup_complete(blacs_data)
            except Exception:
                # backwards compatibility for old plugins
                try:
                    plugin.plugin_setup_complete()
                    logger.warning('Plugin \'%s\' using old API. Please update Plugin.plugin_setup_complete method to accept a dictionary of blacs_data as the only argument.'%module_name)
                except Exception:
                    logger.exception('Plugin \'%s\' error. Plugin may not be functional.'%module_name)

        # Connect menu actions
        self.ui.actionOpenPreferences.triggered.connect(self.on_open_preferences)
        self.ui.actionSave.triggered.connect(self.on_save_front_panel)
        self.ui.actionOpen.triggered.connect(self.on_load_front_panel)

        # Connect the windows AppId stuff:
        if os.name == 'nt':
            self.ui.newWindow.connect(set_win_appusermodel)

        logger.info('showing UI')
        self.ui.show()
class System:
    # __init__ is the class constructor and is also where you must define your instance variables
    def __init__(self, pin: str = '123456'):
        # system starts disarmed, the '_' in front on the name indicates that this variable is supposed to be private
        # python does not have any other way to differentiate between public and private. This same annotation is also
        # used for private functions
        # The 'self' indicates that this variable is an instance variable much like 'this' is used in other languages.
        self.is_armed = False
        self.is_sensing = False  # is sensing is used to tell the system start looking for intruders
        # When arming a system, the system needs to give a delay in order to for the home owner to leave the house
        # without tripping the alarm system
        self._arm_time_delay = 5  # 1 * 60
        # setting to a default pin
        self._pin = pin
        self._user_pin_entry = ""
        self._user_first_key_entry_time = 0
        self._invalid_entry_count = 0

        # When user incorrectly enters in the pass code 4 times the system gets locked for 5min
        self.system_locked = False
        self._lock_time = 0
        self._lockout_duration = 10  # * 60  # currently set to 5 min but might consider less for testing
        self._pin_entry_max_timeout = 10  # Unit in seconds
        self._max_invalid_entry_before_system_lock = 4
        self.alarm_active = False

        # variable that tracks if a user modified the current state of the system
        # System needs to be running
        self._running = False
        # list to keep track of worker threads
        # DO NOT Create or start threads here!! Do it in the run method.
        self._threads = []

        # Setup logging for this module.
        self._logger = logging.getLogger('AlarmSystem')
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(threadName)s - %(levelname)s - %(message)s'
        )
        ch.setFormatter(formatter)
        self._logger.addHandler(ch)
        self._logger.setLevel(logging.DEBUG)
        # setting up tcp socket to receive
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            self._socket.bind(('127.0.0.1', 9090))
        except socket.error as e:
            self._logger.fatal('{}'.format(e))
            exit(1)

        # Create the sub system items that the main system will monitor and control
        self.keypad = Keypad()
        self.led = LED()
        self.event_queue = queue.Queue()
        # self.pir_sensor = PirSensor(self.event_queue)  # Turned off for now due to interference
        self.ultra_sonic_distance_sensor = UltraSonicDistanceSensor(
            self.event_queue)
        self.calendar = Calendar()
        self.watson = Watson()
        self.notifications = Notifications()

        # The web UI
        self._web_client = ui.create_app()
        self._web_process = Process(target=self._web_client.run,
                                    args=('0.0.0.0', 1234))

    def run(self):
        """
        System will create and start the helper threads here to ensure synchronization
        """
        if not self._running:
            self._running = True
            sensor_t = Thread(target=self._sensor_thread,
                              args=(),
                              name="Sensor_Thread")
            self._threads.append(sensor_t)
            sensor_t.start()

            calendar_t = Thread(target=self._calendar_thread,
                                args=(),
                                name="Calendar_Thread")
            self._threads.append(calendar_t)
            calendar_t.start()

            k_thread = Thread(target=self.keypad.capture_keypress,
                              args=(),
                              name="Keypad_Thread")
            self._threads.append(k_thread)
            k_thread.start()

            alarm_t = Thread(target=self._alarm_thread,
                             args=(),
                             name="Alarm_Thread")
            self._threads.append(alarm_t)
            alarm_t.start()

            ultra_sonic_thread = Thread(
                target=self.ultra_sonic_distance_sensor.monitor_distance,
                args=(),
                name="Ultra_Sonic_Thread")
            self._threads.append(ultra_sonic_thread)
            ultra_sonic_thread.start()

            self._web_process.start()
            self._main_thread()
            self._logger.info('web client has started')

    def _process_keypress_event(self, keypress_event: str):
        """
        The process of keypress event to deactivate or activate a system

        :param keypress_event:
        :return:
        """
        # When the last entry has been greater than x seconds, just clear the past data because of the timeout req
        if time(
        ) - self._user_first_key_entry_time > self._pin_entry_max_timeout:
            self.reset_user_entry()

        if not self.is_armed:
            # start the timer for the first keypress and reset the user entry
            if keypress_event == "#":
                self.reset_user_entry()
                self._logger.debug('# entered, passcode reset')
            else:
                self._user_pin_entry += keypress_event
                self._logger.debug('current pass code:' + self._user_pin_entry)
                # Check for success, we will only check for valid entry when the sizes are the same
                if len(self._user_pin_entry) == len(self._pin):
                    self._arm(self._user_pin_entry)
        else:
            self._user_pin_entry += keypress_event
            self._logger.debug('current pass code:' + self._user_pin_entry)
            if len(self._user_pin_entry) == len(self._pin):
                self._disarm(self._user_pin_entry)

    def reset_user_entry(self):
        self._user_pin_entry = ""
        self._user_first_key_entry_time = time()

    def _alarm_thread(self):
        """
        This method is intended to handle the periodic processing when the alarm needs to go off. Sounding an alarm and led
        This is indented to be run in a thread and only run when alarm is active. The Pictures and video should be handled
        outside this thread when the alarm gets activated
        :return:
        """
        # Threads should reference this run flag for loops so the system can close and join them when stopped.
        while self._running:
            if self.alarm_active:
                while self.alarm_active and self._running:
                    self.led.turn_on(color=LEDColor.RED, debug=False)
                    sleep(.1)
                    self.led.turn_off(color=LEDColor.RED, debug=False)
                    sleep(.1)
            else:
                # Added to not eat up the processing. This give a max of .5 delay when the alarm can be started
                sleep(.5)

    def _process_pir_event(self, pir_event: PIREvent):
        """
        The process of a PIR event that can signal an alarm if the system is armed

        For the alarm it will be latched. A latched alarm means that once it has been activated someone has to
        manually disable it using the pin or some kind of confirmation.

        :param pir_event:
        :return:
        """

        if pir_event.event_type == PirEventType.falling:
            self._logger.debug('Falling event occurred')
            self.watson.send_movement_falling()
        elif pir_event.event_type == PirEventType.rising:
            if self.is_sensing:
                # First event that has occurred when armed, activate alarm thread
                if not self.alarm_active:
                    self.alarm_active = True
                    self._logger.info('Alarm has been activated')
                    self.watson.send_alarm_activated()
                    camera.take_photo()
                    camera.take_video()
                    sleep(1)
                    # Get the latest image taken and send that in the message
                    list_of_files = glob.glob("/home/pi/motion/camera1" +
                                              '/*-snapshot.jpg')
                    latest_file = max(list_of_files, key=os.path.getctime)
                    self.notifications.send_alert_message(latest_file)
                    camera.take_video()
            self._logger.debug('Rising event occurred')
            self.watson.send_movement_rising()

    def _sensor_thread(self):
        """
        Thread for checking the sensor inputs.
        """
        self._logger.debug('starting sensor thread')
        while self._running:
            """
            Keypress Event check
            In the even of the queue being empty, the exception queue.Empty will be thrown. Thus a Try catch will be
            needed to handle the normal case when no event is in the queue
            """
            try:
                """
                Monitor if the system is locked. When locked all keypress are ignored. After the 5min timer is up then
                the time is reset and the system is unlocked
                """
                keypress_event = self.keypad.keypress_queue.get_nowait()
                if not self.system_locked:
                    self._process_keypress_event(keypress_event)
                else:
                    # Once the lockout has expired, reset the invalid entry count and led status
                    if time() - self._lock_time > self._lockout_duration:
                        self.system_locked = False
                        self._invalid_entry_count = 0
                        self.led.turn_off(LEDColor.RED)

            except queue.Empty:
                pass
            """
            PIR Event check
            In the even of the queue being empty, the exception queue.Empty will be thrown. Thus a Try catch will be
            needed to handle the normal case when no event is in the queue
            """
            try:
                pir_event = self.event_queue.get_nowait()
                self._process_pir_event(pir_event)
            except queue.Empty:
                pass
            sleep(.2)
            # TODO - should we consider a delay in this tread to not eat up the process?

    def _main_thread(self):
        """
        Main thread that checks for inputs from user devices and WebGUI
        :return:
        """
        self._logger.debug('starting main thread')
        try:
            while self._running:
                # accept connections
                self._socket.listen(5)
                connection = self._socket.accept()
                if connection is not None:
                    # self._logger.info("Received connection")
                    # create new thread an pass it the connection
                    t = Thread(target=self._connection_thread,
                               args=(connection[0], ))
                    self._threads.append(t)
                    t.start()
        except socket.error as e:
            self._logger.error('{}'.format(e))
        except KeyboardInterrupt as e:
            self._logger.info('{}'.format(e))
        finally:
            self._running = False
            self._join_threads()

    def _connection_thread(self, connection: socket.socket):
        """
        Process a connection from the system client.
        :param connection: The socket connection to utilize
        """
        try:
            data = json.loads(bytes(connection.recv(1024)).decode('utf-8'))
            if data is not None and isinstance(data, dict) and 'func' in data:
                func = data['func']
                if func == 'arm_disarm' and 'pin' in data and isinstance(
                        data['pin'], str):
                    if self.is_armed:
                        result = self._disarm(data['pin'])
                        connection.send(
                            json.dumps({
                                'result': result
                            }).encode('utf-8'))
                    else:
                        result = self._arm(data['pin'])
                        connection.send(
                            json.dumps({
                                'result': result
                            }).encode('utf-8'))
                elif func == 'set_pin' and 'current_pin' in data and isinstance(data['current_pin'], str) \
                        and 'new_pin' in data and isinstance(data['new_pin'], str):
                    result = self._set_pin(data['current_pin'],
                                           data['new_pin'])
                    connection.send(
                        json.dumps({
                            'result': result
                        }).encode('utf-8'))
                elif func == 'take_photo':
                    camera.take_photo()
                    connection.send(
                        json.dumps({
                            'result': True
                        }).encode('utf-8'))
                elif func == 'take_video':
                    camera.take_video()
                    connection.send(
                        json.dumps({
                            'result': True
                        }).encode('utf-8'))
                elif func == 'status':
                    connection.send(
                        json.dumps({
                            'armed': self.is_armed,
                            'led_color': self.led.color.name,
                            'led_enabled': self.led.enabled,
                            "is_sensing": self.is_sensing
                        }).encode('utf-8'))
        except socket.error as e:
            self._logger.error('{}'.format(e))
        except json.JSONDecodeError as e:
            self._logger.error('{}'.format(e))
        finally:
            connection.close()

    def _calendar_thread(self):
        """
        Thread that checks the google calendar once a second and takes action as appropriate.
        """
        while self._running:
            res = self.calendar.check_calendar()
            if res[0]:
                if res[1] and not self.is_armed:
                    self._arm(self._pin)
                elif not res[1] and self.is_armed:
                    self._disarm(self._pin)
            sleep(1)

    def _join_threads(self):
        """
        Joins all active threads before the program exits
        """
        self._logger.debug('joining threads...')
        for t in self._threads:
            t.join()
        self._logger.debug('threads joined')
        self._logger.debug('stopping UI process')
        self._web_process.close()
        self._logger.debug('stopped UI process')

    def _set_arm_after_delay(self):
        # Its possible we could have the system disarmed right way so we need to ignore this request to start sensing
        if self.is_armed:
            self._logger.info("System has been set to armed")
            self.is_sensing = True
            self.watson.send_armed()

    def _turn_off_led_after_system_unlocked(self):
        self.system_locked = False
        self._invalid_entry_count = 0
        self.led.turn_off(color=LEDColor.RED)

    def _arm(self, pin: str):
        # to create function documentation in pycharm simple type '"' three times and hit enter.
        """
        Arms the system if the system is not armed and the pin is correct.
        Assumption: The pin entry is the same length as the given pin. Upon a failed check the user entry is reset
        :param pin: the system pin
        """
        if not self.is_armed and self._check_pin(pin):
            self._logger.info(
                'Passcode entered correctly. System will be armed in ' +
                str(self._arm_time_delay) + " seconds")
            self.reset_user_entry()
            self._invalid_entry_count = 0
            self.led.flash_led(color=LEDColor.GREEN, flash_count=5)
            self.led.turn_on(color=LEDColor.BLUE)
            self.is_armed = True
            Timer(self._arm_time_delay, self._set_arm_after_delay).start()
            self.notifications.send_armed_message()
            return True
        else:
            return self.invalid_pin_entry()

    def invalid_pin_entry(self):
        self._invalid_entry_count += 1
        if self._invalid_entry_count > self._max_invalid_entry_before_system_lock:
            self.led.flash_led(color=LEDColor.YELLOW, flash_count=5)
            self.led.turn_on(color=LEDColor.RED)
            self._lock_time = time()
            self.system_locked = True
            self.notifications.send_locked_message()
            self._logger.info('System is locked')
            Timer(self._lockout_duration,
                  self._turn_off_led_after_system_unlocked).start()
        else:
            turn_alarm_back_on = False
            # Handing the case where the alarm is active and we need to notify the user they entered in an incorrect pin
            # This case will disable the alarm while the led will flash yellow, then will turn the alarm back on
            if self.alarm_active:
                self.alarm_active = False
                turn_alarm_back_on = True
                sleep(.5)
            self.led.flash_led(color=LEDColor.YELLOW, flash_count=2)
            if turn_alarm_back_on:
                self.alarm_active = True

            self.reset_user_entry()
            self._logger.info('Failed to enter the pin correctly')
        return False

    def _disarm(self, pin: str):
        """
        Disarms the system if the system is armed and the pin is correct.
        :param pin: the system pin
        :return:
        """
        if self.is_armed:
            if self._check_pin(pin):
                # When the alarm is running, deactivate alarm
                if self.alarm_active:
                    self.alarm_active = False
                    self._logger.info('Alarm turned off')
                    self.watson.send_alarm_deactivated()
                self.reset_user_entry()
                self._logger.info('System is now disarmed')
                self.is_armed = False
                self.is_sensing = False
                self.watson.send_diarmed()
                self.led.clear_led()
                self.led.flash_led(color=LEDColor.GREEN, flash_count=5)
                self._invalid_entry_count = 0
                self.notifications.send_disarmed_message()
                return True
            else:
                return self.invalid_pin_entry()

        self._logger.info('Failed to disarmed system')
        return False

    def _set_pin(self, current_pin: str, new_pin: str):
        """
        Sets a new pin for the system if the current_pin proved matches the system pin.
        :param current_pin: the current system pin
        :param new_pin: the new pin value
        :return if setting the pin was successful
        :rtype bool
        """
        if self._check_pin(current_pin):
            # check to see if the new pin is a length of 6 and if it only contains numbers
            if len(new_pin) == 6 and new_pin.isnumeric():
                self._pin = new_pin
                self._logger.info('System pin set')
                return True
        self._logger.info('Failed to set system pin')
        return False

    def _check_pin(self, pin: str):
        """
        Checks to see if the pin provided matches the system pin
        :param pin: the given pin to check
        :return: returns True if given pin matches system pin
        """
        if self._pin == pin:
            return True
        return False

    def is_armed(self):
        """
        Returns the armed status of the system.
        :return: armed
        """
        return self.is_armed
    def __init__(self, pin: str = '123456'):
        # system starts disarmed, the '_' in front on the name indicates that this variable is supposed to be private
        # python does not have any other way to differentiate between public and private. This same annotation is also
        # used for private functions
        # The 'self' indicates that this variable is an instance variable much like 'this' is used in other languages.
        self.is_armed = False
        self.is_sensing = False  # is sensing is used to tell the system start looking for intruders
        # When arming a system, the system needs to give a delay in order to for the home owner to leave the house
        # without tripping the alarm system
        self._arm_time_delay = 5  # 1 * 60
        # setting to a default pin
        self._pin = pin
        self._user_pin_entry = ""
        self._user_first_key_entry_time = 0
        self._invalid_entry_count = 0

        # When user incorrectly enters in the pass code 4 times the system gets locked for 5min
        self.system_locked = False
        self._lock_time = 0
        self._lockout_duration = 10  # * 60  # currently set to 5 min but might consider less for testing
        self._pin_entry_max_timeout = 10  # Unit in seconds
        self._max_invalid_entry_before_system_lock = 4
        self.alarm_active = False

        # variable that tracks if a user modified the current state of the system
        # System needs to be running
        self._running = False
        # list to keep track of worker threads
        # DO NOT Create or start threads here!! Do it in the run method.
        self._threads = []

        # Setup logging for this module.
        self._logger = logging.getLogger('AlarmSystem')
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(threadName)s - %(levelname)s - %(message)s'
        )
        ch.setFormatter(formatter)
        self._logger.addHandler(ch)
        self._logger.setLevel(logging.DEBUG)
        # setting up tcp socket to receive
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            self._socket.bind(('127.0.0.1', 9090))
        except socket.error as e:
            self._logger.fatal('{}'.format(e))
            exit(1)

        # Create the sub system items that the main system will monitor and control
        self.keypad = Keypad()
        self.led = LED()
        self.event_queue = queue.Queue()
        # self.pir_sensor = PirSensor(self.event_queue)  # Turned off for now due to interference
        self.ultra_sonic_distance_sensor = UltraSonicDistanceSensor(
            self.event_queue)
        self.calendar = Calendar()
        self.watson = Watson()
        self.notifications = Notifications()

        # The web UI
        self._web_client = ui.create_app()
        self._web_process = Process(target=self._web_client.run,
                                    args=('0.0.0.0', 1234))
Exemplo n.º 20
0
from notifications import Notifications
import time

n = Notifications()
n.alert_leak("shower")
n.general_alert("We are testing")
n.alert_usage_level()
Exemplo n.º 21
0
import serial

# Serial connection to LCD Module
lcd = serial.Serial(port='/dev/ttyAMA0', baudrate=9600)

# Format is 'message'; time to display,
NOTIFY_SETTINGS = {
    'status_date': 30,
    'status_torrents': 9,
    'status_email': 10,
    'status_weather': 30,
    'status_disk': 9,
}

# Initialize the notifications class
nt = Notifications()

# Set up the screen for first run
lcd.write(chr(12))  # Carriage Return (Clear any text)
sleep(1)  # Necessary delay after clearing display
lcd.write(nt.startup())
lcd.write(chr(22))  # Display on, no cursor, no blink
lcd.write(chr(17))  # Backlight on
sleep(3)

# Loop through the list of settings and display
while True:
    for i, (TIMEOUT) in NOTIFY_SETTINGS.iteritems():
        msg = getattr(nt, i)()
        if len(msg):
            lcd.write(chr(12))
Exemplo n.º 22
0
class MessageHandler(object):

    def __init__(self, host, port, username, password, logdir, logflg):

        self.connection = pika.BlockingConnection(
            pika.ConnectionParameters(host=host, port=port, credentials=pika.PlainCredentials(username, password)))
        self.channel = self.connection.channel()
        self.channel.exchange_declare(exchange='events', type='fanout')
        self.queue_name = self.channel.queue_declare(exclusive=True).method.queue
        self.channel.queue_bind(exchange='events', queue=self.queue_name)

        self.thread = threading.Thread(target=self.run, args=())
        self.thread.daemon = True

        self.nfs = Notifications()
        self.reg = Registrations()
        self.logflg = logflg
        self.newsqn = False
        self.badhard = False

        ts = time.strftime("%d-%b-%Y-%H-%M-%S", time.gmtime(time.time()))
        lgf = "%s/cosmicpi-logs/%s.log" % (logdir, ts)
        dir = os.path.dirname(lgf)
        if not os.path.exists(dir):
            os.makedirs(dir)
        try:
            self.log = open(lgf, "w")
        except Exception as e:
            msg = "Exception: Cant open log file: %s" % (e)
            print "Fatal: %s" % msg
            sys.exit(1)

    def start(self):
        self.thread.start()

    def run(self):
        self.channel.basic_consume(self.on_message, queue=self.queue_name, no_ack=True)
        self.channel.start_consuming()

    def join(self):
        self.thread.join()

    def on_message(self, ch, method, properties, body):
        if len(body):
            event = Event(json.loads(body))

            if hasattr(event, 'event'):
                self.newsqn = True
                print 'Cosmic event received'
                print "Event.........: %s" % json.dumps(event.event)
                print "Timing........: %s" % json.dumps(event.timing)
                print "Date..........: %s" % json.dumps(event.date)

            elif hasattr(event, 'vibration'):
                self.newsqn = True
                print 'Vibration event received'
                print "Vibration.....: %s" % json.dumps(event.vibration)
                print "Accelerometer.: %s" % json.dumps(event.accelerometer)
                print "Magnetometer..: %s" % json.dumps(event.magnetometer)
                print "Timing........: %s" % json.dumps(event.timing)

            elif hasattr(event, 'temperature'):
                self.newsqn = True
                print 'Weather event received'
                print "Thermometer...: %s" % json.dumps(event.temperature)
                print "Barometer.....: %s" % json.dumps(event.barometer)
                print "Timing........: %s" % json.dumps(event.timing)

            elif hasattr(event, 'PAT'):
                pat = event.PAT
                print
                print "Notification..: Pat:%s Ntf:%s" % (pat["Pat"], pat["Ntf"])
                if pat["Ntf"] == True:
                    msg = "Your are now registered to recieve pi server notifications"
                else:
                    msg = "You will no longer recieve pi server notifications"

                self.nfs.send_ntf(pat["Pat"], msg)

                r = self.reg.get_create_reg("Ipa", pat)
                r["Pat"] = pat["Pat"]
                r["Ntf"] = pat["Ntf"]
                self.reg.set_reg(r)

            elif hasattr(event, 'status'):
                sts = event.status
                r = self.reg.get_create_reg("Ipa", sts)
                r["temp_status"] = sts["temp_status"]
                r["baro_status"] = sts["baro_status"]
                r["accel_status"] = sts["accel_status"]
                r["mag_status"] = sts["mag_status"]
                r["gps_status"] = sts["gps_status"]
                self.reg.set_reg(r)

                msg = ""
                if int(r["temp_status"]) == 0:
                    msg = msg + "temp_status down: "
                if int(r["baro_status"]) == 0:
                    msg = msg + "baro_status down: "
                if int(r["accel_status"]) == 0:
                    msg = msg + "accel_status down: "
                if int(r["mag_status"]) == 0:
                    msg = msg + "mag_status down: "
                if int(r["gps_status"]) == 0:
                    msg = msg + "gps_status down: "

                if len(msg) > 0:
                    if self.badhard == False:
                        self.badhard = True
                        if r["Ntf"]:
                            self.nfs.send_ntf(event.PAT["Pat"], msg)
                        print "Hardware error:%s %s" % (sts, msg)
                else:
                    if self.badhard == True:
                        self.badhard = False
                        msg = "Hardware OK again"
                        if r["Ntf"]:
                            self.nfs.send_ntf(event.PAT["Pat"], msg)
                        print "%s:%s" % (msg, sts)
            if self.newsqn:
                self.newsqn = False
                sqn = event.sequence
                r = self.reg.get_create_reg("Ipa", sqn)
                j = int(r["Sqn"])
                i = int(sqn["number"])
                if i != j + 1 and j != 0:
                    msg = "Sequence error: %s %d-%d" % (sqn, i, j)
                    print msg
                    if r["Ntf"]:
                        self.nfs.send_ntf(event.PAT["Pat"], msg)

                r["number"] = i
                self.reg.set_reg(r)

            # if self.logflg:
            #     line = "%s - %s" % (str(recv[0]), str(recv[1]))
            #     self.log.write(line)
            #     self.log.write("\n\n")

    def close(self):
        self.connection.close()
Exemplo n.º 23
0
 def __init__(self):
     self.logger = logger.getLogger(self.__class__.__name__)
     self.notifications = Notifications()
Exemplo n.º 24
0
from media.sonarr import Sonarr
from media.trakt import Trakt
from misc import helpers
from misc.config import cfg
from misc.log import logger
from notifications import Notifications

############################################################
# INIT
############################################################

# Logging
log = logger.get_logger('traktarr')

# Notifications
notify = Notifications()


# Click
@click.group(help='Add new shows & movies to Sonarr/Radarr from Trakt lists.')
@click.version_option('1.1.1', prog_name='traktarr')
def app():
    pass


############################################################
# SHOWS
############################################################


@app.command(help='Add new shows to Sonarr.')