#!/usr/bin/perl
# Модуль осуществляет контроль состояния показателей управляемого оборудования (по SNMP) и рассылку сообщений о тревогах
# http://userside.ua/wiki/index.php/Manual_296 - информация о модуле
$zrevision = "12";
$zver = "us_control v.1.2." . $zrevision; #версия
# ============================================================================= 
use Net::SNMP;
use threads;
use DBI;
use Time::Local;
use FindBin;

$zpath = $FindBin::RealBin . '/';
require($zpath . 'us_config.tmp');

$ps_full_debug = 0;

$zmodule_param = 'M_CONTROL';

$zoid_by_thread = 500; #500 - оптимально

if ($zlost_count < 1) {
    $zlost_count = 5;
}
if ($zlost_count > 100) {
    $zlost_count = 100;
}
if ($isFixedAllLog ne 1) {
	$isFixedAllLog = 0;
}

if ($isFixedAllLog eq 1) {
	$allLogFileName = $ps_logpath . 'us_control_alllog.txt';
	open ($allLogFile, ">>" . $allLogFileName) || die;
	$allLogSqlFileName = $ps_logpath . 'us_control_alllog_sql.txt';
	open ($allLogFileSql, ">>" . $allLogSqlFileName) || die;
}

#Загружаем параметры
load_first_light();

#Загружаем настройки конфига
$ps_gl_snmp_com = '';
$ps_constr = "SELECT PARAM, VALUEINT, VALUESTR FROM tbl_conf";
$ps_dontsend_unact = 0;
$zisjabber = 0;
$zjab_field = 0;
printlog_sql_u($ps_constr);
    while (@ln = $rs->fetchrow_array()) {
        #Выясняем - нужно ли запускать модуль
        if ($ln[0] eq 'US_CONTROL') {
            $ps_module_allow = $ln[1];
        }
        if ($ln[0] eq 'CONTROL_DONTSEND_UNACT') {
            $ps_dontsend_unact = $ln[1];
        }
        if ($ln[0] eq $zmodule_param) {
            $ps_needversion = $ln[2];
        }
        if ($ln[0] eq 'SNMPCOMUNITY') {
            $ps_gl_snmp_com = $ln[2];
        }
        if ($ln[0] eq 'ISJABBER') {
            $zisjabber = $ln[1];
        }
        if ($ln[0] eq 'JABBER_FIELD') {
            $zjab_field = $ln[2];
        }
    };
$rs->finish();
if ($ps_gl_snmp_com eq '') {
    $ps_gl_snmp_com = 'public';
}
if ($ps_dontsend_unact ne 1) {
    $ps_dontsend_unact = 0;
}

#Проверяем версию и включен ли модуль
version_verify_light();

#Начальные системные операции
load_second_light();

#Фиксируем в логе специфические параметры
printlog("zlost_count   = " . $zlost_count);
printlog("donsend_unact = " . $ps_dontsend_unact);

bufer_clear();

#Начинаем работу
my @pmas_oid = ();
$pmas_oid_c = 0;

#Увеличиваем счетчик - чтобы не опрашивать отключенные устройства
$zlost_count = 5;
$ps_constr = q{
    UPDATE
        tbl_control_device
    SET
        DOWNCOUNT = IFNULL(DOWNCOUNT, 0) + 1
    WHERE
        ISALERT = 1};
sql_do($ps_constr);
$ps_constr = qq{
    UPDATE
        tbl_control_device
    SET
        DOWNCOUNT = 0
    WHERE
        DOWNCOUNT >= $zlost_count};
sql_do($ps_constr);

#Работаем параметры
$ps_constr = q{
    SELECT
        co.CODE,
        cd.DEVTYPER,
        cd.DEVCODE,
        (SELECT INET_NTOA(MIN(i.USERIP)) FROM tbl_ip AS i WHERE i.TYPER = cd.DEVTYPER AND i.USERCODE = cd.DEVCODE) AS USERIP,
        IF(cd.DEVTYPER = 3, s.HOSTNAME, (IF (cd.DEVTYPER = 4, w.HOSTNAME, ''))) AS HOSTNAME,
        IF(cd.DEVTYPER = 3, s.SNMPVER, (IF (cd.DEVTYPER = 4, w.SNMPVER, bs.SNMPVER))) AS SNMPVER,
        IF(cd.DEVTYPER = 3, s.COM_PUBLIC, (IF (cd.DEVTYPER = 4, w.COM_PUBLIC, bs.COM_PUBLIC))) AS COMMUNITY,
        co.OID,
        co.ALERTTHEN,
        co.ALERTPARAM1,
        co.ALERTPARAM2,
        cc.CODE,
        IFNULL(cc.LASTVALUE, '$$$US$$$') AS LASTVALUE,
        cc.ISALERT,
        cd.CODE,
        IFNULL(cd.ISALERT, 0)
    FROM
        tbl_control_device AS cd
    LEFT JOIN
        tbl_control_profile AS cp
    ON
        cp.ISPOLLING = 1
    AND
        cp.CODE = cd.PROFILECODE    
    LEFT JOIN
        tbl_control_profile_oid AS cpo
    ON
        cpo.PROFILECODE = cp.CODE
    INNER JOIN
        tbl_control_oid AS co
    ON
        (co.CODE = cpo.OIDCODE OR FIND_IN_SET(CONCAT('*', co.CODE, '|'), cd.CUSTOM_OIDCODE))
    AND
        co.ISPOLLING = 1
    LEFT JOIN
        tbl_basesist AS bs
    ON
        bs.CODE = cd.DEVCODE
    AND
        cd.DEVTYPER = 2
    LEFT JOIN
        tbl_switch AS s
    ON
        s.CODE = cd.DEVCODE
    LEFT JOIN
        tbl_wifi AS w
    ON
        w.CODE = cd.DEVCODE
    AND
        cd.DEVTYPER = 4
    LEFT JOIN
        tbl_control_current AS cc
    ON
        cc.DEVTYPER = cd.DEVTYPER
    AND
        cc.DEVCODE = cd.DEVCODE
    AND
        cc.OIDCODE = co.CODE        
    WHERE
        cd.ISPOLLING = 1
    AND
        IFNULL(cd.DOWNCOUNT, 0) = 0
    GROUP BY
        cd.DEVTYPER, cd.DEVCODE, co.CODE
    ORDER BY
        cd.DEVTYPER, cd.DEVCODE, co.NAZV};
printlog_sql_u($ps_constr);
    while (@ln = $rs->fetchrow_array()) {        
        $ps_devtyper = $ln[1];
        $ps_devcode = $ln[2];
        if ($ln[4] ne '') {
            $ps_ip = $ln[4]; #HOSTNAME
        } else {
            $ps_ip = $ln[3]; #USERIP
        }
        $ps_community = $ln[6]; #COMMUNITY
        if ($ps_community eq '') {
            $ps_community = $ps_gl_snmp_com;
        }
        $ps_snmpver = $ln[5]; #SNMPVER
        if ($ps_snmpver ne 1) {
            $ps_snmpver = 2;
        }
        $ps_oid = $ln[7]; #OID
        $ps_code = $ln[11]; #cc.CODE
        $ps_laststatus = $ln[12]; #cc.LASTVALUE
        $ps_alertthen = $ln[8]; #ALERTTHEN
        $ps_alertparam1 = $ln[9]; #ALERTPARAM1
        $ps_alertparam2 = $ln[10]; #ALERTPARAM2
        $ps_isalertnow = $ln[13]; #cc.ISALERT
        $ps_oid_code = $ln[0]; #co.CODE
        $ps_device_code = $ln[14]; #cd.CODE
        $ps_device_isalert = $ln[15]; #cd.ISALERT
        
        #Объединяем
        $ps_concat = $ps_ip . '-US-' . $ps_community . '-US-' . $ps_snmpver . '-US-' . $ps_oid . '-US-' . $ps_code . '-US-' . $ps_laststatus . '-US-' . $ps_alertthen . '-US-' . $ps_alertparam1 . '-US-' . $ps_alertparam2 . '-US-' . $ps_isalertnow . '-US-' . $ps_devtyper . '-US-' . $ps_devcode . '-US-' . $ps_oid_code . '-US-' . $ps_device_code . '-US-' . $ps_device_isalert;
        
        #Фиксируем в массив
        $pmas_oid_c++;
        $pmas_oid[$pmas_oid_c] = $ps_concat;

    };
