通过 RPC 推送告警到钉钉
1. 场景说明
ThinkLink(TKL)平台的 RPC 支持调用外部 HTTP 接口(见 RPC 模型 §1.3.2 类型四),可以把设备告警实时推送到钉钉自定义机器人。本文介绍如何使用钉钉加签机制安全地推送告警消息。
2. 准备工作
2.1 创建钉钉自定义机器人
- 在钉钉群中点击 群设置 → 智能群助手 → 添加机器人 → 自定义
- 安全设置至少勾选一项,强烈推荐选择 "加签" 模式(不要只用关键词或 IP 白名单)
- 复制生成的 Webhook 地址 和 加签密钥 (Secret,以
SEC开头)
Webhook: https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxx
Secret: SECxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2.2 妥善保管 access_token 与 Secret(必读)
⚠️ 安全提示:
access_token是机器人的发送凭证,Secret是签名密钥。两者任一泄漏都会带来安全风险 —— 攻击者可以伪造来自机器人的消息。
请遵守以下规则:
- 不要把
access_token或Secret硬编码进脚本、配置文件、截图 - 推荐做法:把两者保存在设备(或资产)的
server_attrs中,脚本里通过device.server_attrs.dingtalk_token和.dingtalk_secret引用 - 始终启用加签机制:钉钉的"自定义关键词"和"IP 地址段"两种安全模式很容易被绕过,加签是唯一难以被伪造的方式
- 建议至少 每季度更换一次 机器人凭证(重新生成机器人即可)
- 严格控制群成员,并定期清理不再需要的机器人
- 发现凭证泄漏时立即在群机器人设置中删除并重建
3. 在 RPC 中调用钉钉
3.1 在设备属性中保存凭证
在 运维管理 → 设备管理 → 设备详情 → 属性 标签下,为 server_attrs 添加:
json
{
"dingtalk_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"dingtalk_secret": "SECxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}3.2 RPC 脚本:带加签的 Markdown 消息
javascript
function rpc_script({ device, params, alarms, logger }) {
let token = device.server_attrs?.dingtalk_token;
let secret = device.server_attrs?.dingtalk_secret;
if (!token || !secret) {
logger.error("dingtalk credentials not configured", { eui: device.eui });
return null;
}
// 计算钉钉加签:timestamp + "\n" + secret,用 HmacSHA256 摘要后做 base64 + URL encode
let timestamp = Date.now();
let stringToSign = `${timestamp}\n${secret}`;
let crypto = require("crypto");
let sign = encodeURIComponent(
crypto.createHmac("sha256", secret).update(stringToSign).digest("base64")
);
let url = `https://oapi.dingtalk.com/robot/send?access_token=${token}` +
`×tamp=${timestamp}&sign=${sign}`;
let title = `设备告警 - ${device.name}`;
let text = [
`### ${title}`,
``,
`- **设备 EUI**:\`${device.eui}\``,
`- **告警等级**:**${(params.level || "").toUpperCase()}**`,
`- **告警内容**:${params.desc || "无"}`,
`- **时间**:${new Date().toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" })}`
].join("\n");
return [
{
sleepTimeMs: 0,
type: "axios",
dnMsg: {
method: "POST",
url: url,
headers: { "Content-Type": "application/json" },
data: {
msgtype: "markdown",
markdown: { title: title, text: text },
at: {
atMobiles: params.at_mobiles || [],
isAtAll: !!params.at_all
}
},
timeout: 5000
}
}
];
}💡 钉钉加签要求
timestamp与服务器时间偏差不超过 1 小时,签名需对当前时间戳重新计算 —— 不能预先固定。
3.3 RPC 脚本:发送纯文本消息
javascript
function rpc_script({ device, params, alarms, logger }) {
let token = device.server_attrs?.dingtalk_token;
let secret = device.server_attrs?.dingtalk_secret;
if (!token || !secret) return null;
let timestamp = Date.now();
let crypto = require("crypto");
let sign = encodeURIComponent(
crypto.createHmac("sha256", secret)
.update(`${timestamp}\n${secret}`).digest("base64")
);
return [
{
sleepTimeMs: 0,
type: "axios",
dnMsg: {
method: "POST",
url: `https://oapi.dingtalk.com/robot/send?access_token=${token}×tamp=${timestamp}&sign=${sign}`,
headers: { "Content-Type": "application/json" },
data: {
msgtype: "text",
text: { content: params.content || `${device.name} 告警通知` }
},
timeout: 5000
}
}
];
}4. 配置 RPC 参数
| 字段标识 | 类型 | 别名 | 说明 |
|---|---|---|---|
content | string | 消息内容 | 纯文本模式使用 |
level | string | 告警等级 | low / mid / high / urgent |
desc | string | 告警描述 | Markdown 模式下的详情 |
at_mobiles | object | @ 手机号列表 | 数组,例如 ["13800000000"] |
at_all | boolean | 是否 @ 所有人 | 慎用,避免打扰 |
5. 集成到告警流程
参考 企业微信 AN 中的触发联动示例,把 method 改成本 RPC 的 Method 名即可。
6. 故障排查
| 现象 | 可能原因 |
|---|---|
钉钉返回 errcode: 310000 sign not match | timestamp 或 secret 不匹配;签名编码方式错误(应为 base64 后 URL encode) |
钉钉返回 errcode: 130101 | 关键词模式下消息内容不包含设定的关键词 |
| 完全收不到 | access_token 错误;机器人被群管理员禁用;服务器到 oapi.dingtalk.com 网络不通 |
| 频率限制 | 单个机器人每分钟 20 条消息,超过会被限流 |
7. 注意事项
- 加签机制要求每条消息单独签名,不能复用旧签名
- 消息内容不要包含完整客户隐私数据、内部 IP 地址、Token 等敏感信息
- @ 手机号必须是钉钉群内成员的注册手机号,否则不会触发 @ 提醒
- 重要告警建议同时配置多个通道(如钉钉 + 邮件),避免单一通道异常漏报