rewrite dahboard config, update APRS receive

This commit is contained in:
KF7EEL 2021-03-04 12:42:33 -08:00
parent 6b49e069e8
commit e6c61dd72a
7 changed files with 413 additions and 116 deletions

View File

@ -148,6 +148,11 @@ IGATE_BEACON_ICON = /I
IGATE_LATITUDE = 0000.00N IGATE_LATITUDE = 0000.00N
IGATE_LONGITUDE = 00000.00W IGATE_LONGITUDE = 00000.00W
# The APRS filter below is used for the message received script. See http://www.aprs-is.net/javAPRSFilter.aspx for details
# about APRS filters.
APRS_RECEIVE_LOGIN_CALL: N0CALL-1
APRS_FILTER: r/47/-120/500 t/m
# The email gateway settingns below are OPTIONAL. They are NOT REQUIRED if you don't want # The email gateway settingns below are OPTIONAL. They are NOT REQUIRED if you don't want
# to enable the email gateway. Leave as is to disable. # to enable the email gateway. Leave as is to disable.
EMAIL_SENDER: EMAIL_SENDER:
@ -155,6 +160,51 @@ EMAIL_PASSWORD:
SMTP_SERVER: smtp.gmail.com SMTP_SERVER: smtp.gmail.com
SMTP_PORT: 465 SMTP_PORT: 465
# The options below are required for operation of the dashboard and will cause errors in gps_data.py
# if configured wrong. Leave them as default unless you know what you are doing.
# If you do change, you must use absolute paths.
LOCATION_FILE: /tmp/gps_data_user_loc.txt
BULLETIN_BOARD_FILE: /tmp/gps_data_user_bb.txt
MAILBOX_FILE: /tmp/gps_data_user_mailbox.txt
EMERGENCY_SOS_FILE: /tmp/gps_data_user_sos.txt
# The following options are used for the dashboard. The dashboard is optional.
# Title of the Dashboard
DASHBOARD_TITLE: HBLink3 D-APRS Dashboard
# Logo used on dashboard page
LOGO: https://raw.githubusercontent.com/kf7eel/hblink3/gps/HBlink.png
# Port to run server
DASH_PORT: 8092
# IP to run server on
DASH_HOST: 127.0.0.1
#Description of dashboard to show on main page
DESCRIPTION: Welcome to the dashboard.
# Gateway contact info displayed on about page.
CONTACT_NAME: your name
CONTACT_CALL: N0CALL
CONTACT_EMAIL: email@example.org
CONTACT_WEBSITE: https://hbl.ink
# Time format for display
TIME_FORMAT: %%H:%%M:%%S - %%m/%%d/%%y
# Center dashboard map over these coordinates
MAP_CENTER_LAT: 47.00
MAP_CENTER_LON: -120.00
ZOOM_LEVEL: 7
# List and preview of some map themes at http://leaflet-extras.github.io/leaflet-providers/preview/
# The following are options for map themes and just work, you should use one of these: “OpenStreetMap”, “Stamen” (Terrain, Toner, and Watercolor),
MAP_THEME: Stamen Toner
# RSS feed link, shows in the link section of each RSS item.
RSS_LINK: http://localhost:8092
# OPENBRIDGE INSTANCES - DUPLICATE SECTION FOR MULTIPLE CONNECTIONS # OPENBRIDGE INSTANCES - DUPLICATE SECTION FOR MULTIPLE CONNECTIONS
# OpenBridge is a protocol originall created by DMR+ for connection between an # OpenBridge is a protocol originall created by DMR+ for connection between an
# IPSC2 server and Brandmeister. It has been implemented here at the suggestion # IPSC2 server and Brandmeister. It has been implemented here at the suggestion

View File

