def ok_worker(self, mode): ''' The callback function called when the alarm or warning pop up window is closed by clicking on the Ok button. arguments: - mode: what this is closing, an 'alarm' or a 'warning' ''' if mode not in ['alarm', 'warning']: raise Exception('mode must be alarm or warning.') if mode == 'alarm': self._alarm_raised = False else: self._warning_raised = False # Reset the alarms/warnings in the ESP # If the ESP connection fails at this # time, raise an error box try: if mode == 'alarm': self._esp32.reset_alarms() else: self._esp32.reset_warnings() except Exception as error: msg = MessageBox() fn = msg.critical("Critical", "Severe hardware communication error", str(error), "Communication error", { msg.Retry: lambda: self.ok_worker(mode), msg.Abort: lambda: None }) fn()
def _on_click_snooze(self): ''' The callback function called when the alarm snooze button is clicked. ''' if self._mode not in [WARNING, ERROR]: raise Exception('mode must be alarm or warning.') # Reset the alarms/warnings in the ESP # If the ESP connection fails at this # time, raise an error box try: if self._mode == ERROR: self._esp32.snooze_hw_alarm(self._code) self._alarm_h.snooze_alarm(self._code) else: self._esp32.reset_warnings() self._alarm_h.snooze_warning(self._code) except Exception as error: msg = MessageBox() fn = msg.critical("Critical", "Severe hardware communication error", str(error), "Communication error", { msg.Retry: lambda: self.ok_worker(mode), msg.Abort: lambda: None }) fn()
def toggle_lung_recruit(self): if self._lung_recruit: self._lung_recruit = False self._esp32.set("pause_lg", 0) self._lung_recruit_timer.stop() self.button_lung_recruit.setText("Lung\nRecruitment") else: msg = MessageBox() fn = msg.question( "Please confirm", "Do you want to start the Lung Recruitment procedure?", None, "Confirmation required", { msg.Yes: lambda: True, msg.No: lambda: False }) answer = fn() if not answer: return self._lung_recruit = True lr_time = self._config["lung_recruit_time"]["current"] lr_pres = self._config["lung_recruit_pres"]["current"] self.button_lung_recruit.setText("Stop\nLung Recruitment\n %d" % lr_time) self._esp32.set("pause_lg_p", lr_pres) self._esp32.set("pause_lg_time", lr_time) self._esp32.set("pause_lg", 1) self._lung_recruit_timer = QtCore.QTimer() self._lung_recruit_timer.timeout.connect( self._get_lung_recruit_eta) self._lung_recruit_timer.start(500)
def thread_complete(self): ''' Called when a thread ends. ''' if self._running: print( "\033[91mERROR: The I/O thread finished! Going to start a new one...\033[0m" ) self._n_attempts += 1 self._running = False if self._n_attempts > 10: self._n_attempts = 0 msg = MessageBox() # TODO: find a good exit point callbacks = { msg.Retry: self.start_io_thread, msg.Abort: lambda: sys.exit(-1) } fn = msg.critical("COMMUNICATION ERROR", "CANNOT COMMUNICATE WITH THE HARDWARE", "Check cable connections then click retry.", "COMMUNICATION ERROR", callbacks) fn() time.sleep(0.05) self.start_io_thread()
def set_run(self, run): ''' Sets the run variable directly. Usually called at start up, when reading the run value from the ESP. arguments: - run: the run value (0 or 1) to set ''' if self._run == run: return self._run = run if run == self.DONOT_RUN: # TODO: this should be an alarm msg = MessageBox() msg.critical( 'STOPPING VENTILATION', 'The hardware has stopped the ventilation.', 'The microcontroller has stopped the ventilation by sending run = ' + str(run), 'The microcontroller has stopped the ventilation by sending run = ' + str(run), {msg.Ok: self.show_start_button})() else: self.show_stop_button()
def handle_alarms(self): ''' The callback method which is called periodically to check if the ESP raised any alarm or warning. If an alarm or warning is raised, a pop up window appears, showing the list of alarms and warnings. If more alarms or warnings add up, the window is updated automatically showing the latest errors. ''' # Retrieve alarms and warnings from the ESP try: esp32alarm = self._esp32.get_alarms() esp32warning = self._esp32.get_warnings() except Exception as error: esp32alarm = None esp32warning = None err_msg = "Severe hardware communication error. " err_msg += "Cannot retrieve alarm and warning statuses from hardware." msg = MessageBox() fn = msg.critical("Critical", err_msg, str(error), "Communication error", { msg.Retry: lambda: None, msg.Abort: lambda: None }) fn() # # ALARMS # if esp32alarm: errors = esp32alarm.strerror_all() errors_full = esp32alarm.strerror_all(append_err_no=True) alarm_codes = esp32alarm.get_alarm_codes() for alarm_code, err_str in zip(alarm_codes, errors): if alarm_code not in self._err_buttons: btn = AlarmButton(ERROR, alarm_code, err_str, self._alarmlabel, self._snooze_btn) self._alarmstack.addWidget(btn) self._err_buttons[alarm_code] = btn # # WARNINGS # if esp32warning: errors = esp32warning.strerror_all() errors_full = esp32warning.strerror_all(append_err_no=True) warning_codes = esp32warning.get_alarm_codes() for warning_code, err_str in zip(warning_codes, errors): if warning_code not in self._war_buttons: btn = AlarmButton(WARNING, warning_code, err_str, self._alarmlabel, self._snooze_btn) self._alarmstack.addWidget(btn) self._war_buttons[warning_code] = btn
def _raise_comm_error(self, message): """ Opens an error window with 'message'. """ # TODO: find a good exit point msg = MessageBox() msg.critical('COMMUNICATION ERROR', 'Error communicating with the hardware', message, '** COMMUNICATION ERROR **', {msg.Ok: lambda: sys.exit(-1)})()
def __init__(self, config, esp32): ''' Constructor arguments: - config: the dictionary storing the configuration - esp32: the esp32serial object ''' self._config = config self._esp32 = esp32 self._alarm_raised = False self._warning_raised = False self._msg_err = MessageBox() self._msg_war = MessageBox() self._alarm_timer = QtCore.QTimer() self._alarm_timer.timeout.connect(self.handle_alarms) self._alarm_timer.start(config["alarminterval"] * 1000)
def _open_backup_warning(self): ''' Opens a warning message if the ventilator changed from PSV to PCV ventilation. ''' msg = MessageBox() callbacks = {msg.Ok: self._acknowlege_backup} msg.warning("CHANGE OF MODE", "The ventilator changed from PSV to PCV mode.", "The microcontroller raised the backup flag.", "", callbacks)()
def confirm_stop_pressed(self): ''' Opens a window which asks for confirmation when the Stop button is pressed. ''' self.button_autoassist.setDown(False) currentMode = self.mode_text.upper() msg = MessageBox() ok = msg.question("**STOPPING %s MODE**" % currentMode, "Are you sure you want to STOP %s MODE?" % currentMode, None, "IMPORTANT", { msg.Yes: lambda: True, msg.No: lambda: False })() return ok
def test_MessageBox_Question(qtbot): msg = MessageBox() def foo(): pass callbacks = {msg.Ok: foo} msg.question("CHANGE OF MODE", "The ventilator changed from PSV to PCV mode.", "The microcontroller raised the backup flag.", "", callbacks, True) assert msg is not None
def send_signal(self, mode, pause): ''' Sends signal the appropriate signal the ESP to pause inpiration or expiration. ''' try: if not self._data_h.set_data(mode, int(pause)): raise Exception('Call to set_data failed.') except Exception as error: msg = MessageBox() fn = msg.critical("Critical", "Severe hardware communication error", str(error), "Communication error", {msg.Ok: lambda: self.stop_timer()}) fn()
def start_gui(): """ Launch the MVM GUI """ base_dir = os.path.dirname(__file__) settings_file = os.path.join(base_dir, 'default_settings.yaml') with open(settings_file) as mvm_settings: config = yaml.load(mvm_settings, Loader=yaml.FullLoader) print('Config:', yaml.dump(config), sep='\n') app = QtWidgets.QApplication(sys.argv) esp32 = None if 'fakeESP32' in sys.argv: print('******* Simulating communication with ESP32') esp32 = FakeESP32Serial(config) else: while True: try: err_msg = "Cannot communicate with port %s" % config['port'] esp32 = ESP32Serial(config) break except SerialException as error: msg = MessageBox() retry = msg.critical("Do you want to retry?", "Severe hardware communication error", str(error) + err_msg, "Communication error", {msg.Retry: lambda: True, msg.Abort: lambda: sys.exit(-1)}) if not retry(): break if esp32 is None: exit(-1) esp32.set("wdenable", 1) watchdog = QtCore.QTimer() watchdog.timeout.connect(esp32.set_watchdog) watchdog.start(config["wdinterval"] * 1000) window = MainWindow(config, esp32) window.show() app.exec_() esp32.set("wdenable", 0)
def open_comm_error(self, error): ''' Opens a message window if there is a communication error. ''' msg = MessageBox() # TODO: find a good exit point callbacks = { msg.Retry: self._restart_timer, msg.Abort: lambda: sys.exit(-1) } fn = msg.critical( "COMMUNICATION ERROR", "CANNOT COMMUNICATE WITH THE HARDWARE", "Check cable connections then click retry.\n" + error, "COMMUNICATION ERROR", callbacks) fn()
def send_signal(self, mode, pause): """ Sends signal the appropriate signal the ESP to pause inpiration or expiration. arguments: - mode: The pause mode (either 'pause_exhale' or 'pause_inhale') - pause: Boolean for paused or not paused """ try: if not self._data_h.set_data(mode, int(pause)): raise Exception('Call to set_data failed.') except Exception as error: msg = MessageBox() confirm_func = msg.critical( "Critical", "Severe hardware communication error", str(error), "Communication error", {msg.Ok: lambda: self.stop_timer(mode)}) confirm_func()
def set_run(self, run): ''' Sets the run variable directly. Usually called at start up, when reading the run value from the ESP. ''' if self.run == run: return if self.run == self.DO_RUN: msg = MessageBox() msg.critical('STOPPING VENTILATION', 'The hardware has stopped the ventilation.', 'The microcontroller has stopped the ventilation by sending run = '+str(run), 'The microcontroller has stopped the ventilation by sending run = '+str(run), {msg.Ok: self._stop_abruptly})() else: self.toggle_start_stop()
def __init__(self, screen, data): self.screen = screen self.data = data self.stage_num = 1 self.select_num = 0 self.option_num = 0 self.path = glob('stage/*/') self.new_path = [] for i in range(len(self.path)): self.new_path.append(self.path[i].strip('stage\/')) StageSelect_font = pygame.font.Font("font/freesansbold.ttf", 55) Arrow_font = pygame.font.Font("font/freesansbold.ttf", 100) self.Stage_font = pygame.font.Font("font/freesansbold.ttf", 45) self.StageSelect_text = StageSelect_font.render("Stage Select", True, (255,255,255)) self.RightArrow_text = Arrow_font.render(">", True, (255,255,255)) self.LeftArrow_text = Arrow_font.render("<", True, (255,255,255)) self.RightArrow_text = pygame.transform.rotate(self.RightArrow_text, 90) self.LeftArrow_text = pygame.transform.rotate(self.LeftArrow_text, 90) # ステージのテキスト情報をリストにする self.stage_text = [None] '''for i in range(3): text = "Stage" + str(i+1) self.stage_text.append(Stage_font.render(text, True, (255,255,255))) ''' # リストボックスの設定 self.option_listbox = ListBox(self.screen, 50, 80, 250, 200, ['Back', 'Shop', 'Equip'], font_size=55, title="Menu") self.option_listbox.set_selectable([True, True, True]) self.file_listbox = ListBox(self.screen, 940, 80, 120, 400, self.new_path, title="File") self.file_listbox.set_selectable([True, True]) self.file_listbox() self.file_id = None # メッセージボックスの設定 self.messagebox = MessageBox(self.screen, 130, 540, 900, outline_color=(180,180,180), select='random') with open('data/message.txt', 'r', encoding='utf-8') as fp: self.messagebox += fp.readlines() self.clock = pygame.time.Clock()
def connect_esp32(config): try: if 'fakeESP32' in sys.argv: print('******* Simulating communication with ESP32') err_msg = "Cannot setup FakeESP32Serial" esp32 = FakeESP32Serial(config) esp32.set("wdenable", 1) else: err_msg = "Cannot communicate with port %s" % config['port'] esp32 = ESP32Serial(config) esp32.set("wdenable", 1) except Exception as error: msg = MessageBox() fn = msg.critical("Do you want to retry?", "Severe hardware communication error", str(error) + err_msg, "Communication error", { msg.Retry: lambda: connect_esp32(config), msg.Abort: lambda: None}) return fn() return esp32
def processComplet(document): bdd = getSheetByName(document, "base de données") config = getSheetByName(document, "configuration") blanc = config.getCellByPosition(0, 0).getPropertyValue('CellBackColor') plantation = config.getCellByPosition(1, 0).getPropertyValue('CellBackColor') croissance = config.getCellByPosition(1, 1).getPropertyValue('CellBackColor') recolte = config.getCellByPosition(1, 2).getPropertyValue('CellBackColor') erreur = config.getCellByPosition(1, 3).getPropertyValue('CellBackColor') pcSheet = Sheet(getSheetByName(document, "PC"), erreur) saSheet = Sheet(getSheetByName(document, "SA"), erreur) dicoLegume = dictionnaireLegumes(bdd) if dicoLegume is None: MessageBox( document, 'Completer la feuille «base de données». Un filtre sur la croissance et la récolte = 0 peut aider', 'Erreur bdd') document.getCurrentController().setActiveSheet(bdd) return None MessageBox(document, 'Lecture de la BDD fait', 'Step 1') def coloriser(sheet: Sheet, dicoLegumes): oosheet = sheet.oosheet typeDeSol = oosheet.Name erreurs = {"placePrise": [], "légume inexistant": [], 'ajout': {}} for cell in sheet.getValideCell(): colonne = cell.CellAddress.Column year = sheet.convertColonneToYear(colonne) week = sheet.convertColonneToSemaine(colonne) ligne = cell.CellAddress.Row currentLegume = dicoLegumes.getInfos( cell.String, typeDeSol, sheet.convertColonneToSemaine(colonne)) failed = False if currentLegume is None: erreurs["légume inexistant"].append( (cell.String, typeDeSol, convertSemaineToTrimestre( sheet.convertColonneToSemaine(colonne)))) failed = True else: for i in range(1, currentLegume.aColoriser() + 1): if oosheet.getCellByPosition( colonne + i, ligne).getPropertyValue('CellBackColor') != blanc: erreurs["placePrise"].append(cell) failed = True cell.setPropertyValue("CellBackColor", erreur) break if failed == False: cell.setPropertyValue("CellBackColor", plantation) dureeCroissance = currentLegume.croissance dureeRecolte = currentLegume.recolte for i in range(1, currentLegume.croissance + 1): oosheet.getCellByPosition(colonne + i, ligne).setPropertyValue( 'CellBackColor', croissance) for i in range(dureeCroissance + 1, dureeCroissance + dureeRecolte + 1): oosheet.getCellByPosition(colonne + i, ligne).setPropertyValue( 'CellBackColor', recolte) if year not in erreurs['ajout']: erreurs['ajout'][year] = {} if currentLegume not in erreurs['ajout'][year]: erreurs['ajout'][year][currentLegume] = {} if week not in erreurs['ajout'][year][currentLegume]: erreurs['ajout'][year][currentLegume][week] = 0 erreurs['ajout'][year][currentLegume][week] += 1 erreurs["légume inexistant"] = set(erreurs["légume inexistant"]) return erreurs def completeSemis(bilan, document): for site in bilan: for year in bilan[site]: semisDoc = getSheetByName(document, "Semis " + str(year % 2000)) emptyLine = 1 while semisDoc.getCellByPosition(0, emptyLine).String != "": emptyLine += 1 emptyLine += 1 for legume in bilan[site][year]: for week in bilan[site][year][legume]: quantite = bilan[site][year][legume][week] semisDoc.getCellRangeByName("A" + str(emptyLine)).setFormula( legume.nom) semisDoc.getCellRangeByName( "C" + str(emptyLine)).setFormula(site) semisDoc.getCellRangeByName( "D" + str(emptyLine)).setFormula(week - legume.elevage) semisDoc.getCellRangeByName( "F" + str(emptyLine)).setFormula(week) semisDoc.getCellRangeByName( "J" + str(emptyLine)).setFormula(quantite) semisDoc.getCellRangeByName("K" + str(emptyLine)).setFormula( legume.densite) semisDoc.getCellRangeByName("N" + str(emptyLine)).setFormula( legume.nbCaisse * quantite) semisDoc.getCellRangeByName("H" + str(emptyLine)).setFormula( legume.croissance + week) emptyLine += 1 bilanPC = coloriser(pcSheet, dicoLegume) MessageBox(document, 'Feuille PC : traitée', 'Step 2') bilanSA = coloriser(saSheet, dicoLegume) bilanAjout = {'PC': bilanPC['ajout'], 'SA': bilanSA['ajout']} completeSemis(bilanAjout, document) MessageBox(document, 'Feuille SA : traitée', 'Step 3') missingLegumes = bilanSA["légume inexistant"].union( bilanPC["légume inexistant"]) if len(missingLegumes) > 0: addMissingLegumes(bdd, missingLegumes) MessageBox(document, str(len(missingLegumes)) + ' légumes rajoutés à la feuille', 'Ajout légumes') document.getCurrentController().setActiveSheet(bdd) if (len(bilanSA["placePrise"]) + len(bilanPC["placePrise"])) > 0: MessageBox( document, str(len(bilanSA["placePrise"]) + len(bilanPC["placePrise"])) + ' légumes n\'ont pas assez de places et ont été mis en rouge', 'Soucis planning') MessageBox(document, 'Fini', 'Fini') return None
logfile = open(logfilename, 'w').close() # Clear log file logging.basicConfig(format='%(asctime)s %(message)s', filename=logfilename, level=logging.ERROR) text = open(filename, 'r') url = text.read() url = convertURL(url) seen_posts = [] # Store which posts we've already marked as potential signups checkpoint = 1 # 1 to ignore OP post startup_delay_thread = Thread(target=delaySignUpNotifications, args=()) startup_delay_thread.daemon = True startup_delay_thread.start() messageBox = MessageBox() # Initialise Pushover Client client = None if SEND_PUSH_NOTIFICATIONS: try: client = Client(getenv("USER_KEY"), api_token=getenv("API_TOKEN"), device=getenv("DEVICE")) print("Pushover client initialised successfully") except: logging.exception("An exception occured. Stack trace below") while True: try: response = requests.get(url) parsed_json = json.loads(response.text) if not thread_limit_reached_message_displayed:
def handle_alarms(self): ''' The callback method which is called periodically to check if the ESP raised any alarm or warning. If an alarm or warning is raised, a pop up window appears, showing the list of alarms and warnings. If more alarms or warnings add up, the window is updated automatically showing the latest errors. ''' # Retrieve alarms and warnings from the ESP try: esp32alarm = self._esp32.get_alarms() esp32warning = self._esp32.get_warnings() except Exception as error: esp32alarm = None esp32warning = None err_msg = "Severe hardware communication error. " err_msg += "Cannot retrieve alarm and warning statuses from hardware." msg = MessageBox() fn = msg.critical("Critical", err_msg, str(error), "Communication error", { msg.Retry: lambda: None, msg.Abort: lambda: None }) fn() # # ALARMS # if esp32alarm: errors = esp32alarm.strerror_all() errors_full = esp32alarm.strerror_all(append_err_no=True) if not self._alarm_raised: self._alarm_raised = True self._msg_err.critical("ALARM", " - ".join(errors), "\n".join(errors_full), "Alarm received.", { self._msg_err.Ignore: lambda: self.ok_worker('alarm', esp32alarm) }, do_not_block=True) self._msg_err.move(0, 100) self._msg_err.open() else: # If the window is already opened, just change the text self._msg_err.setInformativeText(" - ".join(errors)) self._msg_err.setDetailedText("\n".join(errors_full)) self._msg_err.raise_() # # WARNINGS # if esp32warning: errors = esp32warning.strerror_all() errors_full = esp32warning.strerror_all(append_err_no=True) if not self._warning_raised: self._warning_raised = True self._msg_war.warning("WARNING", " - ".join(errors), "\n".join(errors_full), "Warning received.", { self._msg_war.Ok: lambda: self.ok_worker('warning', esp32warning) }, do_not_block=True) self._msg_war.move(0, 300) self._msg_war.open() else: # If the window is already opened, just change the text self._msg_war.setInformativeText(" - ".join(errors)) self._msg_war.setDetailedText("\n".join(errors_full)) self._msg_war.raise_()
def setUp(self): text = open("fixtures.json", 'r') self.parsed_json = json.loads(text.read()) self.messageBoxMock = MessageBox() self.messageBoxMock.displayMessageBox = MagicMock() text.close()
def send_values_to_hardware(self): ''' Sends the currently set values to the ESP ''' settings_to_file = {} for param, btn in self._all_spinboxes.items(): settings_to_file[param] = self._current_values[param] # value is the variable to be sent to the hardware, # so possibly converted from the settings if param in ['enable_backup', 'pcv_trigger_enable']: value = int(self._current_values[param]) elif param == 'insp_expir_ratio': i_over_e = 1. / self._current_values[param] value = 1. / (i_over_e + 1) else: value = self._current_values[param] if 'conversion' in self._config[param]: value = value * self._config[param]['conversion'] if self._debug: print('Converting value for', param, 'from', value / self._config[param].get('conversion', 1.), 'to', value) if self._debug: print('Setting value of', param, ':', value) # Update the value in the config file self._config[param]['current'] = self._current_values[param] # Set color to red until we know the value has been set. btn.setStyleSheet("color: red") esp_param_name = self._config['esp_settable_param'][param] # Finally, try to set the value to the ESP # Raise an error message if this fails. try: if self._data_h.set_data(esp_param_name, value): # Now set the color to green, as we know it has been set btn.setStyleSheet("color: green") except Exception as error: msg = MessageBox() msg.critical( "Critical", "Severe Hardware Communication Error", str(error), "Communication error", { msg.Retry: lambda: self.send_values_to_hardware, msg.Abort: lambda: sys.exit(-1) })() if param == 'respiratory_rate': self.toolsettings_lookup["respiratory_rate"].update(value) elif param == 'insp_expir_ratio': self.toolsettings_lookup["insp_expir_ratio"].update( self._current_values[param]) elif param == 'insp_pressure': self.toolsettings_lookup["insp_pressure"].update(value) settings_file = SettingsFile(self._config["settings_file_path"]) settings_file.store(settings_to_file)