Remove all fitting detection logic (setParams, fitting event listener,
timeout). User manually confirms wearing, then proceeds to detection
page. No BLE commands sent on this page.
- Remove parseVendorStatus 17-byte branch (FFE4 is now 19 bytes)
- Remove parseVendorStatus 33-byte branch (FFE1 is now 34 bytes)
- Remove buildVendorCommand33 deprecated alias
- Remove fitting/run_state !== -1 guards in connection.js
- Update commands.js to use buildVendorCommand directly
wear-check:
- Send weak pulse light (brightness=26) to trigger FFE4 fitting report
- Timeout degrades to pass (backward compat with 17-byte firmware)
- Sync _resolved flag prevents double-resolve
treating:
- Only treat run_state=0x00 as completion after seeing run_state=0x02
(prevents false completion on startup)
- Sync _finishing flag replaces async data.completed for race prevention
- onStatus preserves paused state during fitting loss (|| fittingLost)
- Remove dead _fittingTimer reference from onUnload
auto-scan:
- Sync _completed flag in _scanComplete prevents double-build
- Listen for 'fitting' event: detect skin detachment, pause on loss,
resume on re-attach
- Listen for 'run_state' event: detect device fault (0xFF) and IDLE
completion (0x00)
- Low battery warnings: toast at <=10%, force stop at <=5%
- Guard finishAsComplete against double-completion
- Proper cleanup of all new event listeners on unload
Firmware does R→UV→Y→IR sequential scan autonomously. Miniprogram
now listens for 4 consecutive ADC notifications, storing each as a
separate spectrum group. Also listens for run_state=IDLE as scan
completion signal. Displays all 4 spectrum groups with PD1-PD7 bars.
Stores full scan data in globalData.lastScanData for diagnosis phase.
Listen for 'fitting' event from FFE4 Byte17 (0=not fitted, 1=fitted).
10s timeout if no fitting signal received. Removes vendor_33 bypass
that always returned ok.
- parseVendorStatus: add checksum_ok verification for 34-byte and 33-byte params
- command-sync.js: passthrough control, current_gain, hold_time from server payload
- Mark buildVendorCommand33 as deprecated alias
Per 协议简述(3): FFE4 now 19 bytes — adds Byte17 fitting status
(0=not fitted, 1=fitted) and Byte18 run state (0=IDLE, 1=scanning,
2=treating, FF=fault). Maintains backward compat with 17-byte format.
- Extract _cleanup() to properly unregister ADC listener + clear timers
- ADC callback unregisters itself on first receive (prevent duplicates)
- setParams failure now stops scanning and clears all state
- Timeout handler unregisters ADC listener
- Add BLE connection check before scan
- SCAN_TIMEOUT 8s → 12s (must exceed hold_time 10s)
- Pre-compute barWidth in JS instead of float math in WXML
- Error only shows when scanning is false
- Send scan command: all 5 regions LED on, brightness 128
- Listen for ADC notify (17 bytes) instead of broken queryStatus
- Parse and display PD1-PD7 values with visual bars
- Show VBAT/battery info
- Store scan PD data in globalData for Phase 3 smart adjustment
- 8s timeout fallback, stop LED on page unload
Region name mapping corrected to match actual hardware IO positions:
- 0x01: 左区→右区, 0x02: 右区→左区
- 0x08: 下区→中区, 0x10: 中区→下区
Auto-scan no longer shows timeout error, proceeds to next step instead.
Fixes timeout during binding when targetDeviceId is set but exact
string match fails due to encoding differences. Also skips devices
with no name, and logs match result for every candidate.
- parseDeviceId accepts hex with spaces (e.g. "672B6D5A 4DCD861")
- BLE scan does exact match on "JW_<device_id>" when target is known
- Manual input placeholder updated to show new format
Replace '光子美容仪' with '智美'/'智能面膜'/'我的设备' throughout.
Replace '护理' with '使用' in all UI text.
Replace '皮肤' with '检测'/'智能' where applicable.
Replace 🌸 with 💎 for brand identity.
Internal code (variable names, API paths, file names) unchanged.
- New grantTrialIfEligible() in subscription.dao.js with SELECT FOR UPDATE
to prevent concurrent bind race condition granting double trials
- confirmBind + mockBind now call the shared function (was duplicated)
- Trial days no longer hardcoded to 7 in binding — respects settings
confirmBind and mockBind now check trial history before granting trial.
Previously only checked for active subscriptions — if trial expired,
rebinding would create a new 7-day trial, allowing infinite free usage.
Now checks if user ever had a trial (any status), skips if so.
- ADC (17-byte) now emits 'adc' + 'battery' events, not 'status'
- Fixes CRITICAL timer jump: remaining_ms:0 was resetting countdown
- Drop ADC packets with bad XOR checksum
- treating.js + index.js subscribe to 'battery' for live battery updates
- onStatus only updates remaining_ms when > 0
Protocol update adds FFE4 Status format: 7×PD sensors (little-endian)
+ VBAT battery voltage (mV) + XOR checksum = 17 bytes.
- parseVendorStatus: handles 1-byte heartbeat, 17-byte ADC, 33-byte params
- handleValueChange: ADC type extracts PD array + battery % from VBAT
- Battery calculated as linear 3000mV(0%) to 4200mV(100%)
- PD data passed through status event for treatment pages
- Updated protocol doc with full byte table and old/new comparison
- 01-快速开始: local setup for all 3 modules, common issues
- 02-配置说明: all env vars, WeChat/Pay/DB/COS config details
- 03-架构说明: system overview, directory structure, data flows
- 04-部署指南: Tencent Cloud SCF/COS deployment, launch checklist
- 05-API接口文档: all 42 endpoints with params and response format
- README index with audience guide and quick links
- Loading animation only shows on first visit, subsequent onShow updates silently
- Subscription row always navigates to plans page (was no-op when active)
- Move devMode init to onLoad (only needs to run once)