$rs->finish();

bufer_clear();

#Разбиваем в блоки для опроса
my @pmas_param = ();
$ps_thread_c = 1;
$pi_temp_c = 0;
for ($pi1=1; $pi1<=$pmas_oid_c; $pi1++) {
    $pi_temp_c++;
    if ($pi_temp_c > $zoid_by_thread) {
        #Открываем следующий блок
        $ps_thread_c++;
        $pi_temp_c = 1;
    }
    $pmas_param[$ps_thread_c][$pi_temp_c] = $pmas_oid[$pi1];
}

bufer_clear();

$ps_outputname = $ps_logpath . 'us_control_outputlog.txt';
open ($ps_file_output, ">" . $ps_outputname) || die;

#Загружаем потоки
my @pmas_thread = ();
for ($pi1=1; $pi1<=$ps_thread_c; $pi1++) {
    my $ps_thread_id = threads->new({'context' => 'list'}, 'child_load', $pi1);
    $pmas_thread[$pi1] = $ps_thread_id;
}

bufer_clear();

#Ожидаем выполнения потоков
my @pmas_all_result = ();
$pmas_all_result_c = 0;
my @pmas_all_result_device = ();
$pmas_all_result_device_c = 0;
for ($pi1=1; $pi1<=$ps_thread_c; $pi1++) {
    ($pi_local_result_c, $pi_local_device_result_c, $pmas_local_result, $pmas_local_device_result) = $pmas_thread[$pi1]->join;
    @pmas_local_result = @$pmas_local_result;
    @pmas_local_device_result = @$pmas_local_device_result;    
    #Добавляем результаты
    #print "thr: " . $pi1 . " = " . $pi_local_result_c . "\n";
    for ($pi2=1; $pi2<=$pi_local_result_c; $pi2++) {
        $pmas_all_result_c++;
        $pmas_all_result[$pmas_all_result_c][1] = $pmas_local_result[$pi2][1];
        $pmas_all_result[$pmas_all_result_c][2] = $pmas_local_result[$pi2][2];
        $pmas_all_result[$pmas_all_result_c][3] = $pmas_local_result[$pi2][3];
        $pmas_all_result[$pmas_all_result_c][4] = $pmas_local_result[$pi2][4];
        $pmas_all_result[$pmas_all_result_c][5] = $pmas_local_result[$pi2][5];
        $pmas_all_result[$pmas_all_result_c][6] = $pmas_local_result[$pi2][6];
    }
    for ($pi2=1; $pi2<=$pi_local_device_result_c; $pi2++) {
        $pmas_all_result_device_c++;
        $pmas_all_result_device[$pmas_all_result_device_c][1] = $pmas_local_device_result[$pi2][1];
        $pmas_all_result_device[$pmas_all_result_device_c][2] = $pmas_local_device_result[$pi2][2];
        $pmas_all_result_device[$pmas_all_result_device_c][3] = $pmas_local_device_result[$pi2][3];
        $pmas_all_result_device[$pmas_all_result_device_c][4] = $pmas_local_device_result[$pi2][4];
        $pmas_all_result_device[$pmas_all_result_device_c][5] = $pmas_local_device_result[$pi2][5];
    }
}

bufer_clear();

$ps_constr_stat = '';
my @pmas_alert = ();
$pmas_alert_c = 0;
my @pmas_allok = ();
$pmas_allok_c = 0;

#Обрабатываем устройства сначала
$ps_constr = '';
$ps_constr2 = '';
for ($pi1=1; $pi1<=$pmas_all_result_device_c; $pi1++) {
    $ps_isalert = $pmas_all_result_device[$pi1][1];
    if ($ps_isalert eq 2) {
        $ps_isalert = 0;
    }
    $ps_devtyper = $pmas_all_result_device[$pi1][2];
    $ps_devcode = $pmas_all_result_device[$pi1][3];
    $ps_device_code = $pmas_all_result_device[$pi1][4];
    $ps_isalert_old = $pmas_all_result_device[$pi1][5];
    #Тревогу поставить
    if ($ps_isalert eq 1 && $ps_isalert_old ne 1) {
        $pmas_alert_c++;
        $pmas_alert[$pmas_alert_c][1] = $ps_devtyper;
        $pmas_alert[$pmas_alert_c][2] = $ps_devcode;
        $pmas_alert[$pmas_alert_c][3] = 0;
        if ($ps_constr ne '') {
            $ps_constr .= ',';
        }
        $ps_constr .= $ps_device_code;
        $ps_constr_stat .= "(" . $ps_devtyper . ", " . $ps_devcode . ", 0, NOW(), 'DOWN', 1, '')";
    }
    #Тревогу снять
    #print "|t=" . $ps_devtyper . "|c=" . $ps_devcode . "|a=" . $ps_isalert . "|oa=" . $ps_isalert_old . "|\n";
    if ($ps_isalert ne 1 && $ps_isalert_old eq 1) {
        $pmas_allok_c++;
        $pmas_allok[$pmas_allok_c][1] = $ps_devtyper;
        $pmas_allok[$pmas_allok_c][2] = $ps_devcode;
        $pmas_allok[$pmas_allok_c][3] = 0;
        if ($ps_constr2 ne '') {
            $ps_constr2 .= ',';
        }
        $ps_constr2 .= $ps_device_code;
        $ps_constr_stat .= "(" . $ps_devtyper . ", " . $ps_devcode . ", 0, NOW(), 'UP', 1, '')";
    }
}
if ($ps_constr ne '') {
    printlog("Run SQL-command d-1");
    $ps_constr = "UPDATE tbl_control_device SET ISALERT = 1, DOWNCOUNT = 0 WHERE CODE IN (" . $ps_constr . ")";
    sql_do($ps_constr);
}
if ($ps_constr2 ne '') {
    printlog("Run SQL-command d-2");
    $ps_constr2 = "UPDATE tbl_control_device SET ISALERT = 0, DOWNCOUNT = 0 WHERE CODE IN (" . $ps_constr2 . ")";
    sql_do($ps_constr2);
}

bufer_clear();

