# Jensen - WebUSB Helper

一个基于WebUSB API的硬件设备通信库，支持设备连接、文件管理、蓝牙扫描等功能。

## 📋 目录

- [功能特性](#功能特性)
- [安装](#安装)
- [快速开始](#快速开始)
- [API 文档](#api-文档)
- [使用案例](#使用案例)
- [第三方项目导入](#第三方项目导入)
- [版本依赖](#版本依赖)
- [开发指南](#开发指南)

## ✨ 功能特性

- 🔌 **WebUSB设备连接** - 支持HiDock系列设备的USB连接
- 📁 **文件管理** - 文件列表、下载、删除等操作
- 📱 **蓝牙管理** - 蓝牙设备扫描、连接、状态查询
- ⏰ **时间同步** - 设备时间获取和设置
- 🔧 **设备设置** - 自动录音、自动播放、通知等设置
- 📊 **实时数据** - 支持实时数据传输和控制
- 📝 **日志系统** - 完整的调试和错误日志

## 📦 安装

### 从npm安装

```bash
npm install jensen-webusb
```

### 从源码安装

```bash
git clone http://gitlab.sugrsugr.com/skye/jensen.git
cd jensen
npm install
```

## 🚀 快速开始

### 基本使用

```typescript
import Jensen from 'jensen-webusb';

// 创建Jensen实例
const jensen = new Jensen();

// 连接设备
await jensen.connect();

// 获取设备信息
const deviceInfo = await jensen.getDeviceInfo();
console.log('设备序列号:', deviceInfo.sn);
console.log('版本号:', deviceInfo.versionCode);
```

### 在React项目中使用

```typescript
import { useEffect, useState } from 'react';
import Jensen from 'jensen-webusb';

function DeviceManager() {
  const [jensen] = useState(() => new Jensen());
  const [isConnected, setIsConnected] = useState(false);
  const [deviceInfo, setDeviceInfo] = useState(null);

  useEffect(() => {
    jensen.onconnect = () => {
      setIsConnected(true);
      jensen.getDeviceInfo().then(setDeviceInfo);
    };
    
    jensen.ondisconnect = () => {
      setIsConnected(false);
    };
  }, [jensen]);

  const handleConnect = async () => {
    try {
      await jensen.connect();
    } catch (error) {
      console.error('连接失败:', error);
    }
  };

  return (
    <div>
      <button onClick={handleConnect}>连接设备</button>
      {isConnected && <p>设备已连接: {deviceInfo?.sn}</p>}
    </div>
  );
}
```

## 📚 API 文档

### 核心类

#### Jensen

主要的设备通信类，提供所有设备操作接口。

```typescript
class Jensen {
  constructor(log?: Logger);
}
```

### 连接管理

#### connect()
连接到WebUSB设备

```typescript
await jensen.connect(): Promise<void>
```

#### disconnect()
断开设备连接

```typescript
await jensen.disconnect(): Promise<void>
```

#### isConnected()
检查设备连接状态

```typescript
jensen.isConnected(): boolean
```

#### tryconnect(disableOnConnect?: boolean)
尝试连接已授权的设备

```typescript
await jensen.tryconnect(disableOnConnect?: boolean): Promise<boolean>
```

### 设备信息

#### getDeviceInfo(time?: number)
获取设备信息

```typescript
await jensen.getDeviceInfo(time?: number): Promise<DeviceInfo>

interface DeviceInfo {
  sn: string;           // 设备序列号
  versionNumber: number; // 版本号
  versionCode: string;   // 版本代码
}
```

#### getModel()
获取设备型号

```typescript
jensen.getModel(): string
```

### 文件管理

#### listFiles(time?: number)
获取文件列表

```typescript
await jensen.listFiles(time?: number): Promise<FileInfo[]>

interface FileInfo {
  name: string;        // 文件名
  createDate: string;  // 创建日期
  createTime: string;  // 创建时间
  time: Date;          // 时间对象
  duration: number;    // 时长
  length: number;      // 文件大小
  signature: string;   // 文件签名
}
```

#### getFile(fileName, length, on?, onprogress?)
下载完整文件

```typescript
jensen.getFile(
  fileName: string,
  length: number,
  on?: (msg: Uint8Array | 'fail') => void,
  onprogress?: (size: number) => void
): void
```

#### getFilePart(fileName, length, on?, onprogress?)
下载文件片段

```typescript
jensen.getFilePart(
  fileName: string,
  length: number,
  on?: (msg: Uint8Array | 'fail') => void,
  onprogress?: (size: number) => void
): void
```

#### deleteFile(fileName)
删除文件

```typescript
await jensen.deleteFile(fileName: string): Promise<{ result: 'failed' | 'success' | 'not-exists' }>
```

### 蓝牙管理

#### scanDevices(seconds?: number)
扫描蓝牙设备

```typescript
await jensen.scanDevices(seconds?: number): Promise<BluetoothDevice[]>

interface BluetoothDevice {
  name: string;  // 设备名称
  mac: string;   // MAC地址
}
```

#### connectBTDevice(mac, seconds?: number)
连接蓝牙设备

```typescript
await jensen.connectBTDevice(mac: string, seconds?: number): Promise<ReturnStruct['common']>
```

#### disconnectBTDevice(seconds?: number)
断开蓝牙设备

```typescript
await jensen.disconnectBTDevice(seconds?: number): Promise<ReturnStruct['common']>
```

#### getBluetoothStatus(seconds?: number)
获取蓝牙状态

```typescript
await jensen.getBluetoothStatus(seconds?: number): Promise<BluetoothStatus>

interface BluetoothStatus {
  status: string;     // 连接状态
  mac?: string;       // MAC地址
  name?: string;      // 设备名称
  a2dp?: boolean;     // A2DP支持
  hfp?: boolean;      // HFP支持
  avrcp?: boolean;    // AVRCP支持
  battery?: number;   // 电池电量
}
```

### 时间管理

#### getTime(time?: number)
获取设备时间

```typescript
await jensen.getTime(time?: number): Promise<{ time: string }>
```

#### setTime(date, timeout?: number)
设置设备时间

```typescript
await jensen.setTime(date: Date, timeout?: number): Promise<ReturnStruct['common']>
```

### 设备设置

#### getSettings(time?: number)
获取设备设置

```typescript
await jensen.getSettings(time?: number): Promise<{
  autoRecord: boolean;
  autoPlay: boolean;
  notification?: boolean;
} | null>
```

#### setAutoRecord(enable, time?: number)
设置自动录音

```typescript
await jensen.setAutoRecord(enable: boolean, time?: number): Promise<ReturnStruct['common']>
```

#### setAutoPlay(enable, time?: number)
设置自动播放

```typescript
await jensen.setAutoPlay(enable: boolean, time?: number): Promise<ReturnStruct['common']>
```

### 实时数据

#### startRealtime()
开始实时数据传输

```typescript
await jensen.startRealtime(): Promise<ReturnStruct['common']>
```

#### pauseRealtime()
暂停实时数据传输

```typescript
await jensen.pauseRealtime(): Promise<ReturnStruct['common']>
```

#### stopRealtime()
停止实时数据传输

```typescript
await jensen.stopRealtime(): Promise<ReturnStruct['common']>
```

#### getRealtime(frames)
获取实时数据

```typescript
await jensen.getRealtime(frames: number): Promise<{ data: Uint8Array; rest: number }>
```

## 💡 使用案例

### 案例1: 设备连接和文件下载

```typescript
import Jensen from 'jensen-webusb';

async function downloadLatestFile() {
  const jensen = new Jensen();
  
  try {
    // 连接设备
    await jensen.connect();
    console.log('设备连接成功');
    
    // 获取文件列表
    const files = await jensen.listFiles();
    if (files.length === 0) {
      console.log('没有找到文件');
      return;
    }
    
    // 下载最新文件
    const latestFile = files[files.length - 1];
    console.log(`开始下载文件: ${latestFile.name}`);
    
    jensen.getFile(latestFile.name, latestFile.length, (data) => {
      if (data instanceof Uint8Array) {
        // 保存文件
        const blob = new Blob([data]);
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = latestFile.name;
        a.click();
        URL.revokeObjectURL(url);
        console.log('文件下载完成');
      } else {
        console.error('文件下载失败');
      }
    }, (progress) => {
      console.log(`下载进度: ${progress}/${latestFile.length}`);
    });
    
  } catch (error) {
    console.error('操作失败:', error);
  }
}
```

### 案例2: 蓝牙设备管理

```typescript
import Jensen from 'jensen-webusb';

async function manageBluetoothDevices() {
  const jensen = new Jensen();
  
  try {
    await jensen.connect();
    
    // 扫描蓝牙设备
    console.log('开始扫描蓝牙设备...');
    const devices = await jensen.scanDevices();
    console.log(`找到 ${devices.length} 个设备:`);
    
    devices.forEach(device => {
      console.log(`- ${device.name} (${device.mac})`);
    });
    
    // 连接第一个设备
    if (devices.length > 0) {
      const result = await jensen.connectBTDevice(devices[0].mac);
      console.log('连接结果:', result.result);
      
      // 获取连接状态
      const status = await jensen.getBluetoothStatus();
      console.log('蓝牙状态:', status);
    }
    
  } catch (error) {
    console.error('蓝牙操作失败:', error);
  }
}
```

### 案例3: 设备设置管理

```typescript
import Jensen from 'jensen-webusb';

async function configureDevice() {
  const jensen = new Jensen();
  
  try {
    await jensen.connect();
    
    // 获取当前设置
    const settings = await jensen.getSettings();
    console.log('当前设置:', settings);
    
    // 修改设置
    await jensen.setAutoRecord(true);
    await jensen.setAutoPlay(false);
    await jensen.setNotification(true);
    
    console.log('设置已更新');
    
    // 验证设置
    const newSettings = await jensen.getSettings();
    console.log('更新后的设置:', newSettings);
    
  } catch (error) {
    console.error('设置操作失败:', error);
  }
}
```

### 案例4: 实时数据监控

```typescript
import Jensen from 'jensen-webusb';

async function monitorRealtimeData() {
  const jensen = new Jensen();
  
  try {
    await jensen.connect();
    
    // 开始实时数据传输
    await jensen.startRealtime();
    console.log('实时数据传输已开始');
    
    // 定期获取数据
    const interval = setInterval(async () => {
      try {
        const result = await jensen.getRealtime(100);
        console.log(`接收到 ${result.data.length} 字节数据`);
        
        // 处理数据...
        processData(result.data);
        
      } catch (error) {
        console.error('获取实时数据失败:', error);
        clearInterval(interval);
      }
    }, 1000);
    
    // 10秒后停止
    setTimeout(async () => {
      clearInterval(interval);
      await jensen.stopRealtime();
      console.log('实时数据传输已停止');
    }, 10000);
    
  } catch (error) {
    console.error('实时监控失败:', error);
  }
}

function processData(data: Uint8Array) {
  // 处理实时数据的逻辑
  console.log('处理数据:', data);
}
```

## 🔧 第三方项目导入

### 在React项目中使用

```bash
npm install jensen-webusb
```

```typescript
// 在组件中使用
import { useEffect, useState } from 'react';
import Jensen from 'jensen-webusb';

function JensenComponent() {
  const [jensen] = useState(() => new Jensen());
  const [isConnected, setIsConnected] = useState(false);
  
  useEffect(() => {
    jensen.onconnect = () => setIsConnected(true);
    jensen.ondisconnect = () => setIsConnected(false);
  }, [jensen]);
  
  // 组件逻辑...
}
```

### 在Vue项目中使用

```bash
npm install jensen-webusb
```

```typescript
// 在Vue组件中使用
import { ref, onMounted } from 'vue';
import Jensen from 'jensen-webusb';

export default {
  setup() {
    const jensen = ref(new Jensen());
    const isConnected = ref(false);
    
    onMounted(() => {
      jensen.value.onconnect = () => isConnected.value = true;
      jensen.value.ondisconnect = () => isConnected.value = false;
    });
    
    return {
      jensen,
      isConnected
    };
  }
};
```

### 在Node.js项目中使用

```bash
npm install jensen-webusb
```

```typescript
// 注意：WebUSB API仅在浏览器环境中可用
import Jensen from 'jensen-webusb';

// 在浏览器环境中使用
if (typeof window !== 'undefined') {
  const jensen = new Jensen();
  // 使用逻辑...
}
```

### 在TypeScript项目中使用

```typescript
// 类型定义已包含在包中
import Jensen, { DeviceInfo, FileInfo, BluetoothDevice } from 'jensen-webusb';

const jensen = new Jensen();

async function typedExample() {
  const deviceInfo: DeviceInfo = await jensen.getDeviceInfo();
  const files: FileInfo[] = await jensen.listFiles();
  const bluetoothDevices: BluetoothDevice[] = await jensen.scanDevices();
}
```

## 📋 版本依赖

### 核心依赖

```json
{
  "dependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  }
}
```

### 开发依赖

```json
{
  "devDependencies": {
    "@types/node": "^22.10.2",
    "@types/react-dom": "^19.0.2",
    "@vitejs/plugin-react-swc": "^3.7.2",
    "prettier": "^3.3.3",
    "typescript": "^5.7.2",
    "vite": "^6.0.3"
  }
}
```

### 浏览器兼容性

- Chrome 67+
- Edge 79+
- Opera 54+
- 支持WebUSB API的现代浏览器

### Node.js版本要求

- Node.js 16.0.0+

## 🛠️ 开发指南

### 本地开发

```bash
# 克隆项目
git clone http://gitlab.sugrsugr.com/skye/jensen.git
cd jensen

# 安装依赖
npm install

# 启动开发服务器
npm run dev

# 构建项目
npm run build

# 代码格式化
npm run prettier
```

### 项目结构

```
jensen/
├── src/
│   ├── App.tsx              # 主应用入口
│   ├── index.tsx            # 主组件
│   ├── index.css            # 样式文件
│   └── utils/
│       ├── jensen.js        # 核心Jensen类
│       └── utils.js         # 工具函数
├── jensen.d.ts              # TypeScript类型定义
├── package.json             # 项目配置
├── tsconfig.json            # TypeScript配置
├── vite.config.mts          # Vite配置
└── README.md               # 项目文档
```

### 贡献指南

1. Fork 项目
2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 打开 Pull Request

### 许可证

本项目采用 ISC 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。

## 📞 支持
Martin Hou (martin@hidock.com)



**注意**: 此库需要支持WebUSB API的现代浏览器，并且设备需要支持相应的USB协议。 