APRS IMPLEMENTATION
This commit is contained in:
		
							parent
							
								
									08f6669bd3
								
							
						
					
					
						commit
						f70fc26707
					
				
							
								
								
									
										10
									
								
								config.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								config.py
									
									
									
									
									
								
							@ -104,6 +104,7 @@ def build_config(_config_file):
 | 
			
		||||
 | 
			
		||||
    CONFIG = {}
 | 
			
		||||
    CONFIG['GLOBAL'] = {}
 | 
			
		||||
    CONFIG['APRS'] = {}
 | 
			
		||||
    CONFIG['REPORTS'] = {}
 | 
			
		||||
    CONFIG['LOGGER'] = {}
 | 
			
		||||
    CONFIG['ALIASES'] = {}
 | 
			
		||||
@ -122,6 +123,15 @@ def build_config(_config_file):
 | 
			
		||||
                    'TG1_ACL': config.get(section, 'TGID_TS1_ACL'),
 | 
			
		||||
                    'TG2_ACL': config.get(section, 'TGID_TS2_ACL')
 | 
			
		||||
                })
 | 
			
		||||
                
 | 
			
		||||
            elif section == 'APRS':
 | 
			
		||||
                CONFIG['APRS'].update({
 | 
			
		||||
                    'ENABLED': config.getboolean(section, 'ENABLED'),
 | 
			
		||||
                    'CALLSIGN': config.get(section, 'CALLSIGN'),
 | 
			
		||||
                    'REPORT_INTERVAL': config.getint(section, 'REPORT_INTERVAL'),
 | 
			
		||||
                    'SERVER': config.get(section, 'SERVER'),
 | 
			
		||||
                    'MESSAGE': config.get(section, 'MESSAGE')
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
            elif section == 'REPORTS':
 | 
			
		||||
                CONFIG['REPORTS'].update({
 | 
			
		||||
 | 
			
		||||
@ -1,241 +1,254 @@
 | 
			
		||||
# PROGRAM-WIDE PARAMETERS GO HERE
 | 
			
		||||
# PATH - working path for files, leave it alone unless you NEED to change it
 | 
			
		||||
# PING_TIME - the interval that peers will ping the master, and re-try registraion
 | 
			
		||||
#           - how often the Master maintenance loop runs
 | 
			
		||||
# MAX_MISSED - how many pings are missed before we give up and re-register
 | 
			
		||||
#           - number of times the master maintenance loop runs before de-registering a peer
 | 
			
		||||
#
 | 
			
		||||
# ACLs:
 | 
			
		||||
#
 | 
			
		||||
# Access Control Lists are a very powerful tool for administering your system.
 | 
			
		||||
# But they consume packet processing time. Disable them if you are not using them.
 | 
			
		||||
# But be aware that, as of now, the configuration stanzas still need the ACL
 | 
			
		||||
# sections configured even if you're not using them.
 | 
			
		||||
#
 | 
			
		||||
# REGISTRATION ACLS ARE ALWAYS USED, ONLY SUBSCRIBER AND TGID MAY BE DISABLED!!!
 | 
			
		||||
#
 | 
			
		||||
# The 'action' May be PERMIT|DENY
 | 
			
		||||
# Each entry may be a single radio id, or a hypenated range (e.g. 1-2999)
 | 
			
		||||
# Format:
 | 
			
		||||
# 	ACL = 'action:id|start-end|,id|start-end,....'
 | 
			
		||||
#		--for example--
 | 
			
		||||
#	SUB_ACL: DENY:1,1000-2000,4500-60000,17
 | 
			
		||||
#
 | 
			
		||||
# ACL Types:
 | 
			
		||||
# 	REG_ACL: peer radio IDs for registration (only used on HBP master systems)
 | 
			
		||||
# 	SUB_ACL: subscriber IDs for end-users
 | 
			
		||||
# 	TGID_TS1_ACL: destination talkgroup IDs on Timeslot 1
 | 
			
		||||
# 	TGID_TS2_ACL: destination talkgroup IDs on Timeslot 2
 | 
			
		||||
#
 | 
			
		||||
# ACLs may be repeated for individual systems if needed for granularity
 | 
			
		||||
# Global ACLs will be processed BEFORE the system level ACLs
 | 
			
		||||
# Packets will be matched against all ACLs, GLOBAL first. If a packet 'passes'
 | 
			
		||||
# All elements, processing continues. Packets are discarded at the first
 | 
			
		||||
# negative match, or 'reject' from an ACL element.
 | 
			
		||||
#
 | 
			
		||||
# If you do not wish to use ACLs, set them to 'PERMIT:ALL'
 | 
			
		||||
# TGID_TS1_ACL in the global stanza is used for OPENBRIDGE systems, since all
 | 
			
		||||
# traffic is passed as TS 1 between OpenBridges
 | 
			
		||||
[GLOBAL]
 | 
			
		||||
PATH: ./
 | 
			
		||||
PING_TIME: 5
 | 
			
		||||
MAX_MISSED: 3
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
REG_ACL: PERMIT:ALL
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_TS1_ACL: PERMIT:ALL
 | 
			
		||||
TGID_TS2_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# NOT YET WORKING: NETWORK REPORTING CONFIGURATION
 | 
			
		||||
#   Enabling "REPORT" will configure a socket-based reporting
 | 
			
		||||
#   system that will send the configuration and other items
 | 
			
		||||
#   to a another process (local or remote) that may process
 | 
			
		||||
#   the information for some useful purpose, like a web dashboard.
 | 
			
		||||
#
 | 
			
		||||
#   REPORT - True to enable, False to disable
 | 
			
		||||
#   REPORT_INTERVAL - Seconds between reports
 | 
			
		||||
#   REPORT_PORT - TCP port to listen on if "REPORT_NETWORKS" = NETWORK
 | 
			
		||||
#   REPORT_CLIENTS - comma separated list of IPs you will allow clients
 | 
			
		||||
#       to connect on. Entering a * will allow all.
 | 
			
		||||
#
 | 
			
		||||
# ****FOR NOW MUST BE TRUE - USE THE LOOPBACK IF YOU DON'T USE THIS!!!****
 | 
			
		||||
[REPORTS]
 | 
			
		||||
REPORT: True
 | 
			
		||||
REPORT_INTERVAL: 60
 | 
			
		||||
REPORT_PORT: 4321
 | 
			
		||||
REPORT_CLIENTS: 127.0.0.1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# SYSTEM LOGGER CONFIGURAITON
 | 
			
		||||
#   This allows the logger to be configured without chaning the individual
 | 
			
		||||
#   python logger stuff. LOG_FILE should be a complete path/filename for *your*
 | 
			
		||||
#   system -- use /dev/null for non-file handlers.
 | 
			
		||||
#   LOG_HANDLERS may be any of the following, please, no spaces in the
 | 
			
		||||
#   list if you use several:
 | 
			
		||||
#       null
 | 
			
		||||
#       console
 | 
			
		||||
#       console-timed
 | 
			
		||||
#       file
 | 
			
		||||
#       file-timed
 | 
			
		||||
#       syslog
 | 
			
		||||
#   LOG_LEVEL may be any of the standard syslog logging levels, though
 | 
			
		||||
#   as of now, DEBUG, INFO, WARNING and CRITICAL are the only ones
 | 
			
		||||
#   used.
 | 
			
		||||
#
 | 
			
		||||
[LOGGER]
 | 
			
		||||
LOG_FILE: /tmp/hblink.log
 | 
			
		||||
LOG_HANDLERS: console-timed
 | 
			
		||||
LOG_LEVEL: DEBUG
 | 
			
		||||
LOG_NAME: HBlink
 | 
			
		||||
 | 
			
		||||
# DOWNLOAD AND IMPORT SUBSCRIBER, PEER and TGID ALIASES
 | 
			
		||||
# Ok, not the TGID, there's no master list I know of to download
 | 
			
		||||
# This is intended as a facility for other applcations built on top of
 | 
			
		||||
# HBlink to use, and will NOT be used in HBlink directly.
 | 
			
		||||
# STALE_DAYS is the number of days since the last download before we
 | 
			
		||||
# download again. Don't be an ass and change this to less than a few days.
 | 
			
		||||
[ALIASES]
 | 
			
		||||
TRY_DOWNLOAD: True
 | 
			
		||||
PATH: ./
 | 
			
		||||
PEER_FILE: peer_ids.json
 | 
			
		||||
SUBSCRIBER_FILE: subscriber_ids.json
 | 
			
		||||
TGID_FILE: talkgroup_ids.json
 | 
			
		||||
PEER_URL: https://www.radioid.net/static/rptrs.json
 | 
			
		||||
SUBSCRIBER_URL: https://www.radioid.net/static/users.json
 | 
			
		||||
STALE_DAYS: 7
 | 
			
		||||
 | 
			
		||||
# OPENBRIDGE INSTANCES - DUPLICATE SECTION FOR MULTIPLE CONNECTIONS
 | 
			
		||||
# OpenBridge is a protocol originall created by DMR+ for connection between an
 | 
			
		||||
# IPSC2 server and Brandmeister. It has been implemented here at the suggestion
 | 
			
		||||
# of the Brandmeister team as a way to legitimately connect HBlink to the
 | 
			
		||||
# Brandemiester network.
 | 
			
		||||
# It is recommended to name the system the ID of the Brandmeister server that
 | 
			
		||||
# it connects to, but is not necessary. TARGET_IP and TARGET_PORT are of the
 | 
			
		||||
# Brandmeister or IPSC2 server you are connecting to. PASSPHRASE is the password
 | 
			
		||||
# that must be agreed upon between you and the operator of the server you are
 | 
			
		||||
# connecting to. NETWORK_ID is a number in the format of a DMR Radio ID that
 | 
			
		||||
# will be sent to the other server to identify this connection.
 | 
			
		||||
# other parameters follow the other system types.
 | 
			
		||||
#
 | 
			
		||||
# ACLs:
 | 
			
		||||
# OpenBridge does not 'register', so registration ACL is meaningless.
 | 
			
		||||
# OpenBridge passes all traffic on TS1, so there is only 1 TGID ACL.
 | 
			
		||||
# Otherwise ACLs work as described in the global stanza
 | 
			
		||||
[OBP-1]
 | 
			
		||||
MODE: OPENBRIDGE
 | 
			
		||||
ENABLED: True
 | 
			
		||||
IP:
 | 
			
		||||
PORT: 62035
 | 
			
		||||
NETWORK_ID: 3129100
 | 
			
		||||
PASSPHRASE: password
 | 
			
		||||
TARGET_IP: 1.2.3.4
 | 
			
		||||
TARGET_PORT: 62035
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
# MASTER INSTANCES - DUPLICATE SECTION FOR MULTIPLE MASTERS
 | 
			
		||||
# HomeBrew Protocol Master instances go here.
 | 
			
		||||
# IP may be left blank if there's one interface on your system.
 | 
			
		||||
# Port should be the port you want this master to listen on. It must be unique
 | 
			
		||||
# and unused by anything else.
 | 
			
		||||
# Repeat - if True, the master repeats traffic to peers, False, it does nothing.
 | 
			
		||||
#
 | 
			
		||||
# MAX_PEERS -- maximun number of peers that may be connect to this master
 | 
			
		||||
# at any given time. This is very handy if you're allowing hotspots to
 | 
			
		||||
# connect, or using a limited computer like a Raspberry Pi.
 | 
			
		||||
#
 | 
			
		||||
# ACLs:
 | 
			
		||||
# See comments in the GLOBAL stanza
 | 
			
		||||
[MASTER-1]
 | 
			
		||||
MODE: MASTER
 | 
			
		||||
ENABLED: True
 | 
			
		||||
REPEAT: True
 | 
			
		||||
MAX_PEERS: 10
 | 
			
		||||
EXPORT_AMBE: False
 | 
			
		||||
IP:
 | 
			
		||||
PORT: 54000
 | 
			
		||||
PASSPHRASE: s3cr37w0rd
 | 
			
		||||
GROUP_HANGTIME: 5
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
REG_ACL: DENY:1
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_TS1_ACL: PERMIT:ALL
 | 
			
		||||
TGID_TS2_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
# PEER INSTANCES - DUPLICATE SECTION FOR MULTIPLE PEERS
 | 
			
		||||
# There are a LOT of errors in the HB Protocol specifications on this one!
 | 
			
		||||
# MOST of these items are just strings and will be properly dealt with by the program
 | 
			
		||||
# The TX & RX Frequencies are 9-digit numbers, and are the frequency in Hz.
 | 
			
		||||
# Latitude is an 8-digit unsigned floating point number.
 | 
			
		||||
# Longitude is a 9-digit signed floating point number.
 | 
			
		||||
# Height is in meters
 | 
			
		||||
# Setting Loose to True relaxes the validation on packets received from the master.
 | 
			
		||||
# This will allow HBlink to connect to a non-compliant system such as XLXD, DMR+ etc.
 | 
			
		||||
#
 | 
			
		||||
# ACLs:
 | 
			
		||||
# See comments in the GLOBAL stanza
 | 
			
		||||
[REPEATER-1]
 | 
			
		||||
MODE: PEER
 | 
			
		||||
ENABLED: True
 | 
			
		||||
LOOSE: False
 | 
			
		||||
EXPORT_AMBE: False
 | 
			
		||||
IP: 
 | 
			
		||||
PORT: 54001
 | 
			
		||||
MASTER_IP: 172.16.1.1
 | 
			
		||||
MASTER_PORT: 54000
 | 
			
		||||
PASSPHRASE: homebrew
 | 
			
		||||
CALLSIGN: W1ABC
 | 
			
		||||
RADIO_ID: 312000
 | 
			
		||||
RX_FREQ: 449000000
 | 
			
		||||
TX_FREQ: 444000000
 | 
			
		||||
TX_POWER: 25
 | 
			
		||||
COLORCODE: 1
 | 
			
		||||
SLOTS: 1
 | 
			
		||||
LATITUDE: 38.0000
 | 
			
		||||
LONGITUDE: -095.0000
 | 
			
		||||
HEIGHT: 75
 | 
			
		||||
LOCATION: Anywhere, USA
 | 
			
		||||
DESCRIPTION: This is a cool repeater
 | 
			
		||||
URL: www.w1abc.org
 | 
			
		||||
SOFTWARE_ID: 20170620
 | 
			
		||||
PACKAGE_ID: MMDVM_HBlink
 | 
			
		||||
GROUP_HANGTIME: 5
 | 
			
		||||
OPTIONS:
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_TS1_ACL: PERMIT:ALL
 | 
			
		||||
TGID_TS2_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
[XLX-1]
 | 
			
		||||
MODE: XLXPEER
 | 
			
		||||
ENABLED: True
 | 
			
		||||
LOOSE: True
 | 
			
		||||
EXPORT_AMBE: False
 | 
			
		||||
IP: 
 | 
			
		||||
PORT: 54002
 | 
			
		||||
MASTER_IP: 172.16.1.1
 | 
			
		||||
MASTER_PORT: 62030
 | 
			
		||||
PASSPHRASE: passw0rd
 | 
			
		||||
CALLSIGN: W1ABC
 | 
			
		||||
RADIO_ID: 312000
 | 
			
		||||
RX_FREQ: 449000000
 | 
			
		||||
TX_FREQ: 444000000
 | 
			
		||||
TX_POWER: 25
 | 
			
		||||
COLORCODE: 1
 | 
			
		||||
SLOTS: 1
 | 
			
		||||
LATITUDE: 38.0000
 | 
			
		||||
LONGITUDE: -095.0000
 | 
			
		||||
HEIGHT: 75
 | 
			
		||||
LOCATION: Anywhere, USA
 | 
			
		||||
DESCRIPTION: This is a cool repeater
 | 
			
		||||
URL: www.w1abc.org
 | 
			
		||||
SOFTWARE_ID: 20170620
 | 
			
		||||
PACKAGE_ID: MMDVM_HBlink
 | 
			
		||||
GROUP_HANGTIME: 5
 | 
			
		||||
XLXMODULE: 4004
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_TS1_ACL: PERMIT:ALL
 | 
			
		||||
TGID_TS2_ACL: PERMIT:ALL
 | 
			
		||||
# PROGRAM-WIDE PARAMETERS GO HERE
 | 
			
		||||
# PATH - working path for files, leave it alone unless you NEED to change it
 | 
			
		||||
# PING_TIME - the interval that peers will ping the master, and re-try registraion
 | 
			
		||||
#           - how often the Master maintenance loop runs
 | 
			
		||||
# MAX_MISSED - how many pings are missed before we give up and re-register
 | 
			
		||||
#           - number of times the master maintenance loop runs before de-registering a peer
 | 
			
		||||
#
 | 
			
		||||
# ACLs:
 | 
			
		||||
#
 | 
			
		||||
# Access Control Lists are a very powerful tool for administering your system.
 | 
			
		||||
# But they consume packet processing time. Disable them if you are not using them.
 | 
			
		||||
# But be aware that, as of now, the configuration stanzas still need the ACL
 | 
			
		||||
# sections configured even if you're not using them.
 | 
			
		||||
#
 | 
			
		||||
# REGISTRATION ACLS ARE ALWAYS USED, ONLY SUBSCRIBER AND TGID MAY BE DISABLED!!!
 | 
			
		||||
#
 | 
			
		||||
# The 'action' May be PERMIT|DENY
 | 
			
		||||
# Each entry may be a single radio id, or a hypenated range (e.g. 1-2999)
 | 
			
		||||
# Format:
 | 
			
		||||
# 	ACL = 'action:id|start-end|,id|start-end,....'
 | 
			
		||||
#		--for example--
 | 
			
		||||
#	SUB_ACL: DENY:1,1000-2000,4500-60000,17
 | 
			
		||||
#
 | 
			
		||||
# ACL Types:
 | 
			
		||||
# 	REG_ACL: peer radio IDs for registration (only used on HBP master systems)
 | 
			
		||||
# 	SUB_ACL: subscriber IDs for end-users
 | 
			
		||||
# 	TGID_TS1_ACL: destination talkgroup IDs on Timeslot 1
 | 
			
		||||
# 	TGID_TS2_ACL: destination talkgroup IDs on Timeslot 2
 | 
			
		||||
#
 | 
			
		||||
# ACLs may be repeated for individual systems if needed for granularity
 | 
			
		||||
# Global ACLs will be processed BEFORE the system level ACLs
 | 
			
		||||
# Packets will be matched against all ACLs, GLOBAL first. If a packet 'passes'
 | 
			
		||||
# All elements, processing continues. Packets are discarded at the first
 | 
			
		||||
# negative match, or 'reject' from an ACL element.
 | 
			
		||||
#
 | 
			
		||||
# If you do not wish to use ACLs, set them to 'PERMIT:ALL'
 | 
			
		||||
# TGID_TS1_ACL in the global stanza is used for OPENBRIDGE systems, since all
 | 
			
		||||
# traffic is passed as TS 1 between OpenBridges
 | 
			
		||||
[GLOBAL]
 | 
			
		||||
PATH: ./
 | 
			
		||||
PING_TIME: 5
 | 
			
		||||
MAX_MISSED: 3
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
REG_ACL: PERMIT:ALL
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_TS1_ACL: PERMIT:ALL
 | 
			
		||||
TGID_TS2_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
# APRS - BY IU7IGU
 | 
			
		||||
# Enabling "APRS" will configure APRS-Beaconing of Master's connection
 | 
			
		||||
# like repeater and hotspots.
 | 
			
		||||
# REPORT_INTERVAL in Minute (ALLOW only > 3 Minutes)
 | 
			
		||||
# CALLSIGN: Callsign that will pubblish data on aprs server
 | 
			
		||||
# MESSAGE: This message will print on APRS description together RX and TX Frequency
 | 
			
		||||
 | 
			
		||||
[APRS]
 | 
			
		||||
ENABLED: True
 | 
			
		||||
REPORT_INTERVAL: 5
 | 
			
		||||
CALLSIGN:HB1LNK-11
 | 
			
		||||
SERVER:euro.aprs2.net
 | 
			
		||||
MESSAGE:Connesso ad HBLINK
 | 
			
		||||
 | 
			
		||||
# NOT YET WORKING: NETWORK REPORTING CONFIGURATION
 | 
			
		||||
#   Enabling "REPORT" will configure a socket-based reporting
 | 
			
		||||
#   system that will send the configuration and other items
 | 
			
		||||
#   to a another process (local or remote) that may process
 | 
			
		||||
#   the information for some useful purpose, like a web dashboard.
 | 
			
		||||
#
 | 
			
		||||
#   REPORT - True to enable, False to disable
 | 
			
		||||
#   REPORT_INTERVAL - Seconds between reports
 | 
			
		||||
#   REPORT_PORT - TCP port to listen on if "REPORT_NETWORKS" = NETWORK
 | 
			
		||||
#   REPORT_CLIENTS - comma separated list of IPs you will allow clients
 | 
			
		||||
#       to connect on. Entering a * will allow all.
 | 
			
		||||
#
 | 
			
		||||
# ****FOR NOW MUST BE TRUE - USE THE LOOPBACK IF YOU DON'T USE THIS!!!****
 | 
			
		||||
[REPORTS]
 | 
			
		||||
REPORT: True
 | 
			
		||||
REPORT_INTERVAL: 60
 | 
			
		||||
REPORT_PORT: 4321
 | 
			
		||||
REPORT_CLIENTS: 127.0.0.1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# SYSTEM LOGGER CONFIGURAITON
 | 
			
		||||
#   This allows the logger to be configured without chaning the individual
 | 
			
		||||
#   python logger stuff. LOG_FILE should be a complete path/filename for *your*
 | 
			
		||||
#   system -- use /dev/null for non-file handlers.
 | 
			
		||||
#   LOG_HANDLERS may be any of the following, please, no spaces in the
 | 
			
		||||
#   list if you use several:
 | 
			
		||||
#       null
 | 
			
		||||
#       console
 | 
			
		||||
#       console-timed
 | 
			
		||||
#       file
 | 
			
		||||
#       file-timed
 | 
			
		||||
#       syslog
 | 
			
		||||
#   LOG_LEVEL may be any of the standard syslog logging levels, though
 | 
			
		||||
#   as of now, DEBUG, INFO, WARNING and CRITICAL are the only ones
 | 
			
		||||
#   used.
 | 
			
		||||
#
 | 
			
		||||
[LOGGER]
 | 
			
		||||
LOG_FILE: /tmp/hblink.log
 | 
			
		||||
LOG_HANDLERS: console-timed
 | 
			
		||||
LOG_LEVEL: DEBUG
 | 
			
		||||
LOG_NAME: HBlink
 | 
			
		||||
 | 
			
		||||
# DOWNLOAD AND IMPORT SUBSCRIBER, PEER and TGID ALIASES
 | 
			
		||||
# Ok, not the TGID, there's no master list I know of to download
 | 
			
		||||
# This is intended as a facility for other applcations built on top of
 | 
			
		||||
# HBlink to use, and will NOT be used in HBlink directly.
 | 
			
		||||
# STALE_DAYS is the number of days since the last download before we
 | 
			
		||||
# download again. Don't be an ass and change this to less than a few days.
 | 
			
		||||
[ALIASES]
 | 
			
		||||
TRY_DOWNLOAD: True
 | 
			
		||||
PATH: ./
 | 
			
		||||
PEER_FILE: peer_ids.json
 | 
			
		||||
SUBSCRIBER_FILE: subscriber_ids.json
 | 
			
		||||
TGID_FILE: talkgroup_ids.json
 | 
			
		||||
PEER_URL: https://www.radioid.net/static/rptrs.json
 | 
			
		||||
SUBSCRIBER_URL: https://www.radioid.net/static/users.json
 | 
			
		||||
STALE_DAYS: 7
 | 
			
		||||
 | 
			
		||||
# OPENBRIDGE INSTANCES - DUPLICATE SECTION FOR MULTIPLE CONNECTIONS
 | 
			
		||||
# OpenBridge is a protocol originall created by DMR+ for connection between an
 | 
			
		||||
# IPSC2 server and Brandmeister. It has been implemented here at the suggestion
 | 
			
		||||
# of the Brandmeister team as a way to legitimately connect HBlink to the
 | 
			
		||||
# Brandemiester network.
 | 
			
		||||
# It is recommended to name the system the ID of the Brandmeister server that
 | 
			
		||||
# it connects to, but is not necessary. TARGET_IP and TARGET_PORT are of the
 | 
			
		||||
# Brandmeister or IPSC2 server you are connecting to. PASSPHRASE is the password
 | 
			
		||||
# that must be agreed upon between you and the operator of the server you are
 | 
			
		||||
# connecting to. NETWORK_ID is a number in the format of a DMR Radio ID that
 | 
			
		||||
# will be sent to the other server to identify this connection.
 | 
			
		||||
# other parameters follow the other system types.
 | 
			
		||||
#
 | 
			
		||||
# ACLs:
 | 
			
		||||
# OpenBridge does not 'register', so registration ACL is meaningless.
 | 
			
		||||
# OpenBridge passes all traffic on TS1, so there is only 1 TGID ACL.
 | 
			
		||||
# Otherwise ACLs work as described in the global stanza
 | 
			
		||||
[OBP-1]
 | 
			
		||||
MODE: OPENBRIDGE
 | 
			
		||||
ENABLED: True
 | 
			
		||||
IP:
 | 
			
		||||
PORT: 62035
 | 
			
		||||
NETWORK_ID: 3129100
 | 
			
		||||
PASSPHRASE: password
 | 
			
		||||
TARGET_IP: 1.2.3.4
 | 
			
		||||
TARGET_PORT: 62035
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
# MASTER INSTANCES - DUPLICATE SECTION FOR MULTIPLE MASTERS
 | 
			
		||||
# HomeBrew Protocol Master instances go here.
 | 
			
		||||
# IP may be left blank if there's one interface on your system.
 | 
			
		||||
# Port should be the port you want this master to listen on. It must be unique
 | 
			
		||||
# and unused by anything else.
 | 
			
		||||
# Repeat - if True, the master repeats traffic to peers, False, it does nothing.
 | 
			
		||||
#
 | 
			
		||||
# MAX_PEERS -- maximun number of peers that may be connect to this master
 | 
			
		||||
# at any given time. This is very handy if you're allowing hotspots to
 | 
			
		||||
# connect, or using a limited computer like a Raspberry Pi.
 | 
			
		||||
#
 | 
			
		||||
# ACLs:
 | 
			
		||||
# See comments in the GLOBAL stanza
 | 
			
		||||
[MASTER-1]
 | 
			
		||||
MODE: MASTER
 | 
			
		||||
ENABLED: True
 | 
			
		||||
REPEAT: True
 | 
			
		||||
MAX_PEERS: 10
 | 
			
		||||
EXPORT_AMBE: False
 | 
			
		||||
IP:
 | 
			
		||||
PORT: 54000
 | 
			
		||||
PASSPHRASE: s3cr37w0rd
 | 
			
		||||
GROUP_HANGTIME: 5
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
REG_ACL: DENY:1
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_TS1_ACL: PERMIT:ALL
 | 
			
		||||
TGID_TS2_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
# PEER INSTANCES - DUPLICATE SECTION FOR MULTIPLE PEERS
 | 
			
		||||
# There are a LOT of errors in the HB Protocol specifications on this one!
 | 
			
		||||
# MOST of these items are just strings and will be properly dealt with by the program
 | 
			
		||||
# The TX & RX Frequencies are 9-digit numbers, and are the frequency in Hz.
 | 
			
		||||
# Latitude is an 8-digit unsigned floating point number.
 | 
			
		||||
# Longitude is a 9-digit signed floating point number.
 | 
			
		||||
# Height is in meters
 | 
			
		||||
# Setting Loose to True relaxes the validation on packets received from the master.
 | 
			
		||||
# This will allow HBlink to connect to a non-compliant system such as XLXD, DMR+ etc.
 | 
			
		||||
#
 | 
			
		||||
# ACLs:
 | 
			
		||||
# See comments in the GLOBAL stanza
 | 
			
		||||
[REPEATER-1]
 | 
			
		||||
MODE: PEER
 | 
			
		||||
ENABLED: True
 | 
			
		||||
LOOSE: False
 | 
			
		||||
EXPORT_AMBE: False
 | 
			
		||||
IP: 
 | 
			
		||||
PORT: 54001
 | 
			
		||||
MASTER_IP: 172.16.1.1
 | 
			
		||||
MASTER_PORT: 54000
 | 
			
		||||
PASSPHRASE: homebrew
 | 
			
		||||
CALLSIGN: W1ABC
 | 
			
		||||
RADIO_ID: 312000
 | 
			
		||||
RX_FREQ: 449000000
 | 
			
		||||
TX_FREQ: 444000000
 | 
			
		||||
TX_POWER: 25
 | 
			
		||||
COLORCODE: 1
 | 
			
		||||
SLOTS: 1
 | 
			
		||||
LATITUDE: 38.0000
 | 
			
		||||
LONGITUDE: -095.0000
 | 
			
		||||
HEIGHT: 75
 | 
			
		||||
LOCATION: Anywhere, USA
 | 
			
		||||
DESCRIPTION: This is a cool repeater
 | 
			
		||||
URL: www.w1abc.org
 | 
			
		||||
SOFTWARE_ID: 20170620
 | 
			
		||||
PACKAGE_ID: MMDVM_HBlink
 | 
			
		||||
GROUP_HANGTIME: 5
 | 
			
		||||
OPTIONS:
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_TS1_ACL: PERMIT:ALL
 | 
			
		||||
TGID_TS2_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
[XLX-1]
 | 
			
		||||
MODE: XLXPEER
 | 
			
		||||
ENABLED: True
 | 
			
		||||
LOOSE: True
 | 
			
		||||
EXPORT_AMBE: False
 | 
			
		||||
IP: 
 | 
			
		||||
PORT: 54002
 | 
			
		||||
MASTER_IP: 172.16.1.1
 | 
			
		||||
MASTER_PORT: 62030
 | 
			
		||||
PASSPHRASE: passw0rd
 | 
			
		||||
CALLSIGN: W1ABC
 | 
			
		||||
RADIO_ID: 312000
 | 
			
		||||
RX_FREQ: 449000000
 | 
			
		||||
TX_FREQ: 444000000
 | 
			
		||||
TX_POWER: 25
 | 
			
		||||
COLORCODE: 1
 | 
			
		||||
SLOTS: 1
 | 
			
		||||
LATITUDE: 38.0000
 | 
			
		||||
LONGITUDE: -095.0000
 | 
			
		||||
HEIGHT: 75
 | 
			
		||||
LOCATION: Anywhere, USA
 | 
			
		||||
DESCRIPTION: This is a cool repeater
 | 
			
		||||
URL: www.w1abc.org
 | 
			
		||||
SOFTWARE_ID: 20170620
 | 
			
		||||
PACKAGE_ID: MMDVM_HBlink
 | 
			
		||||
GROUP_HANGTIME: 5
 | 
			
		||||
XLXMODULE: 4004
 | 
			
		||||
USE_ACL: True
 | 
			
		||||
SUB_ACL: DENY:1
 | 
			
		||||
TGID_TS1_ACL: PERMIT:ALL
 | 
			
		||||
TGID_TS2_ACL: PERMIT:ALL
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										149
									
								
								hblink.py
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								hblink.py
									
									
									
									
									
								
							@ -35,6 +35,9 @@ from hashlib import sha256, sha1
 | 
			
		||||
from hmac import new as hmac_new, compare_digest
 | 
			
		||||
from time import time
 | 
			
		||||
from collections import deque
 | 
			
		||||
import aprslib
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Twisted is pretty important, so I keep it separate
 | 
			
		||||
from twisted.internet.protocol import DatagramProtocol, Factory, Protocol
 | 
			
		||||
@ -66,6 +69,8 @@ __email__      = 'n0mjs@me.com'
 | 
			
		||||
# Global variables used whether we are a module or __main__
 | 
			
		||||
systems = {}
 | 
			
		||||
 | 
			
		||||
open("nom_aprs","w").close
 | 
			
		||||
 | 
			
		||||
# Timed loop used for reporting HBP status
 | 
			
		||||
def config_reports(_config, _factory):
 | 
			
		||||
    def reporting_loop(_logger, _server):
 | 
			
		||||
@ -80,10 +85,10 @@ def config_reports(_config, _factory):
 | 
			
		||||
 | 
			
		||||
    reporting = task.LoopingCall(reporting_loop, logger, report_server)
 | 
			
		||||
    reporting.start(_config['REPORTS']['REPORT_INTERVAL'])
 | 
			
		||||
 | 
			
		||||
    return report_server
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Shut ourselves down gracefully by disconnecting from the masters and peers.
 | 
			
		||||
def hblink_handler(_signal, _frame):
 | 
			
		||||
    for system in systems:
 | 
			
		||||
@ -104,6 +109,7 @@ def acl_check(_id, _acl):
 | 
			
		||||
#    OPENBRIDGE CLASS
 | 
			
		||||
#************************************************
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OPENBRIDGE(DatagramProtocol):
 | 
			
		||||
    def __init__(self, _name, _config, _report):
 | 
			
		||||
        # Define a few shortcuts to make the rest of the class more readable
 | 
			
		||||
@ -112,7 +118,9 @@ class OPENBRIDGE(DatagramProtocol):
 | 
			
		||||
        self._report = _report
 | 
			
		||||
        self._config = self._CONFIG['SYSTEMS'][self._system]
 | 
			
		||||
        self._laststrid = deque([], 20)
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    def dereg(self):
 | 
			
		||||
        logger.info('(%s) is mode OPENBRIDGE. No De-Registration required, continuing shutdown', self._system)
 | 
			
		||||
 | 
			
		||||
@ -474,8 +482,18 @@ class HBSYSTEM(DatagramProtocol):
 | 
			
		||||
                            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))
 | 
			
		||||
                    self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
 | 
			
		||||
                    if self._CONFIG['APRS']['ENABLED']:
 | 
			
		||||
                        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]
 | 
			
		||||
 | 
			
		||||
            else:
 | 
			
		||||
                _peer_id = _data[4:8]      # Configure Command
 | 
			
		||||
                if _peer_id in self._peers \
 | 
			
		||||
@ -502,6 +520,124 @@ 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'])
 | 
			
		||||
            #APRS IMPLEMENTATION
 | 
			
		||||
                    conta = 0
 | 
			
		||||
                    lista_blocco=['ysf', 'xlx', 'nxdn', 'dstar', 'echolink','p25', 'svx']
 | 
			
		||||
                    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()
 | 
			
		||||
                                
 | 
			
		||||
                    def sendAprs():
 | 
			
		||||
                        AIS = aprslib.IS(str(self._CONFIG['APRS']['CALLSIGN']), passwd=aprslib.passcode(str(self._CONFIG['APRS']['CALLSIGN'])), host=str(self._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:]
 | 
			
		||||
                                    
 | 
			
		||||
                                    
 | 
			
		||||
                                    AIS.sendall(str(dati[0])+">APRS,TCPIP*,qAC,"+str(self._CONFIG['APRS']['CALLSIGN'])+":!"+str(lat_utile)[:-2]+lat_verso+"/"+str(lon_utile)[:-1]+lon_verso+"r"+str(self._CONFIG['APRS']['MESSAGE'])+' RX: '+str(rx_utile)+' TX: '+str(tx_utile))
 | 
			
		||||
                        logging.info('APRS INVIATO')
 | 
			
		||||
                                    
 | 
			
		||||
                    if conta == 0:                
 | 
			
		||||
                        if self._CONFIG['APRS']['REPORT_INTERVAL'] > 3:
 | 
			
		||||
                            l=task.LoopingCall(sendAprs)
 | 
			
		||||
                            l.start(float(int(self._CONFIG['APRS']['REPORT_INTERVAL']*60)))
 | 
			
		||||
                        else:
 | 
			
		||||
                            l=task.LoopingCall(sendAprs)
 | 
			
		||||
                            l.start(5*60)
 | 
			
		||||
                            logger.info('Report Time APRS to short')
 | 
			
		||||
                        
 | 
			
		||||
                    
 | 
			
		||||
                else:
 | 
			
		||||
                    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))
 | 
			
		||||
