This commit is contained in:
KF7EEL 2020-12-23 15:27:59 -08:00
parent f6a501a42e
commit 11e5aba3fc

175
hblink.py
View File

@ -27,6 +27,9 @@ works stand-alone before troubleshooting any applications that use it. It has
sufficient logging to be used standalone as a troubleshooting application. sufficient logging to be used standalone as a troubleshooting application.
''' '''
# Added config option for APRS in the master config section. Will only send packets to APRS-IS if each master is enabled.
# Modified by KF7EEL - 10-15-2020
# Specifig functions from modules we need # Specifig functions from modules we need
from binascii import b2a_hex as ahex from binascii import b2a_hex as ahex
from binascii import a2b_hex as bhex from binascii import a2b_hex as bhex
@ -35,6 +38,9 @@ from hashlib import sha256, sha1
from hmac import new as hmac_new, compare_digest from hmac import new as hmac_new, compare_digest
from time import time from time import time
from collections import deque from collections import deque
import aprslib
import os
# Twisted is pretty important, so I keep it separate # Twisted is pretty important, so I keep it separate
from twisted.internet.protocol import DatagramProtocol, Factory, Protocol from twisted.internet.protocol import DatagramProtocol, Factory, Protocol
@ -66,6 +72,91 @@ __email__ = 'n0mjs@me.com'
# Global variables used whether we are a module or __main__ # Global variables used whether we are a module or __main__
systems = {} systems = {}
open("nom_aprs","w").close
file_config=config.build_config('hblink.cfg')
def sendAprs():
AIS = aprslib.IS(str(file_config['APRS']['CALLSIGN']), passwd=aprslib.passcode(str(file_config['APRS']['CALLSIGN'])), host=str(file_config['APRS']['SERVER']), port=14580)
AIS.connect()
f = open('nom_aprs', 'r')
lines = f.readlines()
if lines:
for line in lines:
if line != ' ':
lat_verso = ''
lon_verso = ''
dati = line.split(":")
d1_c = int(float(dati[4]))
d2_c = int(float(dati[5]))
if d1_c < 0:
d1 = abs(d1_c)
dm1=abs(float(dati[4])) - d1
dm1_s= float(dm1) * 60
dm1_u="{:.4f}".format(dm1_s)
if d1 < 10 and d1 > -10:
lat_utile='0'+str(d1)+str(dm1_u)
else:
lat_utile = str(d1)+str(dm1_u)
lat_verso = 'S'
else:
d1 = int(float(dati[4]))
dm1=float(dati[4]) - d1
dm1_s= float(dm1) * 60
dm1_u="{:.4f}".format(dm1_s)
if d1 < 10 and d1 > -10:
lat_utile='0'+str(d1)+str(dm1_u)
else:
lat_utile = str(d1)+str(dm1_u)
lat_verso = 'N'
if d2_c < 0:
d2=abs(d2_c)
dm2=abs(float(dati[5])) - d2
dm2_s= float(dm2) * 60
dm2_u="{:.3f}".format(dm2_s)
if d2 < 10 and d2 > -10:
lon_utile = '00'+str(d2)+str(dm2_u)
elif d2 < 100:
lon_utile = '0'+str(d2)+str(dm2_u)
else:
lon_utile = str(d2)+str(dm2_s)
lon_verso = 'W'
else:
d2=int(float(dati[5]))
dm2=float(dati[5]) - d2
dm2_s= float(dm2) * 60
dm2_u="{:.3f}".format(dm2_s)
if d2 < 10 and d2 > -10:
lon_utile = '00'+str(d2)+str(dm2_u)
elif d2 < 100:
lon_utile = '0'+str(d2)+str(dm2_u)
else:
lon_utile = str(d2)+str(dm2_u)
lon_verso = 'E'
rx_utile = dati[2][0:3]+'.'+dati[2][3:]
tx_utile = dati[3][0:3]+'.'+dati[3][3:]
if self._config['APRS_ENABLED']:
AIS.sendall(str(dati[0])+">APRS,TCPIP*,qAC,"+str(file_config['APRS']['CALLSIGN'])+":!"+str(lat_utile)[:-2]+lat_verso+"/"+str(lon_utile)[:-1]+lon_verso+"r"+str(file_config['APRS']['MESSAGE'])+' RX: '+str(rx_utile)+' TX: '+str(tx_utile))
logging.info('APRS INVIATO/APRS Sent')
else:
pass
if file_config['APRS']['ENABLED']:
if int(file_config['APRS']['REPORT_INTERVAL']) >= 10:
l=task.LoopingCall(sendAprs)
l.start(int(file_config['APRS']['REPORT_INTERVAL'])*60)
else:
l=task.LoopingCall(sendAprs)
l.start(15*60)
logger.info('Report Time APRS to short')
# Timed loop used for reporting HBP status # Timed loop used for reporting HBP status
def config_reports(_config, _factory): def config_reports(_config, _factory):
def reporting_loop(_logger, _server): def reporting_loop(_logger, _server):
@ -80,10 +171,10 @@ def config_reports(_config, _factory):
reporting = task.LoopingCall(reporting_loop, logger, report_server) reporting = task.LoopingCall(reporting_loop, logger, report_server)
reporting.start(_config['REPORTS']['REPORT_INTERVAL']) reporting.start(_config['REPORTS']['REPORT_INTERVAL'])
return report_server return report_server
# Shut ourselves down gracefully by disconnecting from the masters and peers. # Shut ourselves down gracefully by disconnecting from the masters and peers.
def hblink_handler(_signal, _frame): def hblink_handler(_signal, _frame):
for system in systems: for system in systems:
@ -104,6 +195,7 @@ def acl_check(_id, _acl):
# OPENBRIDGE CLASS # OPENBRIDGE CLASS
#************************************************ #************************************************
class OPENBRIDGE(DatagramProtocol): class OPENBRIDGE(DatagramProtocol):
def __init__(self, _name, _config, _report): def __init__(self, _name, _config, _report):
# Define a few shortcuts to make the rest of the class more readable # Define a few shortcuts to make the rest of the class more readable
@ -112,7 +204,9 @@ class OPENBRIDGE(DatagramProtocol):
self._report = _report self._report = _report
self._config = self._CONFIG['SYSTEMS'][self._system] self._config = self._CONFIG['SYSTEMS'][self._system]
self._laststrid = deque([], 20) self._laststrid = deque([], 20)
def dereg(self): def dereg(self):
logger.info('(%s) is mode OPENBRIDGE. No De-Registration required, continuing shutdown', self._system) logger.info('(%s) is mode OPENBRIDGE. No De-Registration required, continuing shutdown', self._system)
@ -474,8 +568,19 @@ class HBSYSTEM(DatagramProtocol):
and self._peers[_peer_id]['SOCKADDR'] == _sockaddr: and self._peers[_peer_id]['SOCKADDR'] == _sockaddr:
logger.info('(%s) Peer is closing down: %s (%s)', self._system, self._peers[_peer_id]['CALLSIGN'], int_id(_peer_id)) logger.info('(%s) Peer is closing down: %s (%s)', self._system, self._peers[_peer_id]['CALLSIGN'], int_id(_peer_id))
self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr) self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
if self._CONFIG['APRS']['ENABLED']:
#if self._config['APRS_ENABLED'] == True:
fn = 'nom_aprs'
f = open(fn)
output = []
for line in f:
if not str(int_id(_peer_id)) in line:
output.append(line)
f.close()
f = open(fn, 'w')
f.writelines(output)
f.close()
del self._peers[_peer_id] del self._peers[_peer_id]
else: else:
_peer_id = _data[4:8] # Configure Command _peer_id = _data[4:8] # Configure Command
if _peer_id in self._peers \ if _peer_id in self._peers \
@ -502,6 +607,48 @@ class HBSYSTEM(DatagramProtocol):
self.send_peer(_peer_id, b''.join([RPTACK, _peer_id])) 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']) logger.info('(%s) Peer %s (%s) has sent repeater configuration', self._system, _this_peer['CALLSIGN'], _this_peer['RADIO_ID'])
#APRS IMPLEMENTATION
conta = 0
lista_blocco=['ysf', 'xlx', 'nxdn', 'dstar', 'echolink','p25', 'svx', 'l1nk']
#if self._CONFIG['SYSTEMS']['APRS_ENABLED']['ENABLED'] and self._CONFIG['APRS']['ENABLED'] and not str(_this_peer['CALLSIGN'].decode('UTF-8')).replace(' ', '').isalpha() :
# Check if master has APRS enabled instead of global.
if self._CONFIG['APRS']['ENABLED'] and not str(_this_peer['CALLSIGN'].decode('UTF-8')).replace(' ', '').isalpha() :
file = open("nom_aprs","r")
linee = file.readlines()
file.close()
for link in lista_blocco:
if int(str(_this_peer['CALLSIGN'].decode('UTF-8')).replace(' ', '').find(link.upper())) == 0:
conta = conta + 1
if len(linee) > 0:
logging.info('Leggo')
for linea in linee:
dati_l = linea.split(':')
if str(_this_peer['RADIO_ID']) == str(dati_l[1]):
conta = conta + 1
if conta == 0:
file=open("nom_aprs",'a')
if len(str(_this_peer['RADIO_ID'])) > 7:
id_pr=int(str(_this_peer['RADIO_ID'])[-2:])
callsign_u=str(_this_peer['CALLSIGN'].decode('UTF-8'))+"-"+str(id_pr)
file.write(callsign_u.replace(' ', '')+ ":"+ str(_this_peer['RADIO_ID']) +":"+ str(_this_peer['RX_FREQ'].decode('UTF-8')) + ":" + str(_this_peer['TX_FREQ'].decode('UTF-8'))+ ":" + str(_this_peer['LATITUDE'].decode('UTF-8')) + ":" + str(_this_peer['LONGITUDE'].decode('UTF-8')) + "\n")
file.close()
else:
file.write(str(_this_peer['CALLSIGN'].decode('UTF-8')).replace(' ', '')+ ":"+ str(_this_peer['RADIO_ID']) +":"+ str(_this_peer['RX_FREQ'].decode('UTF-8')) + ":" + str(_this_peer['TX_FREQ'].decode('UTF-8'))+ ":" + str(_this_peer['LATITUDE'].decode('UTF-8')) + ":" + str(_this_peer['LONGITUDE'].decode('UTF-8')) + "\n")
file.close()
else:
if conta == 0:
file=open("nom_aprs",'a')
if len(str(_this_peer['RADIO_ID'])) > 7:
id_pr=int(str(_this_peer['RADIO_ID'])[-2:])
callsign_u=str(_this_peer['CALLSIGN'].decode('UTF-8'))+"-"+str(id_pr)
file.write(callsign_u.replace(' ', '')+ ":"+ str(_this_peer['RADIO_ID']) +":"+ str(_this_peer['RX_FREQ'].decode('UTF-8')) + ":" + str(_this_peer['TX_FREQ'].decode('UTF-8'))+ ":" + str(_this_peer['LATITUDE'].decode('UTF-8')) + ":" + str(_this_peer['LONGITUDE'].decode('UTF-8')) + "\n")
file.close()
else:
file.write(str(_this_peer['CALLSIGN'].decode('UTF-8')).replace(' ', '')+ ":"+ str(_this_peer['RADIO_ID']) +":"+ str(_this_peer['RX_FREQ'].decode('UTF-8')) + ":" + str(_this_peer['TX_FREQ'].decode('UTF-8'))+ ":" + str(_this_peer['LATITUDE'].decode('UTF-8')) + ":" + str(_this_peer['LONGITUDE'].decode('UTF-8')) + "\n")
file.close()
else: else:
self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr) self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
logger.warning('(%s) Peer info from Radio ID that has not logged in: %s', self._system, int_id(_peer_id)) logger.warning('(%s) Peer info from Radio ID that has not logged in: %s', self._system, int_id(_peer_id))
@ -519,18 +666,6 @@ class HBSYSTEM(DatagramProtocol):
self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr) self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
logger.warning('(%s) Ping from Radio ID that is not logged in: %s', self._system, int_id(_peer_id)) logger.warning('(%s) Ping from Radio ID that is not logged in: %s', self._system, int_id(_peer_id))
elif _command == RPTO:
_peer_id = _data[4:8]
if _peer_id in self._peers \
and self._peers[_peer_id]['CONNECTION'] == 'YES' \
and self._peers[_peer_id]['SOCKADDR'] == _sockaddr:
logger.info('(%s) Peer %s (%s) has send options: %s', self._system, self._peers[_peer_id]['CALLSIGN'], int_id(_peer_id), _data[8:])
self.transport.write(b''.join([RPTACK, _peer_id]), _sockaddr)
elif _command == DMRA:
_peer_id = _data[4:8]
logger.info('(%s) Recieved DMR Talker Alias from peer %s, subscriber %s', self._system, self._peers[_peer_id]['CALLSIGN'], int_id(_rf_src))
else: else:
logger.error('(%s) Unrecognized command. Raw HBP PDU: %s', self._system, ahex(_data)) logger.error('(%s) Unrecognized command. Raw HBP PDU: %s', self._system, ahex(_data))
@ -660,7 +795,6 @@ class HBSYSTEM(DatagramProtocol):
self._stats['CONNECTION'] = 'YES' self._stats['CONNECTION'] = 'YES'
self._stats['CONNECTED'] = time() self._stats['CONNECTED'] = time()
logger.info('(%s) Connection to Master Completed', self._system) logger.info('(%s) Connection to Master Completed', self._system)
# If we are an XLX, send the XLX module request here. # If we are an XLX, send the XLX module request here.
if self._config['MODE'] == 'XLXPEER': if self._config['MODE'] == 'XLXPEER':
self.send_xlxmaster(self._config['RADIO_ID'], int(4000), self._config['MASTER_SOCKADDR']) self.send_xlxmaster(self._config['RADIO_ID'], int(4000), self._config['MASTER_SOCKADDR'])
@ -781,6 +915,8 @@ if __name__ == '__main__':
import sys import sys
import os import os
import signal import signal
import aprslib
import threading
# 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])))
@ -802,12 +938,12 @@ if __name__ == '__main__':
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
logger = log.config_logging(CONFIG['LOGGER']) logger = log.config_logging(CONFIG['LOGGER'])
logger.info('\n\nCopyright (c) 2013, 2014, 2015, 2016, 2018, 2019, 2020\n\tThe Regents of the K0USY Group. All rights reserved.\n') logger.info('APRS IMPLEMENTATION BY IU7IGU email: iu7igu@yahoo.com \n APRS per master config by KF7EEL - KF7EEL@qsl.net \n\nCopyright (c) 2013, 2014, 2015, 2016, 2018, 2019, 2020\n\tThe Regents of the K0USY Group. All rights reserved.')
logger.debug('(GLOBAL) Logging system started, anything from here on gets logged') logger.debug('(GLOBAL) Logging system started, anything from here on gets logged')
# Set up the signal handler # Set up the signal handler
def sig_handler(_signal, _frame): def sig_handler(_signal, _frame):
logger.info('(GLOBAL) SHUTDOWN: HBLINK IS TERMINATING WITH SIGNAL %s', str(_signal)) logger.info('(GLOBAL) SHUTDOWN: HBLINK IS TERMINATING WITH SIGNAL %s', str(_signal))
hblink_handler(_signal, _frame) hblink_handler(_signal, _frame)
logger.info('(GLOBAL) SHUTDOWN: ALL SYSTEM HANDLERS EXECUTED - STOPPING REACTOR') logger.info('(GLOBAL) SHUTDOWN: ALL SYSTEM HANDLERS EXECUTED - STOPPING REACTOR')
reactor.stop() reactor.stop()
@ -833,7 +969,10 @@ if __name__ == '__main__':
systems[system] = OPENBRIDGE(system, CONFIG, report_server) systems[system] = OPENBRIDGE(system, CONFIG, report_server)
else: else:
systems[system] = HBSYSTEM(system, CONFIG, report_server) systems[system] = HBSYSTEM(system, CONFIG, report_server)
logger.info(CONFIG['SYSTEMS'][system]['APRS_ENABLED'])
reactor.listenUDP(CONFIG['SYSTEMS'][system]['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['IP']) reactor.listenUDP(CONFIG['SYSTEMS'][system]['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['IP'])
logger.debug('(GLOBAL) %s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system]) logger.debug('(GLOBAL) %s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system])
reactor.run() reactor.run()