写点什么

树莓派上的家庭监控中心

用户头像
冯骐
关注
发布于: 2021 年 03 月 01 日
树莓派上的家庭监控中心

前言


上回在 树莓派上的温湿度环境监控 里提及过,Open-Falcon 也是可以直接装在树莓派上的。所以其实可以使用树莓派在家里做一个小型的监控中心,把相应的监控指标采集过来推给树莓派上的 Open-Falcon 就好了嘛


根据这个思路,我尝试了温湿度,PM2.5 和路由器这几块的监控,这里做个分享


环境


树莓派:RaspberryPi 3

温湿度传感器:DHT11,DS18B20

PM2.5 传感器:攀藤 PMS3003(G3)

路由器:华硕 RT-AC68U,华硕 RT-AC66U


安装 Open-Falcon


说到底,树莓派就是个 CPU 是 ARMv6 的 Linux 而已,所以我们只要准备好 ARMv6 上的 Golang 环境然后编译就好了

获取 golang 的二进制包


wget https://storage.googleapis.com/golang/go1.9.linux-armv6l.tar.gz
复制代码

解压


tar -C /usr/local -xzf go1.9.linux-armv6l.tar.gz
复制代码

配置环境(永久生效应该写道 profile 里去)


export PATH=$PATH:/usr/local/go/binexport GOPATH=/usr/local/gopath
复制代码


# go versiongo version go1.9 linux/arm
复制代码

然后编译 Open-Falcon 就好了~

环境准备,Raspbian 是基于 Debain 魔改的,因此是 apt-get 系统


apt-get install mysql-serverapt-get install redis-server
复制代码


mkdir -p $GOPATH/src/github.com/open-falconcd $GOPATH/src/github.com/open-falcongit clone https://github.com/open-falcon/falcon-plus.git
cd $GOPATH/src/github.com/open-falcon/falcon-plus/scripts/mysql/db_schema/mysql -h 127.0.0.1 -u root -p < 1_uic-db-schema.sqlmysql -h 127.0.0.1 -u root -p < 2_portal-db-schema.sqlmysql -h 127.0.0.1 -u root -p < 3_dashboard-db-schema.sqlmysql -h 127.0.0.1 -u root -p < 4_graph-db-schema.sqlmysql -h 127.0.0.1 -u root -p < 5_alarms-db-schema.sql
cd $GOPATH/src/github.com/open-falcon/falcon-plus/
# make all modulesmake all
# make specified modulemake agent
# pack all modulesmake pack
export WorkDir="$HOME/open-falcon"mkdir -p $WorkDirtar -xzvf open-falcon-vx.x.x.tar.gz -C $WorkDircd $WorkDir
cd $WorkDir./open-falcon start
复制代码

当然还有 Dashboard


export HOME=/home/work/
mkdir -p $HOME/open-falcon/cd $HOME/open-falcon && git clone https://github.com/open-falcon/dashboard.gitcd dashboard;
apt-get install -y python-virtualenvapt-get install -y slapd ldap-utilsapt-get install -y libmysqld-devapt-get install -y build-essentialapt-get install -y python-dev libldap2-dev libsasl2-dev libssl-dev
cd $HOME/open-falcon/dashboard/virtualenv ./env
./env/bin/pip install -r pip_requirements.txt -i https://pypi.douban.com/simple
复制代码



是不是很亲切?


环境监控


温湿度监控


温湿度监控用 DHT11 ,我觉得这个精度已经够用了。我这里放了一个 DS18B20 作为对比,可以看一下两者的温度精度差异。



温湿度监控的具体实现可以看 树莓派上的温湿度环境监控 。


PM 2.5 监控


空气中的颗粒度浓度也是我们很关心的指标。这里用了攀藤的 G3 来做。


image.png

针脚说明


PIN 定义说明


连接


再次祭出树莓派针脚图



连接就很简单了


PMS3003Raspbian Pi 3Pin1 接 5V ,例如 Pin2Pin2 接地,例如 Pin6Pin3 设置口,随便接个,例如 Pin11(GPIO17),或者悬空。Pin5 数据接收口,接 Pin8


串口