@ -768,6 +904,8 @@ if __name__ == '__main__':
 | 
			
		||||
    import sys
 | 
			
		||||
    import os
 | 
			
		||||
    import signal
 | 
			
		||||
    import aprslib
 | 
			
		||||
    import threading
 | 
			
		||||
 | 
			
		||||
    # Change the current directory to the location of the application
 | 
			
		||||
    os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
 | 
			
		||||
@ -789,12 +927,12 @@ if __name__ == '__main__':
 | 
			
		||||
    if cli_args.LOG_LEVEL:
 | 
			
		||||
        CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL
 | 
			
		||||
    logger = log.config_logging(CONFIG['LOGGER'])
 | 
			
		||||
    logger.info('\n\nCopyright (c) 2013, 2014, 2015, 2016, 2018, 2019\n\tThe Regents of the K0USY Group. All rights reserved.\n')
 | 
			
		||||
    logger.info('APRS IMPLEMENTATION BY IU7IGU email: iu7igu@yahoo.com \n\nCopyright (c) 2013, 2014, 2015, 2016, 2018, 2019\n\tThe Regents of the K0USY Group. All rights reserved.')
 | 
			
		||||
    logger.debug('(GLOBAL) Logging system started, anything from here on gets logged')
 | 
			
		||||
 | 
			
		||||
    # Set up the signal handler
 | 
			
		||||
    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)
 | 
			
		||||
        logger.info('(GLOBAL) SHUTDOWN: ALL SYSTEM HANDLERS EXECUTED - STOPPING REACTOR')
 | 
			
		||||
        reactor.stop()
 | 
			
		||||
@ -824,3 +962,4 @@ if __name__ == '__main__':
 | 
			
		||||
            logger.debug('(GLOBAL) %s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system])
 | 
			
		||||
 | 
			
		||||
    reactor.run()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user