独居老人安全守护:基于乐橙云 API 快速搭建跌倒检测与双向通话通知系统
周三傍晚,社区网格员小刘接到系统推送:张奶奶家客厅摄像机触发疑似跌倒。他拨电话——占线、挂断、再拨无人接听。
五分钟后,女儿王女士在「守护端」收到同一条告警,点开画面,用对讲喊了一声「妈,能听到吗?」摄像机那头传来回应:「脚绊了一下,缓过来了。」
小刘后来问我:「你们怎么知道该打电话,还是该对讲?」——告警类型不同,处置路径必须不同。跌倒和「长时间无活动」,不能都当成普通动检。
独居老人安全,难的不是「装个摄像头」
民政部数据显示,我国独居老人规模持续扩大。街道、民政、物业、家属四方都在找「低成本、可落地」的守护方案。很多项目的第一版,就是给老人家里装一个 Wi-Fi 摄像机——然后就没有然后了。
常见翻车点:
| 现象 | 根因 | 后果 |
|---|---|---|
| 告警太多,家属关通知 | 把 videoMotion 当跌倒 | 真事故被淹没 |
| 跌倒发生了,子女不知道 | 事件只在乐橙 App,未进业务系统 | 黄金救援时间浪费 |
| 子女看到告警,联系不上老人 | 只有视频,没有双向语音 | 焦虑升级 |
| 老人按了紧急按钮,平台没反应 | 未订阅 callEvent / 未配回调 | 硬件白装 |
我们给街道做的「独居守护」二期,目标很明确:跌倒 / 疑似跌倒 / 呼叫 / 长时间无人体活动 四类事件进统一平台;子女端在 10 秒内能「看见 + 听见 + 说话」。
乐橙开放平台在养老场景的分工
乐橙开放平台 首页「智慧养老」方案里,核心组合是:跌倒检测设备 + 传感设备 + 实时预览、双向视频通话、报警推送、远程控制 API(见开放平台首页 · 智慧养老)。
对开发者而言,可以拆成三层:
感知层 支持跌倒 AI / 人形 / 呼叫能力的 IPC(设备端开启智能)
传输层 setMessageCallback → 你的公网桥接服务(HTTP 200)
交互层 子女 App:OpenSDK 预览 + LCOpenSDK_Talk 对讲(需 AudioTalk 能力)
增值层 电话提醒(控制台配置)+ getAlarmMessageStatistics 日报
为什么不用纯 HTTP 实现对讲?
乐橙 双向语音 走 OpenSDK 的 LCOpenSDK_Talk.playTalk,前提是设备能力集含 AudioTalk 或 AudioTalkV1,且需先成功开启预览(见OpenSDK 语音对讲)。云端 OpenAPI 负责事件与直播地址;实时音频通道在客户端 SDK 完成——集成时务必把边界写进方案,避免对甲方过度承诺。
关键事件类型(养老必盯)
| 业务 | 统计标签 labelType | 回调 msgType(常见) | 说明 |
|---|---|---|---|
| 跌倒 | peopleFallAlarm | 设备 AI 跌倒告警 | 见getAlarmMessageStatistics |
| 疑似跌倒 | suspectedPeopleFallAlarm | 疑似跌倒 | 建议人工复核或二次确认 |
| 老人呼叫 | callAlarm | callEvent / callBellEvent | 见事件消息类型定义 |
| 语音求助 | voiceHelpAlarm | 视机型 | 部分设备支持 |
| 长久无活动 | — | noZigbeeAir | 人体感应类配件/机型 |
| 普通动检 | motionAlarm | videoMotion | 降级处理,勿当跌倒 |
Step 0:注册应用 + 选型验收
// scripts/00-check-elder-device.js
import 'dotenv/config';
import { callOpenApi, getToken } from '../src/openapi-client.js';
const appId = process.env.LECHANGE_APP_ID;
const appSecret = process.env.LECHANGE_APP_SECRET;
const token = await getToken(appId, appSecret);
const { deviceList } = await callOpenApi('listDeviceDetailsByPage', appId, appSecret, {
token,
pageSize: 50,
page: 1,
source: 'bindAndShare',
});
for (const dev of deviceList ?? []) {
const ab = dev.deviceAbility ?? '';
const talk = ab.includes('AudioTalk') || ab.includes('AudioTalkV1');
const chAb = dev.channelList?.[0]?.channelAbility ?? '';
console.log(
dev.deviceId,
dev.deviceName,
dev.deviceStatus,
talk ? '✓可对讲' : '✗缺AudioTalk',
chAb.slice(0, 60)
);
}
选型建议(平台推荐机型参考 电话提醒产品页 关联 IPC):室内云台 + 人形/跌倒 AI + 双向语音。
踩坑 A:子女手机 App 能预览,但 playTalk 失败——listDeviceDetailsByPage 里根本没有 AudioTalk,换机型或加带对讲的 IPC。
设备绑定走 接入指南 或 bindDevice;列表验收用 listDeviceDetailsByPage,不用旧版 deviceList。
Step 1:统一 OpenAPI 客户端
// src/openapi-client.js
import crypto from 'node:crypto';
import { randomUUID } from 'node:crypto';
const BASE = 'https://openapi.lechange.cn/openapi';
export function calcSign(time, nonce, appSecret) {
const raw = `time:${time},nonce:${nonce},appSecret:${appSecret}`;
return crypto.createHash('md5').update(raw, 'utf8').digest('hex');
}
export async function callOpenApi(method, appId, appSecret, params = {}) {
const time = Math.floor(Date.now() / 1000);
const nonce = randomUUID();
const body = {
system: { ver: '1.0', appId, sign: calcSign(time, nonce, appSecret), time, nonce },
id: randomUUID(),
params,
};
const res = await fetch(`${BASE}/${method}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const json = await res.json();
if (json.result?.code !== '0') throw new Error(`[${json.result.code}] ${json.result.msg}`);
return json.result.data;
}
export const getToken = (appId, appSecret) =>
callOpenApi('accessToken', appId, appSecret, {});
签名规则见开发规范:time 误差 ≤5 分钟,nonce 5 分钟内不可重复。
Step 2:注册告警回调
// scripts/01-set-callback.js
import 'dotenv/config';
import { callOpenApi, getToken } from '../src/openapi-client.js';
const appId = process.env.LECHANGE_APP_ID;
const appSecret = process.env.LECHANGE_APP_SECRET;
const token = await getToken(appId, appSecret);
await callOpenApi('setMessageCallback', appId, appSecret, {
token,
status: 'on',
callbackUrl: 'https://elder-care.example.com/imou/events',
callbackFlag: 'alarm,deviceStatus',
basePush: '2',
});
console.log(await callOpenApi('getMessageCallback', appId, appSecret, { token }));
文档:setMessageCallback · 事件消息推送流程
踩坑 B:桥接服务在内网,平台验 URL 失败。我们测试期用云函数 + 固定 HTTPS 域名,上线换 Nginx + 证书。
Step 3:桥接服务 — 跌倒 / 呼叫分级
// src/elder-bridge.js
import express from 'express';
const app = express();
app.use(express.json());
/** 养老场景 P0/P1 分级 */
const P0 = new Set([
'callEvent',
'callBellEvent',
'urgencyAlarm',
// 跌倒类:以设备实际上报 msgType 为准,常见为 AI 跌倒告警
'peopleFallAlarm',
'suspectedPeopleFallAlarm',
]);
const P1 = new Set(['noZigbeeAir', 'human', 'voiceHelpAlarm']);
function classify(msg) {
const msgType = msg.msgType;
if (P0.has(msgType)) return 'P0';
if (P1.has(msgType)) return 'P1';
if (msgType === 'videoMotion') return 'P3'; // 普通动检,不电话轰炸
return 'P2';
}
app.post('/imou/events', (req, res) => {
res.status(200).send('ok');
queueMicrotask(() => dispatch(req.body).catch(console.error));
});
async function dispatch(msg) {
const level = classify(msg);
const payload = {
level,
msgType: msg.msgType,
deviceId: msg.did ?? msg.deviceId,
channelId: msg.cid ?? msg.channelId,
alarmId: msg.id,
time: msg.time,
token: msg.token,
};
if (level === 'P0') {
await notifyFamilyApp(payload); // WebSocket / 厂商推送
await maybePhoneAlert(payload); // 平台电话提醒或自建 VoIP
} else if (level === 'P1') {
await notifyFamilyApp({ ...payload, silent: false });
}
await saveEvent(payload);
}
async function notifyFamilyApp(p) {
console.log('[push-family]', p);
}
async function maybePhoneAlert(p) {
console.log('[phone-alert]', p.deviceId, p.msgType);
}
async function saveEvent(p) {
console.log('[db]', p.alarmId);
}
app.listen(8080);
回调 JSON 样例 — 设备呼叫(事件消息格式定义):
{
"id": 2447736600,
"appId": "lcdxxxxxxxxx",
"did": "ELDER_CAM_001",
"cid": 0,
"msgType": "callEvent",
"time": 1716355200,
"cname": "张奶奶-客厅",
"token": "f2dc8c09eeae4b5bad6abf522c93d825"
}
踩坑 C:第一次联调,跌倒事件没进来——设备端 跌倒检测开关未开,且部分能力需 AI 智见 / 智见云存储 才有 aiCopyWriting。我们在验收清单里加了「模拟跌倒测试片段 + 查统计报表」。
Step 4:告警详情 + AI 文案(留证)
收到回调后,用 alarmId 拉详情,便于守护端展示「发生了什么」:
// scripts/02-alarm-detail.js
import 'dotenv/config';
import { callOpenApi, getToken } from '../src/openapi-client.js';
const appId = process.env.LECHANGE_APP_ID;
const appSecret = process.env.LECHANGE_APP_SECRET;
const token = await getToken(appId, appSecret);
const detail = await callOpenApi('getAlarmMessageById', appId, appSecret, {
token,
deviceId: 'ELDER_CAM_001',
channelId: '0',
alarmId: '1726360834259136',
msgType: 'videoMotion', // 与回调 msgType 一致
});
console.log(detail.aiCopyWriting); // 例:「老人倒在客厅地面」
console.log(detail.securityRiskLevel);
console.log(detail.aiTag);
console.log(detail.picurlArray?.[0]);
文档:getAlarmMessageById
说明:aiCopyWriting、aiTag 需通道开通 AI 智见套餐或智见云存储;未开通时仍有 picurlArray,但无 AI 摘要。
历史补洞:
await callOpenApi('getAlarmMessage', appId, appSecret, {
token,
deviceId: 'ELDER_CAM_001',
channelId: '0',
beginTime: '2026-05-22 00:00:00',
endTime: '2026-05-22 23:59:59',
count: 30,
nextAlarmId: '-1',
});
Step 5:日报统计 — 给街道看「这户稳不稳」
民政/街道常要「这周跌倒几次、呼叫几次」。用 getAlarmMessageStatistics,开启 aiStatisticsAnalysisEnable: true:
// scripts/03-daily-report.js
import 'dotenv/config';
import { callOpenApi, getToken } from '../src/openapi-client.js';
const appId = process.env.LECHANGE_APP_ID;
const appSecret = process.env.LECHANGE_APP_SECRET;
const token = await getToken(appId, appSecret);
const stats = await callOpenApi('getAlarmMessageStatistics', appId, appSecret, {
token,
deviceId: 'ELDER_CAM_001',
channelId: '0',
startDay: '20260520',
endDay: '20260522',
aiStatisticsAnalysisEnable: true,
});
for (const row of stats.statistics ?? []) {
console.log(row.date, {
fall: row.peopleFallAlarm,
suspected: row.suspectedPeopleFallAlarm,
call: row.callAlarm,
voiceHelp: row.voiceHelpAlarm,
motion: row.motionAlarm,
});
}
返回字段含 peopleFallAlarm、suspectedPeopleFallAlarm、callAlarm、voiceHelpAlarm 等(见报警统计文档)。
踩坑 D:报表为空——通道未开智见相关套餐;aiStatisticsAnalysisEnable 只是请求 AI 标签维度,不能替代套餐。
Step 6:子女端 — 预览 + 双向对讲(OpenSDK)
告警推送后,守护 App 跳转「实时画面 + 一键对讲」。Android 侧核心流程(摘自OpenSDK 文档):
// 1. 初始化(accessToken 由你的服务端下发,勿硬编码 appSecret)
InitParams initParams = new InitParams(context, "openapi.lechange.cn:443", accessToken);
LCOpenSDK_Api.initOpenApi(initParams);
// 2. 开启预览
LCOpenSDK_PlayRealWindow playWindow = new LCOpenSDK_PlayRealWindow();
playWindow.initPlayWindow(this, playContainer, 0, false);
LCOpenSDK_ParamReal paramReal = new LCOpenSDK_ParamReal(/* deviceId, channelId, ... */);
playWindow.playRtspReal(paramReal);
// 3. 对讲(能力集须含 AudioTalk / AudioTalkV1)
playWindow.stopAudio();
LCOpenSDK_Talk.setListener(new LCOpenSDK_TalkerListener());
LCOpenSDK_ParamTalk paramTalk = new LCOpenSDK_ParamTalk(/* 当前预览设备信息 */);
LCOpenSDK_Talk.playTalk(paramTalk);
// 结束:LCOpenSDK_Talk.stopTalk();
权限:RECORD_AUDIO、MODIFY_AUDIO_SETTINGS 必须声明,否则对讲无声——我们第一次联调在这卡了两小时。
Web 端轻量查看可先用 bindDeviceLive 出 HLS(见创建设备源直播地址),对讲仍建议走原生 OpenSDK 或轻应用 JS 组件中带对讲能力的方案。
const live = await callOpenApi('bindDeviceLive', appId, appSecret, {
token,
deviceId: 'ELDER_CAM_001',
channelId: '0',
streamId: 1,
});
console.log(live.streams?.[0]?.hls);
Step 7:电话提醒(可选增值)
对「电话打了三遍没人接」的场景,可叠加平台 电话提醒 增值服务:按告警类型绑定联系人,平台侧语音外呼。我们在桥接 P0 分支里保留 maybePhoneAlert,与控制台电话提醒策略二选一或互为备份,避免重复呼叫需做节流(同一老人 5 分钟内只呼一次)。
端到端 Checklist
□ listDeviceDetailsByPage:deviceStatus=online,含 AudioTalk
□ 设备端:跌倒检测 / 人形 / 呼叫按钮已启用
□ setMessageCallback 公网 HTTPS,实测 200
□ 模拟触发 callEvent / 跌倒,桥接分级正确
□ getAlarmMessageById 能拉到图片与 aiCopyWriting(如已开套餐)
□ 子女 App:预览成功后 playTalk 可双向说话
□ getAlarmMessageStatistics 日报字段符合街道验收
□ 普通 videoMotion 不触发电话提醒
边界与合规
| 话题 | 建议 |
|---|---|
| 医疗诊断 | 跌倒 AI 是辅助告警,不能替代医疗判断;产品文案用「疑似」「请及时确认」 |
| 隐私 | 老人室内画面敏感;告知同意 + 账号分权 + 日志脱敏 |
| 误报 | suspectedPeopleFallAlarm 走复核;videoMotion 勿升级 P0 |
| 图片留存 | 平台推送图片约 1 天内有效,须转存自有 OSS(见人脸推送文档备注) |
| 加密图 | 缩略图需 OpenSDK LCOpenSDK_Utils.decryptPic 解密展示 |
性能与可靠性
- 回调必须先 200,再异步拉
getAlarmMessageById——我们曾把拉详情放在请求线程里,高峰丢推送一周。 accessToken缓存 3 天,遇TK1002刷新(accessToken)。- 幂等:同一
alarmId只推送一次 P0 电话。 - 离线:订阅
deviceStatus,摄像机离线同时通知家属换 4G 机型(如 TS 系列 4G IPC)。 - 子账号:街道管理员用子账户 token 时,权限需含
Alarm、DevControl(见各接口「子账户最小权限」)。
排错表
| 现象 | 原因 | 处理 |
|---|---|---|
| 只有动检无跌倒 | 未开跌倒 AI / 机型不支持 | 换支持机型,App 内开智能 |
| 有跌倒无 aiCopyWriting | 未开智见套餐 | 控制台开通或仅展示原图 |
| playTalk 失败 | 无 AudioTalk / 未开预览 | 查 deviceAbility,先 preview |
| 回调中断 | 未返回 200 | 桥接改 async |
| 统计报表全 0 | 日期格式 / 无套餐 | yyyyMMdd,确认智见 |
总结
独居老人守护系统的关键,不是「多装一个 App」,而是把 跌倒、呼叫、无活动 变成可分级、可触达、可对话的事件链:
listDeviceDetailsByPage 验收能力
→ setMessageCallback 收告警
→ 桥接 P0/P1 分流
→ getAlarmMessageById 留证
→ OpenSDK 预览 + playTalk 对讲
→ getAlarmMessageStatistics 给街道日报
乐橙开放平台提供设备上云、消息推送、客户端 SDK 与 AI 统计报表;开发者专注 老人档案、家属关系、处置流程,就能在几天内做出可演示的 MVP。
开始接入
如果你在做养老 SaaS、社区独居守护或家属端小程序,建议先拿一台支持 人形 + 对讲 的 IPC,跑通 callEvent 或跌倒回调 + OpenSDK 对讲。
到 乐橙开放平台 open.imou.com 注册开发者并创建应用,可领取免费设备接入额度与媒体带宽。平台以视频技术和安全为核心,开放低代码组件与 OpenAPI,帮助第三方厂商和个人开发者快速、低成本落地视频场景——智慧养老,是最典型也最有温度的方向之一。
180

被折叠的 条评论
为什么被折叠?