PMS3003 的数据是通过串口来传输的,因此我们需要配置一下树莓派,把串口功能打开,由于树莓派的串口略坑,稍微扯点题外话:


大家知道 Unix 一切为文件,因此串口的驱动会创建对应的字符设备(文件)以供读写。通常这些设备是以类型+序号来命名。


例如:x86 架构下串口通常命名为 /dev/ttyS0(Serial 0),大家可以找台 x86 的 Linux 服务器去看看。 Raspbian 是 ARM 架构的因此其串口命名为 /dev/ttyAMA0(TeleTyper ARM UART 0)


然而在 Raspbian Pi 3 上,这里情况就不太一样了。Pi3 的 /dev/ttyAMA0 被蓝牙给默认占用了, 于是它给出一个 /dev/ttyS0 设备用于软串口的 Mini UART。 然后为了使得新老 Raspbian Pi 之间的兼容性 ,又把 3 代之前版本 的 /dev/ttyAMA0 和 Raspberry Pi 3 的 /dev/ttyS0 软链接到同一个 /dev/serial0 。这样子绕了一圈,然而Minu UART 的性能又是相当令人捉急的。。。


因此我们得调整一下配置,把默认的 /etc/ttyAMA0 给搞回来。


启用 UART,修改/boot/config.txt,增加(新版 Raspbian 已经默认开启了)


enable_uart=1
复制代码

关掉默认的 console


sudo systemctl disable serial-getty@ttyS0.service
复制代码

在启动脚本/boot/cmdline.txt里干掉 console=ttyAMA0 或者 console=ttyS0 的配置,类似这样


dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline ...
复制代码

关掉蓝牙


dtoverlay=pi3-disable-bt 
复制代码

重启之


数据传输


PMS3003 的数据格式如下所示


数据功能


可以看到,一个完整的数据包长度一共是 24 个字节,我们不妨先看一下他的数据到底长什么样子。

写一段简单的串口读取代码


#!/usr/bin/pythonimport serialimport time

def pm(): ser = serial.Serial("/dev/ttyAMA0", 9600) while True: time.sleep(1) # 等个 1 秒钟等数据进来 count = ser.inWaiting() if count >= 24: # 由于一个完整的数据包长度是24个字节,因此等到缓冲区字节数超过 24 个了,开始读取。 recv = ser.read(count) # 读取数据 # 这里如果直接 print recv 肯定是一堆无意义的乱码,即便 print repr(recv), # 由于 python 默认的 ACSII 编码,他还是会把其中一部分字符给编码成字符打印出来, # 所以要看到原始的 16 进制报文,得额外处理一下 print map(lambda c: hex(ord(c)), recv) # 按 16 进制格式打印接受到的数据 ser.flushInput() #读完了清掉缓冲区 ser.close() return
if __name__ == '__main__': pm()
复制代码

执行之


# python pm25_test.py['0x42', '0x4d', '0x0', '0x14', '0x0', '0x4e', '0x0', '0x6d', '0x0', '0x78', '0x0', '0x33', '0x0', '0x48', '0x0', '0x50', '0x10', '0x44', '0x0', '0x30', '0x91', '0x0', '0x3', '0xb6']
复制代码

可以看到,起始符分别为 0x420x4d,然后是高低位的帧长度 = 20(24 个字节去掉 2 个字节起始符和高低位 2 个字节的帧长度)。接着是 2 个字节一组的数据,一共 9 个。最后是校验和,高位 0x3,低位 0xb6,也就是校验和为 0x3b6。

我们来尝试计算一下校验和


root@raspberrypi:/opt/falcon-scripts# pythonPython 2.7.9 (default, Sep 17 2016, 20:26:04)[GCC 4.9.2] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> a = 0x42 + 0x4d + 0x0 + 0x14 + 0x0 + 0x4e + 0x0 + 0x6d + 0x0 + 0x78 + 0x0 + 0x33 + 0x0 + 0x48 + 0x0 + 0x50 + 0x10 + 0x44 + 0x0 + 0x30 + 0x91 + 0x0>>> print hex(a)0x3b6>>>
复制代码

校验和正确,所以这组数据是正确的,可以被接收的。


