NUT (Network UPS Tools)



  • Захотелось мне пересадить свой pfSense на бесперебойник. Причём не просто так, а чтобы с обратной связью - чтобы при низком заряде батареи мой домашний сервер благополучно завершал работу, а при возобновлении питания - сам запускался. Вопрос ПО я почему-то стал изучать не со стороны pfSense, а с более кардинальной - со стороны FreeBSD. Ну и нашёл собственно NUT. Поставил из пэкэджэй FreeBSD 8.3, настроил (не без труда) и задумался как подключить всё это дело к интерфейсу pfSense, и оказалось (о чудо!) что NUT есть в пэкэджах самого pfSense прям в интерфейсе, причём очень актуальной версии!

    Снёс я свой NUT, поставил из-под pfSense, мой ИБП Powercom BNT-800AP pfSense почему-то не узнал (хотя я его выбирал специально под NUT т.к. он имеет уровень поддержки на 5 из 5 баллов), точнее его не было в списке моделей. Но после установки NUTа вручную прописать нужный драйвер (usbhid-ups вместо того что было) в ups.conf не составило труда. И всё тут же заработало.

    Вроде бы красиво - в сервисах открываем NUT и смотрим состояние. Но мне было бы удобней видеть состояние ИБП на общей панельке - на Dashboard. Стал я рыть дальше, и на буржуйском разделе pfSense нашёл почти готовый виджет (виджеты все тут: /usr/local/www/widgets/widgets):
    http://forum.pfsense.org/index.php/topic,43438.msg265128.html
    http://forum.pfsense.org/index.php/topic,43769.0.html
    Только вот автор пишет, что хотелось бы заставить работать виджет в режиме он-лайн, т.е. постоянно обновлять данные так же, как это делают другие виджеты. Ему там давали советы по "оживлению", но автор сослался что свободное время у него закончилось и возможности заниматься этой идеей нет.

    Собственно вопрос: а у нас тут в русском разделе случайно никто не может добить эту идею до логичного завершения? Т.е. прикрутить к виджету обновление данных. Ну и логичней бы смотрелись прогресс-бары в стиле загрузки CPU, памяти и т.п.:

    ЗЫ: Я тут ещё немного добавил к виджету автора: третью строку с информацией о загрузке ИБП и входящем/исходящем напряжении:

    
    /*
            $Id$
            Copyright 2008 Seth Mos
            Part of pfSense widgets (www.pfsense.com)
            originally based on m0n0wall (http://m0n0.ch/wall)
    
            Redistribution and use in source and binary forms, with or without
            modification, are permitted provided that the following conditions are met:
    
            1\. Redistributions of source code must retain the above copyright notice,
               this list of conditions and the following disclaimer.
    
            2\. Redistributions in binary form must reproduce the above copyright
               notice, this list of conditions and the following disclaimer in the
               documentation and/or other materials provided with the distribution.
    
            THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
            INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
            AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
            AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
            OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
            SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
            INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
            CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
            ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
            POSSIBILITY OF SUCH DAMAGE.
    */
    
    $nocsrf = true;
    
    require_once("guiconfig.inc");
    require_once("pfsense-utils.inc");
    require_once("functions.inc");
    
    $nut_config = $config['installedpackages']['nut']['config'][0];
    
    /* functions */
    
    function secs2hms($secs) {
         if ($secs<0) return false;
         $m = (int)($secs / 60); $s = $secs % 60;
         $h = (int)($m / 60); $m = $m % 60;
         return array($h, "h ", $m, "m ", $s, "s ");
    }
    
    function tblrowbar ($value, $symbol, $red, $yellow, $green) {
         if(!$value) return;
    
         $value = sprintf("%.1f", $value);
    
         $red = explode('-', $red);
         $yellow = explode('-', $yellow);
         $green = explode('-', $green);
    
         sort($red);
         sort($yellow);
         sort($green);
    
         if($value >= $red[0] && $value <= ($red[0]+9)) {
              $color = 'black';
              $bgcolor = 'red';
         }
         if($value >= ($red[0]+10) && $value <= $red[1]) {
              $color = 'white';
              $bgcolor = 'red';
         }
         if($value >= $yellow[0] && $value <= $yellow[1]) {
              $color = 'black';
              $bgcolor = 'yellow';
         }
         if($value >= $green[0] && $value <= ($green[0]+9)) {
              $color = 'black';
              $bgcolor = 'green';
         }
         if($value >= ($green[0]+10) && $value <= $green[1]) {
              $color = 'white';
              $bgcolor = 'green';
         }
    
         print(<< <eod<br>{$value}{$symbol}
    
    EOD
         ."\n");
    }
    
    ?>
    
    | Monitoring | Model | Status |
    | 
    
         $running = ((int)exec('pgrep upsmon | wc -l') > 0) ? true : false;
    
         if($nut_config['monitor'] == 'local') {
              echo "Local UPS";
              $cmd = "upsc {$nut_config['name']}@localhost";
         } elseif($nut_config['monitor'] == 'remote') {
              echo "Remote UPS";
              $cmd = "upsc {$nut_config['remotename']}@{$nut_config['remoteaddr']}";
         } elseif($nut_config['monitor'] == 'snmp') {
              echo "SNMP UPS";
              $cmd = "upsc {$nut_config['snmpname']}@localhost";
         }
    
    ?>
    
                           | 
    
    if($running)
              $handle = popen($cmd, 'r');
         elseif($nut_config['monitor'] == 'snmp')
              $condition = "NUT enabled but service not running!\nSNMP UPS may be unreachable.";
         else
              $condition = "NUT enabled but service not running!";
    
         if($handle) {
              $read = fread($handle, 4096);
              pclose($handle);
    
              $lines = explode("\n", $read);
              $ups = array();
              foreach($lines as $line) {
                   $line = explode(':', $line);
                   $ups[$line[0]] = trim($line[1]);
              }
    
              if(count($lines) == 1)
                   $condition = "ERROR:Data stale!";
    
              echo $ups['ups.model'];
    
              print(<< | 
    EOD
         ."\n");
    
              $status = explode(' ', $ups['ups.status']);
              foreach($status as $condition) {
                   if($disp_status) $disp_status .= ', ';
                   switch ($condition) {
                        case 'WAIT':
                             $disp_status .= 'Waiting';
                             break;
                        case 'OFF':
                             $disp_status .= 'Off Line';
                             break;
                        case 'OL':
                             $disp_status .= 'On Line';
                             break;
                        case 'OB':
                             $disp_status .= 'On Battery';
                             break;
                        case 'TRIM':
                             $disp_status .= 'SmartTrim';
                             break;
                        case 'BOOST':
                             $disp_status .= 'SmartBoost';
                             break;
                        case 'OVER':
                             $disp_status .= 'Overload';
                             break;
                        case 'LB':
                             $disp_status .= 'Battery Low';
                             break;
                        case 'RB':
                             $disp_status .= 'Replace Battery';
                             break;
                        case 'CAL':
                             $disp_status .= 'Calibration';
                             break;
                        case 'CHRG':
                             $disp_status .= 'Charging';
                             break;
                        default:
                             $disp_status .= $condition;
                             break;
                   }
              }
    
              echo $disp_status;
              print(<< |
    | Battery Charge | Runtime Remaining | Battery Voltage |
    | 
    EOD
         ."\n");
    
    /*          echo $ups['battery.charge'] . "%"; */
    
              tblrowbar($ups['battery.charge'], '%', '0-29' ,'30-79', '80-100');
    
              print(<< | 
    EOD
         ."\n");
    
              echo implode(secs2hms($ups['battery.runtime']));
    
              print(<< | 
    EOD
         ."\n");
    
              echo $ups['battery.voltage'] . "V";
              print(<< |
    | Load | Input Voltage | Output Voltage |
    | 
    EOD
         ."\n");
    
              tblrowbar($ups['ups.load'], '%', '100-80', '79-60', '59-0');
    
              print(<< | 
    EOD
         ."\n");
    
              echo $ups['input.voltage'] . "V";
    
              print(<< | 
    EOD
         ."\n");
    
              echo $ups['output.voltage'] . "V";
         }
    ?>
    
     |</eod<br> 
    


  • А такую красоту не пробовали организовать?

    З.Ы. Ссылка на скине рабочая.
    З.Ы.Ы. "Мопед не мой" (С)  ;D






  • Такую красоту видел. Как это организовать достаточно подробно написано тут (начиная со сборки порта):
    http://www.ignix.ru/book/freebsd/daemon/network_ups_tools
    Но pfSense команду make install не понимает, да и не особо интересно было ставить такую дополнительную штуковину. Хочется иметь всю информацию в одном месте - интерфейсе pfSense.

    ЗЫ: В этой красоте кстати данные тоже только по F5 обновляются ;)


Locked