feat: add smart scale BLE gateway integration

- Add evershelf-scale-gateway/ Android app (Kotlin):
  - BLE scanning and GATT connection to smart scales
  - Supports BT SIG Weight Scale (0x181D), Body Composition (0x181B), and generic heuristic parser
  - WebSocket server on port 8765 (local LAN)
  - Real-time weight broadcasting to EverShelf browser client
- Add scale status indicator in header (green/orange/grey dot)
- Add Settings tab for scale configuration (URL, enable toggle, test, APK download link)
- Add 'Read from scale' button in Add/Use forms when unit is g or ml
- Add scale WebSocket client logic in app.js with auto-reconnect
- Fix recipe suggestion: expiry-prioritized ingredients now only injected into
  AI prompt when user explicitly selects 'Priorità Scadenze' or 'Zero Sprechi'
- Update README with smart scale section and website link
- Update all translations (it, en, de) with scale strings
This commit is contained in:
dadaloop82
2026-04-14 15:59:40 +00:00
parent f2b518dd4b
commit 0893742f05
22 changed files with 1954 additions and 22 deletions
+52
View File
@@ -22,6 +22,7 @@
<div class="header-content">
<h1 class="header-title" onclick="showPage('dashboard')"><span data-i18n="nav.title">🏠 EverShelf</span><span class="header-version">v1.2.0</span></h1>
<div class="header-actions">
<span id="scale-status-indicator" class="scale-status-indicator scale-status-disconnected" style="display:none" data-i18n-title="scale.status_disconnected" title="⚖️ Bilancia">⚖️</span>
<button class="header-scan-btn header-gemini-btn" onclick="showPage('chat')" title="Chat con Gemini" data-i18n-title="chat.title">
<svg class="gemini-icon" viewBox="0 0 24 24" width="28" height="28" fill="white"><path d="M12 0C12 6.627 6.627 12 0 12c6.627 0 12 5.373 12 12 0-6.627 5.373-12 12-12-6.627 0-12-5.373-12-12z"/></svg>
</button>
@@ -227,6 +228,7 @@
<option value="ml">ml</option>
</select>
</div>
<button type="button" id="btn-scale-add" class="btn btn-secondary scale-read-btn" style="display:none" onclick="readScaleWeight('add-quantity', function(){ return document.getElementById('add-unit').value; })" data-i18n="scale.read_btn">⚖️ Leggi dalla bilancia</button>
<div id="add-conf-size-row" class="conf-size-row" style="display:none">
<label class="conf-size-label">📦 Ogni confezione contiene:</label>
<div class="conf-size-inputs">
@@ -278,6 +280,7 @@
</div>
<div class="form-group">
<label>Quanto hai usato?</label>
<button type="button" id="btn-scale-use" class="btn btn-secondary scale-read-btn" style="display:none" onclick="readScaleWeight('use-quantity', function(){ return _useNormalUnit || 'g'; })" data-i18n="scale.read_btn">⚖️ Leggi dalla bilancia</button>
<div class="use-unit-switch" id="use-unit-switch" style="display:none">
<button type="button" class="use-unit-btn active" id="use-unit-sub" onclick="switchUseUnit('sub')"></button>
<button type="button" class="use-unit-btn" id="use-unit-conf" onclick="switchUseUnit('conf')">Confezioni</button>
@@ -667,6 +670,7 @@
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-security')" data-tab="tab-security" title="Sicurezza">🔒</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-tts')" data-tab="tab-tts" title="Voce (TTS)" data-i18n-title="settings.tab_tts">🔊</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-language')" data-tab="tab-language" title="Lingua" data-i18n-title="settings.tab_language">🌐</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-scale')" data-tab="tab-scale" title="Bilancia Smart" data-i18n-title="settings.scale.tab">⚖️</button>
</div>
<div class="settings-panels">
<!-- API Keys Tab -->
@@ -967,6 +971,54 @@
<div id="tts-test-status" style="display:none;margin-top:8px"></div>
</div>
</div>
<!-- Scale Tab -->
<div class="settings-panel" id="tab-scale">
<div class="settings-card">
<h4 data-i18n="settings.scale.title">⚖️ Bilancia Smart</h4>
<p class="settings-hint" data-i18n="settings.scale.hint">Collega una bilancia Bluetooth tramite il gateway Android per leggere il peso automaticamente.</p>
<!-- Download gateway app -->
<div style="background:rgba(124,58,237,0.07);border:1px solid rgba(124,58,237,0.2);border-radius:10px;padding:14px;margin-bottom:16px">
<p style="margin:0 0 4px;font-weight:600">📱 EverShelf Scale Gateway</p>
<p class="settings-hint" style="margin-bottom:10px" data-i18n="settings.scale.download_hint">App Android che fa da ponte tra la bilancia BLE e questo sito.</p>
<a href="https://github.com/dadaloop82/EverShelf/releases/latest/download/evershelf-scale-gateway.apk" target="_blank" rel="noopener noreferrer" class="btn btn-large btn-accent full-width" style="text-decoration:none;display:block;text-align:center" data-i18n="settings.scale.download_btn">📥 Scarica Gateway Android (APK)</a>
<p class="settings-hint" style="margin-top:8px" data-i18n="settings.scale.download_sub">Sorgente: <code>evershelf-scale-gateway/</code> nella root del progetto</p>
</div>
<!-- Enable toggle -->
<div class="form-group" style="margin-bottom:10px">
<label class="toggle-row">
<span data-i18n="settings.scale.enabled">✅ Abilita bilancia smart</span>
<span class="toggle-switch">
<input type="checkbox" id="setting-scale-enabled" onchange="onScaleEnabledChange()">
<span class="toggle-slider"></span>
</span>
</label>
</div>
<!-- Gateway URL -->
<div class="form-group">
<label data-i18n="settings.scale.url_label">🌐 URL Gateway WebSocket</label>
<input type="url" id="setting-scale-url" class="form-input" placeholder="ws://192.168.1.x:8765" data-i18n-placeholder="settings.scale.url_placeholder">
<p class="settings-hint" data-i18n="settings.scale.url_hint">Copia l'URL mostrato dall'app Android (stessa rete Wi-Fi). Es: <code>ws://192.168.1.100:8765</code></p>
</div>
<!-- Test button -->
<button class="btn btn-secondary full-width mt-2" onclick="testScaleConnection()" data-i18n="settings.scale.test_btn">🔗 Testa connessione</button>
<div id="scale-test-status" style="display:none;margin-top:8px" class="settings-status"></div>
<!-- Protocol info -->
<div class="settings-hint" style="margin-top:16px;padding:10px;background:var(--bg-secondary,#f8fafc);border-radius:8px">
<p style="margin:0 0 6px;font-weight:600">🔌 Protocolli BLE supportati:</p>
<ul style="margin:0 0 0 16px;padding:0;font-size:0.8rem">
<li>Bluetooth SIG Weight Scale (0x181D)</li>
<li>Bluetooth SIG Body Composition (0x181B) — peso, grasso, BMI</li>
<li>Xiaomi Mi Body Composition Scale 2</li>
<li>Generico — heuristica automatica su 100+ modelli</li>
</ul>
</div>
</div>
</div>
<!-- Language Tab -->
<div class="settings-panel" id="tab-language">
<div class="settings-card">