Zabbix中具有Megatec协议的集体农场监控UPS

有必要监视UPS动物园,Ippon,Powercom和Krauler可用。作为监视工具,使用了Zabbix。

自然,需要解决的问题是:1)价格便宜2)价格更低,因此带有SNMP模块的选件立即被拒绝。由于具有Ippon和APC的开发经验,因此决定使用串行端口连接。顺便说一句,二级市场上的APC以合理的价格提供了SNMP模块,但是对于便宜的UPS,我只能以11.2万卢布的价格找到新的模块。

在工作过程中,设置了以下附加任务:

  1. 查找并检查用于连接每个UPS的电缆,因为该套件中没有电缆
  2. 要实现某个模块,该模块一方面具有RS-232接口并了解与每个UPS的数据交换协议,另一方面具有网络接口并可以zabbix_trapper的形式发送数据。
  3. 测试数据收集和传输模型,部分代码以及数据格式。


在第二和第三段的实施过程中,我想在一个地方收集所有数据,这些数据将来将允许为m / c实现单独的设备。

因此:

  • 1.电缆

没有任何UPS的电缆。原则上,对于可以计算DB9连接器上的联系人的人员而言,第一个任务不会出现问题。事实证明,不仅包括我在内,不仅每个人都知道如何做。F和M连接器上的触点是镜像的,但已签名,如果小心,通常不会出错。



一个小的题外话。服务器的骨干网由两个Vmware ESXi主机组成,它们被容纳在具有两个UPS的机架中。某些服务器有2个电源。不幸的是,一部分只是其中之一,这就是为什么他们经常遭受痛苦。 Zabbix当前作为虚拟机托管在其中一台主机上。原则上,在Ubuntu上部署小型虚拟服务器(我使用该平台提供服务)来实现任何任务都不是问题。

因此,方案如下:ESXi上的COM端口->虚拟机上的COM端口->从UPS返回数据的C程序->发送zabbix陷阱的脚本或程序。最后两点应在将来合并。虽然它像那样工作。

通过为一台UPS连接电缆,为服务器连接一个额外的连接器(其中有两个,再加上一个DB9的rj-45适配器),依次检查连接,检查程序,设置Zabbiks中的组件,依次解决了问题。

  • 2.程序对COM端口的询问

首先需要选择一个服务器来托管可执行代码。我没有绞尽脑汁,而是将所有这些发布到Zabbix服务器上。
其次,我考虑了如何处理数据。由于Bash的设计
array=( $(/home/appliance/uniups) )

将字符串分解为数据数组,我决定只返回字符串段MMM.M NNN.N PPP.P QQQ RR.R S.SS TT.T
程式码
#include <stdio.h>   /*   / */
#include <string>
#include <iostream>
#include <cstring>

using namespace std;
#include <unistd.h>  /*    UNIX */
#include <fcntl.h>   /*    */
#include <errno.h>   /*    */
#include <termios.h> /*   POSIX- */
#include <sys/types.h>
#include <sys/stat.h>

