- Remove BLE/scale code (BleScaleManager, ScaleProtocol, GatewayWebSocketServer, ScaleGatewayService)
- Kiosk is now a pure WebView wrapper — scale handled by standalone gateway app
- Fix SSL certificate error: accept self-signed certs for local servers (WebView + connection test)
- Add gateway APK detection: check if it.dadaloop.evershelf.scalegate is installed
- If gateway installed: show green status, auto-launch on finish
- If not installed: show download link to GitHub releases
- Remove BLE/foreground service permissions from manifest
- Remove java-websocket dependency
- Bump version to 1.1.0
- 3-step wizard: Welcome → Server URL → Scale Setup → Launch
- Connection test with live feedback
- BLE scale status during wizard
- Dark theme with modern UI (slate/purple palette)
- Settings page with URL edit, connection test, scale info, wizard reset
- Skip scale option for users without BLE scales
- Error page with retry button when server unreachable
- All UI in English
- Adaptive icon XMLs (API 26+) with vector foreground + green background
- PNG fallbacks for all density buckets (mdpi through xxxhdpi)
- Added ic_launcher_background color to colors.xml
- Green-themed banner between settings panels and Save button
- Direct download link to kiosk-latest release APK
- Auto-hidden when running inside Android WebView (kiosk mode)
- i18n: translations added for it/en/de
- Fix progress-bar restarting continuously when weight is stable:
add _cancelScaleTimersOnly() that stops timers/animations without
_cancelScaleTimersOnly() so the same value resumes counting when
stability returns instead of always restarting the 5-s wait.
Add 'else if' branch in _scaleAutoFillUse / _scaleAutoFillRecipeUse
to restart stability wait after brief instability for the same value.
- Show red blinking warning in scale-live-box when weight < 10 g:
adds scale-low-weight CSS class with pulsing border/shadow animation,
the label shows '< 10 g · inserisci manualmente' instead of the
stability progress bar. No auto-confirm fires below 10 g.
- Gateway Android app: scale auto-reconnect now retries indefinitely.
isAutoReconnecting flag keeps the scan→wait→scan cycle running until
the scale is found again; onScanStopped schedules a new scan after
10 s whenever autoReconnect is active and scale is still offline.
When the scale turns off by itself (auto-off after inactivity), onDisconnected()
now automatically restarts BLE scan after 5 s, with enableAutoConnect() set so
the saved scale is connected as soon as it starts advertising again.
The hint text shows '🔄 Reconnecting to saved scale in 5 s…' during the wait.
Two root causes:
1. _useNormalUnit was stale ('pz') for conf products because it's only
updated in normal mode — fix: resolve effective unit from
_useConfMode.packageUnit when in sub mode
2. Food scales in liquid mode send unit='ml' directly — was falling
through to raw value, skipping density; fix: detect scaleAlreadyMl
flag to use ml directly for ml target, or apply density for g target
Also: add scale pre-fill call after switchUseUnit('sub') in conf mode
- _scaleDensityForProduct(): returns g/ml density based on product name/category
olio oliva 0.91, girasole 0.92, spirits 0.94, aceto/panna 1.01, latte 1.03,
yogurt 1.05, succo 1.04, miele/sciroppo 1.40, default 1.00 (water)
- _scaleAutoFillUse(): normalises all scale units to grams first, then converts
to target unit; when unit=ml applies density; never touches pz/conf
- _scaleAutoFillUse(): converts and fills use-quantity on stable readings
- _scaleLatestWeight pre-fills when use page opens (after unit is known)
- oninput on use-quantity pauses auto-fill when user types manually
- showUseForm() resets paused flag so next opening resumes auto-fill
- Small 'live' hint text shown while auto-filling, hidden when overridden
- api/scale_discover.php: async TCP scan of whole /24 subnet on port 8765,
confirms with WebSocket handshake, returns found ws:// URLs in ~1.5s
- index.html: '🔍 Auto' button next to gateway URL field
- app.js: discoverScaleGateway() — calls relay, fills URL field and
auto-saves settings + reconnects on success
- ScaleProtocol: WeightReading now holds Float value + String unit
- parseQNFood: divide raw by 10 (0.1-unit resolution) so 170 raw -> 17.0g
- parseQNFood: detect unit from byte[4] (0x01=g, 0x02=oz, 0x03-04=ml)
- GatewayWebSocketServer: publishWeight(value: Float, unit: String, ...)
WebSocket now sends {"value":17.0,"unit":"g"} with correct precision
- BleScaleManager: reading.grams -> reading.value (Float check > 0f)
- All Italian UI strings translated to English in all 4 Kotlin files + XML
The QN-KS sends 18-byte frames on FFF1 with opcode 0x10:
[0x10][0x12=len][...][flags][weight_hi][weight_lo][...][crc]
Weight is u16BE at bytes 9-10 in grams (1g resolution).
Stable flag is bit 3 of byte[8] (0xF8=stable, 0xF0=settling).
Checksum = sum(bytes[0..16]) mod 256.
The generic parser was reading byte[1]=0x12=18 as '18 grams' (the
packet length field), which is why it always showed 18g.
Added parseQNFood() with CRC validation, detected before generic fallback.
Also added AE00/AE02 UUIDs (secondary notifiable service on QN-KS).
- Version label (e.g. v2.0.0 (6)) displayed in the app header
- Copy and Share buttons appear when debug panel is open
- Copy puts full log in clipboard, Share opens Android share sheet
- Generic parser now supports food scale weight ranges (1g-15kg)
with candidates for gram, 0.1g, and 0.5g divisors
- WebSocket sends grams (unit: 'g') for weights under 15kg
- MainActivity displays grams for food-scale readings
- Enhanced debug: raw byte dump on decode failure with index/decimal/hex
- versionCode=5, versionName=1.6.0
- Remove Unicode ─ characters from section comment dividers that caused
Kotlin compiler parse error (line 191:83 Closing bracket expected)
- Use plain ASCII dashes in section comments
- Remove inline field comments from data class
- File was duplicated (672 lines), truncated to correct 316 lines
BREAKING FIX: 'always 1.8 kg' — the old brute-force parseGeneric was
matching noise bytes. Replaced with protocol-specific parsers:
Protocol support (from openScale research):
- Bluetooth SIG 0x2A9D/0x2A9C (standard weight/body composition)
- QN/Yolanda/FITINDEX (opcode 0x10 weight, 0x12 scale info)
- 1byone/Eufy (0xCF header, LE weight at bytes 3-4)
- Hesley/YunChen (20-byte body composition frame)
- Renpho proprietary (0x2E header on 0x2A9D)
- Safe generic fallback (stricter: min 4 bytes, min 2kg, unstable)
Body composition fields: fat%, muscle%, water%, bone, BMR/kcal,
impedance — all displayed when available.
Debug panel fix: capped at 150 lines, UI updates throttled to 200ms
(was: unbounded StringBuilder updated on every BLE notification = freeze).
Auto-reconnect: saves last connected device MAC to SharedPreferences,
auto-starts scan on app launch and connects when saved device found.
GATT service discovery: now explicitly subscribes to QN (FFE0/FFE1)
and custom FFF0 (FFF4 or FFF1) characteristics in addition to
standard Weight Scale and Body Composition services.
ScaleProtocol state: resetState() called on new connection to reset
QN weight divisor (100 or 10, learned from 0x12 info frame).
- Show device names from ScanRecord (fixes MAC-only display)
- Show 'Senza nome' for unnamed devices instead of hiding them
- Show proximity (Vicino/Medio/Lontano) instead of raw dBm
- Sort scan results: scale-likely devices first (keyword + UUID scoring)
- Add debug panel (toggle with 🐛 Debug button):
shows GATT service map, raw hex bytes, parse attempts
- Expand parseGeneric: all 2-byte windows × 3 resolutions × LE+BE
(adds 0.1f and big-endian candidates – common in cheap consumer scales)
- Log GATT services/characteristics after connection
- Log raw hex bytes on every characteristic notification
- showMoveAfterUseModal: add '🫙 Torna sotto vuoto' checkbox (default=previous state)
only shown if item was vacuum sealed; confirmMoveAfterUse passes vacuum_sealed to API
- showRecipeMoveModal: same vacuum checkbox with wasVacuum default passed from ingredient
- confirmRecipeMove: passes vacuum_sealed to inventory_update
- PHP API: add vacuum_sealed to recipe ingredient enrichment
- renderCookingStep: remove step-text word filter; show ALL unused from_pantry
ingredients at every cooking step (AI uses pronouns like 'tagliarla' instead of
repeating the ingredient name, causing them to be invisible)
Many consumer scales like LePulse FI2016LB don't advertise standard
Weight Scale (0x181D) or Body Composition (0x181B) service UUIDs.
Remove the scan filter so all BLE devices are discovered.
The GATT fallback already handles proprietary services.
- Add .github/workflows/build-scale-gateway.yml
Triggers on push to main (evershelf-scale-gateway/** path filter)
Builds debug APK with Gradle/JDK 17, renames to evershelf-scale-gateway.apk
Creates/updates 'latest' GitHub Release so the direct download URL resolves
- Bump web app version v1.2.0 -> v1.3.0 (index.html)
- Bump Android versionCode 1->2, versionName 1.0.0->1.3.0 (app/build.gradle.kts)
- 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
- Add 9 curated screenshots to assets/img/screenshots/ covering all main features
- Update README with 3x3 screenshot table with Italian descriptions
- Anchor /screenshots/ gitignore rule so assets/img/screenshots/ is tracked
- Screenshots cover: dashboard, inventory, barcode scanner, recipe detail,
recipes list, cooking mode, AI chat, shopping list, smart predictions
Merging all changes from develop into main for v1.2.0 release:
- Project renamed from Dispensa Manager to EverShelf
- Contact email: evershelfproject@gmail.com
- All localStorage keys migrated: dispensa_* -> evershelf_*
- SQLite DB renamed: dispensa.db -> evershelf.db
- Docker/Apache resources renamed to evershelf
- Version badge added to app header
- App name updated in all translations (it, en, de)
- Asset version strings bumped to bust browser cache
- JS file truncation fix (safe Python-based replacements)
- CHANGELOG, manifest.json, OpenAPI spec updated for v1.2.0
- Add v1.2.0 version badge to app header
- Update CHANGELOG with v1.2.0 entries
- Bump manifest.json version to 1.2.0
- Bump OpenAPI spec version to 1.2.0
- Recover app.js from pre-rebrand commit and re-apply all substitutions safely
- Fix all localStorage keys: dispensa_* -> evershelf_* (settings, setup, lang)
- Fix TTS test strings: 'Dispensa Manager' -> 'EverShelf'
- Set nav.title to EverShelf in it/en/de translations and HTML fallback
- Fix JS syntax error (Unexpected end of input) that broke the site
- CI JavaScript Lint should now pass