Commit Graph

259 Commits

Author SHA1 Message Date
dadaloop82 745e042375 Merge develop: auto-sync Bring for items depleting within 7 days 2026-04-19 09:10:44 +00:00
dadaloop82 cedd97fd73 fix(bring): keep weekly depletion items auto-synced despite local purchased blocklist
- autoAddCriticalItems now bypasses _isBringPurchased for imminent items
  (days_left <= 7 and uses_per_month >= 3)
- prevents missing Bring additions for items predicted to finish within a week
  after temporary local blocklist entries
2026-04-19 09:10:39 +00:00
dadaloop82 2db86ca541 Merge develop: fix Bring mapping ambiguity on generic words 2026-04-19 09:07:50 +00:00
dadaloop82 c115f83879 fix(bring): avoid ambiguous fallback match on generic words like 'dolce'
- italianToBring(): pass-2 whole-word fallback now ignores generic qualifiers
  (dolce, light, classico, originale, etc.)
- when multiple single-word matches exist, choose the longest/specific token
  instead of first catalog iteration hit
- prevents wrong mappings like 'Pancetta Dolce' being interpreted via generic
  adjective rather than the core product token
2026-04-19 09:07:44 +00:00
dadaloop82 ed8c6fbd07 Merge develop: auto-add to Bring! items running out <7 days 2026-04-19 06:52:19 +00:00
dadaloop82 d778817fd8 fix: auto-add to Bring! items running out within 7 days
- autoAddCriticalItems now adds:
  - critical: always (unchanged)
  - high: always (removed sub-conditions — PHP already gates high urgency strictly)
  - medium + days_left <= 7 + uses_per_month >= 3 (NEW: weekly depletion rule)
- Reduce auto-add guard from 10 min to 5 min for faster detection
- Covers: Latte di Montagna (high, 3gg), items running out mid-week (medium, 4-7gg)
2026-04-19 06:52:16 +00:00
dadaloop82 33163b9235 Merge develop: smarter proactive shopping list urgency 2026-04-19 06:06:36 +00:00
dadaloop82 1021f04735 fix: smarter proactive shopping list urgency
- PHP: predictive urgency block now scales by imminence:
  round(days_left) <= 3 → high, <= 7 → medium, <= 14 → low
  (was flat 'low' for any days_left <= 14)
- PHP: also upgrades existing 'low' urgency to 'high' when
  imminent depletion detected (round(days_left) <= 3, isFrequent)
- JS: autoAddCriticalItems now also adds:
  - high urgency items with pct_left < 20% (nearly empty)
  - high urgency items with days_left <= 3 (imminent)
  - any item with days_left <= 2 and uses_per_month >= 5

Result: Latte di Montagna (27.8x/mo, 3 days left) now appears
on shopping list before running out, as do Lenticchie/Riso
Basmati at 1% stock and Sandwich at 1 day left.
2026-04-19 06:06:18 +00:00
dadaloop82 3901113e76 fix: Storico nav icon, recipe title in transaction notes and log display
- index.html: replace broken byte with 📋 emoji in Storico nav button
- submitRecipeUse: pass 'Ricetta: <title>' as notes to inventory_use API
  so every ingredient use is linked to the recipe in the DB
- loadLog: render recipe note as small italic line 🍳 below log-detail row
- style.css: add .log-recipe-note style (0.75rem, muted, italic)
2026-04-18 19:12:07 +00:00
dadaloop82 2edd5a6ebd fix(kiosk): skip debug keystore config when file does not exist (CI fix) 2026-04-18 18:56:27 +00:00
dadaloop82 37cd8caf4f Merge develop into main: kiosk overlay, preferred location, scale reconnect, Bring! fixes, smart cache 2026-04-18 18:51:55 +00:00
dadaloop82 07bdfe6b87 fix: kiosk overlay, preferred use-location, scale reconnect, Bring! translation, smart cache invalidation
- Kiosk: replace header-inject overlay with position:fixed div appended to <html>
  so buttons appear regardless of SPA init timing
- Kiosk: bump versionCode 3→4, versionName 1.2.0→1.3.0
- Kiosk: add explicit signingConfigs block (debug keystore) to avoid signature
  mismatch on updates; update banner now shows uninstall instruction + 12s timeout
- Web: v1.4.0 → v1.5.0
- Preferred use-location: remember last N location choices per product; after 3+
  consistent picks auto-select and collapse location picker (with 'cambia' link)
- Scale: call updateScaleReadButtons() on every status change so live-box and
  read button appear instantly on reconnect without manual refresh
- Smart shopping cache: invalidate JSON cache file on every inventory_add and
  inventory_use so next shopping-page load always sees current stock
