def changeEvent(self, event): # This minimizes the program to tray when Minimize button pressed if event.type() == QEvent.WindowStateChange: if self.windowState() & Qt.WindowMinimized: print(QSystemTrayIcon.isSystemTrayAvailable()) if QSystemTrayIcon.isSystemTrayAvailable( ) and self.isActiveWindow(): event.ignore() self.tray.show() self.hide() self.listener = keyboard.Listener( on_release=self.on_release) self.listener.start()
def availableMethods(cls) -> Dict[int, str]: out = { cls.METHOD_STUB: "Disabled", cls.METHOD_TOOLTIP: "Cursor tooltip", } if (QSystemTrayIcon.isSystemTrayAvailable() and QSystemTrayIcon.supportsMessages()): out[cls.METHOD_NOTIFICATION] = "Notification" return out
def __init__(self): super().__init__() self.settings = QSettings(self) type_ = int( self.settings.value("settings/tooltip", self.METHOD_NOTIFICATION)) if (QSystemTrayIcon.isSystemTrayAvailable() and QSystemTrayIcon.supportsMessages() and type_ == self.METHOD_NOTIFICATION): self.notifier = TrayIconNotifier() elif type_ == self.METHOD_TOOLTIP: self.notifier = TooltipNotifier() else: self.notifier = StubNotifier()
def start(self) -> None: if not QSystemTrayIcon.isSystemTrayAvailable(): QMessageBox.critical(None, SYSTEM_TRAY_APP_NAME, 'System tray is not available.') sys.exit(1) if not QSystemTrayIcon.supportsMessages(): QMessageBox.warning( None, SYSTEM_TRAY_APP_NAME, 'The system tray does not support notification ' '("balloon") messages.') self._tray_icon.show()
def _trayIconCreate(self, icon): if QSystemTrayIcon.isSystemTrayAvailable(): self.__isTrayIcon = True trayIconMenu = QMenu(self.parent) trayIconMenu.addAction(self.minimizeAction) trayIconMenu.addAction(self.maximizeAction) trayIconMenu.addAction(self.restoreAction) trayIconMenu.addSeparator() trayIconMenu.addAction(self.closeAction) trayIconMenu.addSeparator() trayIconMenu.addAction(self.abortAction) if platform.system() == "Windows": style = QtWidgets.QStyleFactory.create("windowsvista") trayIconMenu.setStyle(style) self.setContextMenu(trayIconMenu) self.setIcon(icon)
def __init__(self, parent, icon, seconds=5): super().__init__(parent) self.__isTrayIcon = False if QSystemTrayIcon.isSystemTrayAvailable(): self.__isTrayIcon = True self.parent = parent self.icon = icon self.__seconds = seconds self.minimizeAction = QAction() self.maximizeAction = QAction() self.restoreAction = QAction() self.quitAction = QAction() self._trayIconActionsCreate() self._trayIconCreate(icon) self.setToolTip(config.APPNAME) self.setToolTipSignal.connect(self.setToolTip) self.activated.connect(self.iconActivated)
class MainWindow(QObject): def __init__(self, parent=None): """Main window, holding all user interface including. Args: parent: parent class of main window Returns: None Raises: None """ super(MainWindow, self).__init__() self._window = None self._old_pos = None self._tray = QSystemTrayIcon(self._window) if self._tray.isSystemTrayAvailable(): self._tray.setIcon(QIcon('./media/dekban.png')) else: self._tray = None self.setup_ui() @property def window(self): """The main window object""" return self._window def setup_ui(self): loader = QUiLoader() file = QFile('./main_window.ui') file.open(QFile.ReadOnly) self._window = loader.load(file) file.close() self._window.setWindowFlags(Qt.Window | Qt.FramelessWindowHint) self._window.installEventFilter(self) self.center() self._old_pos = self._window.pos() self.set_title() self.set_buttons() self.set_edits() self.set_icon_combo() self.set_tray() self._tray.show() def set_title(self): """Setup label""" self._window.title.setText('Welcome to PySide2 Tutorial') font = QFont("Arial", 20, QFont.Black) self._window.title.setFont(font) # set widget size (x, y, width, height) self._window.title.setGeometry(0, 0, 600, 30) # set alignment self._window.title.setAlignment(Qt.AlignBottom | Qt.AlignCenter) def set_buttons(self): """Setup buttons""" self._window.send_btn.setText('Send Msg') self._window.exit_btn.setText('Exit') self._window.send_btn.setIcon(QIcon('./media/import.svg')) self._window.send_btn.clicked.connect(self.send_message) self._window.exit_btn.clicked.connect(self.exit) def set_edits(self): """Setup line edit and text edit""" self._window.title_line.setPlaceholderText('Input Msg Title') self._window.msg_edit.setPlaceholderText('Input Msg') def set_icon_combo(self): """Setup options in icon select combobox.""" self._window.icon_combo.addItem(QIcon('./media/font.png'), 'font') self._window.icon_combo.addItem(QIcon('./media/paint.png'), 'paint') self._window.icon_combo.addItem(QIcon('./media/dekban.png'), 'default') self._window.icon_combo.currentIndexChanged.connect(self.set_icon) def set_tray(self): menu = QMenu(self._window) action_show = menu.addAction("Show/Hide") action_show.triggered.connect( lambda: self._window.hide() if self._window.isVisible() else self._window.show()) action_quit = menu.addAction("Quit") action_quit.triggered.connect(self._window.close) self._tray.setContextMenu(menu) def eventFilter(self, obj, event): if obj is self._window: if event.type() == QtCore.QEvent.MouseButtonPress: self.mouse_press_event(event) elif event.type() == QtCore.QEvent.MouseMove: self.mouse_move_event(event) return super(MainWindow, self).eventFilter(obj, event) def center(self): qr = self._window.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self._window.move(qr.topLeft()) def mouse_press_event(self, event): self._old_pos = event.globalPos() def mouse_move_event(self, event): delta_x = int(event.globalPos().x()) - self._old_pos.x() delta_y = int(event.globalPos().y()) - self._old_pos.y() self._window.move(self._window.x() + delta_x, self._window.y() + delta_y) self._old_pos = event.globalPos() @QtCore.Slot(int) def set_icon(self, index): icon = self._window.icon_combo.itemIcon(index) self._tray.setIcon(icon) @QtCore.Slot() def send_message(self): title = self._window.title_line.text() msg = self._window.msg_edit.toPlainText() self._tray.showMessage(title, msg, QIcon('./media/dekban.png')) @QtCore.Slot() def exit(self): self._window.close()
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ## ## $QT_END_LICENSE$ ## ############################################################################# import sys from PySide2.QtWidgets import QApplication, QMessageBox, QSystemTrayIcon from window import Window if __name__ == "__main__": app = QApplication() if not QSystemTrayIcon.isSystemTrayAvailable(): QMessageBox.critical( None, "Systray", "I couldn't detect any system tray on this system.") sys.exit(1) QApplication.setQuitOnLastWindowClosed(False) window = Window() window.show() sys.exit(app.exec_())
def __init__(self): if (QSystemTrayIcon.isSystemTrayAvailable() and QSystemTrayIcon.supportsMessages()): self.notifier = TrayIconNotifier() else: self.notifier = TooltipNotifier()
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self): super(MainWindow, self).__init__() self.green_color = None self.yellow_color = None self.red_color = None self.tray = QSystemTrayIcon(self) self.connected_port = None self.config_filename = None self.base_output_filename = None self.output_hex_filename = None self.output_binary_filename = None self.port_read_thread = PortReadThread(self.read_port, self.stop_read) self.log = Logger().create_log() self.log.info("Launched MinXSS Beacon Decoder.") self.setup_ui() self.connect_ui_to_functions() self.setup_output_files() QApplication.instance().aboutToQuit.connect(self.prepare_to_exit) self.show() def setup_ui(self): self.setupUi(self) self.setup_colors() self.setup_tray_icon() self.setup_available_ports() self.setup_last_used_settings() def setup_colors(self): green = QColor(55, 195, 58) palette_green = QtGui.QPalette() palette_green.setColor(QtGui.QPalette.Text, green) palette_green.setColor(QtGui.QPalette.Foreground, green) self.green_color = palette_green yellow = QColor(244, 212, 66) palette_yellow = QtGui.QPalette() palette_yellow.setColor(QtGui.QPalette.Text, yellow) palette_yellow.setColor(QtGui.QPalette.Foreground, yellow) self.yellow_color = palette_yellow red = QColor(242, 86, 77) palette_red = QtGui.QPalette() palette_red.setColor(QtGui.QPalette.Text, red) palette_red.setColor(QtGui.QPalette.Foreground, red) self.red_color = palette_red def setup_tray_icon(self): if self.tray.isSystemTrayAvailable(): self.tray.setIcon(QIcon('assets/icon_256.png')) menu = QMenu() action_quit = menu.addAction("Quit") action_quit.triggered.connect(self.close) self.tray.setContextMenu(menu) self.tray.show() else: self.tray = None def setup_available_ports(self): """ Determine what ports are available for serial reading and populate the combo box with these options """ self.comboBox_serialPort.clear() list_port_info_objects = list_ports.comports() port_names = [x[0] for x in list_port_info_objects] self.comboBox_serialPort.addItems(port_names) def connect_ui_to_functions(self): self.actionConnect.triggered.connect(self.connect_clicked) self.checkBox_saveData.stateChanged.connect(self.save_data_toggled) self.checkBox_forwardData.stateChanged.connect(self.forward_data_toggled) self.checkBox_decodeKiss.stateChanged.connect(self.decode_kiss_toggled) self.lineEdit_callsign.editingFinished.connect(self.ground_station_config_changed) self.lineEdit_latitude.editingFinished.connect(self.ground_station_config_changed) self.lineEdit_longitude.editingFinished.connect(self.ground_station_config_changed) self.actionCompletePass.triggered.connect(self.complete_pass_clicked) def ground_station_config_changed(self): self.setup_output_files() self.write_gui_config_options_to_config_file() def setup_output_files(self): self.set_base_output_filename() self.setup_output_file_decoded_data_as_hex() self.setup_output_file_decoded_data_as_binary() def set_base_output_filename(self): callsign = self.lineEdit_callsign.text() latitude = self.lineEdit_latitude.text() longitude = self.lineEdit_longitude.text() self.base_output_filename = os.path.join(os.path.expanduser("~"), "MinXSS_Beacon_Decoder", "output", datetime.datetime.utcnow().isoformat().replace(':', '_')) + '_' + callsign + '_' + latitude + '_' + longitude def setup_output_file_decoded_data_as_hex(self): self.ensure_output_folder_exists() self.set_output_hex_filename() with open(self.output_hex_filename, 'w') as output_hex_file: self.log.info("Opening new .txt file to output decoded data as hex.") self.display_gui_output_hex_is_saving() output_hex_file.close() # Will later append to file as needed @staticmethod def ensure_output_folder_exists(): if not os.path.exists(os.path.join(os.path.expanduser("~"), "MinXSS_Beacon_Decoder", "output")): os.makedirs(os.path.join(os.path.expanduser("~"), "MinXSS_Beacon_Decoder", "output")) def set_output_hex_filename(self): self.output_hex_filename = self.base_output_filename + ".txt" def display_gui_output_hex_is_saving(self): self.textBrowser_savingDataToFile.setText("Saving data to files: {} and .dat.".format(self.output_hex_filename)) self.textBrowser_savingDataToFile.setPalette(self.green_color) def setup_output_file_decoded_data_as_binary(self): self.ensure_output_folder_exists() self.set_output_binary_filename() with open(self.output_binary_filename, 'w') as buffer_output_binary_file: self.log.info("Opening new binary file to output decoded data.") buffer_output_binary_file.close() def set_output_binary_filename(self): self.output_binary_filename = self.base_output_filename + ".dat" def write_gui_config_options_to_config_file(self): config = configparser.ConfigParser() config.read(self.config_filename) config.set('input_properties', 'serial_port', self.comboBox_serialPort.currentText()) config.set('input_properties', 'baud_rate', self.lineEdit_baudRate.text()) config.set('input_properties', 'ip_address', self.lineEdit_ipAddress.text()) config.set('input_properties', 'port', self.lineEdit_ipPort.text()) config.set('input_properties', 'decode_kiss', str(self.checkBox_decodeKiss.isChecked())) config.set('input_properties', 'forward_data', str(self.checkBox_forwardData.isChecked())) config.set('input_properties', 'callsign', self.lineEdit_callsign.text()) config.set('input_properties', 'latitude', self.lineEdit_latitude.text()) config.set('input_properties', 'longitude', self.lineEdit_longitude.text()) with open(os.path.join(os.path.expanduser("~"), "MinXSS_Beacon_Decoder", "input_properties.cfg"), 'w') as configfile: config.write(configfile) self.log.info('Updated input_properties.cfg file with new settings.') def setup_last_used_settings(self): config = configparser.ConfigParser() self.config_filename = os.path.join(os.path.expanduser("~"), "MinXSS_Beacon_Decoder", "input_properties.cfg") if self.need_new_config_file(config): self.log.info('No input_properties.cfg file found. Creating the default one.') self.write_default_config() config.read(self.config_filename) self.set_instance_variables_from_config(config) def need_new_config_file(self, config): if not os.path.isfile(self.config_filename): return True if os.stat(self.config_filename).st_size == 0: return True try: config.read(self.config_filename) except configparser.MissingSectionHeaderError: return True if not config.has_option('input_properties', 'serial_port'): return True if not config.has_option('input_properties', 'baud_rate'): return True if not config.has_option('input_properties', 'ip_address'): return True if not config.has_option('input_properties', 'port'): return True if not config.has_option('input_properties', 'decode_kiss'): return True if not config.has_option('input_properties', 'forward_data'): return True if not config.has_option('input_properties', 'callsign'): return True if not config.has_option('input_properties', 'latitude'): return True if not config.has_option('input_properties', 'longitude'): return True def write_default_config(self): with open(self.config_filename, "w") as config_file: print("[input_properties]", file=config_file) print("serial_port = 3", file=config_file) print("baud_rate = 19200", file=config_file) print("ip_address = localhost", file=config_file) print("port = 10000", file=config_file) print("decode_kiss = True", file=config_file) print("forward_data = True", file=config_file) print("callsign = SFJPM86", file=config_file) print("latitude = 40.240", file=config_file) print("longitude = -105.2353", file=config_file) def set_instance_variables_from_config(self, config): self.tabWidget_serialIp.setCurrentIndex(1) # TODO: Make this an actual config parameter self.comboBox_serialPort.insertItem(0, config.get('input_properties', 'serial_port')) self.comboBox_serialPort.setCurrentIndex(0) self.lineEdit_baudRate.setText(config.get('input_properties', 'baud_rate')) self.lineEdit_ipAddress.setText(config.get('input_properties', 'ip_address')) self.lineEdit_ipPort.setText(config.get('input_properties', 'port')) self.lineEdit_callsign.setText(config.get('input_properties', 'callsign')) self.lineEdit_latitude.setText(config.get('input_properties', 'latitude')) self.lineEdit_longitude.setText(config.get('input_properties', 'longitude')) self.checkBox_decodeKiss.setChecked(self.str2bool(config.get('input_properties', 'decode_kiss'))) self.checkBox_forwardData.setChecked(self.str2bool(config.get('input_properties', 'forward_data'))) # Intentionally don't do saveData -- always defaults to on to avoid frustration of lost data @staticmethod def str2bool(bool_string): if bool_string == 'True': return True if bool_string == 'False': return False raise ValueError('Can only accept exact strings "True" or "False". Was passed {}'.format(bool_string)) def connect_clicked(self): self.write_gui_config_options_to_config_file() connect_button_text = str(self.actionConnect.iconText()) if connect_button_text == "Connect": self.connect_to_port() else: self.disconnect_from_port() def connect_to_port(self): self.log.info("Attempting to connect to port.") self.toggle_connect_button(is_currently_connect=True) if self.user_chose_serial_port(): self.connected_port, port_readable = self.connect_to_serial_port() else: # user chose TCP/IP socket self.connected_port, port_readable = self.connect_to_socket_port() if port_readable: self.port_read_thread.start() self.display_gui_reading() else: self.display_gui_read_failed() def toggle_connect_button(self, is_currently_connect): if is_currently_connect: connect_button_text = 'Disconnect' else: connect_button_text = 'Connect' self.actionConnect.setText(QApplication.translate("MainWindow", connect_button_text, None, -1)) def user_chose_serial_port(self): if self.tabWidget_serialIp.currentIndex() == self.tabWidget_serialIp.indexOf(self.serial): return True else: return False # implying user chose TCP/IP socket def connect_to_serial_port(self): port = self.comboBox_serialPort.currentText() baud_rate = self.lineEdit_baudRate.text() connect_serial = connect_port_get_packet.ConnectSerial(port, baud_rate, self.log) connected_port = connect_serial.connect_to_port() port_readable = connected_port.port_readable return connected_port, port_readable def connect_to_socket_port(self): ip_address = self.lineEdit_ipAddress.text() port = self.lineEdit_ipPort.text() connect_socket = connect_port_get_packet.ConnectSocket(ip_address, port) connected_port = connect_socket.connect_to_port() port_readable = connect_socket.port_readable return connected_port, port_readable def display_gui_reading(self): reading = QApplication.translate("MainWindow", "Reading", None, -1) if self.user_chose_serial_port(): self.label_serialStatus.setText(reading) self.label_serialStatus.setPalette(self.green_color) else: self.label_socketStatus.setText(reading) self.label_socketStatus.setPalette(self.green_color) def display_gui_read_failed(self): read_failed = QApplication.translate("MainWindow", "Read failed", None, -1) if self.user_chose_serial_port: self.label_serialStatus.setText(read_failed) self.label_serialStatus.setPalette(self.red_color) else: self.label_socketStatus.setText(read_failed) self.label_socketStatus.setPalette(self.red_color) def disconnect_from_port(self): self.log.info("Attempting to disconnect from port.") self.toggle_connect_button(is_currently_connect=False) self.display_gui_port_closed() self.stop_read() def display_gui_port_closed(self): port_closed = QApplication.translate("MainWindow", "Port closed", None, -1) if self.user_chose_serial_port(): self.label_serialStatus.setText(port_closed) self.label_serialStatus.setPalette(self.red_color) else: self.label_socketStatus.setText(port_closed) self.label_socketStatus.setPalette(self.red_color) def complete_pass_clicked(self): self.upload_data() def upload_data(self): if self.do_forward_data(): self.display_gui_uploading() file_upload.upload(self.output_binary_filename) self.display_gui_upload_complete() def do_forward_data(self): return self.checkBox_forwardData.isChecked() def display_gui_uploading(self): self.label_uploadStatus.setText("Upload status: Uploading") def display_gui_upload_complete(self): self.label_uploadStatus.setText("Upload status: Complete") def read_port(self): while True: buffer_data = self.connected_port.read_packet() if len(buffer_data) == 0: continue buffer_data = self.decode_kiss(buffer_data) buffer_data_hex_string = self.convert_buffer_data_to_hex_string(buffer_data) self.display_gui_hex(buffer_data_hex_string) self.save_data_to_disk(buffer_data_hex_string, buffer_data) minxss_parser = MinxssParser(buffer_data) telemetry = minxss_parser.parse_packet() self.display_gui_telemetry(telemetry) def decode_kiss(self, buffer_data): if self.do_decode_kiss(): # C0 is a special KISS character that get replaced; unreplace it buffer_data = buffer_data.replace(bytearray([0xdb, 0xdc]), bytearray([0xc0])) # DB is a special KISS character that get replaced; unreplace it buffer_data = buffer_data.replace(bytearray([0xdb, 0xdd]), bytearray([0xdb])) return buffer_data def do_decode_kiss(self): return self.checkBox_decodeKiss.isChecked() @staticmethod def convert_buffer_data_to_hex_string(buffer_data): return ' '.join('0x{:02x}'.format(x) for x in buffer_data) def display_gui_hex(self, buffer_data_hex_string): self.textBrowser_serialOutput.append(buffer_data_hex_string) scroll_to_bottom = self.textBrowser_serialOutput.verticalScrollBar().maximum() self.textBrowser_serialOutput.verticalScrollBar().setValue(scroll_to_bottom) def save_data_to_disk(self, buffer_data_hex_string, buffer_data): if self.do_save_data(): output_hex_file = open(self.output_hex_filename, 'a') output_hex_file.write(buffer_data_hex_string) output_hex_file.close() output_binary_file = open(self.output_binary_filename, 'ab') output_binary_file.write(buffer_data) output_binary_file.close() def do_save_data(self): return self.checkBox_saveData.isChecked() def display_gui_telemetry(self, telemetry): if not telemetry: return self.label_lastPacketTime.setText( "Last packet at: {} local / {} UTC".format(self.get_local_time(), self.get_utc_time())) self.display_gui_telemetry_spacecraft_state(telemetry) self.display_gui_telemetry_solar_data(telemetry) self.display_gui_telemetry_power(telemetry) self.display_gui_telemetry_temperature(telemetry) self.label_spacecraftMode.setPalette(self.green_color) self.color_code_telemetry(telemetry) @staticmethod def get_local_time(): local_time = datetime.datetime.now().replace(microsecond=0).isoformat(' ') return local_time @staticmethod def get_utc_time(): utc_time = datetime.datetime.utcnow().replace(microsecond=0).isoformat(' ') return utc_time def display_gui_telemetry_spacecraft_state(self, telemetry): self.label_flightModel.setText("{0:0=1d}".format(telemetry['FlightModel'])) self.label_commandAcceptCount.setText("{0:0=1d}".format(telemetry['CommandAcceptCount'])) if telemetry['SpacecraftMode'] == 0: self.label_spacecraftMode.setText("Unknown") elif telemetry['SpacecraftMode'] == 1: self.label_spacecraftMode.setText("Phoenix") elif telemetry['SpacecraftMode'] == 2: self.label_spacecraftMode.setText("Safe") elif telemetry['SpacecraftMode'] == 4: self.label_spacecraftMode.setText("Science") if telemetry['PointingMode'] == 0: self.label_pointingMode.setText("Coarse Point") elif telemetry['PointingMode'] == 1: self.label_pointingMode.setText("Fine Point") if telemetry['EnableX123'] == 1: self.label_enableX123.setText("Yes") else: self.label_enableX123.setText("No") if telemetry['EnableSps'] == 1: self.label_enableSps.setText("Yes") else: self.label_enableSps.setText("No") if telemetry['Eclipse'] == 1: self.label_eclipse.setText("Eclipse") else: self.label_eclipse.setText("In Sun") def display_gui_telemetry_solar_data(self, telemetry): self.label_spsX.setText("{0:.2f}".format(round(telemetry['SpsX'], 2))) self.label_spsY.setText("{0:.2f}".format(round(telemetry['SpsY'], 2))) self.label_xp.setText("{0:.2f}".format(round(telemetry['Xp'], 2))) def display_gui_telemetry_power(self, telemetry): self.label_batteryVoltage.setText("{0:.2f}".format(round(telemetry['BatteryVoltage'], 2))) battery_current = self.get_battery_current(telemetry) self.label_batteryCurrent.setText("{0:.2f}".format(round(battery_current, 2))) solar_panel_minus_y_power = telemetry['SolarPanelMinusYVoltage'] * telemetry['SolarPanelMinusYCurrent'] / 1e3 solar_panel_plus_x_power = telemetry['SolarPanelPlusXVoltage'] * telemetry['SolarPanelPlusXCurrent'] / 1e3 solar_panel_plus_y_power = telemetry['SolarPanelPlusYVoltage'] * telemetry['SolarPanelPlusYCurrent'] / 1e3 self.label_solarPanelMinusYPower.setText("{0:.2f}".format(round(solar_panel_minus_y_power, 2))) self.label_solarPanelPlusXPower.setText("{0:.2f}".format(round(solar_panel_plus_x_power, 2))) self.label_solarPanelPlusYPower.setText("{0:.2f}".format(round(solar_panel_plus_y_power, 2))) def get_battery_current(self, telemetry): if telemetry['BatteryChargeCurrent'] > telemetry['BatteryDischargeCurrent']: battery_current = telemetry['BatteryChargeCurrent'] / 1e3 self.label_batteryCurrentText.setText("Battery Charge Current") else: battery_current = telemetry['BatteryDischargeCurrent'] / 1e3 self.label_batteryCurrentText.setText("Battery Discharge Current") return battery_current def display_gui_telemetry_temperature(self, telemetry): self.label_commBoardTemperature.setText("{0:.2f}".format(round(telemetry['CommBoardTemperature'], 2))) self.label_batteryTemperature.setText("{0:.2f}".format(round(telemetry['BatteryTemperature'], 2))) self.label_epsBoardTemperature.setText("{0:.2f}".format(round(telemetry['EpsBoardTemperature'], 2))) self.label_cdhTemperature.setText("{0:.2f}".format(round(telemetry['CdhBoardTemperature'], 2))) self.label_motherboardTemperature.setText("{0:.2f}".format(round(telemetry['MotherboardTemperature'], 2))) self.label_solarPanelMinusYTemperature.setText("{0:.2f}".format(round(telemetry['SolarPanelMinusYTemperature'], 2))) self.label_solarPanelPlusXTemperature.setText("{0:.2f}".format(round(telemetry['SolarPanelPlusXTemperature'], 2))) self.label_solarPanelPlusYTemperature.setText("{0:.2f}".format(round(telemetry['SolarPanelPlusYTemperature'], 2))) def color_code_telemetry(self, telemetry): self.color_code_spacecraft_state(telemetry) self.color_code_solar_data(telemetry) self.color_code_power(telemetry) self.color_code_temperature(telemetry) def color_code_spacecraft_state(self, telemetry): if telemetry['SpacecraftMode'] == 0: self.label_spacecraftMode.setPalette(self.red_color) elif telemetry['SpacecraftMode'] == 1: self.label_spacecraftMode.setPalette(self.red_color) elif telemetry['SpacecraftMode'] == 2: self.label_spacecraftMode.setPalette(self.yellow_color) elif telemetry['SpacecraftMode'] == 4: self.label_spacecraftMode.setPalette(self.green_color) if telemetry['PointingMode'] == 0: self.label_pointingMode.setPalette(self.yellow_color) elif telemetry['PointingMode'] == 1: self.label_pointingMode.setPalette(self.green_color) def color_code_solar_data(self, telemetry): if abs(telemetry['SpsX']) <= 3.0: self.label_spsX.setPalette(self.green_color) else: self.label_spsX.setPalette(self.red_color) if abs(telemetry['SpsY']) <= 3.0: self.label_spsY.setPalette(self.green_color) else: self.label_spsY.setPalette(self.red_color) if 0 <= telemetry['Xp'] <= 24860.0: self.label_xp.setPalette(self.green_color) else: self.label_xp.setPalette(self.red_color) def color_code_power(self, telemetry): solar_panel_minus_y_power = telemetry['SolarPanelMinusYVoltage'] * telemetry['SolarPanelMinusYCurrent'] / 1e3 solar_panel_plus_x_power = telemetry['SolarPanelPlusXVoltage'] * telemetry['SolarPanelPlusXCurrent'] / 1e3 solar_panel_plus_y_power = telemetry['SolarPanelPlusYVoltage'] * telemetry['SolarPanelPlusYCurrent'] / 1e3 battery_current = self.get_battery_current(telemetry) if -1.0 <= solar_panel_minus_y_power <= 10.4: self.label_solarPanelMinusYPower.setPalette(self.green_color) else: self.label_solarPanelMinusYPower.setPalette(self.red_color) if -1.0 <= solar_panel_plus_x_power <= 5.9: self.label_solarPanelPlusXPower.setPalette(self.green_color) else: self.label_solarPanelPlusXPower.setPalette(self.red_color) if -1.0 <= solar_panel_plus_y_power <= 10.4: self.label_solarPanelPlusYPower.setPalette(self.green_color) else: self.label_solarPanelPlusYPower.setPalette(self.red_color) if telemetry['BatteryVoltage'] >= 7.2: self.label_batteryVoltage.setPalette(self.green_color) elif telemetry['BatteryVoltage'] >= 6.6: self.label_batteryVoltage.setPalette(self.yellow_color) else: self.label_batteryVoltage.setPalette(self.red_color) if 0 <= battery_current <= 2.9: self.label_batteryCurrent.setPalette(self.green_color) else: self.label_batteryCurrent.setPalette(self.red_color) def color_code_temperature(self, telemetry): if -8.0 <= telemetry['CommBoardTemperature'] <= 60.0: self.label_commBoardTemperature.setPalette(self.green_color) else: self.label_commBoardTemperature.setPalette(self.red_color) if 5.0 <= telemetry['BatteryTemperature'] <= 25: self.label_batteryTemperature.setPalette(self.green_color) elif 2.0 <= telemetry['BatteryTemperature'] < 5.0 or telemetry['BatteryTemperature'] > 25.0: self.label_batteryTemperature.setPalette(self.yellow_color) else: self.label_batteryTemperature.setPalette(self.red_color) if -8.0 <= telemetry['EpsBoardTemperature'] <= 45.0: self.label_epsBoardTemperature.setPalette(self.green_color) else: self.label_epsBoardTemperature.setPalette(self.red_color) if -8.0 <= telemetry['CdhBoardTemperature'] <= 29.0: self.label_cdhTemperature.setPalette(self.green_color) else: self.label_cdhTemperature.setPalette(self.red_color) if -13.0 <= telemetry['MotherboardTemperature'] <= 28.0: self.label_motherboardTemperature.setPalette(self.green_color) else: self.label_motherboardTemperature.setPalette(self.red_color) if -75.0 <= telemetry['SolarPanelMinusYTemperature'] <= 85.0: self.label_solarPanelMinusYTemperature.setPalette(self.green_color) else: self.label_solarPanelMinusYTemperature.setPalette(self.red_color) if -75.0 <= telemetry['SolarPanelPlusXTemperature'] <= 85.0: self.label_solarPanelPlusXTemperature.setPalette(self.green_color) else: self.label_solarPanelPlusXTemperature.setPalette(self.red_color) if -75.0 <= telemetry['SolarPanelPlusYTemperature'] <= 85.0: self.label_solarPanelPlusYTemperature.setPalette(self.green_color) else: self.label_solarPanelPlusYTemperature.setPalette(self.red_color) def stop_read(self): self.connected_port.close() def save_data_toggled(self): if self.do_save_data(): self.setup_output_files() else: self.display_gui_no_output_data() def display_gui_no_output_data(self): self.textBrowser_savingDataToFile.setText("Not saving data to file.") self.textBrowser_savingDataToFile.setPalette(self.red_color) def forward_data_toggled(self): if self.do_forward_data(): self.display_gui_upload_idle() else: self.display_gui_upload_disabled() self.write_gui_config_options_to_config_file() def display_gui_upload_idle(self): self.label_uploadStatus.setText("Upload status: Idle") def display_gui_upload_disabled(self): self.label_uploadStatus.setText("Upload status: Disabled") def decode_kiss_toggled(self): self.write_gui_config_options_to_config_file() def prepare_to_exit(self): self.log.info("About to quit.") self.upload_data() # Only occurs if forward data is toggled on self.log.info("Closing MinXSS Beacon Decoder.")