Release v2.0.0 with dual-nail control and hardened safety
This commit is contained in:
@@ -4,7 +4,13 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>piNail2 Controller</title>
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="apple-mobile-web-app-title" content="piNail2">
|
||||
<link rel="icon" type="image/png" href="/static/img/pi_favicon.png">
|
||||
<link rel="apple-touch-icon" href="/static/img/pi_favicon.png">
|
||||
<link rel="manifest" href="/static/manifest.webmanifest">
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
</head>
|
||||
@@ -15,23 +21,62 @@
|
||||
<h1>Controller</h1>
|
||||
</div>
|
||||
<div class="conn-wrap">
|
||||
<span id="last-ack" class="last-ack">Last command: none</span>
|
||||
<span id="backend-status" class="backend-status">Backend: Online</span>
|
||||
<div class="mode-switch" role="group" aria-label="UI mode">
|
||||
<button id="mode-simple-btn" class="mode-btn" onclick="setUiMode('simple')">Simple</button>
|
||||
<button id="mode-nail1-btn" class="mode-btn" onclick="setUiMode('nail1')">Nail 1</button>
|
||||
<button id="mode-nail2-btn" class="mode-btn" onclick="setUiMode('nail2')">Nail 2</button>
|
||||
</div>
|
||||
<button id="install-btn" class="install-btn" onclick="installApp()" hidden>Install App</button>
|
||||
<span id="last-ack" class="last-ack advanced-only">Last command: none</span>
|
||||
<span id="backend-status" class="backend-status advanced-only">Backend: Online</span>
|
||||
<div id="connection-status" class="status-dot connected" title="Connected"></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<!-- Top row: Big temp display + power toggle -->
|
||||
<section class="simple-only dual-simple" id="simple-dual">
|
||||
<div class="simple-card" id="simple-card-nail1">
|
||||
<h3>Nail 1</h3>
|
||||
<div class="simple-temp"><span id="simple-temp-nail1">---</span>°F</div>
|
||||
<div class="simple-line">Mode: <span id="simple-mode-nail1">grounded</span></div>
|
||||
<div class="simple-line">Target: <span id="simple-target-nail1">---</span>°F</div>
|
||||
<div class="simple-controls">
|
||||
<input type="number" id="simple-setpoint-nail1" value="530" min="0" max="800" step="5">
|
||||
<button class="apply-btn" onclick="simpleApplySetpoint(1)">Set</button>
|
||||
<button id="simple-power-nail1" class="power-mini off" onclick="simpleTogglePower(1)">OFF</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="simple-card" id="simple-card-nail2">
|
||||
<h3>Nail 2</h3>
|
||||
<div class="simple-temp"><span id="simple-temp-nail2">---</span>°F</div>
|
||||
<div class="simple-line">Mode: <span id="simple-mode-nail2">grounded</span></div>
|
||||
<div class="simple-line">Target: <span id="simple-target-nail2">---</span>°F</div>
|
||||
<div class="simple-controls">
|
||||
<input type="number" id="simple-setpoint-nail2" value="530" min="0" max="800" step="5">
|
||||
<button class="apply-btn" onclick="simpleApplySetpoint(2)">Set</button>
|
||||
<button id="simple-power-nail2" class="power-mini off" onclick="simpleTogglePower(2)">OFF</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="hero">
|
||||
<div class="temp-display">
|
||||
<span id="current-temp" class="temp-value">---</span>
|
||||
<span class="temp-unit">°F</span>
|
||||
<div id="advanced-nail-label" class="wall-clock">Nail 1</div>
|
||||
<div id="wall-clock" class="wall-clock">--:--:--</div>
|
||||
<div class="temp-main">
|
||||
<span id="current-temp" class="temp-value">---</span>
|
||||
<span class="temp-unit">°F</span>
|
||||
</div>
|
||||
<div id="error-stats" class="error-stats">Err(3m): --</div>
|
||||
</div>
|
||||
<div class="hero-right">
|
||||
<div class="setpoint-display">
|
||||
Target: <span id="current-setpoint">---</span>°F
|
||||
</div>
|
||||
<div id="mode-pill" class="mode-pill">Mode: grounded</div>
|
||||
<div id="mode-eta" class="mode-eta">ETA: --</div>
|
||||
<div id="sched-eta" class="mode-eta">Next descent: --</div>
|
||||
<div id="autotune-pill" class="autotune-pill idle">Autotune: Idle</div>
|
||||
<button id="power-btn" class="power-btn off" onclick="togglePower()">OFF</button>
|
||||
</div>
|
||||
@@ -52,9 +97,8 @@
|
||||
<canvas id="temp-chart"></canvas>
|
||||
</section>
|
||||
|
||||
<!-- Controls -->
|
||||
<section class="controls">
|
||||
<!-- Setpoint -->
|
||||
<!-- Setpoint (always visible) -->
|
||||
<section class="controls controls-setpoint">
|
||||
<div class="control-group">
|
||||
<h3>Setpoint</h3>
|
||||
<div class="setpoint-controls">
|
||||
@@ -69,9 +113,34 @@
|
||||
<!-- Filled by JS -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Advanced controls row -->
|
||||
<section class="controls controls-advanced-row advanced-only">
|
||||
<!-- Loop Timing -->
|
||||
<div class="control-group">
|
||||
<h3>Loop Timing</h3>
|
||||
<div class="pid-controls">
|
||||
<label>
|
||||
Loop Size (ms)
|
||||
<input type="number" id="control-loop-size" step="100" min="1500" max="5000" value="3000">
|
||||
</label>
|
||||
<label>
|
||||
Sleep (s)
|
||||
<input type="number" id="control-sleep-time" step="0.01" min="0.15" max="0.6" value="0.4">
|
||||
</label>
|
||||
<button class="apply-btn" onclick="applyControlTiming()">Apply Timing</button>
|
||||
</div>
|
||||
<div class="autotune-controls">
|
||||
<button class="adj-btn" onclick="applyTimingProfile('conservative')">Conservative</button>
|
||||
<button class="adj-btn" onclick="applyTimingProfile('balanced')">Balanced</button>
|
||||
<button class="adj-btn" onclick="applyTimingProfile('responsive')">Responsive</button>
|
||||
<span class="autotune-status idle">Limits: 1500-5000ms, 0.15-0.6s</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PID Tuning -->
|
||||
<div class="control-group">
|
||||
<div class="control-group advanced-only">
|
||||
<h3>PID Tuning</h3>
|
||||
<div class="pid-controls">
|
||||
<label>
|
||||
@@ -104,8 +173,55 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="controls controls-advanced-row advanced-only">
|
||||
<div class="control-group">
|
||||
<h3>Flight Modes</h3>
|
||||
<div class="autotune-controls">
|
||||
<button class="adj-btn" onclick="setFlightMode('takeoff')">Takeoff</button>
|
||||
<button class="adj-btn" onclick="setFlightMode('descent')">Descent</button>
|
||||
<span id="flight-mode-status" class="autotune-status idle">Use power button for Grounded/Cruise.</span>
|
||||
</div>
|
||||
<div class="pid-controls">
|
||||
<label>
|
||||
Takeoff (s)
|
||||
<input type="number" id="flight-takeoff-seconds" step="5" min="5" max="1800" value="300">
|
||||
</label>
|
||||
<label>
|
||||
Descent (s)
|
||||
<input type="number" id="flight-descent-seconds" step="5" min="5" max="1800" value="300">
|
||||
</label>
|
||||
<label>
|
||||
Descent target (F)
|
||||
<input type="number" id="flight-descent-target" step="5" min="80" max="500" value="120">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<h3>Descent Scheduler</h3>
|
||||
<div class="pid-controls">
|
||||
<label>
|
||||
Scheduler
|
||||
<select id="sched-enabled" onchange="schedulerEnabledChanged()">
|
||||
<option value="true">Enabled</option>
|
||||
<option value="false">Disabled</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Add time (HH:MM)
|
||||
<input type="text" id="sched-time-input" value="23:00" placeholder="HH:MM" inputmode="numeric" maxlength="5">
|
||||
</label>
|
||||
<button class="adj-btn" onclick="addSchedulerTime()">Add Time</button>
|
||||
</div>
|
||||
<div id="sched-time-list" class="sched-time-list"></div>
|
||||
<div class="autotune-controls">
|
||||
<span class="autotune-status idle">Scheduler only triggers descent -> grounded. No auto takeoff.</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Status bar -->
|
||||
<section class="status-bar">
|
||||
<section class="status-bar advanced-only">
|
||||
<div class="status-item">
|
||||
<span class="label">Output</span>
|
||||
<span id="status-output" class="value">0</span>
|
||||
|
||||
Reference in New Issue
Block a user