因此 PM2.5 等的数据采集大体是这个逻辑。由于我们是每分钟定期采集一次数据,没有必要实时的去处理串口的数据流(实际上 PMS3003 也是间隔 200ms ~ 800ms 定期往串口发数据)。只要在开始采集的时候等待上 1 秒钟,等到有至少 24 个字节输入进入后进行处理即可。

对于数据异常,例如起始符不正确,校验和不正确等数据,直接抛弃等下一轮就好了。


完整代码


#!/usr/bin/python#encoding=utf-8import serialimport timeimport jsonimport requestsimport copy

def pm(): ser = serial.Serial("/dev/ttyAMA0", 9600) while True: time.sleep(1) count = ser.inWaiting() if count >= 24: recv = ser.read(count) data = map(lambda c: ord(c), recv) # 上面写 hex() 是为了打印出来方便人看,实际运行就不需要了,不然后面还得转换 if check_data(data) != True: # 数据校验不合法,抛弃之等下一轮 ser.flushInput() continue return get_data(data) # 读到数据了直接返回退出循环 ser.flushInput() ser.close() return 0,0,0
def check_data(data): sum = 0x00 if data[0] != int('0x42',16): # 起始符校验 return False if data[1] != int('0x4d',16): return False for d in data[0:21]: sum = sum + d check_sum_high = data[22]<<8 # 校验和校验,位移 8 位到高位 check_sum_low = data[23] check_sum = check_sum_high | check_sum_low # 按位或运算,高低位合并 if sum == check_sum: return True return False
def get_data(data): pm1 = (data[10] << 8) | data[11] # 高位位移,按位或运算合并高低位 pm2_5 = (data[12] << 8) | data[13] pm10 = (data[14] << 8) | data[15] return pm1,pm2_5,pm10
def push_falcon(value_name,value): ts = int(time.time()) push_url = "http://127.0.0.1:1988/v1/push" payload = [{"endpoint":"home","metric":"room.air_quality","timestamp":ts,"step":60,"value":value,"counterType":"GAUGE","tags":"module="+value_name}] r = requests.post(push_url, data=json.dumps(payload))
if __name__ == '__main__': pm1, pm2_5,pm10 = pm() push_falcon("pm1",pm1) push_falcon("pm2.5",pm2_5) push_falcon("pm10",pm10)
复制代码

效果如下所示



如果要控制 PMS3003 的工作状态的话,可以通过调节他的 Pin3,也就是 set 口。可以让他处于待机状态。但注意转入工作状态之后,要至少工作 30 秒以上,读取的数据才比较准确。


import RPi.GPIO as GPIOimport timepin = 17 # 11管脚对于的BCM管脚号码GPIO.setmode(GPIO.BCM)GPIO.setup(pin, GPIO.OUT) # 写入 GPIOGPIO.output(pin, GPIO.HIGH) # 工作GPIO.output(pin, GPIO.LOW) # 待机
复制代码

路由器监控


监控路由器,那肯定是走 snmp 了。虽然在路由器的环境里(例如 RC-66U,openwrt 系统, cpu MIPS 指令集) 应该也能够编译出 golang 来 go-mips32 ,但是考虑到易用性和减少路由器的资源占用,肯定还是开启路由器的 net-snmp 比较合适。


以华硕的 RT-AC66U 和 RT-AC68U 为例。


开启 snmp —— 官版系统


华硕的官版固件默认并没有开启 snmp,如果要开启的话需要有一个曲折的过程~


  1. 首先找一个 U 盘插上路由器

  2. 在路由器后台里开启 Download Master (为了激活 ipkg 包管理器),并开启 telnet

  3. 安装 net-snmp


ipkg install net-snmpapp_set_enabled.sh net-snmp yes
复制代码

这一步过程中,有很大概率遭遇不可描述的网络故障导致网络连接异常下载失败

可能需要通过一些不可描述的方法来规避网络连接的异常


  1. 如果成功了,就可以 snmpwalk -v 2c -c public 192.168.1.1 测试了


开启 snmp —— 梅林


更省事的办法是用 梅林 的系统。话说都买了华硕的路由器了,不刷个梅林好意思么?


