#!/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({list => [
	"force", 
	"purge",
], man => $THIS_FILE});

# 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({level => 2, 'print' => 1, 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_message_0024";
						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}++, set_by => $THIS_FILE});
					}
					
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }});
					if ($battery_changed)
					{
						# Save the changes.
						my $query = "
UPDATE 
    scan_apc_ups_batteries 
SET 
    scan_apc_ups_battery_scan_apc_ups_uuid     = ".$anvil->Database->quote($scan_apc_ups_uuid).",
    scan_apc_ups_battery_number                = ".$anvil->Database->quote($battery_number).", 
    scan_apc_ups_battery_next_replacement_date = ".$anvil->Database->quote($scan_apc_ups_battery_next_replacement_date).",
    scan_apc_ups_battery_health                = ".$anvil->Database->quote($scan_apc_ups_battery_health).",
    scan_apc_ups_battery_model                 = ".$anvil->Database->quote($scan_apc_ups_battery_model).",
    scan_apc_ups_battery_percentage_charge     = ".$anvil->Database->quote($scan_apc_ups_battery_percentage_charge).",
    scan_apc_ups_battery_last_replacement_date = ".$anvil->Database->quote($scan_apc_ups_battery_last_replacement_date).",
    scan_apc_ups_battery_state                 = ".$anvil->Database->quote($scan_apc_ups_battery_state).",
    scan_apc_ups_battery_temperature           = ".$anvil->Database->quote($scan_apc_ups_battery_temperature).",
    scan_apc_ups_battery_alarm_temperature     = ".$anvil->Database->quote($scan_apc_ups_battery_alarm_temperature).",
    scan_apc_ups_battery_voltage               = ".$anvil->Database->quote($scan_apc_ups_battery_voltage).",
    modified_date                              = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_apc_ups_battery_uuid                  = ".$anvil->Database->quote($scan_apc_ups_battery_uuid)."
";
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
						$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
					}
				}
				else
				{
					# New battery
					$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 }});
				}
				
				# Check battery temperatures.
				process_temperature($anvil, $scan_apc_ups_battery_uuid, $battery_number, $scan_apc_ups_uuid); 
			}
		}
		
		# If the UPS health is '4' (boosting for low input voltage), or if there is no input voltage,
		# we'll set that we're on batteries.
		my $scan_apc_ups_on_battery = 0;
		if (($scan_apc_ups_input_voltage eq "0") or ($scan_apc_ups_health eq "4"))
		{
			$scan_apc_ups_on_battery = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_apc_ups_health        => $scan_apc_ups_health, 
				scan_apc_ups_input_voltage => $scan_apc_ups_input_voltage, 
				scan_apc_ups_on_battery    => $scan_apc_ups_on_battery, 
			}});
		}
		
		my $power_uuid = $anvil->Database->insert_or_update_power({
			debug                   => 3,
			power_ups_uuid          => $ups_uuid, 
			power_on_battery        => $scan_apc_ups_on_battery,
			power_seconds_left      => $scan_apc_ups_output_estimated_runtime,
			power_charge_percentage => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{highest_charge_percent},
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { power_uuid => $power_uuid }});
	}
	
	return(0);
}

# This reads in the last scan's data.
sub read_last_scan
{
	my ($anvil) = @_;
	
	# Read in existing data, if any.
	my $query = "
SELECT 
    scan_apc_ups_uuid, 
    scan_apc_ups_ups_uuid, 
    scan_apc_ups_serial_number, 
    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_nmc_firmware_version,
    scan_apc_ups_nmc_serial_number,
    scan_apc_ups_nmc_mac_address 
FROM 
    scan_apc_upses 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
		results => $results, 
		count   => $count,
	}});
	# One or more records were found.
	foreach my $row (@{$results})
	{
		my $scan_apc_ups_uuid = $row->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { scan_apc_ups_uuid => $scan_apc_ups_uuid }});
		
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ups_uuid}              = $row->[1];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_serial_number}         = $row->[2];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_name}                  = $row->[3];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ip}                    = $row->[4];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay}      = $row->[5];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay}        = $row->[6];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version}      = $row->[7];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_health}                = $row->[8];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_high_transfer_voltage} = $row->[9];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_low_transfer_voltage}  = $row->[10];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_last_transfer_reason}  = $row->[11];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date}     = $row->[12];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_model}                 = $row->[13];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_firmware_version}  = $row->[14];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_serial_number}     = $row->[15];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address}       = $row->[16];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_ups_uuid"              => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ups_uuid}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_serial_number"         => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_serial_number}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_name"                  => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_name}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_ip"                    => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ip}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_ac_restore_delay"      => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_shutdown_delay"        => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_firmware_version"      => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_health"                => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_health}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_high_transfer_voltage" => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_high_transfer_voltage}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_low_transfer_voltage"  => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_low_transfer_voltage}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_last_transfer_reason"  => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_last_transfer_reason}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_manufactured_date"     => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_model"                 => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_model}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_nmc_firmware_version"  => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_firmware_version}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_nmc_serial_number"     => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_serial_number}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_nmc_mac_address"       => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address}, 
		}});
		
		# Make it possible to find the UPS by ups_uuid and by serial number.
		my $scan_apc_ups_ups_uuid                                                          = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ups_uuid};
		my $scan_apc_ups_serial_number                                                     = $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_serial_number};
		   $anvil->data->{sql}{ups_uuid_to_apc_ups_uuid}{$scan_apc_ups_ups_uuid}           = $scan_apc_ups_uuid;
		   $anvil->data->{sql}{serial_number_to_apc_ups_uuid}{$scan_apc_ups_serial_number} = $scan_apc_ups_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::ups_uuid_to_apc_ups_uuid::${scan_apc_ups_ups_uuid}"           => $anvil->data->{sql}{ups_uuid_to_apc_ups_uuid}{$scan_apc_ups_ups_uuid},
			"sql::serial_number_to_apc_ups_uuid::${scan_apc_ups_serial_number}" => $anvil->data->{sql}{serial_number_to_apc_ups_uuid}{$scan_apc_ups_serial_number},
		}});
	}
	undef $results;
	
	# Read in the battery data
	$query = "