- isLowStock: conf threshold changed <= 1 → < 1 (1 full pack is not low stock)
- italianToBring: replace substring matching with whole-word matching (min 4 chars)
  to prevent 'gin' matching 'original', 'rum' matching 'crumble', etc.
  Philadelphia original was silently mapped to Gin and skipped as duplicate
- Storico: add undo support (transaction_undo endpoint, undone column, JS undo btn)
- LOG → Storico rename in UI, nav, translations
- Bring! sync: urgency-aware purchased blocklist TTL (critical 30m, high 90m, others 4h)
- forceSyncBring() button to clear all guards and re-sync from scratch
- Scale live-box: position:fixed CSS class, 1.6rem/800 value, direct ml display
- Recipe use modal: scale live-box with 10s stability + 5s auto-confirm countdown
- Recipe use modal: show recipe quantity as highlighted row in Usa popup
2026-04-18 18:50:15 +00:00
dadaloop82 7dba155183 Merge develop: v1.3.0 — banner notifications, quick-access, swipe navigation, bug fixes 2026-04-18 05:37:16 +00:00
dadaloop82 9e2a24def4 feat: v1.3.0 — banner notifications, quick-access, swipe navigation, bug fixes
Added:
- Expired/expiring product banner alerts with use, throw, edit, dismiss actions
- Priority-sorted notifications (expired > expiring > suspicious qty > predictions)
- Touch swipe navigation for banner with dot indicators and arrow buttons
- Quick-access buttons on inventory (4 recent + 8 popular products)
- Auto-refresh banner every 5 min on dashboard
- Edit expiry dates directly from expired/expiring notifications

Fixed:
- Ignore negative BLE scale readings
- Banner re-appearing after edit (confirmation now persisted)
- False consumption predictions when inventory was manually edited
- Kiosk overlay no longer blocks web app header
2026-04-18 05:37:03 +00:00
dadaloop82 52cfbba663 docs: update all READMEs with new features
- README.md: add anomaly banner, AI local matching, scale 10g threshold,
  ml conversion hint, auto-fill improvements, Android kiosk section,
  updated roadmap with completed items, architecture tree with kiosk
- evershelf-kiosk/README.md: complete rewrite — now reflects pure WebView
  wrapper architecture (no BLE), setup wizard, kiosk lock, exit/refresh
  buttons, permissions, gateway auto-launch, update notifications
- evershelf-scale-gateway/README.md: update architecture diagram to show
  SSE relay path, add kiosk integration note
2026-04-17 06:14:33 +00:00
dadaloop82 32e2833b27 feat: AI scan shows existing products, scale ml hint, 10g threshold
1. AI photo scan: searches local DB for matching products and shows
   'Già in dispensa' section before OFF matches. User can tap an
   existing product directly. 'Non è nessuno di questi' button for
   new products.

2. Scale live box: when product unit is ml, shows hint
   'Peso in grammi → verrà convertito in ml' so user knows the
   gram reading will be converted.

3. Scale auto-fill: ignores stable weight if it differs less than
   10g from the last confirmed reading. Prevents re-triggering the
   same weight when switching between products on the scale.
   _scaleLastConfirmedGrams tracks the last auto-confirmed weight
   and resets on page navigation.