@ -111,7 +111,7 @@ __email__ = 'n0mjs@me.com'
# AT-D878 - Compressed UDP # AT-D878 - Compressed UDP
# MD-380 - Unified Data Transport # MD-380 - Unified Data Transport
hdr_type = '' hdr_type = ''
btf = '' btf = -1
ssid = '' ssid = ''
# From dmr_utils3, modified to decode entire packet. Works for 1/2 rate coded data. # From dmr_utils3, modified to decode entire packet. Works for 1/2 rate coded data.
@ -162,11 +162,11 @@ def aprs_send(packet):
def dashboard_loc_write(call, lat, lon, time, comment): def dashboard_loc_write(call, lat, lon, time, comment):
#try: #try:
dash_entries = ast.literal_eval(os.popen('cat /tmp/gps_data_user_loc.txt').read()) dash_entries = ast.literal_eval(os.popen('cat ' + loc_file).read())
# except: # except:
# dash_entries = [] # dash_entries = []
dash_entries.insert(0, {'call': call, 'lat': lat, 'lon': lon, 'time':time, 'comment':comment}) dash_entries.insert(0, {'call': call, 'lat': lat, 'lon': lon, 'time':time, 'comment': comment})
with open("/tmp/gps_data_user_loc.txt", 'w') as user_loc_file: with open(loc_file, 'w') as user_loc_file:
user_loc_file.write(str(dash_entries[:200])) user_loc_file.write(str(dash_entries[:200]))
user_loc_file.close() user_loc_file.close()
logger.info('User location saved for dashboard') logger.info('User location saved for dashboard')
@ -174,36 +174,38 @@ def dashboard_loc_write(call, lat, lon, time, comment):
def dashboard_bb_write(call, dmr_id, time, bulletin): def dashboard_bb_write(call, dmr_id, time, bulletin):
#try: #try:
dash_bb = ast.literal_eval(os.popen('cat /tmp/gps_data_user_bb.txt').read()) dash_bb = ast.literal_eval(os.popen('cat ' + bb_file).read())
# except: # except:
# dash_entries = [] # dash_entries = []
dash_bb.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'bulletin':bulletin}) dash_bb.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'bulletin':bulletin})
with open("/tmp/gps_data_user_bb.txt", 'w') as user_bb_file: with open(bb_file, 'w') as user_bb_file:
user_bb_file.write(str(dash_bb[:20])) user_bb_file.write(str(dash_bb[:20]))
user_bb_file.close() user_bb_file.close()
logger.info('User bulletin entry saved.') logger.info('User bulletin entry saved.')
#logger.info(dash_bb) #logger.info(dash_bb)
def mailbox_write(call, dmr_id, time, message, recipient): def mailbox_write(call, dmr_id, time, message, recipient):
#try: #try:
mail_file = ast.literal_eval(os.popen('cat ./gps_data_user_mailbox.txt').read()) mail_file = ast.literal_eval(os.popen('cat ' + the_mailbox_file).read())
mail_file.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'message':message, 'recipient': recipient}) mail_file.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'message':message, 'recipient': recipient})
with open("./gps_data_user_mailbox.txt", 'w') as mailbox_file: with open(the_mailbox_file, 'w') as mailbox_file:
mailbox_file.write(str(mail_file[:100])) mailbox_file.write(str(mail_file[:100]))
mailbox_file.close() mailbox_file.close()
logger.info('User mail saved.') logger.info('User mail saved.')
def mailbox_delete(dmr_id): def mailbox_delete(dmr_id):
mail_file = ast.literal_eval(os.popen('cat ./gps_data_user_mailbox.txt').read()) mail_file = ast.literal_eval(os.popen('cat ' + the_mailbox_file).read())
call = str(get_alias((dmr_id), subscriber_ids)) call = str(get_alias((dmr_id), subscriber_ids))
new_data = [] new_data = []
for message in mail_file: for message in mail_file:
if message['recipient'] != call: if message['recipient'] != call:
new_data.append(message) new_data.append(message)
with open("./gps_data_user_mailbox.txt", 'w') as mailbox_file: with open(the_mailbox_file, 'w') as mailbox_file:
mailbox_file.write(str(new_data[:100])) mailbox_file.write(str(new_data[:100]))
mailbox_file.close() mailbox_file.close()
logger.info('Mailbox updated. Delete occurred.') logger.info('Mailbox updated. Delete occurred.')
def sos_write(dmr_id, time, message): def sos_write(dmr_id, time, message):
user_settings = ast.literal_eval(os.popen('cat ./user_settings.txt').read()) user_settings = ast.literal_eval(os.popen('cat ./user_settings.txt').read())
try: try:
@ -213,8 +215,8 @@ def sos_write(dmr_id, time, message):
sos_call = user_settings[dmr_id][0]['call'] + '-' + user_settings[dmr_id][1]['ssid'] sos_call = user_settings[dmr_id][0]['call'] + '-' + user_settings[dmr_id][1]['ssid']
except: except:
sos_call = str(get_alias((dmr_id), subscriber_ids)) sos_call = str(get_alias((dmr_id), subscriber_ids))
sos_info = {'call': sos_call, 'dmr_id': dmr_id, 'time': time, 'message':message} sos_info = {'call': sos_call, 'dmr_id': dmr_id, 'time': time, 'message':message}
with open("/tmp/gps_data_user_sos.txt", 'w') as sos_file: with open(emergency_sos_file, 'w') as sos_file:
sos_file.write(str(sos_info)) sos_file.write(str(sos_info))
sos_file.close() sos_file.close()
logger.info('Saved SOS.') logger.info('Saved SOS.')
@ -257,6 +259,8 @@ def user_setting_write(dmr_id, setting, value):
user_dict[dmr_id][1]['ssid'] = value user_dict[dmr_id][1]['ssid'] = value
if setting.upper() == 'COM': if setting.upper() == 'COM':
user_comment = user_dict[dmr_id][3]['comment'] = value[0:35] user_comment = user_dict[dmr_id][3]['comment'] = value[0:35]
if setting.upper() == 'APRS':
user_dict[dmr_id] = [{'call': str(get_alias((dmr_id), subscriber_ids))}, {'ssid': ''}, {'icon': ''}, {'comment': ''}]
f.close() f.close()
logger.info('Loaded user settings. Preparing to write...') logger.info('Loaded user settings. Preparing to write...')
# Write modified dict to file # Write modified dict to file
@ -284,6 +288,9 @@ def process_sms(_rf_src, sms):
user_setting_write(int_id(_rf_src), re.sub(' .*|@','',sms), re.sub('@SSID| ','',sms)) user_setting_write(int_id(_rf_src), re.sub(' .*|@','',sms), re.sub('@SSID| ','',sms))
elif '@COM' in sms: elif '@COM' in sms:
user_setting_write(int_id(_rf_src), re.sub(' .*|@','',sms), re.sub('@COM |@COM','',sms)) user_setting_write(int_id(_rf_src), re.sub(' .*|@','',sms), re.sub('@COM |@COM','',sms))
# Write blank entry to cause APRS receive to look for packets for this station.
elif '@APRS' in sms:
user_setting_write(int_id(_rf_src), 'APRS', '')
elif '@BB' in sms: elif '@BB' in sms:
dashboard_bb_write(get_alias(int_id(_rf_src), subscriber_ids), int_id(_rf_src), time(), re.sub('@BB|@BB ','',sms)) dashboard_bb_write(get_alias(int_id(_rf_src), subscriber_ids), int_id(_rf_src), time(), re.sub('@BB|@BB ','',sms))
elif '@' and ' E-' in sms: elif '@' and ' E-' in sms:
@ -302,7 +309,7 @@ def process_sms(_rf_src, sms):
elif '@SOS' in sms or '@NOTICE' in sms: elif '@SOS' in sms or '@NOTICE' in sms:
sos_write(int_id(_rf_src), time(), sms) sos_write(int_id(_rf_src), time(), sms)
elif '@REM SOS' == sms: elif '@REM SOS' == sms:
os.remove('/tmp/gps_data_user_sos.txt') os.remove(emergency_sos_file)
logger.info('Removing SOS') logger.info('Removing SOS')
elif '@' and 'M-' in sms: elif '@' and 'M-' in sms:
message = re.sub('^@|.* M-|','',sms) message = re.sub('^@|.* M-|','',sms)
@ -354,7 +361,7 @@ def process_sms(_rf_src, sms):
ssid = user_settings[int_id(_rf_src)][1]['ssid'] ssid = user_settings[int_id(_rf_src)][1]['ssid']
if user_settings[int_id(_rf_src)][3]['comment'] != '': if user_settings[int_id(_rf_src)][3]['comment'] != '':
comment = user_settings[int_id(_rf_src)][3]['comment'] comment = user_settings[int_id(_rf_src)][3]['comment']
aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + icon_table + str(aprs_lon) + icon_icon + '/' + str(comment) aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:@' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + icon_table + str(aprs_lon) + icon_icon + '/' + str(comment)
logger.info(aprs_loc_packet) logger.info(aprs_loc_packet)
logger.info('User comment: ' + comment) logger.info('User comment: ' + comment)
logger.info('User SSID: ' + ssid) logger.info('User SSID: ' + ssid)
@ -374,7 +381,7 @@ def process_sms(_rf_src, sms):
elif 'A-' in sms and '@' in sms: elif 'A-' in sms and '@' in sms:
#Example SMS text: @ARMDS A-This is a test. #Example SMS text: @ARMDS A-This is a test.
aprs_dest = re.sub('@| A-.*','',sms) aprs_dest = re.sub('@| A-.*','',sms)
aprs_msg = re.sub('@.* A-|','',sms) aprs_msg = re.sub('^@|.* A-|','',sms)
logger.info('APRS message to ' + aprs_dest.upper() + '. Message: ' + aprs_msg) logger.info('APRS message to ' + aprs_dest.upper() + '. Message: ' + aprs_msg)
user_settings = ast.literal_eval(os.popen('cat ./user_settings.txt').read()) user_settings = ast.literal_eval(os.popen('cat ./user_settings.txt').read())
if int_id(_rf_src) in user_settings and user_settings[int_id(_rf_src)][1]['ssid'] != '': if int_id(_rf_src) in user_settings and user_settings[int_id(_rf_src)][1]['ssid'] != '':
@ -1535,7 +1542,7 @@ class routerHBP(HBSYSTEM):
ssid = user_settings[int_id(_rf_src)][1]['ssid'] ssid = user_settings[int_id(_rf_src)][1]['ssid']
if user_settings[int_id(_rf_src)][3]['comment'] != '': if user_settings[int_id(_rf_src)][3]['comment'] != '':
comment = user_settings[int_id(_rf_src)][3]['comment'] comment = user_settings[int_id(_rf_src)][3]['comment']
aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + icon_table + str(aprs_lon) + icon_icon + '/' + str(comment) aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:@' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + icon_table + str(aprs_lon) + icon_icon + '/' + str(comment)
logger.info(aprs_loc_packet) logger.info(aprs_loc_packet)
logger.info('User comment: ' + comment) logger.info('User comment: ' + comment)
logger.info('User SSID: ' + ssid) logger.info('User SSID: ' + ssid)
@ -1631,14 +1638,14 @@ class routerHBP(HBSYSTEM):
ssid = user_settings[int_id(_rf_src)][1]['ssid'] ssid = user_settings[int_id(_rf_src)][1]['ssid']
if user_settings[int_id(_rf_src)][3]['comment'] != '': if user_settings[int_id(_rf_src)][3]['comment'] != '':
comment = user_settings[int_id(_rf_src)][3]['comment'] comment = user_settings[int_id(_rf_src)][3]['comment']
aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(loc.lat[0:7]) + str(loc.lat_dir) + icon_table + str(loc.lon[0:8]) + str(loc.lon_dir) + icon_icon + str(round(loc.true_course)).zfill(3) + '/' + str(round(loc.spd_over_grnd)).zfill(3) + '/' + str(comment) aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:@' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(loc.lat[0:7]) + str(loc.lat_dir) + icon_table + str(loc.lon[0:8]) + str(loc.lon_dir) + icon_icon + str(round(loc.true_course)).zfill(3) + '/' + str(round(loc.spd_over_grnd)).zfill(3) + '/' + str(comment)
logger.info(aprs_loc_packet) logger.info(aprs_loc_packet)
logger.info('User comment: ' + comment) logger.info('User comment: ' + comment)
logger.info('User SSID: ' + ssid) logger.info('User SSID: ' + ssid)
logger.info('User icon: ' + icon_table + icon_icon) logger.info('User icon: ' + icon_table + icon_icon)
except Exception as error_exception: except Exception as error_exception:
logger.info('Error or user settings file not found, proceeding with default settings.') logger.info('Error or user settings file not found, proceeding with default settings.')
aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + str(user_ssid) + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(loc.lat[0:7]) + str(loc.lat_dir) + '/' + str(loc.lon[0:8]) + str(loc.lon_dir) + '[' + str(round(loc.true_course)).zfill(3) + '/' + str(round(loc.spd_over_grnd)).zfill(3) + '/' + aprs_comment + ' DMR ID: ' + str(int_id(_rf_src)) aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + str(user_ssid) + '>APHBL3,TCPIP*:@' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(loc.lat[0:7]) + str(loc.lat_dir) + '/' + str(loc.lon[0:8]) + str(loc.lon_dir) + '[' + str(round(loc.true_course)).zfill(3) + '/' + str(round(loc.spd_over_grnd)).zfill(3) + '/' + aprs_comment + ' DMR ID: ' + str(int_id(_rf_src))
logger.info(error_exception) logger.info(error_exception)
logger.info(str(traceback.extract_tb(error_exception.__traceback__))) logger.info(str(traceback.extract_tb(error_exception.__traceback__)))
try: try:
@ -1765,38 +1772,6 @@ if __name__ == '__main__':
# Change the current directory to the location of the application # Change the current directory to the location of the application
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
# Check if user_settings (for APRS settings of users) exists. Creat it if not.
if Path('./user_settings.txt').is_file():
pass
else:
Path('./user_settings.txt').touch()
with open("./user_settings.txt", 'w') as user_dict_file:
user_dict_file.write("{1: [{'call': 'N0CALL'}, {'ssid': ''}, {'icon': ''}, {'comment': ''}]}")
user_dict_file.close()
# Check to see if dashboard files exist
if Path('/tmp/gps_data_user_loc.txt').is_file():
pass
else:
Path('/tmp/gps_data_user_loc.txt').touch()
with open("/tmp/gps_data_user_loc.txt", 'w') as user_loc_file:
user_loc_file.write("[]")
user_loc_file.close()
if Path('/tmp/gps_data_user_bb.txt').is_file():
pass
else:
Path('/tmp/gps_data_user_bb.txt').touch()
with open("/tmp/gps_data_user_bb.txt", 'w') as user_bb_file:
user_bb_file.write("[]")
user_bb_file.close()
if Path('./gps_data_user_mailbox.txt').is_file():
pass
else:
Path('./gps_data_user_mailbox.txt').touch()
with open("./gps_data_user_mailbox.txt", 'w') as user_loc_file:
user_loc_file.write("[]")
user_loc_file.close()
# CLI argument parser - handles picking up the config file from the command line, and sending a "help" message # CLI argument parser - handles picking up the config file from the command line, and sending a "help" message
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-c', '--config', action='store', dest='CONFIG_FILE', help='/full/path/to/config.file (usually hblink.cfg)') parser.add_argument('-c', '--config', action='store', dest='CONFIG_FILE', help='/full/path/to/config.file (usually hblink.cfg)')
@ -1829,6 +1804,43 @@ if __name__ == '__main__':
smtp_server = CONFIG['GPS_DATA']['SMTP_SERVER'] smtp_server = CONFIG['GPS_DATA']['SMTP_SERVER']
smtp_port = CONFIG['GPS_DATA']['SMTP_PORT'] smtp_port = CONFIG['GPS_DATA']['SMTP_PORT']
# Dashboard files
bb_file = CONFIG['GPS_DATA']['BULLETIN_BOARD_FILE']
loc_file = CONFIG['GPS_DATA']['LOCATION_FILE']
the_mailbox_file = CONFIG['GPS_DATA']['MAILBOX_FILE']
emergency_sos_file = CONFIG['GPS_DATA']['EMERGENCY_SOS_FILE']
# Check if user_settings (for APRS settings of users) exists. Creat it if not.
if Path('./user_settings.txt').is_file():
pass
else:
Path('./user_settings.txt').touch()
with open("./user_settings.txt", 'w') as user_dict_file:
user_dict_file.write("{1: [{'call': 'N0CALL'}, {'ssid': ''}, {'icon': ''}, {'comment': ''}]}")
user_dict_file.close()
# Check to see if dashboard files exist
if Path(loc_file).is_file():
pass
else:
Path(loc_file).touch()
with open(loc_file, 'w') as user_loc_file:
user_loc_file.write("[]")
user_loc_file.close()
if Path(bb_file).is_file():
pass
else:
Path(bb_file).touch()
with open(bb_file, 'w') as user_bb_file:
user_bb_file.write("[]")
user_bb_file.close()
if Path(the_mailbox_file).is_file():
pass
else:
Path(the_mailbox_file).touch()
with open(the_mailbox_file, 'w') as user_loc_file:
user_loc_file.write("[]")
user_loc_file.close()
# Ensure we have a path for the rules file, if one wasn't specified, then use the default (top of file) # Ensure we have a path for the rules file, if one wasn't specified, then use the default (top of file)
if not cli_args.RULES_FILE: if not cli_args.RULES_FILE:
cli_args.RULES_FILE = os.path.dirname(os.path.abspath(__file__))+'/rules.py' cli_args.RULES_FILE = os.path.dirname(os.path.abspath(__file__))+'/rules.py'

