Skip to content

指令 Command

指令是下发给设备的一次动作请求——重启、校准、切换模式、设定温度……定义归属模板 Profile ,调用归属设备,带一组输入/输出参数,由驱动执行后回执结果。

指令回答的是"让设备做一件事",它是事件的对偶:事件上行(设备说"发生了什么"),指令下行(平台说"去做什么")。

它是什么、为什么需要

工业设备除了"上报数值"和"被读写某个量",还需要被触发动作型能力:重启、固件升级、模式切换、按模板下发一段配置。这些动作往往带参数、需要回执、要做超时与审计——把它们建模成 Profile 下的结构化子资源,就是指令 Command。定义沉淀在模板里(这类设备能做哪些动作、每个动作收哪些参数),调用落到具体设备实例(某台设备某时刻执行了一次)。

最关键的区分:两类下行不要混淆

DC3 有两条独立的下行链路,初学者最容易混淆:

维度写位号 PointCommand自定义指令 Command / CommandCall
改什么某一个量(一个 Point 的值)触发一个带参数的动作
定义来源PointrwFlag 含 WRITEdc3_command 独立定义表
驱动接口DriverCustomService.write()DriverCommand.execute()
参数单值(一个目标值)结构化输入/输出参数 Map
DTOPointCommandDTOCommandCallDTO / CommandCallResultDTO
队列前缀dc3.e.point_commanddc3.e.command

一句话边界(见设计稿 point-command.md §1.2):写位号是属性维度的运行态访问,自定义指令是模板层的动作能力。

一个例子讲清边界

给空调"把目标温度设为 26℃"——这是写位号targetTemp 是一个可写 Point,写入 26 即可,本质是改一个量。 给空调"执行一次自清洁"——这是自定义指令 selfClean:它不对应某个量,而是一个动作,可能还带参数(如 duration=30),执行完返回 resultCode。 判断口诀:能落到"改某个 Point 的值"就是写位号;是"触发一段动作流程"就是指令。

本页讲的"指令 Command"指自定义指令。写位号请看 位号 Point

关键字段

指令定义 CommandBO(归属 Profile,表 dc3_command):

字段类型含义
commandNameString指令名称(展示用)
commandCodeString指令标识符,同一 profileId 下唯一,调用时按它匹配(如 setTemperature
commandTypeFlagCommandTypeEnum指令类型,见下
callTypeFlagCallTypeEnum调用方式:sync / async
timeoutInteger调用超时时间(秒)
commandExtCommandExt扩展配置(协议映射、驱动指令模板、幂等等)
profileIdLong归属的模板
enableFlagEnableFlagEnum启停状态
tenantIdLong归属租户

指令参数 CommandParamBO(声明指令的输入/输出参数,归属指令定义):

字段类型含义
paramName / paramCodeString参数名 / 标识符
paramDirectionFlagParamDirectionTypeEnum方向:input(入参)/ output(出参)
paramTypeFlagPointTypeEnum参数数据类型
requiredFlagBoolean是否必填
defaultValueString默认值
commandIdLong归属的指令定义

CommandParam 复用位号的类型系统

paramTypeFlag 用的是和位号一样的 PointTypeEnumSTRING / INT / FLOAT / DOUBLE / BOOLEAN…)。注意区分:入参 是调用时由调用方传入(如 temperature),出参是执行后由设备回写(如 resultCode)。

调用入参 CommandCallBO(一次调用的提交体):deviceIdcommandIdcommandCodeparamValuesMap<String,String>,按参数 paramCode 键控)。

指令类型

类型 commandTypeFlag说明
custom自定义指令
config配置型指令
action动作型指令

与其它概念的关系

