『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 8684|回复: 44

[经验分享] 米家猫眼视频本地存储

  [复制链接]

4

主题

64

帖子

608

积分

论坛技术达人

积分
608
金钱
534
HASS币
40
发表于 2024-3-6 12:42:27 | 显示全部楼层 |阅读模式
本帖最后由 wz1st 于 2024-3-8 09:15 编辑

0x00 前提
论坛中看到了大佬的【立省100%】小米系可视门铃本地存储 ,遂在自己的环境上折腾,经过一天的和领导斗智斗勇(划掉)折腾,虽成功实现,但也遇见不少小问题:
  • 米家猫眼的m3u8文件使用AES加密,#35楼中的对m3u8进行切片再组装的方案无法获取原始视频数据;
  • 保存成功的视频使用的是HEVC格式编码,部分设备播放黑屏或无法播放;
  • 网络环境波动导致m3u8文件或ts文件下载失败;
so.沿用大佬的思路,用Python改造了一下,现在开始吧!!



0x01 准备
  • 米家接入

       emmmm
  • 米家设置
       把猫眼改为实时查看模式,不然HA经常性的猫眼掉线


0x02 配置
  • HA配置
       HACS中找pyscript,安装;/config/pyscript中新建video_doorbell.py,写入下面的代码
import re, requests, functools, urllib.parse

@service
def video_doorbell():
    entity = camera.loock_v06_d9c1_video_doorbell  #替换为你自己的实体
    stream_address = urllib.parse.quote(getattr(entity, 'stream_address'))
    motion_video_time = re.sub(r'[^0-9]', '', getattr(entity, 'motion_video_time'))
    save_video(stream_address, motion_video_time)


async def save_video(stream_address, motion_video_time):
    nas_addr = "http://192.168.0.250:5005" #替换为你自己的nas地址,端口为app.py中定义的端口,或者docker开放的端口
    post_request = functools.partial(requests.post, f'{nas_addr}/save_video', data={"stream_address": stream_address, "motion_video_time": motion_video_time})
    response = await hass.async_add_executor_job(post_request)
    return response


      在开发者工具->YAML配置->重载Pyscript Python scripting
      新建一个自动化
alias: 猫眼视频保存
description: ""
trigger:
  - platform: state
  entity_id:
    - camera.loock_v06_d9c1_video_doorbell
  attribute: motion_video_time
condition: []
action:
  - service: pyscript.video_doorbell
  data: {}
mode: single



  • Nas配置
       不一定非要用Nas,总结来说Docker、装有ffmpeg的Linux这两种类型设备,用HAOS、openwrt也行
       1.Linux
        安装ffmpeg和驱动
apt-get update && apt-get install -y ffmpeg libva-drm2 libva2 vainfo i965-va-driver && apt-get clean  #centos和win自己解决
       安装Python3和pip(自己解决),安装依赖库:pip3 install flask requests pycryptodome pycrypto m3u8
        新建app.py文件,写入以下代码,然后运行:python3 app.py (后台运行:nohup python3 app.py > save2mp4.log 2>&1 &)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from flask import Flask, request
import urllib.parse, os, requests, m3u8
from datetime import datetime
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad


app = Flask(__name__)