SELECT 
    scan_apc_ups_battery_uuid,
    scan_apc_ups_battery_scan_apc_ups_uuid,
    scan_apc_ups_battery_number, 
    scan_apc_ups_battery_next_replacement_date,
    scan_apc_ups_battery_health,
    scan_apc_ups_battery_model,
    scan_apc_ups_battery_percentage_charge,
    scan_apc_ups_battery_last_replacement_date,
    scan_apc_ups_battery_state,
    scan_apc_ups_battery_temperature,
    scan_apc_ups_battery_alarm_temperature,
    scan_apc_ups_battery_voltage, 
    round(extract(epoch from modified_date)) 
FROM 
    scan_apc_ups_batteries 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	# Do the query against the source DB and loop through the results.
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $scan_apc_ups_battery_uuid   = $row->[0];
		my $scan_apc_ups_uuid           = $row->[1];
		my $scan_apc_ups_battery_number = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_apc_ups_battery_uuid   => $scan_apc_ups_battery_uuid, 
			scan_apc_ups_uuid           => $scan_apc_ups_uuid,
			scan_apc_ups_battery_number => $scan_apc_ups_battery_number, 
		}});
		
		$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} = $row->[3];
		$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}                = $row->[4];
		$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}                 = $row->[5];
		$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}     = $row->[6];
		$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} = $row->[7];
		$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}                 = $row->[8];
		$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}           = $row->[9];
		$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}     = $row->[10];
		$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}               = $row->[11];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_battery_uuid}{$scan_apc_ups_battery_uuid}{last_update_unixtime}                       = $row->[12];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"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"      => $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}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_battery_uuid::${scan_apc_ups_battery_uuid}::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}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_battery_uuid::${scan_apc_ups_battery_uuid}::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}, 
			"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"     => $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}, 
			"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" => $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}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_battery_uuid::${scan_apc_ups_battery_uuid}::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}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_battery_uuid::${scan_apc_ups_battery_uuid}::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}, 
			"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"     => $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}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_battery_uuid::${scan_apc_ups_battery_uuid}::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}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_battery_uuid::${scan_apc_ups_battery_uuid}::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->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery_number}{$scan_apc_ups_battery_number}{scan_apc_ups_battery_uuid} = $scan_apc_ups_battery_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery_number::${scan_apc_ups_battery_number}::scan_apc_ups_battery_uuid" => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery_number}{$scan_apc_ups_battery_number}{scan_apc_ups_battery_uuid}, 
		}});
	}
	undef $results;
	
	# Read in the input voltage data
	$query = "
SELECT 
    scan_apc_ups_input_uuid,
    scan_apc_ups_input_scan_apc_ups_uuid,
    scan_apc_ups_input_frequency, 
    scan_apc_ups_input_sensitivity, 
    scan_apc_ups_input_voltage, 
    scan_apc_ups_input_1m_maximum_input_voltage, 
    scan_apc_ups_input_1m_minimum_input_voltage 
FROM 
    scan_apc_ups_input 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
	
	# Do the query against the source DB and loop through the results.
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $scan_apc_ups_uuid = $row->[1];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { scan_apc_ups_uuid => $scan_apc_ups_uuid }});
		
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_uuid}                     = $row->[0];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency}                = $row->[2];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}              = $row->[3];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage}                  = $row->[4];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage} = $row->[5];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage} = $row->[6];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_uuid"                     => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_uuid}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_frequency"                => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_sensitivity"              => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_voltage"                  => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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}, 
		}});
	}
	undef $results;
	
	# And finally, the output voltage data
	$query = "
SELECT 
    scan_apc_ups_output_uuid,
    scan_apc_ups_output_scan_apc_ups_uuid,
    scan_apc_ups_output_load_percentage, 
    scan_apc_ups_output_time_on_batteries, 
    scan_apc_ups_output_estimated_runtime, 
    scan_apc_ups_output_frequency, 
    scan_apc_ups_output_voltage, 
    scan_apc_ups_output_total_output 
FROM 
    scan_apc_ups_output 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
	
	# Do the query against the source DB and loop through the results.
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $scan_apc_ups_uuid = $row->[1];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { scan_apc_ups_uuid => $scan_apc_ups_uuid }});
		
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_uuid}              = $row->[0];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}   = $row->[2];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries} = $row->[3];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime} = $row->[4];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}         = $row->[5];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}           = $row->[6];
		$anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}      = $row->[7];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_uuid"              => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_uuid},
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_load_percentage"   => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_estimated_runtime" => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_frequency"         => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_voltage"           => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}, 
			"sql::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_total_output"      => $anvil->data->{sql}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}, 
		}});
	}
	undef $results;
	
	return(0);
}

