CoAP 驱动
dc3-driver-coap 把 CoAP 设备接入 IoT DC3。它基于 Eclipse Californium,既能作为 CoAP 客户端主动连设备(读发 GET、写发 PUT),也能作为 CoAP 服务端监听设备主动 POST 上报的遥测。读完你能在设备上配好 deviceHost/devicePort、在位号上配好读写资源路径,并定位常见的"采不到值 / UDP 连不通" 问题。
你在这里:网络层"轻协议侧"的一个落地驱动。CoAP 在协议层的请求/响应模型、UDP/DTLS 端口、Observe 概念见IoT 协议与无线网络。
协议背景
CoAP(Constrained Application Protocol,受限应用协议)是 IETF 为低功耗、低带宽的物联网终端设计的轻量协议(RFC 7252)。它保留了 HTTP 熟悉的请求/响应 + 方法(GET/PUT/POST/DELETE)+ 资源路径模型,但把报文压到几十字节,跑在 UDP 上、默认端口 5683 (加密用 DTLS 的 CoAPS 走 5684)。无连接的 UDP 省去了 TCP 握手与保活开销,对电池供电、偶尔醒来上报一次的终端极友好;代价是可靠性要靠 CoAP 自己的 CON/NON 确认机制补回来。常见于电池供电的传感器、嵌入式网关、NB-IoT/6LoWPAN 终端等"省电省流量"的场景。
在物联网四层架构里,CoAP 属于网络层的应用层消息协议:它定义" 一条消息长什么样、怎么投递、可靠到什么程度",与底层用什么无线无关——同一个 CoAP 报文,可以跑在 Wi-Fi 上,也可以跑在 NB-IoT 蜂窝链路上。CoAP 的通信模型既支持客户端主动请求资源,也支持服务端在客户端 POST 时被动接收,本驱动两侧都实现了:
客户端模式是默认形态,由 IoT DC3 的采集调度按 cron 周期对每个位号的 readPath 发 GET,下发写命令时对 writePath 发 PUT。服务端模式则反过来:驱动监听一个 CoAP 端口,设备主动把遥测 POST 到 /data 资源,驱动解析后转发上报。两种模式由 dc3.driver.coap.mode 决定(见下文属性配置)。
属性配置
接入一台 CoAP 设备,主要在两个层面填属性:设备级的连接参数(driver-attribute )和每个位号的资源路径(point-attribute)。此外驱动还暴露一组进程级的 dc3.driver.coap.* Spring 配置项(控制客户端/服务端模式、超时、DTLS),它们不在设备配置里,而是运维通过环境/配置文件调。下面各属性、类型、默认值均取自驱动的 application.yml 与 CoapProperties(dc3-driver-coap 模块)。
驱动属性(设备级 driver-attribute)
驱动属性回答"连到哪台设备"。在设备上为每台 CoAP 设备填一组:
| 属性 | code | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| Device Host | deviceHost | STRING | localhost | CoAP 设备主机地址(IP 或主机名) |
| Device Port | devicePort | INT | 5683 | CoAP 设备端口(标准 5683) |
驱动用这两个属性拼出设备根地址 coap://<deviceHost>:<devicePort>,再接上位号的资源路径访问具体资源。驱动按设备根地址(URI)缓存 CoapClient(一个 URI 一个客户端),设备被删除或更新时释放对应客户端。配置校验(validate)会要求 deviceHost、devicePort 两项都非空,缺一即报错、设备无法启动。
位号属性(point-attribute)
位号属性回答"读写这台设备的哪个资源路径"。每个位号填一组:
| 属性 | code | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| Read Path | readPath | STRING | /sensors | 采集时 GET 的 CoAP 资源路径 |
| Write Path | writePath | STRING | /actuators | 下发写值时 PUT 的 CoAP 资源路径 |
| Content Format | contentFormat | STRING | json | 内容格式声明:json / text / cbor / octet-stream |
读写各走各的资源路径
采集时驱动对 coap://<host>:<port><readPath> 发 GET,返回的响应体(payload)就是这个位号 的位号值;下发写命令时对 <writePath> 发 PUT,请求体是要写的值。readPath 和 writePath 互不影响,只读位号只配 readPath 即可,writePath 空着不会被用到。位号配置校验(validatePoint)只强制要求 readPath 非空。
CoAP 没有独立的 command-attribute 配置表——可写位号的写入目标由位号自身的 writePath 决定,下发写命令时驱动直接对该路径发 PUT,无需额外的命令属性。
进程级配置(dc3.driver.coap.*)
这组配置控制驱动进程整体行为(客户端超时、是否起服务端、DTLS 加密),通过配置文件或环境变量设置,对所有设备生效。 application.yml 里未显式列出,因此默认全部取 CoapProperties 的内置默认值:
| 配置项 | 默认值 | 说明 |
|---|---|---|
mode | CLIENT | 工作模式:CLIENT(仅客户端,主动读写)/ SERVER(仅服务端,监听上报)/ BOTH |
serverHost | 0.0.0.0 | 服务端绑定地址(SERVER/BOTH 模式生效) |
serverPort | 5683 | 服务端监听端口(SERVER/BOTH 模式生效) |
secureEnabled | false | 是否启用 DTLS 加密 |
clientTimeout | 5000 | 客户端 GET 的报文交换生命周期(毫秒,最小 100) |
clientAckTimeout | 2000 | 客户端 CON 确认超时(毫秒,最小 100) |
clientMaxRetransmit | 4 | 客户端最大重传次数(最小 1) |
dtls.* | 空 | DTLS 凭据:pskIdentity / pskSecret 或证书路径 trustStorePath / identityCertificatePath / identityPrivateKeyPath |
默认即客户端模式,服务端模式需显式开
默认 mode=CLIENT,驱动作为客户端按 cron 周期主动 GET/PUT,不监听任何端口。要让设备主动 POST 上报,需把 mode 设为 SERVER 或 BOTH——此时驱动起一个 CoAP 服务端、在 serverPort 上注册 /data 资源接收上报。secureEnabled/dtls.* 是为 DTLS 预留的配置项,当前 CoapClientManager 与 CoapServerManager 建连时尚未据它装配 DTLS 端点(明文 UDP),公网加密能力以代码为准。
故障排查
CoAP 接入失败大多集中在 UDP 链路、资源路径、上报格式三类。按下面顺序排查:
UDP 连不通(采不到值 /
statusCode=timeout)。CoAP 默认走 UDP 5683(不是 TCP)。设备无响应时,客户端 GET 超时返回null,read按失败处理、跳过本轮并打CoAP read failed ... statusCode=timeout。先用 CoAP 客户端(如coap-client -m get coap://<host>:5683<readPath>)手动验链路:确认设备在线、防火墙放行 UDP 5683、deviceHost/devicePort填对,而不是先怀疑路径配错。能连上但路径取不到(4.04 Not Found)。
readPath写错会让设备返回4.04,此时response.isSuccess()为 false、read同样返回null。核对资源路径大小写与前导/,必要时先 GET 设备的/.well-known/core看它实际暴露了哪些资源。响应慢于超时被误判。客户端默认
clientTimeout=5000ms、clientAckTimeout=2000ms、最大重传4次。链路 RTT 高(如蜂窝/NB-IoT)的设备可能在默认窗口内来不及应答而被判超时——调大dc3.driver.coap.clientTimeout/clientAckTimeout,而不是缩短采集周期。写命令返回失败。写走 PUT 到
writePath,请求体为命令传入的值。失败(PUT 超时或设备返回非 2.xx)时write返回false、写命令不回显。先确认writePath是设备上可写的资源、且设备接受 PUT 方法。注意:驱动 PUT 固定以application/json媒体类型发送,与位号的contentFormat声明无关(见下方易错点)。服务端模式收不到上报。
mode必须为SERVER或BOTH,设备要 POST 到coap://<驱动host>:<serverPort>/data。上报体必须是能反序列化成PointValue的 JSON(至少含deviceId、pointId),否则驱动打missingIdentity/parse failed并丢弃。空 body 会被回4.00 Bad Request。设备在线状态抖动。健康检查默认每 15 秒一次、租约超时 45 秒。频繁 online/offline 跳变多半是 UDP 丢包或设备响应慢于超时——在线状态机制见设备。
contentFormat 只是声明,当前不参与解析
contentFormat 声明资源的内容格式(json / text / cbor / octet-stream),但当前驱动按原始 payload( response.getResponseText())直接返回位号值、未据它做格式解析;写方向也固定用 application/json 媒体类型 PUT,不读这个属性。拿不准设备实际返回格式时,先用 CoAP 客户端手动 GET 一次看返回内容再填。
在 IoT DC3 中如何落地
dc3.driver.code:CoapDriver(类型DRIVER_CLIENT)。这是稳定的路由标识,不要随意改。- 读能力:✓ 已实现。客户端模式按 cron 对每个位号的
readPath发 GET,响应体作为位号值上报。 - 写能力:✓ 已实现。对位号的
writePath发 PUT(application/json),下发命令时触发。 - 订阅/上报:— 不计入驱动能力矩阵的"订阅"列。矩阵中 CoAP 为「✓ / ✓ / —」,指的是 SDK 位号模型下的主动读 / 主动写 / 无订阅。CoAP 的 Observe(RFC 7641,资源变化推送)在本驱动里尚未接通:仅有
CoapObserveHandler接口定义,无任何实现或调用方。 - 服务端上报(额外能力):
SERVER/BOTH模式下驱动起 CoAP 服务端、在/data接收设备 POST 的PointValueJSON 并转发上报。这是矩阵之外的一条独立链路,需显式开mode。 - 采集周期:默认 cron
0/30 * * * * ?(每 30 秒采一轮),在驱动application.yml的schedule.read配置。schedule.custom(默认 cron0/5 * * * * ?)虽启用,但schedule()实现为空操作,不做位号采集之外的周期逻辑。 - 健康/在线:设备健康检查默认 cron
0/15 * * * * ?,租约超时45 秒。
实现状态:可用(客户端读写 + 服务端上报),Observe 未实现
本驱动的客户端读写与服务端上报接收均为完整实现(非骨架),底层基于 Eclipse Californium。唯一未接通的是 CoAP * Observe* 订阅推送:CoapObserveHandler 仅是接口、无实现,因此驱动当前不能"订阅"资源由设备变更推送——需要事件驱动上报的场景请改用服务端 POST 模式。DTLS 加密(secureEnabled/dtls.*)为配置预留、尚未在建连时装配,以代码为准。
最小接入示例
把地址 192.168.1.20:5683、温度资源在 /temp 的一台 CoAP 传感器接进来:
- 选
CoAP Driver创建设备,driver 属性填deviceHost=192.168.1.20、devicePort=5683。 - 给设备绑定的模板加一个温度位号(
READ_ONLY),point 属性填readPath=/temp、contentFormat=json(writePath留空)。 - 启动驱动,30 秒内就能在位号值里看到对
coap://192.168.1.20:5683/tempGET 回来的值。 - 若该位号需可写,给它配写命令、并填
writePath,下发时驱动对该路径 PUT。
设备主动上报选服务端模式
若设备只会偶尔醒来主动上报、不接受被轮询,把 dc3.driver.coap.mode 设为 SERVER,让设备 POST 到驱动的 /data 资源(上报体为含 deviceId/pointId 的 PointValue JSON)。这避免了对休眠设备做无谓的周期 GET。
延伸阅读
- 驱动总览 — 全部驱动入口与分类
- 驱动能力矩阵 — 读/写/订阅能力一览,含 CoAP 行
- 设备接入 — 一次完整的接入流程
- IoT 协议与无线网络 — CoAP/LwM2M 等轻协议的请求/响应模型、UDP/DTLS 与 Observe
- LwM2M 驱动 — 架在 CoAP 之上、带设备管理对象模型的驱动