feat: add deep sleep batch caching, wake log, and log viewer tools
- Batch-fetch asset IDs in deep sleep mode with NVS caching to reduce network calls and improve battery life (configurable batch size 1-50) - Add wake_log module: persistent CSV log of each photo cycle surviving reboots and deep sleep, with download/clear via web UI - Add browser-based log viewer and log comparison tools (tools/) - Update .gitignore to exclude .cursor/, chat-summaries/, wake_*.csv, and .DS_Store Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
31
data/app.js
31
data/app.js
@@ -110,6 +110,13 @@ async function renderSlideshow(el) {
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Deep Sleep Batch Size</h2>
|
||||
<p style="opacity:0.7;font-size:13px;margin-bottom:8px">Photos to pre-fetch per API call in deep sleep mode. Higher = fewer network calls, better battery life.</p>
|
||||
<div class="field">
|
||||
<input type="number" id="timerBatch" min="1" max="50" value="${settings.timer_batch_size || 10}" style="width:80px">
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group"><button class="btn btn-primary" id="saveSlideshow">Save</button></div>`;
|
||||
el.querySelectorAll('[data-interval]').forEach(btn => {
|
||||
btn.onclick = () => {
|
||||
@@ -128,7 +135,8 @@ async function renderSlideshow(el) {
|
||||
interval = parseInt(activeBtn?.dataset.interval || '5');
|
||||
}
|
||||
const mode = parseInt(document.getElementById('cycleMode').value);
|
||||
await api('/api/settings', { method: 'POST', body: JSON.stringify({ interval_min: interval, cycle_mode: mode }) });
|
||||
const batch = Math.min(50, Math.max(1, parseInt(document.getElementById('timerBatch').value) || 10));
|
||||
await api('/api/settings', { method: 'POST', body: JSON.stringify({ interval_min: interval, cycle_mode: mode, timer_batch_size: batch }) });
|
||||
toast('Slideshow settings saved');
|
||||
};
|
||||
}
|
||||
@@ -241,6 +249,14 @@ async function renderDevice(el) {
|
||||
<button class="btn btn-danger" onclick="if(confirm('Enter deep sleep?'))api('/api/action/sleep',{method:'POST'})">Deep Sleep</button>
|
||||
<button class="btn btn-danger" onclick="if(confirm('Reboot device?'))fetch('/api/action/reboot',{method:'POST'})">Reboot</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Wake Log</h2>
|
||||
<p style="opacity:0.7;margin-bottom:8px">Persistent CSV log of each photo cycle (survives reboots/sleep).</p>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-primary" id="downloadLog">Download Log</button>
|
||||
<button class="btn btn-danger" id="clearLog">Clear Log</button>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
document.getElementById('saveImmich').onclick = async () => {
|
||||
@@ -270,6 +286,19 @@ async function renderDevice(el) {
|
||||
const result = await api('/api/action/sync-time', { method: 'POST' });
|
||||
toast(result.msg || 'Time synced');
|
||||
};
|
||||
|
||||
document.getElementById('downloadLog').onclick = () => {
|
||||
const a = document.createElement('a');
|
||||
a.href = '/api/log';
|
||||
a.download = 'wake_log.csv';
|
||||
a.click();
|
||||
};
|
||||
|
||||
document.getElementById('clearLog').onclick = async () => {
|
||||
if (!confirm('Clear the wake log?')) return;
|
||||
const result = await api('/api/log/clear', { method: 'POST' });
|
||||
toast(result.msg || 'Log cleared');
|
||||
};
|
||||
}
|
||||
|
||||
async function renderFirmware(el) {
|
||||
|
||||
Reference in New Issue
Block a user