Merge pull request #149 from darksidelemm/testing

Add custom email subject field, add audio / IQ logging options.
pull/154/head
Mark Jessop 2019-03-23 22:13:04 +10:30 zatwierdzone przez GitHub
commit e0581d4aa3
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 125 dodań i 54 usunięć

Wyświetl plik

@ -135,7 +135,8 @@ def start_scanner():
device_idx = _device_idx,
gain = autorx.sdr_list[_device_idx]['gain'],
ppm = autorx.sdr_list[_device_idx]['ppm'],
bias = autorx.sdr_list[_device_idx]['bias']
bias = autorx.sdr_list[_device_idx]['bias'],
save_detection_audio = config['save_detection_audio']
)
# Add a reference into the sdr_list entry
@ -198,6 +199,8 @@ def start_decoder(freq, sonde_type):
gain = autorx.sdr_list[_device_idx]['gain'],
ppm = autorx.sdr_list[_device_idx]['ppm'],
bias = autorx.sdr_list[_device_idx]['bias'],
save_decode_audio = config['save_decode_audio'],
save_decode_iq = config['save_decode_iq'],
exporter = exporter_functions,
timeout = config['rx_timeout'],
telem_filter = telemetry_filter,
@ -487,7 +490,8 @@ def main():
_email_notification = EmailNotification(
smtp_server = config['email_smtp_server'],
mail_from = config['email_from'],
mail_to = config['email_to']
mail_to = config['email_to'],
mail_subject = config['email_subject']
)
exporter_objects.append(_email_notification)

Wyświetl plik

@ -6,7 +6,7 @@
# Released under GNU GPL v3 or later
#
__version__ = "20190322-beta"
__version__ = "20190323-beta"
# Global Variables

Wyświetl plik

