diff --git a/README.md b/README.md index 3c9de83..bd4b78a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,17 @@ # 1. 项目简介 +📃 **Lot_manager**:基于**MQTT**(客户端-服务器的消息发布/订阅传输协议)、**FFmpeg**(多媒体视频处理工具)、**Supervisor**(Linux进程控制系统)的**物联网数据上传**、**视频推流**和**视频录像**应用。 + +⛓️ 本项目大致实现原理如图所示,包含两个模块:视频推流模块和物联网数据管理模块。 +1. 视频推流模块:使用MQTT的客户端连接MQ服务器(**EMQX**),MQ服务端通过发布消息,如推流命令、停止推流命令、录像上传命令等,MQTT客户端接收指令后通过supervisor启动相应的进程,从而启动服务,将视频推流至**ZLMediaKit**服务器。 +2. 物联网数据管理模块:数据上传通过MQTT客户端进行连接服务器,如果连接成功,则通过supervisor启动数据上传服务,并发布数据到服务端。如果连接失败或者断开了连接,则通过supervisor停止数据上传服务,则将数据保存到本地(**sqlite**)。 +![image](https://yjxiao.oss-cn-shanghai.aliyuncs.com/flow.png) +### 技术路线图 + +- [x] 视频推流 + - [x] FFmpeg +- [x] 物联网数据管理 +- [x] MQTT程序控制 +- [ ] MQTT程序控制的返回结果,设置统一的返回状态码 # 2. 开发环境部署 @@ -6,10 +19,9 @@ #### 已经测试过的系统 -- Debian GNU/Linux 12(bookworm) Linux version 5.16.17+ +* Debian GNU/Linux 12(bookworm) Linux version 5.16.17+ ## 环境安装 - ``` # 首先,确信你的机器安装了python 3.11.2 $ python --version @@ -39,9 +51,7 @@ Thu Dec 14 15:13:45 CST 2023 # 更新py库 $ pip3 install --upgrade pip ``` - ## 配置wifi - ``` # 使用arp协议查看以太网接口的摄像机地址,需要将摄像机连接以太网 $ sudo arp -a @@ -52,22 +62,22 @@ enabled # 连接wifi $ sudo nmcli dev wifi connect password ``` - ## 配置系统静态IP ### 使用nmtui网络界面管理 `$ sudo nmtui` -- 设置的静态IP地址网段需要和摄像机在同一个网段 -- 无需设置网关,即为空。此项解决wifi上网和以太网上网冲突的问题。 -- DNS设置为8.8.8.8 -- 勾选始终不使用此网络于默认路由 +* 设置的静态IP地址网段需要和摄像机在**同一个网段** +* **无需设置网关,即为空。此项解决wifi上网和以太网上网冲突的问题** +* DNS设置为8.8.8.8 +* 勾选始终不使用此网络于默认路由 +![image](https://yjxiao.oss-cn-shanghai.aliyuncs.com/%E5%9B%BE%E7%89%871.png) +![image](https://yjxiao.oss-cn-shanghai.aliyuncs.com/%E4%BB%A5%E5%A4%AA%E7%BD%91%E8%AE%BE%E7%BD%AE.png) ## 配置git和pip - ``` -# 设置git的usrenmae +# 设置git的username $ git config --global user.name xxx # 设置git的email $ git config --global user.email xxx @@ -78,24 +88,21 @@ $ cd lot_manager # 安装项目依赖 $ pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple ``` - ## 创建设备名称(系统唯一标识名称) - +该部分创建核桃派系统的设备名称,用于标识。设备名称创建在**主目录**下。 ``` -# lihai_lot_walnutpi_dev_1代表1号设备,可以自行设置 +# lihai_lot_walnutpi_dev_1 代表1号设备,可以自行设置 $ cd ~ $ echo 'lihai_lot_walnutpi_dev_1' | tee device_name lihai_lot_walnutpi_dev_1 ``` - -## 创建mp4文件目录 - +## 创建视频录像保存目录 +录像保存在主目录下的mp4目录下。 ``` $ mkdir /home/pi/mp4 ``` - ## 配置定时任务 - +配置一些定时任务,如录像只保存2天。物联网数据只保存3天。对于32G的内存卡,只要超过20G就进行删除录像,直至录像小于20G。 ``` $ sudo crontab -e # 公共定时任务 @@ -108,31 +115,29 @@ $ sudo crontab -e # 每隔15分钟进行 */15 * * * * /usr/bin/python /home/pi/lot_manager/delete_than20G.py ``` - ## 初始化本地数据库 - +本项目采用sqlite进行数据的保存,数据库文件存放在主目录下。 ``` $ python /home/pi/lot_manager/create_db.py ``` - ## 配置supervisor文件 -1. 安装完supervisor后,会在/etc/supervisor目录下存在supervisord.conf文件和conf.d目录。 +1. 安装完supervisor后,会在/etc/supervisor目录下存在supervisord.conf文件和conf.d目录。 ``` $ cd /etc/supervisor/ $ ls conf.d supervisord.conf supervisord.conf.bak ``` - -2. 需要对supervisord.conf文件进行配置 - +2. 对supervisord.conf文件进行配置 +首先备份默认配置,然后进行配置。 ``` $ sudo cp supervisord.conf supervisord.conf.bak $ sudo vim supervisord.conf ``` + +配置信息: -3. 配置信息: ``` ; supervisor config file @@ -176,94 +181,150 @@ priority=1 [include] files = /home/pi/lot_manager/conf/common/*.conf ``` - 上面是已经修改好的配置文件,修改了其中几项: - [unix_http_server] - chmod改为0777,使得普通用户得以执行。 + chmod改为0777,使得普通用户得以执行。 - [include] - files = /etc/supervisor/conf.d/*.conf,files是用户定义的配置文件。 + files = /etc/supervisor/conf.d/*.conf,files是用户定义的配置文件。 - [supervisorctl] - 添加user=pi,使得普通用户得以执行。 + 添加user=pi,使得普通用户得以执行。 - [program:\_\_mqtt\_\_] - 添加mqtt配置信息 + 添加mqtt配置信息 - 修改/etc/supervisor/conf.d的权限,sudo chmod 777 /etc/supervisor/conf.d -4. 设置开启启动supervisor - +1. 设置开启启动supervisor ``` $ sudo systemctl enable supervisor ``` - -5. 启动supervisor - +2. 启动supervisor ``` -sudo systemctl start supervisor +$ sudo systemctl start supervisor ``` - # 3. 项目结构 -- lot_manager - - bash - - cron_delete_mp4.sh 定时删除录像脚本 - - modify_device_name.sh 修改设备唯一名称脚本 - - record.sh 录像脚本 - - start_data_upload.sh 开启数据上传脚本 - - start_push_stream.sh 启动推流脚本 - - stop_data_upload.sh 停止数据上传脚本 - - stop_push_stream.sh 停止推流脚本 - - stream.sh 推流命令脚本 - - conf - - common - - data_upload.conf 数据上传配置 - - mqtt.conf mqtt配置 - - push_stream.conf 推流配置 - - record.conf 录像配置 - - sensor_to_local.conf 数据保存在本地 - - sensor_to_server.conf 数据发布到mq服务器 - - device - - device.conf 不同设备的配置 - - example - - cron_for_32G.conf 对于32G卡的定时任务配置 - - cron_for_64G.conf 对于64G卡的定时任务配置 - - supervisord.conf 配置supervisor文件 - - main - - common.conf 公共配置 - - tmp - - device_name 需要修改的设备名称 - - zhanguan - - topic.conf 展馆的特殊设备 - - db/ 本地数据库管理 - - MQTT.py - - data_upload.py 数据上传程序 - - api.py 本地数据库api - - config.py 读取各种配置文件 - - create_db.py 创建数据库程序 - - delete_lot_3_days.py 删除数据库中早于3天的数据 - - delete_than20G.py 当录像超过20G,直接删除直到小于20G - - sensor_to_local.py 数据保存在本地 - - sensor_to_server.py 数据发布到服务器 - - tool.py 工具 - - git_push.sh 推送git脚本 - - git_update.sh 更新git脚本 - - install.sh 安装依赖脚本 +* lot_manager + * bash + * cron_delete_mp4.sh 定时删除录像脚本 + * modify_device_name.sh 修改设备唯一名称脚本 + * record.sh 录像脚本 + * start_data_upload.sh 开启数据上传脚本 + * start_push_stream.sh 启动推流脚本 + * stop_data_upload.sh 停止数据上传脚本 + * stop_push_stream.sh 停止推流脚本 + * stream.sh 推流命令脚本 + * conf + * common + * data_upload.conf 数据上传配置 + * mqtt.conf mqtt配置 + * push_stream.conf 推流配置 + * record.conf 录像配置 + * sensor_to_local.conf 数据保存在本地 + * sensor_to_server.conf 数据发布到mq服务器 + * device + * device.conf 不同设备的配置 + * example + * cron_for_32G.conf 对于32G卡的定时任务配置 + * cron_for_64G.conf 对于64G卡的定时任务配置 + * supervisord.conf 配置supervisor文件 + * main + * common.conf 公共配置 + * tmp + * device_name 需要修改的设备名称 + * zhanguan + * topic.conf 展馆的特殊设备 + * db/ 本地数据库管理 + * MQTT.py + * data_upload.py 数据上传程序 + * api.py 本地数据库api + * config.py 读取各种配置文件 + * create_db.py 创建数据库程序 + * delete_lot_3_days.py 删除数据库中早于3天的数据 + * delete_than20G.py 当录像超过20G,直接删除直到小于20G + * sensor_to_local.py 数据保存在本地 + * sensor_to_server.py 数据发布到服务器 + * tool.py 工具 + * git_push.sh 推送git脚本 + * git_update.sh 更新git脚本 + * install.sh 安装依赖脚本 -# 4.supervisor参数配置 +## MQTT程序控制 -MQTT.py +![image](https://yjxiao.oss-cn-shanghai.aliyuncs.com/mqtt.png) + +## 物联网数据上传 -data_upload.py +![image](https://yjxiao.oss-cn-shanghai.aliyuncs.com/data_upload.png) + +## sensor_to_server.py +![image](https://yjxiao.oss-cn-shanghai.aliyuncs.com/sensor_to_server.png) + +## 项目的配置文件 -config.py +通过**configparser**读取.conf文件。 +项目的配置文件均在conf目录下: +* conf + * common 表示supervisor管理的进程配置文件 + * device 设置不同device的配置,包括订阅主题、发布主题、用户名和密码等 + * main 公共配置,包括域名设置、录像上传地址等 +``` +import configparser + +import subprocess + +p = subprocess.Popen(['cat /home/pi/device_name'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) +out, err = p.communicate() +# 设备名称,必须要有 +device_name = out.decode('utf-8').strip() + +# 读取配置 +config = configparser.ConfigParser() +# 读取公共配置 +config.read('conf/main/common.conf') +# 域名 +broker = config.get("broker", "host") +# 端口,这里必须是int类型 +port = config.getint("broker", "port") +# 录像地址 +post_record_list_url = config.get("record", "post_record_list_url") +post_record_url = config.get("record", "post_record_url") +# 发布消息的认证pwd +publish_pwd = config.get("publish_pwd", "value") + + +# 读取设备配置 +config.read('conf/device/device.conf') +# 订阅的主题 +subscribe_topic = config.get(device_name, "subscribe_topic") +# 发布的主题 +publish_topic = config.get(device_name, "publish_topic") +# 用户 +username = config.get(device_name, "username") +# 密码 +password = config.get(device_name, "password") + +# 特殊配置 +config.read('conf/zhanguan/topic.conf') +zhanguan_device_name = config.get("device", "name") + +# tool配置 +mp4_path = '/home/pi/mp4' +``` + + +# 4. Supervisor服务参数配置 配置文件都在conf文件夹下。主要是common、main和device文件夹。 -- conf - - common 表示supervisor管理的进程配置文件 - - device 设置不同device的配置,包括订阅主题、发布主题、用户名和密码等 - - main 公共配置,包括域名设置、录像上传地址等 +* conf + * common 表示supervisor管理的进程配置文件 + * device 设置不同device的配置,包括订阅主题、发布主题、用户名和密码等 + * main 公共配置,包括域名设置、录像上传地址等 -### MQTT的supervisor配置文件 +### supervisor服务配置 -directory表示执行命令时,首先进入这个文件夹 -command表示要执行的命令 -user必须是pi -autostart表示随开机或supervisor重启时跟着启动 -autorestart表示启动失败自动重启3次 +- directory表示执行命令时,首先进入这个文件夹 +- command表示要执行的命令 +- user必须是pi +- autostart表示随开机或supervisor重启时跟着启动 +- autorestart表示启动失败自动重启3次 ``` [program:__mqtt__] @@ -301,7 +362,6 @@ stopasgroup=True ### 推流的supervisor配置文件 注意不要跟随开机或supervisor重启启动 - ``` [program:push_stream] directory=/home/pi/lot_manager/bash @@ -313,7 +373,6 @@ redirect_stderr=true stopsignal=TERM stopasgroup=True ``` - ### 录像的supervisor配置文件 ``` @@ -353,7 +412,6 @@ stopasgroup=True ``` ### 数据保存在mq服务器的supervisor配置文件 - ``` [program:sensor_to_server] directory=/home/pi/lot_manager @@ -369,9 +427,10 @@ redirect_stderr=true stopsignal=TERM stopasgroup=True ``` - ## 不同设备的配置 - +1. 订阅的主题表示MQTT控制时,发布的主题,比如对设备lihai_lot_walnutpi_dev_1进行推流。 +2. 发布消息的主题,表示**物联网数据上传**时发布消息的主题。 +3. username和password是MQTT连接服务器的用户名和密码。 ``` # 设备1-32G # 编号 @@ -428,9 +487,10 @@ publish_topic=camera_6 username=lihai_lot_land_1 password=123456 ``` - ### 公共配置 - +1. host和port表示MQTT的服务器地址。 +2. post_record_list_url是上传录像的目录的地址。 +3. post_record_url是上传录像的地址。 ``` # 域名地址 [broker] @@ -442,33 +502,29 @@ post_record_url=https://ceshi-iot.lihaink.cn/api/index/upload [publish_pwd] value=123456 ``` - # 5. ffmpeg推流设置 推流的脚本为stream.sh,内容如下: - ``` #!/bin/bash device_name=`cat /home/pi/device_name` /usr/bin/ffmpeg -rtsp_transport tcp -re -i rtsp://admin:123456@192.168.0.123:554/mpeg4 -c copy -preset fast -r 20 -flvflags no_duration_filesize -f rtsp -rtsp_transport tcp rtsp://47.108.186.87:554/live/$device_name ``` - 对于ffmpeg的参数设置如下: -- -rtsp_transport_tcp tcp 表示以tcp进行获取流,保证数据完整性 -- -re 表示推流设置 -- -i 表示输入流,这里是摄像机地址 -- -c 表示直接复制源流对象,不进行编码 -- -preset fast表示快速传输 -- -r 20表示以帧率20传输 -- flvflags no_duration_filesize表示其他一些错误排除 -- -f rtsp -rtsp_transport tcp 表示输出的文件格式,输出为rtsp流,也是tcp传输 -- rtsp://47.108.186.87:554/live/$device_name表示推流地址 +* \-rtsp\_transport\_tcp tcp 表示以tcp进行获取流,保证数据完整性 +* \-re 表示推流设置 +* \-i 表示输入流,这里是摄像机地址 +* \-c 表示直接复制源流对象,不进行编码 +* \-preset fast表示快速传输 +* \-r 20表示以帧率20传输 +* flvflags no\_duration\_filesize表示其他一些错误排除 +* \-f rtsp -rtsp\_transport tcp 表示输出的文件格式,输出为rtsp流,也是tcp传输 +* rtsp\://47.108.186.87:554/live/\$device\_name表示推流地址 # 6.录像保存设置 录像的脚本为record.sh,内容如下: - ``` #!/bin/bash @@ -482,25 +538,23 @@ OUTPUT_FILE="${OUTPUT_DIR}/${CURRENT_TIME}.mp4" # 开始录制RTSP流 /usr/bin/ffmpeg -rtsp_transport tcp -i "${RTSP_URL}" -c copy -c:a aac -s 1920x1080 -r 15 -crf 35 -t "${RECORD_DURATION}" -f mp4 "${OUTPUT_FILE}" ``` - 参数设置如下: -- -rtsp_transport_tcp tcp 表示以tcp进行获取流,保证数据完整性 -- -i 表示输入流,这里是摄像机地址 -- -c 表示直接复制源流对象,不进行编码 -- -c:a aac表示音频编码格式为aac -- -s 1920x1080是分辨率裁剪 -- -r 15是帧率改为15 -- -crf 35是改变恒定传输速率,值越大,压缩越好,但质量越差,默认值是28 -- -t 表示900秒一次保存一次 -- -f mp4是保存为mp4文件 +* \-rtsp\_transport\_tcp tcp 表示以tcp进行获取流,保证数据完整性 +* \-i 表示输入流,这里是摄像机地址 +* \-c 表示直接复制源流对象,不进行编码 +* \-c\:a aac表示音频编码格式为aac +* \-s 1920x1080是分辨率裁剪 +* \-r 15是帧率改为15 +* \-crf 35是改变恒定传输速率,值越大,压缩越好,但质量越差,默认值是28 +* \-t 表示900秒一次保存一次 +* \-f mp4是保存为mp4文件 -# MQTT程序控制配置,发布消息和订阅消息 +# 7. MQTT程序控制配置,发布消息和订阅消息 ### 设备的编号配置信息 设备的配置为: - ``` [lihai_lot_walnutpi_dev_1] # 订阅的控制主题,必须和系统设置的相同 @@ -510,25 +564,22 @@ publish_topic=camera_1 username=lihai_lot_land_1 password=123456 ``` - 其中, -- subscribe_topic 表示订阅的主题,只有订阅后才能进行控制 -- publish_topic 表示数据发布的主题 -- username 表示客户端进行连接的用户名 -- password 表示客户端进行连接的密码 +* subscribe\_topic 表示订阅的主题,只有订阅后才能进行控制 +* publish\_topic 表示数据发布的主题 +* username 表示客户端进行连接的用户名 +* password 表示客户端进行连接的密码 ### 控制设备(推流、数据上传、录像等) -1. 发布的主题 +1. 发布的主题 ``` lihai_lot_walnutpi_dev_1 ``` - -2. 发送的消息体payload - example: - +1. 发送的消息体payload + example: ``` { "msg":"exec", @@ -536,13 +587,11 @@ lihai_lot_walnutpi_dev_1 "pwd":"123456" } ``` - ### msg类型 msg表示消息类型,包括: -- push_stream 设备启动推流 - +- push\_stream 设备启动推流 ``` 发布主题:lihai_lot_walnutpi_dev_1 { @@ -550,9 +599,7 @@ msg表示消息类型,包括: "pwd":"123456" } ``` - -- close_stream 设备关闭推流 - +* close\_stream 设备关闭推流 ``` 发布主题:lihai_lot_walnutpi_dev_1 { @@ -560,8 +607,8 @@ msg表示消息类型,包括: "pwd":"123456" } ``` +* record\_list 录像文件列表 -- record_list 录像文件列表 ``` 发布主题:lihai_lot_walnutpi_dev_1 @@ -570,8 +617,8 @@ msg表示消息类型,包括: "pwd":"123456" } ``` +* record 上传选定文件 -- record 上传选定文件 ``` 发布主题:lihai_lot_walnutpi_dev_1 @@ -581,8 +628,8 @@ msg表示消息类型,包括: "pwd":"123456" } ``` +* status 查看supervisor运行状态 -- status 查看supervisor运行状态 ``` 发布主题:lihai_lot_walnutpi_dev_1 @@ -592,8 +639,8 @@ msg表示消息类型,包括: "pwd":"123456" } ``` +* reload 重启supervisor -- reload 重启supervisor ``` 发布主题:lihai_lot_walnutpi_dev_1 @@ -603,8 +650,8 @@ msg表示消息类型,包括: "pwd":"123456" } ``` +* update 更新git -- update 更新git ``` 发布主题:lihai_lot_walnutpi_dev_1 @@ -614,8 +661,8 @@ msg表示消息类型,包括: "pwd":"123456" } ``` +* exec 执行linux命令 -- exec 执行linux命令 ``` 发布主题:lihai_lot_walnutpi_dev_1 @@ -626,15 +673,13 @@ msg表示消息类型,包括: "pwd":"123456" } ``` - ### data -- data在执行linux命令和获取录像时必须设置。 -- 在执行命令时,data则是需要执行的命令,获取录像时,需要指定需要的录像名称 -- 订阅success和error主题,可以查看错误消息和命令执行结果 - -# 本地数据库字段设置 +* data在执行linux命令和获取录像时必须设置。 +* 在执行命令时,data则是需要执行的命令,获取录像时,需要指定需要的录像名称 +* 订阅success和error主题,可以查看错误消息和命令执行结果 +# 8. 本地数据库字段设置 ``` class LOT_DATA(BaseModel): create_time: int = Field(None, description='创建时间(时间戳) ') @@ -654,9 +699,7 @@ class LOT_DATA(BaseModel): soil_potassium_phosphate_phosphorus: float = Field(None, description='土壤磷酸钾:磷的标准值在57-100mg/kg,') soil_potassium_phosphate_potassium: float = Field(None, description='土壤磷酸钾:钾的标准值在106-150mg/kg') ``` - ### 本地数据库存放位置 - ``` # 存放的路径 KB_ROOT_PATH = "/home/pi/" @@ -665,9 +708,11 @@ DB_ROOT_PATH = os.path.join(KB_ROOT_PATH, "lot_data.db") # 连接URI SQLALCHEMY_DATABASE_URI = f"sqlite:///{DB_ROOT_PATH}" ``` +### 数据库操作api +本项目采用**sqlalchemy**对sqlite进行数据的增删改查。api服务为项目的api.py文件。 +api包括的功能: +* add 添加数据到数据库 +* delete 删除3天之前的数据 + -# 技术路线图 -- [x] 数据上传 -- [x] 摄像机推流 -- [ ] MQTT程序控制的返回结果,设置统一的返回状态码 \ No newline at end of file