#Фиксируем результаты
$ps_constr = '';
$ps_constr2 = '';
$ps_constr3 = '';
$ps_constr4 = '';
$ps_constr5 = '';
my @pmas_eq_bs = ();
my @pmas_eq_sw = ();
my @pmas_eq_w = ();
$ps_constr_sw = '';
$ps_constr_w = '';
$ps_constr_bs = '';
for ($pi1=1; $pi1<=$pmas_all_result_c; $pi1++) {
    $ps_code = $pmas_all_result[$pi1][1];
    $ps_ret = $pmas_all_result[$pi1][2];
    $ps_ret = substr($ps_ret, 0, 255);
    $ps_ret =~s/
/ /g;
    $pb_alert = $pmas_all_result[$pi1][3];
    $ps_devtyper = $pmas_all_result[$pi1][4];
    $ps_devcode = $pmas_all_result[$pi1][5];
    $ps_oid_code = $pmas_all_result[$pi1][6];
    
    #Активность оборудованию
    if ($pb_alert ne 1) {
        #Basesist
        if ($ps_devtyper eq 2) {
            if ($pmas_eq_bs[$ps_devcode] ne 1) {
                if ($ps_constr_bs ne '') {
                    $ps_constr_bs .= ',';
                }
                $ps_constr_bs .= $ps_devcode;
                $pmas_eq_bs[$ps_devcode] = 1;
            }
        }
        #Switch
        if ($ps_devtyper eq 3) {
            if ($pmas_eq_sw[$ps_devcode] ne 1) {
                if ($ps_constr_sw ne '') {
                    $ps_constr_sw .= ',';
                }
                $ps_constr_sw .= $ps_devcode;   
                $pmas_eq_sw[$ps_devcode] = 1;        
            }
        }
        #WiFi
        if ($ps_devtyper eq 4) {
            if ($pmas_eq_w[$ps_devcode] ne 1) {
                if ($ps_constr_w ne '') {
                    $ps_constr_w .= ',';
                }
                $ps_constr_w .= $ps_devcode;    
                $pmas_eq_w[$ps_devcode] = 1;       
            }
        }
    }

    if ($pb_alert ne 0) {
        #Проверка наличия тревоги
        if ($pb_alert eq 1) {
            $pmas_alert_c++;
            $pmas_alert[$pmas_alert_c][1] = $ps_devtyper;
            $pmas_alert[$pmas_alert_c][2] = $ps_devcode;
            $pmas_alert[$pmas_alert_c][3] = $ps_oid_code;
            $pmas_alert[$pmas_alert_c][4] = $ps_ret;
            if ($ps_code > 0) {
                if ($ps_constr3 ne '') {
                    $ps_constr3 .= ',';
                }            
                $ps_constr3 .= $ps_code;
            }
            #print "ALERT: " . $ps_devtyper . '/' . $ps_devcode . '/' . $ps_oid_code . "\n";
        }

        #Проверка наличия отмены тревоги
        if ($pb_alert eq -1) {
            $pmas_allok_c++;
            $pmas_allok[$pmas_allok_c][1] = $ps_devtyper;
            $pmas_allok[$pmas_allok_c][2] = $ps_devcode;
            $pmas_allok[$pmas_allok_c][3] = $ps_oid_code;
            $pmas_allok[$pmas_allok_c][4] = $ps_ret;
            if ($ps_code > 0) {
                if ($ps_constr4 ne '') {
                    $ps_constr4 .= ',';
                }            
                $ps_constr4 .= $ps_code;            
            }
            #print "ALL OK: " . $ps_devtyper . '/' . $ps_devcode . '/' . $ps_oid_code . "\n";
        }
    }
    if ($pb_alert eq 1 || $pb_alert eq -1) {
        $pb_alert_temp = 1;
    } else {
        $pb_alert_temp = 0;
    }    

    if ($ps_code > 0) {
        #Старые значения
        #Обновление значений и даты съема значений
        if ($ps_ret ne '-US_NOTCHANGE-') {
            if ($ps_constr2 ne '') {
                $ps_constr2 .= ',';
            }
            $ps_constr2 .= "(" . $ps_code . ", NOW(), '" . $ps_ret . "', 1)";

            #Stat
            if ($ps_constr_stat ne '') {
                $ps_constr_stat .= ',';
            }
            $ps_constr_stat .= "(" . $ps_devtyper . ", " . $ps_devcode . ", " . $ps_oid_code . ", NOW(), '" . $ps_ret . "', " . $pb_alert_temp . ", '')";
        } else {
            #Обновление только даты съема значения
            if ($ps_constr ne '') {
                $ps_constr .= ',';
            }
            $ps_constr .= $ps_code;
        }
    } else {
        #Stat
        if ($ps_constr_stat ne '') {
            $ps_constr_stat .= ',';
        }
        $ps_constr_stat .= "(" . $ps_devtyper . ", " . $ps_devcode . ", " . $ps_oid_code . ", NOW(), '" . $ps_ret . "', " . $pb_alert_temp . ", '')";
        #Новые значения
        if ($pb_alert eq 1) {
            $pb_alert_temp = 1;
        } else {
            $pb_alert_temp = 0;
        }        
        if ($ps_constr5 ne '') {
            $ps_constr5 .= ',';
        }          
        $ps_constr5 .= "(" . $ps_oid_code . ", " . $ps_devtyper . ", " . $ps_devcode . ", NOW(), '" . $ps_ret . "', " . $pb_alert_temp . ", 1)";
    }
}

bufer_clear();

#Снимаем флаг обновления
$ps_constr_temp = "UPDATE tbl_control_current SET ISUPD = 0";
sql_do($ps_constr_temp);
if ($ps_constr ne '') {
    printlog("Run SQL-command 1");
    $ps_constr = "UPDATE tbl_control_current SET DATEDO = NOW(), ISUPD = 1 WHERE CODE IN (" . $ps_constr . ")";
    sql_do($ps_constr);
}
if ($ps_constr2 ne '') {
    printlog("Run SQL-command 2");
    $ps_constr2 = "INSERT INTO tbl_control_current (CODE, DATEDO, LASTVALUE, ISUPD) VALUES " . $ps_constr2 . " ON DUPLICATE KEY UPDATE DATEDO = VALUES(DATEDO), LASTVALUE = VALUES(LASTVALUE), ISUPD = VALUES(ISUPD)";
    sql_do($ps_constr2);
}
if ($ps_constr3 ne '') {
    printlog("Run SQL-command 3");
    $ps_constr3 = "UPDATE tbl_control_current SET ISALERT = 1 WHERE CODE IN (" . $ps_constr3 . ")";
    sql_do($ps_constr3);
}
if ($ps_constr4 ne '') {
    printlog("Run SQL-command 4");
    $ps_constr4 = "UPDATE tbl_control_current SET ISALERT = 0 WHERE CODE IN (" . $ps_constr4 . ")";
    sql_do($ps_constr4);
}
if ($ps_constr5 ne '') {
    printlog("Run SQL-command 5");
    $ps_constr5 = "INSERT INTO tbl_control_current (OIDCODE, DEVTYPER, DEVCODE, DATEDO, LASTVALUE, ISALERT, ISUPD) VALUES " . $ps_constr5;
    sql_do($ps_constr5);
}
if ($ps_constr_stat ne '') {
    printlog("Run SQL-command Stat");
    $ps_constr_stat = "INSERT INTO tbl_control_stat (DEVTYPER, DEVCODE, OIDCODE, DATECHANGE, LASTVALUE, ISSEND, WHORECEIVE) VALUES " . $ps_constr_stat;
    sql_do($ps_constr_stat);
}

#Активность оборудованию
if ($ps_constr_bs ne '') {
    printlog("Run SQL-command Act - basesist");
    $ps_constr_stat = "UPDATE tbl_basesist SET LASTACT = NOW() WHERE CODE IN (" . $ps_constr_bs . ")";
    sql_do($ps_constr_stat);
}
if ($ps_constr_sw ne '') {
    printlog("Run SQL-command Act - switch");
    $ps_constr_stat = "UPDATE tbl_switch SET LASTACT = NOW() WHERE CODE IN (" . $ps_constr_sw . ")";
    sql_do($ps_constr_stat);
}
if ($ps_constr_w ne '') {
    printlog("Run SQL-command Act - wifi");
    $ps_constr_stat = "UPDATE tbl_wifi SET LASTACT = NOW() WHERE CODE IN (" . $ps_constr_w . ")";
    sql_do($ps_constr_stat);
}

