diff --git a/horusgui/__init__.py b/horusgui/__init__.py index 771bc6e..aa4cd15 100755 --- a/horusgui/__init__.py +++ b/horusgui/__init__.py @@ -1 +1 @@ -__version__ = "0.3.9" +__version__ = "0.3.10" diff --git a/horusgui/config.py b/horusgui/config.py index 6b93c19..d127912 100644 --- a/horusgui/config.py +++ b/horusgui/config.py @@ -35,6 +35,9 @@ default_config = { "rotator_type": "rotctld", "rotator_host": "localhost", "rotator_port": 4533, + "logging_enabled": False, + "log_format": "CSV", + "log_directory": "", "payload_list": json.dumps(horusdemodlib.payloads.HORUS_PAYLOAD_LIST), "custom_field_list": json.dumps({}) } @@ -73,7 +76,7 @@ def read_config(widgets): """ Read in configuration settings from Qt """ global qt_settings, default_config - OK_VERSIONS = [__version__, '0.3.8', '0.3.7', '0.3.6', '0.3.5', '0.3.4', '0.3.1', '0.2.1'] + OK_VERSIONS = [__version__, '0.3.9', '0.3.8', '0.3.7', '0.3.6', '0.3.5', '0.3.4', '0.3.1', '0.2.1'] # Try and read in the version parameter from QSettings if qt_settings.value("version") not in OK_VERSIONS: @@ -83,14 +86,14 @@ def read_config(widgets): for _setting in default_config: try: _new_setting = qt_settings.value(_setting) - if _new_setting: + if _new_setting is not None: default_config[_setting] = _new_setting except Exception as e: logging.debug("Missing config setting: " + _setting) if widgets: # Habitat Settings - widgets["habitatUploadSelector"].setChecked(ValueToBool(default_config["habitat_upload_enabled"])) + widgets["sondehubUploadSelector"].setChecked(ValueToBool(default_config["habitat_upload_enabled"])) widgets["userCallEntry"].setText(str(default_config["habitat_call"])) widgets["userLatEntry"].setText(str(default_config["habitat_lat"])) widgets["userLonEntry"].setText(str(default_config["habitat_lon"])) @@ -122,6 +125,11 @@ def read_config(widgets): widgets["rotatorHostEntry"].setText(str(default_config["rotator_host"])) widgets["rotatorPortEntry"].setText(str(default_config["rotator_port"])) + # Logging Settings + widgets["loggingPathEntry"].setText(str(default_config["log_directory"])) + widgets["loggingFormatSelector"].setCurrentText(default_config["log_format"]) + widgets["enableLoggingSelector"].setChecked(ValueToBool(default_config["logging_enabled"])) + if default_config['baud_rate'] != -1: widgets["horusModemRateSelector"].setCurrentText(str(default_config['baud_rate'])) @@ -145,8 +153,9 @@ def save_config(widgets): if widgets: default_config["habitat_upload_enabled"] = widgets[ - "habitatUploadSelector" + "sondehubUploadSelector" ].isChecked() + default_config["version"] = __version__ default_config["habitat_call"] = widgets["userCallEntry"].text() default_config["habitat_lat"] = float(widgets["userLatEntry"].text()) default_config["habitat_lon"] = float(widgets["userLonEntry"].text()) @@ -164,6 +173,9 @@ def save_config(widgets): default_config["rotator_type"] = widgets["rotatorTypeSelector"].currentText() default_config["rotator_host"] = widgets["rotatorHostEntry"].text() default_config["rotator_port"] = int(widgets["rotatorPortEntry"].text()) + default_config["logging_enabled"] = widgets["enableLoggingSelector"].isChecked() + default_config["log_directory"] = widgets["loggingPathEntry"].text() + default_config["log_format"] = widgets["loggingFormatSelector"].currentText() default_config["payload_list"] = json.dumps(horusdemodlib.payloads.HORUS_PAYLOAD_LIST) default_config["custom_field_list"] = json.dumps(horusdemodlib.payloads.HORUS_CUSTOM_FIELDS) diff --git a/horusgui/gui.py b/horusgui/gui.py index a8ee963..6802476 100644 --- a/horusgui/gui.py +++ b/horusgui/gui.py @@ -31,10 +31,10 @@ from .udpaudio import * from .fft import * from .modem import * from .config import * -from .habitat import * from .utils import position_info from .icon import getHorusIcon from .rotators import ROTCTLD, PSTRotator +from .telemlogger import TelemetryLogger from horusdemodlib.demod import HorusLib, Mode from horusdemodlib.decoder import decode_packet, parse_ukhas_string from horusdemodlib.payloads import * @@ -63,8 +63,8 @@ audio_devices = {} audio_stream = None fft_process = None horus_modem = None -habitat_uploader = None sondehub_uploader = None +telemetry_logger = None decoder_init = False @@ -112,7 +112,7 @@ win.setWindowIcon(getHorusIcon()) # Create multiple dock areas, for displaying our data. d0 = Dock("Audio", size=(300, 50)) d0_modem = Dock("Modem", size=(300, 80)) -d0_habitat = Dock("Habitat", size=(300, 200)) +d0_habitat = Dock("SondeHub", size=(300, 200)) d0_other = Dock("Other", size=(300, 100)) d0_rotator = Dock("Rotator", size=(300, 100)) d1 = Dock("Spectrum", size=(800, 350)) @@ -213,10 +213,7 @@ d0_modem.addWidget(w1_modem) w1_habitat = pg.LayoutWidget() # Listener Information -widgets["habitatHeading"] = QtGui.QLabel("Habitat Settings") -widgets["habitatUploadLabel"] = QtGui.QLabel("Enable Habitat Upload:") -widgets["habitatUploadSelector"] = QtGui.QCheckBox() -widgets["habitatUploadSelector"].setChecked(True) +widgets["habitatHeading"] = QtGui.QLabel("SondeHub Settings") widgets["sondehubUploadLabel"] = QtGui.QLabel("Enable SondeHub-Ham Upload:") widgets["sondehubUploadSelector"] = QtGui.QCheckBox() widgets["sondehubUploadSelector"].setChecked(True) @@ -246,7 +243,7 @@ widgets["userRadioEntry"].setToolTip( ) widgets["habitatUploadPosition"] = QtGui.QPushButton("Re-upload Position") widgets["habitatUploadPosition"].setToolTip( - "Manually re-upload your position information to HabHub and SondeHub.\n"\ + "Manually re-upload your position information to SondeHub-Amateur.\n"\ "Note that it can take a few minutes for your new information to\n"\ "appear on the map." ) @@ -254,31 +251,29 @@ widgets["dialFreqLabel"] = QtGui.QLabel("Radio Dial Freq (MHz):") widgets["dialFreqEntry"] = QtGui.QLineEdit("") widgets["dialFreqEntry"].setToolTip( "Optional entry of your radio's dial frequency in MHz.\n"\ - "Used to provide frequency information on Habitat & SondeHub."\ + "Used to provide frequency information on SondeHub-Amateur."\ ) widgets["saveSettingsButton"] = QtGui.QPushButton("Save Settings") -w1_habitat.addWidget(widgets["habitatUploadLabel"], 0, 0, 1, 1) -w1_habitat.addWidget(widgets["habitatUploadSelector"], 0, 1, 1, 1) -w1_habitat.addWidget(widgets["sondehubUploadLabel"], 1, 0, 1, 1) -w1_habitat.addWidget(widgets["sondehubUploadSelector"], 1, 1, 1, 1) -w1_habitat.addWidget(widgets["userCallLabel"], 2, 0, 1, 1) -w1_habitat.addWidget(widgets["userCallEntry"], 2, 1, 1, 2) -w1_habitat.addWidget(widgets["userLocationLabel"], 3, 0, 1, 1) -w1_habitat.addWidget(widgets["userLatEntry"], 3, 1, 1, 1) -w1_habitat.addWidget(widgets["userLonEntry"], 3, 2, 1, 1) -w1_habitat.addWidget(widgets["userAltitudeLabel"], 4, 0, 1, 1) -w1_habitat.addWidget(widgets["userAltEntry"], 4, 1, 1, 2) -w1_habitat.addWidget(widgets["userAntennaLabel"], 5, 0, 1, 1) -w1_habitat.addWidget(widgets["userAntennaEntry"], 5, 1, 1, 2) -w1_habitat.addWidget(widgets["userRadioLabel"], 6, 0, 1, 1) -w1_habitat.addWidget(widgets["userRadioEntry"], 6, 1, 1, 2) -w1_habitat.addWidget(widgets["dialFreqLabel"], 7, 0, 1, 1) -w1_habitat.addWidget(widgets["dialFreqEntry"], 7, 1, 1, 2) -w1_habitat.addWidget(widgets["habitatUploadPosition"], 8, 0, 1, 3) -w1_habitat.layout.setRowStretch(9, 1) -w1_habitat.addWidget(widgets["saveSettingsButton"], 10, 0, 1, 3) +w1_habitat.addWidget(widgets["sondehubUploadLabel"], 0, 0, 1, 1) +w1_habitat.addWidget(widgets["sondehubUploadSelector"], 0, 1, 1, 1) +w1_habitat.addWidget(widgets["userCallLabel"], 1, 0, 1, 1) +w1_habitat.addWidget(widgets["userCallEntry"], 1, 1, 1, 2) +w1_habitat.addWidget(widgets["userLocationLabel"], 2, 0, 1, 1) +w1_habitat.addWidget(widgets["userLatEntry"], 2, 1, 1, 1) +w1_habitat.addWidget(widgets["userLonEntry"], 2, 2, 1, 1) +w1_habitat.addWidget(widgets["userAltitudeLabel"], 3, 0, 1, 1) +w1_habitat.addWidget(widgets["userAltEntry"], 3, 1, 1, 2) +w1_habitat.addWidget(widgets["userAntennaLabel"], 4, 0, 1, 1) +w1_habitat.addWidget(widgets["userAntennaEntry"], 4, 1, 1, 2) +w1_habitat.addWidget(widgets["userRadioLabel"], 5, 0, 1, 1) +w1_habitat.addWidget(widgets["userRadioEntry"], 5, 1, 1, 2) +w1_habitat.addWidget(widgets["dialFreqLabel"], 6, 0, 1, 1) +w1_habitat.addWidget(widgets["dialFreqEntry"], 6, 1, 1, 2) +w1_habitat.addWidget(widgets["habitatUploadPosition"], 7, 0, 1, 3) +w1_habitat.layout.setRowStretch(8, 1) +w1_habitat.addWidget(widgets["saveSettingsButton"], 9, 0, 1, 3) d0_habitat.addWidget(w1_habitat) @@ -310,6 +305,24 @@ widgets["ozimuxUDPEntry"].setMaxLength(5) widgets["ozimuxUDPEntry"].setToolTip( "UDP Port to output 'OziMux' UDP messages to." ) +widgets["loggingHeaderLabel"] = QtGui.QLabel("Logging") +widgets["enableLoggingLabel"] = QtGui.QLabel("Enable Logging:") +widgets["enableLoggingSelector"] = QtGui.QCheckBox() +widgets["enableLoggingSelector"].setChecked(False) +widgets["enableLoggingSelector"].setToolTip( + "Enable logging of received telemetry to disk (JSON)" +) +widgets["loggingFormatLabel"] = QtGui.QLabel("Log Format:") +widgets["loggingFormatSelector"] = QtGui.QComboBox() +widgets["loggingFormatSelector"].addItem("CSV") +widgets["loggingFormatSelector"].addItem("JSON") +widgets["loggingPathLabel"] = QtGui.QLabel("Log Directory:") +widgets["loggingPathEntry"] = QtGui.QLineEdit("") +widgets["loggingPathEntry"].setToolTip( + "Logging Directory" +) +widgets["selectLogDirButton"] = QtGui.QPushButton("Select Directory") + widgets["otherHeaderLabel"] = QtGui.QLabel("Other Settings") widgets["inhibitCRCLabel"] = QtGui.QLabel("Hide Failed CRC Errors:") widgets["inhibitCRCSelector"] = QtGui.QCheckBox() @@ -327,10 +340,18 @@ w1_other.addWidget(widgets["ozimuxUploadLabel"], 3, 0, 1, 1) w1_other.addWidget(widgets["ozimuxUploadSelector"], 3, 1, 1, 1) w1_other.addWidget(widgets["ozimuxUDPLabel"], 4, 0, 1, 1) w1_other.addWidget(widgets["ozimuxUDPEntry"], 4, 1, 1, 1) -w1_other.addWidget(widgets["otherHeaderLabel"], 5, 0, 1, 2) -w1_other.addWidget(widgets["inhibitCRCLabel"], 6, 0, 1, 1) -w1_other.addWidget(widgets["inhibitCRCSelector"], 6, 1, 1, 1) -w1_other.layout.setRowStretch(7, 1) +w1_other.addWidget(widgets["loggingHeaderLabel"], 5, 0, 1, 2) +w1_other.addWidget(widgets["enableLoggingLabel"], 6, 0, 1, 1) +w1_other.addWidget(widgets["enableLoggingSelector"], 6, 1, 1, 1) +w1_other.addWidget(widgets["loggingFormatLabel"], 7, 0, 1, 1) +w1_other.addWidget(widgets["loggingFormatSelector"], 7, 1, 1, 1) +w1_other.addWidget(widgets["loggingPathLabel"], 8, 0, 1, 1) +w1_other.addWidget(widgets["loggingPathEntry"], 8, 1, 1, 1) +w1_other.addWidget(widgets["selectLogDirButton"], 9, 0, 1, 2) +w1_other.addWidget(widgets["otherHeaderLabel"], 10, 0, 1, 2) +w1_other.addWidget(widgets["inhibitCRCLabel"], 11, 0, 1, 1) +w1_other.addWidget(widgets["inhibitCRCSelector"], 11, 1, 1, 1) +w1_other.layout.setRowStretch(12, 1) d0_other.addWidget(w1_other) @@ -584,21 +605,74 @@ def update_modem_settings(): global widgets populate_modem_settings(widgets) - widgets["horusModemSelector"].currentIndexChanged.connect(update_modem_settings) +def select_log_directory(): + global widgets + + folder = str(QtWidgets.QFileDialog.getExistingDirectory(None, "Select Directory")) + + if folder is None: + logging.info("No log directory selected.") + return False + else: + if folder == "": + logging.info("No log directory selected.") + return False + else: + widgets["loggingPathEntry"].setText(folder) + widgets["enableLoggingSelector"].setChecked(False) + if telemetry_logger: + widgets["enableLoggingSelector"].setChecked(True) + telemetry_logger.update_log_directory(widgets["loggingPathEntry"].text()) + telemetry_logger.enabled = True + + return True + +widgets["selectLogDirButton"].clicked.connect(select_log_directory) + + +def set_logging_state(): + global widgets + + logging_enabled = widgets["enableLoggingSelector"].isChecked() + + if logging_enabled: + if widgets["loggingPathEntry"].text() == "": + # No logging directory set, prompt user to select one. + _success = select_log_directory() + if not _success: + # User didn't select a directory, set checkbox to false again. + logging.error("No log directory selected, logging disabled.") + widgets["enableLoggingSelector"].setChecked(False) + # Disable logging. + if telemetry_logger: + telemetry_logger.enabled = False + + return + + # Enable logging + if telemetry_logger: + telemetry_logger.enabled = True + telemetry_logger.update_log_directory(widgets["loggingPathEntry"].text()) + + else: + # Disable logging + if telemetry_logger: + telemetry_logger.enabled = False + +widgets["enableLoggingSelector"].clicked.connect(set_logging_state) + +def set_logging_format(): + if telemetry_logger: + telemetry_logger.log_format = widgets["loggingFormatSelector"].currentText() + +widgets["loggingFormatSelector"].currentIndexChanged.connect(set_logging_format) + # Read in configuration file settings read_config(widgets) -# Start Habitat Uploader -habitat_uploader = HabitatUploader( - user_callsign=widgets["userCallEntry"].text(), - listener_lat=widgets["userLatEntry"].text(), - listener_lon=widgets["userLonEntry"].text(), - listener_radio="Horus-GUI v" + __version__ + " " + widgets["userRadioEntry"].text(), - listener_antenna=widgets["userAntennaEntry"].text(), -) try: if float(widgets["userLatEntry"].text()) == 0.0 and float(widgets["userLonEntry"].text()) == 0.0: @@ -618,18 +692,18 @@ sondehub_uploader = SondehubAmateurUploader( software_version = __version__, ) +telemetry_logger = TelemetryLogger( + log_directory = widgets["loggingPathEntry"].text(), + log_format = widgets["loggingFormatSelector"].currentText(), + enabled = widgets["enableLoggingSelector"].isChecked() +) + # Handlers for various checkboxes and push-buttons def habitat_position_reupload(): """ Trigger a re-upload of user position information """ - global widgets, habitat_uploader, sondehub_uploader + global widgets, sondehub_uploader - habitat_uploader.user_callsign = widgets["userCallEntry"].text() - habitat_uploader.listener_lat = widgets["userLatEntry"].text() - habitat_uploader.listener_lon = widgets["userLonEntry"].text() - habitat_uploader.listener_radio = "Horus-GUI v" + __version__ + " " + widgets["userRadioEntry"].text() - habitat_uploader.listener_antenna = widgets["userAntennaEntry"].text() - habitat_uploader.trigger_position_upload() # Do the same for Sondehub. sondehub_uploader.user_callsign = widgets["userCallEntry"].text() @@ -650,13 +724,10 @@ widgets["habitatUploadPosition"].clicked.connect(habitat_position_reupload) def habitat_inhibit(): """ Update the Habitat inhibit flag """ - global widgets, habitat_uploader, sondehub_uploader - habitat_uploader.inhibit = not widgets["habitatUploadSelector"].isChecked() + global widgets, sondehub_uploader sondehub_uploader.inhibit = not widgets["sondehubUploadSelector"].isChecked() - logging.debug(f"Updated Habitat Inhibit state: {habitat_uploader.inhibit}") logging.debug(f"Updated Sondebub Inhibit state: {sondehub_uploader.inhibit}") -widgets["habitatUploadSelector"].clicked.connect(habitat_inhibit) widgets["sondehubUploadSelector"].clicked.connect(habitat_inhibit) @@ -849,7 +920,6 @@ def handle_new_packet(frame): # Add on the centre frequency estimation onto the dial frequency. _radio_dial += widgets["fest_float"] - habitat_uploader.last_freq_hz = _radio_dial except: _radio_dial = None @@ -871,10 +941,6 @@ def handle_new_packet(frame): widgets["latestRawSentenceData"].setText(f"{_packet} ({_snr:.1f} dB SNR)") widgets["latestDecodedSentenceData"].setText(f"{_packet}") - # Upload the string to Habitat - _decoded_str = "$$" + frame.data.split('$')[-1] + '\n' - habitat_uploader.add(_decoded_str) - # Upload the string to Sondehub Amateur sondehub_uploader.add(_decoded) @@ -899,7 +965,6 @@ def handle_new_packet(frame): widgets["latestRawSentenceData"].setText(f"{_packet} ({_snr:.1f} dB SNR)") widgets["latestDecodedSentenceData"].setText(_decoded['ukhas_str']) - habitat_uploader.add(_decoded['ukhas_str']+'\n') # Upload the string to Sondehub Amateur sondehub_uploader.add(_decoded) except Exception as e: @@ -962,6 +1027,10 @@ def handle_new_packet(frame): _udp_port = int(widgets["ozimuxUDPEntry"].text()) send_ozimux_message(_decoded, port=_udp_port) + # Log telemetry + if telemetry_logger: + telemetry_logger.add(_decoded) + @@ -972,7 +1041,7 @@ def start_decoding(): Start decoding! (Or, stop decoding) """ - global widgets, audio_stream, fft_process, horus_modem, habitat_uploader, audio_devices, running, fft_update_queue, status_update_queue + global widgets, audio_stream, fft_process, horus_modem, audio_devices, running, fft_update_queue, status_update_queue if not running: # Grab settings off widgets @@ -1010,8 +1079,7 @@ def start_decoding(): widgets["latestPacketBearingValue"].setText("---") widgets["latestPacketRangeValue"].setText("---") - # Ensure the Habitat upload is set correctly. - habitat_uploader.inhibit = not widgets["habitatUploadSelector"].isChecked() + # Ensure the SondeHub upload is set correctly. sondehub_uploader.inhibit = not widgets["sondehubUploadSelector"].isChecked() # Init FFT Processor @@ -1262,12 +1330,12 @@ def main(): pass try: - habitat_uploader.close() + sondehub_uploader.close() except: pass try: - sondehub_uploader.close() + telemetry_logger.close() except: pass diff --git a/horusgui/telemlogger.py b/horusgui/telemlogger.py new file mode 100644 index 0000000..fa600f1 --- /dev/null +++ b/horusgui/telemlogger.py @@ -0,0 +1,184 @@ +# Telemetry Logging +import csv +import datetime +import json +import logging +import os.path +import time +from threading import Thread +from queue import Queue + + +class TelemetryLogger(object): + """ + Telemetry Logger Class + + Queued telemetry logging class + """ + + def __init__( + self, + log_directory = None, + log_format = "CSV", + enabled = False + ): + self.log_directory = log_directory + self.log_format = log_format + self.enabled = enabled + + self.log_directory_updated = False + + self.input_queue = Queue() + self.json_filenames = {} + self.csv_filenames = {} + + self.processing_running = True + + self.processing_thread = Thread(target=self.process_telemetry) + self.processing_thread.start() + + + def write_json(self, telemetry): + + # Remove detailed packet format information if it exists. + if 'packet_format' in telemetry: + telemetry.pop('packet_format') + + if telemetry['callsign'] not in self.json_filenames: + _filename = datetime.datetime.utcnow().strftime("%Y%m%d-%H%M%S") + f"_{telemetry['callsign']}.json" + _filepath = os.path.join(self.log_directory, _filename) + + try: + _current_f = open(_filepath, 'a') + self.json_filenames[telemetry['callsign']] = _filepath + logging.info(f"Telemetry Logger - Opened new log file: {_filepath}") + + except Exception as e: + logging.error(f"Telemetry Logger - Could not open log file in directory {self.log_directory}. Disabling logger.") + self.enabled = False + return + + else: + # Open the file we already have started writing to. + try: + _current_f = open(self.json_filenames[telemetry['callsign']], 'a') + except Exception as e: + # Couldn't open log file. Remove filename from local list so we try and make a new file on next telemetry. + logging.error(f"Telemetry Logger - Could not open existing log file {self.json_filenames[telemetry['callsign']]}.") + self.json_filenames.pop(telemetry['callsign']) + return + + # Convert telemetry to JSON + _data = json.dumps(telemetry) + "\n" + # Write to file. + _current_f.write(_data) + # Close file. + _current_f.close() + + + def write_csv(self, telemetry): + # Remove detailed packet format information if it exists. + if 'packet_format' in telemetry: + telemetry.pop('packet_format') + + if 'ukhas_str' in telemetry: + telemetry.pop('ukhas_str') + + if 'custom_field_names' in telemetry: + telemetry.pop('custom_field_names') + + csv_keys = list(telemetry.keys()) + csv_keys.sort() + csv_keys.remove("time") + csv_keys.remove("callsign") + csv_keys.remove("latitude") + csv_keys.remove("longitude") + csv_keys.remove("altitude") + csv_keys.insert(0,"time") # datetime should be at the front of the CSV + csv_keys.insert(1,"callsign") + csv_keys.insert(2,"latitude") + csv_keys.insert(3,"longitude") + csv_keys.insert(4,"altitude") + + + if telemetry['callsign'] not in self.csv_filenames: + _filename = datetime.datetime.utcnow().strftime("%Y%m%d-%H%M%S") + f"_{telemetry['callsign']}.csv" + _filepath = os.path.join(self.log_directory, _filename) + + try: + _current_f = open(_filepath, 'a') + self.csv_filenames[telemetry['callsign']] = _filepath + logging.info(f"Telemetry Logger - Opened new log file: {_filepath}") + + fc = csv.DictWriter(_current_f, fieldnames=csv_keys) + fc.writeheader() + + except Exception as e: + logging.error(f"Telemetry Logger - Could not open log file in directory {self.log_directory}. Disabling logger.") + self.enabled = False + return + + else: + # Open the file we already have started writing to. + try: + _current_f = open(self.csv_filenames[telemetry['callsign']], 'a') + except Exception as e: + # Couldn't open log file. Remove filename from local list so we try and make a new file on next telemetry. + logging.error(f"Telemetry Logger - Could not open existing log file {self.csv_filenames[telemetry['callsign']]}.") + self.csv_filenames.pop(telemetry['callsign']) + return + + fc = csv.DictWriter(_current_f, fieldnames=csv_keys) + fc.writerows([telemetry]) + # Close file. + _current_f.close() + + + def handle_telemetry(self, telemetry): + + if self.log_directory.strip() == "" or self.log_directory is None: + return + + if self.log_directory_updated: + # Log directory has been moved, clear out existing filenames. + self.json_filenames = {} + self.csv_filenames = {} + self.log_directory_updated = False + + if self.log_format == "JSON": + self.write_json(telemetry) + elif self.log_format == "CSV": + self.write_csv(telemetry) + else: + logging.error(f"Telemetry Logger - Unknown Logging Format {self.log_format}") + + def process_telemetry(self): + + logging.debug("Started Telemetry Logger Thread") + + while self.processing_running: + + while self.input_queue.qsize() > 0: + try: + self.handle_telemetry(self.input_queue.get()) + except Exception as e: + logging.error(f"Telemetry Logger - Error handling telemetry - {str(e)}") + + time.sleep(1) + + logging.debug("Closed Telemetry Logger Thread") + + def add(self, telemetry): + if self.enabled: + try: + self.input_queue.put_nowait(telemetry) + except Exception as e: + logging.error("Telemetry Logger - Error adding sentence to queue: %s" % str(e)) + + def update_log_directory(self, directory): + """ Update the log directory in a hopefully clean manner """ + self.log_directory = directory + self.log_directory_updated = True + + def close(self): + self.processing_running = False \ No newline at end of file