@app.route('/save_video', methods=['POST'])
def save_video():
    current_date = datetime.now().strftime("%Y%m%d")
    
    data = request.form
    stream_address = urllib.parse.unquote(data.get('stream_address'))
    motion_video_time = data.get('motion_video_time')
    save_path = '/nas'  #视频保存位置
    video_limit = '30'  #保存天数上限

    m3u8_file = f'{save_path}/tmp/{motion_video_time}.m3u8'
    ts_tmp_dir = f'{save_path}/tmp/{motion_video_time}/'

    try:
        os.makedirs(f"{save_path}/{current_date}")
    except:
        pass
    try:
        os.makedirs(f"{save_path}/tmp")
    except:
        pass
    try:
        os.makedirs(ts_tmp_dir)
    except:
        pass
    download_m3u8(stream_address, m3u8_file)
    with open(m3u8_file, 'r') as f:
        m3u8_data = f.read()
        m3u8_decode(m3u8_data, ts_tmp_dir)
        try:
            os.system(f"rm -rf {save_path}/{current_date}/{motion_video_time}.mp4")
            # 猫眼的视频是HEVC编码格式,有点占用较少,缺点不同的设备不一定能播放出画面
            # os.system(f"ffmpeg -f concat -safe 0 -i {ts_tmp_dir}ts.list -c copy {save_path}/{current_date}/{motion_video_time}.mp4")


            # 软解把HEVC转成H.264,占用较大,软解硬解都能放
            os.system(f"ffmpeg -f concat -safe 0 -i {ts_tmp_dir}ts.list -c:v libx264 -preset slow -crf 22 -c:a copy -b:a 128k {save_path}/{current_date}/{motion_video_time}.mp4")

            # 启用VAAPI硬编码
            # os.system(f"ffmpeg -f concat -safe 0 -i {ts_tmp_dir}ts.list -vaapi_device /dev/dri/renderD128 -c:v h264_vaapi -global_quality 25 -vf 'format=nv12|vaapi,hwupload' -c:a copy {save_path}/{current_date}/{motion_video_time}.mp4")
            os.system(f"rm -rf {save_path}/tmp/{motion_video_time}*")
            os.system(f"find {save_path} -type f -mtime +{video_limit} -delete")
            os.system(f"find {save_path} -depth -type d -empty -delete")
        except:
            pass
    return "ok"

def download_m3u8(url, output_file):
    for i in range(5):
        try:
            response = requests.get(url)
            if response.status_code == 200:
                with open(output_file, 'wb') as f:
                    f.write(response.content)
                break
        except:
            pass

def m3u8_decode(m3u8_data, ts_tmp_dir):
    m3u8_obj = m3u8.loads(m3u8_data)
    key = download_key(m3u8_obj.keys[0].uri)
    iv = bytes.fromhex(m3u8_obj.keys[0].iv.split('0x')[1])
    os.system(f"rm -rf {ts_tmp_dir}ts.list")
    with open(f"{ts_tmp_dir}ts.list", "a") as f:
        for i in range(len(m3u8_obj.segments)):
            for j in range(5):
                try:
                    ts_data = requests.get(m3u8_obj.segments[i].uri).content
                    break
                except:
                    pass
            cipher = AES.new(key, AES.MODE_CBC, iv)
            decrypted_data = unpad(cipher.decrypt(ts_data), AES.block_size)
            with open(f"{ts_tmp_dir}{i}.ts", "wb") as f1:
                f1.write(decrypted_data)
            f.write(f"file '{ts_tmp_dir}{i}.ts'\n")
    return True

def download_key(key_url):
    for i in range(5):
        try:
            response = requests.get(key_url)
            return response.content
        except:
            pass

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5005)




       2.Docker
       Docker版用的是Dockerfile创建镜像,还没学会上传到dockerhub,具体文件可以看下我的gayhub:保存米家门铃视频
       a.把gayhub仓库的nas文件夹放到你自己的nas中,cd命令切换到nas,执行命令docker build -t save2mp4 .创建镜像
       b.运行docker run -it -p 5005:5005 -v $(pwd):/app -v /{替换为你的视频保存地址}:/nas --device=/dev/dri:/dev/dri save2mp4


0x03 结束
可以到门口溜一圈了,效果如下

效果

效果

0x04 吐槽
莫得markdown......  代码缩紧问题自行处理吧。。
gayhub点个星也是极好的




评分

参与人数 5金钱 +58 HASS币 +20 收起 理由
admin + 20 + 20 大神666!
Alkali + 10 高手,这是高手!
q873139535 + 8 论坛有你更精彩!
隔壁的王叔叔 + 10 高手,这是高手!
DDDear + 10 纳尼,还有这种操作?

查看全部评分

技术宅拯救世界~~~
回复

使用道具 举报

4

主题

64

帖子

608

积分

论坛技术达人

积分
608
金钱
534
HASS币
40
 楼主| 发表于 2024-3-13 17:25:05 | 显示全部楼层
本帖最后由 wz1st 于 2024-3-13 17:31 编辑
zhenxiwen 发表于 2024-3-12 20:44
还需要米家猫眼吗?
我在客厅做了个大显示器,
用frigate获取摄像头的stream,