int fd; /*     */
char buf[512];/*      */
int main (int argc, char* argv[])
 {
    int iIn,iOut;
    string UPSAnswer;
    if (argc>=2)
{
        fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY); /*'open_port()' -    */
        if (fd == -1)   {
           printf("error port\n");
           perror("open_port: Unable to open port - ");   }
     else
        {
         struct termios options; /*   */
         tcgetattr(fd, &options); /*  */

         cfsetispeed(&options, B2400); /*  */
         cfsetospeed(&options, B2400); /*  */

         options.c_cflag &= ~PARENB; /*  */
         options.c_cflag &= ~CSTOPB; /* 2- ,  1 */
         options.c_cflag &= ~CSIZE; /*  */
         options.c_cflag |= CS8; /* 8*/
         tcsetattr(fd, TCSANOW, &options); /*  */
        }

        char Params[64];

        if(argc>=3)
        {
            if (!strcmp(argv[2],"status"))
            {
                iOut = write(fd, "Q1\r", 3);
                usleep(800000);
                if (iOut < 0)  fputs("write() of 4 bytes failed!\n", stderr);
                iIn=read(fd,buf,250); /*    */

                 strncpy(Params,&buf[38],11);
                 Params[46]=0;
            }
            else if (!strcmp(argv[2],"help"))
            {
                printf (" .   !\r\n");
            }
            else if (!strcmp(argv[2],"name"))
            {
                iOut = write(fd, "I\r", 3);
                usleep(800000);
                if (iOut < 0)  fputs("write() of 4 bytes failed!\n", stderr);
                iIn=read(fd,buf,250); /*    */
                strncpy(Params,&buf[0],60);

            }
            else if (!strcmp(argv[2],"stat2"))
            {
                iOut = write(fd, "F\r", 3);
                usleep(800000);
                if (iOut < 0)  fputs("write() of 4 bytes failed!\n", stderr);
                iIn=read(fd,buf,250); /*    */
                strncpy(Params,&buf[1],60);
         Params[20]=0;
            }
            else
            {
                printf ("? \r\n");
            }
        }
        else
        {
           /*    Q1 */
                usleep(1800);
                iIn=read(fd,buf,250);
                usleep(1800);
           iOut = write(fd, "Q1\r", 3);
           usleep(800000);
           if (iOut < 0)  fputs("write() of 4 bytes failed!\n", stderr);
           iIn=read(fd,buf,250); /*    */

           strncpy(Params,&buf[1],36);
           Params[36]=' ';
        }
    close(fd);
    printf("%s\r\n",Params);
}
else
printf("Usage %s /dev/ttySx", argv[0]);

}


我发现可以在Google中使用该端口,可以从Bash中读取内容,但是从Bash中无法实现稳定的操作。原则上,Linux中的C代码是b。首先对Ippon进行了测试,然后在研究Powercom UPS时启动了端口监视器,这表明PowerCom也可以通过Megatec协议工作,并且本机程序在启动时使用“ I”和“ F”命令轮询UPS,然后循环使用“ Q1”。我将端口名称挂在第一个参数上的形式为“ / dev / ttyS0”或“ / dev / ttyS1”,第二个参数允许您请求其他参数,代码显示。

在目录/ home / device /中放置了程序,称为uniups.cpp。已编译
g++ -o uniups uniups.cpp 


原则上,结果是这样的(是的,我是在根底下工作,甚至不发表评论)

root@zabbix:~# ./uniups /dev/ttyS0
204.4 204.4 204.4 035 49.9 54.8 54.5
root@zabbix:~# ./uniups /dev/ttyS0 name
I
root@zabbix:~# ./uniups /dev/ttyS1 name
#POWERCOM        SXL-2000A  LCD  V4.3
root@zabbix:~# ./uniups /dev/ttyS1
216.3 216.3 216.3 000 50.0 54.2 30.0
root@zabbix:~# ./uniups /dev/ttyS1 stat2
220.0 009 048.0 50.0
root@zabbix:~#

重要的是,最终所有的UPS都使用相同的协议,从而允许使用一个程序。使用2400、8N1上的连接,其他所有设备均关闭。美中不足的是,UPS的名称通常仅返回Powercom,Ippon无法理解“ I”命令,而Krauler返回“#R1.1.1”。

此外,在文档中,Krauler将电压返回至元件,将其余的UPS返回至电池。
SS.S或S.SS对于在线装置,电池电压/电池以S.SS的形式提供。对于备用设备,实际电池电压以SS.S形式提供

有鉴于此,我不得不在脚本上添加补丁。关于它下面。

  • 3.将数据发送到Zabbix

发送此消息后,所有场合都变成了动物园。在服务器上,Zabbix使用zabbix_sender实用程序来加快过程。
zabbix_sender -z _ -p 10051 -s ___ -k  -o 

