0x01 前言

最近突发奇想,想用智能电表监控机柜的用电情况和电力输入质量。经过考量后,我决定采用Modbus协议。

得益于该协议的成熟性,目前支持Modbus协议的电表已经非常便宜,所以我购买了一整套用于动力系统改造的东西。

“动力系统”这个词语非常高大上,其实在我这里仅仅是很简单的一个电力分配单元,而在数据中心中则要复杂得多。

注意!除非你有强电的基础知识,否则请勿尝试重复我的实验!这可能会给你或他人带来生命危险!

0x02 硬件

上一张简单的电路图:

电工知识大多还给老师了,上图只能将就点看。

首先220V交流电接入2P空气开关的输入端,然后从输出端输出并连接至智能电表的输入端,电流流经电表后通过电表的输出端输出并连接至3P插座,为了安全,还需要连接3P插座中的地线。

空气开关我选用德力西的2P空气开关,额定电流为20A:

空气开关的主要作用是防止电流过大,当电流超过空气开关的额定电流后就会跳闸。

这里有一点要注意的,买空气开关的时候一般会有3种选择:

  • 1P
  • 1P+N
  • 2P

1P只控制火线的分合;1P+N中的N总是保持为通路状态,且只能接零线;而2P则可以同时控制火线与零线的开合。另外1P+N和2P一般同时具备漏电保护功能。

其实三者的价格相差几块而已,所以我选择2P的开关。

空气开关后面是一个智能电表,这类的电表很多,价格基本在150以上:

因为是家用的,所以功能比较少,只有基本的功能:电压、电流、频率、有功功率、用电量与功率因数的监控。如果大家感兴趣,可以了解下施耐德的相关产品。

我选择的这个产品使用RS-485接口与Modbus RTU协议。因为我无法直接与Modbus RTU通讯,所以还需要一个网关,将Modbus RTU协议转换为Modbus TCP,这样就可以通过网线直接读取数据:

选择网关的时候要注意选购支持web GUI配置的产品,价格会根据接口数量的不同而不同。

最后,还需要一根导轨和若干插座:

以下是接线部分的图片,技术不太好,虽然不好看,但也能用:以下是通电后的情况:

0x03 Modbus 网关配置

首先是电力分配:

因为有2个插座,根据我的计划,其中一个会接PDU,该PDU上的设备由市电供电;另一个插座连接UPS的输入端,为UPS供电。UPS输出端连接PDU,该PDU上的设备由UPS供电。

在取值之前需要将Modbus网关和智能电表的RS-485接口相连接,RS-485接口一般采用两线制,支持半双工网络。这两根线不能接反,因为两根线传输的是0与1的逻辑信号,连接线接反后会导致无法通讯。

我是用网线的其中4根线作为信号线,如下图所示:

电源与网络端口在另一侧:

完成连接后即可通过浏览器登入管理界面:

因为每个厂商的登入方式和界面都不一样,所以上图仅代表我家中的设备。

从图中可以看到有我的这个网关有2个串口,也就是支持2个设备接入。点击模式设置后如下图:

COM1只支持RS-232接口,COM2则是RS-485接口。

在这里我需要将该接口设置为Modbus RTU Slave模式以便从智能电表读取数据,在默认情况下,ModBus TCP的端口应该为502,不过在这里我是用网关默认的8002。

至于上位机的配置信息保持默认即可,在这里我没有上位机,所以没多大用处。

完成模式设置后再进入串口设置的界面:

我这个智能电表的默认波特率为9600,数据位为8,奇偶校验需要选择Even,停止位为1。至于时间间隔与超时的配置无果没特殊要求,保持默认即可。

因为这个网关功能比较弱,高端点的网关可以配置的内容会比较多,这一般支持多个节点。如果对这方面感兴趣的朋友可以自行了解相关的知识。

至此已完成Modbus硬件的配置。

0x04 测试

Modbus RTU是一个很成熟的协议,简单来说网关是Master,而只能电表为Slave,一台Master可以从多个Slave中取值。

这里有一点要注意的,如果需要从多个Slave中取值,需要注意网关的性能。性能低的话可能会导致取值失败甚至数值异常。

在这里我是用以下开源软件与网关通讯:

可以根据GitHub中的说明进行编辑安装:

 cd mbpoll
 mkdir build
 cd build
 cmake ..

我需要关注的数据的取值命令如下:

[[email protected] ~]# /usr/local/bin/mbpoll -r 1 -c 30 -a 1 -p 8002 -t 3:float -B -1 10.1.1.21
mbpoll 1.3-2 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright (c) 2015 epsilonRT, All rights reserved.
This software is governed by the CeCILL license <http://www.cecill.info>