#Удаляем устаревшие
$ps_constr_temp = "DELETE FROM tbl_control_current WHERE ISUPD = 0";
sql_do($ps_constr_temp);

close $ps_file_output;
if ($isFixedAllLog eq 1) {
	close $allLogFile;
	close $allLogFileSql;
}
bufer_clear();

#*** TEST
if (1 eq 0) {
    $pmas_alert_c++;
    $pmas_alert[$pmas_alert_c][1] = 2;
    $pmas_alert[$pmas_alert_c][2] = 8;
    $pmas_alert[$pmas_alert_c][3] = 0;

    $pmas_alert_c++;
    $pmas_alert[$pmas_alert_c][1] = 3;
    $pmas_alert[$pmas_alert_c][2] = 1;
    $pmas_alert[$pmas_alert_c][3] = 5;
    $pmas_alert[$pmas_alert_c][4] = 1;

    $pmas_alert_c++;
    $pmas_alert[$pmas_alert_c][1] = 3;
    $pmas_alert[$pmas_alert_c][2] = 1;
    $pmas_alert[$pmas_alert_c][3] = 7;
    $pmas_alert[$pmas_alert_c][4] = 1;

    $pmas_allok_c++;
    $pmas_allok[$pmas_allok_c][1] = 3;
    $pmas_allok[$pmas_allok_c][2] = 1;
    $pmas_allok[$pmas_allok_c][3] = 11;
    $pmas_allok[$pmas_allok_c][4] = 2;
}