# This calls each UPS, first to get the model number and update the OIDs to use if needed, then gathers the 
# information from the UPS.
sub gather_ups_data
{
	my ($anvil) = @_;
	
	### TODO: If the network with the UPS is congested, it is possible that, despite connecting to the 
	###       UPS, some OID reads may fail with '#!no_connection!#'. Try to read them a second time in
	###       these cases. Regardless, be sure to check all returned OID values for 'no connection' and
	###       handle such cases more gracefully.
	
	# Loop through the UPSes we found in upses.
	foreach my $ups_uuid (sort {$a cmp $b} keys %{$anvil->data->{upses}{ups_uuid}})
	{
		my $ups_ip   = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ip_address};
		my $ups_name = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			ups_uuid => $ups_uuid, 
			ups_ip     => $ups_ip, 
			ups_name   => $ups_name, 
		}});
		
		# Have we seen this UPS before?
		my $scan_apc_ups_uuid = "";
		my $new_ups           = 1;
		if ((exists $anvil->data->{sql}{ups_uuid_to_apc_ups_uuid}{$ups_uuid}) && (defined $anvil->data->{sql}{ups_uuid_to_apc_ups_uuid}{$ups_uuid}))
		{
			# Yup!
			$scan_apc_ups_uuid = $anvil->data->{sql}{ups_uuid_to_apc_ups_uuid}{$ups_uuid};
			$new_ups           = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_apc_ups_uuid => $scan_apc_ups_uuid, 
				new_ups           => $new_ups, 
			}});
		}
		
		# Can I ping it? This returns '1' if it was pingable, '0' if not.
		my ($pinged, $average_time) = $anvil->Network->ping({ping => $ups_ip, debug => 2});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			pinged       => $pinged,
			average_time => $average_time, 
		}});
		
		if (not $pinged)
		{
			# Can't reach it.
			$anvil->data->{upses}{ups_uuid}{$ups_uuid}{ping}      = 0;
			$anvil->data->{upses}{ups_uuid}{$ups_uuid}{connected} = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"upses::ups_uuid::${ups_uuid}::ping"      => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ping}, 
				"upses::ups_uuid::${ups_uuid}::connected" => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{connected}, 
			}});
			next;
		}

		### NOTE: At this time, we've only seen SNMP v2c, but it's possible we may need to test other
		###       versions on a per-UPS bases down the road.
		$anvil->data->{upses}{ups_uuid}{$ups_uuid}{ping}              = 1;
 		$anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version}      = $anvil->data->{snmp}{community}{version};
		$anvil->data->{upses}{ups_uuid}{$ups_uuid}{scan_apc_ups_uuid} = $scan_apc_ups_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"upses::ups_uuid::${ups_uuid}::ping"              => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ping}, 
			"upses::ups_uuid::${ups_uuid}::snmp_version"      => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version}, 
			"upses::ups_uuid::${ups_uuid}::scan_apc_ups_uuid" => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{scan_apc_ups_uuid}, 
		}});
		
		my ($scan_apc_ups_serial_number, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{serial_number},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_apc_ups_serial_number => $scan_apc_ups_serial_number,
			data_type                  => $data_type,
		}});
		
		# If the serial number is '!!no_connection!!', this isn't the UPS we want or SNMP is disabled.
		if ($scan_apc_ups_serial_number eq "!!no_connection!!")
		{
			$scan_apc_ups_serial_number                           = "";
			$anvil->data->{upses}{ups_uuid}{$ups_uuid}{connected} = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_apc_ups_serial_number                => $scan_apc_ups_serial_number, 
				"upses::ups_uuid::${ups_uuid}::connected" => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{connected}, 
			}});
		}
		
		# If we didn't find the UPS using the ups_uuid, see if we can find it by the serial number.
		if ($new_ups)
		{
			if (($scan_apc_ups_serial_number) && (exists $anvil->data->{sql}{serial_number_to_apc_ups_uuid}{$scan_apc_ups_serial_number}))
			{
				# It's new, generate the UUID now. We'll set 'scan_apc_ups_new' so we know to INSERT 
				# it later.
				$scan_apc_ups_uuid = $anvil->data->{sql}{serial_number_to_apc_ups_uuid}{$scan_apc_ups_serial_number};
				$new_ups           = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_ups_uuid => $scan_apc_ups_uuid, 
					new_ups           => $new_ups, 
				}});
			}
			else
			{
				# It's new, generate the UUID now. We'll set 'scan_apc_ups_new' so we know to INSERT 
				# it later.
				$scan_apc_ups_uuid = $anvil->Get->uuid();
				$new_ups           = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_ups_uuid => $scan_apc_ups_uuid, 
					new_ups           => $new_ups, 
				}});
			}
		}
		
		# These are set to avoid 'undefined' variable warnings later if we fail to reach this UPS.
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{highest_charge_percent}                      = 0;
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{new_ups}                                     = $new_ups;
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_upses}{scan_apc_ups_ups_uuid}       = $ups_uuid;
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_serial_number}                  = $scan_apc_ups_serial_number;
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_name}                           = $ups_name;
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ip}                             = $ups_ip;
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay}               = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay}                 = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version}               = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_health}                         = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_high_transfer_voltage}          = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_low_transfer_voltage}           = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_last_transfer_reason}           = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date}              = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_model}                          = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_firmware_version}           = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_serial_number}              = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address}                = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage} = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage} = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}              = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency}                = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}                 = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}            = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}               = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries}       = "";
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}         = "";
		
		# If I got the serial number, I found the UPS.
		next if not $scan_apc_ups_serial_number;
		
		# Now that I can trust my OIDs, lets start gathering data! Keep track of how long it took to
		# query the OIDs.
		
		#############################################################################################
		# Base UPS info                                                                             #
		#############################################################################################
		
		# Get the AC restore delay, if set. (High-precision, divide by 10 to get seconds).
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{ac_restore_delay},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_ac_restore_delay" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay},
			data_type                                                                     => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_ac_restore_delay", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_ac_restore_delay" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay},
			}});
		}
		
		# Get the shut down delay, if set. (in ticks, divide by 100).
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{shutdown_delay},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_shutdown_delay" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay},
			data_type                                                                   => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_shutdown_delay", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_shutdown_delay" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay},
			}});
		}
		
		# Get the UPS's firmware version.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{firmware_version},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version} =~ s/^\s+//;
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version} =~ s/\s+$//;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_firmware_version" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_firmware_version},
			data_type                                                                     => $data_type,
		}});
		
		### Gather the main UPS data. The returned integer value maps to the appropriate 
		### 'scan_apc_ups_health_00xx' string.
		# 1 => Unknown, 		2 => Online, 			3 => On Battery, 
		# 4 => onSmartBoost,		5 => timedSleeping,		6 => softwareBypass,
		# 7 => off, 			8 => rebooting,			9 => switchedBypass,
		# 10 => hardwareFailureBypass,	11 => sleepingUntilPowerReturn, 
		# 12 => onSmartTrim,		13 => ecoMode, 			14 => hotStandby, 
		# 15 => onBatteryTest,		15 => emergencyStaticBypass, 
		# 17 => staticBypassStandby,	18 => powerSavingMode,
		# 19 => spotMode,		20 => eConversion
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_health}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{health},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_health" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_health},
			data_type                                                           => $data_type,
		}});
		
		# Get the high and low transfer voltages.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_high_transfer_voltage}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{high_transfer_voltage},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_high_transfer_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_high_transfer_voltage},
			data_type                                                                          => $data_type,
		}});
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_low_transfer_voltage}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{low_transfer_voltage},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_low_transfer_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_low_transfer_voltage},
			data_type                                                                         => $data_type,
		}});
		
		### Get the last transfer reason. The returned integer maps to the appropriate 
		### 'scan_apc_ups_last_transfer_00xx' string.
		# 1 => noTransfer, 		2 => highLineVoltage,		3 => brownout,
		# 4 => blackout,		5 => smallMomentarySag,		6 => deepMomentarySag,
		# 7 => smallMomentarySpike,	8 => largeMomentarySpike,
		# 9 => selfTest,		10 => rateOfVoltageChange
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_last_transfer_reason}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{last_transfer_reason},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_last_transfer_reason" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_last_transfer_reason},
			data_type                                                                         => $data_type,
		}});
		
		# Get the manufacture date of the UPS. This really should never change, but we need to record
		# it at least once.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{manufactured_date},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_manufactured_date" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date},
			data_type                                                                      => $data_type,
		}});
		# Convert the format.
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date} = $anvil->Convert->format_mmddyy_to_yymmdd({date => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date}});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_manufactured_date" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_manufactured_date}, 
		}});
		
		# Get the model of the UPS. 
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_model}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{model},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_model" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_model},
			data_type                                                          => $data_type,
		}});
		
		# Get the temperature units. 1 == C, 2 == F
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_temperature_units}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{temperature_units},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_temperature_units" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_temperature_units},
			data_type                                                                      => $data_type,
		}});
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_temperature_units} = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_temperature_units} eq "2" ? "F" : "C";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_temperature_units" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_temperature_units}, 
		}});
		
		# If the UPS was replaced, these values could change
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_serial_number}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{ups}{serial_number},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_serial_number" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_serial_number},
			data_type                                                                  => $data_type,
		}});
		
		#############################################################################################
		# NMC information                                                                           #
		#############################################################################################
		
		# Get the NMC firmware.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_firmware_version}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{nmc}{firmware_version},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_nmc_firmware_version" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_firmware_version},
			data_type                                                                  => $data_type,
		}});
		
		# Get the NMC serial number.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_serial_number}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{nmc}{serial_number},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_nmc_serial_number" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_serial_number},
			data_type                                                                      => $data_type,
		}});
		
		# Now the MAC address.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{nmc}{mac_address},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_nmc_mac_address" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address},
			data_type                                                                         => $data_type,
		}});
		# Convert the MAC format.
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address} =~ s/([0-9a-fA-F]{2}) ([0-9a-fA-F]{2}) ([0-9a-fA-F]{2}) ([0-9a-fA-F]{2}) ([0-9a-fA-F]{2}) ([0-9a-fA-F]{2})/$1:$2:$3:$4:$5:$6/g;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_nmc_mac_address" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_nmc_mac_address}, 
		}});
		
		#############################################################################################
		# Battery information                                                                       #
		#############################################################################################
		
		# NOTE: In the future, we'll try to read multi-battery UPSes. For now, this is basically a 
		#       place-holder. Also note; There is no unique identifiers for UPS batteries. So we 
		#       simply track them by sequence number (possibly tied to the OID, to be determined...)
		foreach my $battery_number (1..1)
		{
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{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_health}                = "";
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_model}                 = "";
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge}     = "";
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{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_state}                 = "";
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature}           = "";
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature}     = "";
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage}               = "";
				
			# Read the estimated battery replacement date. This only has value if the user remembered to
			# mark the date the battery was replaced.
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_next_replacement_date}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{next_replacement_date},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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},
				data_type                                                                             => $data_type,
			}});
			# Convert the date format
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_next_replacement_date} = $anvil->Convert->format_mmddyy_to_yymmdd({date => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_next_replacement_date}});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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}, 
			}});
			
			# Read the battery's health. 1 == OK, 2 == Failed, replace.
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_health}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{health},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_health" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_health},
				data_type                                                                   => $data_type,
			}});
			
			# Read the battery's model number.
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_model}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{model},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_model" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_model},
				data_type                                                                  => $data_type,
			}});

			# Read the percentage charge. This is high-precision, so divide by 10 to get the actual 
			# percentage (ie: 1000 == 100.0%).
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{percentage_charge_hp},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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},
				data_type                                                                              => $data_type,
			}});
			if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge} =~ /\D/))
			{
				$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
					name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_percentage_charge", 
					value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge}, 
				}, file => $THIS_FILE, line => __LINE__});
				
				$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge} = -1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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},
				}});
			}
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge} /= 10;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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}, 
			}});
			
			if ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge} > $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{highest_charge_percent})
			{
				$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{highest_charge_percent} = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::highest_charge_percent" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{highest_charge_percent},
				}});
			}
			
			# Get the date that the UPS was last replaced. (mm/dd/yy or yyyy format)
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_last_replacement_date}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{last_replacement_date},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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},
				data_type                                                                         => $data_type,
			}});
			# Convert the format.
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_last_replacement_date} = $anvil->Convert->format_mmddyy_to_yymmdd({date => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_last_replacement_date}});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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}, 
			}});
			
			### The battery state is expressed as an integer and maps to 'scan_apc_ups_battery_000x'.
			# 1 => unknown,			2 => batteryNormal,	3 => batteryLow, 
			# 4 => batteryInFaultCondition
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_state}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{'state'},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_state" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_state},
				data_type                                                                         => $data_type,
			}});
			
			# This is the temperature of the UPS battery. It is high-precision, so divide by 10 to get 
			# the actual temperature. It is always celsius, so don't convert it.
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{temperature_hp},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_temperature" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature},
				data_type                                                                         => $data_type,
			}});
			if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature} =~ /\D/))
			{
				$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
					name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_temperature", 
					value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature}, 
				}, file => $THIS_FILE, line => __LINE__});
				
				$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature} = -1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_temperature" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature},
				}});
			}
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature} /= 10;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_temperature" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature},
			}});
			
			# Get the temperature at which the system throws a fit. This is stated as a standard integer,
			# no need to divide by 10.
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{alarm_temperature},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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},
				data_type                                                                              => $data_type,
			}});
			if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature} =~ /\D/))
			{
				$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
					name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_alarm_temperature", 
					value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature}, 
				}, file => $THIS_FILE, line => __LINE__});
				
				$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature} = 40 ;
				$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_temperature_units}                                   = "C";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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},
					"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_temperature_units" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_temperature_units},
				}});
			}
			if ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_temperature_units} eq "F")
			{
				# We live in a metric world!
				$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature} = $anvil->Convert->fahrenheit_to_celsius({temperature => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature}});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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}, 
				}});
			}
			
			# Read the current battery voltage (vDC). It is a high-precision value, so divide by 10.
			($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $ups_ip, 
				oid       => $anvil->data->{oids}{battery}{temperature_hp},
				version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage},
				data_type                                                                         => $data_type,
			}});
			if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage} =~ /\D/))
			{
				$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
					name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_voltage", 
					value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage}, 
				}, file => $THIS_FILE, line => __LINE__});
				
				$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage} = -1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::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->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage} /= 10;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage},
			}});
		}
		
		#############################################################################################
		# Input Information                                                                         #
		#############################################################################################
		
		# This is the current input frequency. It is high-precision, so divide by 10.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{input}{frequency_hp},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_frequency" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency},
			data_type                                                                    => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_frequency", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_frequency" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency} /= 10;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_frequency" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency},
		}});
		
		### The input sensitivity is an integer that maps to 'scan_apc_ups_sensitivity_000x'. If the
		### UPS is an 'online' (dual-conversion model), this will return '0'.
		# 1 => Auto,	2 => Low,	3 => Medium,	4 => High
		# We set this to '0' if no value was returned to indicate an 'Online' UPS.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{input}{sensitivity},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_sensitivity" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity},
			data_type                                                                      => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_sensitivity", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_sensitivity" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity} /= 10;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_sensitivity" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}, 
		}});
		
		# High-precision input voltage
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{input}{voltage_hp},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage},
			data_type                                                                      => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_voltage", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage} /= 10;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage}, 
		}});
		
		# High-precision maximum and minimum input voltages (vAC) over the last 60 seconds.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{input}{'1m_maximum_input_voltage_hp'},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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},
			data_type                                                                      => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_1m_maximum_input_voltage", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage} /= 10;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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}, 
		}});
		
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{input}{'1m_minimum_input_voltage_hp'},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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},
			data_type                                                                      => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_1m_minimum_input_voltage", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage} /= 10;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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}, 
		}});
		
		
		#############################################################################################
		# Output Information                                                                        #
		#############################################################################################
		
		# High-precision output load percentage, divide by 10.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{output}{load_percentage_hp},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_load_percentage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage},
			data_type                                                                      => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_load_percentage", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_load_percentage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage} /= 10;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_load_percentage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}, 
		}});
		
		# The time (in ticks, divide by 100) that the UPS has been running on batteries. '0' 
		# indicates that it is not on batteries.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{output}{time_on_batteries},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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},
			data_type                                                                             => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_time_on_batteries", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries} /= 100;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::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}, 
		}});
		
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{output}{estimated_runtime},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_estimated_runtime" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime},
			data_type                                                                             => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_estimated_runtime", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_estimated_runtime" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime} /= 100;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_estimated_runtime" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime}, 
		}});
		
		# This is the high-precision output frequency in Hz (divide by 10).
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{output}{frequency_hp},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_frequency" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency},
			data_type                                                                             => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_frequency", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_frequency" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency} /= 10;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_frequency" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}, 
		}});
		
		# High-precision output voltage (vAC, divide by 10).
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{output}{voltage_hp},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage},
			data_type                                                                             => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_voltage", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage} /= 10;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_voltage" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}, 
		}});
		
		# This is the total power outputted since the UPS was created. It is measured in tens of 
		# watt-hours, so divide be 100 to get kW/hr.
		($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $ups_ip, 
			oid       => $anvil->data->{oids}{output}{total_output},
			version   => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_total_output" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output},
			data_type                                                                             => $data_type,
		}});
		if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output} =~ /\D/))
		{
			$anvil->Log->entry({level => 1, key => "scan_apc_ups_error_0001", variables => {
				name  => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_total_output", 
				value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}, 
			}, file => $THIS_FILE, line => __LINE__});
			
			$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output} = -1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_total_output" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output},
			}});
		}
		$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output} /= 100;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_total_output" => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}, 
		}});
	}
	
	return(0);
}

