独居老人安全守护:基于乐橙云 API 快速搭建跌倒检测与双向通话通知系统

独居老人安全守护:基于乐橙云 API 快速搭建跌倒检测与双向通话通知系统


周三傍晚,社区网格员小刘接到系统推送:张奶奶家客厅摄像机触发疑似跌倒。他拨电话——占线、挂断、再拨无人接听。

五分钟后,女儿王女士在「守护端」收到同一条告警,点开画面,用对讲喊了一声「妈,能听到吗?」摄像机那头传来回应:「脚绊了一下,缓过来了。」

小刘后来问我:「你们怎么知道该打电话,还是该对讲?」——告警类型不同,处置路径必须不同。跌倒和「长时间无活动」,不能都当成普通动检。


独居老人安全,难的不是「装个摄像头」

民政部数据显示,我国独居老人规模持续扩大。街道、民政、物业、家属四方都在找「低成本、可落地」的守护方案。很多项目的第一版,就是给老人家里装一个 Wi-Fi 摄像机——然后就没有然后了

常见翻车点:

现象根因后果
告警太多,家属关通知videoMotion 当跌倒真事故被淹没
跌倒发生了,子女不知道事件只在乐橙 App,未进业务系统黄金救援时间浪费
子女看到告警,联系不上老人只有视频,没有双向语音焦虑升级
老人按了紧急按钮,平台没反应未订阅 callEvent / 未配回调硬件白装

我们给街道做的「独居守护」二期,目标很明确:跌倒 / 疑似跌倒 / 呼叫 / 长时间无人体活动 四类事件进统一平台;子女端在 10 秒内能「看见 + 听见 + 说话」。

乐橙开放平台在养老场景的分工

乐橙开放平台 首页「智慧养老」方案里,核心组合是:跌倒检测设备 + 传感设备 + 实时预览、双向视频通话、报警推送、远程控制 API(见开放平台首页 · 智慧养老)。

对开发者而言,可以拆成三层:

感知层   支持跌倒 AI / 人形 / 呼叫能力的 IPC(设备端开启智能)
传输层   setMessageCallback → 你的公网桥接服务(HTTP 200)
交互层   子女 App:OpenSDK 预览 + LCOpenSDK_Talk 对讲(需 AudioTalk 能力)
增值层   电话提醒(控制台配置)+ getAlarmMessageStatistics 日报
电话提醒/短信 子女守护 App 守护桥接服务 乐橙开放平台 客厅 IPC 电话提醒/短信 子女守护 App 守护桥接服务 乐橙开放平台 客厅 IPC 跌倒/呼叫/无活动事件 POST 回调 JSON HTTP 200(立即) WebSocket 推送 P0 告警 可选:平台电话提醒 OpenSDK 预览 + playTalk 双向语音「妈,还好吗?」

为什么不用纯 HTTP 实现对讲?
乐橙 双向语音 走 OpenSDK 的 LCOpenSDK_Talk.playTalk,前提是设备能力集含 AudioTalkAudioTalkV1,且需先成功开启预览(见OpenSDK 语音对讲)。云端 OpenAPI 负责事件与直播地址实时音频通道在客户端 SDK 完成——集成时务必把边界写进方案,避免对甲方过度承诺。

关键事件类型(养老必盯)

业务统计标签 labelType回调 msgType(常见)说明
跌倒peopleFallAlarm设备 AI 跌倒告警getAlarmMessageStatistics
疑似跌倒suspectedPeopleFallAlarm疑似跌倒建议人工复核或二次确认
老人呼叫callAlarmcallEvent / callBellEvent事件消息类型定义
语音求助voiceHelpAlarm视机型部分设备支持
长久无活动noZigbeeAir人体感应类配件/机型
普通动检motionAlarmvideoMotion降级处理,勿当跌倒

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
说明aiCopyWritingaiTag 需通道开通 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,
  });
}

返回字段含 peopleFallAlarmsuspectedPeopleFallAlarmcallAlarmvoiceHelpAlarm 等(见报警统计文档)。
踩坑 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_AUDIOMODIFY_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 解密展示

性能与可靠性

  1. 回调必须先 200,再异步拉 getAlarmMessageById——我们曾把拉详情放在请求线程里,高峰丢推送一周。
  2. accessToken 缓存 3 天,遇 TK1002 刷新(accessToken)。
  3. 幂等:同一 alarmId 只推送一次 P0 电话。
  4. 离线:订阅 deviceStatus,摄像机离线同时通知家属换 4G 机型(如 TS 系列 4G IPC)。
  5. 子账号:街道管理员用子账户 token 时,权限需含 AlarmDevControl(见各接口「子账户最小权限」)。

排错表

现象原因处理
只有动检无跌倒未开跌倒 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,帮助第三方厂商和个人开发者快速、低成本落地视频场景——智慧养老,是最典型也最有温度的方向之一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值