my @pmas_pers = ();
my @pmas_otdel = ();
my @pmas_oid = ();
if ($pmas_alert_c > 0 || $pmas_allok_c > 0) {
    printlog("Send MSG. Start");
    #Набьём базу получателей
    $ps_constr = qq{
        SELECT
            p.CODE,
            p.ACTUAL_PHONE,
            p.ACTUAL_MAIL,
            a3.VALUESTR
        FROM
            tbl_pers AS p
        LEFT JOIN 
            tbl_attr AS a3
        ON 
            a3.ATTRCODE = '$zjab_field' AND a3.USERCODE = p.CODE
        WHERE
            p.ISWORK = 1
    };
    printlog_sql_u($ps_constr);
        while (@ln = $rs->fetchrow_array()) {
            $pmas_pers[$ln[0]][1] = $ln[1]; #PHONE
            $pmas_pers[$ln[0]][2] = $ln[2]; #MAIL
            $pmas_pers[$ln[0]][3] = $ln[3]; #JABBER
        };
    $rs->finish();    
    #Отделы
    $ps_constr = q{
        SELECT
            po.CODE, 
            (SELECT GROUP_CONCAT(pd.PERSCODE) FROM tbl_pers_dolg AS pd WHERE pd.OTDELCODE = po.CODE AND pd.ISWORK = 1) AS PERS_LIST
        FROM
            tbl_pers_otdel AS po        
    };
    printlog_sql_u($ps_constr);
        while (@ln = $rs->fetchrow_array()) {
            $pmas_otdel[$ln[0]][1] = $ln[1]; #PERS_LIST
        };
    $rs->finish();
    
    #База параметров
    $ps_constr = q{
        SELECT
            co.CODE, 
            co.NAZV,
            co.ALERTTHEN,
            co.ALERTPARAM1,
            co.ALERTPARAM2
        FROM
            tbl_control_oid AS co
    };
    printlog_sql_u($ps_constr);
        while (@ln = $rs->fetchrow_array()) {
            $pmas_oid[$ln[0]][1] = $ln[1]; #NAZV
            $ps_alert_text = '';
            $ps_alert_param1 = $ln[3];
            $ps_alert_param2 = $ln[4];
            if ($ln[2] eq 1) {
                $ps_alert_text = '=' . $ps_alert_param1;
            }
            if ($ln[2] eq 2) {
                $ps_alert_text = '<>' . $ps_alert_param1;
            }
            if ($ln[2] eq 3) {
                $ps_alert_text = '>' . $ps_alert_param1;
            }
            if ($ln[2] eq 4) {
                $ps_alert_text = '<' . $ps_alert_param1;
            }
            if ($ln[2] eq 5) {
                $ps_alert_text = $ps_alert_param1 . '<->' . $ps_alert_param2;
            }
            $pmas_oid[$ln[0]][2] = $ps_alert_text;
        };
    $rs->finish();
    
    #Начинаем рассылать уведомления
    $ps_constr = q{
        SELECT
            cd.DEVTYPER,
            cd.DEVCODE,
            cd.WHORECEIVE,
            IF(
                cd.DEVTYPER = 2, 
                bs.NAZV, (
                    IF(
                        cd.DEVTYPER = 3, 
                        s.NAZV, (
                        IF(
                            cd.DEVTYPER = 4, 
                            tt.TOVARNAZV, 
                            '')
                        )
                    )
                )
            ) AS NAZV, 
            u.NAZV AS LOCATION,
            (SELECT INET_NTOA(MIN(i.USERIP)) FROM tbl_ip AS i WHERE i.TYPER = cd.DEVTYPER AND i.USERCODE = cd.DEVCODE) AS USERIP,
            IF(cd.DEVTYPER = 3, s.HOSTNAME, (IF (cd.DEVTYPER = 4, w.HOSTNAME, ''))) AS HOSTNAME
        FROM
            tbl_control_device AS cd
        LEFT JOIN
            tbl_basesist AS bs
        ON
            cd.DEVTYPER = 2 AND bs.CODE = cd.DEVCODE
        LEFT JOIN
            tbl_switch AS s
        ON
            cd.DEVTYPER = 3 AND s.CODE = cd.DEVCODE
        LEFT JOIN
            tbl_wifi AS w
        ON
            cd.DEVTYPER = 4 AND w.CODE = cd.DEVCODE
        LEFT JOIN
            tbl_tovar AS t
        ON
            t.CODE = w.SKLADCODE
        LEFT JOIN
            tbl_tovartype AS tt
        ON
            tt.CODE = t.TOVARCODE
        LEFT JOIN
            tbl_uzel AS u
        ON
            u.CODE IN (bs.UZELCODE, s.UZELCODE, w.UZELCODE)            
        WHERE
            cd.ISPOLLING = 1
        AND
            IFNULL(cd.WHORECEIVE, '') <> ''        
        ORDER BY
            cd.DEVTYPER, cd.DEVCODE    
    };
    printlog_sql_u($ps_constr);
        while (@ln = $rs->fetchrow_array()) {        
            $ps_devtyper = $ln[0];
            $ps_devcode = $ln[1];
            $ps_whoreceive = $ln[2];
            $ps_dev_nazv = $ln[3];
            $ps_dev_adr = $ln[4];
            $pi_alert_c = 0;
            $pi_normal_c = 0;
            $pb_is_device_status = 0;
            $ps_dev_ip = $ln[6]; #HOSTNAME
            if ($ps_dev_ip eq '') {
                $ps_dev_ip = $ln[5]; #IP
            }
            #Сначала ошибки
            $ps_text_param = '';
            $ps_text_param_sms = '';
            for ($pi1=1; $pi1<=$pmas_alert_c; $pi1++) {
                if ($pmas_alert[$pi1][1] eq $ps_devtyper && $pmas_alert[$pi1][2] eq $ps_devcode) {
                    $ps_oidcode = $pmas_alert[$pi1][3];
                    if ($ps_oidcode eq 0) {
                        $pb_is_device_status = -1;
                    } else {
                        $ps_text_param .= "ALERT - " . $pmas_oid[$ps_oidcode][1] . ' ($zl[4765] "' . $pmas_oid[$ps_oidcode][2] . '") $zl[4774]: ' . $pmas_alert[$pi1][4] . "\n"; #Тревога, если значение... Текущее значение
                        #$ps_text_param_sms .= "ALERT - " . $pmas_oid[$ps_oidcode][1] . "\n";
                        $ps_text_param_sms .= $pmas_oid[$ps_oidcode][1] . ' - ALARM' . "\n";
                    }
                    $pi_alert_c++;
                }
            }
            #Теперь нормально
            for ($pi1=1; $pi1<=$pmas_allok_c; $pi1++) {
                if ($pmas_allok[$pi1][1] eq $ps_devtyper && $pmas_allok[$pi1][2] eq $ps_devcode) {
                    $ps_oidcode = $pmas_allok[$pi1][3];
                    if ($ps_oidcode eq 0) {
                        $pb_is_device_status = 1;
                    } else {
                        $ps_text_param .= "OK - " . $pmas_oid[$ps_oidcode][1] . ' ($zl[4765] "' . $pmas_oid[$ps_oidcode][2] . '") $zl[4774]: ' . $pmas_allok[$pi1][4] . "\n"; #Тревога, если значение... Текущее значение
                        #$ps_text_param_sms .= "OK - " . $pmas_oid[$ps_oidcode][1] . "\n";
                        $ps_text_param_sms .= $pmas_oid[$ps_oidcode][1] . ' - OK' . "\n";
                    }
                    $pi_normal_c++;
                }
            }
            
            #Есть что-то к отправке
            if ($pi_alert_c > 0 || $pi_normal_c > 0) {
                #Формируем тему
                $ps_theme = 'USERSIDE - ' . $ps_dev_nazv . ' - ' . $ps_dev_adr;
                $ps_type5 = '';
                if ($ps_devtyper eq 2) {
                    $ps_type5 = 'basesist';
                }
                if ($ps_devtyper eq 3) {
                    $ps_type5 = 'switch';
                }
                if ($ps_devtyper eq 4) {
                    $ps_type5 = 'wifi';
                }
                
                $ps_sms = '';
                $ps_jabber_text = '';
                $ps_body = '';
                $ps_body .= '$zl[3187]: $zpathoper/equip.php?type=device&type2=show&type5=' . $ps_type5 . "&code=" . $ps_devcode . "\n"; #Ссылка
                $ps_body .= "============================================================================================================\n";
                $ps_body .= '$zl[1186]: ' . $ps_dev_adr . "\n"; #Адрес
                $ps_body .= '$zl[1451]: ' . $ps_dev_nazv . "\n"; #Наименование
                $ps_body .= "IP: " . $ps_dev_ip . "\n";
                if ($pb_is_device_status ne 0) {
                    #Проблема с самим устройством
                    if ($pb_is_device_status eq 1) {
                        $ps_theme .= ' - UP';
                        $ps_sms = 'UP. ';
                        $ps_body = '$zl[4780]' . "\n\n" . $ps_body; #Устройство вновь активно
                    }
                    if ($pb_is_device_status eq -1) {
                        $ps_sms = 'DOWN. ';
                        $ps_theme .= ' - DOWN';
                        $ps_body = '$zl[4781]' . "\n\n" . $ps_body; #Пропала активность у устройства
                    }
                    $ps_sms .= $ps_dev_adr . ' - ' . $ps_dev_nazv . ' IP: ' . $ps_dev_ip;
                } else {
                    #Проблема с параметрами
                    $ps_body = '$zl[4782]' . "\n\n" . $ps_body; #Изменились значения параметров
                    if ($pi_alert_c > 0) {
                        $ps_theme .= ' - ALERT: ' . $pi_alert_c;
                        $ps_sms .= 'ALERT: ' . $pi_alert_c;
                    }
                    if ($pi_normal_c > 0) {
                        $ps_theme .= ' - OK: ' . $pi_normal_c;
                        if ($ps_sms ne '') {
                            $ps_sms .= '/';
                            $ps_sms .= 'OK: ' . $pi_normal_c;
                        }
                    }
                    $ps_body .= " \n " . $ps_text_param . " \n ";
                    #$ps_sms .= " \n " . $ps_dev_adr . ' - ' . $ps_dev_nazv . ' IP: ' . $ps_dev_ip;
                    #$ps_sms .= " \n " . $ps_text_param_sms;
                    $ps_sms .= "\n" . $ps_dev_adr . ' - ' . $ps_dev_nazv . "\n".'IP: ' . $ps_dev_ip;
                    $ps_sms .= "\n" . $ps_text_param_sms;
                }
                
                if ($pb_is_device_status eq 0 || $ps_dontsend_unact eq 0) {
                    #Если это не связано с изменением статуса самого устройства
                    #или разрешена отправка сообщений при неактивности
                    
                    $ps_body .= "============================================================================================================\n";
                    $ps_body = formatdatetime("DD.MM.YYYY hh:mm:ss", time) . " - " . $ps_body;

                    #$ps_jabber_body = "USERSIDE - " . $ps_body;
                    #$ps_jabber_body =~s/============================================================================================================/==================================================/g;
                    #$ps_jabber_body =~s/\"/ /g;
                    $ps_jabber_body = $ps_sms;
                    
                    #Получатели
                    $ps_whoreceive =~s/\*//g;
                    #print $ps_whoreceive . "\n";
                    @pmas_temp = split(/\|/,$ps_whoreceive); 
                    @pmas_already_send_mail = $pmas_pers;
                    @pmas_already_send_sms = $pmas_pers;
                    @pmas_already_send_jabber = $pmas_pers;
                    for ($pi1 = 0; $pi1<@pmas_temp; $pi1++) {
                        @pmas_temp2 = split(/=/,$pmas_temp[$pi1]); 
                        $ps_rec_typer = $pmas_temp2[0];
                        $ps_rec_list = $pmas_temp2[1];
                        @pmas_temp3 = split(/,/,$ps_rec_list); 
                        #print '|' . $ps_rec_typer . '=' . $ps_rec_list . "|\n";
                        for ($pi2 = 0; $pi2<@pmas_temp3; $pi2++) {
                            $ps_obj_code = $pmas_temp3[$pi2];
                            #print '|' . $ps_obj_code . "|\n";

                            if ($ps_rec_typer eq 'EMAIL_PERS') {
                                $ps_mail = $pmas_pers[$ps_obj_code][2];
                                if ($ps_mail ne '' && $pmas_already_send_mail[$ps_obj_code][90] ne 1) {
                                    $pmas_already_send_mail[$ps_obj_code][90] = 1;
                                    printlog('SENDMAIL: ' . $ps_mail . " - " . $ps_theme . " - " . $ps_dev_ip);
                                    $ps_constr = "INSERT INTO tbl_tmp_mail SET DATEADD = NOW(), RECEIVER = '" . $ps_mail . "', SUBJ = '" . $ps_theme . "', OPIS = '" . $ps_body . "'";
                                    sql_do($ps_constr);
                                }
                            }

                            if ($ps_rec_typer eq 'EMAIL_OTDEL') {
                                $ps_perslist = $pmas_otdel[$ps_obj_code][1];
                                if ($ps_perslist ne '') {
                                    @pmas_temp5 = split(/,/,$ps_perslist); 
                                    for ($pi3 = 0; $pi3<@pmas_temp5; $pi3++) {
                                        $ps_perscode = $pmas_temp5[$pi3];
                                        $ps_mail = $pmas_pers[$ps_perscode][2];
                                        if ($ps_mail ne '' && $pmas_already_send_mail[$ps_perscode][90] ne 1) {
                                            printlog('SENDMAIL (o): ' . $ps_mail . " - " . $ps_theme . " - " . $ps_dev_ip);
                                            $pmas_already_send_mail[$ps_perscode][90] = 1;
                                            $ps_constr = "INSERT INTO tbl_tmp_mail SET DATEADD = NOW(), RECEIVER = '" . $ps_mail . "', SUBJ = '" . $ps_theme . "', OPIS = '" . $ps_body . "'";
                                            sql_do($ps_constr);
                                        }
                                    }
                                }
                            }

                            if ($ps_rec_typer eq 'SMS_PERS') {
                                $ps_phone = $pmas_pers[$ps_obj_code][1];
                                if ($ps_phone ne '' && $pmas_already_send_sms[$ps_obj_code][90] ne 1) {
                                    $pmas_already_send_sms[$ps_obj_code][90] = 1;
                                    printlog('SENDSMS: ' . $ps_obj_code);
                                    $ps_constr = "INSERT INTO tbl_sms SET TYPER = 8, TEL = '" . $ps_phone . "', SMSTEXT = '" . $ps_sms . "', DATEADD = NOW(), STATUS = 1";
                                    sql_do($ps_constr);
                                }
                            }

                            if ($ps_rec_typer eq 'SMS_OTDEL') {
                                $ps_perslist = $pmas_otdel[$ps_obj_code][1];
                                if ($ps_perslist ne '') {
                                    @pmas_temp5 = split(/,/,$ps_perslist); 
                                    for ($pi3 = 0; $pi3<@pmas_temp5; $pi3++) {
                                        $ps_perscode = $pmas_temp5[$pi3];
                                        $ps_phone = $pmas_pers[$ps_perscode][1];
                                        if ($ps_phone ne '' && $pmas_already_send_sms[$ps_perscode][90] ne 1) {
                                            printlog('SENDSMS (o): ' . $ps_perscode);
                                            $pmas_already_send_sms[$ps_perscode][90] = 1;
                                            $ps_constr = "INSERT INTO tbl_sms SET TYPER = 8, TEL = '" . $ps_phone . "', SMSTEXT = '" . $ps_sms . "', DATEADD = NOW(), STATUS = 1";
                                            sql_do($ps_constr);
                                        }
                                    }
                                }
                            }
                            
                            if ($zisjabber eq 1) {
                                if ($ps_rec_typer eq 'JABBER_PERS') {
                                    $ps_jabber = $pmas_pers[$ps_obj_code][3];
                                    if ($ps_jabber ne '' && $pmas_already_send_jabber[$ps_obj_code][90] ne 1) {
                                        $pmas_already_send_jabber[$ps_obj_code][90] = 1;
                                        printlog('SENDJABBER: ' . $ps_obj_code);
                                        $ps_constr = "INSERT INTO tbl_jabber SET DATEDO = NOW(), OPERCODE = 0, PERSCODE = " . $ps_obj_code . ", RECEIVER = '" . $ps_jabber . "', OPIS = '" . $ps_jabber_body . "', PAR1 = 6, PAR2 = " . $ps_obj_code . ", ISSEND = 0";
                                        sql_do($ps_constr);
                                    }
                                }                          
                                if ($ps_rec_typer eq 'JABBER_OTDEL') {
                                    $ps_perslist = $pmas_otdel[$ps_obj_code][1];
                                    if ($ps_perslist ne '') {
                                        @pmas_temp5 = split(/,/,$ps_perslist); 
                                        for ($pi3 = 0; $pi3<@pmas_temp5; $pi3++) {
                                            $ps_perscode = $pmas_temp5[$pi3];
                                            $ps_jabber = $pmas_pers[$ps_perscode][3];
                                            if ($ps_jabber ne '' && $pmas_already_send_jabber[$ps_perscode][90] ne 1) {
                                                printlog('SENDJABBER (o): ' . $ps_perscode);
                                                $pmas_already_send_jabber[$ps_perscode][90] = 1;
                                                $ps_constr = "INSERT INTO tbl_jabber SET DATEDO = NOW(), OPERCODE = 0, PERSCODE = " . $ps_obj_code . ", RECEIVER = '" . $ps_jabber . "', OPIS = '" . $ps_jabber_body . "', PAR1 = 6, PAR2 = " . $ps_obj_code . ", ISSEND = 0";
                                                sql_do($ps_constr);
                                            }
                                        }
                                    }
                                }
                            }

                        }
                    }
                }
            }
        };
    $rs->finish();
    printlog("Send MSG. Finish");
}

