# ScentApp **Repository Path**: kingkie/ScentApp ## Basic Information - **Project Name**: ScentApp - **Description**: ScentApp - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-18 - **Last Updated**: 2026-07-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 气味播放器 (ScentMixedPlayer) 跨平台气味播放软件,支持 **Android(React Native)** 与 **Windows(Electron)** 双端,共享同一套 TypeScript 业务逻辑层。通过 USB/蓝牙串口与气味播放硬件通信,实现单气味播放、多气味混合、嗅觉测试、评分与数据导出。 > 架构沿用本仓库 `serial-port-app` 的成熟方案:`shared/`(纯 TS 逻辑)+ `android-app/`(RN)+ `desktop-app/`(Electron),HAL 适配层对接各端原生串口。 --- ## 目录结构 ``` scent-player-app/ ├── shared/ # 跨平台共享业务逻辑层(纯 TypeScript,无平台依赖) │ ├── src/ │ │ ├── types.ts # 全局类型定义 + 常量 │ │ ├── index.ts # 统一导出入口 │ │ ├── protocol/ │ │ │ └── SerialProtocol.ts# 串口协议:CRC16 + 帧构造 │ │ ├── config/ │ │ │ ├── defaultConfig.ts # 默认气味配置 │ │ │ └── ConfigManager.ts # 配置加载/校验 │ │ ├── engine/ │ │ │ ├── ScentPlayerEngine.ts # 播放引擎(状态机 + 传输层抽象) │ │ │ └── MixController.ts # 混合控制器(选择/浓度/组合) │ │ ├── data/ │ │ │ ├── IDatabase.ts # 数据持久化接口 + 内存实现 + SQL Schema │ │ │ └── ExportManager.ts # CSV / Excel 导出 │ │ ├── test/ │ │ │ └── TestManager.ts # 嗅觉测试流程 │ │ ├── rating/ │ │ │ └── RatingSystem.ts # 评分统计 │ │ └── state/ │ │ └── AppStore.ts # 全局状态(配置 / 连接 / 多语言 / 混合) │ └── tests/ │ └── verify.mjs # 协议帧验证(node 直接运行) ├── android-app/ # Android 端(React Native) │ ├── src/ │ │ ├── screens/ # 首页 / 气味列表 / 混合 / 测试 / 设置 │ │ ├── components/ # ScentCard / CategoryTabs / ScentRing │ │ ├── engine/useScentEngine.ts # 引擎 ↔ 原生串口桥接 Hook │ │ ├── SerialPortService.ts # 串口服务(调 NativeModules) │ │ └── theme.ts │ ├── android/ # 原生工程(Gradle + Kotlin) │ │ └── app/src/main/java/com/scentplayer/ │ │ ├── ScentSerialModule.kt # usb-serial-for-android 原生模块 │ │ ├── ScentSerialPackage.kt │ │ ├── MainApplication.kt │ │ └── MainActivity.kt │ ├── App.tsx / index.js / app.json / metro.config.js / babel.config.js │ └── package.json ├── desktop-app/ # Windows 端(Electron + React + Vite) │ ├── src/ │ │ ├── screens/ # 同 Android 五大页面(Web 版) │ │ ├── components/ │ │ ├── engine/useScentEngine.ts │ │ ├── bridge/SerialPortService.ts # 经 window.scentSerial 调主进程 │ │ ├── theme.ts / App.tsx / main.tsx / index.css │ ├── electron/ │ │ ├── main.js # Electron 主进程(serialport 12) │ │ └── preload.js # contextBridge 安全注入 │ ├── index.html / vite.config.ts / tsconfig.json │ └── package.json ├── config.sample.json # 气味配置样例 ├── schema.sql # SQLite 建表脚本 └── README.md ``` --- ## 串口通信协议 帧格式(16 进制): ``` 帧头 源地址 目标地址 指令码 数据长度 数据 CRC 帧尾 F5 00 00 00 00 02 05 01 00 00 27 10 8D 02 55 ``` | 字段 | 字节 | 说明 | |------|------|------| | 帧头 | 1 | 固定 `0xF5` | | 源地址 | 2 | 默认 `00 00` | | 目标地址 | 2 | 默认 `00 00` | | 指令码 | 1 | `0x00` 停止 / `0x02` 单播放 / `0x13` 混合 | | 数据长度 | 1 | 数据段字节数 | | 数据 | 变长 | 见下 | | CRC | 2 | Modbus CRC16,覆盖「源地址+目标地址+指令码+数据长度+数据」,高字节在前 | | 帧尾 | 1 | 固定 `0x55` | ### 指令示例 **播放单气味**(code=1,时长 10000ms = `0x2710`): ``` F5 00 00 00 00 02 05 01 00 00 27 10 8D 02 55 ``` 数据段 = `[scentCode(1B), duration(4B 大端 ms)]` **停止**(固定帧): ``` F5 00 00 00 00 00 01 00 90 1A 55 ``` **混合播放**(code=1 浓度5 + code=2 浓度10): ``` F5 00 00 00 00 13 04 01 05 02 0A 55 ``` 数据段 = `[scentCode, concentration, ...]`,每种气味 2 字节,浓度 0-100。 > CRC16 算法(Modbus,多项式 0xA001,初值 0xFFFF)与需求文档 C# `CalcCrc` 完全一致,已通过 `shared/tests/verify.mjs` 逐字节验证。 --- ## 共享业务层(shared) 平台无关,被两端通过 `@scent-player/shared` 别名引用: - **SerialProtocol**:`calcCrc` / `buildFrame` / `buildPlaySingleFrame` / `buildStopFrame` / `buildMixFrame` / `frameToHex` / `parseFrame` - **ScentPlayerEngine**:状态机(idle/playing/mixing),`setTransport` 注入串口发送函数,`onUsage` 回调记录使用日志,`onStateChange` 推送状态变化 - **MixController**:管理多气味选择与浓度,变更时通知引擎重发混合帧 - **AppStore**:全局状态(config / connection / language / mixEntries),响应式订阅 - **IDatabase + MemoryDatabase**:数据持久化抽象,含完整 SQLite Schema - **TestManager**:嗅觉测试流程(出题 / 闻香 / 选择 / 评分 / 结果) - **RatingSystem**:0-10 分评分与星级映射 - **ExportManager**:CSV / Excel(SpreadsheetML 2003,无第三方依赖)导出 ### 运行协议验证 ```bash cd shared node tests/verify.mjs # 预期: ✅ 全部规格测试通过 ``` --- ## Android 端构建 **技术栈**:React Native 0.86 + Kotlin + `usb-serial-for-android:3.7.0`(OTG USB 串口) **环境要求**:JDK 17、Android SDK 35、NDK r27c、CMake 3.22.1、Node 22 ```bash cd android-app yarn install # 方式一:Metro 开发服务 yarn start # 方式二:编译 Debug APK(横屏) cd android ./gradlew assembleDebug # 产物: android/app/build/outputs/apk/debug/app-debug.apk ``` **原生模块**:`ScentSerialModule`(`com.scentplayer`)通过 `usb-serial-for-android` 打开 USB 串口设备,暴露 `listDevices` / `open` / `close` / `writeHex` 给 JS 层,并经 `RCTDeviceEventEmitter` 推送数据与状态事件。Manifest 已声明 USB 权限与 `device_filter`,支持设备插入自动识别。 > 注:若机型不支持 OTG(如部分 vivo),可参照 `serial-port-app` 切换蓝牙 SPP 方案(HC-05/HC-06/JDY-31)。 --- ## Windows 端构建 **技术栈**:Electron + React 18 + Vite + `serialport@12` ```bash cd desktop-app yarn install # 开发(Vite + Electron) yarn dev # 打包(electron-builder 产出 exe) yarn build ``` **架构**: - `electron/main.js`:主进程用 `serialport` 枚举/打开 COM 口,接收数据经 IPC 转发渲染进程 - `electron/preload.js`:`contextBridge` 注入 `window.scentSerial` 安全 API(list / open / close / writeHex / onData / onStatus) - `src/bridge/SerialPortService.ts`:渲染进程封装,`sendFrame(Uint8Array)` 内部转 hex 写串口 - `src/engine/useScentEngine.ts`:将共享引擎与 Electron 串口桥接 --- ## 配置说明 `config.sample.json` 定义气味库结构: ```jsonc { "version": "1.0", "languages": ["zh", "en", "fr"], "categories": [ { "id": "classic", "name": { "zh": "经典口味", "en": "Classic", "fr": "Classiques" }, "scents": [ { "id": "caramel", // 业务 id "code": 1, // 硬件编码(1 字节,0-255) "name": { "zh": "焦糖", "en": "Caramel", "fr": "Caramel" }, "icon": "icons/caramel.png", "defaultConcentration": 5 // 0-100 } ] } ] } ``` - `code` 必须与下位机固件约定一致 - 支持中 / 英 / 法三语,UI 跟随 `AppStore.language` 切换 - 自定义配置放入应用工作目录后由 `ConfigManager` 加载 --- ## 数据持久化 `schema.sql` 定义 6 张表:`scents` / `scent_categories` / `usage_log` / `mix_records` / `ratings` / `test_sessions` + `test_answers`。 - Android 端可用 Room / SQLite 实现 `IDatabase` - Windows 端可用 `better-sqlite3` 或 `sql.js` 实现 - 共享层自带 `MemoryDatabase` 内存实现,供测试与无 DB 环境降级 导出(设置页):`ExportManager.exportRecords('csv' | 'excel', { usage, mixes, ratings })`,CSV 为纯文本,Excel 为 SpreadsheetML 2003 XML(Excel/WPS 可直接打开,零依赖)。 --- ## 功能清单 | 模块 | 说明 | |------|------| | 气味播放 | 单气味播放,可调时长;环形混合盘可视化组合 | | 混合播放 | 多气味浓度调节(0-100),实时下发混合帧 | | 嗅觉测试 | 随机出题 → 闻香 → 选择 → 自动评分 → 结果汇总 | | 评分系统 | 对混合组合 0-10 分评分,支持均值统计与星级展示 | | 数据采集 | 每次播放/混合自动记录使用日志 | | 数据导出 | CSV / Excel 导出使用记录、混合记录、评分记录 | | 多语言 | 中文 / English / Français 动态切换 | | 串口管理 | 设备扫描、连接、断开、状态实时反馈 |