2026-04-17 05:42:48 +00:00
dadaloop82 ccd59269d4 feat(kiosk): move exit button left of title, add hard-refresh button
- Exit ✕ and Refresh ↻ buttons now appear left of the title
- Refresh clears WebView cache and reloads (picks up web app updates)
- Uses native bridge hardReload() for true cache-busting reload
- Banner alerts reload automatically when dashboard is shown
2026-04-17 05:24:22 +00:00
dadaloop82 d37b43003c feat: show brand in anomaly banner title
Example: 'Anomalia: Latte (Granarolo)'
2026-04-16 19:22:27 +00:00
dadaloop82 9083e25f37 feat(kiosk): add camera, microphone, storage permissions
- Manifest: CAMERA, RECORD_AUDIO, READ_EXTERNAL_STORAGE, READ_MEDIA_IMAGES
- Runtime: requests all permissions on startup (requestAllPermissions)
- WebView: onPermissionRequest checks runtime grants, requests if needed
- onRequestPermissionsResult grants pending WebView permission after user allows
- Camera and mic now work inside the kiosk WebView
2026-04-16 19:07:30 +00:00
dadaloop82 bc70f330f8 fix(kiosk): replace header overlay with exit button next to Gemini
- Removed invisible overlay that was blocking camera/Gemini buttons
- Added a visible ✕ button in the header-actions bar
- Tap shows confirm dialog 'Uscire dalla modalità kiosk?'
- All header buttons (camera, Gemini, scale) work normally again
2026-04-16 18:59:53 +00:00
dadaloop82 4250a37f0d fix: dismiss banner item after editing anomaly from banner
- Added _bannerEditPending flag set when edit/weigh triggered from banner
- submitEditInventory now calls dismissBannerItem() after save
- Next banner item shows automatically after correction
- Flag reset on modal close (cancel) to prevent stale state
2026-04-16 18:58:06 +00:00
dadaloop82 c45b8ddbb9 fix(kiosk): remove FLAG_ACTIVITY_LAUNCH_ADJACENT causing split-screen
Was triggering multi-window split mode instead of launching gateway
behind the kiosk. Now uses only FLAG_ACTIVITY_NEW_TASK.
2026-04-16 18:46:27 +00:00
dadaloop82 45040f250c fix: triple-tap exit, update banner auto-dismiss, .env overwrite bug
- Triple-tap exit zone now covers full header height (was 6px, untappable)
- Uses touchend event instead of click for reliable tablet interaction
- JS bridge registered once before loadUrl (not on every page load)
- Update banner auto-dismisses after 3 seconds
- CRITICAL: _finishSetup() no longer sends empty strings to save_settings
  → was overwriting .env values (Gemini key, Bring credentials) with blanks
  → now only sends non-empty values to the API
2026-04-16 17:36:48 +00:00
dadaloop82 e38a6cb7f6 feat(kiosk): true kiosk mode, gateway bg launch, update checks, wizard fix v1.2.0
- Screen pinning (startLockTask) blocks home/recent buttons
- Gateway launches in background, kiosk returns to front after 1.5s
- Injected thin green bar at top of WebView for triple-tap exit
- JavaScript bridge for kiosk exit from WebView context
- Update check via GitHub releases API (every 6h)
- Shows banner in WebView when kiosk/gateway updates available
- Setup wizard no longer re-appears after completion/skip (evershelf_setup_done flag)
- REORDER_TASKS permission for moveTaskToFront
- singleTask launch mode for proper kiosk behavior
- Version bumped to 1.2.0 (versionCode 3)
2026-04-16 17:25:47 +00:00
dadaloop82 5991e666ec fix(kiosk): connection test, gateway detection, splash, triple-tap exit
- Fix 404: test base URL directly instead of appending /api/
- Fix gateway not detected: add <queries> block for Android 11+ package visibility
- Add splash screen with icon + loading spinner (1.5s)
- Add triple-tap on wizard title to exit kiosk mode
- Accept 3xx redirects as valid responses
- New house/shelf vector icon for launcher
- Replace emoji icon with drawable on welcome screen
- Version 1.1.0
2026-04-16 17:04:25 +00:00
dadaloop82 9363bc147e refactor(kiosk): remove built-in scale, add SSL + gateway detection
- 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
2026-04-16 16:40:11 +00:00
dadaloop82 f8c8dfb990 fix(kiosk): match statusCallback signature (3 params) 2026-04-16 16:27:09 +00:00
dadaloop82 95b6258ad8 feat(kiosk): add setup wizard on first launch
- 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
2026-04-16 16:23:13 +00:00
dadaloop82 d931b471f0 fix: add missing launcher icons for kiosk app
- 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
2026-04-16 16:06:25 +00:00
dadaloop82 383ef1113d feat: kiosk APK download banner in settings page
- 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
2026-04-16 16:00:40 +00:00
dadaloop82 1c792a4e4a ci: add GitHub Actions workflow for kiosk APK build 2026-04-16 14:47:35 +00:00
dadaloop82 3e25fcd5df feat: banner alerts, consumption predictions, scale improvements, kiosk app
- Banner notification system: suspicious quantities + consumption prediction alerts
- Consumption predictions API: tracks 90-day usage patterns, flags >30% deviations
- Scale stability timeout: 5s → 10s, auto-confirm remains 5s
- Scale integration in edit form: weigh button with inline live display
- Banner edit/weigh actions open edit form directly with scale activation
- Cooking mode: Italian aliases + stem-prefix matching for ingredients
- Recipe regeneration: tracks rejected ingredients for diversity
- Settings migration: localStorage → .env server-side storage
- Expiry priority: mandatory ≤3 days, recommended ≤7 days in recipes
- Scale bug fixes: clear stale weight, double-submit guard, cap deduction
- Android kiosk app (evershelf-kiosk): WebView + embedded BLE scale gateway
- Version bump to 1.4.0
2026-04-16 14:46:30 +00:00
dadaloop82 3ff91b3018 fix(scale): progress-bar restart loop + low-weight warning + gateway auto-reconnect cycle
- 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.
2026-04-16 06:25:40 +00:00
dadaloop82 1c686fa842 feat(gateway): auto-reconnect to scale after disconnect (scale auto-off)
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.
2026-04-15 21:17:34 +00:00
dadaloop82 951ef1d64f fix(scale): auto-fill broken for conf products (e.g. latte)
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
2026-04-15 21:12:37 +00:00
dadaloop82 7144ec7386 feat(scale): g→ml density conversion for liquid products
- _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
2026-04-15 21:08:41 +00:00
dadaloop82 d26229800c feat(scale): auto-fill use-quantity live from scale reading
- _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
2026-04-15 21:06:12 +00:00
dadaloop82 6f5bc15734 fix: use relative API paths (leading / broke /dispensa/ subdir routing) 2026-04-15 21:00:34 +00:00
dadaloop82 55c5b34381 feat(scale): auto-discover gateway on local network
- 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
2026-04-15 20:56:54 +00:00
dadaloop82 099a6cc4e8 fix: HTTPS/WebSocket mixed-content — add PHP SSE relay for scale gateway
The browser (HTTPS) cannot connect to ws:// directly (mixed-content block).
Solution: PHP SSE relay bridges the gap server-side.