刷完梅林之后,直接在路由器 web 后台就能够开启 snmp


监控 - swcollector


要在 open-falcon 下的通过 snmp 监控路由器的话,自然考虑用 swcollector 了。这篇文章也可以提供参考 Open-Falcon 中的交换机监控


在编译 swcollector 之前,我们不妨先 snmpwalk 测试一下我们的路由器,以防踩坑,比如:

1 号坑:


root@raspberrypi:/home/pi# snmpwalk -v 2c -c public 192.168.2.2 1.3.6.1.2.1.31.1.1.1.15iso.3.6.1.2.1.31.1.1.1.15.1 = Gauge32: 10iso.3.6.1.2.1.31.1.1.1.15.2 = Gauge32: 10iso.3.6.1.2.1.31.1.1.1.15.3 = Gauge32: 0iso.3.6.1.2.1.31.1.1.1.15.4 = Gauge32: 0iso.3.6.1.2.1.31.1.1.1.15.5 = Gauge32: 10iso.3.6.1.2.1.31.1.1.1.15.6 = Gauge32: 10iso.3.6.1.2.1.31.1.1.1.15.7 = Gauge32: 0root@raspberrypi:/home/pi# snmpwalk -v 2c -c public 192.168.2.2 1.3.6.1.2.1.2.2.1.5iso.3.6.1.2.1.2.2.1.5.1 = Gauge32: 10000000iso.3.6.1.2.1.2.2.1.5.2 = Gauge32: 10000000iso.3.6.1.2.1.2.2.1.5.3 = Gauge32: 0iso.3.6.1.2.1.2.2.1.5.4 = Gauge32: 0iso.3.6.1.2.1.2.2.1.5.5 = Gauge32: 10000000iso.3.6.1.2.1.2.2.1.5.6 = Gauge32: 10000000iso.3.6.1.2.1.2.2.1.5.7 = Gauge32: 0
复制代码

好嘛,无论是 ifSpeed 还是 ifHighSpeed,这货返回的结果都根本不对嘛。这有点像是 net-snmp 的一个 bug。但是在 asuswrt-merlin 里,snmpd 已经是以 admin ,也就是 root 权限在跑了。所以具体原因也吃不太准,我在 github 上给 asuswrt-merlin 提了个 issue,希望能有个答案吧。


总之,这样的话我们就没办法愉快的监控了。因为 swcollector 自 4.0 版本起,就会根据 ifSpeed 的值对采集到的流量进行合法性判断,如果采集到的流量计算出来超过了接口的速率,讲被视作异常值而抛弃的。你这里给我来个统统 10M,这岂不是一开下载监控就要断流的节奏嘛。。。


这样只好人工设置 speedlimit 为 1G 了


"speedlimit":1000000000,
复制代码

除了常规的 cpu,内存,接口各种流量,包数之外。我们还可以通过自定义监控的方式来拿一些更多的信息,比如系统的 load 信息


{        "metrics":                [                        {                        "ipRange":[                   "192.168.2.1-192.168.2.3"                        ],                        "metric":"switch.system.load",                        "tag":"",                        "type":"GAUGE",                        "oid":"1.3.6.1.4.1.2021.10.1.3.1"                        }                ]}
复制代码

现在我们可以去 Open-Falcon 里看看我们监控的路由器了。欸?路由器的内存好像有点不太对?



没错,此处就是 2 号坑,net-snmp 在这里有内存泄露,如果你这么就一直跑下去,路由器倒是不会死球,snmpd 肯定是妥妥的会死球无响应的。


解决的办法只能是在路由器上起一个定时任务,每天半夜重启一下 snmpd 咯


admin@RT-AC66U-F5C8:/usr/sbin# crontab -e0 5 * * * service restart_snmpd
复制代码

同时把我们监控的采集周期调高到 5 分钟,避免一个晚上他内存就炸了,好歹撑到凌晨内存释放


    "transfer": {        "enabled": true,        "addr": "127.0.0.1:8433",        "interval": 300,        "timeout": 1000    },
复制代码

好啦,现在监控木有什么问题了。我们会看到 ASUS 有以下这么些个接口