# This looks for APC UPSes.
sub find_upses
{
	my ($anvil) = @_;
	
	### TODO: On nodes and DR hosts, limit this to the UPSes selected as powering the given machine.
	# Search in 'upses' for UPSes using this scan agent. These aren't bound to hosts (or even Anvil! 
	# systems), so not all may be available.
	my $query = "
SELECT 
    ups_uuid, 
    ups_name, 
    ups_ip_address 
FROM 
    upses 
WHERE 
    ups_agent = ".$anvil->Database->quote($THIS_FILE)."
AND 
    ups_ip_address != 'DELETED'
ORDER BY 
    ups_name ASC 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $ups_uuid       = $row->[0];
		my $ups_name       = $row->[1];
		my $ups_ip_address = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
			ups_uuid      => $ups_uuid, 
			ups_name      => $ups_name, 
			ups_ip_address => $ups_ip_address, 
		}});
		
		$anvil->data->{upses}{ups_uuid}{$ups_uuid}{name}       = $ups_name;
		$anvil->data->{upses}{ups_uuid}{$ups_uuid}{ip_address} = $ups_ip_address;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"upses::ups_uuid::${ups_uuid}::name"       => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{name},
			"upses::ups_uuid::${ups_uuid}::ip_address" => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ip_address},
		}});
	}
	
	my $ups_count = keys %{$anvil->data->{upses}{ups_uuid}};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_count => $ups_count }});
	return($ups_count);
}

