You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3412 lines
211 KiB
3412 lines
211 KiB
#!/usr/bin/perl |
|
# |
|
# This uses data in the 'upses' database table (any that use this agent' to get a list of APC-brand UPSes to scan. |
|
# |
|
# Examples; |
|
# |
|
# Exit codes; |
|
# 0 - Success |
|
# 1 - Something went wrong, agent aborted run. |
|
# |
|
# 255 - The host's UUID isn't in the hosts table yet, ScanCore itself hasn't been run. |
|
# |
|
# TODO: |
|
# - Set a health score if we lose one or both/all UPSes. |
|
# - Support UPSes with extended runtime batteries |
|
# - Pick a battery temperature where the UPS will automatically shut down if it passes over. |
|
# - Add support for sudden temperature jumps in process_temperature(). |
|
# - It might be possible that a battery goes over temp, then is removed and not replaced, the UPS could keep |
|
# reporting a temp anomoly. |
|
# |
|
|
|
# Use my modules. |
|
use strict; |
|
use warnings; |
|
use Anvil::Tools; |
|
use Data::Dumper; |
|
use Socket; |
|
no warnings 'recursion'; |
|
|
|
# Disable buffering |
|
$| = 1; |
|
|
|
# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error. |
|
$< = $>; |
|
$( = $); |
|
|
|
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; |
|
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; |
|
if (($running_directory =~ /^\./) && ($ENV{PWD})) |
|
{ |
|
$running_directory =~ s/^\./$ENV{PWD}/; |
|
} |
|
|
|
my $anvil = Anvil::Tools->new(); |
|
|
|
# Make sure we're running as 'root' |
|
# $< == real UID, $> == effective UID |
|
if (($< != 0) && ($> != 0)) |
|
{ |
|
# Not root |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0005"}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Get the handle to the AN::Tools and preset some variables I will use. |
|
$anvil->data->{'scan-apc-ups'} = { |
|
# Starts at '2' so that anything set to '1' manually shows first |
|
alert_sort => 2, |
|
disable => 0, |
|
# By default, a temperature sensor will go into warning state when it goes over this number of °C |
|
# below the alert temperature reported by the UPS. |
|
temperature_warning_delta => 3, |
|
# This is the number of °C below a warning or critical level where an alert is cleared. |
|
temperature_clear_delta => 5, |
|
# If the temperature jumps by more than this amount in less than set time, an alert will be |
|
# generated. This is meant to help detect cooling loss. |
|
temperature_jump_threshold => 5, # degrees C |
|
temperature_jump_time => 60, # seconds |
|
# If the battery charge drops below this level, a warning level alert will be |
|
# triggered. |
|
low_charge_percentage_warning => 20, |
|
# If the battery charge rate climbs above this level, the user will be informed that |
|
# the UPS is back to an acceptible charge |
|
low_charge_percentage_ok => 25, |
|
# This is the number of volts above the low voltage trasfer lever or below the high |
|
# voltage transfer level needed to clear the alert. |
|
transfer_voltage_clear_delta => 2, |
|
# This is the number of scans in a row that an alert state needs to exist for before |
|
# we trigger an alarm. |
|
sensor_loss_count_to_alarm => 3, |
|
# This is the load percentage over which we trigger a high-load alert. |
|
high_load_threshold => 80, |
|
high_load_clear_threshold => 60, |
|
# This is the estimated hold-up time (in seconds) under which we trigger a low-hold-up-time alert. |
|
low_hold_up_threshold => 900, |
|
low_hold_up_clear_threshold => 1200, |
|
}; |
|
$anvil->data->{oids} = { |
|
battery => { |
|
# Estimated next replacement date (in 'mm/dd/yy' or 'mm/dd/yyyy' format.) |
|
next_replacement_date => ".1.3.6.1.4.1.318.1.1.1.2.2.21.0", |
|
# 1 => OK, 2 => Replacement needed |
|
health => ".1.3.6.1.4.1.318.1.1.1.2.2.4.0", |
|
model => ".1.3.6.1.4.1.318.1.1.1.2.2.19.0", |
|
# High precision, (1000 = 100.0% charge) |
|
percentage_charge_hp => ".1.3.6.1.4.1.318.1.1.1.2.3.1.0", |
|
# Last approximate replacement date (mm/dd/yy or yyyy format) |
|
last_replacement_date => ".1.3.6.1.4.1.318.1.1.1.2.1.3.0", |
|
# 1 => unknown, 2 => batteryNormal, 3 => batteryLow, |
|
# 4 => batteryInFaultCondition |
|
'state' => ".1.3.6.1.4.1.318.1.1.1.2.1.1.0", |
|
# High-precision, (315 == 31.5) |
|
temperature_hp => ".1.3.6.1.4.1.318.1.1.1.2.3.2.0", |
|
# Temperature alarm upper limit (in even degrees, 40 = 40*C or *F |
|
# (see ups::temperature_units)) |
|
alarm_temperature => ".1.3.6.1.4.1.318.1.1.10.1.2.2.1.3.1", |
|
# High precision voltage (271 = 27.1 vDC) |
|
voltage_hp => ".1.3.6.1.4.1.318.1.1.1.2.3.4.0", |
|
}, |
|
input => { |
|
# High precision, (600 == 60.0 Hz) |
|
frequency_hp => ".1.3.6.1.4.1.318.1.1.1.3.3.4.0", |
|
# 1 => Auto, 2 => Low, 3 => Medium, 4 => High |
|
sensitivity => ".1.3.6.1.4.1.318.1.1.1.5.2.7.0", |
|
# High precision, (1245 => "124.5 vAC) |
|
voltage_hp => ".1.3.6.1.4.1.318.1.1.1.3.3.1.0", |
|
# High precision; Maximum and minimum voltage in the last 60 seconds (1245 == 124.5 vAC) |
|
'1m_maximum_input_voltage_hp' => ".1.3.6.1.4.1.318.1.1.1.3.3.2.0", |
|
'1m_minimum_input_voltage_hp' => ".1.3.6.1.4.1.318.1.1.1.3.3.3.0", |
|
}, |
|
ups => { |
|
# Time in tickss after AC restore before UPS powers on (ie: 1000 = 10 seconds) |
|
ac_restore_delay => ".1.3.6.1.4.1.318.1.1.1.5.2.9.0", |
|
# How many batteries are in the UPS. |
|
battery_count => ".1.3.6.1.4.1.318.1.1.1.2.2.5.0", |
|
# Delay time from when the shutdown command is sent until when the UPS |
|
# actually powers off (measured in ticks) |
|
shutdown_delay => ".1.3.6.1.4.1.318.1.1.1.5.2.10.0", |
|
firmware_version => ".1.3.6.1.4.1.318.1.1.1.1.2.1.0", |
|
# The modes are documented as 'scan_apc_ups_health_00{01..20}' with |
|
# the integer value correlating to the returned health integer value. |
|
health => ".1.3.6.1.4.1.318.1.1.1.4.1.1.0", |
|
# Voltage at which TRIM ONLINE kicks in (127 == 127 vAC) |
|
high_transfer_voltage => ".1.3.6.1.4.1.318.1.1.1.5.2.2.0", |
|
# 1 => noTransfer, 2 => highLineVoltage, 3 => brownout, |
|
# 4 => blackout, 5 => smallMomentarySag, 6 => deepMomentarySag, |
|
# 7 => smallMomentarySpike, 8 => largeMomentarySpike, |
|
# 9 => selfTest, 10 => rateOfVoltageChange |
|
last_transfer_reason => ".1.3.6.1.4.1.318.1.1.1.3.2.5.0", |
|
# Voltage at which BOOST ONLINE kicks in (106 == 106vAC) |
|
low_transfer_voltage => ".1.3.6.1.4.1.318.1.1.1.5.2.3.0", |
|
# Manufactured date (in 'mm/dd/yy' or 'mm/dd/yyyy' format.) |
|
manufactured_date => ".1.3.6.1.4.1.318.1.1.1.1.2.2.0", |
|
model => ".1.3.6.1.4.1.318.1.1.1.1.2.5.0", |
|
# Temperature units (1 = *C, 2 = *F) |
|
temperature_units => ".1.3.6.1.4.1.318.1.1.10.1.2.2.1.5.1", |
|
serial_number => ".1.3.6.1.4.1.318.1.1.1.1.2.3.0", |
|
# This is used to power off the UPS. Set: |
|
# 2 = turnUpsOff (no delay), |
|
# 3 = turnUpsOffGracefully (use delay) |
|
power_off => ".1.3.6.1.4.1.318.1.1.1.6.2.1.0", |
|
}, |
|
nmc => { |
|
firmware_version => ".1.3.6.1.4.1.318.1.4.2.4.1.4.1", |
|
serial_number => ".1.3.6.1.4.1.318.1.4.2.4.1.2.1", |
|
mac_address => ".1.3.6.1.2.1.4.30.1.4.2", |
|
}, |
|
output => { |
|
# High precision, Current load percentage (58 = 5.8%) |
|
load_percentage_hp => ".1.3.6.1.4.1.318.1.1.1.4.3.3.0", |
|
# Time in ticks on batteries, 0 == not on batteries |
|
time_on_batteries => ".1.3.6.1.4.1.318.1.1.1.2.1.2.0", |
|
# In ticks (10ms) |
|
estimated_runtime => ".1.3.6.1.4.1.318.1.1.1.2.2.3.0", |
|
# high-precision, (600 == 60.0 Hz) |
|
frequency_hp => ".1.3.6.1.4.1.318.1.1.1.4.3.2.0", |
|
# High precision (1245 = 124.5 vAC) |
|
voltage_hp => ".1.3.6.1.4.1.318.1.1.1.4.3.1.0", |
|
# Total output power (in 10 watt-hour increments, divide by 100 |
|
# for kW/hr |
|
total_output => ".1.3.6.1.4.1.318.1.1.1.4.3.6.0", |
|
}, |
|
}; |
|
$anvil->data->{snmp} = { |
|
alternate => { |
|
'SUART' => { |
|
}, |
|
}, |
|
community => { |
|
'read' => "public", |
|
version => "2c", |
|
'write' => "private", |
|
}, |
|
}; |
|
|
|
$anvil->Storage->read_config(); |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }}); |
|
|
|
# Read switches |
|
$anvil->Get->switches; |
|
|
|
# Too many connections cause the UPS to lag out, so we only run on Strikers. |
|
my $host_type = $anvil->Get->host_type(); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); |
|
if (($host_type ne "striker") && (not $anvil->data->{switches}{force})) |
|
{ |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Handle start-up tasks |
|
my $problem = $anvil->ScanCore->agent_startup({agent => $THIS_FILE}); |
|
if ($problem) |
|
{ |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
if ($anvil->data->{switches}{purge}) |
|
{ |
|
# This can be called when doing bulk-database purges. |
|
my $schema_file = $anvil->data->{path}{directories}{scan_agents}."/".$THIS_FILE."/".$THIS_FILE.".sql"; |
|
$anvil->Database->purge_data({ |
|
debug => 2, |
|
tables => $anvil->Database->get_tables_from_schema({schema_file => $schema_file}), |
|
}); |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
|
|
# Find the UPSes. The number of UPSes found is returned. If 0, we exit |
|
if (not find_upses($anvil)) |
|
{ |
|
# No UPSes found. |
|
$anvil->Log->entry({log_level => 1, 'print' => 1, message_key => "scan_apc_ups_message_0001", file => $THIS_FILE, line => __LINE__}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Read the last state of any UPSes we already know about |
|
read_last_scan($anvil); |
|
|
|
# Gather details on UPSes. |
|
gather_ups_data($anvil); |
|
|
|
# Look for changes. |
|
find_changes($anvil); |
|
|
|
# Shut down. |
|
$anvil->ScanCore->agent_shutdown({agent => $THIS_FILE}); |
|
|
|
|
|
############################################################################################################# |
|
# Functions # |
|
############################################################################################################# |
|
|
|
# This reads in the last scan data from one of the databases and compares it against the just-read data. If |
|
# anything changed, register an alert. |
|
sub find_changes |
|
{ |
|
my ($anvil) = @_; |
|
|
|
# This stores all the queries so that they're committed in one transaction. |
|
$anvil->data->{sys}{queries} = []; |
|
$anvil->data->{'scan-apc-ups'}{alert_sort} = 1; |
|
|
|
# Loop through each UPS we've seen this pass |
|
foreach my $scan_apc_ups_uuid (sort {$a cmp $b} keys %{$anvil->data->{ups}{scan_apc_ups_uuid}}) |
|
{ |
|
my $new_ups = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{new_ups}; |
|
my $ups_uuid = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_upses}{scan_apc_ups_ups_uuid}; |
|
my $scan_apc_ups_serial_number = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_serial_number}; |
|
my $scan_apc_ups_name = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_name}; |
|
my $scan_apc_ups_ip = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ip}; |
|
my $scan_apc_ups_ac_restore_delay = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay}; |
|
my $scan_apc_ups_shutdown_delay = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay}; |
|
my $scan_apc_ups_firmware_version = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version}; |
|
my $scan_apc_ups_health = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_health}; |
|
my $scan_apc_ups_high_transfer_voltage = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_high_transfer_voltage}; |
|
my $scan_apc_ups_low_transfer_voltage = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_low_transfer_voltage}; |
|
my $scan_apc_ups_last_transfer_reason = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_last_transfer_reason}; |
|
my $scan_apc_ups_manufactured_date = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date}; |
|
my $scan_apc_ups_model = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_model}; |
|
my $scan_apc_ups_nmc_firmware_version = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_firmware_version}; |
|
my $scan_apc_ups_nmc_serial_number = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_serial_number}; |
|
my $scan_apc_ups_nmc_mac_address = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
new_ups => $new_ups, |
|
ups_uuid => $ups_uuid, |
|
scan_apc_ups_serial_number => $scan_apc_ups_serial_number, |
|
scan_apc_ups_ip => $scan_apc_ups_ip, |
|
scan_apc_ups_ac_restore_delay => $scan_apc_ups_ac_restore_delay, |
|
scan_apc_ups_shutdown_delay => $scan_apc_ups_shutdown_delay, |
|
scan_apc_ups_firmware_version => $scan_apc_ups_firmware_version, |
|
scan_apc_ups_health => $scan_apc_ups_health, |
|
scan_apc_ups_high_transfer_voltage => $scan_apc_ups_high_transfer_voltage, |
|
scan_apc_ups_low_transfer_voltage => $scan_apc_ups_low_transfer_voltage, |
|
scan_apc_ups_last_transfer_reason => $scan_apc_ups_last_transfer_reason, |
|
scan_apc_ups_manufactured_date => $scan_apc_ups_manufactured_date, |
|
scan_apc_ups_model => $scan_apc_ups_model, |
|
scan_apc_ups_nmc_firmware_version => $scan_apc_ups_nmc_firmware_version, |
|
scan_apc_ups_nmc_serial_number => $scan_apc_ups_nmc_serial_number, |
|
scan_apc_ups_nmc_mac_address => $scan_apc_ups_nmc_mac_address, |
|
}}); |
|
|
|
# These are loaded now as some variables are needed when examining others from other tables. |
|
my $scan_apc_ups_input_1m_minimum_input_voltage = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage}; |
|
my $scan_apc_ups_input_1m_maximum_input_voltage = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage}; |
|
my $scan_apc_ups_input_voltage = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage}; |
|
my $scan_apc_ups_input_sensitivity = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}; |
|
my $scan_apc_ups_input_frequency = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
scan_apc_ups_input_1m_minimum_input_voltage => $scan_apc_ups_input_1m_minimum_input_voltage, |
|
scan_apc_ups_input_1m_maximum_input_voltage => $scan_apc_ups_input_1m_maximum_input_voltage, |
|
scan_apc_ups_input_voltage => $scan_apc_ups_input_voltage, |
|
scan_apc_ups_input_sensitivity => $scan_apc_ups_input_sensitivity, |
|
scan_apc_ups_input_frequency => $scan_apc_ups_input_frequency, |
|
}}); |
|
|
|
my $scan_apc_ups_output_voltage = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}; |
|
my $scan_apc_ups_output_total_output = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}; |
|
my $scan_apc_ups_output_frequency = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}; |
|
my $scan_apc_ups_output_time_on_batteries = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries}; |
|
my $scan_apc_ups_output_estimated_runtime = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime}; |
|
my $scan_apc_ups_output_load_percentage = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
scan_apc_ups_output_voltage => $scan_apc_ups_output_voltage, |
|
scan_apc_ups_output_total_output => $scan_apc_ups_output_total_output, |
|
scan_apc_ups_output_frequency => $scan_apc_ups_output_frequency, |
|
scan_apc_ups_output_time_on_batteries => $scan_apc_ups_output_time_on_batteries, |
|
scan_apc_ups_output_estimated_runtime => $scan_apc_ups_output_estimated_runtime, |
|
scan_apc_ups_output_load_percentage => $scan_apc_ups_output_load_percentage, |
|
}}); |
|
|
|
# Have I seen this UPS before? |
|
if ($new_ups) |
|
{ |
|
# New, INSERT it. |
|
my $query = " |
|
INSERT INTO |
|
scan_apc_upses |
|
( |
|
scan_apc_ups_uuid, |
|
scan_apc_ups_ups_uuid, |
|
scan_apc_ups_name, |
|
scan_apc_ups_ip, |
|
scan_apc_ups_ac_restore_delay, |
|
scan_apc_ups_shutdown_delay, |
|
scan_apc_ups_firmware_version, |
|
scan_apc_ups_health, |
|
scan_apc_ups_high_transfer_voltage, |
|
scan_apc_ups_low_transfer_voltage, |
|
scan_apc_ups_last_transfer_reason, |
|
scan_apc_ups_manufactured_date, |
|
scan_apc_ups_model, |
|
scan_apc_ups_serial_number, |
|
scan_apc_ups_nmc_firmware_version, |
|
scan_apc_ups_nmc_serial_number, |
|
scan_apc_ups_nmc_mac_address, |
|
modified_date |
|
) VALUES ( |
|
".$anvil->Database->quote($scan_apc_ups_uuid).", |
|
".$anvil->Database->quote($ups_uuid).", |
|
".$anvil->Database->quote($scan_apc_ups_name).", |
|
".$anvil->Database->quote($scan_apc_ups_ip).", |
|
".$anvil->Database->quote($scan_apc_ups_ac_restore_delay).", |
|
".$anvil->Database->quote($scan_apc_ups_shutdown_delay).", |
|
".$anvil->Database->quote($scan_apc_ups_firmware_version).", |
|
".$anvil->Database->quote($scan_apc_ups_health).", |
|
".$anvil->Database->quote($scan_apc_ups_high_transfer_voltage).", |
|
".$anvil->Database->quote($scan_apc_ups_low_transfer_voltage).", |
|
".$anvil->Database->quote($scan_apc_ups_last_transfer_reason).", |
|
".$anvil->Database->quote($scan_apc_ups_manufactured_date).", |
|
".$anvil->Database->quote($scan_apc_ups_model).", |
|
".$anvil->Database->quote($scan_apc_ups_serial_number).", |
|
".$anvil->Database->quote($scan_apc_ups_nmc_firmware_version).", |
|
".$anvil->Database->quote($scan_apc_ups_nmc_serial_number).", |
|
".$anvil->Database->quote($scan_apc_ups_nmc_mac_address).", |
|
".$anvil->Database->quote($anvil->Database->refresh_timestamp)." |
|
);"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); |
|
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); |
|
|
|
my $variables = { |
|
name => $scan_apc_ups_name, |
|
model => $scan_apc_ups_model, |
|
serial_number => $scan_apc_ups_serial_number, |
|
manufactured_date => $scan_apc_ups_manufactured_date, |
|
firmware_version => $scan_apc_ups_firmware_version, |
|
ip_address => $scan_apc_ups_ip, |
|
nmc_serial_number => $scan_apc_ups_nmc_serial_number, |
|
nmc_firmware_version => $scan_apc_ups_nmc_firmware_version, |
|
nmc_mac_address => $scan_apc_ups_nmc_mac_address, |
|
ac_restore_delay => $scan_apc_ups_ac_restore_delay, |
|
shutdown_delay => $scan_apc_ups_shutdown_delay, |
|
health => "#!string!scan_apc_ups_health_".sprintf("%04d", $scan_apc_ups_health)."!#", |
|
high_transfer_voltage => $scan_apc_ups_high_transfer_voltage, |
|
low_transfer_voltage => $scan_apc_ups_low_transfer_voltage, |
|
last_transfer_reason => "#!string!scan_apc_ups_last_xfer_".sprintf("%04d", $scan_apc_ups_last_transfer_reason)."!#", |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_message_0002", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_message_0002", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
|
|
# Add any batteries. |
|
foreach my $battery_number (sort {$a cmp $b} keys %{$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}}) |
|
{ |
|
my $scan_apc_ups_battery_uuid = insert_battery($anvil, $scan_apc_ups_uuid, $battery_number); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_apc_ups_battery_uuid => $scan_apc_ups_battery_uuid }}); |
|
} |
|
|
|
# Record input data |
|
my $scan_apc_ups_input_uuid = insert_input($anvil, $scan_apc_ups_uuid); |
|
|
|
# Record output data |
|
my $scan_apc_ups_output_uuid = insert_output($anvil, $scan_apc_ups_uuid); |
|
} |
|
else |
|
{ |
|
# Existing UPS, look for changes. |
|
my $old_scan_apc_ups_ups_uuid = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ups_uuid}; |
|
my $old_scan_apc_ups_serial_number = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_serial_number}; |
|
my $old_scan_apc_ups_name = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_name}; |
|
my $old_scan_apc_ups_ip = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ip}; |
|
my $old_scan_apc_ups_ac_restore_delay = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay}; |
|
my $old_scan_apc_ups_shutdown_delay = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay}; |
|
my $old_scan_apc_ups_firmware_version = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version}; |
|
my $old_scan_apc_ups_health = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_health}; |
|
my $old_scan_apc_ups_high_transfer_voltage = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_high_transfer_voltage}; |
|
my $old_scan_apc_ups_low_transfer_voltage = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_low_transfer_voltage}; |
|
my $old_scan_apc_ups_last_transfer_reason = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_last_transfer_reason}; |
|
my $old_scan_apc_ups_manufactured_date = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date}; |
|
my $old_scan_apc_ups_model = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_model}; |
|
my $old_scan_apc_ups_nmc_firmware_version = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_firmware_version}; |
|
my $old_scan_apc_ups_nmc_serial_number = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_serial_number}; |
|
my $old_scan_apc_ups_nmc_mac_address = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
old_scan_apc_ups_ups_uuid => $old_scan_apc_ups_ups_uuid, |
|
old_scan_apc_ups_serial_number => $old_scan_apc_ups_serial_number, |
|
old_scan_apc_ups_name => $old_scan_apc_ups_name, |
|
old_scan_apc_ups_ip => $old_scan_apc_ups_ip, |
|
old_scan_apc_ups_ac_restore_delay => $old_scan_apc_ups_ac_restore_delay, |
|
old_scan_apc_ups_shutdown_delay => $old_scan_apc_ups_shutdown_delay, |
|
old_scan_apc_ups_firmware_version => $old_scan_apc_ups_firmware_version, |
|
old_scan_apc_ups_health => $old_scan_apc_ups_health, |
|
old_scan_apc_ups_high_transfer_voltage => $old_scan_apc_ups_high_transfer_voltage, |
|
old_scan_apc_ups_low_transfer_voltage => $old_scan_apc_ups_low_transfer_voltage, |
|
old_scan_apc_ups_last_transfer_reason => $old_scan_apc_ups_last_transfer_reason, |
|
old_scan_apc_ups_manufactured_date => $old_scan_apc_ups_manufactured_date, |
|
old_scan_apc_ups_model => $old_scan_apc_ups_model, |
|
old_scan_apc_ups_nmc_firmware_version => $old_scan_apc_ups_nmc_firmware_version, |
|
old_scan_apc_ups_nmc_serial_number => $old_scan_apc_ups_nmc_serial_number, |
|
old_scan_apc_ups_nmc_mac_address => $old_scan_apc_ups_nmc_mac_address, |
|
}}); |
|
|
|
my $ups_changed = 0; |
|
if ($scan_apc_ups_name ne $old_scan_apc_ups_name) |
|
{ |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
old_name => $scan_apc_ups_name, |
|
new_name => $old_scan_apc_ups_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0005", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0005", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
if ($scan_apc_ups_serial_number ne $old_scan_apc_ups_serial_number) |
|
{ |
|
# Likely a replacement UPS. |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_serial_number, |
|
new_value => $scan_apc_ups_serial_number, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0006", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0006", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
if ($scan_apc_ups_ip ne $old_scan_apc_ups_ip) |
|
{ |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_ip, |
|
new_value => $scan_apc_ups_ip, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0007", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0007", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
if ($scan_apc_ups_model ne $old_scan_apc_ups_model) |
|
{ |
|
# Likely a replacement UPS. |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_model, |
|
new_value => $scan_apc_ups_model, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0008", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0008", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
if ($scan_apc_ups_ac_restore_delay ne $old_scan_apc_ups_ac_restore_delay) |
|
{ |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_ac_restore_delay, |
|
new_value => $scan_apc_ups_ac_restore_delay, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0009", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0009", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
if ($scan_apc_ups_shutdown_delay ne $old_scan_apc_ups_shutdown_delay) |
|
{ |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_shutdown_delay, |
|
new_value => $scan_apc_ups_shutdown_delay, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0010", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0010", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
if ($scan_apc_ups_firmware_version ne $old_scan_apc_ups_firmware_version) |
|
{ |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_firmware_version, |
|
new_value => $scan_apc_ups_firmware_version, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0011", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0011", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
|
|
# Has the health changed? This is fairly complex as there are many possible health |
|
# values. |
|
if ($scan_apc_ups_health ne $old_scan_apc_ups_health) |
|
{ |
|
my $level = "notice"; |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
### There are 20 possible states |
|
### (* == warning, rest are notice): |
|
# *1 - The UPS's health is in an unknown state. |
|
# 2 - The UPS is operating normally. |
|
# 3 - The UPS is running on its batteries. See below for checks if input |
|
# voltage remains. If not, this will indicate a power loss event. |
|
# 4 - The UPS is compensating for low input power. This is treated as being |
|
# on batteries. |
|
# 5 - The UPS is in a timed sleep. It will power back on when the timer has |
|
# expired. |
|
# 6 - The UPS is in bypass-mode and was placed in this mode by software. |
|
# Power is passing to downstream devices through a radio frequency |
|
# interference filter, but is not conditioned in any other way. Batter |
|
# protection is not available. |
|
# *7 - The UPS is off. No power is being provided to down-stream equipment. |
|
# *8 - The UPS is currently rebooting. |
|
# 9 - The UPS is in bypass-mode and was placed in this mode by a hardware |
|
# switch. Power is passing to downstream devices through a radio |
|
# frequency interference filter, but is not conditioned in any other |
|
# way. Batter protection is not available. |
|
# 10 - The UPS is in bypass-mode because of an internal failure. Power is |
|
# passing to downstream devices through a radio frequency interference |
|
# filter, but is not conditioned in any other way. Batter protection is |
|
# not available. |
|
# *11 - The UPS has lost input power and is sleeping. It will restore output |
|
# power once input power has been restored. |
|
# 12 - The UPS is compensating for high input voltage. |
|
# 13 - The UPS is operating in low-power mode. In this mode, the UPS is in |
|
# static bypass mode and it is drawing very little power. If a fault is |
|
# detected, it will switch to either normal operation or forced static |
|
# bypass mode. |
|
# 14 - The UPS is operating in hot-standby mode. |
|
# 15 - The UPS is performing a test of its batteries. |
|
# *16 - The UPS has been placed in emergency static bypass mode. Power is |
|
# passing to downstream devices through a radio frequency interference |
|
# filter, but is not conditioned in any other way. Batter protection is |
|
# not available. |
|
# 17 - The UPS is in static bypass standby mode. It is not currently |
|
# providing power to downstream devices. |
|
# 18 - The UPS is in power saving mode. The front panel display will be off |
|
# but the UPS is operating normally. |
|
# 19 - The UPS is in SPoT (Self Power Test) operating mode. |
|
# - http://www.apcmedia.com/salestools/COCR-9TZK8N/COCR-9TZK8N_R0_EN.pdf |
|
# 20 - The UPS is in ECOnversion mode. The UPS is providing power to the |
|
# downstream devices via the bypass. The UPS's inverter is operational |
|
# and ready to take over the output load if an input fault occurs. |
|
# - http://www.apcmedia.com/salestools/MBPN-9HCLNT/MBPN-9HCLNT_R0_EN.pdf |
|
# ----[ Fake ones ]---- |
|
# 30 - The UPS is running on batteries but there is still input voltage, but |
|
# it is higher than the high transfer voltage so we're TRIMing. |
|
# 31 - The UPS is running on batteries but there is still input voltage, but |
|
# it is lower than the low transfer voltage so we're BOOSTing |
|
# 32 - The UPS is running on batteries but there is still nominal input |
|
# voltage, so it is likely a self-test. |
|
|
|
# Make sure we have a valid health integer |
|
my $say_scan_apc_ups_health = $scan_apc_ups_health; |
|
my $say_old_scan_apc_ups_health = $old_scan_apc_ups_health; |
|
if (($scan_apc_ups_health =~ /\D/) or (($scan_apc_ups_health < 0) or ($scan_apc_ups_health > 20))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$say_scan_apc_ups_health = 99; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_scan_apc_ups_health => $say_scan_apc_ups_health }}); |
|
} |
|
elsif (($old_scan_apc_ups_health =~ /\D/) or (($old_scan_apc_ups_health < 0) or ($old_scan_apc_ups_health > 20))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$say_old_scan_apc_ups_health = 99; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_old_scan_apc_ups_health => $say_old_scan_apc_ups_health }}); |
|
} |
|
|
|
# If the UPS is on batteries, check the input voltage. If there is |
|
# still power we'll indicate a self-test. |
|
if ($scan_apc_ups_health eq "3") |
|
{ |
|
if ($scan_apc_ups_input_voltage > $scan_apc_ups_high_transfer_voltage) |
|
{ |
|
$scan_apc_ups_health = 30; |
|
} |
|
elsif ($scan_apc_ups_input_voltage < 10) |
|
{ |
|
# Actual power loss. |
|
$scan_apc_ups_health = 3; |
|
$level = "warning"; |
|
} |
|
elsif ($scan_apc_ups_input_voltage < $scan_apc_ups_low_transfer_voltage) |
|
{ |
|
$scan_apc_ups_health = 31; |
|
} |
|
else |
|
{ |
|
$scan_apc_ups_health = 32; |
|
} |
|
} |
|
# Now check if power is back. |
|
if ($old_scan_apc_ups_health eq "3") |
|
{ |
|
# Clear the alert. |
|
$level = "warning"; |
|
} |
|
|
|
# If the old or new level is one worthy of a warning, set the alert level to |
|
# warning. |
|
if (($scan_apc_ups_health eq "1") or |
|
($scan_apc_ups_health eq "7") or |
|
($scan_apc_ups_health eq "8") or |
|
($scan_apc_ups_health eq "11") or |
|
($scan_apc_ups_health eq "16")) |
|
{ |
|
# Entered a warning state. |
|
$level = "warning"; |
|
} |
|
elsif (($old_scan_apc_ups_health eq "1") or |
|
($old_scan_apc_ups_health eq "7") or |
|
($old_scan_apc_ups_health eq "8") or |
|
($old_scan_apc_ups_health eq "11") or |
|
($old_scan_apc_ups_health eq "16")) |
|
{ |
|
# Warning state cleared. |
|
$level = "warning"; |
|
} |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => "#!string!scan_apc_ups_health_".sprintf("%04d", $say_scan_apc_ups_health)."!#", |
|
old_value => "#!string!scan_apc_ups_health_".sprintf("%04d", $say_old_scan_apc_ups_health)."!#", |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0012", variables => $variables}); |
|
$anvil->Alert->register({alert_level => $level, message => "scan_apc_ups_warning_0012", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
|
|
if ($scan_apc_ups_low_transfer_voltage ne $old_scan_apc_ups_low_transfer_voltage) |
|
{ |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
# This is a 'notice' level alert. Which message we use will depend on whether |
|
# the threshold increased or decreased. |
|
my $message_key = "scan_apc_ups_warning_0013"; |
|
if ($scan_apc_ups_low_transfer_voltage < $old_scan_apc_ups_low_transfer_voltage) |
|
{ |
|
$message_key = "scan_apc_ups_warning_0014"; |
|
} |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_low_transfer_voltage, |
|
old_value => $old_scan_apc_ups_low_transfer_voltage, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => $message_key, variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
|
|
# Has the last transfer reason changed? There are 10 reasons why this might happen, |
|
# some being more critical than others. |
|
if ($scan_apc_ups_last_transfer_reason ne $old_scan_apc_ups_last_transfer_reason) |
|
{ |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
### NOTE: This used to be 'warning' level, but it caused way too many false |
|
### alarms. If a serious issue arises, the input voltage will trigger a |
|
### 'warning' level alert. |
|
### There are 10 possible states |
|
# 0 - There is no information on when the UPS last transferred to battery. |
|
# 1 - The UPS has not transferred to battery power since the last time it booted. |
|
# 2 - The UPS last transferred to batteries because of high input voltage. |
|
# 3 - The UPS last transferred to batteries because of a brown out. That is, a prolonged drop in input voltage from the mains circuit. |
|
# 4 - The UPS last transferred to batteries because of a black out. That is, a prolonged loss of input voltage from the mains circuit. |
|
# 5 - The UPS last transferred to batteries because of a brief, minor reduction of input voltage from the mains circuit. |
|
# 6 - The UPS last transferred to batteries because of a brief, significant reduction of input voltage from the mains circuit. |
|
# 7 - The UPS last transferred to batteries because of a brief, minor increase of input voltage from the mains circuit. |
|
# 8 - The UPS last transferred to batteries because of a brief, significant spike of input voltage from the mains circuit. |
|
# 9 - The UPS last transferred to batteries as part of a planned self-test. |
|
# 10 - The UPS last transferred to batteries because of a significant change of input voltage from the mains circuit. |
|
|
|
# Make sure we have a valid health integer |
|
my $say_scan_apc_ups_last_transfer_reason = $scan_apc_ups_last_transfer_reason; |
|
my $say_old_scan_apc_ups_last_transfer_reason = $old_scan_apc_ups_last_transfer_reason; |
|
if (($scan_apc_ups_last_transfer_reason =~ /\D/) or (($scan_apc_ups_last_transfer_reason < 0) or ($scan_apc_ups_last_transfer_reason > 10))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$say_scan_apc_ups_last_transfer_reason = 99; |
|
} |
|
elsif (($old_scan_apc_ups_last_transfer_reason =~ /\D/) or (($old_scan_apc_ups_last_transfer_reason < 0) or ($old_scan_apc_ups_last_transfer_reason > 10))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$say_old_scan_apc_ups_last_transfer_reason = 99; |
|
} |
|
|
|
# The level of the alert will depends on the now/old state |
|
my $log_level = 3; |
|
my $alert_level = "info"; |
|
if (($scan_apc_ups_last_transfer_reason eq "2") or ($old_scan_apc_ups_last_transfer_reason eq "2") or |
|
($scan_apc_ups_last_transfer_reason eq "3") or ($old_scan_apc_ups_last_transfer_reason eq "3") or |
|
($scan_apc_ups_last_transfer_reason eq "4") or ($old_scan_apc_ups_last_transfer_reason eq "3") or |
|
($scan_apc_ups_last_transfer_reason eq "6") or ($old_scan_apc_ups_last_transfer_reason eq "6") or |
|
($scan_apc_ups_last_transfer_reason eq "8") or ($old_scan_apc_ups_last_transfer_reason eq "8") or |
|
($scan_apc_ups_last_transfer_reason eq "10") or ($old_scan_apc_ups_last_transfer_reason eq "10")) |
|
{ |
|
$log_level = 2; |
|
$alert_level = "notice"; |
|
} |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => "#!string!scan_apc_ups_last_transfer_".sprintf("%04d", $say_scan_apc_ups_last_transfer_reason)."!#", |
|
old_value => "#!string!scan_apc_ups_last_transfer_".sprintf("%04d", $say_old_scan_apc_ups_last_transfer_reason)."!#", |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => "scan_apc_ups_warning_0015", variables => $variables}); |
|
$anvil->Alert->register({alert_level => $alert_level, message => "scan_apc_ups_warning_0015", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
if ($scan_apc_ups_manufactured_date ne $old_scan_apc_ups_manufactured_date) |
|
{ |
|
# Likely a replacement UPS. |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_manufactured_date, |
|
new_value => $scan_apc_ups_manufactured_date, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0016", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0016", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
|
|
# Has the NMC's firmware changed? |
|
if ($scan_apc_ups_nmc_firmware_version ne $old_scan_apc_ups_nmc_firmware_version) |
|
{ |
|
# NMC was either updated or replaced. |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_nmc_firmware_version, |
|
new_value => $scan_apc_ups_nmc_firmware_version, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0017", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0017", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
|
|
# Has the NMC serial number changed? If the user changed the network card, |
|
# this could be triggered. |
|
if ($scan_apc_ups_nmc_serial_number ne $old_scan_apc_ups_nmc_serial_number) |
|
{ |
|
# NMC was probably replaced |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_nmc_serial_number, |
|
new_value => $scan_apc_ups_nmc_serial_number, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0018", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0018", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
|
|
# As with above, if the MAC address changed, it is probably because the NMC |
|
# was replaced. |
|
if ($scan_apc_ups_nmc_mac_address ne $old_scan_apc_ups_nmc_mac_address) |
|
{ |
|
# NMC was probably replaced |
|
$ups_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_changed => $ups_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
old_value => $old_scan_apc_ups_nmc_mac_address, |
|
new_value => $scan_apc_ups_nmc_mac_address, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0019", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0019", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
|
|
if ($ups_changed) |
|
{ |
|
my $query = " |
|
UPDATE |
|
scan_apc_upses |
|
SET |
|
scan_apc_ups_name = ".$anvil->Database->quote($scan_apc_ups_name).", |
|
scan_apc_ups_ip = ".$anvil->Database->quote($scan_apc_ups_ip).", |
|
scan_apc_ups_serial_number = ".$anvil->Database->quote($scan_apc_ups_serial_number).", |
|
scan_apc_ups_ac_restore_delay = ".$anvil->Database->quote($scan_apc_ups_ac_restore_delay).", |
|
scan_apc_ups_shutdown_delay = ".$anvil->Database->quote($scan_apc_ups_shutdown_delay).", |
|
scan_apc_ups_firmware_version = ".$anvil->Database->quote($scan_apc_ups_firmware_version).", |
|
scan_apc_ups_health = ".$anvil->Database->quote($scan_apc_ups_health).", |
|
scan_apc_ups_high_transfer_voltage = ".$anvil->Database->quote($scan_apc_ups_high_transfer_voltage).", |
|
scan_apc_ups_low_transfer_voltage = ".$anvil->Database->quote($scan_apc_ups_low_transfer_voltage).", |
|
scan_apc_ups_last_transfer_reason = ".$anvil->Database->quote($scan_apc_ups_last_transfer_reason).", |
|
scan_apc_ups_manufactured_date = ".$anvil->Database->quote($scan_apc_ups_manufactured_date).", |
|
scan_apc_ups_model = ".$anvil->Database->quote($scan_apc_ups_model).", |
|
scan_apc_ups_nmc_firmware_version = ".$anvil->Database->quote($scan_apc_ups_nmc_firmware_version).", |
|
scan_apc_ups_nmc_serial_number = ".$anvil->Database->quote($scan_apc_ups_nmc_serial_number).", |
|
scan_apc_ups_nmc_mac_address = ".$anvil->Database->quote($scan_apc_ups_nmc_mac_address).", |
|
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." |
|
WHERE |
|
scan_apc_ups_uuid = ".$anvil->Database->quote($scan_apc_ups_uuid)." |
|
;"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); |
|
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); |
|
} |
|
|
|
# Input changes. This can only change, never come new |
|
my $input_changed = 0; |
|
my $scan_apc_ups_input_uuid = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_uuid}; |
|
my $old_scan_apc_ups_input_sensitivity = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}; |
|
my $old_scan_apc_ups_input_voltage = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage}; |
|
my $old_scan_apc_ups_input_1m_maximum_input_voltage = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage}; |
|
my $old_scan_apc_ups_input_1m_minimum_input_voltage = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
old_scan_apc_ups_input_sensitivity => $old_scan_apc_ups_input_sensitivity, |
|
old_scan_apc_ups_input_voltage => $old_scan_apc_ups_input_voltage, |
|
old_scan_apc_ups_input_1m_maximum_input_voltage => $old_scan_apc_ups_input_1m_maximum_input_voltage, |
|
old_scan_apc_ups_input_1m_minimum_input_voltage => $old_scan_apc_ups_input_1m_minimum_input_voltage, |
|
}}); |
|
|
|
# Output changes. This can only change, never come new |
|
my $output_changed = 0; |
|
my $scan_apc_ups_output_uuid = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_uuid}; |
|
my $old_scan_apc_ups_output_load_percentage = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}; |
|
my $old_scan_apc_ups_output_time_on_batteries = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries}; |
|
my $old_scan_apc_ups_output_estimated_runtime = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime}; |
|
my $old_scan_apc_ups_output_frequency = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}; |
|
my $old_scan_apc_ups_output_voltage = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}; |
|
my $old_scan_apc_ups_output_total_output = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
old_scan_apc_ups_output_voltage => $old_scan_apc_ups_output_voltage, |
|
old_scan_apc_ups_output_total_output => $old_scan_apc_ups_output_total_output, |
|
old_scan_apc_ups_output_frequency => $old_scan_apc_ups_output_frequency, |
|
old_scan_apc_ups_output_time_on_batteries => $old_scan_apc_ups_output_time_on_batteries, |
|
old_scan_apc_ups_output_estimated_runtime => $old_scan_apc_ups_output_estimated_runtime, |
|
old_scan_apc_ups_output_load_percentage => $old_scan_apc_ups_output_load_percentage, |
|
}}); |
|
|
|
if ($scan_apc_ups_input_sensitivity ne $old_scan_apc_ups_input_sensitivity) |
|
{ |
|
$input_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { input_changed => $input_changed }}); |
|
|
|
# Make sure we have a valid health integer |
|
my $say_scan_apc_ups_input_sensitivity = $scan_apc_ups_input_sensitivity; |
|
my $say_old_scan_apc_ups_input_sensitivity = $old_scan_apc_ups_input_sensitivity; |
|
if (($scan_apc_ups_input_sensitivity =~ /\D/) or (($scan_apc_ups_input_sensitivity < 0) or ($scan_apc_ups_input_sensitivity > 4))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$say_scan_apc_ups_input_sensitivity = 99; |
|
} |
|
elsif (($old_scan_apc_ups_input_sensitivity =~ /\D/) or (($old_scan_apc_ups_input_sensitivity < 0) or ($old_scan_apc_ups_input_sensitivity > 4))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$say_old_scan_apc_ups_input_sensitivity = 99; |
|
} |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => "#!string!scan_apc_ups_sensitivity_".sprintf("%04d", $say_scan_apc_ups_input_sensitivity)."!#", |
|
old_value => "#!string!scan_apc_ups_sensitivity_".sprintf("%04d", $say_old_scan_apc_ups_input_sensitivity)."!#", |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0020", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0020", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++}); |
|
} |
|
|
|
# Has the input voltage changed? |
|
if ($scan_apc_ups_input_voltage ne $old_scan_apc_ups_input_voltage) |
|
{ |
|
$input_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { input_changed => $input_changed }}); |
|
|
|
# This is always changing, so normally we will use an 'info' level alert. |
|
my $message_key = "scan_apc_ups_warning_0024"; |
|
|
|
# These are thresholds |
|
my $high_transfer_voltage = $scan_apc_ups_high_transfer_voltage; |
|
my $clear_high_transfer = ($scan_apc_ups_high_transfer_voltage - $anvil->data->{'scan-apc-ups'}{transfer_voltage_clear_delta}); |
|
my $low_transfer_voltage = $scan_apc_ups_low_transfer_voltage; |
|
my $clear_low_transfer = ($scan_apc_ups_low_transfer_voltage + $anvil->data->{'scan-apc-ups'}{transfer_voltage_clear_delta}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
high_transfer_voltage => $high_transfer_voltage, |
|
clear_high_transfer => $clear_high_transfer, |
|
low_transfer_voltage => $low_transfer_voltage, |
|
clear_low_transfer => $clear_low_transfer, |
|
}}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $anvil->Convert->round({places => 1, number => $scan_apc_ups_input_voltage}), |
|
old_value => $anvil->Convert->round({places => 1, number => $old_scan_apc_ups_input_voltage}), |
|
holdup_time => $anvil->Convert->time({'time' => $scan_apc_ups_output_estimated_runtime}), |
|
high_transfer_voltage => $high_transfer_voltage, |
|
clear_high_transfer => $clear_high_transfer, |
|
low_transfer_voltage => $low_transfer_voltage, |
|
clear_low_transfer => $clear_low_transfer, |
|
}; |
|
# holdup_time => $anvil->Convert->time({'time' => $scan_apc_ups_output_estimated_runtime}), |
|
|
|
my $lost_voltage_key = $scan_apc_ups_uuid."::scan_apc_ups_input_voltage_lost"; |
|
my $low_voltage_key = $scan_apc_ups_uuid."::scan_apc_ups_input_voltage_low"; |
|
my $high_voltage_key = $scan_apc_ups_uuid."::scan_apc_ups_input_voltage_high"; |
|
|
|
# Is the voltage rising or falling? |
|
if ($scan_apc_ups_input_voltage > $old_scan_apc_ups_input_voltage) |
|
{ |
|
### It is rising. |
|
# Has it crossed over the high-voltage transfer threshold? If not, |
|
# has it crossed over the low-voltage clear level? |
|
if ($old_scan_apc_ups_input_voltage == 0) |
|
{ |
|
# Power has been restored. |
|
my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $lost_voltage_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0021", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0021", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
elsif ($scan_apc_ups_input_voltage > $high_transfer_voltage) |
|
{ |
|
# Voltage is too high, see if the alert exists already |
|
my $changed = $anvil->Alert->check_alert_sent({record_locator => $high_voltage_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0022", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0022", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
elsif ($scan_apc_ups_input_voltage > $clear_low_transfer) |
|
{ |
|
# Above the low transfer clear level. |
|
my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $low_voltage_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0023", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0023", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
# It is falling. |
|
$message_key = "scan_apc_ups_warning_0025"; |
|
|
|
# Has it dropped below the low transfer voltage? If not, has |
|
# it dropped below the high-voltage clear level? |
|
if ($scan_apc_ups_input_voltage == 0) |
|
{ |
|
# Power lost entirely |
|
my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $lost_voltage_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0026", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0026", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
elsif ($scan_apc_ups_input_voltage < $low_transfer_voltage) |
|
{ |
|
# It is below the low-transfer limit, set an alert if needed. |
|
my $changed = $anvil->Alert->check_alert_sent({record_locator => $low_voltage_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0027", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0027", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
elsif ($scan_apc_ups_input_voltage < $clear_high_transfer) |
|
{ |
|
# The voltage is below the high transfer voltage. |
|
my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $high_voltage_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0028", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0028", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
} |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => $message_key, variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the maximum input voltage seen in the last 60 seconds changed? |
|
if ($scan_apc_ups_input_1m_maximum_input_voltage ne $old_scan_apc_ups_input_1m_maximum_input_voltage) |
|
{ |
|
# This is expected to always happen. |
|
$input_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { input_changed => $input_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $anvil->Convert->round({places => 1, number => $scan_apc_ups_input_1m_maximum_input_voltage}), |
|
old_value => $anvil->Convert->round({places => 1, number => $old_scan_apc_ups_input_1m_maximum_input_voltage}), |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0029", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0029", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the minimum input voltage seen in the last 60 seconds changed? |
|
if ($scan_apc_ups_input_1m_minimum_input_voltage ne $old_scan_apc_ups_input_1m_minimum_input_voltage) |
|
{ |
|
$input_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { input_changed => $input_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $anvil->Convert->round({places => 1, number => $scan_apc_ups_input_1m_minimum_input_voltage}), |
|
old_value => $anvil->Convert->round({places => 1, number => $old_scan_apc_ups_input_1m_minimum_input_voltage}), |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0030", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0030", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { input_changed => $input_changed }}); |
|
if ($input_changed) |
|
{ |
|
my $query = " |
|
UPDATE |
|
scan_apc_ups_input |
|
SET |
|
scan_apc_ups_input_scan_apc_ups_uuid = ".$anvil->Database->quote($scan_apc_ups_uuid).", |
|
scan_apc_ups_input_frequency = ".$anvil->Database->quote($scan_apc_ups_input_frequency).", |
|
scan_apc_ups_input_sensitivity = ".$anvil->Database->quote($scan_apc_ups_input_sensitivity).", |
|
scan_apc_ups_input_voltage = ".$anvil->Database->quote($scan_apc_ups_input_voltage).", |
|
scan_apc_ups_input_1m_maximum_input_voltage = ".$anvil->Database->quote($scan_apc_ups_input_1m_maximum_input_voltage).", |
|
scan_apc_ups_input_1m_minimum_input_voltage = ".$anvil->Database->quote($scan_apc_ups_input_1m_minimum_input_voltage).", |
|
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." |
|
WHERE |
|
scan_apc_ups_input_uuid = ".$anvil->Database->quote($scan_apc_ups_input_uuid)." |
|
;"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); |
|
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); |
|
} |
|
|
|
# Look for changes in output data now. |
|
if ($scan_apc_ups_output_load_percentage ne $old_scan_apc_ups_output_load_percentage) |
|
{ |
|
$output_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output_changed => $output_changed }}); |
|
|
|
# Is it rising or falling? |
|
my $log_normal = 1; |
|
my $high_load_key = $scan_apc_ups_uuid."::scan_apc_ups_high_load"; |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_output_load_percentage, |
|
old_value => $old_scan_apc_ups_output_load_percentage, |
|
high_load => $anvil->data->{'scan-apc-ups'}{high_load_threshold}, |
|
high_clear => $anvil->data->{'scan-apc-ups'}{high_load_clear_threshold}, |
|
}; |
|
if ($scan_apc_ups_output_load_percentage > $old_scan_apc_ups_output_load_percentage) |
|
{ |
|
# Rising, is it over the high-load alert? |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
scan_apc_ups_output_load_percentage => $scan_apc_ups_output_load_percentage, |
|
"scan-apc-ups::high_load_threshold" => $anvil->data->{'scan-apc-ups'}{high_load_threshold}, |
|
}}); |
|
if ($scan_apc_ups_output_load_percentage > $anvil->data->{'scan-apc-ups'}{high_load_threshold}) |
|
{ |
|
# Over high load, is this a first? |
|
my $changed = $anvil->Alert->check_alert_sent({record_locator => $high_load_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$log_normal = 0; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0032", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0032", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
# Falling, is it below the high-load clear threshold? |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
scan_apc_ups_output_load_percentage => $scan_apc_ups_output_load_percentage, |
|
"scan-apc-ups::high_load_clear_threshold" => $anvil->data->{'scan-apc-ups'}{high_load_clear_threshold}, |
|
}}); |
|
if ($scan_apc_ups_output_load_percentage < $anvil->data->{'scan-apc-ups'}{high_load_clear_threshold}) |
|
{ |
|
# It's below the clear high-load value, is this new? |
|
my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $high_load_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$log_normal = 0; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0033", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0033", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
} |
|
|
|
if ($log_normal) |
|
{ |
|
# This is an info level alert as it changes all the time. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0031", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0031", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
} |
|
|
|
# Has the time on batteries value changed? |
|
if ($scan_apc_ups_output_time_on_batteries ne $old_scan_apc_ups_output_time_on_batteries) |
|
{ |
|
$output_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output_changed => $output_changed }}); |
|
|
|
# If the old value was '0', we just switched to batteries. This will be a |
|
# 'notice' level event. Likewise if the new time is '0'. Otherwise, it is |
|
# 'info'. We don't do 'warning' because that is caught by the loss of input |
|
# voltage. |
|
my $level = "info"; |
|
my $message_key = "scan_apc_ups_warning_0034"; |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $anvil->Convert->time({'time' => $scan_apc_ups_output_time_on_batteries}), |
|
old_value => $anvil->Convert->time({'time' => $old_scan_apc_ups_output_time_on_batteries}), |
|
}; |
|
|
|
# Is the old time '0'? |
|
if ($scan_apc_ups_output_time_on_batteries eq "0") |
|
{ |
|
# We're on batteries now. |
|
$level = "notice"; |
|
$message_key = "scan_apc_ups_warning_0035"; |
|
} |
|
elsif ($old_scan_apc_ups_output_time_on_batteries eq "0") |
|
{ |
|
# We're no longer on batteries. |
|
$level = "notice"; |
|
$message_key = "scan_apc_ups_warning_0036"; |
|
} |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
level => $level, |
|
message_key => $message_key, |
|
}}); |
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); |
|
$anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the estimated runtime changed? |
|
if ($scan_apc_ups_output_estimated_runtime ne $old_scan_apc_ups_output_estimated_runtime) |
|
{ |
|
$output_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output_changed => $output_changed }}); |
|
|
|
# If the estimated hold-up time is below 15 minutes, send an alert. If the |
|
# estimated hold-up time is greater than 20 minutes, clear it. |
|
my $send_alert = 1; |
|
my $low_hold_up_key = $scan_apc_ups_uuid."::scan_apc_ups_low_holdup_time"; |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $anvil->Convert->time({'time' => $scan_apc_ups_output_estimated_runtime}), |
|
old_value => $anvil->Convert->time({'time' => $old_scan_apc_ups_output_estimated_runtime}), |
|
low_threshold => $anvil->Convert->time({'time' => $anvil->data->{'scan-apc-ups'}{low_hold_up_threshold}}), |
|
clear_threshold => $anvil->Convert->time({'time' => $anvil->data->{'scan-apc-ups'}{low_hold_up_clear_threshold}}), |
|
}; |
|
if ($scan_apc_ups_output_estimated_runtime < $anvil->data->{'scan-apc-ups'}{low_hold_up_threshold}) |
|
{ |
|
# Low hold up time, has an alert been sent? |
|
my $changed = $anvil->Alert->check_alert_sent({record_locator => $low_hold_up_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$send_alert = 0; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "err", key => "scan_apc_ups_warning_0038", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "note", message => "scan_apc_ups_warning_0038", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
elsif ($scan_apc_ups_output_estimated_runtime > $anvil->data->{'scan-apc-ups'}{low_hold_up_clear_threshold}) |
|
{ |
|
# Above the clear threshold, was an alert set? |
|
my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $low_hold_up_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$send_alert = 0; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "err", key => "scan_apc_ups_warning_0039", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "note", clear_alert => 1, message => "scan_apc_ups_warning_0039", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
|
|
if ($send_alert) |
|
{ |
|
# A normal minor change. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0037", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0037", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
} |
|
|
|
# Has the output frequency changed? |
|
if ($scan_apc_ups_output_frequency ne $old_scan_apc_ups_output_frequency) |
|
{ |
|
$output_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output_changed => $output_changed }}); |
|
|
|
# This changes often, so it's info |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $anvil->Convert->round({places => 1, number => $scan_apc_ups_output_frequency}), |
|
old_value => $anvil->Convert->round({places => 1, number => $old_scan_apc_ups_output_frequency}), |
|
}; |
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0040", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0040", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the output voltage changed? |
|
if ($scan_apc_ups_output_voltage ne $old_scan_apc_ups_output_voltage) |
|
{ |
|
$output_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output_changed => $output_changed }}); |
|
|
|
# This changes often and is generally not a concern. |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $anvil->Convert->round({places => 1, number => $scan_apc_ups_output_voltage}), |
|
old_value => $anvil->Convert->round({places => 1, number => $old_scan_apc_ups_output_voltage}), |
|
}; |
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0041", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0041", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# This is always changing... |
|
if ($scan_apc_ups_output_total_output ne $old_scan_apc_ups_output_total_output) |
|
{ |
|
$output_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output_changed => $output_changed }}); |
|
|
|
# This changes every scan and is not a concern. |
|
my $say_scan_apc_ups_output_total_output = $anvil->Convert->round({places => 2, number => $scan_apc_ups_output_total_output}); |
|
$say_scan_apc_ups_output_total_output = $anvil->Convert->add_commas({number => $say_scan_apc_ups_output_total_output}); |
|
my $say_old_scan_apc_ups_output_total_output = $anvil->Convert->round({places => 2, number => $old_scan_apc_ups_output_total_output}); |
|
$say_old_scan_apc_ups_output_total_output = $anvil->Convert->add_commas({number => $say_old_scan_apc_ups_output_total_output}); |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $say_scan_apc_ups_output_total_output, |
|
old_value => $say_old_scan_apc_ups_output_total_output, |
|
}; |
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0042", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0042", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output_changed => $output_changed }}); |
|
if ($output_changed) |
|
{ |
|
# Update the DB table |
|
my $query = " |
|
UPDATE |
|
scan_apc_ups_output |
|
SET |
|
scan_apc_ups_output_scan_apc_ups_uuid = ".$anvil->Database->quote($scan_apc_ups_uuid).", |
|
scan_apc_ups_output_load_percentage = ".$anvil->Database->quote($scan_apc_ups_output_load_percentage).", |
|
scan_apc_ups_output_time_on_batteries = ".$anvil->Database->quote($scan_apc_ups_output_time_on_batteries).", |
|
scan_apc_ups_output_estimated_runtime = ".$anvil->Database->quote($scan_apc_ups_output_estimated_runtime).", |
|
scan_apc_ups_output_frequency = ".$anvil->Database->quote($scan_apc_ups_output_frequency).", |
|
scan_apc_ups_output_voltage = ".$anvil->Database->quote($scan_apc_ups_output_voltage).", |
|
scan_apc_ups_output_total_output = ".$anvil->Database->quote($scan_apc_ups_output_total_output).", |
|
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." |
|
WHERE |
|
scan_apc_ups_output_uuid = ".$anvil->Database->quote($scan_apc_ups_output_uuid)." |
|
"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); |
|
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); |
|
} |
|
|
|
# Look for batteries, these can come, go and be replaced. |
|
foreach my $battery_number (sort {$a cmp $b} keys %{$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}}) |
|
{ |
|
my $scan_apc_ups_battery_uuid = ""; |
|
my $scan_apc_ups_battery_next_replacement_date = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_next_replacement_date}; |
|
my $scan_apc_ups_battery_health = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_health}; |
|
my $scan_apc_ups_battery_model = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_model}; |
|
my $scan_apc_ups_battery_percentage_charge = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge}; |
|
my $scan_apc_ups_battery_last_replacement_date = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_last_replacement_date}; |
|
my $scan_apc_ups_battery_state = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_state}; |
|
my $scan_apc_ups_battery_temperature = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature}; |
|
my $scan_apc_ups_battery_alarm_temperature = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature}; |
|
my $scan_apc_ups_battery_voltage = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
scan_apc_ups_battery_next_replacement_date => $scan_apc_ups_battery_next_replacement_date, |
|
scan_apc_ups_battery_health => $scan_apc_ups_battery_health, |
|
scan_apc_ups_battery_model => $scan_apc_ups_battery_model, |
|
scan_apc_ups_battery_percentage_charge => $scan_apc_ups_battery_percentage_charge, |
|
scan_apc_ups_battery_last_replacement_date => $scan_apc_ups_battery_last_replacement_date, |
|
scan_apc_ups_battery_state => $scan_apc_ups_battery_state, |
|
scan_apc_ups_battery_temperature => $scan_apc_ups_battery_temperature, |
|
scan_apc_ups_battery_alarm_temperature => $scan_apc_ups_battery_alarm_temperature, |
|
scan_apc_ups_battery_voltage => $scan_apc_ups_battery_voltage, |
|
}}); |
|
|
|
if (exists $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery_number}{$battery_number}{scan_apc_ups_battery_uuid}) |
|
{ |
|
$scan_apc_ups_battery_uuid = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery_number}{$battery_number}{scan_apc_ups_battery_uuid}; |
|
my $old_scan_apc_ups_battery_next_replacement_date = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_next_replacement_date}; |
|
my $old_scan_apc_ups_battery_health = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_health}; |
|
my $old_scan_apc_ups_battery_model = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_model}; |
|
my $old_scan_apc_ups_battery_percentage_charge = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_percentage_charge}; |
|
my $old_scan_apc_ups_battery_last_replacement_date = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_last_replacement_date}; |
|
my $old_scan_apc_ups_battery_state = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_state}; |
|
my $old_scan_apc_ups_battery_temperature = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_temperature}; |
|
my $old_scan_apc_ups_battery_alarm_temperature = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_alarm_temperature}; |
|
my $old_scan_apc_ups_battery_voltage = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{scan_apc_ups_battery_voltage}; |
|
my $last_update_unixtime = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{last_update_unixtime}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
scan_apc_ups_battery_uuid => $scan_apc_ups_battery_uuid, |
|
old_scan_apc_ups_battery_next_replacement_date => $old_scan_apc_ups_battery_next_replacement_date, |
|
old_scan_apc_ups_battery_health => $old_scan_apc_ups_battery_health, |
|
old_scan_apc_ups_battery_model => $old_scan_apc_ups_battery_model, |
|
old_scan_apc_ups_battery_percentage_charge => $old_scan_apc_ups_battery_percentage_charge, |
|
old_scan_apc_ups_battery_last_replacement_date => $old_scan_apc_ups_battery_last_replacement_date, |
|
old_scan_apc_ups_battery_state => $old_scan_apc_ups_battery_state, |
|
old_scan_apc_ups_battery_temperature => $old_scan_apc_ups_battery_temperature, |
|
old_scan_apc_ups_battery_alarm_temperature => $old_scan_apc_ups_battery_alarm_temperature, |
|
old_scan_apc_ups_battery_voltage => $old_scan_apc_ups_battery_voltage, |
|
last_update_unixtime => $last_update_unixtime, |
|
}}); |
|
|
|
# Looks for changes |
|
my $battery_changed = 0; |
|
|
|
# Has the estimated replacement date changed? |
|
if ($scan_apc_ups_battery_next_replacement_date ne $old_scan_apc_ups_battery_next_replacement_date) |
|
{ |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
# This changes often with load shifts, so it's an info alert. |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_battery_next_replacement_date, |
|
old_value => $old_scan_apc_ups_battery_next_replacement_date, |
|
battery_number => $battery_number, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0008", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0008", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the battery health changed? |
|
if ($scan_apc_ups_battery_health ne $old_scan_apc_ups_battery_health) |
|
{ |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
my $bad_value = ""; |
|
my $level = "notice"; |
|
my $message_key = "scan_apc_ups_message_0009"; |
|
|
|
# Make sure we have a valid health integer |
|
my $say_scan_apc_ups_battery_health = $scan_apc_ups_battery_health; |
|
my $say_old_scan_apc_ups_battery_health = $old_scan_apc_ups_battery_health; |
|
if (($scan_apc_ups_battery_health =~ /\D/) or (($scan_apc_ups_battery_health < 0) or ($scan_apc_ups_battery_health > 2))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$bad_value = $scan_apc_ups_battery_health; |
|
$scan_apc_ups_battery_health = 99; |
|
} |
|
elsif (($old_scan_apc_ups_battery_health =~ /\D/) or (($old_scan_apc_ups_battery_health < 0) or ($old_scan_apc_ups_battery_health > 2))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$bad_value = $old_scan_apc_ups_battery_health; |
|
$old_scan_apc_ups_battery_health = 99; |
|
} |
|
|
|
### There are 2 possible states (* == warning): |
|
# 1 - The UPS battery is healthy. |
|
# *2 - The UPS battery has failed and needs to be replaced. |
|
if ($scan_apc_ups_battery_health eq "2") |
|
{ |
|
# Entered a warning state. |
|
$level = "warning"; |
|
$message_key = "scan_apc_ups_message_0010"; |
|
} |
|
elsif ($old_scan_apc_ups_battery_health eq "2") |
|
{ |
|
# Warning state cleared. |
|
$level = "warning"; |
|
$message_key = "scan_apc_ups_message_0011"; |
|
} |
|
|
|
my $sort_position = $level eq "warning" ? 1 : $anvil->data->{'scan-apc-ups'}{alert_sort}++; |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
battery_number => $battery_number, |
|
bad_value => $bad_value, |
|
new_value => "#!string!scan_apc_ups_battery_health_".sprintf("%04d", $say_scan_apc_ups_battery_health)."!#", |
|
old_value => "#!string!scan_apc_ups_battery_health_".sprintf("%04d", $say_old_scan_apc_ups_battery_health)."!#", |
|
battery_model => $scan_apc_ups_battery_model, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); |
|
$anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the battery model changed? |
|
if ($scan_apc_ups_battery_model ne $old_scan_apc_ups_battery_model) |
|
{ |
|
# This is almost certainly an event the admin knows about. |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
my $variables = { |
|
battery_number => $battery_number, |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_battery_model, |
|
old_value => $old_scan_apc_ups_battery_model, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0012", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0012", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# If the battery charge percentage has changed, it will usually be an 'info' |
|
# level event, unless it drops below the warning threshold, climbs above the |
|
# OK threshold or hits 100% |
|
if ($scan_apc_ups_battery_percentage_charge ne $old_scan_apc_ups_battery_percentage_charge) |
|
{ |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
my $low_charge_key = $scan_apc_ups_uuid."::battery-".$battery_number."::scan_apc_ups_low_charge"; |
|
my $level = "info"; |
|
my $message_key = "scan_apc_ups_note_0022"; |
|
my $alert_sent = 0; |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_battery_percentage_charge, |
|
old_value => $old_scan_apc_ups_battery_percentage_charge, |
|
battery_number => $battery_number, |
|
low_charge_clear => $anvil->data->{'scan-apc-ups'}{low_charge_percentage_ok}, |
|
low_charge_alert => $anvil->data->{'scan-apc-ups'}{low_charge_percentage_warning}, |
|
}; |
|
|
|
# Is the battery charging or discharging? |
|
if ($scan_apc_ups_battery_percentage_charge > $old_scan_apc_ups_battery_percentage_charge) |
|
{ |
|
# Charging |
|
if ($scan_apc_ups_battery_percentage_charge eq "100") |
|
{ |
|
# For cases where the UPS's input voltage |
|
# often drops a little below the low-transfer |
|
# volage, causing frequent small discharge/ |
|
# charge cycles, we don't want to constantly |
|
# sent "battery has charged" alerts. To |
|
# handle this, we check to see how long ago |
|
# the input voltage was less than half the |
|
# low transfer voltage. |
|
my $low_limit = int($scan_apc_ups_low_transfer_voltage / 2); |
|
$low_limit = 0 if $low_limit =~ /\D/; |
|
$low_limit = 0 if $low_limit < 0; |
|
my $query = " |
|
SELECT |
|
round(extract(epoch from modified_date)) |
|
FROM |
|
scan_apc_ups_input |
|
WHERE |
|
scan_apc_ups_input_scan_apc_ups_uuid = ".$anvil->Database->quote($scan_apc_ups_uuid)." |
|
AND |
|
scan_apc_ups_input_1m_minimum_input_voltage < ".$low_limit." |
|
ORDER BY |
|
modified_date DESC |
|
LIMIT 1 |
|
;"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); |
|
|
|
# Do the query... |
|
my $last_power_loss = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; |
|
$last_power_loss = 0 if not defined $last_power_loss; |
|
my $current_time = time; |
|
my $difference = ($current_time - $last_power_loss); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
last_power_loss => $last_power_loss, |
|
current_time => $current_time, |
|
difference => $difference, |
|
}}); |
|
|
|
# if it's less than six hours, well assume it has finished charging. |
|
if ($difference < 21600) |
|
{ |
|
$level = "notice"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { level => $level }}); |
|
} |
|
else |
|
{ |
|
$level = "info"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { level => $level }}); |
|
} |
|
$message_key = "scan_apc_ups_message_0013"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); |
|
} |
|
elsif ($scan_apc_ups_battery_percentage_charge > $anvil->data->{'scan-apc-ups'}{low_charge_percentage_ok}) |
|
{ |
|
# Crossed the "now OK" threshold. Was there an alert? |
|
# If so, tell the user. |
|
my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $low_charge_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$alert_sent = 1; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_message_0014", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_message_0014", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
# Discharging |
|
$message_key = "scan_apc_ups_message_0015"; |
|
if ($scan_apc_ups_battery_percentage_charge < $anvil->data->{'scan-apc-ups'}{low_charge_percentage_warning}) |
|
{ |
|
# Crossed the "oh crap" threshold. Is this the first |
|
# time? 'set' is set to 1 if so. |
|
my $changed = $anvil->Alert->check_alert_sent({record_locator => $low_charge_key, set_by => $THIS_FILE }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); |
|
if ($changed) |
|
{ |
|
# Register an alert. |
|
$alert_sent = 1; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_message_0016", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_message_0016", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
} |
|
|
|
# If we didn't send a threshold alert, send a normal alert now. |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alert_sent => $alert_sent }}); |
|
if (not $alert_sent) |
|
{ |
|
my $sort_position = $level eq "warning" ? 1 : $anvil->data->{'scan-apc-ups'}{alert_sort}++; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); |
|
$anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); |
|
} |
|
} |
|
|
|
# Has the replacement date changed? |
|
if ($scan_apc_ups_battery_last_replacement_date ne $old_scan_apc_ups_battery_last_replacement_date) |
|
{ |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_battery_last_replacement_date, |
|
old_value => $old_scan_apc_ups_battery_last_replacement_date, |
|
battery_number => $battery_number, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0017", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0017", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the battery state changed? There are four possible battery states. |
|
if ($scan_apc_ups_battery_state ne $old_scan_apc_ups_battery_state) |
|
{ |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
my $level = "notice"; |
|
my $message_key = "scan_apc_ups_message_0018"; |
|
my $clear_alert = 0; |
|
|
|
### There are four possible states (* == warning): |
|
# *1 - The UPS battery is in an unknown state. |
|
# 2 - The UPS battery is operating normally. |
|
# 3 - The UPS battery is in a low voltage state. |
|
# *4 - The UPS battery is in a failed state and needs to be replaced. |
|
# Make sure we have a valid health integer |
|
my $say_scan_apc_ups_battery_state = $scan_apc_ups_battery_state; |
|
my $say_old_scan_apc_ups_battery_state = $old_scan_apc_ups_battery_state; |
|
if (($scan_apc_ups_battery_state =~ /\D/) or (($scan_apc_ups_battery_state < 0) or ($scan_apc_ups_battery_state > 4))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$say_scan_apc_ups_battery_state = 99; |
|
} |
|
elsif (($old_scan_apc_ups_battery_state =~ /\D/) or (($old_scan_apc_ups_battery_state < 0) or ($old_scan_apc_ups_battery_state > 4))) |
|
{ |
|
# We'll use '99' as a generic "this is not known" |
|
$say_old_scan_apc_ups_battery_state = 99; |
|
} |
|
|
|
if (($scan_apc_ups_battery_state eq "1") or ($scan_apc_ups_battery_state eq "4")) |
|
{ |
|
# Entered a warning state. |
|
$level = "warning"; |
|
} |
|
elsif (($old_scan_apc_ups_battery_state eq "1") or ($old_scan_apc_ups_battery_state eq "4")) |
|
{ |
|
# Warning state cleared. |
|
$level = "warning"; |
|
$message_key = "scan_apc_ups_message_0019"; |
|
$clear_alert = 1; |
|
} |
|
|
|
my $sort_position = $level eq "warning" ? 1 : $anvil->data->{'scan-apc-ups'}{alert_sort}++; |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => "#!string!scan_apc_ups_battery_state_".sprintf("%04d", $say_scan_apc_ups_battery_state)."!#", |
|
old_value => "#!string!scan_apc_ups_battery_state_".sprintf("%04d", $say_old_scan_apc_ups_battery_state)."!#", |
|
battery_model => $scan_apc_ups_battery_model, |
|
battery_number => $battery_number, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); |
|
$anvil->Alert->register({alert_level => $level, clear_alert => $clear_alert, message => $message_key, variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the battery's temperature changed? Alerts will be processed |
|
# later (in process_alerts() below). Here, we just log the change as |
|
# an info level alert. |
|
if ($scan_apc_ups_battery_temperature ne $old_scan_apc_ups_battery_temperature) |
|
{ |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
my $send_alert = 1; |
|
|
|
# Did the temperature jump? |
|
if ($scan_apc_ups_battery_alarm_temperature > $old_scan_apc_ups_battery_alarm_temperature) |
|
{ |
|
my $difference = $scan_apc_ups_battery_alarm_temperature - $old_scan_apc_ups_battery_alarm_temperature; |
|
my $time_span = time - $last_update_unixtime; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
difference => $difference, |
|
time_span => $time_span, |
|
"scan-apc-ups::temperature_jump_threshold" => $anvil->data->{'scan-apc-ups'}{temperature_jump_threshold}, |
|
"scan-apc-ups::temperature_jump_time" => $anvil->data->{'scan-apc-ups'}{temperature_jump_time}, |
|
}}); |
|
if (($difference >= $anvil->data->{'scan-apc-ups'}{temperature_jump_threshold}) && |
|
($time_span <= $anvil->data->{'scan-apc-ups'}{temperature_jump_time})) |
|
{ |
|
# Send a temp jump alert. |
|
$send_alert = 0; |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_battery_alarm_temperature, |
|
old_value => $old_scan_apc_ups_battery_alarm_temperature, |
|
battery_number => $battery_number, |
|
difference => $difference, |
|
time_span => $time_span, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0023", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0023", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); |
|
} |
|
} |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { send_alert => $send_alert }}); |
|
if ($send_alert) |
|
{ |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_battery_temperature, |
|
old_value => $old_scan_apc_ups_battery_temperature, |
|
battery_number => $battery_number, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0020", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0020", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
} |
|
|
|
# Has the alarm temperature changed? |
|
if ($scan_apc_ups_battery_alarm_temperature ne $old_scan_apc_ups_battery_alarm_temperature) |
|
{ |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $scan_apc_ups_battery_alarm_temperature, |
|
old_value => $old_scan_apc_ups_battery_alarm_temperature, |
|
battery_number => $battery_number, |
|
}; |
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0021", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0021", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, set_by => $THIS_FILE}); |
|
} |
|
|
|
# Has the UPS battery voltage changed? |
|
if ($scan_apc_ups_battery_voltage ne $old_scan_apc_ups_battery_voltage) |
|
{ |
|
$battery_changed = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); |
|
|
|
# This is normal and is therefor an info level alert. |
|
my $variables = { |
|
ups_name => $scan_apc_ups_name, |
|
new_value => $anvil->Convert->round({places => 1, number => $scan_apc_ups_battery_voltage}), |
|
old_value => $anvil->Convert->round({places => 1, number => $old_scan_apc_ups_battery_voltage}), |
|
battery_number => $battery_number, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0022", variables => $variables}); |
|
$anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0022", variables => $variables, sort_position => $anvil->data->{'scan-apc-ups'}{alert_sort}++, |