bufer_clear();

printlog("Module finish");

#Прописываемся в базу
$ps_constr = "UPDATE tbl_conf SET VALUEDATE = NOW() WHERE PARAM = '" . $zmodule_param . "'";
sql_do($ps_constr);
printlog("Request count: u:" . $zl_sqlc_u);
print $ps_file101 "===========================================\n";
print $ps_file101 "\n";
close $ps_file101;

open ($ps_file101, ">>" . $ps_repalllog) || die;
    print $ps_file101 $zver . " Module FINISH at " . formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "\n";
    print $ps_file101 "==============================================================\n";
close $ps_file101;
close $ps_file102;
if ($zsilence ne 1) {
    print "finish module at " . formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "\n";
    print "===================================\n";
}
$rs->finish();
$conn1->disconnect();
exit(0);

sub child_load() {
    ($pi_number) = @_;
    my $pi_local_result_c = 0;
    my @pmas_local_result = ();
    my $pi_local_device_result_c = 0;
    my @pmas_local_device_result = ();
    #print "thread: " . $pi_number . "\n";
    #print $ps_file_output "thread: " . $pi_number . "\n";
    $ps_last_ip = '';
    $pb_sess_open = 0;
    $ps_black_ip = '';
    for ($pi1=1; $pi1<=$zoid_by_thread; $pi1++) {
        $ps_data = $pmas_param[$pi_number][$pi1];
        if ($ps_data ne '') {
            #print $ps_file_output $pi_number . "| data: " . $ps_data . "\n";
            my @pmas_temp = split(/-US-/, $ps_data); 
            $ps_ip = $pmas_temp[0];
            $ps_community = $pmas_temp[1];
            $ps_snmpver = $pmas_temp[2];
            $ps_oid = $pmas_temp[3];
            $ps_code = $pmas_temp[4];
            $ps_laststatus = $pmas_temp[5];
            $ps_alertthen = $pmas_temp[6];
            $ps_alertparam1 = $pmas_temp[7];
            $ps_alertparam2 = $pmas_temp[8];
            $ps_isalertnow = $pmas_temp[9];
            $ps_devtyper = $pmas_temp[10];
            $ps_devcode = $pmas_temp[11];
            $ps_oid_code = $pmas_temp[12];
            $ps_device_code = $pmas_temp[13];
            $ps_device_isalert = $pmas_temp[14];
            #print $ps_file_output "IP: " . $ps_ip . "| COM: " . $ps_community . "| VER: " . $ps_snmpver . "| OID: " . $ps_oid . "|\n";
            #print "IP: " . $ps_ip . "| COM: " . $ps_community . "| VER: " . $ps_snmpver . "| OID: " . $ps_oid . "|\n"; #***
            
            if ($ps_black_ip ne $ps_ip) {
                if ($ps_last_ip ne $ps_ip) {
                    if ($pb_sess_open eq 1) {
                        $session->close;
                    }
                    ($session, $error) = Net::SNMP->session(-hostname=>$ps_ip, -community=>$ps_community, -port=>161, -version=>$ps_snmpver, -timeout => 8, -retries => 3);
                    #print '|session=' . $session . '| error=' . $error . "|\n"; #***
                    #Пробуем еще раз открыть сессию
                    if (!$session) {
                        ($session, $error) = Net::SNMP->session(-hostname=>$ps_ip, -community=>$ps_community, -port=>161, -version=>$ps_snmpver, -timeout => 10, -retries => 2);
                    }
                    #И еще раз
                    if (!$session) {
                        ($session, $error) = Net::SNMP->session(-hostname=>$ps_ip, -community=>$ps_community, -port=>161, -version=>$ps_snmpver, -timeout => 15, -retries => 1);
                    }
                    $ps_last_ip = $ps_ip;
                    $pi_local_device_result_c++;
                    $pmas_local_device_result[$pi_local_device_result_c][1] = 0;
                    $pmas_local_device_result[$pi_local_device_result_c][2] = $ps_devtyper;
                    $pmas_local_device_result[$pi_local_device_result_c][3] = $ps_devcode;
                    $pmas_local_device_result[$pi_local_device_result_c][4] = $ps_device_code;
                    $pmas_local_device_result[$pi_local_device_result_c][5] = $ps_device_isalert;
                }
                if ($session) {
                    $pb_sess_open = 1;
                    $ps_result = $session->get_request($ps_oid);
                    if (!defined($ps_result)) {
                        #Устройство недоступно
                        $ps_black_ip = $ps_ip;
                        if ($pmas_local_device_result[$pi_local_device_result_c][1] ne 2) {
                            $pmas_local_device_result[$pi_local_device_result_c][1] = 1; #ALERT
                        }
                        print $ps_file_output $pi_number . "| IP: " . $ps_ip . "| oid: " . $ps_oid . "| error: result not defined\n";
                        if ($isFixedAllLog eq 1) {
                        	print $allLogFile formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "|" . $pi_number . "| IP: " . $ps_ip . "| oid: " . $ps_oid . "| error: result not defined\n";
                        }
                        $pb_sess_open = 0;
                        $session->close;
                        undef $session;
                    } else {
                        $ps_ret = $ps_result->{$ps_oid};
    					$ps_ret =~s/
/ /g;
    					$ps_ret = substr($ps_ret, 0, 255);
                        $pmas_local_device_result[$pi_local_device_result_c][1] = 2; #REALY NORMAL
                        print $ps_file_output $pi_number . "| IP: " . $ps_ip . "| oid: " . $ps_oid . "| res: " . $ps_ret . "|\n";
                        if ($isFixedAllLog eq 1) {
                        	print $allLogFile formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "|" . $pi_number . "| IP: " . $ps_ip . "| oid: " . $ps_oid . "| res: " . $ps_ret . "|\n";
                        }
                        if ($ps_ret eq '') {
                        	$ps_ret = $ps_laststatus;
                        }
                        
                        #print "|" . $ps_code;
                        $pi_local_result_c++;
                        $pmas_local_result[$pi_local_result_c][1] = $ps_code;
                        $pmas_local_result[$pi_local_result_c][4] = $ps_devtyper;
                        $pmas_local_result[$pi_local_result_c][5] = $ps_devcode;
                        $pmas_local_result[$pi_local_result_c][6] = $ps_oid_code;
                        $pb_alert = 0;
                        #Тревога, если...
                        if ($ps_alertthen > 0) {
                            #Равно
                            if ($ps_alertthen eq 1 && $ps_ret eq $ps_alertparam1) {
                                $pb_alert = 1;
                            }
                            #Не равно
                            if ($ps_alertthen eq 2 && $ps_ret ne $ps_alertparam1) {
                                $pb_alert = 1;
                            }
                            #Больше
                            if ($ps_alertthen eq 3 && $ps_ret > $ps_alertparam1) {
                                $pb_alert = 1;
                            }
                            #Меньше
                            if ($ps_alertthen eq 4 && $ps_ret < $ps_alertparam1) {
                                $pb_alert = 1;
                            }
                            #Между
                            if ($ps_alertthen eq 5 && ($ps_ret > $ps_alertparam1 && $ps_ret < $ps_alertparam2)) {
                                $pb_alert = 1;
                            }
                            
                            #Произошла тревога
                            if ($pb_alert eq 1 && $ps_isalertnow ne 1) {
                                $pmas_local_result[$pi_local_result_c][3] = $pb_alert; #Флаг - тревога
                            }

                            #Если тревога прошла - может нужно отпустить
                            if ($pb_alert ne 1 && $ps_isalertnow eq 1) {
                                $pb_alert = -1;
                                $pmas_local_result[$pi_local_result_c][3] = $pb_alert; #Флаг - тревога прошла
                            }
                        }

                        #Если значение не изменилось - то ставим спец.признак
                        if ($ps_laststatus eq $ps_ret) {
                            $ps_ret = '-US_NOTCHANGE-';
                        } else {
                            #print "|".$ps_laststatus."|".$ps_ret."|\n"; #***
                        }

                        $pmas_local_result[$pi_local_result_c][2] = $ps_ret;
                    }
                } else {
                    #Устройство недоступно
                    $ps_black_ip = $ps_ip;
                    $pb_sess_open = 0;
                    $pmas_local_device_result[$pi_local_device_result_c][1] = 1; #ALERT
                    print $ps_file_output $pi_number . "| IP: " . $ps_ip . "| error: " . $error . "\n";
                    if ($isFixedAllLog eq 1) {
                    	print $allLogFile formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "|" . $pi_number . "| IP: " . $ps_ip . "| error: " . $error . "\n";
                    }
                }
            }
            threads->yield();  
        }
    }
    if ($pb_sess_open eq 1) {
        $session->close;
    }
    close $ps_file_output;
    open ($ps_file_output, ">>" . $ps_outputname) || die;
    return ($pi_local_result_c, $pi_local_device_result_c, \@pmas_local_result, \@pmas_local_device_result);
}