sub insert_battery
{
	my ($anvil, $scan_apc_ups_uuid, $battery_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_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, 
	}});
	    
	my $scan_apc_ups_battery_uuid = $anvil->Get->uuid;
	my $query                     = "
INSERT INTO 
    scan_apc_ups_batteries 
(
    scan_apc_ups_battery_uuid, 
    scan_apc_ups_battery_scan_apc_ups_uuid, 
    scan_apc_ups_battery_number, 
    scan_apc_ups_battery_next_replacement_date, 
    scan_apc_ups_battery_health, 
    scan_apc_ups_battery_model, 
    scan_apc_ups_battery_percentage_charge, 
    scan_apc_ups_battery_last_replacement_date, 
    scan_apc_ups_battery_state, 
    scan_apc_ups_battery_temperature, 
    scan_apc_ups_battery_alarm_temperature, 
    scan_apc_ups_battery_voltage, 
    modified_date
) VALUES (
    ".$anvil->Database->quote($scan_apc_ups_battery_uuid).", 
    ".$anvil->Database->quote($scan_apc_ups_uuid).", 
    ".$anvil->Database->quote($battery_number).", 
    ".$anvil->Database->quote($scan_apc_ups_battery_next_replacement_date).",  
    ".$anvil->Database->quote($scan_apc_ups_battery_health).",  
    ".$anvil->Database->quote($scan_apc_ups_battery_model).",  
    ".$anvil->Database->quote($scan_apc_ups_battery_percentage_charge).",  
    ".$anvil->Database->quote($scan_apc_ups_battery_last_replacement_date).",  
    ".$anvil->Database->quote($scan_apc_ups_battery_state).",  
    ".$anvil->Database->quote($scan_apc_ups_battery_temperature).",  
    ".$anvil->Database->quote($scan_apc_ups_battery_alarm_temperature).",  
    ".$anvil->Database->quote($scan_apc_ups_battery_voltage).",  
    ".$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 = {
		ups_name          => $scan_apc_ups_name, 
		battery_number    => $battery_number, 
		replacement_date  => $scan_apc_ups_battery_next_replacement_date, 
		health            => "#!string!scan_apc_ups_battery_health_".sprintf("%04d", $scan_apc_ups_battery_health)."!#", 
		model             => $scan_apc_ups_battery_model, 
		charge_percentage => $scan_apc_ups_battery_percentage_charge, 
		install_date      => $scan_apc_ups_battery_last_replacement_date, 
		'state'           => "#!string!scan_apc_ups_battery_state_".sprintf("%04d", $scan_apc_ups_battery_state)."!#", 
		temperature       => $scan_apc_ups_battery_temperature, 
		alarm_temperature => $scan_apc_ups_battery_alarm_temperature, 
		voltage           => $scan_apc_ups_battery_voltage, 
	};
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_message_0003", variables => $variables});
	$anvil->Alert->register({
		alert_level       => "warning", 
		message           => "scan_apc_ups_message_0003", 
		variables => $variables, 
		set_by            => $THIS_FILE, 
		sort_position     => $anvil->data->{'scan-apc-ups'}{alert_sort}++,
	});
	
	return($scan_apc_ups_battery_uuid);
}