@ -40,11 +40,12 @@ def read_auto_rx_config(filename):
auto_rx_config = {
# Log Settings
'per_sonde_log' : True,
# Email Settings
'email_enabled': False,
'email_smtp_server': 'localhost',
'email_from': 'sonde@localhost',
'email_to': None,
# Email Settings
'email_enabled': False,
'email_smtp_server': 'localhost',
'email_from': 'sonde@localhost',
'email_to': None,
'email_subject': "<type> Sonde launch detected on <freq>: <id>",
# SDR Settings
'sdr_fm': 'rtl_fm',
'sdr_power': 'rtl_power',
@ -114,7 +115,11 @@ def read_auto_rx_config(filename):
'ozi_update_rate': 5,
'ozi_port' : 55681,
'payload_summary_enabled': False,
'payload_summary_port' : 55672
'payload_summary_port' : 55672,
# Debugging settings
'save_detection_audio' : False,
'save_decode_audio' : False,
'save_decode_iq' : False
}
sdr_settings = {}#'0':{'ppm':0, 'gain':-1, 'bias': False}}
@ -133,8 +138,9 @@ def read_auto_rx_config(filename):
auto_rx_config['email_smtp_server'] = config.get('email', 'smtp_server')
auto_rx_config['email_from'] = config.get('email', 'from')
auto_rx_config['email_to'] = config.get('email', 'to')
auto_rx_config['email_subject'] = config.get('email', 'subject')
except:
logging.error("Config - Invalid email settings. Disabling.")
logging.error("Config - Invalid or missing email settings. Disabling.")
auto_rx_config['email_enabled'] = False
# SDR Settings
@ -165,6 +171,7 @@ def read_auto_rx_config(filename):
auto_rx_config['habitat_payload_callsign'] = config.get('habitat', 'payload_callsign')
auto_rx_config['habitat_uploader_callsign'] = config.get('habitat', 'uploader_callsign')
auto_rx_config['habitat_upload_listener_position'] = config.getboolean('habitat','upload_listener_position')
auto_rx_config['habitat_uploader_antenna'] = config.get('habitat', 'uploader_antenna').strip()
# APRS Settings
auto_rx_config['aprs_enabled'] = config.getboolean('aprs', 'aprs_enabled')
@ -174,6 +181,15 @@ def read_auto_rx_config(filename):
auto_rx_config['aprs_server'] = config.get('aprs', 'aprs_server')
auto_rx_config['aprs_object_id'] = config.get('aprs', 'aprs_object_id')
auto_rx_config['aprs_custom_comment'] = config.get('aprs', 'aprs_custom_comment')
auto_rx_config['aprs_position_report'] = config.getboolean('aprs','aprs_position_report')
auto_rx_config['station_beacon_enabled'] = config.getboolean('aprs','station_beacon_enabled')
auto_rx_config['station_beacon_rate'] = config.getint('aprs', 'station_beacon_rate')
auto_rx_config['station_beacon_comment'] = config.get('aprs', 'station_beacon_comment')
auto_rx_config['station_beacon_icon'] = config.get('aprs', 'station_beacon_icon')
if auto_rx_config['station_beacon_enabled'] and auto_rx_config['station_lat']==0.0 and auto_rx_config['station_lon'] == 0.0:
auto_rx_config['station_beacon_enabled'] = False
logging.error("Config - Disable APRS Station beacon, as no station lat/lon set.")
# OziPlotter Settings
auto_rx_config['ozi_enabled'] = config.getboolean('oziplotter', 'ozi_enabled')
@ -203,48 +219,21 @@ def read_auto_rx_config(filename):
auto_rx_config['rotator_homing_enabled'] = config.getboolean('rotator', 'rotator_homing_enabled')
auto_rx_config['rotator_home_azimuth'] = config.getfloat('rotator', 'rotator_home_azimuth')
auto_rx_config['rotator_home_elevation'] = config.getfloat('rotator', 'rotator_home_elevation')
auto_rx_config['rotator_homing_delay'] = config.getint('rotator', 'rotator_homing_delay')
auto_rx_config['rotation_threshold'] = config.getfloat('rotator', 'rotation_threshold')
# Web interface settings.
auto_rx_config['web_host'] = config.get('web', 'web_host')
auto_rx_config['web_port'] = config.getint('web', 'web_port')
auto_rx_config['web_archive_age'] = config.getint('web', 'archive_age')
# New setting in this version (20180616). Keep it in a try-catch to avoid bombing out if the new setting isn't present.
# New debug settings - added 2019-03-23
try:
auto_rx_config['habitat_uploader_antenna'] = config.get('habitat', 'uploader_antenna').strip()
auto_rx_config['save_detection_audio'] = config.getboolean('debugging', 'save_detection_audio')
auto_rx_config['save_decode_audio'] = config.getboolean('debugging', 'save_decode_audio')
auto_rx_config['save_decode_iq'] = config.getboolean('debugging', 'save_decode_iq')
except:
logging.error("Config - Missing uploader_antenna setting. Using default.")
auto_rx_config['habitat_uploader_antenna'] = '1/4-wave'
# New settings added in 20180624.
try:
auto_rx_config['web_host'] = config.get('web', 'web_host')
auto_rx_config['web_port'] = config.getint('web', 'web_port')
auto_rx_config['web_archive_age'] = config.getint('web', 'archive_age')
except:
logging.error("Config - Missing Web Server settings. Using defaults.")
auto_rx_config['web_host'] = '0.0.0.0'
auto_rx_config['web_port'] = 5000
auto_rx_config['web_archive_age'] = 120
# New setting added in 201810xx (Rotator updates)
try:
auto_rx_config['rotator_homing_delay'] = config.getint('rotator', 'rotator_homing_delay')
auto_rx_config['rotation_threshold'] = config.getfloat('rotator', 'rotation_threshold')
except:
logging.error("Config - Missing new rotator settings, using defaults.")
# New APRS Station Beaconing settings added in 201812xx
try:
auto_rx_config['aprs_position_report'] = config.getboolean('aprs','aprs_position_report')
auto_rx_config['station_beacon_enabled'] = config.getboolean('aprs','station_beacon_enabled')
auto_rx_config['station_beacon_rate'] = config.getint('aprs', 'station_beacon_rate')
auto_rx_config['station_beacon_comment'] = config.get('aprs', 'station_beacon_comment')
auto_rx_config['station_beacon_icon'] = config.get('aprs', 'station_beacon_icon')
if auto_rx_config['station_beacon_enabled'] and auto_rx_config['station_lat']==0.0 and auto_rx_config['station_lon'] == 0.0:
auto_rx_config['station_beacon_enabled'] = False
logging.error("Config - Disable APRS Station beacon, as no station lat/lon set.")
except:
logging.error("Config - APRS Station Beacon settings missing, using defaults.")
logging.error("Config - Could not find debugging settings - using defaults.")
# Now we attempt to read in the individual SDR parameters.

