三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

小智 AI 还能这么玩?接入萤石摄像头,告警抓图一气呵成!

小智 AI 还能这么玩?接入萤石摄像头,告警抓图一气呵成!

本人玩各种AI硬件、具身智能、AI算法、模型训练、机器视觉等。欢迎合作!!!

小智AI接入萤石云摄像头:MQTT 实时告警 + 图片预览。让小智AI/ESP32 设备秒变智能安防终端——门口摄像头检测到有人出现时,屏幕自动弹出告警消息、播放提示音,还能下载并显示现场抓拍图片。


整体架构

萤石摄像头(门铃) │ ├─→ 萤石开放平台 ←─ 注册设备、开启告警推送 │ │ │ ├─→ 告警事件推送 → 消息回调服务 → 发布到 MQTT Broker │ │ │ │ │ ├─→ 飞书机器人 ←─ 手机端实时查看 │ │ │ │ │ └─→ 小智AI(ESP32) ←─ MQTT 订阅 │ │ │ │ │ ├─ 屏幕显示告警气泡 │ │ ├─ 播放提示音 │ │ └─ 下载并显示抓拍图片

步骤一:门铃接入萤石开放平台

1. 注册萤石开放平台账号

访问 萤石开放平台,注册并登录开发者账号。

2. 添加设备

  • 在萤石 APP 中确保门铃已联网并正常工作
  • 在开放平台「我的资源」中添加设备,或扫描设备二维码完成绑定

3. 创建应用获取 AppKey / AppSecret

  • 进入「我的应用」→ 创建应用
  • 获取AppKeyAppSecret,后续 API 调用需要用到

4. 开启告警推送

  • 在「告警服务」中开启设备的移动侦测/门铃事件推送
  • 配置告警推送地址为你的服务器回调 URL

步骤二:部署消息回调服务

萤石开放平台会将告警事件以 HTTP POST 方式推送到你的服务器,需要部署一个回调服务来接收并转发。

服务功能

萤石告警推送 → 回调服务解析 → 提取消息文本和图片URL │ ├─→ 发布到 MQTT Broker (qiongmu/mqtt/ys) └─→ 推送飞书机器人 webhook

部署方式

  • 服务器:任意 Linux 服务器(阿里云、腾讯云等)
  • HTTPS:萤石回调要求 HTTPS,可用 Nginx 反向代理 + Let’s Encrypt 证书
  • 保活:使用systemdsupervisor管理进程

步骤三:接入飞书机器人

1. 创建飞书自定义机器人

  • 打开飞书群聊 → 设置 → 群机器人 → 添加机器人 → 自定义机器人
  • 获取 Webhook 地址

2. 配置回调服务

在上面的回调服务中配置FEISHU_WEBHOOK,告警消息会同时推送到飞书:

🚨 门口有人出现! 📷 抓拍: https://i.ys7.com/streamer/alarm/url/get?fileId=...

3. 效果

  • 手机端:飞书 APP 收到群消息推送,随时查看
  • 带图片:点击链接可查看抓拍图片
  • 可配合飞书自动化:设置特别关注、DND 时段等

步骤四:小智接入 MQTT 实现告警

设备端实现

在小智AI(ESP32-S3)上运行MqttListener,独立订阅 MQTT 告警主题:

// mqtt_listener.h - 独立 MQTT 客户端classMqttListener{// TLS 连接 emqxsl.cn:8883// 订阅 qiongmu/mqtt/ysstaticMqttListener&GetInstance();voidInitialize();voidStart();};

Application::Initialize()中初始化:

auto&mqtt_listener=MqttListener::GetInstance();mqtt_listener.SetMessageCallback([this](conststd::string&topic,conststd::string&payload){OnMqttMessage(payload);});mqtt_listener.Initialize();// 网络激活后启动mqtt_listener.Start();

消息处理

MQTT 消息通过事件队列进入主事件循环:

MQTT 收到 → 入队 → MAIN_EVENT_MQTT_MESSAGE ↓ HandleMqttMessageEvent() ↓ ├── 解析 JSON → msg + pic ├── SetChatMessage("system", msg) → 显示气泡消息 ├── PlaySound(OGG_SUCCESS) → 播放提示音(3次) └── xTaskCreate() → 后台下载图片

图片下载与显示

完整流程

HTTP GET → 跟随 302 重定向(最多3次) → 下载 JPEG ↓ jpeg_to_image() → 解码为 RGB565 ↓ 最近邻缩放至 320×320(保持宽高比) ↓ LvglAllocatedImage → SetPreviewImage() 显示

重定向处理

萤石云图片 URL 返回 302 跳转到 AWS S3:

while(redirect_count<3){autohttp=Board::GetInstance().GetNetwork()->CreateHttp(3);http->SetKeepAlive(false);// 禁用连接复用http->Open("GET",current_url);if(status_code==302){std::string location=http->GetResponseHeader("Location");http->Close();current_url=location;redirect_count++;vTaskDelay(pdMS_TO_TICKS(200));continue;}// 下载并解码...}

JPEG 解码 + 缩放

使用 ESP-IDF 自带的 JPEG 解码器(优先硬件加速),解码后缩放到 320×320:

// JPEG 解码uint8_t*rgb565=nullptr;esp_err_t err=jpeg_to_image(jpeg_data,content_length,&rgb565,&rgb_len,&img_width,&img_height,&img_stride);// 缩放到 320×320(保持宽高比)constintMAX_DIM=320;if(img_width>MAX_DIM||img_height>MAX_DIM){intscale_w=(img_width>img_height)?MAX_DIM:(MAX_DIM*img_width/img_height);intscale_h=(img_height>img_width)?MAX_DIM:(MAX_DIM*img_height/img_width);uint8_t*scaled=heap_caps_malloc(scale_w*scale_h*2,MALLOC_CAP_SPIRAM);downscale_rgb565((uint16_t*)rgb565,img_width,img_height,scaled,scale_w,scale_h);heap_caps_free(rgb565);// 立即释放原始大图}

内存对比

原始分辨率解码后缩放后
1920×1080~4MB~200KB
1280×720~1.8MB~112KB
640×480~600KB~150KB

内存保护

ESP32 内存有限,下载前检查可用堆大小:

if(esp_get_free_heap_size()<80*1024){ESP_LOGW(TAG,"Skipping image download, low memory (%zu KB)",esp_get_free_heap_size()/1024);}else{xTaskCreate(...,"mqtt_img",4096*2,...);}

消息气泡持久化

移除了所有SetChatMessage("system", "")空内容调用,让 MQTT 消息在聊天区永久显示,直到:

  • 消息数量超过 MAX_MESSAGES(默认 20 条)自动挤掉最旧的
  • 新对话开始时清除


最终效果

终端效果
小智AI屏幕弹出告警气泡 + 提示音 + 抓拍图片
飞书APP随时随地查看门铃动态


后续计划

  • 图片点击放大全屏查看
  • 支持更多图片格式(PNG/WebP)
  • MQTT 告警消息数量统计
  • 语音播报告警内容
  • 飞书机器人交互式按钮(静音时段、确认已处理等)

项目:xiaozhi-esp32
作者:qiongmu.tech

← 返回列表