从 CSV 导入设备
运营人员通常根据一份库存文件来接入设备群:序列号、名称、设备类型,有时还有出厂时写入的凭据。导入会读取该文件并创建其中的设备。它适用于任意的库存文件;若只需要“N 台编号的测试设备”,请使用批量创建,它根据模板生成设备。
已提供。可在控制台(设备 → 导入)中使用,也可通过 device-management GraphQL API 的 importDevices 使用。
导入只创建,且可以放心重复运行。设备令牌就是键:设备已存在且与该行描述完全一致时,该行报告为 EXISTS;设备已存在但内容不同时,报告为 CONFLICT;已存在的设备绝不会被修改。每一行都是独立的事务,所以一行出错不会影响其他行。
在控制台中导入
- 打开设备并选择导入。
- 选择如何处理凭据(见下文模式)。
- 选择 CSV 文件,或粘贴各行。文件需要有标题行。
- 检查列映射。标题与字段匹配的列会自动映射,包括控制台自己的导出 CSV 所写的标题,因此导出的列表可以直接导入。如果文件没有类型列,请为整个文件选择一个设备类型。
- 选择检查文件。这是一次试运行:服务器按真实导入完全相同的方式判定每一行,并且不写入任何内容。结果列出每一行的结果,并可按结果筛选。
- 选择导入 N 台设备(N 为检查结果中将被创建的行数)。各行以每批 1000 行依次发送,并显示进度;在本批之后停止会在批次之间干净地结束运行。
- 完成后,下载结果(每一行的结果)或失败的行,修正后再导入该文件。已经创建的设备会报告
EXISTS,不会被改动。
一个文件最多可包含 10,000 行和 5 MiB。更大的文件会在读取之前就被拒绝;请拆分后分别导入。
读取文件
- 文件必须是 UTF-8。以其他编码保存的文件会被拒绝并给出提示,而不会读成乱码;在电子表格中请另存为 CSV UTF-8。开头的字节顺序标记会被忽略。
- 分隔符(逗号、分号或制表符)根据第一行识别,因此使用小数逗号的区域设置下由电子表格保存的文件也可直接导入。
- 值可以加引号,可以包含分隔符、成对的双引号和换行,行尾可以是
LF、CRLF或CR。空行会被跳过。 - 文件中的任何内容都不会被求值。以
=、+、-或@开头的单元格按原样的文本保存。(控制台的导出会在这类单元格前加一个撇号,避免电子表格把它们当作公式;导入会再去掉该撇号,因此往返之后得到原始值。) - 在控制台中,除凭据密钥外,所有值两端的空格都会被去除;凭据密钥按原样发送。
列
| 列 | 是否必需 | 含义 |
|---|---|---|
token | 是 | 设备令牌:字母、数字、连字符和下划线,以字母或数字开头,最多 128 个字符。重复运行时依据它来匹配。 |
deviceTypeToken | 是,按行或对整个文件 | 已存在的设备类型的令牌。类型未知会使该行为 INVALID。 |
externalId | 否 | 你的业务标识符,最多 256 个字符,在租户内唯一。它只用于冲突检查,绝不作为键。 |
name | 否 | 最多 128 个字符。 |
description | 否 | 最多 1024 个字符。 |
metadata | 否 | JSON 文档,最大 64 KiB。重复运行时按值比较,所以键的顺序和空格无关紧要。 |
credentialType | 仅出厂凭据 | ACCESS_TOKEN 或 MQTT_BASIC。 |
credentialId | 仅出厂凭据 | 设备出示的内容:访问令牌本身,或 MQTT 用户名。 |
credentialValue | 仅 MQTT_BASIC | 密码,至少 16 字节,最多 4096 字节。只写。 |
设备始终以启用状态创建;导入时没有用于禁用设备的列。需要时请稍后在设备详情页禁用。
凭据模式
| 模式 | 作用 | 文件中的密钥 |
|---|---|---|
无(NONE) | 只创建设备。凭据之后再添加,可在设备的凭据选项卡或通过 GraphQL。 | 无 |
出厂凭据(FACTORY_CREDENTIALS) | 在同一个事务中创建每台设备以及工厂为它提供的凭据。一行不会出现只有设备没有凭据,或相反的情况。 | 有:该文件本来就存在于你的工厂;导入只是使用它,并不创建任何密钥 |
没有会生成凭据并交给你一份密钥文件的模式。DeviceChain 不会产生包含密钥的文件。
在出厂凭据模式之外,凭据列会被拒绝,因此密钥不会意外夹带在文件里。
面向自行接入的设备群的预置模式,将随自助接入功能一起提供。
密钥如何处理
credentialValue 是只写的。它仅以带密钥的摘要形式存储,与单独注册凭据时完全相同,并且不会出现在任何结果、消息、日志行或结果文件中。失败的行文件永远不含密钥列,所以修正后的文件需要你从自己的来源重新补上密钥。在控制台中,密钥只在导入进行期间保存在页面里,结束后即被清除。文件本身仍由你负责保管。
重复运行时,设备和凭据 ID 都已存在的行为 EXISTS;不会比较密钥,所以重复运行中改动的密码不会产生任何效果。要轮换密码,请使用凭据自身的更新。
结果
| 结果 | 含义 |
|---|---|
CREATED | 已创建设备(及其凭据)。在试运行中:将会创建。 |
EXISTS | 设备已存在,且与该行描述完全一致。视为成功;未写入任何内容。 |
CONFLICT | 该令牌已存在,但 deviceTypeToken、externalId、name、description 或 metadata 不同;或外部 ID、凭据 ID 属于另一台设备;或设备已存在但没有该行所指的凭据。未写入任何内容。 |
INVALID | 该行格式错误,或引用了不存在的内容:令牌不合规、设备类型未知、值超出限制、JSON 无效、同一文件中重复的令牌、外部 ID 或凭据 ID,或凭据有问题。 |
REFUSED | 该行格式正确,但被某条规则拒绝:不受支持的凭据类型。 |
除 CREATED 和 EXISTS 之外的每个结果都带有 code 和 message,其中会指出字段。消息绝不包含凭据密钥;它可能重复你提供的令牌,例如设备类型令牌。导入绝不会为已存在的设备添加凭据;请使用凭据自身的创建来完成。
通过 GraphQL
mutation Import($rows: [DeviceImportRow!]!) {
importDevices(rows: $rows, mode: NONE, dryRun: true) {
created exists conflict invalid refused
rows { row token outcome code message }
}
}
{ "rows": [
{ "token": "sensor-001", "deviceTypeToken": "thermostat", "name": "Boiler room" },
{ "token": "sensor-002", "deviceTypeToken": "thermostat", "externalId": "SN-20413" }
] }
- 一次调用最多 1000 行;超过则整个调用以
LIMIT_EXCEEDED失败。更大的文件请拆成多次调用,依次发送。 row是该行在本次调用中的位置,从 1 开始。dryRun: true用与真实调用相同的代码判定每一行,并且不写入任何内容,所以一次无问题的试运行就是可靠的预览。- 与某一行无关的失败(例如数据库变得不可用)会使调用以错误失败。此前已创建的行是真实存在的;再次发送相同的行,它们会报告
EXISTS。 - 需要
device:write权限,与创建设备相同。