Wyświetl plik

@ -74,6 +74,8 @@ class SondeDecoder(object):
ppm = 0,
gain = -1,
bias = False,
save_decode_audio = False,
save_decode_iq = False,
exporter = None,
timeout = 180,
@ -95,6 +97,11 @@ class SondeDecoder(object):
gain (int): SDR Gain setting, in dB. A gain setting of -1 enables the RTLSDR AGC.
bias (bool): If True, enable the bias tee on the SDR.
save_decode_audio (bool): If True, save the FM-demodulated audio to disk to decode_<device_idx>.wav.
Note: This may use up a lot of disk space!
save_decode_iq (bool): If True, save the decimated IQ stream (48 or 96k complex s16 samples) to disk to decode_IQ_<device_idx>.bin
Note: This will use up a lot of disk space!
exporter (function, list): Either a function, or a list of functions, which accept a single dictionary. Fields described above.
timeout (int): Timeout after X seconds of no valid data received from the decoder. Defaults to 180.
telem_filter (function): An optional filter function, which determines if a telemetry frame is valid.
@ -118,6 +125,8 @@ class SondeDecoder(object):
self.ppm = ppm
self.gain = gain
self.bias = bias
self.save_decode_audio = save_decode_audio
self.save_decode_iq = save_decode_iq
self.telem_filter = telem_filter
self.timeout = timeout
@ -222,6 +231,11 @@ class SondeDecoder(object):
# Note: Have removed a 'highpass 20' filter from the sox line, will need to re-evaluate if adding that is useful in the future.
decode_cmd = "%s %s-p %d -d %s %s-M fm -F9 -s 15k -f %d 2>/dev/null |" % (self.sdr_fm, bias_option, int(self.ppm), str(self.device_idx), gain_param, self.sonde_freq)
decode_cmd += "sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - lowpass 2600 2>/dev/null |"
# Add in tee command to save audio to disk if debugging is enabled.
if self.save_decode_audio:
decode_cmd += " tee decode_%s.wav |" % str(self.device_idx)
decode_cmd += "./rs41ecc --crc --ecc --ptu --json 2>/dev/null"
elif self.sonde_type == "RS92":
@ -262,6 +276,11 @@ class SondeDecoder(object):
# rtl_fm -p 0 -g 26.0 -M fm -F9 -s 12k -f 400500000 | sox -t raw -r 12k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 lowpass 2500 2>/dev/null | ./rs92ecc -vx -v --crc --ecc --vel -e ephemeris.dat
decode_cmd = "%s %s-p %d -d %s %s-M fm -F9 -s %d -f %d 2>/dev/null |" % (self.sdr_fm, bias_option, int(self.ppm), str(self.device_idx), gain_param, _rx_bw, self.sonde_freq)
decode_cmd += "sox -t raw -r %d -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - lowpass 2500 highpass 20 2>/dev/null |" % _rx_bw
# Add in tee command to save audio to disk if debugging is enabled.
if self.save_decode_audio:
decode_cmd += " tee decode_%s.wav |" % str(self.device_idx)
decode_cmd += "./rs92ecc -vx -v --crc --ecc --vel --json %s 2>/dev/null" % _rs92_gps_data
elif self.sonde_type == "DFM":
@ -273,6 +292,11 @@ class SondeDecoder(object):
# Note: Have removed a 'highpass 20' filter from the sox line, will need to re-evaluate if adding that is useful in the future.
decode_cmd = "%s %s-p %d -d %s %s-M fm -F9 -s 15k -f %d 2>/dev/null |" % (self.sdr_fm, bias_option, int(self.ppm), str(self.device_idx), gain_param, self.sonde_freq)
decode_cmd += "sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 lowpass 2000 2>/dev/null |"
# Add in tee command to save audio to disk if debugging is enabled.
if self.save_decode_audio:
decode_cmd += " tee decode_%s.wav |" % str(self.device_idx)
# DFM decoder
decode_cmd += "./dfm09ecc -vv --ecc --json --dist --auto 2>/dev/null"
@ -281,6 +305,11 @@ class SondeDecoder(object):
decode_cmd = "%s %s-p %d -d %s %s-M fm -F9 -s 22k -f %d 2>/dev/null |" % (self.sdr_fm, bias_option, int(self.ppm), str(self.device_idx), gain_param, self.sonde_freq)
decode_cmd += "sox -t raw -r 22k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |"
# Add in tee command to save audio to disk if debugging is enabled.
if self.save_decode_audio:
decode_cmd += " tee decode_%s.wav |" % str(self.device_idx)
# M10 decoder
decode_cmd += "./m10 -b -b2 2>/dev/null"
@ -289,6 +318,11 @@ class SondeDecoder(object):
decode_cmd = "%s %s-p %d -d %s %s-M fm -F9 -s 15k -f %d 2>/dev/null |" % (self.sdr_fm, bias_option, int(self.ppm), str(self.device_idx), gain_param, self.sonde_freq)
decode_cmd += "sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |"
# Add in tee command to save audio to disk if debugging is enabled.
if self.save_decode_audio:
decode_cmd += " tee decode_%s.wav |" % str(self.device_idx)
# iMet-4 (IMET1RS) decoder
decode_cmd += "./imet1rs_dft --json 2>/dev/null"