sub insert_input
{
	my ($anvil, $scan_apc_ups_uuid) = @_;
	
	my $scan_apc_ups_name                           = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_name};
	my $scan_apc_ups_input_uuid                     = $anvil->Get->uuid;
	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_sensitivity              => $scan_apc_ups_input_sensitivity, 
		scan_apc_ups_input_frequency                => $scan_apc_ups_input_frequency, 
	}});
	
	my $query = "
INSERT INTO 
    scan_apc_ups_input 
(
    scan_apc_ups_input_uuid,
    scan_apc_ups_input_scan_apc_ups_uuid,
    scan_apc_ups_input_frequency, 
    scan_apc_ups_input_sensitivity, 
    scan_apc_ups_input_voltage, 
    scan_apc_ups_input_1m_maximum_input_voltage, 
    scan_apc_ups_input_1m_minimum_input_voltage, 
    modified_date
) VALUES (
    ".$anvil->Database->quote($scan_apc_ups_input_uuid).", 
    ".$anvil->Database->quote($scan_apc_ups_uuid).", 
    ".$anvil->Database->quote($scan_apc_ups_input_frequency).",  
    ".$anvil->Database->quote($scan_apc_ups_input_sensitivity).", 
    ".$anvil->Database->quote($scan_apc_ups_input_voltage).",  
    ".$anvil->Database->quote($scan_apc_ups_input_1m_maximum_input_voltage).",  
    ".$anvil->Database->quote($scan_apc_ups_input_1m_minimum_input_voltage).",  
    ".$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 = {
		ups_name                   => $scan_apc_ups_name, 
		'1m_minimum_input_voltage' => $scan_apc_ups_input_1m_minimum_input_voltage, 
		'1m_maximum_input_voltage' => $scan_apc_ups_input_1m_maximum_input_voltage, 
		scan_apc_ups_input_voltage => $scan_apc_ups_input_voltage,
		input_sensitivity          => $scan_apc_ups_input_sensitivity, 
		input_frequency            => $scan_apc_ups_input_frequency, 
	};
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_message_0004", variables => $variables});
	$anvil->Alert->register({
		alert_level       => "warning", 
		message           => "scan_apc_ups_message_0004", 
		variables => $variables, 
		set_by            => $THIS_FILE, 
		sort_position     => $anvil->data->{'scan-apc-ups'}{alert_sort}++,
	});

	return($scan_apc_ups_input_uuid);
}

