kopia lustrzana https://github.com/projecthorus/radiosonde_auto_rx
Merge pull request #149 from darksidelemm/testing
Add custom email subject field, add audio / IQ logging options.pull/154/head
commit
e0581d4aa3
|
@ -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)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# Released under GNU GPL v3 or later
|
||||
#
|
||||
|
||||
__version__ = "20190322-beta"
|
||||
__version__ = "20190323-beta"
|
||||
|
||||
|
||||
# Global Variables
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 #
|
||||
|
|
Ładowanie…
Reference in New Issue