Wyświetl plik

@ -32,11 +32,12 @@ class EmailNotification(object):
# We require the following fields to be present in the input telemetry dict.
REQUIRED_FIELDS = [ 'id', 'lat', 'lon', 'alt', 'type', 'freq']
def __init__(self, smtp_server = 'localhost', mail_from = None, mail_to = None):
def __init__(self, smtp_server = 'localhost', mail_from = None, mail_to = None, mail_subject = None):
""" Init a new E-Mail Notification Thread """
self.smtp_server = smtp_server
self.mail_from = mail_from
self.mail_to = mail_to
self.mail_subject = mail_subject
# Dictionary to track sonde IDs
self.sondes = {}
@ -103,7 +104,13 @@ class EmailNotification(object):
msg += 'https://sondehub.org/%s\n' % _id
msg = MIMEText(msg, 'plain', 'UTF-8')
msg['Subject'] = 'Sonde launch detected: ' + _id
# Construct subject
msg['Subject'] = self.mail_subject
msg['Subject'].replace('<id>', telemetry['id'])
msg['Subject'].replace('<type>', telemetry['type'])
msg['Subject'].replace('<freq>', telemetry['freq'])
msg['From'] = self.mail_from
msg['To'] = self.mail_to
msg["Date"] = formatdate()

Wyświetl plik