sub insert_output
{
	my ($anvil, $scan_apc_ups_uuid) = @_;
	
	my $scan_apc_ups_name                     = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_name};
	my $scan_apc_ups_output_uuid              = $anvil->Get->uuid;
	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, 
	}});
	
	my $query = "
INSERT INTO 
    scan_apc_ups_output 
(
    scan_apc_ups_output_uuid, 
    scan_apc_ups_output_scan_apc_ups_uuid, 
    scan_apc_ups_output_load_percentage, 
    scan_apc_ups_output_time_on_batteries, 
    scan_apc_ups_output_estimated_runtime, 
    scan_apc_ups_output_frequency, 
    scan_apc_ups_output_voltage, 
    scan_apc_ups_output_total_output, 
    modified_date
) VALUES (
    ".$anvil->Database->quote($scan_apc_ups_output_uuid).", 
    ".$anvil->Database->quote($scan_apc_ups_uuid).", 
    ".$anvil->Database->quote($scan_apc_ups_output_load_percentage).",  
    ".$anvil->Database->quote($scan_apc_ups_output_time_on_batteries).",  
    ".$anvil->Database->quote($scan_apc_ups_output_estimated_runtime).",  
    ".$anvil->Database->quote($scan_apc_ups_output_frequency).",  
    ".$anvil->Database->quote($scan_apc_ups_output_voltage).",  
    ".$anvil->Database->quote($scan_apc_ups_output_total_output).", 
    ".$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 = {
		ups_name          => $scan_apc_ups_name, 
		voltage           => $scan_apc_ups_output_voltage, 
		total_output      => $scan_apc_ups_output_total_output, 
		time_on_batteries => $scan_apc_ups_output_time_on_batteries ? "#!string!scan_apc_ups_message_0007!#" : "#!string!scan_apc_ups_message_0006!#", 
		load_percentage   => $scan_apc_ups_output_load_percentage, 
	};
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_message_0005", variables => $variables});
	$anvil->Alert->register({
		alert_level       => "warning", 
		message           => "scan_apc_ups_message_0005", 
		variables => $variables, 
		set_by            => $THIS_FILE, 
		sort_position     => $anvil->data->{'scan-apc-ups'}{alert_sort}++,
	});

	return($scan_apc_ups_name);
}

