|  |  |  | @ -1,29 +1,62 @@ | 
			
		
	
		
			
				
					|  |  |  |  | from threading import * | 
			
		
	
		
			
				
					|  |  |  |  | # LOG4OM Web Statuts | 
			
		
	
		
			
				
					|  |  |  |  | # Version: 5-APR-2023 - Jay Moore/NQ4T | 
			
		
	
		
			
				
					|  |  |  |  | # https://git.pickmy.org/nq4t/log4om-webstatus | 
			
		
	
		
			
				
					|  |  |  |  | # https://nq4t.com/software/log4omudp/ | 
			
		
	
		
			
				
					|  |  |  |  | # FreeBSD 3-Clause License (see LICENSE) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import time | 
			
		
	
		
			
				
					|  |  |  |  | import xml.etree.ElementTree as ET | 
			
		
	
		
			
				
					|  |  |  |  | import socket | 
			
		
	
		
			
				
					|  |  |  |  | import select | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | UDP_IP = "0.0.0.0" | 
			
		
	
		
			
				
					|  |  |  |  | UDP_PORT = 2242 # Default Log4OM UDP Out Port | 
			
		
	
		
			
				
					|  |  |  |  | UDP_C_IP = "192.168.1.70" # Set to IP running Log4OM | 
			
		
	
		
			
				
					|  |  |  |  | UDP_C_PORT = 2241 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | tot = 1 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | 
			
		
	
		
			
				
					|  |  |  |  | sock.bind((UDP_IP, UDP_PORT)) | 
			
		
	
		
			
				
					|  |  |  |  | tot = time.time() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | check = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def monitor(): | 
			
		
	
		
			
				
					|  |  |  |  |         global tot | 
			
		
	
		
			
				
					|  |  |  |  |         while True: | 
			
		
	
		
			
				
					|  |  |  |  |                 tc = time.time() - tot # time since last timestamp | 
			
		
	
		
			
				
					|  |  |  |  |                 if tc < 15: #15 seconds | 
			
		
	
		
			
				
					|  |  |  |  |                         time.sleep(6) | 
			
		
	
		
			
				
					|  |  |  |  | def checkrig(): | 
			
		
	
		
			
				
					|  |  |  |  |     check = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | 
			
		
	
		
			
				
					|  |  |  |  |     check.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | 
			
		
	
		
			
				
					|  |  |  |  |     check.bind((UDP_IP, UDP_C_PORT)) | 
			
		
	
		
			
				
					|  |  |  |  |     msg = """<?xml version="1.0" encoding="utf-8"?> | 
			
		
	
		
			
				
					|  |  |  |  |     <RemoteControlRequest> | 
			
		
	
		
			
				
					|  |  |  |  |     <MessageId>C0FC027F-D09E-49F5-9CA6-33A11E05A053</MessageId> | 
			
		
	
		
			
				
					|  |  |  |  |     <RemoteControlMessage>Alive</RemoteControlMessage> | 
			
		
	
		
			
				
					|  |  |  |  |     </RemoteControlRequest>""" | 
			
		
	
		
			
				
					|  |  |  |  |     check.sendto(msg.encode(), (UDP_C_IP, UDP_C_PORT)) | 
			
		
	
		
			
				
					|  |  |  |  |     status = select.select([check], [], [], 2) | 
			
		
	
		
			
				
					|  |  |  |  |     if status[0]: | 
			
		
	
		
			
				
					|  |  |  |  |         writehtml(f"Radio Off", False) | 
			
		
	
		
			
				
					|  |  |  |  |     else: | 
			
		
	
		
			
				
					|  |  |  |  |         writehtml(f"Log4OM Down", False) | 
			
		
	
		
			
				
					|  |  |  |  |     check.close() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def writehtml(rs, t = "true"): | 
			
		
	
		
			
				
					|  |  |  |  |     header = """<html>\n<head>\n<title>FT-1000MP Status</title> | 
			
		
	
		
			
				
					|  |  |  |  |         <meta http-equiv=\"refresh\" content=\"5\">\n</head>\n""" | 
			
		
	
		
			
				
					|  |  |  |  | 	# if you use CSS then modify for your stylesheet URI | 
			
		
	
		
			
				
					|  |  |  |  |     css = """<link rel=\"stylesheet\" href=\"poole.css\"> | 
			
		
	
		
			
				
					|  |  |  |  |         <link rel=\"stylesheet\" href=\"hyde.css\"> | 
			
		
	
		
			
				
					|  |  |  |  |         <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=PT+Sans:400,400italic,700|Abril+Fatface\">""" | 
			
		
	
		
			
				
					|  |  |  |  |     div = "<body><body class=\"theme-base-0d\"><div class=\"sidebar\"><div class=\"sidebar-about\">" | 
			
		
	
		
			
				
					|  |  |  |  |     footer = "\n</div></div></body>\n</html>" | 
			
		
	
		
			
				
					|  |  |  |  |     isonair = "ON THE AIR<br>\n" | 
			
		
	
		
			
				
					|  |  |  |  |     with open("/var/www/log/radio.html", "w") as html: # Modifiy file location as needed. | 
			
		
	
		
			
				
					|  |  |  |  |         if t == True: # Checks for on-air | 
			
		
	
		
			
				
					|  |  |  |  |              html.write(header + css + div + isonair + rs + footer) # If not using CSS, remove it. | 
			
		
	
		
			
				
					|  |  |  |  |         else: | 
			
		
	
		
			
				
					|  |  |  |  |                         writehtml(f"Radio Off or Log4OM Not Running", False) #writehtml() requires two arguements and you can't be on air if radio is off | 
			
		
	
		
			
				
					|  |  |  |  |                         time.sleep(30) # Slow checks when radio off/no UDP | 
			
		
	
		
			
				
					|  |  |  |  |              html.write(header + css + div + rs + footer) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def log4om(): | 
			
		
	
		
			
				
					|  |  |  |  |         global tot | 
			
		
	
		
			
				
					|  |  |  |  | while True: | 
			
		
	
		
			
				
					|  |  |  |  |     ready = select.select([sock], [], [], 6) # Just give it an extra second | 
			
		
	
		
			
				
					|  |  |  |  |     if ready[0]: | 
			
		
	
		
			
				
					|  |  |  |  |         data, addr = sock.recvfrom(1024) | 
			
		
	
		
			
				
					|  |  |  |  |         root = ET.fromstring(data.decode("utf-8")) | 
			
		
	
		
			
				
					|  |  |  |  |         freq = int(root.find("Freq").text) | 
			
		
	
	
		
			
				
					|  |  |  | @ -40,26 +73,9 @@ def log4om(): | 
			
		
	
		
			
				
					|  |  |  |  |              writehtml(f"Frequency: {f}kHz {mode}<br>Tx Split · Down: {sv:.2f} kHz", onair) | 
			
		
	
		
			
				
					|  |  |  |  |         else: | 
			
		
	
		
			
				
					|  |  |  |  |              writehtml(f"Frequency: {f}kHz {mode}", onair) | 
			
		
	
		
			
				
					|  |  |  |  |                 tot = time.time() #timestamp | 
			
		
	
		
			
				
					|  |  |  |  |         time.sleep(.1) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def writehtml(rs, t = "true"): | 
			
		
	
		
			
				
					|  |  |  |  |     header = "<html>\n<head>\n<title>FT-1000MP Status</title>\n<meta http-equiv=\"refresh\" content=\"5\">\n</head>\n" # Basic Header | 
			
		
	
		
			
				
					|  |  |  |  |     #css = "<link rel=\"stylesheet\" href=\"poole.css\">\n<link rel=\"stylesheet\" href=\"hyde.css\">\n<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=PT+Sans:400,400italic,700|Abril+Fatface\">" # This adds my CSS files. | 
			
		
	
		
			
				
					|  |  |  |  |     #div = "<body><body class=\"theme-base-0d\"><div class=\"sidebar\"><div class=\"sidebar-about\">" # This is additional formatting | 
			
		
	
		
			
				
					|  |  |  |  |     footer = "\n</div></div></body>\n</html>" # footer | 
			
		
	
		
			
				
					|  |  |  |  |     isonair = "ON THE AIR<br>\n" # on-air html | 
			
		
	
		
			
				
					|  |  |  |  |     with open("/var/www/log/radio.html", "w") as html: # Modifiy file location as needed. | 
			
		
	
		
			
				
					|  |  |  |  |         if t == True: # Checks for on-air | 
			
		
	
		
			
				
					|  |  |  |  |              #html.write(header + css + div + isonair + rs + footer) # This will add additional variables (for css, etc.) to the HTML file. | 
			
		
	
		
			
				
					|  |  |  |  |              html.write (header + isonair + rs + footer) # No formatting version | 
			
		
	
		
			
				
					|  |  |  |  |         if t == False: # Checks for on-air | 
			
		
	
		
			
				
					|  |  |  |  |              #html.write(header + css + div + rs + footer) # Same as above without isonair, use if additional html is used | 
			
		
	
		
			
				
					|  |  |  |  |              html.write(header + rs + footer) # No formatting version | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | T = Thread(target=monitor,daemon=True) # Daemon the monitor thread | 
			
		
	
		
			
				
					|  |  |  |  | L = Thread(target=log4om) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | L.start() # Start the UDP thread | 
			
		
	
		
			
				
					|  |  |  |  | time.sleep(5) # Wait 5 seconds in case Log4OM is already running and outputting messages | 
			
		
	
		
			
				
					|  |  |  |  | T.start() # Start monitor thread | 
			
		
	
		
			
				
					|  |  |  |  |     else: | 
			
		
	
		
			
				
					|  |  |  |  |         sleepy = time.time() - tot | 
			
		
	
		
			
				
					|  |  |  |  |         if sleepy > 60: # How often to check in Off/Down state | 
			
		
	
		
			
				
					|  |  |  |  |              checkrig() | 
			
		
	
		
			
				
					|  |  |  |  |              tot = time.time() | 
			
		
	
	
		
			
				
					|  |  |  | 
 |