2017-04-29 02:00:10 +00:00
#!/usr/bin/env python
#
2018-05-26 09:18:53 +00:00
# Radiosonde Auto RX Service - V2.0
2017-04-29 02:00:10 +00:00
#
2018-05-26 09:18:53 +00:00
# Copyright (C) 2018 Mark Jessop <vk5qi@rfhead.net>
# Released under GNU GPL v3 or later
2017-04-29 02:00:10 +00:00
#
2018-05-26 09:18:53 +00:00
# Refer github page for instructions on setup and usage.
# https://github.com/projecthorus/radiosonde_auto_rx/
2017-04-29 14:47:26 +00:00
#
2017-05-05 12:56:41 +00:00
import argparse
2017-04-29 14:06:47 +00:00
import datetime
2018-05-26 09:18:53 +00:00
import logging
import re
import sys
2017-04-29 14:06:47 +00:00
import time
import traceback
2017-05-06 23:42:46 +00:00
2018-06-18 11:17:38 +00:00
import autorx
2018-05-26 09:18:53 +00:00
from autorx . scan import SondeScanner
from autorx . decode import SondeDecoder
from autorx . logger import TelemetryLogger
2018-07-04 08:13:58 +00:00
from autorx . email_notification import EmailNotification
2018-05-26 09:18:53 +00:00
from autorx . habitat import HabitatUploader
2018-05-26 11:51:55 +00:00
from autorx . aprs import APRSUploader
2018-05-27 10:59:49 +00:00
from autorx . ozimux import OziUploader
2018-05-26 09:18:53 +00:00
from autorx . utils import rtlsdr_test , position_info
from autorx . config import read_auto_rx_config
2018-06-29 13:02:58 +00:00
from autorx . web import start_flask , stop_flask , flask_emit_event , WebHandler , WebExporter
2017-07-16 10:11:13 +00:00
2018-05-26 09:18:53 +00:00
try :
# Python 2
from Queue import Queue
except ImportError :
# Python 3
from queue import Queue
2017-04-29 14:06:47 +00:00
2018-05-26 09:18:53 +00:00
# Logging level
# INFO = Basic status messages
# DEBUG = Adds detailed information on submodule operations.
logging_level = logging . INFO
2017-04-29 14:06:47 +00:00
2018-05-26 09:18:53 +00:00
#
# Global Variables
#
2017-04-29 14:06:47 +00:00
2018-05-26 09:18:53 +00:00
RS_PATH = " ./ "
2017-04-29 14:06:47 +00:00
2018-05-26 09:18:53 +00:00
# Optional override for RS92 ephemeris data.
rs92_ephemeris = None
2017-04-29 14:06:47 +00:00
2018-06-01 11:32:24 +00:00
# Global configuration dictionary. Populated on startup.
2018-05-26 09:18:53 +00:00
config = None
2017-04-29 14:06:47 +00:00
2018-05-26 09:18:53 +00:00
# Exporter Lists
exporter_objects = [ ] # This list will hold references to each exporter instance that is created.
exporter_functions = [ ] # This list will hold references to the exporter add functions, which will be passed onto the decoders.
2017-04-29 14:06:47 +00:00
2017-07-16 10:11:13 +00:00
2017-04-29 14:06:47 +00:00
2018-05-26 09:18:53 +00:00
# Scan Result Queue
# Scan results are processed asynchronously from the main scanner object.
scan_results = Queue ( )
2017-04-30 04:41:09 +00:00
2017-04-29 02:00:10 +00:00
2018-05-26 09:18:53 +00:00
def allocate_sdr ( check_only = False , task_description = " " ) :
""" Allocate an un-used SDR for a task.
2017-05-06 23:42:46 +00:00
2018-05-26 09:18:53 +00:00
Args :
check_only ( bool ) : If True , don ' t set the free SDR as in-use. Used to check if there are any free SDRs.
2017-12-17 01:44:20 +00:00
2018-05-26 09:18:53 +00:00
Returns :
( str ) : The device index / serial number of the free / allocated SDR , if one is free , else None .
"""
2017-07-16 10:11:13 +00:00
2018-06-18 11:17:38 +00:00
for _idx in autorx . sdr_list . keys ( ) :
if autorx . sdr_list [ _idx ] [ ' in_use ' ] == False :
2018-05-26 09:18:53 +00:00
# Found a free SDR!
if check_only :
# If we are just checking to see if there are any SDRs free, we don't allocate it.
pass
else :
# Otherwise, set the SDR as in-use.
2018-06-18 11:17:38 +00:00
autorx . sdr_list [ _idx ] [ ' in_use ' ] = True
2018-05-26 13:52:46 +00:00
logging . info ( " SDR # %s has been allocated to %s . " % ( str ( _idx ) , task_description ) )
2018-05-26 09:18:53 +00:00
return _idx
# Otherwise, no SDRs are free.
return None
def start_scanner ( ) :
""" Start a scanner thread on the first available SDR """
2018-06-18 11:17:38 +00:00
global config , scan_results , RS_PATH
2018-05-26 09:18:53 +00:00
2018-06-18 11:17:38 +00:00
if ' SCAN ' in autorx . task_list :
2018-05-26 09:18:53 +00:00
# Already a scanner running! Return.
logging . debug ( " Task Manager - Attempted to start a scanner, but one already running. " )
return
# Attempt to allocate a SDR.
_device_idx = allocate_sdr ( task_description = " Scanner " )
if _device_idx is None :
logging . debug ( " Task Manager - No SDRs free to run Scanner. " )
return
2017-12-17 01:44:20 +00:00
else :
2018-05-26 09:18:53 +00:00
# Create entry in task list.
2018-06-18 11:17:38 +00:00
autorx . task_list [ ' SCAN ' ] = { ' device_idx ' : _device_idx , ' task ' : None }
2018-05-26 09:18:53 +00:00
# Init Scanner using settings from the global config.
2018-06-01 11:32:24 +00:00
# TODO: Nicer way of passing in the huge list of args.
2018-06-18 11:17:38 +00:00
autorx . task_list [ ' SCAN ' ] [ ' task ' ] = SondeScanner (
2018-05-26 09:18:53 +00:00
callback = scan_results . put ,
auto_start = True ,
min_freq = config [ ' min_freq ' ] ,
max_freq = config [ ' max_freq ' ] ,
search_step = config [ ' search_step ' ] ,
whitelist = config [ ' whitelist ' ] ,
greylist = config [ ' greylist ' ] ,
blacklist = config [ ' blacklist ' ] ,
snr_threshold = config [ ' snr_threshold ' ] ,
min_distance = config [ ' min_distance ' ] ,
quantization = config [ ' quantization ' ] ,
scan_dwell_time = config [ ' scan_dwell_time ' ] ,
detect_dwell_time = config [ ' detect_dwell_time ' ] ,
max_peaks = config [ ' max_peaks ' ] ,
rs_path = RS_PATH ,
sdr_power = config [ ' sdr_power ' ] ,
sdr_fm = config [ ' sdr_fm ' ] ,
device_idx = _device_idx ,
2018-06-18 11:17:38 +00:00
gain = autorx . sdr_list [ _device_idx ] [ ' gain ' ] ,
ppm = autorx . sdr_list [ _device_idx ] [ ' ppm ' ] ,
bias = autorx . sdr_list [ _device_idx ] [ ' bias ' ]
2018-05-26 09:18:53 +00:00
)
# Add a reference into the sdr_list entry
2018-06-18 11:17:38 +00:00
autorx . sdr_list [ _device_idx ] [ ' task ' ] = autorx . task_list [ ' SCAN ' ] [ ' task ' ]
2018-06-29 13:02:58 +00:00
# Indicate to the web client that the task list has been updated.
flask_emit_event ( ' task_event ' )
2018-05-26 09:18:53 +00:00
def stop_scanner ( ) :
""" Stop a currently running scan thread, and release the SDR it was using. """
2018-06-18 11:17:38 +00:00
if ' SCAN ' not in autorx . task_list :
2018-05-26 09:18:53 +00:00
# No scanner thread running!
# This means we likely have a SDR free already.
return
2018-05-07 12:03:31 +00:00
else :
2018-05-26 09:18:53 +00:00
logging . info ( " Halting Scanner to decode detected radiosonde. " )
2018-06-18 11:17:38 +00:00
_scan_sdr = autorx . task_list [ ' SCAN ' ] [ ' device_idx ' ]
2018-05-26 09:18:53 +00:00
# Stop the scanner.
2018-06-18 11:17:38 +00:00
autorx . task_list [ ' SCAN ' ] [ ' task ' ] . stop ( )
2018-05-26 09:18:53 +00:00
# Relase the SDR.
2018-06-18 11:17:38 +00:00
autorx . sdr_list [ _scan_sdr ] [ ' in_use ' ] = False
autorx . sdr_list [ _scan_sdr ] [ ' task ' ] = None
2018-05-26 09:18:53 +00:00
# Remove the scanner task from the task list
2018-06-18 11:17:38 +00:00
autorx . task_list . pop ( ' SCAN ' )
2018-05-26 09:18:53 +00:00
2018-06-01 11:32:24 +00:00
2018-05-26 09:18:53 +00:00
def start_decoder ( freq , sonde_type ) :
2018-06-01 11:32:24 +00:00
""" Attempt to start a decoder thread for a given sonde.
Args :
freq ( float ) : Radiosonde frequency in Hz .
sonde_type ( str ) : The radiosonde type ( ' RS41 ' , ' RS92 ' , ' DFM ' )
"""
2018-06-18 11:17:38 +00:00
global config , RS_PATH , exporter_functions , rs92_ephemeris
2018-05-26 09:18:53 +00:00
# Allocate a SDR.
_device_idx = allocate_sdr ( task_description = " Decoder ( %s , %.3f MHz) " % ( sonde_type , freq / 1e6 ) )
if _device_idx is None :
logging . error ( " Could not allocate SDR for decoder! " )
return
2017-04-29 14:06:47 +00:00
else :
2018-05-26 09:18:53 +00:00
# Add an entry to the task list
2018-06-18 11:17:38 +00:00
autorx . task_list [ freq ] = { ' device_idx ' : _device_idx , ' task ' : None }
2018-05-26 09:18:53 +00:00
# Set the SDR to in-use
2018-06-18 11:17:38 +00:00
autorx . sdr_list [ _device_idx ] [ ' in_use ' ] = True
2018-05-26 09:18:53 +00:00
# Initialise a decoder.
2018-06-18 11:17:38 +00:00
autorx . task_list [ freq ] [ ' task ' ] = SondeDecoder (
2018-05-26 09:18:53 +00:00
sonde_type = sonde_type ,
sonde_freq = freq ,
rs_path = RS_PATH ,
sdr_fm = config [ ' sdr_fm ' ] ,
device_idx = _device_idx ,
2018-06-18 11:17:38 +00:00
gain = autorx . sdr_list [ _device_idx ] [ ' gain ' ] ,
ppm = autorx . sdr_list [ _device_idx ] [ ' ppm ' ] ,
bias = autorx . sdr_list [ _device_idx ] [ ' bias ' ] ,
2018-05-26 09:18:53 +00:00
exporter = exporter_functions ,
timeout = config [ ' rx_timeout ' ] ,
telem_filter = telemetry_filter ,
rs92_ephemeris = rs92_ephemeris
)
2018-06-18 11:17:38 +00:00
autorx . sdr_list [ _device_idx ] [ ' task ' ] = autorx . task_list [ freq ] [ ' task ' ]
2018-05-26 09:18:53 +00:00
2018-06-29 13:02:58 +00:00
# Indicate to the web client that the task list has been updated.
flask_emit_event ( ' task_event ' )
2018-05-26 09:18:53 +00:00
def handle_scan_results ( ) :
""" Read in Scan results via the scan results Queue.
Depending on how many SDRs are available , two things can happen :
- If there is a free SDR , allocate it to a decoder .
- If there is no free SDR , but a scanner is running , stop the scanner and start decoding .
"""
2018-06-18 11:17:38 +00:00
global scan_results
2018-06-01 11:32:24 +00:00
2018-05-26 09:18:53 +00:00
if scan_results . qsize ( ) > 0 :
2018-06-01 11:32:24 +00:00
# Grab the latest detections from the scan result queue.
2018-05-26 09:18:53 +00:00
_scan_data = scan_results . get ( )
for _sonde in _scan_data :
2018-06-01 11:32:24 +00:00
# Extract frequency & type info
2018-05-26 09:18:53 +00:00
_freq = _sonde [ 0 ]
_type = _sonde [ 1 ]
2018-06-18 11:17:38 +00:00
if _freq in autorx . task_list :
2018-05-26 09:18:53 +00:00
# Already decoding this sonde, continue.
2017-12-20 04:23:29 +00:00
continue
2018-05-26 09:18:53 +00:00
else :
2018-05-26 11:51:55 +00:00
logging . info ( " Detected new %s sonde on %.3f MHz! " % ( _type , _freq / 1e6 ) )
2018-05-26 09:18:53 +00:00
if allocate_sdr ( check_only = True ) is not None :
# There is a SDR free! Start the decoder on that SDR
start_decoder ( _freq , _type )
2018-06-18 11:17:38 +00:00
elif ( allocate_sdr ( check_only = True ) is None ) and ( ' SCAN ' in autorx . task_list ) :
2018-05-26 09:18:53 +00:00
# We have run out of SDRs, but a scan thread is running.
# Stop the scan thread and take that receiver!
stop_scanner ( )
start_decoder ( _freq , _type )
else :
2018-06-01 11:32:24 +00:00
# We have no SDRs free.
# TODO: Alert the user that a sonde was detected, but no SDR was available,
# but don't do this EVERY time we detect the sonde...
2018-05-26 09:18:53 +00:00
pass
2017-05-06 23:42:46 +00:00
2017-07-18 12:39:55 +00:00
2018-06-01 11:32:24 +00:00
2018-05-26 09:18:53 +00:00
def clean_task_list ( ) :
""" Check the task list to see if any tasks have stopped running. If so, release the associated SDR """
2017-07-18 12:35:17 +00:00
2018-06-18 11:17:38 +00:00
for _key in autorx . task_list . keys ( ) :
2018-05-26 09:18:53 +00:00
# Attempt to get the state of the task
try :
2018-06-18 11:17:38 +00:00
_running = autorx . task_list [ _key ] [ ' task ' ] . running ( )
_task_sdr = autorx . task_list [ _key ] [ ' device_idx ' ]
2018-05-26 09:18:53 +00:00
except Exception as e :
logging . error ( " Task Manager - Error getting task %s state - %s " % ( str ( _key ) , str ( e ) ) )
continue
2017-05-06 23:42:46 +00:00
2018-05-26 09:18:53 +00:00
if _running == False :
# This task has stopped. Release it's associated SDR.
2018-06-18 11:17:38 +00:00
autorx . sdr_list [ _task_sdr ] [ ' in_use ' ] = False
autorx . sdr_list [ _task_sdr ] [ ' task ' ] = None
2018-05-26 09:18:53 +00:00
# Pop the task from the task list.
2018-06-18 11:17:38 +00:00
autorx . task_list . pop ( _key )
2018-06-29 13:02:58 +00:00
# Indicate to the web client that the task list has been updated.
flask_emit_event ( ' task_event ' )
2017-05-06 23:42:46 +00:00
2018-05-26 09:18:53 +00:00
# Check if there is a scanner thread still running. If not, and if there is a SDR free, start one up again.
2018-06-18 11:17:38 +00:00
if ( ' SCAN ' not in autorx . task_list ) and ( allocate_sdr ( check_only = True ) is not None ) :
2018-05-26 09:18:53 +00:00
# We have a SDR free, and we are not running a scan thread. Start one.
start_scanner ( )
2017-12-20 04:23:29 +00:00
2017-05-06 23:42:46 +00:00
2018-06-01 11:32:24 +00:00
2018-05-26 09:18:53 +00:00
def stop_all ( ) :
""" Shut-down all decoders, scanners, and exporters. """
2018-06-18 11:17:38 +00:00
global exporter_objects
2018-05-26 09:18:53 +00:00
logging . info ( " Starting shutdown of all threads. " )
2018-06-18 11:17:38 +00:00
for _task in autorx . task_list . keys ( ) :
2018-05-26 09:18:53 +00:00
try :
2018-06-18 11:17:38 +00:00
autorx . task_list [ _task ] [ ' task ' ] . stop ( )
2018-05-26 09:18:53 +00:00
except Exception as e :
logging . error ( " Error stopping task - %s " % str ( e ) )
2017-05-06 23:42:46 +00:00
2018-05-26 09:18:53 +00:00
for _exporter in exporter_objects :
try :
_exporter . close ( )
except Exception as e :
logging . error ( " Error stopping exporter - %s " % str ( e ) )
2017-05-06 23:42:46 +00:00
2018-06-01 11:32:24 +00:00
2018-05-26 09:18:53 +00:00
def telemetry_filter ( telemetry ) :
""" Filter incoming radiosonde telemetry based on various factors,
- Invalid Position
- Invalid Altitude
- Abnormal range from receiver .
- Invalid serial number .
2017-12-22 12:45:40 +00:00
2018-06-01 11:32:24 +00:00
This function is defined within this script to avoid passing around large amounts of configuration data .
2017-12-22 12:45:40 +00:00
"""
global config
2018-05-09 12:00:56 +00:00
# First Check: zero lat/lon
2018-05-26 09:18:53 +00:00
if ( telemetry [ ' lat ' ] == 0.0 ) and ( telemetry [ ' lon ' ] == 0.0 ) :
logging . warning ( " Zero Lat/Lon. Sonde %s does not have GPS lock. " % telemetry [ ' id ' ] )
2018-05-09 12:00:56 +00:00
return False
# Second check: Altitude cap.
2018-05-26 09:18:53 +00:00
if telemetry [ ' alt ' ] > config [ ' max_altitude ' ] :
_altitude_breach = telemetry [ ' alt ' ] - config [ ' max_altitude ' ]
logging . warning ( " Sonde %s position breached altitude cap by %d m. " % ( telemetry [ ' id ' ] , _altitude_breach ) )
2017-12-22 12:45:40 +00:00
return False
2018-05-09 12:00:56 +00:00
# Third check - is the payload more than x km from our listening station.
2017-12-22 12:45:40 +00:00
# Only run this check if a station location has been provided.
if ( config [ ' station_lat ' ] != 0.0 ) and ( config [ ' station_lon ' ] != 0.0 ) :
# Calculate the distance from the station to the payload.
_listener = ( config [ ' station_lat ' ] , config [ ' station_lon ' ] , config [ ' station_alt ' ] )
2018-05-26 09:18:53 +00:00
_payload = ( telemetry [ ' lat ' ] , telemetry [ ' lon ' ] , telemetry [ ' alt ' ] )
2017-12-22 12:45:40 +00:00
# Calculate using positon_info function from rotator_utils.py
_info = position_info ( _listener , _payload )
if _info [ ' straight_distance ' ] > config [ ' max_radius_km ' ] * 1000 :
_radius_breach = _info [ ' straight_distance ' ] / 1000.0 - config [ ' max_radius_km ' ]
2018-05-26 09:18:53 +00:00
logging . warning ( " Sonde %s position breached radius cap by %.1f km. " % ( telemetry [ ' id ' ] , _radius_breach ) )
2017-12-22 12:45:40 +00:00
return False
2018-03-18 07:44:04 +00:00
# Payload Serial Number Checks
2018-05-26 09:18:53 +00:00
_serial = telemetry [ ' id ' ]
2018-03-18 07:44:04 +00:00
# Run a Regex to match known Vaisala RS92/RS41 serial numbers (YWWDxxxx)
# RS92: https://www.vaisala.com/sites/default/files/documents/Vaisala%20Radiosonde%20RS92%20Serial%20Number.pdf
# RS41: https://www.vaisala.com/sites/default/files/documents/Vaisala%20Radiosonde%20RS41%20Serial%20Number.pdf
# This will need to be re-evaluated if we're still using this code in 2021!
2018-05-07 12:03:31 +00:00
vaisala_callsign_valid = re . match ( r ' [J-T][0-5][ \ d][1-7] \ d {4} ' , _serial )
2018-03-18 07:44:04 +00:00
2018-05-09 12:40:06 +00:00
# Regex to check DFM06/09 callsigns.
2018-05-26 09:18:53 +00:00
# TODO: Check if this valid for DFM06s, and find out what's up with the 8-digit DFM09 callsigns.
2018-05-09 12:40:06 +00:00
dfm_callsign_valid = re . match ( r ' DFM0[69]- \ d {6} ' , _serial )
if vaisala_callsign_valid or dfm_callsign_valid :
2018-03-18 07:44:04 +00:00
return True
else :
2018-05-26 09:18:53 +00:00
logging . warning ( " Payload ID %s does not match regex. Discarding. " % telemetry [ ' id ' ] )
2018-03-18 07:44:04 +00:00
return False
2018-05-26 09:18:53 +00:00
def main ( ) :
""" Main Loop """
2018-06-18 11:17:38 +00:00
global config , exporter_objects , exporter_functions , logging_level , rs92_ephemeris
2018-03-18 07:44:04 +00:00
2018-05-26 09:18:53 +00:00
# Command line arguments.
parser = argparse . ArgumentParser ( )
2018-06-01 11:32:24 +00:00
parser . add_argument ( " -c " , " --config " , default = " station.cfg " , help = " Receive Station Configuration File. Default: station.cfg " )
parser . add_argument ( " -f " , " --frequency " , type = float , default = 0.0 , help = " Sonde Frequency Override (MHz). This overrides the scan whitelist with the supplied frequency. " )
parser . add_argument ( " -t " , " --timeout " , type = int , default = 0 , help = " Close auto_rx system after N minutes. Use 0 to run continuously. " )
2018-05-26 09:18:53 +00:00
parser . add_argument ( " -v " , " --verbose " , help = " Enable debug output. " , action = " store_true " )
2018-06-01 11:32:24 +00:00
parser . add_argument ( " -e " , " --ephemeris " , type = str , default = " None " , help = " Use a manually obtained ephemeris file when decoding RS92 Sondes. " )
2018-05-26 09:18:53 +00:00
args = parser . parse_args ( )
2017-04-29 02:00:10 +00:00
2018-06-01 11:32:24 +00:00
# Copy out timeout value, and convert to seconds,
_timeout = args . timeout * 60
# Copy out RS92 ephemeris value, if provided.
if args . ephemeris != " None " :
rs92_ephemeris = args . ephemeris
2018-05-26 09:18:53 +00:00
# Set log-level to DEBUG if requested
if args . verbose :
logging_level = logging . DEBUG
2017-04-29 02:00:10 +00:00
2018-06-17 12:40:43 +00:00
2018-06-01 11:32:24 +00:00
# Configure logging
2018-02-17 04:22:38 +00:00
logging . basicConfig ( format = ' %(asctime)s %(levelname)s : %(message)s ' , filename = datetime . datetime . utcnow ( ) . strftime ( " log/ % Y % m %d - % H % M % S_system.log " ) , level = logging_level )
2017-05-11 08:19:30 +00:00
stdout_format = logging . Formatter ( ' %(asctime)s %(levelname)s : %(message)s ' )
stdout_handler = logging . StreamHandler ( sys . stdout )
stdout_handler . setFormatter ( stdout_format )
logging . getLogger ( ) . addHandler ( stdout_handler )
2017-04-29 14:06:47 +00:00
2018-06-17 12:40:43 +00:00
web_handler = WebHandler ( )
logging . getLogger ( ) . addHandler ( web_handler )
# Set the requests/socketio logger to only display critical log messages.
logging . getLogger ( " requests " ) . setLevel ( logging . CRITICAL )
logging . getLogger ( " urllib3 " ) . setLevel ( logging . CRITICAL )
logging . getLogger ( ' werkzeug ' ) . setLevel ( logging . ERROR )
logging . getLogger ( ' socketio ' ) . setLevel ( logging . ERROR )
logging . getLogger ( ' engineio ' ) . setLevel ( logging . ERROR )
2018-04-15 10:04:14 +00:00
2017-05-05 12:56:41 +00:00
2018-05-26 09:18:53 +00:00
# Attempt to read in config file
logging . info ( " Reading configuration file... " )
_temp_cfg = read_auto_rx_config ( args . config )
if _temp_cfg is None :
logging . critical ( " Error in configuration file! Exiting... " )
sys . exit ( 1 )
2017-12-20 09:28:24 +00:00
else :
2018-05-26 09:18:53 +00:00
config = _temp_cfg
2018-06-18 11:28:49 +00:00
autorx . sdr_list = config [ ' sdr_settings ' ]
2017-12-20 09:28:24 +00:00
2018-06-21 12:59:10 +00:00
# Start up the flask server.
# This needs to occur AFTER logging is setup, else logging breaks horribly for some reason.
2018-06-23 14:13:51 +00:00
start_flask ( port = config [ ' web_port ' ] )
2018-06-21 12:59:10 +00:00
2018-06-01 11:32:24 +00:00
# If we have been supplied a frequency via the command line, override the whitelist settings
# to only include the supplied frequency.
2018-05-26 09:18:53 +00:00
if args . frequency != 0.0 :
config [ ' whitelist ' ] = [ args . frequency ]
2017-05-05 12:56:41 +00:00
2018-05-26 09:18:53 +00:00
# Start our exporter options
# Telemetry Logger
if config [ ' per_sonde_log ' ] :
_logger = TelemetryLogger ( log_directory = " ./log/ " )
exporter_objects . append ( _logger )
exporter_functions . append ( _logger . add )
2017-05-05 12:56:41 +00:00
2018-07-04 08:13:58 +00:00
if config [ ' email_enabled ' ] :
_email_notification = EmailNotification (
smtp_server = config [ ' email_smtp_server ' ] ,
mail_from = config [ ' email_from ' ] ,
mail_to = config [ ' email_to ' ]
)
exporter_objects . append ( _email_notification )
exporter_functions . append ( _email_notification . add )
2018-05-26 09:18:53 +00:00
# Habitat Uploader
if config [ ' habitat_enabled ' ] :
if config [ ' habitat_payload_callsign ' ] == " <id> " :
_habitat_payload_call = None
else :
_habitat_payload_call = config [ ' habitat_payload_callsign ' ]
2017-05-05 12:56:41 +00:00
2018-05-26 09:18:53 +00:00
if config [ ' habitat_upload_listener_position ' ] is False :
_habitat_user_position = None
else :
_habitat_user_position = ( config [ ' station_lat ' ] , config [ ' station_lon ' ] , config [ ' station_alt ' ] )
_habitat = HabitatUploader (
user_callsign = config [ ' habitat_uploader_callsign ' ] ,
2018-06-16 12:34:18 +00:00
user_antenna = config [ ' habitat_uploader_antenna ' ] ,
2018-05-26 09:18:53 +00:00
user_position = _habitat_user_position ,
payload_callsign_override = _habitat_payload_call ,
synchronous_upload_time = config [ ' habitat_upload_rate ' ] ,
callsign_validity_threshold = config [ ' payload_id_valid ' ]
)
2017-04-29 14:06:47 +00:00
2018-05-26 09:18:53 +00:00
exporter_objects . append ( _habitat )
exporter_functions . append ( _habitat . add )
2018-01-06 12:04:47 +00:00
2017-12-17 04:25:20 +00:00
2018-06-01 11:32:24 +00:00
# APRS Uploader
2018-05-26 11:51:55 +00:00
if config [ ' aprs_enabled ' ] :
if config [ ' aprs_object_id ' ] == " <id> " :
_aprs_object = None
else :
_aprs_object = config [ ' aprs_object_id ' ]
_aprs = APRSUploader (
aprs_callsign = config [ ' aprs_user ' ] ,
aprs_passcode = config [ ' aprs_pass ' ] ,
object_name_override = _aprs_object ,
object_comment = config [ ' aprs_custom_comment ' ] ,
aprsis_host = config [ ' aprs_server ' ] ,
synchronous_upload_time = config [ ' aprs_upload_rate ' ] ,
callsign_validity_threshold = config [ ' payload_id_valid ' ]
)
exporter_objects . append ( _aprs )
exporter_functions . append ( _aprs . add )
2017-07-16 10:11:13 +00:00
2018-05-27 10:59:49 +00:00
# OziExplorer
if config [ ' ozi_enabled ' ] or config [ ' payload_summary_enabled ' ] :
if config [ ' ozi_enabled ' ] :
_ozi_port = config [ ' ozi_port ' ]
else :
_ozi_port = None
if config [ ' payload_summary_enabled ' ] :
_summary_port = config [ ' payload_summary_port ' ]
else :
_summary_port = None
_ozimux = OziUploader (
ozimux_port = _ozi_port ,
payload_summary_port = _summary_port ,
update_rate = config [ ' ozi_update_rate ' ] )
exporter_objects . append ( _ozimux )
exporter_functions . append ( _ozimux . add )
2017-04-29 02:00:10 +00:00
2018-06-23 14:13:51 +00:00
_web_exporter = WebExporter ( max_age = config [ ' web_archive_age ' ] )
2018-06-17 13:16:30 +00:00
exporter_objects . append ( _web_exporter )
exporter_functions . append ( _web_exporter . add )
2018-05-26 09:18:53 +00:00
# MQTT (?) - TODO
2018-03-18 07:44:04 +00:00
2018-06-01 11:32:24 +00:00
# Note the start time.
_start_time = time . time ( )
2017-04-29 02:00:10 +00:00
2018-06-01 11:32:24 +00:00
# Loop.
2018-05-26 09:18:53 +00:00
while True :
2018-06-01 11:32:24 +00:00
# Check for finished tasks.
2018-05-26 09:18:53 +00:00
clean_task_list ( )
2018-06-01 11:32:24 +00:00
# Handle any new scan results.
2018-05-26 09:18:53 +00:00
handle_scan_results ( )
2018-06-01 11:32:24 +00:00
# Sleep a little bit.
2018-05-26 09:18:53 +00:00
time . sleep ( 2 )
2017-04-29 02:00:10 +00:00
2018-06-01 11:32:24 +00:00
# Allow a timeout after a set time, for users who wish to run auto_rx
# within a cronjob.
if ( _timeout > 0 ) and ( ( time . time ( ) - _start_time ) > _timeout ) :
logging . info ( " Shutdown time reached. Closing. " )
2018-07-01 01:43:29 +00:00
stop_flask ( port = config [ ' web_port ' ] )
2018-06-01 11:32:24 +00:00
stop_all ( )
break
2018-05-07 12:03:31 +00:00
2017-12-20 04:23:29 +00:00
2018-05-26 09:18:53 +00:00
if __name__ == " __main__ " :
2017-12-20 04:23:29 +00:00
2018-05-26 09:18:53 +00:00
try :
main ( )
2017-12-20 04:23:29 +00:00
except KeyboardInterrupt :
2018-06-01 11:32:24 +00:00
# Upon CTRL+C, shutdown all threads and exit.
2018-07-01 01:43:29 +00:00
stop_flask ( port = config [ ' web_port ' ] )
2018-05-26 09:18:53 +00:00
stop_all ( )
except Exception as e :
2018-06-01 11:32:24 +00:00
# Upon exceptions, attempt to shutdown threads and exit.
2018-05-26 09:18:53 +00:00
traceback . print_exc ( )
print ( " Main Loop Error - %s " % str ( e ) )
2018-07-01 01:43:29 +00:00
stop_flask ( port = config [ ' web_port ' ] )
2018-05-26 09:18:53 +00:00
stop_all ( )
2017-04-29 02:00:10 +00:00