13.1.14. 第三方存储库#

IDE 附带 OpenMV 自己的开发板、固件、示例、机器学习模型和编辑器存根,但它也可以加载来自其他公司的相同类型的内容 - 合作伙伴构建的开发板、在其上运行的固件、为其调整的示例和模型,以及固件添加的 API 的代码完成。这些内容以 third-party repositories 的形式到达:IDE 与自己的内容合并并保持最新的内容文件夹。

此页面有两个受众。其中大部分是供安装和管理其他人发布的存储库的人使用的。最后一部分,authoring a repository,用于供应商构建。

13.1.14.1. 第三方存储库页面#

一切都通过编辑 → 首选项 → OpenMV → 第三方存储库进行管理。该表列出了每个已安装的存储库,以及每个存储库的显示名称、短 ID(无论是 Built-in 还是 User)、它提供的每种内容的已安装版本(固件、示例、模型、存根)以及它更新的 URL。

Built-in 表示存储库由供应商提供的安装程序放置到应用程序自己的目录中,就像驱动程序包将文件添加到程序中一样。 User 表示您自己通过 URL 安装了它。唯一的实际区别是您无法从 IDE 中删除内置存储库——它是通过卸载放置在其中的任何内容来删除的——因此“删除”按钮对其禁用。

13.1.14.2. 安装存储库#

从 URL 安装会询问存储库的 config.json(供应商发布的小清单文件)的地址,并安装它指向的所有内容。粘贴供应商给您的 URL; IDE 下载清单,获取固件、示例、模型和它列出的存根,并验证每个下载。安装、删除和更新存储库都会在重新启动后生效,因此 IDE 会在安装完成后重新启动。

供应商还可以将存储库作为安装程序分发,直接将其放入应用程序目录中,在这种情况下,它在您第一次打开页面时仅显示为 Built-in 行 - 无需安装任何内容。

13.1.14.3. 保持存储库更新#

每次 IDE 启动时都会检查带有更新 URL 的存储库。当有更新的内容可用时,IDE 会告诉您什么 - 列出每个存储库和涉及的版本 - 并提供安装它,所有这些都在一个提示中完成。检查更新按需运行相同的检查。

13.1.14.4. 优先级和覆盖#

存储库是一个有序列表,最高优先级位于顶部,上移和下移会对所选存储库重新排序。仅当两个来源提供 same 事物时,顺序才重要:具有相同 USB 标识符的板,或者具有相同名称的示例、模型或存根。当这种情况发生时,更高的条目会获胜,并且每个存储库都会胜过 OpenMV 的内置内容。这是经过深思熟虑的——供应商为共享 OpenMV 板 USB 标识符的板提供自己的固件,替换 IDE 为其提供的库存固件,或者用为其硬件编写的示例替换库存示例。

因为覆盖会默默地改变熟悉名称的功能,所以页面永远不会隐藏它。覆盖警告面板列出了每个有效的覆盖——哪个存储库的板、示例、模型或存根正在覆盖哪个——并且相同的列表在第一次看到存储库时作为消息出现一次。如果某个板、示例或模型的行为不符合 OpenMV 文档所描述的方式,那么首先要查看此面板。

13.1.14.5. 存储库提供什么#

这四种内容分别出现在 IDE 中的常用位置,因此安装存储库后,就没有什么新内容需要学习了:

  • Boards and firmware. 存储库的板的行为与 OpenMV 板完全相同 - 它在连接时被识别,其类型显示在状态栏中,并且其固件通过 IDE 更新,包括安装最新开发版本路径。参见固件更新与恢复

  • Examples. 存储库的示例出现在“文件”→“示例”中,并合并到类别树中:供应商与 OpenMV 类别命名相同的类别中的示例位于 OpenMV 类别旁边,新类别成为其自己的子菜单。像任何示例一样,它们会被过滤到它们支持的板。参见脚本、示例与文档文件夹

  • Models. 存储库的模型出现在 Model Zoo 中,并以相同的方式合并到浏览器树中,并带有供应商自己的描述。

  • Stubs. 存储库可以传送 .pyi 存根文件,因此 editor 为其固件添加的功能提供补全、签名和文档 - 与 OpenMV 自己的模块以及供应商的自定义 API 获得的补全相同。

13.1.14.6. 创作存储库#

存储库是一个以供应商命名的文件夹,包含一个 config.json 清单和它提供的每种内容的子文件夹:

acme/
  config.json
  firmware/
    settings.json                 board descriptions
    ACME_CAM1/                    one folder per board, named by boardFirmwareFolder
      firmware.bin
      romfs0.img
  firmware.version
  examples/
    index.csv                     which examples show for which board / sensor
    01-Getting-Started/           numbered category folders, same as OpenMV's
      hello_acme.py
      read_sensor.py
    02-Acme-Widgets/
      spin_widget.py
  examples.version
  models/
    index.csv                     which models show for which board
    acme/                         a group; its index.html + image describe it
      index.html
      image.jpg
      person_detector/            one folder per model
        person_detector.tflite
        person_detector.txt       class labels
  models.version
  stubs/
    acme_hal.pyi                  a module the firmware adds
    csi.pyi                       overrides OpenMV's to add methods
  stubs.version

文件夹名称是存储库ID:小写字母、数字、-_,以字母开头。每个零件文件夹都是可选的;只运送您拥有的东西。每个部件文件夹旁边都有一个 <part>.version 文件,其中包含单个版本字符串 (1.2.0),IDE 使用该文件来决定更新何时较新。

13.1.14.6.1. 清单#

config.json 命名存储库,并针对每个部分指向可下载的存档:

{
  "name": "acme",
  "displayName": "Acme Robotics",
  "homepage": "https://acme.example",
  "configUrl": "https://acme.example/openmv/config.json",
  "firmware": {
    "release":     { "version": "1.2.0", "url": "https://acme.example/acme-fw-1.2.0.zip", "sha256": "..." },
    "development": { "version": "dev-20260701", "url": "https://acme.example/acme-fw-dev.zip", "sha256": "..." }
  },
  "examples": { "release": { "version": "1.1.0", "url": "https://acme.example/acme-examples-1.1.0.zip", "sha256": "..." } },
  "models":   { "release": { "version": "1.0.0", "url": "https://acme.example/acme-models-1.0.0.zip", "sha256": "..." } },
  "stubs":    { "release": { "version": "1.0.0", "url": "https://acme.example/acme-stubs-1.0.0.zip", "sha256": "..." } }
}

name 必须与文件夹名称匹配。 configUrl 是同一文件的托管地址; IDE 会重新获取它以检查更新,因此仅对于永远不会更新的存储库省略它。每个部件都有一个 release 通道,固件也可能有一个安装最新开发版本时使用的 development 通道。版本 version 值作为数字进行比较,因此提供更高的值作为更新;开发版本仅针对更改进行比较。 sha256 是可选的,但在存在时进行验证。

每个 url 都指向 .zip(仅限拉链)。存档恰好包含 one top-level folder,IDE 会安装该文件夹的 contents 作为该部分 - 因此固件存档的打包方式如下:

acme-fw-1.2.0.zip
  acme-firmware/           one wrapping folder; its name does not matter
    settings.json
    ACME_CAM1/
      firmware.bin
      romfs0.img

并解压到前面显示的 firmware/ 文件夹。示例、模型和存根档案以相同的方式打包 - 一个包装文件夹包含 examples/models/stubs/ 中的内容。包装文件夹的名称将被忽略;重要的是确实有一个。在没有包装文件夹的情况下将文件压缩到存档根目录,或者将它们包装在多个文件夹中,将无法安装。最简单的方法是压缩文件夹本身 - 选择 acme-firmware 并压缩它,而不是选择其内容。

13.1.14.6.2. 板、示例、模型和存根#

firmware/settings.json 使用与 IDE 附带的固件相同的板描述格式;为每个面板添加一个 boards 条目。有一些特定于第三方板的规则:boardFirmwareFolder 必须是唯一的(OpenMV 或其他供应商尚未使用它,因为它命名了二进制文件所在的文件夹),每个板必须带有自己的 firmware_version(这是驱动更新连接提示的原因),并且板可以将 boardFirmwareFolderAlias 设置为 OpenMV 板的固件文件夹名称,以继承该板的库存示例和模型 - 板的逃生舱口其固件与 OpenMV 兼容。预计会重用 OpenMV 引导加载程序标识符(它们携带签名的 Windows 驱动程序);与内置板冲突的应用程序标识符会覆盖该板,覆盖警告面板会报告该情况。

示例位于编号类别文件夹中,例如 OpenMV 的 (01-Getting-Started);一个与 OpenMV 名称相同的类别会插入其中,新名称将成为其自己的菜单部分。模型是一个包含其 .tflite 和匹配的类标签 .txt 的文件夹,分组在一个文件夹下,其 index.html(和可选图像)是模型动物园中其旁边显示的描述。 examples/index.csvmodels/index.csv 与 OpenMV 自己的示例和模型使用的板和传感器过滤器文件相同,与您的示例和模型路径相匹配,并决定您的哪个显示于哪个板。存根是普通的.pyi文件; IDE 将它们的文件夹交给语言服务器,以便它们与 OpenMV 的文件夹一起解析,并且以现有模块 (csi.pyi) 命名的存根会覆盖该模块的完成。

13.1.14.6.3. 发布与更新#

要发布,请将 config.json 及其引用的档案托管在稳定的 URL 上,并为用户提供用于安装的 config.json URL。任何通过 HTTPS 提供纯文件的地方都可以工作——Web 服务器、对象存储或代码主机。要发布更新,请上传新存档,在托管的 config.json 中增加受影响的 version 值,并且下次每个用户的 IDE 启动时它会提供更新。通过安装程序安装存储库的用户会以相同的方式获取更新,只要安装的 config.json 带有 configUrl 即可。

13.1.14.6.4. 在 GitHub 上托管#

GitHub 是一个方便的主机,IDE 从它获取资源的方式与获取自己的资源的方式相同。有两部分需要放置:清单和档案。

config.json 保留在存储库中,并为用户提供其 raw URL——直接提供文件的地址,而不是显示该文件的 GitHub 页面。文件上的 Raw 按钮会显示它;它有以下形式

https://raw.githubusercontent.com/<user>/<repo>/<branch>/config.json

该原始 URL 是用户粘贴到“从 URL 安装”中的内容,以及您在清单自己的 configUrl 中放入的内容,以便 IDE 重新获取它以检查更新。将其指向分支(main)意味着推送新的提交来发布更改;将其指向标签会将用户固定到固定版本。

.zip 存档托管为 release assets 而不是提交它们 - 版本是为二进制下载而构建的,因此多兆字节的固件包属于那里,而不是存储库的历史记录中。将每个存档附加到 GitHub 版本并使用其下载 URL,其格式为

https://github.com/<user>/<repo>/releases/download/<tag>/acme-fw-1.2.0.zip

在清单的 url 字段中,每个字段都有存档的 sha256。然后发送更新:将新档案附加到发行版,编辑 config.json 以指向它们并更改版本,然后提交。 IDE 在下次启动时拾取更改(原始文件通过缓存提供,该缓存在推送后几分钟内刷新)。