Second Version. Major rewrite
							parent
							
								
									86b32701b3
								
							
						
					
					
						commit
						3a0ee78b86
					
				| @ -0,0 +1,28 @@ | ||||
| BSD 3-Clause License | ||||
| 
 | ||||
| Copyright (c) 2023, Jay Moore | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
| 
 | ||||
| 1. Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
| 
 | ||||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|    this list of conditions and the following disclaimer in the documentation | ||||
|    and/or other materials provided with the distribution. | ||||
| 
 | ||||
| 3. Neither the name of the copyright holder nor the names of its | ||||
|    contributors may be used to endorse or promote products derived from | ||||
|    this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| @ -1,65 +1,81 @@ | ||||
| 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) | ||||
|                 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 | ||||
| 
 | ||||
| def log4om(): | ||||
|         global tot | ||||
|         while True: | ||||
|                 data, addr = sock.recvfrom(1024) | ||||
|                 root = ET.fromstring(data.decode("utf-8")) | ||||
|                 freq = int(root.find("Freq").text) | ||||
|                 tx_freq = int(root.find("TXFreq").text) | ||||
|                 mode = root.find("Mode").text | ||||
|                 onair = (root.find("IsTransmitting").text == "true") | ||||
|                 f = freq / 100 | ||||
|                 tf = tx_freq / 100 | ||||
|                 sv = tf - f # Determines split value | ||||
|                 if sv > 0: | ||||
|                     writehtml(f"Frequency: {f}kHz {mode}<br>Tx Split · Up: {sv:.2f} kHz", onair) | ||||
|                 elif sv < 0: | ||||
|                     sv = sv * -1 # Invert negative numbers | ||||
|                     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 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>\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 | ||||
|     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) # 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) | ||||
|              html.write(header + css + div + isonair + rs + footer) # If not using CSS, remove it. | ||||
|         else: | ||||
|              html.write(header + css + div + rs + footer) | ||||
| 
 | ||||
| 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 | ||||
| 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) | ||||
|         tx_freq = int(root.find("TXFreq").text) | ||||
|         mode = root.find("Mode").text | ||||
|         onair = (root.find("IsTransmitting").text == "true") | ||||
|         f = freq / 100 | ||||
|         tf = tx_freq / 100 | ||||
|         sv = tf - f # Determines split value | ||||
|         if sv > 0: | ||||
|              writehtml(f"Frequency: {f}kHz {mode}<br>Tx Split · Up: {sv:.2f} kHz", onair) | ||||
|         elif sv < 0: | ||||
|              sv = sv * -1 # Invert negative numbers | ||||
|              writehtml(f"Frequency: {f}kHz {mode}<br>Tx Split · Down: {sv:.2f} kHz", onair) | ||||
|         else: | ||||
|              writehtml(f"Frequency: {f}kHz {mode}", onair) | ||||
|         time.sleep(.1) | ||||
|     else: | ||||
|         sleepy = time.time() - tot | ||||
|         if sleepy > 60: # How often to check in Off/Down state | ||||
|              checkrig() | ||||
|              tot = time.time() | ||||
|  | ||||
					Loading…
					
					
				
		Reference in New Issue