switch.if.In/ifIndex=1,ifName=loswitch.if.In/ifIndex=2,ifName=eth0switch.if.In/ifIndex=3,ifName=eth1switch.if.In/ifIndex=4,ifName=eth2switch.if.In/ifIndex=5,ifName=vlan1switch.if.In/ifIndex=6,ifName=vlan2switch.if.In/ifIndex=7,ifName=br0
复制代码

这些接口都是什么意思呢?这张 DD-WRT 的原理图可供参考。 ASUS 与此之的差异在于还有个 eth2 专门跑 WiFi 5G



所以接口的关系是这样的

接口功能


在路由器上,可以通过这个命令来进一步自定义配置


admin@RT-AC68U-AB48:/tmp/home/root# robocfgBroadcom BCM5325/535x/536x/5311x switch configuration utilityCopyright (C) 2005-2008 Oleg I. Vdovikin (oleg@cs.msu.su)Copyright (C) 2005 Dmitry 'dimss' Ivanov of "Telecentrs" (Riga, Latvia)
This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.
Usage: robocfg <op> ... <op>Operations are as below: show -- show current config showmacs -- show known MAC addresses showports -- show only port config switch <enable|disable> port <port_number> [state <enabled|rx_disabled|tx_disabled|disabled>] [stp none|disable|block|listen|learn|forward] [tag <vlan_tag>] [media auto|10HD|10FD|100HD|100FD|1000HD|1000FD] [mdi-x auto|on|off] [jumbo off|on] vlan <vlan_number> [ports <ports_list>] vlans <enable|disable|reset>
ports_list should be one argument, space separated, quoted if needed, port number could be followed by 't' to leave packet vlan tagged (CPU port default) or by 'u' to untag packet (other ports default) before bringing it to the port, '*' is ignored
Samples:1) ASUS WL-500g Deluxe stock config (eth0 is WAN, eth0.1 is LAN):robocfg switch disable vlans enable reset vlan 0 ports "0 5u" vlan 1 ports "1 2 3 4 5t" port 0 state enabled stp none switch enable2) WRT54g, WL-500g Deluxe OpenWRT config (vlan0 is LAN, vlan1 is WAN):robocfg switch disable vlans enable reset vlan 0 ports "1 2 3 4 5t" vlan 1 ports "0 5t" port 0 state enabled stp none switch enable
复制代码

运行截图




树莓派自身


当然还有树莓派自己的监控。这个 Open-Falcon 的 agent 就已经基本解决问题。我们再加一个小脚本来采一下树莓派的 cpu 温度就好了

树莓派的 cpu 温度可以在 /sys/class/thermal/thermal_zone0/temp 这里读到


root@raspberrypi:/opt/falcon-scripts# cat /sys/class/thermal/thermal_zone0/temp52615
复制代码

写个脚本推给 Open-Falcon


#!/usr/bin/python# -*- coding: utf-8 -*-
import requestsimport timeimport json
def get_Pitemp(): file = open("/sys/class/thermal/thermal_zone0/temp") temp = float(file.read()) / 1000 file.close() return temp
if __name__ == '__main__': temp = get_Pitemp() ts = int(time.time()) push_url = "http://127.0.0.1:1988/v1/push" payload = [{"endpoint":"raspberrypi","metric":"cpu.temperature","timestamp":ts,"step":60,"value":temp,"counterType":"GAUGE","tags":""}] r = requests.post(push_url, data=json.dumps(payload))~
复制代码



以上


参考文档


Falcon+

Falcon-Dashboard

Raspbian Jessie 的 GPIO 串口配置

Raspberry Pi 读取攀藤G3 PM2.5

PM2.5传感器PMS3003,同时能测PM1.0 PM2.5 PM10

Install and Configure SNMP on the Asus RT-AC66U Router

DD-WRT leading two separate networks (Asus RT-AC68)


原文于 2017 年 9 月首发于简书,搬家存档。

行文有微调。


发布于: 2021 年 03 月 01 日阅读数: 23
用户头像

冯骐

关注

教育行业码农 2020.06.19 加入

一个教育行业的码农

评论

发布
暂无评论
树莓派上的家庭监控中心