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