树莓派远程监控

树莓派做的远程监控。

1.自制ups和远程开关

突然关机会损坏树莓派sd卡,需要一个ups,断电后切换到ups供电。

购买路由器ups,大概五十元左右。一个5v输出,一个9v输出,使用DC-DC电路板把9v输出转为5v供电给树莓派,另一个5v供电给NodeMCU芯片。

NodeMCU连接两个继电器,控制树莓派电源和树莓派引脚的通断。第一个继电器控制树莓派的一个GPIO信号。树莓派的这个GPIO拉高后,平时是不通的,也就是GPIO一直是高电平,继电器闭合后,树莓派的这个GPIO接地,变成低电平,树莓派通过检测这个GPIO变成低电平来执行shutdown命令关闭树莓派。等待二分钟后,保证树莓派已经关机,就控制第二个继电器关闭树莓派电源。

NodeMCU检查网络断掉后,就认为已经断电,维持适当时间后,关闭树莓派。当来电后,nodemcu检查到网络联通后,就认为来电了,打开树莓派。

NodeMCU通过http协议去请求服务器的json数据,来控制继电器开关,进而控制树莓派电源。根据文档导入证书后,使用https协议连接不上,估计是内存不够。

2. motion使用

树莓派csi夜视摄像头

2.1 开始

执行raspi-config打开csi摄像头

执行raspistill -o test.jpg拍张照片测是摄像头是否可用

2.2 摄像头参数

帧速 30FPS 最高分辨率 2592*1944

2.3 motion安装配置

1.apt-get -y install motion

2.motion中默认配置的设备是videodevice /dev/video0

执行motion命令后,会提示motion找不到divice

motion文档中 https://motion-project.github.io/motion_config.html 的方法

nano /etc/modules
bcm2835-v4l2
reboot

3.nano /etc/default/motion

start_motion_daemon=yes

4.nano /etc/motion/motion.conf

配置好的motion具有可以从网络查看录像,自动保存有运动物体的照片到文件夹,等功能

daemon on
stream_port 8081 #视频流端口
stream_localhost off #本地视频流禁止
webcontrol_port  0 #关闭web control
webcontrol_localhost on
webcontrol_html_output on
width 2592 #最高分辨率图像
height 1944 #实测证明,motion对不同的分辨率会裁剪一部分,模糊一点。
framerate 30 #为了省硬盘可以设的很小
threshold 50000 #发生变化的像素数,如果有超过这个像素数的图像发生了变化,系统就会开始录像,自然这个值要根据你的摄像头的分辨率而定,自然这个值越小越灵敏,建议设置到1%以上,否则容易有很多虚警。
lightswitch 15  #忽略光线变化范围的比率,motion会忽略在这个面积范围以内的光线变化
minimum_motion_frames 1 #忽略运动的帧数,让motion只有在连续几帧以上发现运动的时候才会开始录像
pre_capture 2 #记录下开始运动前的两帧图像
ffmpeg_output_movies off #不保存视频
locate_motion_mode on #给运动物体用方框标出
target_dir /data/motion_save #图片保存的路径
stream_maxrate 30 #这个设置大些,网络监控会比较流畅
stream_motion off #没有检测到运动时,帧率是否保持为1fps
picture_filename %Y%m%d/%v-%Y%m%d%H%M%S-%q #按天分文件夹存储
stream_quality 20 #默认50,网络摄像头传输质量,由于分辨率很大,设置小一些比较流畅
# 0 = disabled
# 1 = Basic authentication
# 2 = MD5 digest (the safer authentication
stream_auth_method 0 #开启密码认证,实践证明,2的话,有时候明明密码是对的,却让你重新输入。
stream_authentication #网页查看摄像头的用户名和密码

5.启动motion

# 停止motion
ps -ef|grep motion|grep -v grep|awk '{print $2}'|xargs kill -9
# 启动motion
motion

3. flask web

下来看看页面

1.使用两个舵机组成云台控制摄像头。

RPi.GPIO库也能控制舵机,不过会有抖动,这是software pwm。需要hardware pwm。RPIO库利用 DMA 为 Raspberry Pi 实现 PWM,不再抖动。

RPIO.PWM provides PWM via DMA for the Raspberry Pi, using the onboard PWM module for semi-hardware pulse width modulation with a precision of up to 1µs.
​ With RPIO.PWM you can use any of the 15 DMA channels and any number of GPIOs per channel. Since the PWM is done via DMA, RPIO.PWM uses almost zero CPU resources and can generate stable pulses with a very high resolution. RPIO.PWM is implemented in C (source); you can use it in Python via the provided wrapper, as well as directly from your C source.

按照作者说明安装,会报错

git clone https://github.com/metachris/RPIO.git
cd RPIO
sudo python setup.py install
RPIO 0.10.1报错SystemError: This module can only be run on a Raspberry Pi!

需要安装https://github.com/metachris/RPIO/tree/v2

git clone https://github.com/metachris/RPIO/tree/v2
cd RPIO-2/
python3 setup.py install

2.安装相关库

