HarmonyOS APP开发---"绿管家"智能植物监测App,需要用到这个库
想做一个植物监测 App,让花盆里的温湿度传感器把数据实时推到手机上?传感器跑在低功耗 MCU 上,HTTP 太重,MQTT 又嫌多余------CoAP 才是 IoT 的"母语",而
@ohos/coap让鸿蒙手机说上了这门母语。
📦 仓库地址:https://gitcode.com/CPF-ApplicationTPC/ohos_coap | 安装:ohpm install @ohos/coap
写在前面
"绿管家"的核心场景很朴素:花盆里插一个 ESP32 温湿度传感器,每 30 秒把数据推到手机 App 上。传感器电池供电、带宽极低、网络不稳定。
这时候 HTTP + JSON 的方案就"杀鸡用牛刀"了------TCP 三次握手、header 动辄几百字节、keep-alive 吃连接。CoAP(受限应用协议) 基于 UDP,报文头才 4 字节,复用 REST 语义,是 IETF 专为受限设备设计的轻量协议。
但 libcoap 是 C 库,在 ArkTS 里用得写 NAPI 桥接。@ohos/coap 把这些活全干了------客户端发起请求,服务端注册处理器,全用 ArkTS。
这篇文章聊什么
- CoAP 客户端------手机向传感器发起 GET 请求拉取温湿度
- CoAP 服务端------手机作为服务端,接收传感器推送的数据
- 块传输------传感器固件升级时,大包数据怎么分块传
#mermaid-svg-CM66sC5bZoMTfaGw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CM66sC5bZoMTfaGw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CM66sC5bZoMTfaGw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CM66sC5bZoMTfaGw .error-icon{fill:#552222;}#mermaid-svg-CM66sC5bZoMTfaGw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CM66sC5bZoMTfaGw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CM66sC5bZoMTfaGw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CM66sC5bZoMTfaGw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CM66sC5bZoMTfaGw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CM66sC5bZoMTfaGw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CM66sC5bZoMTfaGw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CM66sC5bZoMTfaGw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CM66sC5bZoMTfaGw .marker.cross{stroke:#333333;}#mermaid-svg-CM66sC5bZoMTfaGw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CM66sC5bZoMTfaGw p{margin:0;}#mermaid-svg-CM66sC5bZoMTfaGw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CM66sC5bZoMTfaGw .cluster-label text{fill:#333;}#mermaid-svg-CM66sC5bZoMTfaGw .cluster-label span{color:#333;}#mermaid-svg-CM66sC5bZoMTfaGw .cluster-label span p{background-color:transparent;}#mermaid-svg-CM66sC5bZoMTfaGw .label text,#mermaid-svg-CM66sC5bZoMTfaGw span{fill:#333;color:#333;}#mermaid-svg-CM66sC5bZoMTfaGw .node rect,#mermaid-svg-CM66sC5bZoMTfaGw .node circle,#mermaid-svg-CM66sC5bZoMTfaGw .node ellipse,#mermaid-svg-CM66sC5bZoMTfaGw .node polygon,#mermaid-svg-CM66sC5bZoMTfaGw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CM66sC5bZoMTfaGw .rough-node .label text,#mermaid-svg-CM66sC5bZoMTfaGw .node .label text,#mermaid-svg-CM66sC5bZoMTfaGw .image-shape .label,#mermaid-svg-CM66sC5bZoMTfaGw .icon-shape .label{text-anchor:middle;}#mermaid-svg-CM66sC5bZoMTfaGw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CM66sC5bZoMTfaGw .rough-node .label,#mermaid-svg-CM66sC5bZoMTfaGw .node .label,#mermaid-svg-CM66sC5bZoMTfaGw .image-shape .label,#mermaid-svg-CM66sC5bZoMTfaGw .icon-shape .label{text-align:center;}#mermaid-svg-CM66sC5bZoMTfaGw .node.clickable{cursor:pointer;}#mermaid-svg-CM66sC5bZoMTfaGw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CM66sC5bZoMTfaGw .arrowheadPath{fill:#333333;}#mermaid-svg-CM66sC5bZoMTfaGw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CM66sC5bZoMTfaGw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CM66sC5bZoMTfaGw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CM66sC5bZoMTfaGw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CM66sC5bZoMTfaGw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CM66sC5bZoMTfaGw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CM66sC5bZoMTfaGw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CM66sC5bZoMTfaGw .cluster text{fill:#333;}#mermaid-svg-CM66sC5bZoMTfaGw .cluster span{color:#333;}#mermaid-svg-CM66sC5bZoMTfaGw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CM66sC5bZoMTfaGw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CM66sC5bZoMTfaGw rect.text{fill:none;stroke-width:0;}#mermaid-svg-CM66sC5bZoMTfaGw .icon-shape,#mermaid-svg-CM66sC5bZoMTfaGw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CM66sC5bZoMTfaGw .icon-shape p,#mermaid-svg-CM66sC5bZoMTfaGw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CM66sC5bZoMTfaGw .icon-shape .label rect,#mermaid-svg-CM66sC5bZoMTfaGw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CM66sC5bZoMTfaGw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CM66sC5bZoMTfaGw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CM66sC5bZoMTfaGw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CoAP POST
CoAP GET
传感器 ESP32
手机 App 服务端
注册 handler 接收数据
解析温湿度
更新 UI 曲线
手机 App 客户端
传感器
返回当前状态
第一步:安装与权限
bash
ohpm install @ohos/coap
json
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" },
{ "name": "ohos.permission.GET_NETWORK_INFO" }
]
第二步:客户端------主动拉取传感器数据
手机作为 CoAP 客户端,向传感器发起 GET 请求:
typescript
import {
CoapClient, CoapRequestMethod, CoapRequestType,
CoapResponse, CoapResponseCode, CoapBlockMode
} from '@ohos/coap'
// 每个客户端实例对应一次请求
let client = new CoapClient()
client.setBlockMode(CoapBlockMode.COAP_BLOCK_USE_LIBCOAP)
// 向传感器发起 GET:coap://192.168.1.50:5683/sensor
client.request(
'coap://192.168.1.50:5683/sensor',
CoapRequestMethod.GET,
CoapRequestType.COAP_MESSAGE_CON
).then((data: CoapResponse) => {
if (data.code === CoapResponseCode.SUCCESS) {
// 传感器返回 JSON:{"temp":25.6,"humi":68}
const sensor = JSON.parse(data.message)
console.info(`温度 ${sensor.temp}°C,湿度 ${sensor.humi}%`)
// 更新 UI
}
}).catch((err) => {
console.error('传感器请求失败: ' + JSON.stringify(err))
})
CoAP 的 URI 长得像 HTTP(coap://host:port/path),但底层走 UDP,报文极小,传感器那端实现起来也轻。
第三步:服务端------接收传感器主动推送
传感器也可以主动 POST 数据到手机。手机作为 CoAP 服务端监听:
typescript
import { CoapServer } from '@ohos/coap'
const server = new CoapServer()
// 注册 POST 处理器:传感器推送温湿度
server.handle('sensor/upload', (request) => {
const payload = JSON.parse(request.payload)
console.info(`收到推送: ${payload.temp}°C / ${payload.humi}%`)
// 存入数据库,更新 UI 曲线
saveToHistory(payload)
return { code: '2.01', payload: 'OK' } // Created
})
// 注册 GET 处理器:传感器查询手机端配置
server.handle('config', (request) => {
return {
code: '2.05',
payload: JSON.stringify({ interval: 30, threshold: { temp: 35, humi: 20 } })
}
})
server.start('coap://0.0.0.0:5683')
console.info('CoAP 服务端已启动,等待传感器连接...')
第四步:块传输------传感器固件升级
传感器固件升级包有几十 KB,CoAP 单包放不下。开启块传输,自动分块:
typescript
let otaClient = new CoapClient()
otaClient.setBlockMode(CoapBlockMode.COAP_BLOCK_USE_LIBCOAP)
// 拉取固件(库自动分块重组)
otaClient.request(
'coap://192.168.1.50:5683/firmware',
CoapRequestMethod.GET,
CoapRequestType.COAP_MESSAGE_CON
).then((data) => {
console.info(`固件大小: ${data.message.length} 字节`)
// 写入传感器 OTA 分区
})
为什么"绿管家"选了 CoAP?
| 维度 | HTTP | MQTT | CoAP |
|---|---|---|---|
| 传输层 | TCP(重) | TCP | UDP(轻) |
| 报文头 | 几百字节 | 2 字节 | 4 字节 |
| 模式 | 请求-响应 | 发布-订阅 | 请求-响应 + 推送 |
| 服务端能力 | 需要服务器 | 需要 Broker | 设备即可当服务端 |
| 功耗 | 高 | 中 | 低 |
对于"绿管家"这种局域网内手机直连传感器的场景,CoAP 的优势最明显:不需要中间服务器/Broker,手机和传感器点对点 UDP 通信,延迟低、功耗低。
总结
"绿管家"这个场景里,@ohos/coap 解决了三件事:
- 客户端拉取------手机主动 GET 传感器数据,Promise 风格一目了然
- 服务端接收------手机注册 handler,传感器主动 POST 推送
- 块传输------大固件包自动分块,开发者无感
如果你也在做智能家居、农业监测、工业传感器等 IoT 场景,@ohos/coap 让鸿蒙设备和受限设备之间的通信轻得像呼吸。