Skip to content

TC4 自定义:Agent JSON 配置参考 ​

这份文档用于根据真实设备资料生成可由 HiBean 导入的 JSON。面向人的准备、导入和验证操作见使用指南。

核对基线:2026-10-19,App 源码版本 1.5.4+189,提交 d12c9d07bc61e9d2e908f9e718bfd78301b6e3f6。这是源码合同基线,不表示该版本已向所有用户发布。profileVersion: 1、schemaVersion: 2 是文件格式版本,与 App 版本独立。

Agent 工作流程与交付 ​

  1. 获取设备型号、固件版本、用户平台和连接方式;优先阅读固件源码、制造商协议、实际 GATT 服务与特征、串口参数和原始收发记录。不要仅凭设备名称或其他设备的配置猜协议。
  2. 确认读取指令、发送结束符、回复结束符、一条完整原始回复以及各字段含义和单位。温度应为摄氏度;当前自定义设备按摄氏度解释温度,JSON 没有换算能力。
  3. 若需要设备控制,还要确认每个控制的指令模板、取值范围、步长、安全值及对应状态回读。安全值由设备协议和操作条件决定,不能默认“0 一定安全”。
  4. 缺少必要事实时,列出具体问题或需要采集的原始记录;不要输出声称可直接使用的猜测配置。若用户只需测温,可用 actuators: {};若用户要求控制,不要静默删掉控制能力。
  5. 只使用以下白名单字段生成 UTF-8 .json,文件不超过 1 MiB。不要包含注释、尾随逗号或 Markdown 围栏。不要把占位地址交付为已完成配置。
  6. 另附简短说明:每项关键参数的来源、尚未确认的事实、验证状态,以及人的下一步操作。说明留在 JSON 外。人导入后仍需连接、连续读取、控制验证(如启用)、手动记录参数和保存。

必须区分三种结论:导入器校验通过只证明字段合同;实机读取通过证明连接和状态解析;实机控制验证通过还需目标回读和安全回读。导入文件不会携带或替代验证证明,也不会自动创建设备。

文件外层与 config ​

所有对象均拒绝未知字段。下表标为必填的字段不能省略,不接受用 null 代替。

路径类型 / 值规则
kindstring必填,固定 hibean.tc4.custom.profile
profileVersioninteger必填,固定 1
configobject必填,只含下列七项
config.schemaVersioninteger必填,固定 2
config.transportTypestring必填,socket / websocket / classic_bluetooth / ble / serial
config.transportobject必填,与连接方式匹配,见下表
config.initializationCommandsstring[]必填,无初始化时 [];每项非空,不带 CR/LF
config.statusPollingobject必填,见读取合同
config.actuatorCommandSeparatorstring必填,"\n" / "\r" / "\r\n"
config.actuatorsobject必填,无设备控制时 {}

使用 JSON 数字和布尔值,不要写字符串 "1000" 或 "true"。整数建议写整数形式。没有 name、id、description、platform、recordProfile、proofs 或 testValue 字段。设备连接目标的 identifier 属于 transport,与 App 保存设备时分配的身份不同。

transport 合同 ​

每种连接只允许本行列出的键。除明确可选外均必填;字符串去除首尾空白后必须非空。

transportTypetransport 字段约束
sockethost: string;port: integer原始 TCP;端口 1–65535,host 不写 URL scheme
websockethost: string;port: integer;websocketPath: string端口 1–65535;路径以 / 开头;当前实现仅端口 443 使用 wss,其他端口使用 ws
classic_bluetoothidentifier: string当前平台实际选择到的经典蓝牙目标
bleidentifier, serviceUuid, writeCharacteristicUuid: string;可选 notifyCharacteristicUuid: string使用实际扫描/GATT 资料;可选值不用时省略,不填空字符串
serialportName: string;connectionParams: object当前系统实际串口名;参数见下表

没有 URL、认证 header、TLS 开关、BLE 写入模式、MTU 或分包参数字段。BLE 标识可能是 iOS UUID 或其他平台的蓝牙地址,不能承诺跨平台复用。服务 UUID 与特征 UUID 不可混用。

BLE 接收依赖通知订阅,没有 characteristic Read 回退。JSON 允许省略 notifyCharacteristicUuid 不代表任意设备都可不配置通知;应确认 App 能选到实际可通知的特征。当前写入优先设置为 preferWriteWithoutResponse=false,仅支持无响应写入的设备不能靠添加 JSON 字段获得兼容性。

平台允许的向导连接方式:Android 支持除串口外的四种;iOS 支持 BLE、TCP、WebSocket;macOS / Windows 支持五种;Linux 不支持此向导。这不是驱动或硬件兼容性保证。