View File

@ -162,6 +162,10 @@ def build_config(_config_file):
'EMAIL_PASSWORD': config.get(section, 'EMAIL_PASSWORD'), 'EMAIL_PASSWORD': config.get(section, 'EMAIL_PASSWORD'),
'SMTP_SERVER': config.get(section, 'SMTP_SERVER'), 'SMTP_SERVER': config.get(section, 'SMTP_SERVER'),
'SMTP_PORT': config.get(section, 'SMTP_PORT'), 'SMTP_PORT': config.get(section, 'SMTP_PORT'),
'LOCATION_FILE': config.get(section, 'LOCATION_FILE'),
'BULLETIN_BOARD_FILE': config.get(section, 'BULLETIN_BOARD_FILE'),
'MAILBOX_FILE': config.get(section, 'MAILBOX_FILE'),
'EMERGENCY_SOS_FILE': config.get(section, 'EMERGENCY_SOS_FILE'),
}) })
if not CONFIG['LOGGER']['LOG_FILE']: if not CONFIG['LOGGER']['LOG_FILE']:

View File

@ -105,6 +105,7 @@ PEER_URL: https://www.radioid.net/static/rptrs.json
SUBSCRIBER_URL: https://www.radioid.net/static/users.json SUBSCRIBER_URL: https://www.radioid.net/static/users.json
STALE_DAYS: 1 STALE_DAYS: 1
#####################################################################
# GPS/Data Application - by KF7EEL # GPS/Data Application - by KF7EEL
# Configure the settings for the DMR GPS to APRS position application here. # Configure the settings for the DMR GPS to APRS position application here.
# #
@ -116,7 +117,7 @@ STALE_DAYS: 1
# APRS_LOGIN_CALL, PASSCODE, SERVER, and PORT - Login settings for APRS-IS. # APRS_LOGIN_CALL, PASSCODE, SERVER, and PORT - Login settings for APRS-IS.
[GPS_DATA] [GPS_DATA]
DATA_DMR_ID: 9099 DATA_DMR_ID: 9099
CALL_TYPE: both CALL_TYPE: unit
USER_APRS_SSID: 15 USER_APRS_SSID: 15
USER_APRS_COMMENT: HBLink3 D-APRS - USER_APRS_COMMENT: HBLink3 D-APRS -
@ -126,6 +127,11 @@ APRS_LOGIN_PASSCODE: 12345
APRS_SERVER: rotate.aprs2.net APRS_SERVER: rotate.aprs2.net
APRS_PORT: 14580 APRS_PORT: 14580
# The APRS filter below is used for the message received script. See http://www.aprs-is.net/javAPRSFilter.aspx for details
# about APRS filters.
APRS_RECEIVE_LOGIN_CALL: N0CALL-1
APRS_FILTER: r/47/-120/500 t/m
# The following settings are only applicable if you are using the gps_data_beacon_igate script. # The following settings are only applicable if you are using the gps_data_beacon_igate script.
# They do not affect the operation gps_data itself. # They do not affect the operation gps_data itself.
# Time in minutes. # Time in minutes.
@ -135,13 +141,66 @@ IGATE_BEACON_ICON = /I
IGATE_LATITUDE = 0000.00N IGATE_LATITUDE = 0000.00N
IGATE_LONGITUDE = 00000.00W IGATE_LONGITUDE = 00000.00W
# The options below are required for operation of the dashboard. Leave them as default
# unless you know what you are doing.
LOCATION_FILE: /tmp/gps_data_user_loc.txt
BULLETIN_BOARD_FILE: /tmp/gps_data_user_bb.txt
MAILBOX_FILE: /tmp/gps_data_user_mailbox.txt
EMERGENCY_SOS_FILE: /tmp/gps_data_user_sos.txt
# The email gateway settingns below are OPTIONAL. They are NOT REQUIRED if you don't want # The email gateway settingns below are OPTIONAL. They are NOT REQUIRED if you don't want
# to enable the email gateway. Leave as is to disable. http://www.aprs-is.net/javAPRSFilter.aspx# to enable the email gateway. Leave as is to disable.
EMAIL_SENDER: EMAIL_SENDER: test@example.org
EMAIL_PASSWORD: EMAIL_PASSWORD: letmein
SMTP_SERVER: smtp.gmail.com SMTP_SERVER: smtp.gmail.com
SMTP_PORT: 465 SMTP_PORT: 465
# The options below are required for operation of the dashboard and will cause errors in gps_data.py
# if configured wrong. Leave them as default unless you know what you are doing.
# If you do change, you must use absolute paths.
LOCATION_FILE: /tmp/gps_data_user_loc.txt
BULLETIN_BOARD_FILE: /tmp/gps_data_user_bb.txt
MAILBOX_FILE: /tmp/gps_data_user_mailbox.txt
EMERGENCY_SOS_FILE: /tmp/gps_data_user_sos.txt
# The following options are used for the dashboard. The dashboard is optional.
# Title of the Dashboard
DASHBOARD_TITLE: HBLink3 D-APRS Dashboard
# Logo used on dashboard page
LOGO: https://raw.githubusercontent.com/kf7eel/hblink3/gps/HBlink.png
# Port to run server
DASH_PORT: 8092
# IP to run server on
DASH_HOST: 127.0.0.1
#Description of dashboard to show on main page
DESCRIPTION: Welcome to the dashboard.
# Gateway contact info displayed on about page.
CONTACT_NAME: your name
CONTACT_CALL: N0CALL
CONTACT_EMAIL: email@example.org
CONTACT_WEBSITE: https://hbl.ink
# Time format for display
TIME_FORMAT: %%H:%%M:%%S - %%m/%%d/%%y
# Center dashboard map over these coordinates
MAP_CENTER_LAT: 47.00
MAP_CENTER_LON: -120.00
ZOOM_LEVEL: 7
# List and preview of some map themes at http://leaflet-extras.github.io/leaflet-providers/preview/
# The following are options for map themes and just work, you should use one of these: “OpenStreetMap”, “Stamen” (Terrain, Toner, and Watercolor),
MAP_THEME: Stamen Toner
# RSS feed link, shows in the link section of each RSS item.
RSS_LINK: http://localhost:8092
#####################################################################
# OPENBRIDGE INSTANCES - DUPLICATE SECTION FOR MULTIPLE CONNECTIONS # OPENBRIDGE INSTANCES - DUPLICATE SECTION FOR MULTIPLE CONNECTIONS
# OpenBridge is a protocol originall created by DMR+ for connection between an # OpenBridge is a protocol originall created by DMR+ for connection between an
# IPSC2 server and Brandmeister. It has been implemented here at the suggestion # IPSC2 server and Brandmeister. It has been implemented here at the suggestion