首先,我有且只有这个猫眼,我就想把视频保存下来(同理也可以用在摄像头和门锁),我为啥非要再买摄像头、买显示器挂起来?
其次,我分享的是hacs-pyscript脚本写法、ffmpeg编解码方案、m3u8解码解密方案,也没说要你买个猫眼;
而且,猫眼这玩意也没rtsp视频流啊,和摄像头根本就是俩不同的玩意;

你可以质疑我代码问题、思路问题,但这俩技术方向都不同啊
我承认frigate是nb,这不是我没条件么,也不值得单开帖子反问啊
技术宅拯救世界~~~
回复

使用道具 举报

12

主题

434

帖子

2340

积分

金牌会员

Rank: 6Rank: 6

积分
2340
金钱
1906
HASS币
0
发表于 2024-3-6 14:20:49 | 显示全部楼层
360的猫眼有没有的搞呀
回复

使用道具 举报

10

主题

1332

帖子

4250

积分

论坛元老

Rank: 8Rank: 8

积分
4250
金钱
2918
HASS币
0
发表于 2024-3-6 17:13:05 | 显示全部楼层
必须加分鼓励一下,感谢大佬分享
回复

使用道具 举报

9

主题

160

帖子

2804

积分

论坛技术达人

积分
2804
金钱
2634
HASS币
50
发表于 2024-3-7 09:22:23 | 显示全部楼层
发现用 motion_video_time 当触发条件会有挺大的延迟,不知道这个延迟能否缩小?
回复

使用道具 举报

4

主题

64

帖子

608

积分

论坛技术达人

积分
608
金钱
534
HASS币
40
 楼主| 发表于 2024-3-7 09:49:27 | 显示全部楼层
本帖最后由 wz1st 于 2024-3-7 09:55 编辑
ck3 发表于 2024-3-7 09:22
发现用 motion_video_time 当触发条件会有挺大的延迟,不知道这个延迟能否缩小? ...

这个可以改下xiaomi-miot对音箱conversation的轮询时间 为什么设备状态会有延迟?如何减小延迟?,有时候会遇见同一时间触发有人移动和有人停留两种通知,这种就只能保存一个了。。
技术宅拯救世界~~~
回复

使用道具 举报

4

主题

64

帖子

608

积分

论坛技术达人

积分
608
金钱
534
HASS币
40
 楼主| 发表于 2024-3-7 09:52:26 | 显示全部楼层
jjss520 发表于 2024-3-6 14:20
360的猫眼有没有的搞呀

实体属性发下 瞅瞅能不能搞
技术宅拯救世界~~~
回复

使用道具 举报

12

主题

434

帖子

2340

积分

金牌会员

Rank: 6Rank: 6

积分
2340
金钱
1906
HASS币
0
发表于 2024-3-7 10:09:17 | 显示全部楼层
wz1st 发表于 2024-3-7 09:52
实体属性发下 瞅瞅能不能搞

都没办法接入HA,好像没见人搞过
回复

使用道具 举报

9

主题

160

帖子

2804

积分

论坛技术达人

积分
2804
金钱
2634
HASS币
50
发表于 2024-3-7 11:20:39 | 显示全部楼层
wz1st 发表于 2024-3-7 09:49
这个可以改下xiaomi-miot对音箱conversation的轮询时间 为什么设备状态会有延迟?如何减小延迟?,有时候 ...

好的,感谢大佬
回复

使用道具 举报

40

主题

1128

帖子

4252

积分

论坛元老

Rank: 8Rank: 8

积分
4252
金钱
3124
HASS币
0
发表于 2024-3-7 14:12:39 | 显示全部楼层
米家的猫眼接入hass,目前只能看事件触发的视频,不能像监控一样看全部
回复

使用道具 举报

1

主题

60

帖子

422

积分

中级会员

Rank: 3Rank: 3

积分
422
金钱
362
HASS币
10
发表于 2024-3-8 09:07:29 | 显示全部楼层
效果图一直刷不出来,,,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-11-23 23:52 , Processed in 0.125275 second(s), 38 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表