serial.connectionParams ​

字段类型约束
baudRateinteger必填,正整数
dataBitsinteger必填,5–8
stopBitsinteger必填,1 或 2
paritystring必填,none / even / odd / mark / space
flowControlstring必填,none / xonxoff / rtscts / dtrdsr
timeoutSecondsnumber可选,有限正数;串口参数,不是状态帧等待超时

初始化、读取与分帧 ​

statusPolling 必须且只能包含以下四项:

字段类型约束
commandstring非空,不带 CR/LF;必须来自设备协议
intervalMillisinteger至少 1000 毫秒
messageSeparatorstring只能是 "\n" / "\r" / "\r\n"
fieldsobject[]非空;每项只有 signal、type、index

actuatorCommandSeparator 虽以 actuator 命名,实际用于所有发出的初始化、读取和控制指令。接收用 messageSeparator,两者可不同。JSON "\n" 解码后是换行;"\\n" 是字面反斜杠和 n,不能用作结束符。不要再把结束符附在 command / commandTemplate / 初始化指令中。

“连接设备”阶段只建立连接及必要的 GATT 选择;进入状态读取验证时才按顺序发送初始化指令,然后读取样本及基线。没有可配置的初始化 ACK、延迟或自动单位切换指令;需要 UNITS;C 等指令时,必须有对应固件依据后再放入初始化数组。

TCP、BLE、经典蓝牙、串口等待完整结束符;当前帧读取超时为 5 秒,缓冲上限为 64 Ki 字符。WebSocket 完整消息可直接成为一帧,即使未附结束符,但 JSON 的 messageSeparator 仍必填。状态解析取第一个非空帧,固定以逗号拆分,去掉字段两端空白;空字段仍占索引位置,映射到空字段会失败。

fields 与信号 ​

index 是从 0 开始的整数,范围 0–255;同一索引或同一 signal 不能重复。只映射需要的字段,忽略字段时保留其他字段的原始索引。每项 type 只能是 double 或 integer,不是 int。

signal用途类型约束
bean_temperature豆温 BT必须映射;通常 double
environment_temperature环境温度 ET通常 double
inlet_temperature进风温度通常 double
heater_power火力回读控制时建议 integer
fan_speed风机回读控制时建议 integer
drum_speed滚筒回读控制时建议 integer
target_temperature目标温度回读必须 integer;没有对应目标温度控制项
cooling_fan_switch冷却风机回读控制时建议 integer

没有 unknown 信号;未映射的字段不写入数组。数据必须可解析为有限数字,不能带 °C 或 % 后缀。integer 要求数学上为整数(例如 180.0 可解析)。没有字段分隔符、倍率、偏移、正则、公式或温度单位换算字段;固件输出不符合时,需要调整设备协议或另做适配,不能靠杜撰 JSON 字段解决。

actuators 与验证 ​

只允许 heater、fan、drum、coolingFan 四个键,注意最后一个为驼峰命名。没有控制时用 {};不需要的控制建议省略。

每个控制项的字段类型约束
enabledboolean必填
modestring必填,range 或 toggle
commandTemplatestring必填;启用时非空、含精确占位符 {value}、无 CR/LF
safeValueinteger必填;启用时必须为合法安全值
rangeobjectrange 模式必填,只含整数 min、max、step;toggle 模式省略

启用的 range 控制要求 min < max、step > 0、(max-min) % step == 0;安全值在范围内且 (safeValue-min) % step == 0。启用的 toggle 控制只取 0/1,安全值也只能 0/1。coolingFan 启用时只能使用 toggle。模板将 {value} 替换为整数,不支持通用模板表达式。

禁用项也必须满足对象结构和类型;例如禁用的 range 项仍需提供 range 对象,且 step 仍须为正整数。优先省略不需要的项,以免携带无意义的占位配置。

启用的控制必须映射的状态信号
heaterheater_power
fanfan_speed
drumdrum_speed
coolingFancooling_fan_switch

控制回读必须是整数值且符合其范围、步长或开关限制,基线读取也执行这些检查。温度变化不能替代火力回读。

先通过三次连续读取,再由人选择合法且不同于安全值的测试值:写入测试值 → 读取对应状态并匹配 → 写入安全值 → 读取安全状态并匹配。测试值不属于 JSON。读到了明确但不匹配的目标值时,会尝试恢复安全值后判失败;若写入或读取结果不确定,会关闭/作废会话,不盲目补发第二条指令。安全回读失败意味着安全状态未确认。

“手动记录参数”只决定烘焙中人工记录的项目,不是设备控制,不属于可移植 JSON。JSON 也不包含自动测试、PID 或自动冷却流程。