### ================================================================================================================
#Standart Module Light function v.1
#================================================================================================================
sub trim {
    my($string) = @_;
    for ($string) {
        s/^\s+//;
        s/\s+$//;
    }
    return $string;
}

#========================================================
sub formatdatetime {
    my $format = shift @_ || "YYYY-MM-DD hh:mm:ss";
    my $datetime = shift @_ || time;
    my %strings = (
        '500'=>"AM", '501'=>"PM",
        '400'=>"January", '401'=>"February", '402'=>"March", '403'=>"April", '404'=>"May", '405'=>"June", '406'=>"July", '407'=>"August", '408'=>"September", '409'=>"October", '410'=>"November", '411'=>"December",
        '300'=>"Jan", '301'=>"Feb", '302'=>"Mar", '303'=>"Apr", '304'=>"May", '305'=>"Jun", '306'=>"Jul", '307'=>"Aug", '308'=>"Sep", '309'=>"Oct", '310'=>"Nov", '311'=>"Dec",
        '200'=>"Sunday", '201'=>"Monday", '202'=>"Tuesday", '203'=>"Wednesday", '204'=>"Thursday", '205'=>"Friday", '206'=>"Saturday",
        '100'=>"Sun", '101'=>"Mon", '102'=>"Tue", '103'=>"Wed", '104'=>"Thu", '105'=>"Fri", '106'=>"Sat"
    );
    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($datetime);
    $year += 1900;
    if ($format=~m/AM/) {
        my $ampmhour=($hour % 12) || 12;
        $format=~s/hh/sprintf("%02u",$ampmhour)/eg;
        $format=~s/h/$ampmhour/eg;
        $format=~s/AM/($hour>11?"^501":"^500")/eg;
    } else {
        $format=~s/hh/sprintf("%02u",$hour)/eg;
        $format=~s/h/$hour/eg;
    };
    $format=~s/mm/sprintf("%02u",$min)/eg;
    $format=~s/m/$min/eg;
    $format=~s/ss/sprintf("%02u",$sec)/eg;
    $format=~s/s/$sec/eg;

    $format=~s/YYYY/$year/eg;
    $format=~s/YY/sprintf("%02u",$year % 100)/eg;
    $format=~s/MMMM/sprintf("^4%02u",$mon)/eg;
    $format=~s/MMM/sprintf("^3%02u",$mon)/eg;
    $format=~s/MM/sprintf("%02u",$mon+1)/eg;
    $format=~s/M/($mon+1)/eg;
    $format=~s/DDDD/sprintf("^2%02u",$wday)/eg;
    $format=~s/DDD/sprintf("^1%02u",$wday)/eg;
    $format=~s/DD/sprintf("%02u",$mday)/eg;
    $format=~s/D/$mday/eg;
    $format=~s/\^(\d\d\d)/$strings{$1}/g;
    return $format;
}