Protocol configuration: Modbus TCP
Slave configuration...: address = [1]
                        start reference = 1, count = 30
Communication.........: 10.1.1.21, port 8002, t/o 1.00 s, poll rate 1000 ms
Data type.............: 32-bit float (big endian), input register table

-- Polling slave 1...
[1]: 	239.1
[3]: 	0
[5]: 	0
[7]: 	0
[9]: 	2.057
[11]: 	0
[13]: 	0
[15]: 	0
[17]: 	0
[19]: 	478.9
[21]: 	0
[23]: 	0
[25]: 	0
[27]: 	0
[29]: 	0
[31]: 	0
[33]: 	0
[35]: 	0
[37]: 	0
[39]: 	0
[41]: 	0
[43]: 	0.973
[45]: 	0
[47]: 	0
[49]: 	0
[51]: 	0
[53]: 	0
[55]: 	50
[57]: 	0
[59]: 	0

各个参数的含义如下:

  • -r 1:开始读取的寄存器编号
  • -c 30:连续读取30个寄存器的数据
  • -a 1:Slave 1
  • -p 8002:网关端口
  • -t 3:float:使用function code 3并以32bit 浮点数输出
  • -B:使用 Big-Endian
  • -1:这是数字一,仅读取一次

默认情况下一般是以function code 4获取寄存器的数据并输出,不同厂商的设备有不同的技术参数,具体请参考设备厂商的技术文档。

从上面返还的数据可以看出各个寄存器所存储的数据:

  • 寄存器-1:实时电压
  • 寄存器-9:实时电流
  • 寄存器-19:实时有功功率
  • 寄存器-43:功率因数
  • 寄存器-55:实时电频率

0x05 zabbix

获取到需要的寄存器编号后,需要将返还的数据中不必要的内容做个清理,例如寄存器编号为55的实时电频率:

[[email protected] ~]# /usr/local/bin/mbpoll -r 55 -c 1 -a 1 -p 8002 -1 -t 3:float -B 10.1.1.21 | grep '^\[' | cut -d : -f 2 | sed 's/^[ \t]*//g'
50

我只需要返还的数值,其他字符一律不要,因为我需要将这个数字写入zabbix,而且只有数字才能进行算数运算。

取得需要的数值后还需要建立一个自定义的zabbix item key文件,具体可以参考以下文章:

我的定义文件如下:

[[email protected] ~]# cat /etc/zabbix/zabbix_agentd.d/rack-modbus.conf 
UserParameter=rack-modbus-voltage,/usr/local/bin/mbpoll -r 1 -c 1 -a 1 -p 8002 -1 -t 3:float -B 10.1.1.21 | grep '^\[' | cut -d : -f 2 | sed 's/^[ \t]*//g'
UserParameter=rack-modbus-current,/usr/local/bin/mbpoll -r 9 -c 1 -a 1 -p 8002 -1 -t 3:float -B 10.1.1.21 | grep '^\[' | cut -d : -f 2 | sed 's/^[ \t]*//g'
UserParameter=rack-modbus-active-power,/usr/local/bin/mbpoll -r 19 -c 1 -a 1 -p 8002 -1 -t 3:float -B 10.1.1.21 | grep '^\[' | cut -d : -f 2 | sed 's/^[ \t]*//g'
UserParameter=rack-modbus-power-factor,/usr/local/bin/mbpoll -r 43 -c 1 -a 1 -p 8002 -1 -t 3:float -B 10.1.1.21 | grep '^\[' | cut -d : -f 2 | sed 's/^[ \t]*//g'
UserParameter=rack-modbus-frequency,/usr/local/bin/mbpoll -r 55 -c 1 -a 1 -p 8002 -1 -t 3:float -B 10.1.1.21 | grep '^\[' | cut -d : -f 2 | sed 's/^[ \t]*//g'

然后建立模板和host,如果一切正常,那么在Monitoring –> Latest data标签中即可看到相关的数据:

当然,不能总是打开这个页面查看数据。需要在模板中建立可视化图表,完成后再在Screens中建立相关的展示页面:

0x06 结语

经过几个小时的安装、配置与调试,终于完成了。最终将数据用grafana展示:

我还买了一个廉价的Dell显示屏,整体效果是这样的:

一个题外话:如果有大量出租屋的话,可以将电表和水表都换上支持Modbus RTU协议的智能水表,然后都连接到一条总线上,再通过技术手段监控计量数据,顺便写个脚本定时生成报表,这大大提升了效率。

当然,前提是要有大量的空闲房子。

最后:

注意!除非你有强电的基础知识,否则请勿尝试重复我的实验!这可能会给你或他人带来生命危险!