apt-get -y install python3-flask
pip3 install flask_wtf
pip3 install flask_login

3.为了节省资源,没有安装数据库,把用户名和密码的hash信息放到了文件里。

4.uwsgi部署flask

# 安装
pip3 install uwsgi
# 这样就能启动了
uwsgi --socket 0.0.0.0:5000 --protocol=http -w run_manager:app

配置uwsgi服务

[Unit]
Description=uwsgi instance to serve manager
After=network.target

[Service]
User=root
Group=root
RestartSec=30
Restart=on-failure
WorkingDirectory=/raspi2/webs/manager
ExecStart=/usr/local/bin/uwsgi --ini uwsgiconfig.ini --protocol=http
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target
[uwsgi]
# uwsgi 启动时所使用的地址与端口
socket = 0.0.0.0:5000
# 指向网站目录
chdir = /raspi2/webs/
# python 启动程序文件
wsgi-file = run_manager.py
# python 程序内用以启动的 application 变量名
callable = app

master=true # 启动主线程
processes=2 # 设置工作进程的数量
threads=2 # 设置每个工作进程的线程数

5.uwsgi线程阻止关机

谷歌了一下,没有找到解决办法,只能hack的方法解决了,关机前把uwsgi结束任务。

touch /usr/local/bin/cleanup.sh
chmod a+x /usr/local/bin/cleanup.sh
nano /usr/local/bin/cleanup.sh
ps -ef|grep uwsgi|grep -v grep|awk '{print $2}'|xargs kill -9

nano /lib/systemd/system/cleanup.service

[Unit]
Description=Run command at shutdown
Requires=network.target
DefaultDependencies=no
Conflicts=reboot.target
Before=shutdown.target

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/true
ExecStop=/bin/bash /usr/local/bin/cleanup.sh

[Install]
WantedBy=multi-user.target

6.motion的监控页面通过iframe直接嵌入到自己的web界面中,不能改变大小,有cross domain的问题,所以使用flask代理motion监控页面,同时还省去了motion的密码配置,使用flask统一认证。

@app.route('/motion')
@login_required
def motion():
    req = requests.get("http://127.0.0.1:8081", params=request.args, stream=True)
    return Response(stream_with_context(req.iter_content(chunk_size=1024)), content_type=req.headers['content-type'])

7.树莓派的nginx代理flask web

server {
 listen xxx;
 server_name flaskweb.site;

 location ^~ / {
  proxy_pass http://127.0.0.1:5000/;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 }

4. frp内网穿透

4.1 服务器frps

1.安装frps

wget https://github.com/fatedier/frp/releases/download/v0.21.0/frp_0.21.0_linux_amd64.tar.gz
tar -zxvf frp_0.21.0_linux_amd64.tar.gz -C /apps
cd /apps/frp_0.21.0_linux_amd64

2.配置frps

nano frps.ini

[common]
bind_addr = 0.0.0.0
bind_port = xxx
token = xxx

3.打开相应端口

ufw allow xxx #frps的bind_port
ufw allow xxx #代理frpc的端口
ufw reload

4.配置服务

nano /etc/systemd/system/frps.service

[Unit]
Description=frps daemon

[Service]
ExecStart=/apps/frp_0.21.0_linux_amd64/frps -c /apps/frp_0.21.0_linux_amd64/frps.ini
Restart=always

[Install]
WantedBy=multi-user.target

4.2 树莓派frpc

1.安装frpc

wget https://github.com/fatedier/frp/releases/download/v0.21.0/frp_0.21.0_linux_arm.tar.gz
tar -zxvf frp_0.21.0_linux_arm.tar.gz -C /apps

2.配置frpc

[common]
server_addr = xxx.com
# bind_port
server_port = xxx
token = xxx
# 表示自动重试
login_fail_exit = false

[flask_web]
type = tcp
# 本地flask_web端口
local_port = xxx
# 服务器代理树莓派flask_web的端口
remote_port = xxx
# 是否开启加密
use_encryption = true
# 是否开启压缩
use_compression = true

3.配置服务

nano /etc/systemd/system/frpc.service

[Unit]
Description=frpc daemon
After=network.target

[Service]
ExecStart=/apps/frp_0.21.0_linux_arm/frpc -c /apps/frp_0.21.0_linux_arm/frpc.ini
Restart=always

[Install]
WantedBy=multi-user.target

5. 服务器配置域名访问

配置好frp就可以外网访问了,只是通过服务器ip:端口这种形式访问,下面配置域名访问。

服务器nginx配置

server {
	listen 80;
	server_name xxx.xxx.com;
	return 301  https://$server_name$request_uri;
}
server {
	listen 443 ssl;
	server_name xxx.xxx.com;

	location ^~ / {
	    # 由于我使用的是nginx的docker,172.18.0.1是网桥,访问它相当于访问主机
	    # 21024是服务器frps代理端口
		proxy_pass http://172.18.0.1:21024/;

		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	}
}
Copyright © 2021,枫糖, 版权所有,禁止转载、演绎、商用。