Restore safety cutoff to 800F, faster PID loop timing, enhanced simple UI with stats/charts/flight controls, compact TTY display
This commit is contained in:
@@ -155,64 +155,35 @@ class StatusDisplay:
|
||||
return ansi_escape.sub('', text)
|
||||
|
||||
def draw_nail_panel_compact(self, nail_id, status):
|
||||
"""Draw compact status panel for a single nail (for side-by-side layout)."""
|
||||
"""Draw compact status lines for a single nail."""
|
||||
if not status:
|
||||
return []
|
||||
|
||||
lines = []
|
||||
|
||||
# Header
|
||||
return ["No data", "No data", "No data"]
|
||||
|
||||
enabled = status.get("enabled", False)
|
||||
has_error = status.get("error", False)
|
||||
icon = self.format_status_icon(enabled, has_error)
|
||||
|
||||
status_text = "ONLINE" if enabled else "OFFLINE"
|
||||
lines.append("{} {}{}".format(icon, status_text, Colors.RESET))
|
||||
|
||||
# Temperature display
|
||||
state = "ERR" if has_error else ("ON" if enabled else "OFF")
|
||||
|
||||
current = float(status.get("current_temp", 0))
|
||||
setpoint = float(status.get("setpoint", 0))
|
||||
temp_str = "{:5.0f}F".format(current) if current else "ERROR"
|
||||
setpt_str = "{:5.0f}F".format(setpoint)
|
||||
lines.append("T: {} S: {}".format(temp_str, setpt_str))
|
||||
|
||||
# Error display
|
||||
current_str = "{:5.0f}F".format(current) if current else "ERROR"
|
||||
setpoint_str = "{:5.0f}F".format(setpoint)
|
||||
|
||||
error = float(status.get("error", 0))
|
||||
error_color = Colors.RED if abs(error) > 20 else Colors.YELLOW if abs(error) > 5 else Colors.GREEN
|
||||
lines.append("{}Err: {:+5.1f}F{}".format(error_color, error, Colors.RESET))
|
||||
|
||||
# PID Output bar
|
||||
output = float(status.get("output", 0))
|
||||
output_pct = min(100.0, max(0.0, output * 100))
|
||||
bar_filled = int(output_pct / 5)
|
||||
bar = "{}[{}{}]{}".format(
|
||||
Colors.BRIGHT_GREEN,
|
||||
"=" * bar_filled,
|
||||
" " * (5 - bar_filled),
|
||||
Colors.RESET
|
||||
)
|
||||
lines.append("Out: {} {:3.0f}%".format(bar, output_pct))
|
||||
|
||||
# Flight mode
|
||||
mode = status.get("flight_mode", "grounded")
|
||||
mode_short = mode[:7]
|
||||
lines.append("Mode: {}".format(mode_short))
|
||||
|
||||
# Phase
|
||||
phase = status.get("phase", "idle")
|
||||
phase_short = phase[:7]
|
||||
lines.append("Phase: {}".format(phase_short))
|
||||
|
||||
# Safety status
|
||||
bar_filled = int(output_pct / 10)
|
||||
bar = "[{}{}]".format("=" * bar_filled, " " * (10 - bar_filled))
|
||||
|
||||
mode = status.get("flight_mode", "grounded")[:8]
|
||||
phase = status.get("phase", "idle")[:8]
|
||||
safety = status.get("safety", {})
|
||||
temp_ok = safety.get("temp_ok", True)
|
||||
tc_ok = safety.get("tc_ok", True)
|
||||
watchdog_ok = safety.get("watchdog_ok", True)
|
||||
|
||||
safety_status = "{}OK{}".format(Colors.GREEN, Colors.RESET) if (temp_ok and tc_ok and watchdog_ok) else "{}WARN{}".format(Colors.RED, Colors.RESET)
|
||||
lines.append("Safety: {}".format(safety_status))
|
||||
|
||||
return lines
|
||||
safe = "OK" if (safety.get("temp_ok", True) and safety.get("tc_ok", True) and safety.get("watchdog_ok", True)) else "WARN"
|
||||
|
||||
return [
|
||||
"State: {} Temp: {} Set: {}".format(state, current_str, setpoint_str),
|
||||
"Err: {:+6.1f}F Out: {:5.1f}% {}".format(error, output_pct, bar),
|
||||
"Mode: {:<8} Phase: {:<8} Safe: {}".format(mode, phase, safe),
|
||||
]
|
||||
|
||||
def draw_frame(self):
|
||||
"""Draw the complete status display frame."""
|
||||
@@ -261,57 +232,39 @@ class StatusDisplay:
|
||||
nail1_data = self.data.get("nail1", {})
|
||||
nail2_data = self.data.get("nail2", {})
|
||||
|
||||
# Get compact panel lines for both nails
|
||||
# Draw vertical distinct boxes (compact, avoids side bleed)
|
||||
box_width = 58
|
||||
|
||||
def pad(text):
|
||||
if len(text) >= box_width:
|
||||
return text[:box_width]
|
||||
return text + (" " * (box_width - len(text)))
|
||||
|
||||
nail1_lines = self.draw_nail_panel_compact("nail1", nail1_data)
|
||||
lines.append("{}┌{}┐{}".format(Colors.CYAN, "─" * box_width, Colors.RESET))
|
||||
lines.append("{}│{}│{}".format(
|
||||
Colors.CYAN,
|
||||
pad(" NAIL 1"),
|
||||
Colors.RESET,
|
||||
))
|
||||
lines.append("{}├{}┤{}".format(Colors.CYAN, "─" * box_width, Colors.RESET))
|
||||
for panel_line in nail1_lines:
|
||||
lines.append("{}│{}│{}".format(Colors.CYAN, pad(panel_line), Colors.RESET))
|
||||
lines.append("{}└{}┘{}".format(Colors.CYAN, "─" * box_width, Colors.RESET))
|
||||
|
||||
lines.append("")
|
||||
|
||||
nail2_lines = self.draw_nail_panel_compact("nail2", nail2_data)
|
||||
|
||||
# Pad lines to same length
|
||||
max_lines = max(len(nail1_lines), len(nail2_lines))
|
||||
while len(nail1_lines) < max_lines:
|
||||
nail1_lines.append("")
|
||||
while len(nail2_lines) < max_lines:
|
||||
nail2_lines.append("")
|
||||
|
||||
# Draw separate boxes for each nail side-by-side
|
||||
# Top border
|
||||
lines.append("{}┌──────────────────────────┐ ┌──────────────────────────┐{}".format(
|
||||
Colors.CYAN, Colors.RESET))
|
||||
|
||||
# Header line with nail names
|
||||
n1_header = "{}NAIL 1{}".format(Colors.BRIGHT_RED + Colors.BOLD, Colors.CYAN)
|
||||
n2_header = "{}NAIL 2{}".format(Colors.BRIGHT_BLUE + Colors.BOLD, Colors.CYAN)
|
||||
# Manually pad with spaces after stripping ANSI codes
|
||||
n1_spaces = 22 - len(self.strip_ansi(n1_header))
|
||||
n2_spaces = 22 - len(self.strip_ansi(n2_header))
|
||||
lines.append("{}│ {}{:<{}}│ │ {}{:<{}}│{}".format(
|
||||
Colors.CYAN, n1_header, "", n1_spaces, n2_header, "", n2_spaces, Colors.RESET))
|
||||
|
||||
# Middle border
|
||||
lines.append("{}├──────────────────────────┤ ├──────────────────────────┤{}".format(
|
||||
Colors.CYAN, Colors.RESET))
|
||||
|
||||
# Content lines
|
||||
for n1_line, n2_line in zip(nail1_lines, nail2_lines):
|
||||
# Calculate visible length without ANSI codes
|
||||
n1_visible = self.strip_ansi(n1_line)[:22]
|
||||
n2_visible = self.strip_ansi(n2_line)[:22]
|
||||
n1_spaces = 22 - len(n1_visible)
|
||||
n2_spaces = 22 - len(n2_visible)
|
||||
|
||||
lines.append("{}│ {}{:<{}}│ │ {}{:<{}}│{}".format(
|
||||
Colors.CYAN,
|
||||
n1_line,
|
||||
"",
|
||||
n1_spaces,
|
||||
n2_line,
|
||||
"",
|
||||
n2_spaces,
|
||||
Colors.RESET
|
||||
))
|
||||
|
||||
# Bottom border
|
||||
lines.append("{}└──────────────────────────┘ └──────────────────────────┘{}".format(
|
||||
Colors.CYAN, Colors.RESET))
|
||||
lines.append("{}┌{}┐{}".format(Colors.CYAN, "─" * box_width, Colors.RESET))
|
||||
lines.append("{}│{}│{}".format(
|
||||
Colors.CYAN,
|
||||
pad(" NAIL 2"),
|
||||
Colors.RESET,
|
||||
))
|
||||
lines.append("{}├{}┤{}".format(Colors.CYAN, "─" * box_width, Colors.RESET))
|
||||
for panel_line in nail2_lines:
|
||||
lines.append("{}│{}│{}".format(Colors.CYAN, pad(panel_line), Colors.RESET))
|
||||
lines.append("{}└{}┘{}".format(Colors.CYAN, "─" * box_width, Colors.RESET))
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user