- api/scale_relay.php: GET ?url=ws://ip:port
  PHP opens WS connection to Android gateway, streams JSON frames as
  Server-Sent Events to the browser over existing HTTPS connection.
  Includes WS handshake, masked client frames, frame decoder, keep-alive.

- api/scale_ping.php: GET ?url=ws://ip:port
  One-shot connectivity test, returns {"ok":true} or {"ok":false,"error"}.

- app.js: WebSocket -> EventSource (SSE)
  _scaleWs -> _scaleEs, connects to /api/scale_relay.php
  testScaleConnection() -> fetch /api/scale_ping.php (no more direct ws://)
  readScaleWeight(): removed get_weight send (scale streams continuously)
2026-04-15 20:31:54 +00:00
dadaloop82 a146ba124a feat(gateway): fix QN-KS 0.1g resolution, unit passthrough, English UI
- 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
2026-04-15 20:02:51 +00:00
dadaloop82 7be02c7174 chore(gateway): add .gitignore, remove build artifacts from git 2026-04-15 19:46:07 +00:00
dadaloop82 0a35e9e8b4 fix(gateway): add QN-KS food scale parser (QN/Yolanda FFF1 protocol)
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).
2026-04-15 19:45:48 +00:00
dadaloop82 690d5ecd18 fix(gateway): remove trailing junk from ScaleProtocol.kt causing build failure
The file had 6 lines of old code appended after the closing brace,
starting a second 'package' declaration that broke compilation.
2026-04-15 16:33:42 +00:00
dadaloop82 b606e2b361 feat(gateway): show app version in header + copy/share debug log
- 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
2026-04-15 16:07:22 +00:00
dadaloop82 d839a7e267 feat(gateway): food scale only - remove all body scale code v2.0.0
BREAKING CHANGE: WeightReading now uses grams (Int) instead of weightKg (Float).
All body composition fields removed (fat%, BMI, muscle, water, bone, kcal, impedance).
WebSocket always sends {unit:'g', value:<grams>}.

- ScaleProtocol: removed QN, 1byone, Hesley, Renpho, Body Composition parsers
- ScaleProtocol: generic parser tries grams, 0.1g, 0.5g, cg, kg*100, oz*10 (1-15000g)
- BleScaleManager: food scale keyword scoring, demotes body scale devices
- BleScaleManager: simplified service discovery (SIG Weight, FFE0, FFF0, Acaia)
- MainActivity: always displays grams, no body composition UI
- GatewayWebSocketServer: publishWeight(grams: Int), always sends unit='g'
- Version bumped to 2.0.0 (versionCode=6)
2026-04-15 16:00:57 +00:00
dadaloop82 d03a4853b5 feat(gateway): food/kitchen scale support (arboleaf CK10G) v1.6.0
- 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
2026-04-15 15:49:12 +00:00
dadaloop82 71c49e2c82 fix(gateway): clean ScaleProtocol.kt - remove Unicode box-drawing chars and fix duplication
- 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
2026-04-15 15:27:06 +00:00
dadaloop82 d30e9e0aaa gateway v1.5.0: protocol-aware parsers, debug fix, auto-reconnect
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).
2026-04-15 15:11:22 +00:00
dadaloop82 695ea19d5c gateway: UX improvements + debug mode v1.4.0
- 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
2026-04-15 13:15:44 +00:00