Zabbix Agent 主机变身 FSU,可以通过 RS485 以 Modbus 协议读取温湿度,充分扩展 Zabbix 的动环监控能力。

工作原理

20220808222957

串口读 Modbus 协议数据,将其写入 Redis 中,Zabbix Server 请求 Zabbix Agent 读 Redis 中数据。引入 Redis 主要为了解耦,避免多个进程同时读串口造成冲突。

这里 Zabbix Agent 作为 Modbus RTU 主站,每个传感器作为一个单独的 Modbus RTU 从站,在一条 485 总线上,站号唯一,所以主站可以通过轮询的方式向从站读取数据。

材料准备

硬件准备

  • 树莓派或其他开发板,甚至是 x86 工控机,只要有多路串口就行(我以树莓派 3B+为例)
    20220808220459
  • RS485 温湿度模组(我以 2 个模组为例)
    20220808220551
  • TTL 转 485 转接板(树莓派默认是 TTL 电平,需要转换成 485 电平)
    20220808220658
  • USB 转 485 调试器(主要方便调试)
    20220809073301
  • 线缆若干,485 通信线建议为双绞线

软件准备

  • 树莓派系统选择 RPIOS,即为 Debian11
  • 安装 Zabbix Agent 6.0 LTS
  • 安装 Redis

传感器配置

使用 USB 转 485 模块直连传感器,方便刷写 485 站号和做简单的功能验证。

对单个传感器刷写站号,根据我买到的传感器文档中定义,传感器的 485 站号是存在地址为 10 的保持寄存器中的。需要特殊标记每个传感器的站号,需要根据站号采集温湿度值。

20220808233629

根据 Modbus 协议,写保持寄存器的功能码是 0x06,我们可以使用 Modbus 调试工具使用该功能码写保持寄存器来刷写站号。

继续读文档,根据文档定义,传感器的温湿度数据保存在只读的输入寄存器中,寄存器起始地址为 0 长度为 2,且实际值=寄存器值*0.1。

20220808234230

根据 Modbus 协议,读输入寄存器的功能码是 0x04,这个功能码和寄存器我们后面写串口通讯程序时要用到,所以应该提前关注一下。

下面可以连线了,如图连接即可。

20220809193652

树莓派的 4 引脚为 5V+ 接 TTL 转 485 的 VCC 脚,5 引脚为 GND 接 TTL 转 485 的 GND 脚。8 为串口 TXD 接 TTL 转 485 的 RXD 脚,10 为串口 RXD 接 TTL 转 485 的 TXD 脚。

TTL 转 485 的 AB 和 GND 接法,GND 接传感器 GND,A+接传感器 A+,B+接传感器 B+,传感器的 VCC 从 TTL 转 485 的 VCC 引脚取电。

额外提一下:若 485 总线过长,需要在总线起点、终点应加终端电阻(120Ω)。485 长度可以达到 2km,但测点线要小于 1m(布线不规范,会造成通讯不稳定)。下图红色线为总线,绿色线为测点线。当系统中测点大于 30 个点时,考虑到总线驱动能力,建议每 20 点增加一个中继器,进行信号增强。

20220809200538

树莓派配置

禁用 wifi 和蓝牙串口

vim /boot/config.txt,增加以下配置项目。重启后生效。

1
2
3
dtoverlay=pi3-disable-wifi
dtoverlay=pi3-miniuart-bt
force_turbo=1

这样的操作主要是为了避免蓝牙和 Wifi 影响板载串口。

安装 redis

可参考 redis 官方手册进行安装。

1
2
3
4
5
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
apt-get install redis
systemctl enable redis-server
systemctl start redis-server

使用 redis-cli 登录,发送 ping,系统回复 pong,则 redis 服务正常。

安装 python 依赖

1
pip install serial redis modbus_tk

脚本编写

编写一个程序,轮询读取 Modbus 数据并存储到 redis 中,正常应该能打印出两个温湿度模块的温湿度值,并且可以通过 redis-cli 中的 get 方法提取到传感器值。

文中注释和提示请根据实际情况进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import serial
import redis
import time
import modbus_tk.modbus_rtu as rtu
import modbus_tk.defines as cst


def initSerial():
try:
# 树莓派的串口号
serial0 = "/dev/serial0"
ser = serial.Serial(port=serial0,
baudrate=9600,
bytesize=8,
parity="N",
stopbits=1)
if ser.isOpen():
print(serial0, "is Working...")
return ser
except Exception as e:
print("initSerial Error: ", e)
exit()


def initRedis():
try:
red = redis.Redis(host='127.0.0.1', port=6379, decode_responses=True)
pong = red.ping()
if pong:
print("Redis-Server", "is Working...")
return red
except Exception as e:
print("initRedis Error: ", e)
exit()


if __name__ == "__main__":
# init
ser = initSerial()
red = initRedis()

# ModBUS Master
master = rtu.RtuMaster(ser)
master.set_timeout(1.0)
master.set_verbose(True)

while (1):
# 这里 range() 是站号的循环,我的站号是 8 和 9
for site in range(8, 10):
# 读输入寄存器,首地址是 0,长度为 2
rv = master.execute(site, cst.READ_INPUT_REGISTERS, 0, 2)
# 地址 = 0 是温度
temperature = rv[0] / 10
# 地址 = 1 是湿度
humidity = rv[1] / 10
print("站", site, ": ")
red.set('site-' + str(site) + '-temperature', temperature, ex=30)
red.set('site-' + str(site) + '-humidity', humidity, ex=30)
print('温度', temperature, '湿度', humidity)
time.sleep(2)

编写 dht-read 脚本,从 redis 中读温湿度值,将其另存在树莓派中,文件名为 /etc/zabbix/scripts/dht-read.py。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys
import redis

def initRedis():
try:
red = redis.Redis(host='127.0.0.1', port=6379, decode_responses=True)
pong = red.ping()
if pong:
# print("Redis-Server", "is Working...")
return red
except Exception as e:
print("initRedis Error: ", e)
exit()

if __name__ == "__main__":
type = sys.argv[1]
site = sys.argv[2]
red = initRedis()
value = red.get('site-' + str(site) + '-' + type)
print(value)
red.disconnect()

Zabbix 配置

启动采集进程。若需要开启启动可加入 /etc/rc.local 中。

1
nohup /usr/bin/python /home/pi/dht-modbus/main.py

配置自定义监控项,修改 zabbix_agentd.conf,增加以下配置项目。

1
2
UnsafeUserParameters=1
UserParameter=dht.read[*], /usr/bin/python /etc/zabbix/scripts/dht-read.py $1 $2

重启 zabbix_agent。

正常情况,我们可以通过 zabbix_get 命令远程读取传感器的值。

1
zabbix_get -s RPI-FSUIP -p 10050 -k 'dht.read[type,site]'

这里 RPI-FSUIP 是树莓派的 IP,type 可选 temperature,humidity,site 为 485 站号。

20220809001709

在 ZabbixWeb 中,将树莓派增加为主机,接口为客户端。

20220809001911

添加自定义监控项。类型为客户端,信息类型为浮点数,键值类似于 dht.read[type,site]。type 可选 temperature,humidity,site 为 485 站号。

20220809001944

效果展示

添加完毕效果:

20220809002046

20220809002235

历史数据视图效果:

20220809002321

Next

下一步会继续集成烟感、漏水等传感器。