@ -176,7 +176,7 @@ def read_rtl_power(filename):
return (freq, power, freq_step)
def detect_sonde(frequency, rs_path="./", dwell_time=10, sdr_fm='rtl_fm', device_idx=0, ppm=0, gain=-1, bias=False):
def detect_sonde(frequency, rs_path="./", dwell_time=10, sdr_fm='rtl_fm', device_idx=0, ppm=0, gain=-1, bias=False, save_detection_audio = False):
""" Receive some FM and attempt to detect the presence of a radiosonde.
Args:
@ -188,6 +188,7 @@ def detect_sonde(frequency, rs_path="./", dwell_time=10, sdr_fm='rtl_fm', device
ppm (int): SDR Frequency accuracy correction, in ppm.
gain (int): SDR Gain setting, in dB. A gain setting of -1 enables the RTLSDR AGC.
bias (bool): If True, enable the bias tee on the SDR.
save_detection_audio (bool): Save the audio used in detection to a file.
Returns:
str/None: Returns None if no sonde found, otherwise returns a sonde type, from the following:
@ -223,7 +224,12 @@ def detect_sonde(frequency, rs_path="./", dwell_time=10, sdr_fm='rtl_fm', device
# Sample Source (rtl_fm)
rx_test_command = "timeout %ds %s %s-p %d -d %s %s-M fm -F9 -s %d -f %d 2>/dev/null |" % (dwell_time*2, sdr_fm, bias_option, int(ppm), str(device_idx), gain_param, _rx_bw, frequency)
# Sample filtering
rx_test_command += "sox -t raw -r %d -e s -b 16 -c 1 - -r 48000 -t wav - highpass 20 2>/dev/null |" % _rx_bw
rx_test_command += "sox -t raw -r %d -e s -b 16 -c 1 - -r 48000 -t wav - highpass 20 2>/dev/null | " % _rx_bw
# Saving of Debug audio, if enabled,
if save_detection_audio:
rx_test_command += "tee detect_%s.wav | " % str(device_idx)
# Sample decoding / detection
# Note that we detect for dwell_time seconds, and timeout after dwell_time*2, to catch if no samples are being passed through.
rx_test_command += os.path.join(rs_path,"dft_detect") + " -t %d 2>/dev/null" % dwell_time
@ -351,7 +357,8 @@ class SondeScanner(object):
device_idx = 0,
gain = -1,
ppm = 0,
bias = False):
bias = False,
save_detection_audio = False):
""" Initialise a Sonde Scanner Object.
Apologies for the huge number of args...
@ -382,6 +389,7 @@ class SondeScanner(object):
ppm (int): SDR Frequency accuracy correction, in ppm.
gain (int): SDR Gain setting, in dB. A gain setting of -1 enables the RTLSDR AGC.
bias (bool): If True, enable the bias tee on the SDR.
save_detection_audio (bool): Save the audio used in each detecton to detect_<device_idx>.wav
"""
# Thread flag. This is set to True when a scan is running.
@ -410,6 +418,7 @@ class SondeScanner(object):
self.ppm = ppm
self.bias = bias
self.callback = callback
self.save_detection_audio = save_detection_audio
# Error counter.
@ -663,7 +672,8 @@ class SondeScanner(object):
ppm=self.ppm,
gain=self.gain,
bias=self.bias,
dwell_time=self.detect_dwell_time)
dwell_time=self.detect_dwell_time,
save_detection_audio=self.save_detection_audio)
if detected != None:
# Add a detected sonde to the output array

Wyświetl plik

@ -219,6 +219,11 @@ email_enabled = False
smtp_server = localhost
from = sonde@localhost
to = someone@example.com
# Custom subject field. The following fields can be included:
# <freq> - Sonde Frequency, i.e. 401.520 MHz
# <type> - Sonde Type (RS94/RS41)
# <id> - Sonde Serial Number (i.e. M1234567)
subject = <type> Sonde launch detected on <freq>: <id>
@ -273,6 +278,28 @@ web_port = 5000
archive_age = 120
##################
# DEBUG SETTINGS #
##################
[debugging]
# WARNING - Enabling these settings can result in lots of SD-card IO, potentially
# reducing the life of the card. These should only be enabled to collect data for
# debugging purposes.
# Save the audio that a detection pass is run over to: detect_<SDR_ID>.wav
# This file is over-written with every new detection.
save_detection_audio = False
# Save the audio from the output from a sonde decode chain to decode_<SDR_ID>.wav
# This file is over-written with each new sonde decoded for a particular SDR.
save_decode_audio = False
# Save the decimated IQ data from an experimental sonde decode chain to decode_IQ_<SDR_ID>.bin
# This will be in complex signed 16-bit int format, and may be either 48 kHz or 96 kHz.
# Note: This will use a LOT of disk space.
save_decode_iq = False
#####################
# ADVANCED SETTINGS #