原则上,对于轮询两个UPS,这已经足够了,但是,到现在,我将拥有第三个,而将来,我将拥有第四个,因此,我选择了第一个,并且偶然地,我选择了第二个Vmware主机上的唯一Linux服务器并将其发送到他的COM端口。

我没有使用zabbix代理或复制zabbix_sender,我发现后者的描述在

所有盐中都包含在Base64中编码数据。为了检查,我使用了命令

echo "<req>\n<host>S3JhdWxlck1lbW9SVDIwMDA=</host>\n<key>RnJlcQ==</key>\n<data>NDkuNA==</data>\n</req>\n" | nc -q 0 192.168.53.23 10051
其中192.168.53.23是Zabbix服务器的地址。她正在工作。
我调用了上面的脚本zabbix_sender.pl并将其放置在服务器上,我的脚本如下所示:
#!/usr/bin/perl

use IO::Socket;
use IO::Select;
use MIME::Base64;

my ($zabbixserver,$hostname,$item,$data) = @_;

$zabbixserver= @ARGV[0];
$hostname= @ARGV[1];
$item= @ARGV[2];
$data= @ARGV[3];

 my $timeout=10;
 my $request=sprintf("<req>\n<host>%s</host>\n<key>%s</key>\n<data>%s</data>\n</req>\n",
 encode_base64($hostname),encode_base64($item),encode_base64($data));

 my $sock = new IO::Socket::INET ( PeerAddr => $zabbixserver, PeerPort => '10051', Proto => 'tcp', Timeout => $timeout);
 die "Could not create socket: $!\n" unless $sock;
 $sock->send($request);
 my @handles=IO::Select->new($sock)->can_read($timeout);
 if (scalar(@handles) > 0)
 {
  $sock->recv($result,1024);
  print "answer from zabbix server $zabbixserver: $result\n";
 }
 else
 {
  print "no answer from zabbix server\n";
 }
 $sock->close();

Perl已经在服务器上。

接下来,我们需要一个脚本,该脚本将所有组件链接在一起,并可以放置在Cron中。

这是一个端口的示例,对于另一个端口,您可以简单地复制相同的代码并替换为不同的名称。我没有做周期,我几乎无法想象一辆有2个以上COM端口的汽车。

#!/bin/bash
array=( $(//uniups /dev/ttyS0) )
Names=( InVolt FaultVolt OutVolt Current Freq UBatt UTemp NA )
correct[5]="24.0"
j=0;
echo "Checking UPS on serial A - ${#array[@]}"
if  [ ${#array[@]} -gt "7" ]
then
param=""
for i in "${array[@]}"
do
   if [[ ${correct[$j]} ]]
      then
         param=$( echo "scale = 0; $i * ${correct[$j]}" | bc)
       else.
      param=$i
    fi
   //zabbix_sender.pl 192.168.53.23 KraulerMemoRT2000 ${Names[$j]} $param
   j=$j+1;
done
else
echo "No data on A"
fi


小意见:
  • 数组-UPS轮询程序返回的数组,名称-应该在具有相同名称的Zabbix服务器元素上启动名称为Item的数组。KraulerMemoRT2000-不间断的名称,必须与服务器上的主机名匹配。
  • , , Zabbix , , , NA, , , .
  • ${#array[@]}, . , . : , , . , , . , , .
  • 正确的[5] =“ 24.0”是如果UPS返回元件上的电压(电池电压/电池),则电池(阵列中的第5个元件)的电压校正。我电池中有6个元件,串联4个,总共24个。原则上,这在协议中进行了描述。我发现没有必要创建单独的元素,因为我拥有的所有UPS均受模板监控,并且均具有48伏特。当然,当监视不同电压的UPS时,有必要稍微改变其结构,最好将电池参数锤击服务器。


每执行一分钟,就会将上述脚本添加到cron中。本文不考虑Zabbix设置。

原则上就是这样。如果收集到的信息对某人有用,我将感到高兴。

Source: https://habr.com/ru/post/zh-CN397637/


All Articles