fix: timing flash + couleur idle LED + diagnostic auto-brightness
🚀 Deploy — JH Photomaton / 🔍 Vérification (push) Has been cancelled
🚀 Deploy — JH Photomaton / 🍓 Deploy sur le Pi (push) Has been cancelled

This commit is contained in:
2026-07-20 19:06:16 +02:00
parent f192ffc92f
commit 19557b20fb
10 changed files with 247 additions and 37 deletions
+45 -9
View File
@@ -52,10 +52,13 @@
.printer-actions { display: flex; gap: .5rem; flex-wrap: wrap; }
.btn-xs { padding: .3rem .65rem; font-size: .8rem; border: none; border-radius: 6px; cursor: pointer; font-weight: 600; transition: opacity .2s; }
.btn-xs:hover { opacity: .8; }
.btn-enable { background: #1a7340; color: #fff; }
.btn-disable { background: #784700; color: #fff; }
.btn-clear { background: #7a0000; color: #fff; }
.btn-reject { background: #555; color: #fff; }
.btn-enable { background: #1a7340; color: #fff; }
.btn-disable { background: #784700; color: #fff; }
.btn-clear { background: #7a0000; color: #fff; }
.btn-reject { background: #555; color: #fff; }
.btn-exclude { background: #4a2080; color: #fff; }
.btn-include { background: #205080; color: #fff; }
.bs-excluded { background: rgba(100,40,160,.2); color: #b085f0; border: 1px solid rgba(100,40,160,.3); }
/* Jobs CUPS détaillés */
.cups-jobs { font-size: .82rem; }
@@ -131,10 +134,13 @@
<span class="badge-printer badge-state bs-{{ p.state }}">
{% if p.state == 'idle' %}✅ Disponible
{% elif p.state == 'printing' %}🖨 En impression
{% elif p.state == 'disabled' %}⏸ Désactivée
{% elif p.state == 'disabled' %}⏸ Désactivée CUPS
{% elif p.state == 'offline' %}❌ Hors ligne
{% else %}❓ {{ p.state }}{% endif %}
</span>
{% if p.excluded %}
<span class="badge-printer bs-excluded">🚫 Exclue du load-balancing</span>
{% endif %}
<span class="badge-printer badge-accept {{ 'bs-accept' if p.accepting else 'bs-reject' }}">
{{ '✓ Accepte les jobs' if p.accepting else '✗ Refuse les jobs' }}
</span>
@@ -193,15 +199,20 @@
<!-- Actions imprimante -->
<div class="printer-actions">
{% if p.state == 'disabled' %}
<button class="btn-xs btn-enable" onclick="printerAction('{{ p.name }}','enable')">▶ Activer</button>
<button class="btn-xs btn-enable" onclick="printerAction('{{ p.name }}','enable')">▶ Activer CUPS</button>
{% else %}
<button class="btn-xs btn-disable" onclick="printerAction('{{ p.name }}','disable')">⏸ Désactiver</button>
<button class="btn-xs btn-disable" onclick="printerAction('{{ p.name }}','disable')">⏸ Désactiver CUPS</button>
{% endif %}
{% if p.accepting %}
<button class="btn-xs btn-reject" onclick="printerAction('{{ p.name }}','reject')">🚫 Refuser jobs</button>
{% else %}
<button class="btn-xs btn-enable" onclick="printerAction('{{ p.name }}','enable')">✓ Accepter jobs</button>
{% endif %}
{% if p.excluded %}
<button class="btn-xs btn-include" onclick="setExcluded('{{ p.name }}', false)">✓ Réintégrer</button>
{% else %}
<button class="btn-xs btn-exclude" onclick="setExcluded('{{ p.name }}', true)">🚫 Exclure</button>
{% endif %}
{% if p.jobs_count %}
<button class="btn-xs btn-clear" onclick="clearJobs('{{ p.name }}')">✕ Vider file</button>
{% endif %}
@@ -426,16 +437,33 @@ async function refreshPrinters() {
acceptBadge.textContent = p.accepting ? '✓ Accepte les jobs' : '✗ Refuse les jobs';
}
// Badge excluded
const statesDiv = card.querySelector('.printer-states');
if (statesDiv) {
const excBadge = statesDiv.querySelector('.bs-excluded');
if (p.excluded && !excBadge) {
const b = document.createElement('span');
b.className = 'badge-printer bs-excluded';
b.textContent = '🚫 Exclue du load-balancing';
statesDiv.appendChild(b);
} else if (!p.excluded && excBadge) {
excBadge.remove();
}
}
// Boutons actions
const actionsDiv = card.querySelector('.printer-actions');
if (actionsDiv) {
actionsDiv.innerHTML = `
${p.state === 'disabled'
? `<button class="btn-xs btn-enable" onclick="printerAction('${p.name}','enable')">▶ Activer</button>`
: `<button class="btn-xs btn-disable" onclick="printerAction('${p.name}','disable')">⏸ Désactiver</button>`}
? `<button class="btn-xs btn-enable" onclick="printerAction('${p.name}','enable')">▶ Activer CUPS</button>`
: `<button class="btn-xs btn-disable" onclick="printerAction('${p.name}','disable')">⏸ Désactiver CUPS</button>`}
${p.accepting
? `<button class="btn-xs btn-reject" onclick="printerAction('${p.name}','reject')">🚫 Refuser jobs</button>`
: `<button class="btn-xs btn-enable" onclick="printerAction('${p.name}','enable')">✓ Accepter jobs</button>`}
${p.excluded
? `<button class="btn-xs btn-include" onclick="setExcluded('${p.name}',false)">✓ Réintégrer</button>`
: `<button class="btn-xs btn-exclude" onclick="setExcluded('${p.name}',true)">🚫 Exclure</button>`}
${p.jobs_count ? `<button class="btn-xs btn-clear" onclick="clearJobs('${p.name}')">✕ Vider file</button>` : ''}
`;
}
@@ -472,6 +500,14 @@ async function printerAction(name, action) {
} catch(err) { showToast('Erreur : ' + err.message, 'error'); }
}
async function setExcluded(name, excluded) {
try {
await api('POST', `/api/print/printers/${name}/set-excluded?excluded=${excluded}`);
showToast(excluded ? `🚫 ${name} exclue du load-balancing` : `${name} réintégrée`, excluded ? 'info' : 'success');
setTimeout(refreshPrinters, 400);
} catch(err) { showToast('Erreur : ' + err.message, 'error'); }
}
async function clearJobs(printer) {
if (!confirm(`Vider toute la file CUPS de ${printer} ?`)) return;
try {
+41
View File
@@ -394,6 +394,16 @@ select.field {
<p id="auto-brightness-status" style="font-size:.78rem; color:var(--text-muted); margin-top:.5rem;">
&#x23F3; Chargement…
</p>
<div style="display:flex; gap:.5rem; align-items:center; margin-top:.5rem; flex-wrap:wrap;">
<button class="btn btn-ghost btn-sm" onclick="measureAmbient()" id="btn-measure-lux">
&#x1F4F7; Tester la mesure
</button>
<span id="lux-status" style="font-size:.8rem; color:var(--text-muted);"></span>
</div>
<div id="lux-info" style="font-size:.78rem; margin-top:.4rem; color:var(--text-muted); display:none;">
Luminosité mesurée : <strong id="lux-val"></strong> / 255 &nbsp;&nbsp;
<span id="lux-desc"></span>
</div>
</div>
</div>
</div>
@@ -875,6 +885,37 @@ async function loadFlashConfig() {
} catch(e) { console.warn('loadFlashConfig:', e); }
}
async function measureAmbient() {
const btn = document.getElementById('btn-measure-lux');
const status = document.getElementById('lux-status');
const info = document.getElementById('lux-info');
btn.disabled = true;
status.textContent = '⏳ Mesure en cours…';
status.style.color = 'var(--text-muted)';
try {
const r = await api('POST', '/api/leds/measure-ambient');
if (r.ok) {
document.getElementById('lux-val').textContent = r.ambient_lux;
document.getElementById('lux-desc').textContent = r.description;
info.style.display = '';
status.textContent = '✅ Mesure réussie';
status.style.color = '#4caf50';
showToast(`✅ Luminosité : ${r.ambient_lux}${r.description}`, 'success');
} else {
status.textContent = '❌ ' + (r.error || 'Erreur inconnue');
status.style.color = '#e05050';
showToast('❌ Mesure impossible : ' + r.error, 'error');
}
} catch(e) {
status.textContent = '❌ Liveview inaccessible';
status.style.color = '#e05050';
showToast('❌ Liveview inaccessible (endpoint 404). Vérifiez que photobooth-app est démarré.', 'error');
} finally {
btn.disabled = false;
setTimeout(() => { status.textContent = ''; }, 6000);
}
}
async function setAutoBrightness(enabled) {
try {
await api('PUT', `/api/leds/auto-brightness?enabled=${enabled}`);