完整示例与下载 ​

以下均为说明合同的虚构示例,不是某个用户的已验证配置。地址、UUID、READ、OT1 都不是通用默认值。Agent 必须先替换成实际设备资料,才能交付给用户尝试导入。

只读取豆温:TCP ​

假设设备在 TCP 收到 READ 加 LF 后回复 180.5 加 LF,第 0 列是摄氏豆温,不启用设备控制。

json
{
  "kind": "hibean.tc4.custom.profile",
  "profileVersion": 1,
  "config": {
    "schemaVersion": 2,
    "transportType": "socket",
    "transport": {
      "host": "192.0.2.10",
      "port": 4000
    },
    "initializationCommands": [],
    "statusPolling": {
      "command": "READ",
      "intervalMillis": 1000,
      "messageSeparator": "\n",
      "fields": [
        {
          "signal": "bean_temperature",
          "type": "double",
          "index": 0
        }
      ]
    },
    "actuatorCommandSeparator": "\n",
    "actuators": {}
  }
}

读取豆温并控制火力:TCP ​

额外假设:回复为 180.5,0 加 LF;第 1 列为整数火力;OT1;整数 加 LF 设置火力,范围 0–100、步长 1;制造商确认当前操作条件下 0 为安全值。缺少任何一项依据就不能沿用该控制示例。

json
{
  "kind": "hibean.tc4.custom.profile",
  "profileVersion": 1,
  "config": {
    "schemaVersion": 2,
    "transportType": "socket",
    "transport": {
      "host": "192.0.2.10",
      "port": 4000
    },
    "initializationCommands": [],
    "statusPolling": {
      "command": "READ",
      "intervalMillis": 1000,
      "messageSeparator": "\n",
      "fields": [
        {
          "signal": "bean_temperature",
          "type": "double",
          "index": 0
        },
        {
          "signal": "heater_power",
          "type": "integer",
          "index": 1
        }
      ]
    },
    "actuatorCommandSeparator": "\n",
    "actuators": {
      "heater": {
        "enabled": true,
        "mode": "range",
        "commandTemplate": "OT1;{value}",
        "safeValue": 0,
        "range": {
          "min": 0,
          "max": 100,
          "step": 1
        }
      }
    }
  }
}

其余只读示例均沿用上述 READ / 摄氏豆温 / LF 假设,仅替换连接方式。WebSocket 示例路径 /ws、串口示例 115200/8/N/1/无流控、BLE 示例 FFE0 服务 / FFE2 写入 / FFE1 通知,都只是演示值。

排查与维护依据 ​

失败位置优先检查
导入失败文件外层、格式版本、未知键、数据类型、字段索引重复、必需 BT、控制回读映射
连接失败目标平台支持、地址端口、串口权限、蓝牙目标、服务与特征 UUID
能连接但读不到初始化时机、READ 是否真是设备指令、发出结束符、通知订阅、回复结束符
读到了但解析失败第一帧是否为 ACK 而非状态、逗号字段位置、数字单位/缩放、integer 类型
控制验证失败指令及回读是否为同一物理量、范围步长、设备是否执行、目标与安全回读

旧指南的主要修正:从空 config 示意补全为可导入的字段合同;初始化从“连接时发送”修正为读取验证阶段;明确固定逗号解析与 BLE 通知要求;说明发出结束符同时用于 READ 和初始化;补齐手动记录参数步骤,并区分导入校验与实机验证。

维护时从以下 App 源码重新核对,不以示例推导新能力:

  • lib/model/manufacture/tc4/custom/tc4_custom_profile.dart — Tc4CustomProfileCodec / Tc4CustomConfigJsonCodec

  • lib/model/manufacture/tc4/custom/tc4_custom_models.dart — enums / Tc4CustomConfigValidator

  • lib/model/manufacture/tc4/custom/tc4_text_protocol.dart — framing / parsing / readback

  • lib/model/manufacture/tc4/custom/tc4_custom_tester.dart — transport / initialization / writes

  • lib/model/manufacture/tc4/custom/onboarding/tc4_setup_controller.dart — platform / baseline / proof

  • lib/model/manufacture/tc4/custom/onboarding/tc4_custom_provisioner.dart — save

  • lib/page/discovery/tc4/tc4_custom_setup_v2_page.dart — workflow / manual recording

  • lib/model/manufacture/manufacture_constants.dart — default Celsius policy

  • lib/model/manufacture/tc4/custom/tc4_custom_roaster.dart — runtime state publication

  • lib/model/persistence/serial_port_enums.dart — serial enum values

  • lib/model/manufacture/tc4/custom/tc4_custom_profile_file_service.dart — UTF-8 / file size