1:N 指令定义挂模板1N1:N 输入/输出参数1NcommandId 匹配定义提交 → 落记录 PENDINGdeviceId 发起调用模板 PROFILE · dc3_profileidPKprofileName · profileCodeversion指令 COMMAND · dc3_commandidPKcommandName · commandCodeUKcommandTypeFlag (custom/config/action)callTypeFlag (sync/async)timeout(秒)commandExt(协议映射·幂等)enableFlagprofileIdFKtenantIdFK指令参数 COMMAND_PARAMidPKparamName · paramCodeparamDirectionFlag (in/out)paramTypeFlag(复用 PointTypeEnum)requiredFlag · defaultValuecommandIdFK调用提交 COMMAND_CALLdeviceIdFKcommandId · commandCodeparamValues Map<String,String>source · expireAt调用记录 COMMAND_HISTORYrecordIdPKdeviceId · commandIdFKstatus(0..7 状态机)errorCode · finishedAt设备 DEVICE(引用)id · deviceNameprofileIdFKenableFlag两类下行不要混淆写位号 PointCommand — 改一个量· DriverCustomService.write()· 队列 dc3.e.point_command自定义指令 Command — 带参数动作· DriverCommand.execute()· 队列 dc3.e.commandPKPK 主键FKFK 外键UKUK 唯一键1:N 一对多调用发起(虚线)对比注记(虚线框)
  • 指令定义挂在模板下,与位号事件并列,共同描述"这类设备有什么能力"。
  • 指令调用设备发起;驱动执行所需的协议映射由 指令属性配置CommandConfig )提供,与业务参数 CommandParam 分属两层。

调用生命周期与回执

一次调用(CommandCallDTO)携带:recordIdtenantIddeviceIdcommandIdcommandCodeparamValuessourceoccurredAtexpireAt。数据中心持久化为一条 dc3_command_history 记录(PENDING),投递到 RabbitMQ,驱动执行后回执 CommandCallResultDTOstatusresultValueserrorCodeerrorMessagefinishedAt)。

调用方 Caller数据中心 Center消息总线 RabbitMQ驱动 Driver设备 Device提交发布 SENT消费协议报文执行结果回执写回轮询可查① 提交调用POST /data/command_history/callCommandCallBO · 返回 recordId② 受理校验校验设备 profileId 含该指令落 dc3_command_history · PENDING③ 投递队列dc3.e.command状态 SENT · TTL 30s④ 驱动消费每设备串行锁 · 去重DriverCommand.execute()⑤ 设备执行渲染协议报文下发执行 · 超时 · 失败⑥ 执行回执CommandCallResultDTOstatus · resultValues · errorCode⑦ result 队列回执交换机 · TTL 60s⑧ 记录推进按 recordId 回写终态SUCCESS / FAILED / EXPIRED…⑨ 轮询终态GET get_by_record_id以回执 status 为准sync ≠ 调用即完成/call 只返回 recordId是否做完看回执 status泳道(参与方)指令下行(实线)回执链路(虚线)同步语义注记

调用状态机(PointCommandStatusEnum,与写位号共用):

PENDING → SENT → SUCCESS / FAILED / TIMEOUT / EXPIRED / DUPLICATE / DEAD
状态含义
PENDING已创建记录,等待投递
SENT已投递到 RabbitMQ,等待驱动执行
SUCCESS / FAILED驱动执行成功 / 失败,结果已回写
TIMEOUT / EXPIRED应用层超时 / expireAt 已过期未执行
DUPLICATE / DEAD重复命令被去重拦截 / 拒入死信队列

同步指令不等于"调用即完成"

callTypeFlag = sync 只表示调用方愿意等回执,不代表 HTTP 立即返回执行结果。当前 /call 返回 recordId,调用方据此轮询 get_by_record_id 拿终态。是否真正"做完"以回执里的 status 为准,别凭 HTTP 200 就认为设备已执行。

示例

空调的模板里定义一个指令:commandCode = setTemperaturecommandTypeFlag = actioncallTypeFlag = synctimeout = 10,带一个输入参数 temperatureparamDirectionFlag = inputparamTypeFlag = DOUBLErequiredFlag = true )和一个输出参数 resultCodeoutputSTRING)。

调用时提交 CommandCallBO{ deviceId: 1001, commandCode: "setTemperature", paramValues: { temperature: "26" } }。数据中心校验设备 profileId 是否包含该指令,落一条 dc3_command_history(PENDING→SENT),投递给驱动;驱动 execute() 渲染协议报文下发到空调,回执 CommandCallResultDTO{ status: SUCCESS, resultValues: { resultCode: "OK" } },记录推进到 SUCCESS。

API

数据中心服务挂载于 /data

方法路径说明
POST/data/command_history/call下发自定义指令,返回 recordId
GET/data/command_history/get_by_record_idrecordId 查询调用记录详情与终态
POST/data/command_history/list分页查询调用记录

延伸阅读

基于 AGPL-3.0 协议发布