View File

@ -155,11 +155,11 @@ def aprs_send(packet):
def dashboard_loc_write(call, lat, lon, time, comment): def dashboard_loc_write(call, lat, lon, time, comment):
#try: #try:
dash_entries = ast.literal_eval(os.popen('cat /tmp/gps_data_user_loc.txt').read()) dash_entries = ast.literal_eval(os.popen('cat ' + loc_file).read())
# except: # except:
# dash_entries = [] # dash_entries = []
dash_entries.insert(0, {'call': call, 'lat': lat, 'lon': lon, 'time':time, 'comment': comment}) dash_entries.insert(0, {'call': call, 'lat': lat, 'lon': lon, 'time':time, 'comment': comment})
with open("/tmp/gps_data_user_loc.txt", 'w') as user_loc_file: with open(loc_file, 'w') as user_loc_file:
user_loc_file.write(str(dash_entries[:200])) user_loc_file.write(str(dash_entries[:200]))
user_loc_file.close() user_loc_file.close()
logger.info('User location saved for dashboard') logger.info('User location saved for dashboard')
@ -167,11 +167,11 @@ def dashboard_loc_write(call, lat, lon, time, comment):
def dashboard_bb_write(call, dmr_id, time, bulletin): def dashboard_bb_write(call, dmr_id, time, bulletin):
#try: #try:
dash_bb = ast.literal_eval(os.popen('cat /tmp/gps_data_user_bb.txt').read()) dash_bb = ast.literal_eval(os.popen('cat ' + bb_file).read())
# except: # except:
# dash_entries = [] # dash_entries = []
dash_bb.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'bulletin':bulletin}) dash_bb.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'bulletin':bulletin})
with open("/tmp/gps_data_user_bb.txt", 'w') as user_bb_file: with open(bb_file, 'w') as user_bb_file:
user_bb_file.write(str(dash_bb[:20])) user_bb_file.write(str(dash_bb[:20]))
user_bb_file.close() user_bb_file.close()
logger.info('User bulletin entry saved.') logger.info('User bulletin entry saved.')
@ -179,21 +179,21 @@ def dashboard_bb_write(call, dmr_id, time, bulletin):
def mailbox_write(call, dmr_id, time, message, recipient): def mailbox_write(call, dmr_id, time, message, recipient):
#try: #try:
mail_file = ast.literal_eval(os.popen('cat ./gps_data_user_mailbox.txt').read()) mail_file = ast.literal_eval(os.popen('cat ' + the_mailbox_file).read())
mail_file.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'message':message, 'recipient': recipient}) mail_file.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'message':message, 'recipient': recipient})
with open("./gps_data_user_mailbox.txt", 'w') as mailbox_file: with open(the_mailbox_file, 'w') as mailbox_file:
mailbox_file.write(str(mail_file[:100])) mailbox_file.write(str(mail_file[:100]))
mailbox_file.close() mailbox_file.close()
logger.info('User mail saved.') logger.info('User mail saved.')
def mailbox_delete(dmr_id): def mailbox_delete(dmr_id):
mail_file = ast.literal_eval(os.popen('cat ./gps_data_user_mailbox.txt').read()) mail_file = ast.literal_eval(os.popen('cat ' + the_mailbox_file).read())
call = str(get_alias((dmr_id), subscriber_ids)) call = str(get_alias((dmr_id), subscriber_ids))
new_data = [] new_data = []
for message in mail_file: for message in mail_file:
if message['recipient'] != call: if message['recipient'] != call:
new_data.append(message) new_data.append(message)
with open("./gps_data_user_mailbox.txt", 'w') as mailbox_file: with open(the_mailbox_file, 'w') as mailbox_file:
mailbox_file.write(str(new_data[:100])) mailbox_file.write(str(new_data[:100]))
mailbox_file.close() mailbox_file.close()
logger.info('Mailbox updated. Delete occurred.') logger.info('Mailbox updated. Delete occurred.')
@ -209,7 +209,7 @@ def sos_write(dmr_id, time, message):
except: except:
sos_call = str(get_alias((dmr_id), subscriber_ids)) sos_call = str(get_alias((dmr_id), subscriber_ids))
sos_info = {'call': sos_call, 'dmr_id': dmr_id, 'time': time, 'message':message} sos_info = {'call': sos_call, 'dmr_id': dmr_id, 'time': time, 'message':message}
with open("/tmp/gps_data_user_sos.txt", 'w') as sos_file: with open(emergency_sos_file, 'w') as sos_file:
sos_file.write(str(sos_info)) sos_file.write(str(sos_info))
sos_file.close() sos_file.close()
logger.info('Saved SOS.') logger.info('Saved SOS.')
@ -252,6 +252,8 @@ def user_setting_write(dmr_id, setting, value):
user_dict[dmr_id][1]['ssid'] = value user_dict[dmr_id][1]['ssid'] = value
if setting.upper() == 'COM': if setting.upper() == 'COM':
user_comment = user_dict[dmr_id][3]['comment'] = value[0:35] user_comment = user_dict[dmr_id][3]['comment'] = value[0:35]
if setting.upper() == 'APRS':
user_dict[dmr_id] = [{'call': str(get_alias((dmr_id), subscriber_ids))}, {'ssid': ''}, {'icon': ''}, {'comment': ''}]
f.close() f.close()
logger.info('Loaded user settings. Preparing to write...') logger.info('Loaded user settings. Preparing to write...')
# Write modified dict to file # Write modified dict to file
@ -279,6 +281,9 @@ def process_sms(_rf_src, sms):
user_setting_write(int_id(_rf_src), re.sub(' .*|@','',sms), re.sub('@SSID| ','',sms)) user_setting_write(int_id(_rf_src), re.sub(' .*|@','',sms), re.sub('@SSID| ','',sms))
elif '@COM' in sms: elif '@COM' in sms:
user_setting_write(int_id(_rf_src), re.sub(' .*|@','',sms), re.sub('@COM |@COM','',sms)) user_setting_write(int_id(_rf_src), re.sub(' .*|@','',sms), re.sub('@COM |@COM','',sms))
# Write blank entry to cause APRS receive to look for packets for this station.
elif '@APRS' in sms:
user_setting_write(int_id(_rf_src), 'APRS', '')
elif '@BB' in sms: elif '@BB' in sms:
dashboard_bb_write(get_alias(int_id(_rf_src), subscriber_ids), int_id(_rf_src), time.time(), re.sub('@BB|@BB ','',sms)) dashboard_bb_write(get_alias(int_id(_rf_src), subscriber_ids), int_id(_rf_src), time.time(), re.sub('@BB|@BB ','',sms))
elif '@' and ' E-' in sms: elif '@' and ' E-' in sms:
@ -297,7 +302,7 @@ def process_sms(_rf_src, sms):
elif '@SOS' in sms or '@NOTICE' in sms: elif '@SOS' in sms or '@NOTICE' in sms:
sos_write(int_id(_rf_src), time.time(), sms) sos_write(int_id(_rf_src), time.time(), sms)
elif '@REM SOS' == sms: elif '@REM SOS' == sms:
os.remove('/tmp/gps_data_user_sos.txt') os.remove(emergency_sos_file)
logger.info('Removing SOS or Notice') logger.info('Removing SOS or Notice')
elif '@' and 'M-' in sms: elif '@' and 'M-' in sms:
message = re.sub('^@|.* M-|','',sms) message = re.sub('^@|.* M-|','',sms)
@ -349,7 +354,7 @@ def process_sms(_rf_src, sms):
ssid = user_settings[int_id(_rf_src)][1]['ssid'] ssid = user_settings[int_id(_rf_src)][1]['ssid']
if user_settings[int_id(_rf_src)][3]['comment'] != '': if user_settings[int_id(_rf_src)][3]['comment'] != '':
comment = user_settings[int_id(_rf_src)][3]['comment'] comment = user_settings[int_id(_rf_src)][3]['comment']
aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + icon_table + str(aprs_lon) + icon_icon + '/' + str(comment) aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:@' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + icon_table + str(aprs_lon) + icon_icon + '/' + str(comment)
logger.info(aprs_loc_packet) logger.info(aprs_loc_packet)
logger.info('User comment: ' + comment) logger.info('User comment: ' + comment)
logger.info('User SSID: ' + ssid) logger.info('User SSID: ' + ssid)
@ -485,7 +490,7 @@ class DATA_SYSTEM(HBSYSTEM):
ssid = user_settings[int_id(_rf_src)][1]['ssid'] ssid = user_settings[int_id(_rf_src)][1]['ssid']
if user_settings[int_id(_rf_src)][3]['comment'] != '': if user_settings[int_id(_rf_src)][3]['comment'] != '':
comment = user_settings[int_id(_rf_src)][3]['comment'] comment = user_settings[int_id(_rf_src)][3]['comment']
aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + icon_table + str(aprs_lon) + icon_icon + '/' + str(comment) aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:@' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + icon_table + str(aprs_lon) + icon_icon + '/' + str(comment)
logger.info(aprs_loc_packet) logger.info(aprs_loc_packet)
logger.info('User comment: ' + comment) logger.info('User comment: ' + comment)
logger.info('User SSID: ' + ssid) logger.info('User SSID: ' + ssid)
@ -581,14 +586,14 @@ class DATA_SYSTEM(HBSYSTEM):
ssid = user_settings[int_id(_rf_src)][1]['ssid'] ssid = user_settings[int_id(_rf_src)][1]['ssid']
if user_settings[int_id(_rf_src)][3]['comment'] != '': if user_settings[int_id(_rf_src)][3]['comment'] != '':
comment = user_settings[int_id(_rf_src)][3]['comment'] comment = user_settings[int_id(_rf_src)][3]['comment']
aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(loc.lat[0:7]) + str(loc.lat_dir) + icon_table + str(loc.lon[0:8]) + str(loc.lon_dir) + icon_icon + str(round(loc.true_course)).zfill(3) + '/' + str(round(loc.spd_over_grnd)).zfill(3) + '/' + str(comment) aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + ssid + '>APHBL3,TCPIP*:@' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(loc.lat[0:7]) + str(loc.lat_dir) + icon_table + str(loc.lon[0:8]) + str(loc.lon_dir) + icon_icon + str(round(loc.true_course)).zfill(3) + '/' + str(round(loc.spd_over_grnd)).zfill(3) + '/' + str(comment)
logger.info(aprs_loc_packet) logger.info(aprs_loc_packet)
logger.info('User comment: ' + comment) logger.info('User comment: ' + comment)
logger.info('User SSID: ' + ssid) logger.info('User SSID: ' + ssid)
logger.info('User icon: ' + icon_table + icon_icon) logger.info('User icon: ' + icon_table + icon_icon)
except Exception as error_exception: except Exception as error_exception:
logger.info('Error or user settings file not found, proceeding with default settings.') logger.info('Error or user settings file not found, proceeding with default settings.')
aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + str(user_ssid) + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(loc.lat[0:7]) + str(loc.lat_dir) + '/' + str(loc.lon[0:8]) + str(loc.lon_dir) + '[' + str(round(loc.true_course)).zfill(3) + '/' + str(round(loc.spd_over_grnd)).zfill(3) + '/' + aprs_comment + ' DMR ID: ' + str(int_id(_rf_src)) aprs_loc_packet = str(get_alias(int_id(_rf_src), subscriber_ids)) + '-' + str(user_ssid) + '>APHBL3,TCPIP*:@' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(loc.lat[0:7]) + str(loc.lat_dir) + '/' + str(loc.lon[0:8]) + str(loc.lon_dir) + '[' + str(round(loc.true_course)).zfill(3) + '/' + str(round(loc.spd_over_grnd)).zfill(3) + '/' + aprs_comment + ' DMR ID: ' + str(int_id(_rf_src))
logger.info(error_exception) logger.info(error_exception)
logger.info(str(traceback.extract_tb(error_exception.__traceback__))) logger.info(str(traceback.extract_tb(error_exception.__traceback__)))
try: try:
@ -671,36 +676,7 @@ if __name__ == '__main__':
# Change the current directory to the location of the application # Change the current directory to the location of the application
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
# Check if user_settings (for APRS settings of users) exists. Creat it if not.
if Path('./user_settings.txt').is_file():
pass
else:
Path('./user_settings.txt').touch()
with open("./user_settings.txt", 'w') as user_dict_file:
user_dict_file.write("{1: [{'call': 'N0CALL'}, {'ssid': ''}, {'icon': ''}, {'comment': ''}]}")
user_dict_file.close()
# Check to see if dashboard files exist
if Path('/tmp/gps_data_user_loc.txt').is_file():
pass
else:
Path('/tmp/gps_data_user_loc.txt').touch()
with open("/tmp/gps_data_user_loc.txt", 'w') as user_loc_file:
user_loc_file.write("[]")
user_loc_file.close()
if Path('/tmp/gps_data_user_bb.txt').is_file():
pass
else:
Path('/tmp/gps_data_user_bb.txt').touch()
with open("/tmp/gps_data_user_bb.txt", 'w') as user_bb_file:
user_bb_file.write("[]")
user_bb_file.close()
if Path('./gps_data_user_mailbox.txt').is_file():
pass
else:
Path('./gps_data_user_mailbox.txt').touch()
with open("./gps_data_user_mailbox.txt", 'w') as user_loc_file:
user_loc_file.write("[]")
user_loc_file.close()
# CLI argument parser - handles picking up the config file from the command line, and sending a "help" message # CLI argument parser - handles picking up the config file from the command line, and sending a "help" message
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-c', '--config', action='store', dest='CONFIG_FILE', help='/full/path/to/config.file (usually gps_data.cfg)') parser.add_argument('-c', '--config', action='store', dest='CONFIG_FILE', help='/full/path/to/config.file (usually gps_data.cfg)')
@ -731,6 +707,43 @@ if __name__ == '__main__':
smtp_server = CONFIG['GPS_DATA']['SMTP_SERVER'] smtp_server = CONFIG['GPS_DATA']['SMTP_SERVER']
smtp_port = CONFIG['GPS_DATA']['SMTP_PORT'] smtp_port = CONFIG['GPS_DATA']['SMTP_PORT']
# Dashboard files
bb_file = CONFIG['GPS_DATA']['BULLETIN_BOARD_FILE']
loc_file = CONFIG['GPS_DATA']['LOCATION_FILE']
the_mailbox_file = CONFIG['GPS_DATA']['MAILBOX_FILE']
emergency_sos_file = CONFIG['GPS_DATA']['EMERGENCY_SOS_FILE']
# Check if user_settings (for APRS settings of users) exists. Creat it if not.
if Path('./user_settings.txt').is_file():
pass
else:
Path('./user_settings.txt').touch()
with open("./user_settings.txt", 'w') as user_dict_file:
user_dict_file.write("{1: [{'call': 'N0CALL'}, {'ssid': ''}, {'icon': ''}, {'comment': ''}]}")
user_dict_file.close()
# Check to see if dashboard files exist
if Path(loc_file).is_file():
pass
else:
Path(loc_file).touch()
with open(loc_file, 'w') as user_loc_file:
user_loc_file.write("[]")
user_loc_file.close()
if Path(bb_file).is_file():
pass
else:
Path(bb_file).touch()
with open(bb_file, 'w') as user_bb_file:
user_bb_file.write("[]")
user_bb_file.close()
if Path(the_mailbox_file).is_file():
pass
else:
Path(the_mailbox_file).touch()
with open(the_mailbox_file, 'w') as user_loc_file:
user_loc_file.write("[]")
user_loc_file.close()
# Start the system logger # Start the system logger
if cli_args.LOG_LEVEL: if cli_args.LOG_LEVEL:
CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL

View File

@ -0,0 +1,83 @@
###############################################################################
# GPS/Data - Copyright (C) 2020 Eric Craw, KF7EEL <kf7eel@qsl.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
import aprslib
import ast, os
import re
from configparser import ConfigParser
import time
import argparse
def mailbox_write(call, dmr_id, time, message, recipient):
mail_file = ast.literal_eval(os.popen('cat ' + mailbox_file).read())
mail_file.insert(0, {'call': call, 'dmr_id': dmr_id, 'time': time, 'message':message, 'recipient': recipient})
with open("../../gps_data_user_mailbox.txt", 'w') as mailbox_file:
mailbox_file.write(str(mail_file[:100]))
mailbox_file.close()
print('User mail saved.')
def aprs_filter(packet):
#if aprslib.parse(packet) in aprslib.parse(packet):
# print(aprslib.parse(packet))
#else:
# pass
user_settings = ast.literal_eval(os.popen('cat ../../user_settings.txt').read())
if 'addresse' in aprslib.parse(packet):
#print(aprslib.parse(packet))
recipient = re.sub('-.*','', aprslib.parse(packet)['addresse'])
recipient_ssid = re.sub('.*-','', aprslib.parse(packet)['addresse'])
for i in user_settings.items():
## print('checking user_settings ' + recipient)
if recipient in i[1][0]['call'] and recipient_ssid in i[1][1]['ssid']:
## print(i[1][0])
## print(i[1][1])
## print(aprslib.parse(packet))
mailbox_write(re.sub('-.*','', aprslib.parse(packet)['addresse']), aprslib.parse(packet)['from'], time.time(), aprslib.parse(packet)['message_text'], recipient)
if 'msgNo' in aprslib.parse(packet):
time.sleep(1)
AIS.sendall(aprslib.parse(packet)['addresse'] + '>APHBL3,TCPIP*:' + ':' + aprslib.parse(packet)['from'].ljust(9) +':ack'+aprslib.parse(packet)['msgNo'])
print('Send ACK')
print(aprslib.parse(packet)['addresse'] + '>APHBL3,TCPIP*:' + ':' + aprslib.parse(packet)['from'].ljust(9) +':ack'+aprslib.parse(packet)['msgNo'])
## else:
## print(aprslib.parse(packet)['from'])
if __name__ == '__main__':
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('-c', '--config', action='store', dest='CONFIG_FILE', help='/full/path/to/config.file (usually gps_data.cfg)')
cli_args = arg_parser.parse_args()
parser = ConfigParser()
if not cli_args.CONFIG_FILE:
print('\n\nMust specify a config file with -c argument.\n\n')
parser.read(cli_args.CONFIG_FILE)
aprs_server = parser.get('GPS_DATA', 'APRS_SERVER')
aprs_port = parser.get('GPS_DATA', 'APRS_PORT')
aprs_login = parser.get('GPS_DATA', 'APRS_RECEIVE_LOGIN_CALL')
aprs_passcode = parser.get('GPS_DATA', 'APRS_LOGIN_PASSCODE')
mailbox_file = parser.get('GPS_DATA', 'MAILBOX_FILE')
AIS = aprslib.IS(aprs_login, passwd=int(aprs_passcode), host=aprs_server, port=int(aprs_port))
user_settings = ast.literal_eval(os.popen('cat ../../user_settings.txt').read())
print('APRS message receive script for GPS/Data Application.\nAuthor: Eric, KF7EEL - kf7eel@qsl.net')
AIS.set_filter(parser.get('GPS_DATA', 'APRS_FILTER'))
AIS.connect()
print('Connecting to APRS-IS')
AIS.consumer(aprs_filter, raw=True)