sub process_temperature
{
	my ($anvil, $scan_apc_ups_battery_uuid, $battery_number, $scan_apc_ups_uuid) = @_;
	
	### TODO: Left off here, may have delta, warning and critical mixed up.
	my $ups_uuid                   = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_upses}{scan_apc_ups_ups_uuid};
	my $ups_name                   = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_name};
	my $battery_temperature        = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature};
	my $critical_temperature       = $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature};
	my $warning_temperature        = ($critical_temperature - $anvil->data->{'scan-apc-ups'}{temperature_warning_delta});
	my $clear_critical_temperature = ($critical_temperature - $anvil->data->{'scan-apc-ups'}{temperature_clear_delta});
	my $clear_warning_temperature  = ($warning_temperature  - $anvil->data->{'scan-apc-ups'}{temperature_clear_delta});
	my $warning_temp_key           = "scan-apc-ups::".$scan_apc_ups_battery_uuid."::warning_temperature";
	my $critical_temp_key          = "scan-apc-ups::".$scan_apc_ups_battery_uuid."::critical_temperature";
	my $temperature_state          = "ok";
	my $temperature_is             = "nominal";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		ups_uuid                   => $ups_uuid, 
		ups_name                   => $ups_name, 
		battery_temperature        => $battery_temperature, 
		critical_temperature       => $critical_temperature, 
		warning_temperature        => $warning_temperature, 
		clear_critical_temperature => $clear_critical_temperature, 
		clear_warning_temperature  => $clear_warning_temperature, 
		warning_temp_key           => $warning_temp_key, 
		critical_temp_key          => $critical_temp_key, 
	}});
	my $variables = {
		ups_name             => $ups_name, 
		battery_number       => $battery_number, 
		temperature          => $battery_temperature, 
		warning_temp         => $warning_temperature, 
		critical_temperature => $critical_temperature, 
		clear_critical_temp  => $clear_critical_temperature, 
		clear_warning_temp   => $clear_warning_temperature, 
	};
	if ($battery_temperature > $critical_temperature)
	{
		# Critically high. Is this new? (also set the warning temp)
		                        $anvil->Alert->check_alert_sent({clear => 0, record_locator => $warning_temp_key, set_by => $THIS_FILE });
		my $changed           = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $critical_temp_key, set_by => $THIS_FILE });
		   $temperature_state = "critical";
		   $temperature_is    = "high";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			temperature_state => $temperature_state, 
			temperature_is    => $temperature_is. 
			changed           => $changed,
		}});
		if ($changed)
		{
			# Register an alert.
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0001", variables => $variables});
			$anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0001", variables => $variables, sort_position => 1, set_by => $THIS_FILE});
		}
	}
	elsif ($battery_temperature > $critical_temperature)
	{
		# Above warning, is this new?
		my $changed           = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $warning_temp_key, set_by => $THIS_FILE });
		   $temperature_state = "warning";
		   $temperature_is    = "high";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			temperature_state => $temperature_state, 
			temperature_is    => $temperature_is. 
			changed           => $changed,
		}});
		$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_0003", variables => $variables});
			$anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0003", variables => $variables, sort_position => 1, set_by => $THIS_FILE});
		}
	}

	# Any alerts to clear?
	if ($battery_temperature < $clear_warning_temperature)
	{
		# If we had a warning alert, clear it (and critical, in case the temp dropped from critical to clear in one loop).
		              $anvil->Alert->check_alert_sent({clear => 1, record_locator => $critical_temp_key, set_by => $THIS_FILE });
		my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $warning_temp_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_0004", variables => $variables});
			$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0004", variables => $variables, sort_position => 1, set_by => $THIS_FILE});
		}
	}
	elsif ($battery_temperature < $clear_critical_temperature)
	{
		### NOTE: It's possible that the temperature has dropped from critical to warning. So we're 
		###       only clearing the critical alert.
		# If we had a critical alert, clear it.
		my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $critical_temp_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_0002", variables => $variables});
			$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0002", variables => $variables, sort_position => 1, set_by => $THIS_FILE});
		}
	}
	
	my $temperature_uuid = $anvil->Database->insert_or_update_temperature({
		debug                   => 3,
		temperature_agent_name  => $THIS_FILE,
		temperature_sensor_host => $ups_uuid,
		temperature_sensor_name => "ups_battery_temperature", 
		temperature_value_c     => $battery_temperature, 
		temperature_state       => $temperature_state,
		temperature_is          => $temperature_is, 
		temperature_weight      => 1,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { temperature_uuid => $temperature_uuid }});

	return(0);
}