# @esp-vision/device-core 中文文档

规范地址：https://npmcn.com/package/%40esp-vision/device-core/

版本：0\.8\.1
npm 元数据更新时间：2026-11-13T10:30:40.050Z
中文译文更新时间：2026-11-13T22:43:17.661Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40esp-vision/device-core
原文对照：https://npmcn.com/package/%40esp-vision/device-core/?lang=original
项目主页：https://vision.espressif.com/
源码仓库：https://github.com/espressif/esp-vision

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：955 kB，97 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- Node.js 要求：\>=22
- 运行依赖：2 个
- peer 依赖：multicast-dns ^7\.2\.5
- 首次发布：2026-10-16T01:09:06.911Z
- 最新版本发布：2026-11-13T10:30:39.831Z
- 近 30 天下载量：3030（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：16（近 12 个月 16 个）

## 中文简介

共享EV-MUX,设置了REPL,设备会话,以及ESP Vision客户的行动合同.

## 安装

```sh
npm install @esp-vision/device-core
```

也可以使用：`pnpm add @esp-vision/device-core`、`yarn add @esp-vision/device-core`、`bun add @esp-vision/device-core`

## README

# ESP 视觉设备核心

[ESP-VISION (英语)](https://vision.espressif.com/) 是Espressif的低码边缘AI和ESP32板的计算机视觉框架. MicroPython API覆盖相机捕获,图像处理,推断和显示在设备上;浏览器闪烁和Web IDE提供主机开发工作流程. 设备 Core是其可再用,UI-独立主机通信库.

-   GitHub 项目 : [咖啡/电视](https://github.com/espressif/esp-vision)
-   官方网站(简体中文) [视觉. espressif.com](https://vision.espressif.com/)
-   网络 IDE : [(原始内容存档于2018-10-21) (中文(简体) ). ide.vision.espressif.com](https://ide.vision.espressif.com/)
-   固件文档 : [ESP-VISION 方案拟订指南](https://docs.espressif.com/projects/esp-vision/en/latest/)

## 包的身份和安装

| 项目 | 数值 |
| --- | --- |
| 已公布名称 | `@esp-vision/device-core` |
| 第一个公开版本 | `0.1.0`,仅 EV-MUX v4 |
| 书记官处 | `https://registry.npmjs.org/` |
| 软件包页面 | [npm: @esp-vision/device-core (英语)](https://www.npmjs.com/package/@esp-vision/device-core) |
| 出版账户 | [`esp-vision`](https://www.npmjs.com/~esp-vision) |
| 可见度 | 公开; 安装不需要 npm 登录 |
| 来源位置 | `host/device-core` eSP-VISION 固件存储器 |

此源目标 **0.8.0 (中文(简体) )**,npm序列/后端迁移。 设备 Core 仅为 SDK : 管理 CLI 生活在 `@esp-vision/device-cli`,而 Python 执行/文件读取时没有总的最后期限,除非配置。 声明一个小锁的依赖性,并使用一个锁文件来记录已解析的补丁和完整性;在安装前在公共登记册中验证所选版本。 对于未公布的源变化,使用从确切审查源中装入的柏油球。 CI 认证与受保护 `NPM_PUBLISH_TOKEN` 并核实 `npm whoami` 返回时 `esp-vision` 发表前。 托肯斯不是本套件或其文档的一部分.

```sh
# Published baseline; the pending 0.7.1 fixes require a candidate tarball.
npm view @esp-vision/device-core@0.7.0 version dist.integrity
npm install '@esp-vision/device-core@~0.7.0' --registry=https://registry.npmjs.org/
```

源版本,干运行或打开合并请求不发布软件包. CLI和插件捆绑保留自己的版本和嵌入式Core字节;仅出版Core并不更新所安装的工具.

需要EV-MUX v4固件. V3的问候被拒绝了 `VERSION_MISMATCH`;应用程序应当要求用户更新固件. Core对IDE,Agent,DOM或节点系列库没有运行时间依赖. 主机提供物理字节运输和发现适配器; Core拥有协议解析,会话谈判,REPL协调和设备操作.

## 文档

读取设备核心指南 **ESP-VISION 文献中心**数字 : [联合国](https://docs.espressif.com/projects/esp-vision/en/latest/esp32p4/device-core/index.html) | [简体中文](https://docs.espressif.com/projects/esp-vision/zh_CN/latest/esp32p4/device-core/index.html)。 。 。 .

-   [所有应用程序 API](https://docs.espressif.com/projects/esp-vision/en/latest/esp32p4/device-core/api.html),包括固件版本检查,应用程序更新和空白设备安装.
-   [高级出口](https://docs.espressif.com/projects/esp-vision/en/latest/esp32p4/device-core/advanced.html) 财务报告和审定财务报表 [TCP/网络序列集成](https://docs.espressif.com/projects/esp-vision/en/latest/esp32p4/device-core/integration.html)。 。 。 .

文档来源生活在此寄存器 `docs/en/device-core/` 财务报告和审定财务报表 `docs/zh_CN/device-core/` 与 SDK API 在同一 MR 中同时变化. 文档网站使 RST 成为 HTML ; 它不将读取器重定向到 npm 或者要求下载文档 。 npm 包包含运行时库和这个 README,而不是第二个 RST 文档分发. 在读取已出版的固件/文档版本时使用文档中心的版本选择器; `latest` 遵循当前开发文件。 这些新的章节链接在相应文件部署后即可使用.

## 管理活动

从0.5.0开始,"设备核心"是一个库,不安装管理命令. 现有0.4.x设施在明确升级或拆除之前保留其指挥权。 安装独立的 `@esp-vision/device-cli` 工具箱。 它使用公用Core API并被明确安装; Device Core不取取或包接CLI. 见 [CLI 指南](https://docs.espressif.com/projects/esp-vision/en/latest/esp32p4/device-core/cli.html) (单位:千美元)[页:1](https://docs.espressif.com/projects/esp-vision/zh_CN/latest/esp32p4/device-core/cli.html)) (中文(简体) ).

```sh
npm install -g @esp-vision/device-cli
esp-vision-device inspect
esp-vision-device inspect --all-ports
esp-vision-device inspect --interface usj,usb --probe --json
esp-vision-device inspect --port COM3 --fields identity,capabilities
esp-vision-device inspect --tcp 192.168.1.100:3232 --fields network,storage --json
```

连接访问/编号使用可选 npm 本地串联; LAN 发现使用可选 `multicast-dns`,通常由npm安装. 接受Windows/Linux/macOS路径. 被动计数从不打开序列端口; `--probe` 和有针对性的询问获得一个会话,并可能中断 Python。 未识别端口,ROM候选端口和USB-至UART适配器仍然编号并可见. 在坚固软件识别之前, 局名未知; USB 描述符只是提示 。 从dl.espressif.com自动获取固件版本. 固件闪烁使用与浏览器相同的esptool-js引擎;不需要用户加载模块. 使用 `firmware update --mode install --board BOARD --port PORT --version VERSION` 用于在ROM容量的USJ/UART端口上安装空白设备。 安装在完整图像范围内替换数据;默认更新保留了已存在的布局. 没有合格元数据的历史发行量仍然列出,但无法通过这种流通来安装。 在安装新准备的版本之前检查登记版本 .

## 公共设备 API

导入 `createDevice` 从包根。 应用程序代码使用一个设备接口而不是构建解析器,一个REPL和一个会话分别使用.

| 区域 | 方法 | 责任 |
| --- | --- | --- |
| 发现 | `discover(options)` | 不获取设备而列出局域网广告 |
| 连接 | `connect(options)`, (中文(简体) ), `disconnect()` | 谈判/释放EV-MUX会议并管理注入运输 |
| 查询 | `inspect({ fields })` | 读取身份、能力、运行时间、网络和存储状态 |
| 配置 | `configure({ network })` | 更改 Wi-Fi 证书和启用状态 |
| 控制权 | `control({ action, mode })` | 停止 Python, 重置或输入ROM 下载器 |
| 交互式 Python | `python.input(data)` | 不上传文件而发送终端输入 |
| Python 执行 | `python.execute({ source, path, completion })` | 执行源或设备侧脚本 |
| 文件 | `files.list/read/write/remove/mkdir(request)` | 文件与目录操作, 有一个对象参数 |
| 固件 | `firmware.check(request)`, (中文(简体) ), `firmware.update(request)` | 列出版面固件版本, 选择准确的版本, 并在空白设备上进行经过验证的 ROM 应用程序更新或明确安装 |
| 捕获 | `capture({ source, format, quality })` | 从支持的来源获取图像 |
| 活动 | `on(event, handler)` | 订阅; 返回未订阅的函数 |

配置和控制是故意分开的:配置改变持久性设置,而控制则要求立即采取行动. 文件上传从未隐含地开始 Python 执行 .

### 运输和连接

主办方拥有串行/TCP/WebSocket详细信息并履行本字节运输合同:

```js
const transport = {
  async writeBytes(bytes) {
    // Resolve only after all bytes are accepted; reject on failure.
    await byteConnection.write(bytes);
  },
  subscribe({ data, error, close }) {
    // Forward received Uint8Array data and link errors/closure.
    // Return a synchronous unsubscribe function; do not make this async.
    return byteConnection.subscribe({ data, error, close });
  },
  async connect({ signal }) { await byteConnection.open({ signal }); }, // Optional.
  async disconnect() { await byteConnection.close(); },   // Optional.
};
```

`byteConnection` 上面代表您的主机适配器,而不是核心类。 核心在打开连接或发送握手字节前订阅. 如果主机自己打开连接, 请省略 `connect()` 并通过开放的适配器。 已关闭的连接终止了待定的工作; 未订阅会阻止旧连接的进一步输入 .

```js
import { createDevice } from '@esp-vision/device-core';

const device = createDevice({ transport });
const unsubscribeOutput = device.on('python.output', text => console.log(text));
const unsubscribeState = device.on('state', state => console.log(state));
try {
  await device.connect({ role: 'usj' }); // 'usb', 'uart' or 'tcp' on other links.
  console.log(await device.inspect({ fields: ['identity', 'capabilities'] }));
  console.log(await device.python.execute({ source: 'print(1)', completion: 'wait' }));
} finally {
  await device.disconnect();
  unsubscribeOutput();
  unsubscribeState();
}
```

`connect()` 默认情况下发送 Ctrl-C 和一个简短的 REPL活性探测器以求相容性 。 过 `probeRepl: false` 当一个解开的应用程序可能正在运行时: Core仍然获得EV-MUX会话并读取身份/能力,但保留REPL未被更改. 在此模式下报告 `vmReady: false` 保持虚假; 需要准备的 VM 操作的 Python 操作会因准备错误而失败 .

UART连接开始于115200 bps. 与相容的固件和传送 曝光 `setBaudRate(baudRate, { signal })`,核心测试2000000,1500000,921600,460800和115200bps,按第一核实速率排列并停止. `connect({ autoBaud: false })` 跳过此可选谈判,用于限定身份的探测器; `autoBaud` 默认为 `true`原生的USB和遗留的固件跳过UART谈判. 连接期限默认为60000 ms,以允许有界倒置. 运行时间速度和ROM/stub闪出速度是独立谈判的.

浏览器子路径导出被动 `serialTransport({ port, signals?, bufferSize? })` 适配器. 请求并授权选定 `SerialPort` 在 UI 点击处理器中,然后传给这个适配器。 核心管理开放、内部调整和关闭;内部重新开放保留订阅和许可。 默认流缓冲为256 KiB. 一个出乎意料的棋盘重置仍然需要恢复协议;单重新打开一个端口并不能建立会话.

### 不可改变的释放快照和单一的固件BIN

这个 `/firmware` 进口 `loadOfficialFirmware({ board?, version?, fetch?, signal? })` 财务报告和审定财务报表 `loadReleaseManifest({ url, sha256, version?, sourceCommit?, boards?, fetch?, signal? })`。官方读者优先排序 `[publication]` 内 `config.toml`,在返回前,选择一个准确的版本参考并验证其原始清单SHA-256 `{ schemaVersion: 1, version, sourceCommit, pipelineId, layout, releases, website, mcp?, publication }`. 历史参考文献包括:精确的棋盘集;不支持的棋盘/版本组合和不正确的显式出版数据拒绝,而不会回落到被猜测的URL或旧的元数据. 无配置 `[publication]` 保存遗留的种子; 一个明确的版本也限制了旧的元数据请求 .

对于通过经核实的快照构建的网站,保留其选定的出版物参考文献,而不是重新阅读可变内容 `config.toml` 当用户点击时:

```js
import { loadReleaseManifest } from '@esp-vision/device-core/firmware';
const snapshot = await loadReleaseManifest({
  url: reference.manifestUrl, sha256: reference.manifestSha256,
  version: reference.version, boards: reference.boards,
});
const release = snapshot.releases.find(entry => entry.board === selectedBoard);
// Pass release to createDevice().firmware.update(); the website never slices BINs.
```

单位 `layout: 'single-bin'`, (中文(简体) ), `image.source = { url, bytes, sha256, offset }` 描述完整的BIN; `image.url` 等于其 URL,同时 `image.bytes/sha256` 仍然只描述申请。 源代码 URL/长/小时必须匹配 `install`,其抵消必须等于应用程序的闪存抵消。 核心下载了完整容器一次(没有Range请求),验证了整个散列和嵌入式快取器/组件/应用程序散列,再取出并仅将应用程序写入默认更新模式. 现有的分区检查和完整的书面核查仍然是强制性的; `mode: 'install'` 写入合格的完整 BIN 。 与 `image.source`提供 `data` 也必须是完整的 BIN; 旧的只应用元数据保留其现有的原始应用程序 `data` 语义. 明信片以4 MiB为界,固件下载以256 MiB为界,并经过批准的准确尺寸. 官方显示/艺术来源仅限于ESP-VISION CDN根;模型URL使用其全源承诺,MCP有一个版本/承诺/hash描述. npm, 固件标签或CDN 发布不通过编写此源版本来实现.

为了在 npm 发布前验证, 检查一个准确的审查承诺, 运行 `npm install --ignore-scripts --no-audit --no-fund --package-lock=false` 财务报告和审定财务报表 `npm run release:check` 内 `host/device-core`,则 `npm pack --ignore-scripts --pack-destination <project-local-output>`安装当地生产的柏油球或使用被钉住的源档案.

### 浏览器 ROM 闪烁

`@esp-vision/device-core/browser` 出口 `openBrowserRom({ port, logger?, signal?, interface?, baudRate?, onStatus?, expectedMac? })`建筑是被动的; `initialize()` 懒散地装入官员 `esptool-js@0.7.1` 后端和同步为115200. 使用浏览器捆绑器如webpack,Vite或esbuilt来包含芯片分贝. 根入点保持平台中立; `/node` 仅在初始化时加载共享ROM引擎。 不需要 Python 安装或消费者侧依赖补丁 .

0.7.0中引入的浏览器适配器曝光 `chipMac`,使用与节点适配器相同的12个小写十六进制厂-MAC代表. 没错 `null` 身份认证前。 浏览器通过官方芯片读取 `readMac(loader)` 原始的,不重复eFuse布局. 通过所选运行时间的已核实工厂 MAC `expectedMac` 将设备交给ROM时, 例如验证 `machine.unique_id()` 已知与董事会的工厂MAC相匹配. 宿主必须建立这个来源; 任意的遗产 `deviceId` 或USB VID/PID不建立协会。 如果无法验证该值,则使用明确用户选择的手动ROM工作流程,而不是推断自动关联. 此选项接受精确12个十六进制字符,使大写正常化并拒绝分隔符,白空格, `null` 和打开端口前同步的其他类型。 返回错配 `ROM_IDENTITY_CHANGED`中,关闭适配器,无法启动分贝、去除或写入。 无法读取/ 已成型的 MAC 响应返回 `ROM_IDENTITY_INVALID`。没有选项,手动选择一个初始ROM仍然支持;所有后来的同步/恢复仍然绑定了原来的家族,修订版和MAC,拒绝不同的同型设备而不重新绑定.

`interface` 接受 `auto` (违约), `uart`, (中文(简体) ), `usb-otg` 财务报告和审定财务报表 `usb-jtag`自动检测将已知的USB-UART桥标与Espressif OTG和Serial/JTAG区分开来;模棱两可的定制标语保持保守并可以明确识别出. 一个已准备好的OTG ROM是同步的,而不会牵引 DTR/RTS. 一个被剥离或再被设定的设备需要再次选择其当前下载端口;SDK从不将一个被剥离的端口对象作为恢复会话对待.

对于UART, `baudRate: 'auto'` (默认)测试 **2000 000-15 000-921600-460800-115200** 在验证ROM安全性并启动 stub后,然后以第一个通过注册和文摘检查的只读流量的速度停止. 此列表中的数值只测试此速度 。 一个失败的预写候选人重排, 同步于 115200 , 重新检查芯片身份/ 安全性, 并在下一个候选人之前重新装入根 。 原生 USB 跳过 UART 速度谈判;适配器 `baudRate` 实值 `null` 在这里. `onStatus(event)` 报告 ROM 连接、速度测试/失败/选择、检测出闪存ID和压缩写入。 固件书写被压缩并保留完整的书写验证和被保护的更新界限. 中断写入会话无效, 需要新的操作; SDK 永远不会盲目恢复压缩流 .

上游问题限值回放适配器 [esptool-js #273 (英语)](https://github.com/espressif/esptool-js/issues/273) 使用一个 KiB 包, 一个未完成的包和一个被检查的后继 MD5 文摘 。 这涉及协议的完整性,但没有说明调查的再写时间故障的确凿原因。 只有在被绑定的上游替换通过相同的预读后,才去掉适配器 → 完整的写入 → 完整的回读测试. SHA-256在写入前仍然具备源字节的资格. 内置适配器再用官方esptool设备MD5验证了完整的写作;完整的SHA-256回放仍然是自定义适配器的倒放回放,没有写作收据.

```js
import { createDevice } from '@esp-vision/device-core';
import { openBrowserRom } from '@esp-vision/device-core/browser';

// Request permission directly in the user's click handler (HTTPS or localhost).
const port = await navigator.serial.requestPort();
// release comes from firmware.check(), selected for the physical board.
const result = await createDevice().firmware.update({
  release, board: release.board, mode: 'update', // Explicit 'install' for complete images.
  openLoader: ({ signal }) => openBrowserRom({ port, signal, logger: console }),
  onProgress: percent => updateProgress(percent),
});
if (result.needsReset) showManualReset();
```

核心拥有下载,芯片/修正/安全和分区/容量检查,写作,写作验证并重置. 适配器拥有所选端口,直到Core断开;UI必须首先发布任何运行时间串行连接. 在建造或芯片初始化期间, 它不会启动任何支线 : 核心在呼叫前检查已核准的图像和ROM安全 `runStub`P4修订版301/302闪存电源和S31支持来自被钉住的上游9.4.2;Core保留了被捆绑的SLIP-前缀耐受性,原生的USB起动确认和大小的擦除超时. 不支持的根断面明显会失败 。 保持页面和端口的活性,直到更新的"承诺"结算;在写入前接受取消,从不中断开始的写入/读回. 该ROM适配器不提供运行时EV-MUX串行运输或Wi-Fi/TCP OTA.

### 正式节点适配器

公共节点入口也出口 `inventory`, (中文(简体) ), `listSerial`, (中文(简体) ), `filterSerialPorts`, (中文(简体) ), `serialEntry` 财务报告和审定财务报表 `transportFor`。编号是被动的,除非 `inventory({ probe: true })` 明确要求取消; 支持取消。 0.8个核心删除 `defaultPython`, (中文(简体) ), `nodeAdapterAssets` 和派特恩的助手的资产。 节点捆绑者必须保留原生npm依赖及其预建的二进制;独立的CLI构建显示这种包装.

只有节点 `@esp-vision/device-core/node` 子路径导出 `tcpTransport({ host, port })` 财务报告和审定财务报表 `serialTransport({ serial })`。构造器是被动的;核心打开/关闭链接 `connect()`编号 :`disconnect()`. 序列用途 `@serialport/bindings-cpp@13.0.0`,带有克菲2.16.3 Linux USJ 调制解调器控制回落, 以及角色 `usj`, (中文(简体) ), `usb` 或者说 `uart`。根/浏览器切入点不装入节点本地依赖.

```js
import { createDevice } from '@esp-vision/device-core';
import { tcpTransport, serialTransport } from '@esp-vision/device-core/node';

const tcpDevice = createDevice({ transport: tcpTransport({ host: '192.168.1.100', port: 3232 }) });
const usbDevice = createDevice({ transport: serialTransport({ serial: '/dev/ttyACM0', python: 'python3' }) });
// Connect only the selected device, and always disconnect() in finally.
```

只有在发现的情况下才能在以后收到运输:

```js
import { createDevice } from '@esp-vision/device-core';
import { tcpTransport } from '@esp-vision/device-core/node';
import { createNodeDiscovery } from '@esp-vision/device-core/discovery/node';

const provider = createNodeDiscovery();
const device = createDevice({ discovery: provider });
const selected = (await device.discover({ timeout: 3000 })).find(item => item.compatible && item.addresses.length);
if (!selected) throw new Error('No compatible device found');
try {
  await device.connect({ transport: tcpTransport({ host: selected.addresses[0], port: selected.port }), role: 'tcp', expectedDevice: selected });
  console.log(await device.inspect({ fields: ['identity'] }));
} finally { await device.disconnect(); }
```

应用程序发现是 `device.discover()`。 。 。 . `createNodeDiscovery()` 财务报告和审定财务报表 `createBridgeDiscovery()` 适配器合同是 `list({ timeout, signal })`他们不会暴露 `discover()`输入提供者 `createDevice({ discovery: provider })` 而不是打电话 `provider.discover()`。 。 。 . `list()` 是低级集成方法,而不是另一个设备 API.

支持的查询字段为 `identity`, (中文(简体) ), `capabilities`, (中文(简体) ), `runtime`, (中文(简体) ), `network` 财务报告和审定财务报表 `storage`默认为身份/能力/运行时间; `inspect` 仅读取请求的字段,而不更改配置。 网络/存储查询需要相应的固件能力. `connect()` 返回谈判后默认检查结果.

### 活动

`on(name, handler)` 返回未订阅的函数。 如果您需要看到启动输出, 在连接前登记输出处理器 .

| 活动 | 有效载荷 |
| --- | --- |
| `python.output` | 包含 Python stdout/stderr 文本或交互式 REPL 提示的字符串 |
| `raw` | EV- MUX 框架外包含文本的字符串 |
| `log` | 包含固件诊断日志文本的字符串 |
| `preview` | `{ data: Uint8Array, mimeType: 'image/jpeg', metadata }` |
| `state` | `{ state, identity?, reason? }`,包括: `connecting`, (中文(简体) ), `ready` 财务报告和审定财务报表 `disconnected` |
| `diagnostic` | 对象为 `event` 和诊断细节;包括: `rpc.request`, (中文(简体) ), `rpc.response`, (中文(简体) ), `rpc.timeout` |
| `rpc` | 输入的 RPC 对象 `{ channel, metadata, payload }` |

预览框架作为事件交付,而 `capture()` 返回请求的一发图像。 诊断事件有效载荷用于排除故障,而不是替代查询/配置方法。 网络资质通过RPC诊断进行编辑;应用程序仍应避免记录自己的配置请求. 抛掷事件听众不能打断解析器发送或其他听众.

### 配置和控制

网络配置使用部分更新:省略属性保持不变. `credentials: null` 清除保存的证书并禁用网络。 把它和 `enabled: true` 被拒绝。 提供全权证书既要求 `ssid` 财务报告和审定财务报表 `password`; 打开的网络使用空密码.

```js
await device.configure({
  network: {
    enabled: true,
    credentials: { ssid: 'example', password: 'secret' },
  },
});
await device.configure({ network: { enabled: false }, timeout: 45000 }); // Keep credentials.
await device.configure({ network: { credentials: null } });

await device.control({ action: 'stop' });
await device.control({ action: 'reset', mode: 'soft' });
await device.control({ action: 'reset', mode: 'hard' });
await device.control({ action: 'bootloader' });
```

组合配置请求按顺序应用,而不是作为交易应用. 如果失败了, `error.completed` 描述已确认的变化 `error.pending` 识别未完成的操作; Core 不滚动设置。 过 `timeout` 财务报告和审定财务报表 `signal` 在同一请求对象中 `network`编号 :`action`,而不是作为第二个选项参数。 配置超时是综合操作的预算. Wi-Fi 更改可能断开 TCP 连接 。 硬重置并进入下载器也可以去除USB接口;设备返回后通过主机传输重新连接. 成功重置请求不能保证重开的固件已经在线. 配置不返回已保存的 Wi- Fi 密码 .

### 交互式 Python 和脚本

```js
const unsubscribe = device.on('python.output', text => terminal.write(text));
await device.python.input('print(1)\r');
await device.control({ action: 'stop' }); // Ctrl-C / stop.

const result = await device.python.execute({
  source: 'print(1)',
  completion: 'wait',
});
await device.python.execute({ path: '/main.py', completion: 'start' });
unsubscribe();
```

`source` 财务报告和审定财务报表 `path` 两者相互排斥. `completion: 'wait'` (默认)返回 `{ ok, path, output, outputTruncated }` 程序结束后. `'start'` 返回时 `{ ok, path, done }` 在Core从生成的跑取器收到一个私有的 VM 输入标记后;它不等待程序完成,因此在返回手柄时可能已经完成了一个简短的脚本. 核心等待最多5秒钟 开始确认。 如果它超时或被取消,程序可能已经输入,而Core并不声称它停止了. 等着 `done` 用于执行结果。 一旦开始的手柄还原, `device.disconnect()` 发布会话而不要求停止; `done` 当会话关闭时拒绝本地程序,设备程序可能会继续. 提供电话 `signal` 一直约束到 `done` 当会话可用时中止时,会结算并请求停止。 源启动此方法使用一个Core执行后删除的内部临时脚本;断开可以防止这种清理. 终端输入,脚本和文件系统帮助者共享一个MicroPython解译器. 在自动操作拥有REPL时,应用程序不应发送终端输入. 拒绝与自动操作相冲突 `DEVICE_BUSY`; 核心不会默默地排队它们,也不会在第二个解释器中孤立用户Python. 终端输入仍然可供明确开始的交互式脚本使用.

小型 `source` 请求 `completion: 'wait'` 在不创建设备文件的情况下运行到已有的 REPL, 所以当存储被卸载而不需要时它们就会工作 `script.run` 或者说 `file.write.binary`。 Core 将源保存在一个临时的 REPL 变量中,在正常的全局命名空间中执行,这样用户变量仍然可用,完成后只删除该临时变量。 大于REPL输入限制的源头使用临时设备脚本并需要 `script.run`, (中文(简体) ), `file.write.binary`和可写存储.

对于 `completion: 'wait'`,省略 `timeout` 禁用总操作期限; 正数 `timeout` 限制整个操作,包括其REPL队列和启动交换。 Core仍然将每个REPL交换和RPC绑定,因此省略的总最后期限不会产生无约束的协议等. 如果代码运行时出现超时或取消,其效果可能不确定; Core没有声称程序停止或回滚设备改变.

### 文件与图像

```js
await device.files.mkdir({ path: '/models' });
await device.files.write({
  path: '/models/model.espdl',
  data: modelBytes, // Uint8Array; strings are UTF-8.
  overwrite: true,
  signal: abortController.signal,
  onProgress: progress => console.log(progress),
});
const bytes = await device.files.read({ path: '/models/model.espdl' });
const entries = await device.files.list({ path: '/' });
await device.files.remove({ path: '/models/model.espdl' });

const image = await device.capture({ source: 'camera', format: 'jpeg', timeout: 15000 });
// image: { data: Uint8Array, mimeType: 'image/jpeg', metadata }
```

路径是绝对设备路径. `files.list({ path: '/', recursive: false })` 返回条目 `{ name, path, type, size }`。 。 。 . `files.read({ path })` 返回 a `Uint8Array`; 使用 `encoding: 'utf-8'` 返回文本,并 `maxBytes` 以约束读取。 选择 `timeout` 禁用总计读取截止日期; 正数 `timeout` 限制全读。 每一块请求仍受下列限制: `chunkTimeout`,默认为30秒。 写入默认值 `overwrite: true`; 设置为 `false` 需要一个新的目的地。 上传和执行是单独的操作; 创建一个空文件 `files.write({ path, data: new Uint8Array() })` 而不是第二次触摸API。 删除空目录 `files.remove({ path: '/models', type: 'directory' })`;没有隐含的递归删除. `files.mkdir({ path, recursive: true })` 创造了失踪的父母.

**二进制上传( SDK 0. 3. 0) :** 文本、模型和图像上传 共享可靠的原始二进制 `file.write` 框架有16个KiB块,连续的本地VFS写作和SHA-256承诺. 匹配的固件必须广告 `file.write.binary`; 缺少支持以固件升级消息拒绝, 而不会缓慢上传回倒计时. 文件进度不是一个持久的承诺 。 FAT替换保留了旧文件备份,直到普通出版成功,在普通重命名失败上回滚;它不是一个功率损失-原子日记. 文件系统必须挂载并允许写入,并有临时上传和任何已存在的目的地文件的空间. 文件读取和目录操作目前使用REPL.

`capture({ source: 'screen', format: 'jpeg' })` 使用专用 `debug.capture_screen` RPC可以将 LCD 上次提交的 RGB565 帧缓冲器编码,包括显示器的缩放和信箱. 它不读面板电子,也不捕捉相机。 相机捕获用途 `debug.capture_frame` 只有在固件也做广告时 `debug.capture_frame.observed.v1`。它观察应用程序上一次成功相机快照后发布的独立帧;它从未初始化传感器,获得另一个物理帧或覆盖应用程序控件 `Image`. 该独立意见没有反映以后的申请处理情况。 缺少本地安全支持 `UNSUPPORTED_OPERATION` 和固件升级消息, 不发布旧的抓取RPC。 没有有效的发布框架、相机重组、关闭或 VM 重置返回 `CAMERA_FRAME_NOT_READY`; 观察员分配失败返回 `NO_MEM` 而应用程序快照仍然成功。 使用 `connect({ probeRepl: false })` 以观察运行中的应用程序,而无需默认的 REPL 中断。 返回与请求相关的二进制 JPEG 响应; 可选 `quality` 是 1 到 100 的整数 。 缺少固件能力 `UNSUPPORTED_OPERATION`; 未初始化的显示返回 `DISPLAY_NOT_READY`,且没有 LCD 的棋盘返回 `NOT_SUPPORTED`。预览是一个单独的实时流,可能会在拥堵下下降帧.

抓取和预览送出需要自成一体的8位Huffman JPEG(SOF0/1/2). 在EV-MUX长度/CRC和会话关联性检查后,核心检查标记和段边框,量化和Huffman表结构/参考,SOF维度对照元数据,扫描组件覆盖,非空扫描/重启段以及一个没有后缀字节的最后EOI. 这是结构验证,不使用 en解码;它不能确定每个压缩系数都可以被解码. 无效的抓取回复立即拒绝 `INVALID_IMAGE`; 明确的固件错误保留其原始代码. 在任何图像回调前, 无效的预览框架会被丢弃 。 都发出诊断 `{ event: 'image.invalid', channel, method, seq, code: 'INVALID_IMAGE', reason }`; 解析器 `invalidImageFrames` 财务报告和审定财务报表 `droppedFrames` 计数器增加。 固态响应在验证前被过滤,不能拒绝另一个请求.

## 发现和运输适配器

公司软件广告 `_esp-vision._tcp.local` 有主芯片设备ID,全板名,固件版本,犬形主机名和EV-MUX版本. 主机名为 `esp-vision-<full-board-name>-<last-6-mac-hex>-<firmware-version>`;所有运输查询都返回同名. 发现不打开设备 TCP 套接字或获取所有权 。 连接期间设立占用.

节点发现使用可选 `multicast-dns` 端点 :

```js
// npm install multicast-dns
import { createDevice } from '@esp-vision/device-core';
import { createNodeDiscovery } from '@esp-vision/device-core/discovery/node';

const device = createDevice({ discovery: createNodeDiscovery() });
const devices = await device.discover({ timeout: 3000 });
```

浏览器发现使用本地桥上的 HTTP 端点:

```js
import { createDevice } from '@esp-vision/device-core';
import { createBridgeDiscovery } from '@esp-vision/device-core/discovery';

const device = createDevice({
  discovery: createBridgeDiscovery('ws://127.0.0.1:8766/device'),
});
const devices = await device.discover({ timeout: 3000 });
```

结果包含 `deviceId`, (中文(简体) ), `hostname` (无) `.local`, (中文(简体) ), `board`, (中文(简体) ), `firmwareVersion`, (中文(简体) ), `evMuxVersion`, (中文(简体) ), `compatible`, (中文(简体) ), `addresses`, (中文(简体) ), `port`,并针对适配器 `expiresAt`编号 :`connectionUrl`。提供选定的结果 `expectedDevice` 连接时 : Core 在获取前检查稳定的ID和主机名, 防止被扭曲的 DHCP 地址 。 这是身份匹配,不是认证。 刷新已过期的桥柄 。 多播过滤,VLAN和客户端隔离可能需要手动地址. 浏览器没有本地的 DNS- SD 计数 API; 本地网络权限不删除桥接要求 .

仅节点适配器和被动串行库存均从 `@esp-vision/device-core/node`数字 : `listSerial`, (中文(简体) ), `filterSerialPorts`, (中文(简体) ), `serialEntry`, (中文(简体) ), `transportFor`,以及 `inventory`。 。 。 . `listSerial({ signal, timeout })` 使用 npm 有超时和取消信号的串行计数; 它列出端口而不打开. `inventory()` 列表中不默认进行检测。 过 `probe: true` 以获取每个选定的 EV- MUX 会话并查询元数据;这不会发送 Ctrl- C 或运行一个 REPL 探测器,并报告 `vmReady` 状态被保留。 创建传送方式 `transportFor()` 被动且不打开端口。 被动本地 USB ROM 条目返回 `status: rom` 不打开港口。 活动 `inventory({ probe: true })` 首先验证所选的ROM身份/安全性,清除其软件下载锁链并尝试一次正常的SPI出舱,然后只探测匹配的MAC和物理USB位置. `romProbe` 记录过渡; 没有返回的运行时间仍然不明, 安装前可能需要物理的 BOOT/RESET 。 ROM 模式和超时不能证明固件缺失;序列/会话所有权冲突返回 `busy`。 。 。 .

Root/浏览器切入点不导入节点网络模块. 可选的节点发现子路径动态加载 `multicast-dns`。不需要代理软件包.

## 来自会话的迁移 API

这是第一次公开v4发布时的API边界. 只输出包根 `createDevice()`编辑 `Device` 分类是内部执行的细节。 遗产执行类别不在那里出口。 协议适配器和现有集成器可以使用明显的子路径,例如: `/session`, (中文(简体) ), `/evmux`, (中文(简体) ), `/evrepl`, (中文(简体) ), `/actions` 财务报告和审定财务报表 `/bindings` 迁移时; 新应用程序代码应使用 `createDevice`。 。 。 .

| 先前的应用程序调用 | 设备 API |
| --- | --- |
| 构造 `DeviceSession` 与 `EvMuxParser`, (中文(简体) ), `EvRepl`, (中文(简体) ), `makeEvMuxFrame` | `createDevice({ transport, discovery })` |
| `NetworkDiscovery.list()` | `device.discover(options)` 与注入的发现提供者 |
| `negotiate()`, (中文(简体) ), `release()`, (中文(简体) ), `close()` | `connect()`, (中文(简体) ), `disconnect()` |
| `snapshot()`, (中文(简体) ), `hasFeature()`, (中文(简体) ), `networkStatus()`,RAPL 信息助手 | `inspect({ fields })` |
| `configureNetwork()`, (中文(简体) ), `setNetworkEnabled()`, (中文(简体) ), `forgetNetwork()` | `configure({ network })` |
| `interrupt()`, (中文(简体) ), `stopForRepl()`, (中文(简体) ), `control('soft-reset')` | `control({ action, mode })`;准备障碍是内部的 |
| `repl.writeStdin()` | `python.input(data)` |
| `executePython()`, (中文(简体) ), `runScript()`, (中文(简体) ), `startScript()` | `python.execute({ source OR path, completion })` |
| `writeFile()`, (中文(简体) ), `writeScript()`, (中文(简体) ), `repl.writeFile()` | `files.write({ path, data, overwrite, signal, onProgress })` |
| `repl.walkFs/readFile/removeFile/removeDir/makePath()` | `files.list/read/remove/mkdir(request)` |
| `repl.touchFile()` | `files.write({ path, data: new Uint8Array() })` |
| `handlers.text/rawText/preview/log/...` | `on(event, handler)` |
| 行动 `frame.capture` | `capture({ source: 'camera' })` |
| 根固件起伏出口 | `@esp-vision/device-core/firmware` |

构建会话或呼叫的 IDE 和 Agent 适配器 `session.repl` 必须在自己的融合边界移徙。 在UI中不要执行第二个解析器或文件传输协议. 现有的行动合同和协议类别仍然是适配器执行工具,而不是第二个应用API.

## 固件闪烁

ROM闪光仍是一个单独的生命周期 `@esp-vision/device-core/firmware`。主机注入ROM加载器,批准图像显示并重设政策。 适配器验证图像完整性,芯片/修正,安全和分区,验证完整的写法,并重新设置前清理出P4下载夹. 它不分发固件,不打开取取浏览器或提供闪光UI. EV-MUX 变相器 `control({ action: 'bootloader' })` 只请求输入下载器;它不闪出图像。 其设定的REPL路径没有设备识别: `{ acknowledged: false, outcome: 'unknown' }` 报告提交时,下一个ROM连接必须在写入之前识别芯片。 核心在提交重设命令后或当写入结果不确定时, 将旧的 EV- MUX 租赁无效; 断开不会发送 stale `session.release`。在尝试重置命令之前失败,保留了普通清理的活租。 节点串行桥排出已排队的输出后再从一个成功的重设提交返回 .

节点加载器只解决已明确选择的串行路径,并短暂地等待该路径可供使用. 选定的 ESP-VISION 本地 USB 运行时间 (`303a:4003`,或紫外线复合材料 `303a:4023`)必须建立活跃的EV-MUX USB所有者并匹配其设备ID(或遗留的运行时间短) `machine.unique_id()` 在Core一次请求装货机之前 使用USBMAC序列 然后Core只接受一个带有同一种USB MAC和物理位置的ROM接口,在允许写作前验证被ROM报告的工厂MAC. 现有的ROM,UART和USB串行/JTAG端口不作为EV-MUX运行时间被探测. 如果第一个只读的ROM初始化在任何交接或写入之前都失败了,Core只能在其运行时间重新观察到同一设备并再次验证运行时间后恢复一次. 它不重试写或重复已经提交的装入器请求 . `loader.usbTransition` 记录命令确认、观察到的ROM计数和单独清理; `loader.port` 是合格的当前 OS 路径。 失败或被取消的初始化关闭了该加载器,并且不能在同一实例中重放 。 缺失的旧的副标识路径不会授权猜测不同的设备 .

代理工作流程,MCP工具映射,模型提供商和插件包装属于自己的集成包,不在此列.

## 审定和释放

从此目录, 使用 Node.js 22 :

```sh
npm test
npm run check:schema
npm run check:package
npm pack
```

设定 `TMPDIR`, (中文(简体) ), `TMP` 财务报告和审定财务报表 `TEMP` 转到运行软件包验证时的工程本地临时目录。 套件检查在一个孤立的临时目录中安装了柏油球并导入了公共出入口. Node.js 22是支持的节点主机基线. 浏览器主机需要Web Serial或二进制的WebSocket-to-TCP桥外加包分光符的捆绑/进口地图.

设备核心与固件一起维护 `host/device-core` 内 [咖啡/电视](https://github.com/espressif/esp-vision)协议变更、东道主执行、文件和合同测试一起审查。 SDK版本仍然独立于固件版本;相容性通过EV-MUX v4能力谈判. IDE 和 Agent 消费相同的 npm 软件包,不保存协议副本 .

运行 `npm run release:check` 从此目录中可以进行单位测试、计划验证、孤立的软件包安装和出版物干运行。 SDK只更改运行这些节点.js检查而不编译固件. `ESP_VISION_DEVICE_CORE_ONLY=1` 在 API/web 管道中选择 SDK 检查; `ESP_VISION_BUILD_FIRMWARE=1` 在需要时请求最后的固件矩阵。 SDK 版本在 `package.json` 和 npm;不要在这个固件仓库中创建 SDK Git 标记,因为固件/文档版本的发现使用 Git 标记. CI 防御性排除意外 `device-core-v*` 来自固件工作的标记,但是创建这些标记并不是SDK发布工作流程的一部分.

受保护的默认分支推 (PDF)`master` 使用被遮罩/被保护的版本 ) `NPM_PUBLISH_TOKEN`。账户必须是 `esp-vision` 拥有瞄准镜写入权限。 MR, 特性分支, 本地和SDK-tag运行 从来没有发布。 即使源已更改, 已有的版本也会被跳过; 凸起 `package.json` 在释放这些变化之前。 出版物核实新公布的登记册的完整性.

在启用此出版商之前, 禁用旧的 IDE- project 包发布任务, 因此只有一个权威的出版商 。 迁移是分阶段的:限定这个存储器SDK及其出版管道,公布并验证其注册完整性,再将IDE/Agent适配器更新到固定的软件包版本并去除旧的IDE源拷贝. 在消费者迁移完成之前,旧的工作树被保存为一个备份,而不是未来SDK变化的又一来源. Npm 不通过本地移民测试进行出版.

软件包包括库源,计划,许可证和文件,没有IDE/Agent捆绑或发布脚本. 今后每一次发布,都必须更新其版本和更改日志.

## 硬件接受

货包装上它的单元套装和硬件跑道。 从您的应用程序目录中明确瞄准已安装的依赖性 :

```sh
npm --prefix node_modules/@esp-vision/device-core test
npm --prefix node_modules/@esp-vision/device-core run test:hardware -- --help
npm --prefix node_modules/@esp-vision/device-core run test:hardware -- --tcp 192.168.1.100:3232
```

源代码或已安装的软件包目录内部, 使用 `npm test` 财务报告和审定财务报表 `npm run test:hardware -- ...`单位测试不需要设备。 跑者明确列出测试结果,当套房缺位或空出时失败,而不是通过零个案例. 专用硬件跑车使用 `--serial`如其帮助所示.

运行源或安装了SDK来对抗一个使用Node.js 22. 这些检查是公开的 `createDevice()` API并发布会话,之后进行运输. 默认检查读取身份/ 能力/ 运行时间, 并执行一个短文件 `print()` 不创建设备文件。 连接会谈判REPL,所以使用一个运行中的Python应用程序可能安全被中断的设备. 检查不配置Wi-Fi, 重置棋盘或擦除存储 .

```sh
npm run test:hardware -- --tcp 192.168.1.100:3232
npm run test:hardware -- --serial /dev/serial/by-id/YOUR_DEVICE --role usj
npm run test:hardware -- --serial /dev/serial/by-id/YOUR_USB_OTG_DEVICE --role usb --write
npm run test:hardware -- --tcp 192.168.1.100 --write --capture --timeout 90000
npm run test:hardware -- --serial /dev/serial/by-id/YOUR_DEVICE --role usj --checks all --frames 30 --output camera.jpg
npm run test:hardware -- --tcp 192.168.1.100 --checks display --display-hold 2 --screen-output screen.jpg
```

`--write` 明确选择创建随机命名的 1 KiB 二进制文件,通过回读验证每个字节,并删除该文件及其临时上传兄弟. 已存在的匹配路径被拒绝; 清理失败会与测试路径一起报告, 并导致命令失败 . `--capture` 明确在检查被动相机观测之前准备应用程序快照; `--output` 可选择保存 JPEG 。 SIGINT/SIGTERM取消操作;清理有单独的限定期限. 输出排除了网络证书,任意设备日志和Python回溯. 检查失败时退出 .

`--checks all` 运行共享固件/ SDK 硬件套件 : `identity`, (中文(简体) ), `memory`, (中文(简体) ), `camera`, (中文(简体) ), `framesizes`, (中文(简体) ), `pixformats`, (中文(简体) ), `orientation`, (中文(简体) ), `ipa_stats`, (中文(简体) ), `snapshot_rate`, (中文(简体) ), `preview`, (中文(简体) ), `image_ops`, (中文(简体) ), `display`,以及 `display_stream`中选择逗号分隔子集 `--checks memory,camera,preview`时机控制 `--frames` (违约30起), `--frame-timeout` (秒,默认为25),以及 `--display-hold` (秒每后光状态,默认为0). 传感器默认值为 `--framesize QVGA --pixformat RGB565`· ; `--quality` 默认为60。 功能检查默认为总期限60万毫秒;明确 `--timeout` 超过它。 每个结果都是与PASS/FAIL/SKIP相接的JSON线,测量和持续时间,然后是摘要. 未支持的硬件被跳过;IPA的缺席仍然是相机需要IPA的板上的故障.

这些功能检查有意锻炼传感器设置,图像处理,预览和液晶. 他们的单个Apache-2.0 MicroPython固定器被安装到独特的设备路径上 `files.write()`,通过 `python.execute()`,并删除。 随后的检查使用简短 `python.execute()` 调用;预览接收使用公共事件 API. 套房去掉它的固定和Python命名空间,释放出它的显示对象和断开. 它不覆盖应用程序文件,也不维护第二个EV-MUX/RPC执行.

`--screen-output PATH` 明确请求 LCD 截图: 它添加 `display` 检查需要时,绘制红/绿/蓝/白条 `ESP-VISION CI` 文本, 校验回光修改, 抓取相同的显示 `capture({ source: 'screen' })`,验证JPEG的完整性和面板尺寸,并在发布显示前将JPEG写入主机上. 缺少了LCD或屏幕抓取支持,使得此明确请求失败而不是跳过. 摄像头捕捉是另一个来源 运行此套件时, 输出图像和日志应放置在您的工程本地文物目录下 .

TCP和系列需要节点.js 22+. 串行需要启用可选 npm 本地依赖以及支持的平台预建,再加上OS设备驱动器和端口权限. 独立的CLI和插件包括他们的预建;没有使用Python子进程或用户侧编译. 共享的硬件跑道,单元测试以及设备边的MicroPython固定船在源树和npm柏油球. 不包括固件/建造产出和设备证书.

## 许可证

Npm 软件包和 ESP- VISION 捐款的使用 [阿帕奇 - 2.0](https://npmcn.com/package/%40esp-vision/device-core/LICENSE),匹配固件. [通知](https://npmcn.com/package/%40esp-vision/device-core/NOTICE) 保留历史部分和上游部分的原始版权和麻省理工学院许可文本。 第三方依赖者保留自己的许可证;无论是软件包元数据还是项目许可证都不能凌驾于许可证之上.

Hash 绑定的列表和完整BIN源使用浏览器 HTTP 缓存(`cache: default`); 可变配置和仅保留遗留的应用程序BINs `no-store`。一个被绑定资产上的取取级类型 `no-store` 重新尝试从旧的缓存反应中恢复,该反应缺少 CORS 头。 HTTP,机体读取,SHA-256和元数据故障不经过再试或降级.

## 常见问题

### @esp-vision/device-core 是什么？

共享EV-MUX,设置了REPL,设备会话,以及ESP Vision客户的行动合同\.

### 如何安装 @esp-vision/device-core？

在项目目录运行 npm install @esp-vision/device-core，或使用 pnpm add / yarn add / bun add。

### @esp-vision/device-core 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/esp-vision\_\_device-core 是否存在。

### @esp-vision/device-core 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @esp-vision/device-core 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @esp-vision/device-core 可以商用吗？

@esp-vision/device-core 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @esp-vision/device-core 的下载量有多少？

根据 npm 官方下载统计，@esp-vision/device-core 在 2026/10/14 – 2026/11/12 这 30 天内被下载 3,030 次，日均约 101 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @esp-vision/device-core 还在维护吗？

最新版本 0\.8\.1 发布于 2026/11/13（今天）；至今共发布 16 个版本，其中过去 12 个月发布了 16 个；首次发布于 2026/10/16。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

