Reorganize display with side-by-side nail panels for more header space
- Moved NAIL 1 and NAIL 2 panels to side-by-side layout - Created compact panel format with essential metrics only - Freed up vertical space for larger ASCII art header - New header shows 'piNail' in larger ASCII art - More efficient use of screen space and cleaner layout - Deployed and verified on Pi
This commit is contained in:
@@ -148,79 +148,69 @@ class StatusDisplay:
|
|||||||
color, label = phases.get(phase, (Colors.WHITE, " ? "))
|
color, label = phases.get(phase, (Colors.WHITE, " ? "))
|
||||||
return "{}{}{}".format(color, label, Colors.RESET)
|
return "{}{}{}".format(color, label, Colors.RESET)
|
||||||
|
|
||||||
def draw_nail_panel(self, nail_id, status):
|
def draw_nail_panel_compact(self, nail_id, status):
|
||||||
"""Draw status panel for a single nail."""
|
"""Draw compact status panel for a single nail (for side-by-side layout)."""
|
||||||
if not status:
|
if not status:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
# Header
|
# Header
|
||||||
nail_name = "NAIL 1" if nail_id == "nail1" else "NAIL 2"
|
nail_name = "N1" if nail_id == "nail1" else "N2"
|
||||||
enabled = status.get("enabled", False)
|
enabled = status.get("enabled", False)
|
||||||
has_error = status.get("error", False)
|
has_error = status.get("error", False)
|
||||||
icon = self.format_status_icon(enabled, has_error)
|
icon = self.format_status_icon(enabled, has_error)
|
||||||
|
|
||||||
lines.append("{}{} {} {}{}".format(
|
lines.append("{}{}{}{}".format(
|
||||||
Colors.BOLD, nail_name, icon,
|
Colors.BOLD, nail_name, icon,
|
||||||
"ONLINE" if enabled else "OFFLINE",
|
"ON" if enabled else "OFF"
|
||||||
Colors.RESET
|
) + Colors.RESET)
|
||||||
))
|
|
||||||
|
|
||||||
# Temperature display
|
# Temperature display
|
||||||
current = float(status.get("current_temp", 0))
|
current = float(status.get("current_temp", 0))
|
||||||
setpoint = float(status.get("setpoint", 0))
|
setpoint = float(status.get("setpoint", 0))
|
||||||
lines.append(" Temp: {} / {}{}C".format(
|
lines.append("T:{} S:{}".format(
|
||||||
self.format_temp(current),
|
"{:5.0f}F".format(current) if current else "ERR",
|
||||||
self.format_temp(setpoint),
|
"{:5.0f}F".format(setpoint)
|
||||||
Colors.RESET
|
|
||||||
))
|
))
|
||||||
|
|
||||||
# Error display
|
# Error display
|
||||||
error = float(status.get("error", 0))
|
error = float(status.get("error", 0))
|
||||||
error_color = Colors.RED if abs(error) > 20 else Colors.YELLOW if abs(error) > 5 else Colors.GREEN
|
error_color = Colors.RED if abs(error) > 20 else Colors.YELLOW if abs(error) > 5 else Colors.GREEN
|
||||||
lines.append(" Error: {}{:+7.1f}F{}".format(error_color, error, Colors.RESET))
|
lines.append("{}E:{:+6.1f}{}".format(error_color, error, Colors.RESET))
|
||||||
|
|
||||||
# PID Output
|
# PID Output bar
|
||||||
output = float(status.get("output", 0))
|
output = float(status.get("output", 0))
|
||||||
output_pct = min(100.0, max(0.0, output * 100))
|
output_pct = min(100.0, max(0.0, output * 100))
|
||||||
bar_filled = int(output_pct / 5)
|
bar_filled = int(output_pct / 10)
|
||||||
bar = "{}|{}{}|{}".format(
|
bar = "{}|{}{}|{}".format(
|
||||||
Colors.BRIGHT_GREEN,
|
Colors.BRIGHT_GREEN,
|
||||||
"=" * bar_filled,
|
"=" * bar_filled,
|
||||||
" " * (20 - bar_filled),
|
" " * (10 - bar_filled),
|
||||||
Colors.RESET
|
Colors.RESET
|
||||||
)
|
)
|
||||||
lines.append(" Output: {} {:5.1f}%".format(bar, output_pct))
|
lines.append("Out: {} {:3.0f}%".format(bar, output_pct))
|
||||||
|
|
||||||
# Flight mode and phase
|
# Flight mode and phase
|
||||||
mode = status.get("flight_mode", "grounded")
|
mode = status.get("flight_mode", "grounded")
|
||||||
phase = status.get("phase", "idle")
|
phase = status.get("phase", "idle")
|
||||||
lines.append(" Mode: {} Phase: {}".format(
|
mode_short = mode[:4].upper()
|
||||||
self.format_mode_badge(mode),
|
phase_short = phase[:4].upper()
|
||||||
self.format_phase_badge(phase)
|
lines.append("{}M:{} P:{}{}".format(
|
||||||
|
Colors.CYAN,
|
||||||
|
mode_short,
|
||||||
|
phase_short,
|
||||||
|
Colors.RESET
|
||||||
))
|
))
|
||||||
|
|
||||||
# PID coefficients
|
|
||||||
pid = status.get("pid", {})
|
|
||||||
kp = float(pid.get("kP", 0))
|
|
||||||
ki = float(pid.get("kI", 0))
|
|
||||||
kd = float(pid.get("kD", 0))
|
|
||||||
lines.append(" PID: kP={:6.2f} kI={:6.2f} kD={:6.2f}".format(kp, ki, kd))
|
|
||||||
|
|
||||||
# Integral and derivative
|
|
||||||
integral = float(pid.get("integral", 0))
|
|
||||||
derivative = float(pid.get("derivative", 0))
|
|
||||||
lines.append(" Err-I: {:8.1f} Err-D: {:8.3f}".format(integral, derivative))
|
|
||||||
|
|
||||||
# Safety status
|
# Safety status
|
||||||
safety = status.get("safety", {})
|
safety = status.get("safety", {})
|
||||||
temp_ok = safety.get("temp_ok", True)
|
temp_ok = safety.get("temp_ok", True)
|
||||||
tc_ok = safety.get("tc_ok", True)
|
tc_ok = safety.get("tc_ok", True)
|
||||||
watchdog_ok = safety.get("watchdog_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)
|
safety_status = "{}S:OK{}".format(Colors.GREEN, Colors.RESET) if (temp_ok and tc_ok and watchdog_ok) else "{}S:WARN{}".format(Colors.RED, Colors.RESET)
|
||||||
lines.append(" Safety: {}".format(safety_status))
|
lines.append(safety_status)
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
@@ -231,25 +221,33 @@ class StatusDisplay:
|
|||||||
# ASCII Art Title with timestamp side-by-side
|
# ASCII Art Title with timestamp side-by-side
|
||||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append("{}{}{:<20} {}{}{}".format(
|
lines.append("{}{}{:<22} {}{}{}".format(
|
||||||
Colors.BRIGHT_CYAN + Colors.BOLD,
|
Colors.BRIGHT_CYAN + Colors.BOLD,
|
||||||
" ___ _ _ _ _",
|
" ___ __ _ _ _ _",
|
||||||
"",
|
"",
|
||||||
Colors.DIM,
|
Colors.DIM,
|
||||||
timestamp,
|
timestamp,
|
||||||
Colors.RESET
|
Colors.RESET
|
||||||
))
|
))
|
||||||
lines.append("{}{}{:<20} {}{}{}".format(
|
lines.append("{}{}{:<22} {}{}{}".format(
|
||||||
Colors.BRIGHT_CYAN + Colors.BOLD,
|
Colors.BRIGHT_CYAN + Colors.BOLD,
|
||||||
"| \\| | __ _ _ _| | ||_|",
|
" / _ \\ / / | \\| | | | |",
|
||||||
"",
|
"",
|
||||||
Colors.DIM,
|
Colors.DIM,
|
||||||
"piNail2 Status",
|
"piNail2 e-Nail",
|
||||||
Colors.RESET
|
Colors.RESET
|
||||||
))
|
))
|
||||||
lines.append("{}{}{:<20}{}".format(
|
lines.append("{}{}{:<22} {}{}{}".format(
|
||||||
Colors.BRIGHT_CYAN + Colors.BOLD,
|
Colors.BRIGHT_CYAN + Colors.BOLD,
|
||||||
"|__/|_|__|||_||_||_|\\__/",
|
"| |_| |/ /__ \\ / |_|_|",
|
||||||
|
"",
|
||||||
|
Colors.DIM,
|
||||||
|
"Temperature Controller",
|
||||||
|
Colors.RESET
|
||||||
|
))
|
||||||
|
lines.append("{}{}{:<22}{}".format(
|
||||||
|
Colors.BRIGHT_CYAN + Colors.BOLD,
|
||||||
|
" \\___/______| \\/ ",
|
||||||
"",
|
"",
|
||||||
Colors.RESET
|
Colors.RESET
|
||||||
))
|
))
|
||||||
@@ -261,29 +259,30 @@ class StatusDisplay:
|
|||||||
nail1_data = self.data.get("nail1", {})
|
nail1_data = self.data.get("nail1", {})
|
||||||
nail2_data = self.data.get("nail2", {})
|
nail2_data = self.data.get("nail2", {})
|
||||||
|
|
||||||
# Nail 1 panel
|
# Get compact panel lines for both nails
|
||||||
lines.append("{}┌─ NAIL 1 {}".format(Colors.CYAN, Colors.RESET))
|
nail1_lines = self.draw_nail_panel_compact("nail1", nail1_data)
|
||||||
lines.append("│")
|
nail2_lines = self.draw_nail_panel_compact("nail2", nail2_data)
|
||||||
for line in self.draw_nail_panel("nail1", nail1_data):
|
|
||||||
lines.append("│ {}".format(line))
|
|
||||||
lines.append("│")
|
|
||||||
|
|
||||||
# Separator
|
# Pad lines to same length
|
||||||
lines.append("")
|
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("")
|
||||||
|
|
||||||
# Nail 2 panel
|
# Draw side-by-side panels
|
||||||
lines.append("{}┌─ NAIL 2 {}".format(Colors.CYAN, Colors.RESET))
|
lines.append("{}┌─ NAIL 1 ────────────┬─ NAIL 2 ────────────┐{}".format(
|
||||||
lines.append("│")
|
Colors.CYAN, Colors.RESET))
|
||||||
for line in self.draw_nail_panel("nail2", nail2_data):
|
|
||||||
lines.append("│ {}".format(line))
|
for n1_line, n2_line in zip(nail1_lines, nail2_lines):
|
||||||
lines.append("│")
|
# Left pad lines to 20 chars, right pad n2 lines
|
||||||
|
left = "│ {:<18} ".format(n1_line[:18])
|
||||||
|
right = "│ {:<18} │".format(n2_line[:18])
|
||||||
|
lines.append("{}{}{}".format(left, right, Colors.RESET))
|
||||||
|
|
||||||
# Footer
|
# Footer
|
||||||
lines.append("")
|
lines.append("{}└────────────────────┴────────────────────┘{}".format(
|
||||||
lines.append("{}═════════════════════════════════════════════════════{}".format(
|
Colors.CYAN, Colors.RESET))
|
||||||
Colors.CYAN,
|
|
||||||
Colors.RESET
|
|
||||||
))
|
|
||||||
|
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user