#========================================================
sub printlog{
    my($string) = @_;
    print $ps_file101 formatdatetime("DD.MM.YYYY hh:mm:ss", time) . " - " . $string . "\n";
    return $string;
}

#========================================================
sub sql_do{
    my($string) = @_;
    $zl_sqlc_u++;
    #print 'U: '.$zl_sqlc_u."\n";
    print $ps_file102 "U:" . $zl_sqlc_u . "| " . $string . ";\n";

    if ($isFixedAllLogSql eq 1) {
    	print $allLogFileSql formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "|U:" . $zl_sqlc_u . "| " . $string . ";\n";
    }
    
    $conn1->do($string);
    return $string;
}

#========================================================
sub printlog_sql_u{
    my($string) =@_;
    $zl_sqlc_u++ ;
    print $ps_file102 "U:" . $zl_sqlc_u . '| ' . $string . ";\n";
    if ($isFixedAllLogSql eq 1) {
    	print $allLogFileSql formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "|U:" . $zl_sqlc_u . "| " . $string . ";\n";
    }
    $rs = $conn1->prepare($string);
    $rs->execute();
    return $string;
}

#========================================================
sub load_first_light{
    $ps_repalllog = $ps_logpath . 'rep_alllog.txt';
    $ps_rep_logupd = $ps_logpath . 'rep_logupd.txt';
    $ps_rep_sql = $ps_logpath . 'rep_mysql.txt';

    if ($ARGV[0] eq 'debug' || $ARGV[1] eq 'debug' || $ARGV[2] eq 'debug') {
        $ps_full_debug = 1;
    }

    #Удаляем громоздкий файл
    $ps_fn_size  = -s $ps_repalllog;
    if ($ps_fn_size > 100000) {
        unlink($ps_repalllog);
    }
    
    open ($ps_file101, ">>" . $ps_repalllog) || die;
      print $ps_file101 $zver . ' Module START at ' . formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "\n";
    close $ps_file101;
    # Выведем заголовок типа данных
    if ($zsilence ne 1) {
        print $zver . "\n";
        print "===================================\n";
        print 'start module at ' . formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "\n";
    }
    open ($ps_file101, ">" . $ps_rep_logupd) || die;
    print $ps_file101 "===========================================\n";
    printlog($zver . " - start module");
    printlog($zpath);
    open ($ps_file102, ">" . $ps_rep_sql) || die;
    print $ps_file102 formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "\n";
    $zl_sqlc_u = 0;
    #Открываем базу
    $conn1 = DBI->connect("DBI:mysql:database=" . $zubase . ";host=" . $zuserver, $zuuser, $zupass) || die $DBI::errstr;
    if ($zucp eq '') {
        $zucp = 'cp1251';
    }
    $conn1->do('set character set ' . $zucp);
    $conn1->do('set names ' . $zucp);
    return;
}

#========================================================
sub version_verify_light {
    if ($ps_module_allow ne 1) {
        open ($ps_file101, ">>" . $ps_repalllog) || die;
            print $ps_file101 $zver . " Module disabled in system - exit\n";
            print $ps_file101 $zver . " Module FINISH at " . formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "\n";
            print $ps_file101 "==============================================================\n";
        close $ps_file101;
        close $ps_file102;
        print "Module disabled in system - exit\n";
        print "=================================== \n";
        $rs->finish();
        $conn1->disconnect();
        exit(1);
    }
    if (($zrevision < $ps_needversion) || ($ps_needversion < 1)) {
        open ($ps_file101, ">>" . $ps_repalllog) || die;
            print $ps_file101 $zver . ' Version failure. Need version: ' . $ps_needversion . " - exit\n";
            print $ps_file101 $zver . ' Module FINISH at ' . formatdatetime("DD.MM.YYYY hh:mm:ss", time) . "\n";
            print $ps_file101 "==============================================================\n";
        close $ps_file101;
        close $ps_file102;
        print 'Version failure. Need version: ' . $ps_needversion . " - exit\n";
        print "===================================\n";
        $rs->finish();
        $conn1->disconnect();
        exit(1);
    }
    return;
}

#========================================================
sub load_second_light {
    #Фиксируем время по базам
    $ps_constr = 'SELECT NOW()';
    printlog_sql_u($ps_constr);
    @ln = $rs->fetchrow_array();
    $ps_time_us = $ln[0];
    printlog('Time in DB UserSide: ' . $ps_time_us);
    printlog("zsilence      = " . $zsilence);
    
    #Прописываемся в базу
    $ps_info = $zver . '|' . $zpath . '|' . $ps_time_us . '|';
    $ps_constr = "UPDATE tbl_conf SET VALUEMEMO = '" . $ps_info . "' WHERE PARAM = '" . $zmodule_param . "'";
    sql_do($ps_constr);

    return;
}

#========================================================
sub bufer_clear{
    #Сброс буферов в файлы
    close $ps_file101;
    open ($ps_file101, ">>" . $ps_rep_logupd) || die;
    close $ps_file102;
    open ($ps_file102, ">>" . $ps_rep_sql) || die;
    return;
}

#========================================================
sub ip2long {
    return unpack("N",inet_aton(shift));
}

#========================================================

sub mysqldatetounix {
    my($string)=@_;
    if (length($string) eq 10) {
        $string .= " 00:00:01";
    }
    $ps_year = substr($string, -length($string), 4);
    $ps_month = substr($string, -length($string) + 5, 2);
    $ps_day = substr($string, -length($string) + 8, 2);
    $ps_hour = substr($string, -length($string) + 11, 2);
    $ps_minute = substr($string, -length($string) + 14, 2);
    $ps_second = substr($string, -length($string) + 17, 2);
    if ($ps_month < 1) {
        $ps_month = '1';
    }
    if (!$ps_day) {
        $ps_day = '1';
    }
    $string = timelocal($ps_second, $ps_minute, $ps_hour, $ps_day, $ps_month-1, $ps_year);
    return $string;
}

#========================================================
