From 19b32cfc6797361addfa0fdfe7e812b11a3b67ce Mon Sep 17 00:00:00 2001 From: KF7EEL Date: Tue, 15 Mar 2022 13:54:12 -0700 Subject: [PATCH] hotspot APRS position, initial commit --- bridge.py | 37 ++++++++++++++++++++++++++++++--- data_gateway.py | 53 ++++++++++++++++++++++++++++++++++++++++------- hblink-SAMPLE.cfg | 1 + hblink.py | 30 +++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 10 deletions(-) diff --git a/bridge.py b/bridge.py index 8920f8c..309492b 100755 --- a/bridge.py +++ b/bridge.py @@ -75,6 +75,8 @@ from socket import gethostbyname from setproctitle import setproctitle import copy +from pathlib import Path + @@ -430,6 +432,14 @@ def config_reports(_config, _factory): reporting.start(_config['REPORTS']['REPORT_INTERVAL']) return report_server +# Send peer data that needs to be sent to APRS +def svrd_send_aprs_peer(_svrd_data): + _svrd_packet = SVRD + for system in CONFIG['SYSTEMS']: + if CONFIG['SYSTEMS'][system]['ENABLED']: + if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE': + if 'PEER_APRS' in CONFIG['SYSTEMS'][system]['OTHER_OPTIONS']: + systems[system].send_system(SVRD + b'APRS' + str.encode(str(_svrd_data))) # Send data to all OBP connections that have an encryption key. Data such as subscribers are sent to other HBNet servers. def svrd_send_all(_svrd_data): @@ -445,8 +455,8 @@ def mirror_traffic(_data): for system in CONFIG['SYSTEMS']: if CONFIG['SYSTEMS'][system]['ENABLED']: if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE': - print(CONFIG['SYSTEMS'][system]['OTHER_OPTIONS']) - if 'MIRROR_ALL_TRAFFIC' in CONFIG['SYSTEMS'][system]['OTHER_OPTIONS']: +## print(CONFIG['SYSTEMS'][system]['OTHER_OPTIONS']) + if 'MIRROR_DATA' in CONFIG['SYSTEMS'][system]['OTHER_OPTIONS']: systems[system].send_system(SVRD + b'MDAT' + _data) @@ -526,6 +536,7 @@ def ten_loop_func(): # Run this every minute for rule timer updates def rule_timer_loop(unit_flood_time): global UNIT_MAP +## print(HBSYSTEM('HOTSPOT', CONFIG, '')._peers) logger.debug('(ROUTER) routerHBP Rule timer loop started') _now = time() #This is a good place to get and modify rules for users @@ -582,13 +593,24 @@ def rule_timer_loop(unit_flood_time): if CONFIG['REPORTS']['REPORT']: report_server.send_clients(b'bridge updated') + # Send PEER info to data gateway for APRS packet generation + try: + for system in CONFIG['SYSTEMS']: + if CONFIG['SYSTEMS'][system]['ENABLED']: + if CONFIG['SYSTEMS'][system]['MODE'] == 'MASTER' or CONFIG['SYSTEMS'][system]['MODE'] == 'PROXY': + if CONFIG['SYSTEMS'][system]['STATIC_APRS_POSITION_ENABLED'] == True: + dict_data = ast.literal_eval(os.popen('cat /tmp/' + (CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/' + system)).read()) + svrd_send_aprs_peer(dict_data) + except Exception as e: + logger.error(e) + # run this every 10 seconds to trim orphaned stream ids def stream_trimmer_loop(): ping(CONFIG) logger.debug('(ROUTER) Trimming inactive stream IDs from system lists') _now = time() - + for system in systems: # HBP systems, master and peer if CONFIG['SYSTEMS'][system]['MODE'] != 'OPENBRIDGE': @@ -1593,6 +1615,7 @@ if __name__ == '__main__': logger.info('(GLOBAL) SHUTDOWN: CONFBRIDGE IS TERMINATING WITH SIGNAL %s', str(_signal)) hblink_handler(_signal, _frame) logger.info('(GLOBAL) SHUTDOWN: ALL SYSTEM HANDLERS EXECUTED - STOPPING REACTOR') + os.popen('rm /tmp/' + (CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/*')) reactor.stop() # Set signal handers so that we can gracefully exit if need be @@ -1733,4 +1756,12 @@ if __name__ == '__main__': ## if LOCAL_CONFIG['WEB_SERVICE']['REMOTE_CONFIG_ENABLED']: ## with open(CONFIG['WEB_SERVICE']['BURN_FILE'], 'w') as f: ## f.write(str(download_burnlist(CONFIG))) + + # Create folder so hbnet.py can access list PEER connections + print(CONFIG['LOGGER']['LOG_NAME']) + if Path('/tmp/' + (CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/')).exists(): + pass + else: + Path('/tmp/' + (CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/')).mkdir() + reactor.run() diff --git a/data_gateway.py b/data_gateway.py index f6e2e44..9abee35 100644 --- a/data_gateway.py +++ b/data_gateway.py @@ -53,7 +53,6 @@ logger = logging.getLogger(__name__) #### Modules for data gateway ### # modules from DATA_CONFIG.py -from bitarray import bitarray from binascii import b2a_hex as ahex import re ##from binascii import a2b_hex as bhex @@ -79,11 +78,6 @@ try: import maidenhead as mh except: logger.error('Error importing maidenhead module, make sure it is installed.') -# Module for sending email -try: - import smtplib -except: - logger.error('Error importing smtplib module, make sure it is installed.') #Modules for APRS settings import ast @@ -134,6 +128,8 @@ packet_assembly = {} pistar_overflow = 0.1 +peer_aprs = {} + # Keep track of what user needs which SMS format def sms_type(sub, sms): @@ -1645,6 +1641,8 @@ def aprs_beacon_send(): aprslib.parse(beacon_packet) aprs_send(beacon_packet) logger.debug(beacon_packet) + peer_aprs_packets() + logger.info('Uploaded PEER APRS positions') ##### DMR data function #### def data_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, mirror = False): @@ -1965,7 +1963,42 @@ def rule_timer_loop(): logger.error('Send que error') logger.error(e) +def peer_aprs_packets(): + for i in peer_aprs.items(): + for h in i[1].items(): + lat = decdeg2dms(float(h[1]['lat'])) + lon = decdeg2dms(float(h[1]['lon'])) + if lon[0] < 0: + lon_dir = 'W' + if lon[0] > 0: + lon_dir = 'E' + if lat[0] < 0: + lat_dir = 'S' + if lat[0] > 0: + lat_dir = 'N' + aprs_lat = str(str(re.sub('\..*|-', '', str(lat[0]))).zfill(2) + str(re.sub('\..*', '', str(lat[1])).zfill(2) + '.')) + str(re.sub('\..*', '', str(lat[2])).zfill(2)) + lat_dir + aprs_lon = str(str(re.sub('\..*|-', '', str(lon[0]))).zfill(3) + str(re.sub('\..*', '', str(lon[1])).zfill(2) + '.')) + str(re.sub('\..*', '', str(lon[2])).zfill(2)) + lon_dir + + if len(str(h[0])) > 7: + ending = int(str(h[0])[-2:]) + if ending in range(1, 25): + ssid = str(string.ascii_uppercase[ending - 1]) + else: + ssid = 'A' + else: + ssid = 'A' + aprs_loc_packet = str(h[1]['call'] + '-' + ssid + '>APHBL3,TCPIP*:/' + str(datetime.datetime.utcnow().strftime("%H%M%Sh")) + str(aprs_lat) + '\\' + str(aprs_lon) + '&' + '/' + str(h[0]) + ' - ' + str(h[1]['description'])) + logger.debug(aprs_loc_packet) + try: + aprslib.parse(aprs_loc_packet) + aprs_send(aprs_loc_packet) + except Exception as e: + logger.error(e) + +## +## print(lat) +#### print(lon) class OBP(OPENBRIDGE): @@ -1995,8 +2028,14 @@ class OBP(OPENBRIDGE): def svrd_received(self, _mode, _data): logger.debug('SVRD RCV') + print(_mode) if _mode == b'UNIT': - UNIT_MAP[_data] = (self._system, time()) + UNIT_MAP[_data] = (self._system, time()) + if _mode == b'APRS': +## print(_data) +## print(self._system) + peer_aprs[self._system] = ast.literal_eval(_data.decode('utf-8')) + if _mode == b'DATA' or _mode == b'MDAT': ## print(ahex(_data)) # DMR Data packet, sent via SVRD diff --git a/hblink-SAMPLE.cfg b/hblink-SAMPLE.cfg index ae50f4c..5bd30f1 100755 --- a/hblink-SAMPLE.cfg +++ b/hblink-SAMPLE.cfg @@ -87,6 +87,7 @@ REPORT_CLIENTS: 127.0.0.1 LOG_FILE: /tmp/hblink.log LOG_HANDLERS: console-timed LOG_LEVEL: DEBUG +# If running multiple HBNet servers on same host, LOG_NAME must be unique. LOG_NAME: HBlink # DOWNLOAD AND IMPORT SUBSCRIBER, PEER and TGID ALIASES diff --git a/hblink.py b/hblink.py index 1f68804..37b92ea 100755 --- a/hblink.py +++ b/hblink.py @@ -66,6 +66,9 @@ import re # Encryption library from cryptography.fernet import Fernet +from pathlib import Path + + # Does anybody read this stuff? There's a PEP somewhere that says I should do this. __author__ = 'Cortney T. Buffington, N0MJS' @@ -91,6 +94,17 @@ def decrypt_packet(key, message): return token +def write_peer_file(master, peer_dict, CONFIG): + # Pull stuff for aprs out + print(peer_dict) + new_peers = {} + for d in peer_dict.items(): + print(d[1]) + new_peers[int_id(d[0])] = {'call': str(d[1]['CALLSIGN'].decode('utf-8')).strip(' '), 'lat':str(d[1]['LATITUDE'].decode('utf-8')), 'lon':str(d[1]['LONGITUDE'].decode('utf-8')), 'description':str(d[1]['DESCRIPTION'].decode('utf-8'))} + with open('/tmp/' + CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/' + master, 'w') as peer_file: + peer_file.write(str(new_peers)) + peer_file.close() + # Timed loop used for reporting HBP status def config_reports(_config, _factory): def reporting_loop(_logger, _server): @@ -280,6 +294,7 @@ class OPENBRIDGE(DatagramProtocol): class HBSYSTEM(DatagramProtocol): def __init__(self, _name, _config, _report): + # Define a few shortcuts to make the rest of the class more readable self._CONFIG = _config self._system = _name @@ -434,6 +449,7 @@ class HBSYSTEM(DatagramProtocol): # Aliased in __init__ to maintenance_loop if system is a master def master_maintenance_loop(self): + print(self._peers) logger.debug('(%s) Master maintenance loop started', self._system) remove_list = [] for peer in self._peers: @@ -724,6 +740,8 @@ class HBSYSTEM(DatagramProtocol): self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr) self.send_peer_loc(_peer_id, self._peers[_peer_id]['CALLSIGN'], '*', '*', '*', '*', '*', '*') del self._peers[_peer_id] + #open, remove, and write change + write_peer_file(self._system, self._peers, self._CONFIG) else: _peer_id = _data[4:8] # Configure Command @@ -751,11 +769,14 @@ class HBSYSTEM(DatagramProtocol): self.send_peer(_peer_id, b''.join([RPTACK, _peer_id])) logger.info('(%s) Peer %s (%s) has sent repeater configuration', self._system, _this_peer['CALLSIGN'], _this_peer['RADIO_ID']) + if 'NO_MAP' in str(_this_peer['LOCATION']): self.send_peer_loc(_peer_id, self._peers[_peer_id]['CALLSIGN'], '*', '*', '*', '*', '*', '*') ## print(_this_peer['LOCATION']) ## pass else: + # Function to open and write dict here + write_peer_file(self._system, self._peers, self._CONFIG) self.send_peer_loc(_peer_id, _this_peer['CALLSIGN'], _this_peer['LATITUDE'], _this_peer['LONGITUDE'], _this_peer['URL'], _this_peer['DESCRIPTION'], _this_peer['LOCATION'], str(_this_peer['PACKAGE_ID']) + ' - ' + str(_this_peer['SOFTWARE_ID'])) else: self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr) @@ -784,6 +805,8 @@ class HBSYSTEM(DatagramProtocol): ## self.mmdvm_cmd(_data) if 'NO_MAP' in str(_data[8:]): self.send_peer_loc(_peer_id, self._peers[_peer_id]['CALLSIGN'], '*', '*', '*', '*', '*', '*') + elif 'NO_MAP' not in str(_data[8:]): + write_peer_file(self._system, self._peers, self._CONFIG) self.transport.write(b''.join([RPTACK, _peer_id]), _sockaddr) elif _command == DMRA: @@ -1073,6 +1096,7 @@ if __name__ == '__main__': logger.info('(GLOBAL) SHUTDOWN: HBLINK IS TERMINATING WITH SIGNAL %s', str(_signal)) hblink_handler(_signal, _frame) logger.info('(GLOBAL) SHUTDOWN: ALL SYSTEM HANDLERS EXECUTED - STOPPING REACTOR') + os.popen('rm /tmp/' + (CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/*')) reactor.stop() # Set signal handers so that we can gracefully exit if need be @@ -1104,4 +1128,10 @@ if __name__ == '__main__': with open(CONFIG['WEB_SERVICE']['BURN_FILE'], 'w') as f: f.write(str(download_burnlist(CONFIG))) + # Create folder so hbnet.py can access list PEER connections + if Path('/tmp/' + (CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/')).exists(): + pass + else: + Path('/tmp/' + (CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/')).mkdir() + reactor.run()