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