View File

@ -23,11 +23,15 @@ This is a web dashboard for the GPS/Data application.
from flask import Flask, render_template, request, Response, Markup from flask import Flask, render_template, request, Response, Markup
import ast, os import ast, os
from dashboard_settings import * #from dashboard_settings import *
import folium import folium
from folium.plugins import MarkerCluster from folium.plugins import MarkerCluster
import re import re
from datetime import datetime from datetime import datetime
import argparse
from configparser import ConfigParser
app = Flask(__name__) app = Flask(__name__)
@ -42,7 +46,7 @@ tbl_ftr = '''
def get_loc_data(): def get_loc_data():
try: try:
dash_loc = ast.literal_eval(os.popen('cat /tmp/gps_data_user_loc.txt').read()) dash_loc = ast.literal_eval(os.popen('cat ' + loc_file).read())
tmp_loc = '' tmp_loc = ''
loc_hdr = ''' loc_hdr = '''
<tr> <tr>
@ -88,7 +92,7 @@ def get_loc_data():
def get_bb_data(): def get_bb_data():
try: try:
dash_bb = ast.literal_eval(os.popen('cat /tmp/gps_data_user_bb.txt').read()) dash_bb = ast.literal_eval(os.popen('cat ' + bb_file).read())
tmp_bb = '' tmp_bb = ''
bb_hdr = ''' bb_hdr = '''
@ -132,7 +136,7 @@ def get_bb_data():
def check_emergency(): def check_emergency():
# open emergency txt # open emergency txt
try: try:
sos_file = ast.literal_eval(os.popen('cat /tmp/gps_data_user_sos.txt').read()) sos_file = ast.literal_eval(os.popen('cat ' + emergency_sos_file).read())
if type(sos_file['time']) == str: if type(sos_file['time']) == str:
loc_time = str(sos_file['time']) loc_time = str(sos_file['time'])
if type(sos_file['time']) == int or type(sos_file['time']) == float: if type(sos_file['time']) == int or type(sos_file['time']) == float:
@ -200,7 +204,7 @@ def view_map():
reload_time = request.args.get('reload') reload_time = request.args.get('reload')
track_call = request.args.get('track') track_call = request.args.get('track')
map_size = request.args.get('map_size') map_size = request.args.get('map_size')
user_loc = ast.literal_eval(os.popen('cat /tmp/gps_data_user_loc.txt').read()) user_loc = ast.literal_eval(os.popen('cat ' + loc_file).read())
last_known_list = [] last_known_list = []
try: try:
if track_call: if track_call:
@ -302,7 +306,7 @@ def view_map():
return render_template('generic.html', title = dashboard_title, logo = logo, content = Markup(content)) return render_template('generic.html', title = dashboard_title, logo = logo, content = Markup(content))
if not track_call: if not track_call:
folium_map = folium.Map(location=map_center, tiles=map_theme, zoom_start=int(zoom_level)) folium_map = folium.Map(location=(map_center_lat, map_center_lon), tiles=map_theme, zoom_start=int(zoom_level))
marker_cluster = MarkerCluster().add_to(folium_map) marker_cluster = MarkerCluster().add_to(folium_map)
for user_coord in user_loc: for user_coord in user_loc:
user_lat = aprs_to_latlon(float(re.sub('[A-Za-z]','', user_coord['lat']))) user_lat = aprs_to_latlon(float(re.sub('[A-Za-z]','', user_coord['lat'])))
@ -406,7 +410,7 @@ def user_settings():
if icon == '': if icon == '':
icon = '\[' icon = '\['
if comment == '': if comment == '':
comment = 'Default comment.' comment = default_comment + ' ' + user_id
#for result in user_settings: #for result in user_settings:
#return user_settings[int(user_id)][0] #return user_settings[int(user_id)][0]
#return user_id #return user_id
@ -448,7 +452,7 @@ def mailbox():
if not recipient: if not recipient:
mail_content = """ mail_content = """
<p>The Mailbox is a place where users can leave messages via DMR SMS. A user can leave a message for someone else by sending a specially formatted SMS to <strong>""" + data_call_id + """</strong>. <p>The Mailbox is a place where users can leave messages via DMR SMS. A user can leave a message for someone else by sending a specially formatted SMS to <strong>""" + data_call_id + """</strong>.
The message recipient can then use the mailbox to check for messages. Enter your call sign below to check for messages. See the <a href="help">help</a> page for more information.</p> The message recipient can then use the mailbox to check for messages. You can also check for APRS mesages addressed to your DMR radio. Enter your call sign below to check for messages. See the <a href="help">help</a> page for more information.</p>
<form action="mailbox" method="get"> <form action="mailbox" method="get">
<table style="margin-left: auto; margin-right: auto;"> <table style="margin-left: auto; margin-right: auto;">
<tbody> <tbody>
@ -471,17 +475,30 @@ def mailbox():
""" """
else: else:
mailbox_file = ast.literal_eval(os.popen('cat ../../gps_data_user_mailbox.txt').read()) mailbox_file = ast.literal_eval(os.popen('cat ' + the_mailbox_file).read())
mail_content = '<h2 style="text-align: center;">Messages for: ' + recipient.upper() + ''' mail_content = '<h2 style="text-align: center;">Messages for: ' + recipient.upper() + '''
</h2>\n<p style="text-align: center;"><button onclick="history.back()">Back</button></p>\n </h2>\n<p style="text-align: center;"><button onclick="history.back()">Back</button></p>\n
<h4 style="text-align: center;"><a href="mailbox_rss?recipient=''' + recipient.upper() + '''"><em>Mailbox RSS Feed for ''' + recipient.upper() + '''</em></a><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5QIcFBAOXAevLAAAAZZJREFUSMftlbtKA0EUhj8jWhi8gaIEC29oxEoRFESLgIXYiWVSKoj6CCrBBwj6CBHNE1hEWy21ETQqiIW1wXhPo81ZOBw2apbdVPvDsDPnP8M/5zKzECJEQKivYO8DFoAYEAGKtTpQEvhW4w3IA+tAVy2F9fgEskA8COHUL8LOKAMZoMmLQF0FewcwImmNAzPANBB18b0BFoGroNLfBiyLgI2+BMwF3XgNwCrwYsQ//BBPSRPdAoeybjE+A8ClS+Sjfnf1E5A2dW4FzoxfwWvD/XWd7oAxI24jz3gVnpS7eiEpt+KvQEL5D5qal/245zFgU+pnXzMd+Zrh9/3q5l7g3CXtTs0bgWvFffn5vDa7iKcVv2K4DS8i3cAOsAuMm8h12ovqqrVL/R3upFrRKPBgHgctvm0iSynuWNnf5bf6byy5dPKe4nukhg6XU9yW2TfsJlDpNCUX27OaP8pD4WBCzQtmX381EUeAI3Xqe6m5xoHpYAezJuJkNb9Fh0tI4+SlXhpTwJBaZ+XbCcwr+6kcPESI2uAHmAijFaMnEmYAAAAASUVORK5CYII=" /></h4> <h4 style="text-align: center;"><a href="mailbox_rss?recipient=''' + recipient.upper() + '''"><em>Mailbox RSS Feed for ''' + recipient.upper() + '''</em></a><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5QIcFBAOXAevLAAAAZZJREFUSMftlbtKA0EUhj8jWhi8gaIEC29oxEoRFESLgIXYiWVSKoj6CCrBBwj6CBHNE1hEWy21ETQqiIW1wXhPo81ZOBw2apbdVPvDsDPnP8M/5zKzECJEQKivYO8DFoAYEAGKtTpQEvhW4w3IA+tAVy2F9fgEskA8COHUL8LOKAMZoMmLQF0FewcwImmNAzPANBB18b0BFoGroNLfBiyLgI2+BMwF3XgNwCrwYsQ//BBPSRPdAoeybjE+A8ClS+Sjfnf1E5A2dW4FzoxfwWvD/XWd7oAxI24jz3gVnpS7eiEpt+KvQEL5D5qal/245zFgU+pnXzMd+Zrh9/3q5l7g3CXtTs0bgWvFffn5vDa7iKcVv2K4DS8i3cAOsAuMm8h12ovqqrVL/R3upFrRKPBgHgctvm0iSynuWNnf5bf6byy5dPKe4nukhg6XU9yW2TfsJlDpNCUX27OaP8pD4WBCzQtmX381EUeAI3Xqe6m5xoHpYAezJuJkNb9Fh0tI4+SlXhpTwJBaZ+XbCcwr+6kcPESI2uAHmAijFaMnEmYAAAAASUVORK5CYII=" /></h4>
''' '''
for messages in mailbox_file: for messages in mailbox_file:
if messages['recipient'] == recipient.upper(): if messages['recipient'] == recipient.upper():
sender = """
<tr>
<td style="width: 63px;"><strong>DMR ID:</strong></td>
<td style="width: 292.55px; text-align: center;">""" + str(messages['dmr_id']) + """</td>
</tr>
"""
if type(messages['time']) == str: if type(messages['time']) == str:
loc_time = str(messages['time']) loc_time = str(messages['time'])
if type(messages['time']) == int or type(messages['time']) == float: if type(messages['time']) == int or type(messages['time']) == float:
loc_time = datetime.fromtimestamp(messages['time']).strftime(time_format) loc_time = datetime.fromtimestamp(messages['time']).strftime(time_format)
if type(messages['dmr_id']) == str:
sender = """
<tr>
<td style="width: 63px;"><strong>APRS Call:</strong></td>
<td style="width: 292.55px; text-align: center;">""" + str(messages['dmr_id']) + """</td>
</tr>
"""
mail_content = mail_content + """ mail_content = mail_content + """
<table style="margin-left: auto; margin-right: auto; width: 372.55px;" border="1"> <table style="margin-left: auto; margin-right: auto; width: 372.55px;" border="1">
<tbody> <tbody>
@ -489,10 +506,7 @@ def mailbox():
<td style="width: 63px;"><strong>From:</strong></td> <td style="width: 63px;"><strong>From:</strong></td>
<td style="text-align: center; width: 292.55px;"><strong>""" + messages['call'] + """</strong></td> <td style="text-align: center; width: 292.55px;"><strong>""" + messages['call'] + """</strong></td>
</tr> </tr>
<tr> """ + sender + """
<td style="width: 63px;"><strong>DMR ID:</strong></td>
<td style="width: 292.55px; text-align: center;">""" + str(messages['dmr_id']) + """</td>
</tr>
<tr> <tr>
<td style="width: 63px;"><strong>Time:</strong></td> <td style="width: 63px;"><strong>Time:</strong></td>
<td style="width: 292.55px; text-align: center;">""" + loc_time + """</td> <td style="width: 292.55px; text-align: center;">""" + loc_time + """</td>
@ -508,10 +522,11 @@ def mailbox():
""" """
return render_template('generic.html', title = dashboard_title, logo = logo, content = Markup(mail_content)) return render_template('generic.html', title = dashboard_title, logo = logo, content = Markup(mail_content))
@app.route('/bulletin_rss.xml') @app.route('/bulletin_rss.xml')
def bb_rss(): def bb_rss():
try: try:
dash_bb = ast.literal_eval(os.popen('cat /tmp/gps_data_user_bb.txt').read()) dash_bb = ast.literal_eval(os.popen('cat ' + bb_file).read())
post_data = '' post_data = ''
rss_header = """<?xml version="1.0" encoding="UTF-8" ?> rss_header = """<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0"> <rss version="2.0">
@ -532,12 +547,13 @@ def bb_rss():
</item> </item>
""" """
return Response(rss_header + post_data + "\n</channel>\n</rss>", mimetype='text/xml') return Response(rss_header + post_data + "\n</channel>\n</rss>", mimetype='text/xml')
except: except Exception as e:
return str('<h1 style="text-align: center;">No data</h1>') #return str('<h1 style="text-align: center;">No data</h1>')
return str(e)
@app.route('/mailbox_rss') @app.route('/mailbox_rss')
def mail_rss(): def mail_rss():
mailbox_file = ast.literal_eval(os.popen('cat ../../gps_data_user_mailbox.txt').read()) mailbox_file = ast.literal_eval(os.popen('cat ' + the_mailbox_file).read())
post_data = '' post_data = ''
recipient = request.args.get('recipient').upper() recipient = request.args.get('recipient').upper()
rss_header = """<?xml version="1.0" encoding="UTF-8" ?> rss_header = """<?xml version="1.0" encoding="UTF-8" ?>
@ -562,4 +578,64 @@ def mail_rss():
return Response(rss_header + post_data + "\n</channel>\n</rss>", mimetype='text/xml') return Response(rss_header + post_data + "\n</channel>\n</rss>", mimetype='text/xml')
if __name__ == '__main__': if __name__ == '__main__':
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('-c', '--config', action='store', dest='CONFIG_FILE', help='/full/path/to/config.file (usually gps_data.cfg)')
cli_args = arg_parser.parse_args()
parser = ConfigParser()
if not cli_args.CONFIG_FILE:
print('\n\nMust specify a config file with -c argument.\n\n')
parser.read(cli_args.CONFIG_FILE)
###### Definitions #####
# Title of the Dashboard
dashboard_title = parser.get('GPS_DATA', 'DASHBOARD_TITLE')
# Logo used on dashboard page
logo = parser.get('GPS_DATA', 'LOGO')
dash_port = int(parser.get('GPS_DATA', 'DASH_PORT'))
# IP to run server on
dash_host = parser.get('GPS_DATA', 'DASH_HOST')
#Description of dashboard to show on main page
description = parser.get('GPS_DATA', 'DESCRIPTION')
# The following will generate a help page for your users.
# Data call type
if parser.get('GPS_DATA', 'CALL_TYPE') == 'unit':
data_call_type = 'Private Call'
if parser.get('GPS_DATA', 'CALL_TYPE') == 'group':
data_call_type = 'Group Call'
if parser.get('GPS_DATA', 'CALL_TYPE') == 'both':
data_call_type = 'Private or Group Call'
# DMR ID of GPS/Data application
data_call_id = parser.get('GPS_DATA', 'DATA_DMR_ID')
# Default APRS ssid
aprs_ssid = parser.get('GPS_DATA', 'USER_APRS_SSID')
# Gateway contact info displayed on about page.
contact_name = parser.get('GPS_DATA', 'CONTACT_NAME')
contact_call = parser.get('GPS_DATA', 'CONTACT_CALL')
contact_email = parser.get('GPS_DATA', 'CONTACT_EMAIL')
contact_website = parser.get('GPS_DATA', 'CONTACT_WEBSITE')
# Center dashboard map over these coordinates
map_center_lat = float(parser.get('GPS_DATA', 'MAP_CENTER_LAT'))
map_center_lon = float(parser.get('GPS_DATA', 'MAP_CENTER_LON'))
zoom_level = int(parser.get('GPS_DATA', 'ZOOM_LEVEL'))
map_theme = parser.get('GPS_DATA', 'MAP_THEME')
# Time format for display
time_format = parser.get('GPS_DATA', 'TIME_FORMAT')
# RSS feed link, shows in the link section of each RSS item.
rss_link = parser.get('GPS_DATA', 'RSS_LINK')
# Default APRS comment for users.
default_comment = parser.get('GPS_DATA', 'USER_APRS_COMMENT')
# DO NOT MODIFY BELOW HERE.
bb_file = parser.get('GPS_DATA', 'BULLETIN_BOARD_FILE')
loc_file = parser.get('GPS_DATA', 'LOCATION_FILE')
emergency_sos_file = parser.get('GPS_DATA', 'EMERGENCY_SOS_FILE')
the_mailbox_file = parser.get('GPS_DATA', 'MAILBOX_FILE')
########################
app.run(debug = True, port=dash_port, host=dash_host) app.run(debug = True, port=dash_port, host=dash_host)