Added go/nogo
This commit is contained in:
146
main.py
146
main.py
@@ -1,10 +1,38 @@
|
||||
import tkinter as tk
|
||||
import time
|
||||
from datetime import datetime
|
||||
import requests
|
||||
import csv
|
||||
import io
|
||||
|
||||
HTML_FILE = "countdown.html"
|
||||
COUNTDOWN_HTML = "countdown.html"
|
||||
GONOGO_HTML = "gonogo.html"
|
||||
SHEET_LINK = "https://docs.google.com/spreadsheets/d/1UPJTW8vH2mgEzispjg_Y_zSqYTFaLoxuoZnqleVlSZ0/export?format=csv&gid=855477916"
|
||||
session = requests.Session()
|
||||
|
||||
def write_html(mission_name, timer_text):
|
||||
# -------------------------
|
||||
# Fetch Go/No-Go Data
|
||||
# -------------------------
|
||||
def fetch_gonogo():
|
||||
"""Fetch Go/No-Go parameters from L2, L3, L4 (rows 2,3,4; col 12)"""
|
||||
try:
|
||||
resp = session.get(SHEET_LINK, timeout=2) # timeout for faster failure if network is slow
|
||||
resp.raise_for_status()
|
||||
reader = csv.reader(io.StringIO(resp.text))
|
||||
data = list(reader)
|
||||
gonogo = []
|
||||
for i in [1, 2, 3]:
|
||||
value = data[i][11] if len(data[i]) > 11 else "N/A"
|
||||
gonogo.append(value.strip().upper()) # <-- always uppercase
|
||||
return gonogo
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to fetch Go/No-Go: {e}")
|
||||
return ["ERROR"] * 3
|
||||
|
||||
# -------------------------
|
||||
# Write Countdown HTML
|
||||
# -------------------------
|
||||
def write_countdown_html(mission_name, timer_text):
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -17,25 +45,11 @@ body {{
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}}
|
||||
#mission {{
|
||||
color: white;
|
||||
font-family: Consolas, monospace;
|
||||
font-size: 4vw;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 90vw;
|
||||
text-align: center;
|
||||
}}
|
||||
#timer {{
|
||||
color: white;
|
||||
font-family: Consolas, monospace;
|
||||
font-size: 8vw;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}}
|
||||
#mission {{ font-size: 4vw; margin-bottom: 20px; }}
|
||||
#timer {{ font-size: 8vw; margin-bottom: 40px; }}
|
||||
</style>
|
||||
<script>
|
||||
setTimeout(() => location.reload(), 1000);
|
||||
@@ -46,10 +60,62 @@ setTimeout(() => location.reload(), 1000);
|
||||
<div id="timer">{timer_text}</div>
|
||||
</body>
|
||||
</html>"""
|
||||
with open(HTML_FILE, "w", encoding="utf-8") as f:
|
||||
with open(COUNTDOWN_HTML, "w", encoding="utf-8") as f:
|
||||
f.write(html)
|
||||
|
||||
# -------------------------
|
||||
# Write Go/No-Go HTML
|
||||
# -------------------------
|
||||
def write_gonogo_html(gonogo_values=None):
|
||||
if gonogo_values is None:
|
||||
gonogo_values = ["N/A", "N/A", "N/A"]
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body {{
|
||||
margin: 0;
|
||||
background-color: black;
|
||||
color: white;
|
||||
font-family: Consolas, monospace;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}}
|
||||
#gonogo {{
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
}}
|
||||
.status-box {{
|
||||
border: 2px solid white;
|
||||
padding: 20px 40px;
|
||||
font-size: 2.5vw;
|
||||
text-align: center;
|
||||
background-color: #111;
|
||||
}}
|
||||
.go {{ color: #0f0; }}
|
||||
.nogo {{ color: #f00; }}
|
||||
</style>
|
||||
<script>
|
||||
setTimeout(() => location.reload(), 5000);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="gonogo">
|
||||
<div class="status-box {'go' if gonogo_values[0].lower()=='go' else 'nogo'}">Range: {gonogo_values[0]}</div>
|
||||
<div class="status-box {'go' if gonogo_values[2].lower()=='go' else 'nogo'}">Vehicle: {gonogo_values[2]}</div>
|
||||
<div class="status-box {'go' if gonogo_values[1].lower()=='go' else 'nogo'}">Weather: {gonogo_values[1]}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>"""
|
||||
with open(GONOGO_HTML, "w", encoding="utf-8") as f:
|
||||
f.write(html)
|
||||
|
||||
# -------------------------
|
||||
# Countdown App
|
||||
# -------------------------
|
||||
class CountdownApp:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
@@ -66,15 +132,11 @@ class CountdownApp:
|
||||
self.hold_start_time = None
|
||||
self.remaining_time = 0
|
||||
self.mission_name = "Mission"
|
||||
self.gonogo_values = fetch_gonogo()
|
||||
self.last_gonogo_update = time.time()
|
||||
|
||||
# Display
|
||||
self.text = tk.Label(
|
||||
root,
|
||||
text="T-00:00:00",
|
||||
font=("Consolas", 80, "bold"),
|
||||
fg="white",
|
||||
bg="black"
|
||||
)
|
||||
self.text = tk.Label(root, text="T-00:00:00", font=("Consolas", 80, "bold"), fg="white", bg="black")
|
||||
self.text.pack(padx=50, pady=20)
|
||||
|
||||
# Mission name input
|
||||
@@ -139,7 +201,6 @@ class CountdownApp:
|
||||
self.reset_btn = tk.Button(frame_buttons, text="⟳ Reset", command=self.reset, font=("Arial", 14))
|
||||
self.reset_btn.grid(row=0, column=3, padx=5)
|
||||
|
||||
|
||||
self.update_inputs()
|
||||
self.update_clock()
|
||||
|
||||
@@ -186,7 +247,7 @@ class CountdownApp:
|
||||
total_seconds = (target_today - now).total_seconds()
|
||||
except Exception:
|
||||
self.text.config(text="Invalid time")
|
||||
write_html(self.mission_name, "Invalid time")
|
||||
write_countdown_html(self.mission_name, "Invalid time")
|
||||
return
|
||||
|
||||
self.target_time = time.time() + total_seconds
|
||||
@@ -213,11 +274,10 @@ class CountdownApp:
|
||||
self.hold_btn.grid_remove()
|
||||
self.resume_btn.grid()
|
||||
|
||||
|
||||
def scrub(self):
|
||||
self.scrubbed = True
|
||||
self.running = False
|
||||
write_html(self.mission_name, "SCRUB")
|
||||
write_countdown_html(self.mission_name, "SCRUB")
|
||||
self.text.config(text="SCRUB")
|
||||
|
||||
def reset(self):
|
||||
@@ -226,7 +286,7 @@ class CountdownApp:
|
||||
self.scrubbed = False
|
||||
self.counting_up = False
|
||||
self.text.config(text="T-00:00:00")
|
||||
write_html(self.mission_name, "T-00:00:00")
|
||||
write_countdown_html(self.mission_name, "T-00:00:00")
|
||||
self.show_hold_button()
|
||||
|
||||
# ----------------------------
|
||||
@@ -239,19 +299,21 @@ class CountdownApp:
|
||||
return f"{prefix}{h:02}:{m:02}:{s:02}"
|
||||
|
||||
def update_clock(self):
|
||||
now_time = time.time()
|
||||
|
||||
# Update timer
|
||||
if self.running and not self.scrubbed:
|
||||
now = time.time()
|
||||
if self.on_hold:
|
||||
elapsed = int(now - self.hold_start_time)
|
||||
elapsed = int(now_time - self.hold_start_time)
|
||||
timer_text = self.format_time(elapsed, "H+")
|
||||
elif self.target_time:
|
||||
diff = int(self.target_time - now)
|
||||
diff = int(self.target_time - now_time)
|
||||
if diff <= 0 and not self.counting_up:
|
||||
self.counting_up = True
|
||||
self.target_time = now
|
||||
self.target_time = now_time
|
||||
diff = 0
|
||||
if self.counting_up:
|
||||
elapsed = int(now - self.target_time)
|
||||
elapsed = int(now_time - self.target_time)
|
||||
timer_text = self.format_time(elapsed, "T+")
|
||||
else:
|
||||
timer_text = self.format_time(diff, "T-")
|
||||
@@ -261,12 +323,20 @@ class CountdownApp:
|
||||
timer_text = self.text.cget("text")
|
||||
|
||||
self.text.config(text=timer_text)
|
||||
write_html(self.mission_name, timer_text)
|
||||
write_countdown_html(self.mission_name, timer_text)
|
||||
|
||||
# Update Go/No-Go every 10 seconds
|
||||
if now_time - self.last_gonogo_update > 0.5:
|
||||
self.gonogo_values = fetch_gonogo()
|
||||
write_gonogo_html(self.gonogo_values)
|
||||
self.last_gonogo_update = now_time
|
||||
|
||||
self.root.after(200, self.update_clock)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = tk.Tk()
|
||||
app = CountdownApp(root)
|
||||
write_html("Mission", "T-00:00:00")
|
||||
write_countdown_html("Mission", "T-00:00:00")
|
||||
write_gonogo_html(fetch_gonogo())
|
||||
root.mainloop()
|
||||
|
||||
Reference in New Issue
Block a user