#!/usr/bin/perl
# 
# This uses data in the 'fences' database table (any agent starting with 'fence_apc_*' to get a list of APC-
# brand PDUs 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.
# 

# Use my modules.
use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
use Socket;
no warnings 'recursion';

=cut

OIDs of interest;

State data
.1.3.6.1.4.1.318.1.1.4.1.5.0         = Serial Number							<- Global ID
.1.3.6.1.4.1.318.1.1.4.1.4.0         = Model Number
.1.3.6.1.4.1.318.1.1.4.1.3.0         = Date of manufacture (mm/dd/yyyy, if 'yy' year 2000 = '00')
.1.3.6.1.4.1.318.1.1.4.1.2.0         = Firmware version
.1.3.6.1.4.1.318.1.1.4.1.1.0         = Hardware version (never changes)

Variables
.1.3.6.1.2.1.1.3.0                   = Uptime (in timeticks, 900 = 9 seconds)
.1.3.6.1.4.1.318.1.1.12.1.16.0       = Wattage draw (seems to be for the full device, not per phase)

# Phase info
.1.3.6.1.4.1.318.1.1.12.2.1.1.0      = Max Amperage out per phase
.1.3.6.1.4.1.318.1.1.12.2.1.2.0      = Number of phases on the PDU
.1.3.6.1.4.1.318.1.1.12.2.2.1.1.2.1  = Low amp threshold. (0 = Disabled; No alarm on low power. Any digit is the minimum amperage under which we throw an alert)  (NOTE: last digit is phase number, so .1 == phase 1) 
.1.3.6.1.4.1.318.1.1.12.2.2.1.1.3.1  = High amperage warning threshold. If the power draw exceeds this, throw a warning alert, warn on equal or greater
.1.3.6.1.4.1.318.1.1.12.2.2.1.1.4.1  = High amperage critical threshold. If the power draw exceeds this, throw a critical alert (breaker is about to pop), warn on equal or greater	(NOTE: Default == max amp per phase, we should set it lower, Max - 2?)
.1.3.6.1.4.1.318.1.1.12.2.3.1.1.2.1  = Current Amperage on the phase, in 1/10 Amp (x10 to get Amp)

Port information
.1.3.6.1.4.1.318.1.1.4.4.1.0         = Number of outlets (ie: 8)
.1.3.6.1.4.1.318.1.1.4.4.2.1.2.n     = Pending action on state? (1 = command pending, 2 = no command pending, 3 = unknown. If all ports are '3', power cycle is required. If the all devices on the peer report Power is OK, do so immediately)
.1.3.6.1.4.1.318.1.1.4.4.2.1.3.n     = Current state (read: 1 = on, 2 = off, 4 = unknown --- write: 1 = turn on, 2 = turn off, 3 = cycle (~5s), 5 = on after 'sPDUOutletPowerOnTime' delay, 6 = off after sPDUOutletPowerOffTime delay, 7 = off after sPDUOutletPowerOffTime delay, wait sPDUOutletRebootDuration time, then back on.)
.1.3.6.1.4.1.318.1.1.4.5.2.1.3.n     = Outlet name (default is 'Outlet N'), Can be read or set, max 20 chars.		<- Set this when we map the Anvil! 
.1.3.6.1.4.1.318.1.1.4.5.2.1.2.n     = Power on delay (in seconds), default is '0' seconds.  (-1 = stay off, 0 = on with PDU,  X = number of seconds to wait before powering on)
.1.3.6.1.4.1.318.1.1.4.5.2.1.4.n     = Power off delay (in seconds)                          (-1 = stay on,  0 = off with PDU, X = number of seconds to wait before powering off)
.1.3.6.1.4.1.318.1.1.4.5.2.1.5.n     = Reboot delay (sleep time), default is '5' seconds.
.1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.n  = Phase that this outlet is in

Network data  (NOTE: .1 is the loopback interface, .2 is the physical interface)
.1.3.6.1.2.1.2.2.1.4.2 = MTU size
.1.3.6.1.2.1.2.2.1.5.2 = Link speed (in bps)
.1.3.6.1.2.1.2.2.1.6.2 = MAC address	- This is losing the first nibble... It returns type STRING instead of Hex-STRING, even if -Ox is used. If I point to the APC MIB, it returns OK. This is what we should be using.
.1.3.6.1.6.3.10.2.1.1.0 = MAC address (with some prefix) in hex. Not sure if this is supported on other PDUs though...

=cut

# 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});
}

$anvil->data->{'scan-apc-pdu'} = {
	# Starts at '2' so that anything set to '1' manually shows first
	alert_sort			=>	2,
	disable				=>	0,
	# Ticks are genera	lly in 10ms increments
	ticks_per_second		=>	100,
	# By default, the critical amperage is the same as the max amperage. If that is the
	# case here, we will subtract this number of amps from the max and use that as our
	# critical warning threshold. So if the max threshold is 12, and the critical 
	# threshold is also 11 or 12, we will drop it to 10. If the critical is set below 10,
	# we won't adjust it at all.
	critical_amps_below_max		=>	2,
	# This drops the warning to be at least this number of amps below critical's level.
	warning_amps_below_critical	=>	2,
	# A warning or critical alert has to be this number of amps above/below the threshold
	# for the alert to be cleared.
	clear_alert_threshold		=>	2,
	# This is needed to trick/force the 'scan_apc_pdu_mac_address' OID into returning a Hex-STRING.
	striker_mib			=>	"/usr/sbin/scancore-agents/".$THIS_FILE."/Striker-MIB.txt",
};
$anvil->data->{oids} = {
	scan_apc_pdu			=>	{
		scan_apc_pdu_serial_number	=>	".1.3.6.1.4.1.318.1.1.4.1.5.0", 
		scan_apc_pdu_model_number	=>	".1.3.6.1.4.1.318.1.1.4.1.4.0", 
		scan_apc_pdu_manufacture_date	=>	".1.3.6.1.4.1.318.1.1.4.1.3.0", 
		scan_apc_pdu_firmware_version	=>	".1.3.6.1.4.1.318.1.1.4.1.2.0", 
		scan_apc_pdu_hardware_version	=>	".1.3.6.1.4.1.318.1.1.4.1.1.0", 
		scan_apc_pdu_mac_address	=>	".1.3.6.1.2.1.2.2.1.6.2", 
		scan_apc_pdu_mac_address_alt	=>	".1.3.6.1.2.1.2.2.1.6.1", 	# Some PDUs use this
		scan_apc_pdu_mtu_size		=>	".1.3.6.1.2.1.2.2.1.4.2", 
		scan_apc_pdu_mtu_size_alt	=>	".1.3.6.1.2.1.2.2.1.4.1", 	# Some PDUs use this
		scan_apc_pdu_link_speed		=>	".1.3.6.1.2.1.2.2.1.5.2", 
		scan_apc_pdu_link_speed_alt	=>	".1.3.6.1.2.1.2.2.1.5.1", 
		scan_apc_pdu_phase_count	=>	".1.3.6.1.4.1.318.1.1.12.2.1.2.0", 
		scan_apc_pdu_outlet_count	=>	".1.3.6.1.4.1.318.1.1.4.4.1.0", 
	},
	scan_apc_pdu_phases		=>	{
		# The phase number will be appended to the OID
		scan_apc_pdu_phase_current_amperage =>	".1.3.6.1.4.1.318.1.1.12.2.3.1.1.2.", 
		scan_apc_pdu_phase_max_amperage	=>	".1.3.6.1.4.1.318.1.1.12.2.1.1.0",
		### NOTE: These aren't recorded, but they are used for alert triggers.
		phase_low_amp_warning		=>	".1.3.6.1.4.1.318.1.1.12.2.2.1.1.2.1",
		# We'll drop these to be at least 2 Amps below max.
		phase_high_amp_warning		=>	".1.3.6.1.4.1.318.1.1.12.2.2.1.1.3.1",
		# If this is less than 'scan-apc-pdu::critical_amps_below_max' below max, it 
		# will be automatically dropped.
		phase_high_amp_critical		=>	".1.3.6.1.4.1.318.1.1.12.2.2.1.1.4.1",
	},
	scan_apc_pdu_outlets		=>	{
		### The outlet number will be appended to all of these OIDs.
		scan_apc_pdu_outlet_name	=>	".1.3.6.1.4.1.318.1.1.4.5.2.1.3.", 
		scan_apc_pdu_outlet_on_phase	=>	".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.", 
		# read:  1 = on, 2 = off, 4 = unknown
		# write: 1 = on, 2 = off, 3 = cycle
		scan_apc_pdu_outlet_state	=>	".1.3.6.1.4.1.318.1.1.4.4.2.1.3.", 
	},
	scan_apc_pdu_variables		=>	{
		# This is in ticks, so divide the value by 'scan-apc-pdu::ticks_per_second'
		uptime				=>	".1.3.6.1.2.1.1.3.0",
		total_wattage_draw		=>	".1.3.6.1.4.1.318.1.1.12.1.16.0",
	},
};
$anvil->data->{snmp} = {
	community		=>	{
		version			=>	"2c",
		'read'			=>	"public",
		'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});

# Handle start-up tasks
my $problem = $anvil->ScanCore->agent_startup({agent => $THIS_FILE});
if ($problem)
{
	$anvil->nice_exit({exit_code => 1});
}

# Purge can run from anywhere
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});
}

# The APC PDUs only allow one connection at a time. As such, we only run on the striker that is also the
# active DB.
my $host_uuid = $anvil->Get->host_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
	host_uuid                   => $host_uuid,
	"sys::database::primary_db" => $anvil->data->{sys}{database}{primary_db},
	"switches::force"           => $anvil->data->{switches}{force},
}});
if ((not $anvil->data->{switches}{force}) && ($anvil->data->{sys}{database}{primary_db} ne $host_uuid))
{
	# Don't run.
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_pdu_message_0041", variables => { program => $THIS_FILE }});
	$anvil->nice_exit({exit_code => 0});
}

# Find the PDUs. The number of PDUs found is returned. If 0, we exit
if (not find_pdus($anvil))
{
	# No PDUs found.
	$anvil->Log->entry({level => 2, key => "scan_apc_pdu_message_0001", file => $THIS_FILE, line => __LINE__});
	$anvil->nice_exit({exit_code => 1});
}

# Read the last state of any PDUs we already know about
read_last_scan($anvil);

# Collect data from PDUs.
gather_pdu_data($anvil);

# Look for changes.
find_changes($anvil);

# Shut down.
$anvil->ScanCore->agent_shutdown({agent => $THIS_FILE});


#############################################################################################################
# Functions                                                                                                 #
#############################################################################################################

# 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_pdu_uuid, 
    scan_apc_pdu_fence_uuid, 
    scan_apc_pdu_serial_number, 
    scan_apc_pdu_model_number, 
    scan_apc_pdu_manufacture_date, 
    scan_apc_pdu_firmware_version, 
    scan_apc_pdu_hardware_version, 
    scan_apc_pdu_ipv4_address, 
    scan_apc_pdu_mac_address, 
    scan_apc_pdu_mtu_size, 
    scan_apc_pdu_link_speed, 
    scan_apc_pdu_phase_count, 
    scan_apc_pdu_outlet_count 
FROM 
    scan_apc_pdus 
;";
	$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,
	}});
	# One or more records were found.
	foreach my $row (@{$results})
	{
		my $scan_apc_pdu_uuid             = $row->[0];
		my $scan_apc_pdu_fence_uuid       = $row->[1];
		my $scan_apc_pdu_serial_number    = $row->[2];
		my $scan_apc_pdu_model_number     = $row->[3];
		my $scan_apc_pdu_manufacture_date = $row->[4];
		my $scan_apc_pdu_firmware_version = $row->[5];
		my $scan_apc_pdu_hardware_version = $row->[6];
		my $scan_apc_pdu_ipv4_address     = $row->[7];
		my $scan_apc_pdu_mac_address      = $row->[8];
		my $scan_apc_pdu_mtu_size         = $row->[9];
		my $scan_apc_pdu_link_speed       = $row->[10];
		my $scan_apc_pdu_phase_count      = $row->[11];
		my $scan_apc_pdu_outlet_count     = $row->[12];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_apc_pdu_uuid             => $scan_apc_pdu_uuid, 
			scan_apc_pdu_fence_uuid       => $scan_apc_pdu_fence_uuid, 
			scan_apc_pdu_serial_number    => $scan_apc_pdu_serial_number, 
			scan_apc_pdu_model_number     => $scan_apc_pdu_model_number, 
			scan_apc_pdu_manufacture_date => $scan_apc_pdu_manufacture_date, 
			scan_apc_pdu_firmware_version => $scan_apc_pdu_firmware_version, 
			scan_apc_pdu_hardware_version => $scan_apc_pdu_hardware_version, 
			scan_apc_pdu_ipv4_address     => $scan_apc_pdu_ipv4_address, 
			scan_apc_pdu_mac_address      => $scan_apc_pdu_mac_address, 
			scan_apc_pdu_mtu_size         => $scan_apc_pdu_mtu_size, 
			scan_apc_pdu_link_speed       => $scan_apc_pdu_link_speed, 
			scan_apc_pdu_phase_count      => $scan_apc_pdu_phase_count, 
			scan_apc_pdu_outlet_count     => $scan_apc_pdu_outlet_count, 
		}});
		
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_serial_number}    = $scan_apc_pdu_serial_number;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_fence_uuid}       = $scan_apc_pdu_fence_uuid;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_model_number}     = $scan_apc_pdu_model_number;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_manufacture_date} = $scan_apc_pdu_manufacture_date;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_firmware_version} = $scan_apc_pdu_firmware_version;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_hardware_version} = $scan_apc_pdu_hardware_version;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_ipv4_address}     = $scan_apc_pdu_ipv4_address;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_mac_address}      = $scan_apc_pdu_mac_address;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_mtu_size}         = $scan_apc_pdu_mtu_size;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_link_speed}       = $scan_apc_pdu_link_speed;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phase_count}      = $scan_apc_pdu_phase_count;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlet_count}     = $scan_apc_pdu_outlet_count;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_serial_number"    => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_serial_number}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_fence_uuid"       => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_fence_uuid}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_model_number"     => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_model_number}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_manufacture_date" => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_manufacture_date}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_firmware_version" => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_firmware_version}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_hardware_version" => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_hardware_version}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_ipv4_address"     => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_ipv4_address}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_mac_address"      => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_mac_address}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_mtu_size"         => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_mtu_size}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_link_speed"       => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_link_speed}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_phase_count"      => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phase_count}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_outlet_count"     => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlet_count}, 
		}});
		
		# Make it possible to find this PDU by serial number and by fence_uuid reference.
		$anvil->data->{sql}{fence_uuid_to_apc_pdu_uuid}{$scan_apc_pdu_fence_uuid}       = $scan_apc_pdu_uuid;
		$anvil->data->{sql}{serial_number_to_apc_pdu_uuid}{$scan_apc_pdu_serial_number} = $scan_apc_pdu_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::fence_uuid_to_apc_pdu_uuid::${scan_apc_pdu_fence_uuid}"       => $anvil->data->{sql}{fence_uuid_to_apc_pdu_uuid}{$scan_apc_pdu_fence_uuid},
			"sql::serial_number_to_apc_pdu_uuid::${scan_apc_pdu_serial_number}" => $anvil->data->{sql}{serial_number_to_apc_pdu_uuid}{$scan_apc_pdu_serial_number},
		}});
	}
	undef $results;
	
	# Read in the phase data
	$query = "
SELECT 
    scan_apc_pdu_phase_uuid, 
    scan_apc_pdu_phase_scan_apc_pdu_uuid,
    scan_apc_pdu_phase_number, 
    scan_apc_pdu_phase_current_amperage, 
    scan_apc_pdu_phase_max_amperage, 
    scan_apc_pdu_phase_deleted 
FROM 
    scan_apc_pdu_phases 
;";
	$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 => 3, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $scan_apc_pdu_phase_uuid              = $row->[0];
		my $scan_apc_pdu_phase_scan_apc_pdu_uuid = $row->[1];
		my $scan_apc_pdu_phase_number            = $row->[2];
		my $scan_apc_pdu_phase_current_amperage  = $row->[3];
		my $scan_apc_pdu_phase_max_amperage      = $row->[4];
		my $scan_apc_pdu_phase_deleted           = $row->[5];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
			scan_apc_pdu_phase_uuid              => $scan_apc_pdu_phase_uuid, 
			scan_apc_pdu_phase_scan_apc_pdu_uuid => $scan_apc_pdu_phase_scan_apc_pdu_uuid, 
			scan_apc_pdu_phase_number            => $scan_apc_pdu_phase_number, 
			scan_apc_pdu_phase_current_amperage  => $scan_apc_pdu_phase_current_amperage, 
			scan_apc_pdu_phase_max_amperage      => $scan_apc_pdu_phase_max_amperage, 
			scan_apc_pdu_phase_deleted           => $scan_apc_pdu_phase_deleted, 
		}});
		
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_uuid}              = $scan_apc_pdu_phase_uuid;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_scan_apc_pdu_uuid} = $scan_apc_pdu_phase_scan_apc_pdu_uuid;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage}  = $scan_apc_pdu_phase_current_amperage;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_max_amperage}      = $scan_apc_pdu_phase_max_amperage;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_deleted}           = $scan_apc_pdu_phase_deleted;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_phase_scan_apc_pdu_uuid}::scan_apc_pdu_phases::${scan_apc_pdu_phase_number}::scan_apc_pdu_phase_uuid"              => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_uuid}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_phase_scan_apc_pdu_uuid}::scan_apc_pdu_phases::${scan_apc_pdu_phase_number}::scan_apc_pdu_phase_scan_apc_pdu_uuid" => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_scan_apc_pdu_uuid}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_phase_scan_apc_pdu_uuid}::scan_apc_pdu_phases::${scan_apc_pdu_phase_number}::scan_apc_pdu_phase_current_amperage"  => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_phase_scan_apc_pdu_uuid}::scan_apc_pdu_phases::${scan_apc_pdu_phase_number}::scan_apc_pdu_phase_max_amperage"      => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_max_amperage}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_phase_scan_apc_pdu_uuid}::scan_apc_pdu_phases::${scan_apc_pdu_phase_number}::scan_apc_pdu_phase_deleted"           => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_phase_scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_deleted}, 
		}});
	}
	undef $results;
	
	# Read in the outlets.
	$query = "
SELECT 
    scan_apc_pdu_outlet_uuid, 
    scan_apc_pdu_outlet_scan_apc_pdu_uuid,
    scan_apc_pdu_outlet_number, 
    scan_apc_pdu_outlet_name, 
    scan_apc_pdu_outlet_on_phase, 
    scan_apc_pdu_outlet_state 
FROM 
    scan_apc_pdu_outlets 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	$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_pdu_outlet_uuid              = $row->[0];
		my $scan_apc_pdu_outlet_scan_apc_pdu_uuid = $row->[1];
		my $scan_apc_pdu_outlet_number            = $row->[2];
		my $scan_apc_pdu_outlet_name              = $row->[3];
		my $scan_apc_pdu_outlet_on_phase          = $row->[4];
		my $scan_apc_pdu_outlet_state             = $row->[5];
		my $scan_apc_pdu_outlet_note              = $row->[6];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
			scan_apc_pdu_outlet_uuid              => $scan_apc_pdu_outlet_uuid, 
			scan_apc_pdu_outlet_scan_apc_pdu_uuid => $scan_apc_pdu_outlet_scan_apc_pdu_uuid, 
			scan_apc_pdu_outlet_number            => $scan_apc_pdu_outlet_number, 
			scan_apc_pdu_outlet_name              => $scan_apc_pdu_outlet_name, 
			scan_apc_pdu_outlet_on_phase          => $scan_apc_pdu_outlet_on_phase, 
			scan_apc_pdu_outlet_state             => $scan_apc_pdu_outlet_state, 
		}});
		
		# Which serial number does this phase belong to?
		my $scan_apc_pdu_serial_number = $anvil->data->{uuid_to_serial}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_apc_pdu_serial_number => $scan_apc_pdu_serial_number }});
		
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_uuid}              = $scan_apc_pdu_outlet_uuid;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_scan_apc_pdu_uuid} = $scan_apc_pdu_outlet_scan_apc_pdu_uuid;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_name}              = $scan_apc_pdu_outlet_name;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_on_phase}          = $scan_apc_pdu_outlet_on_phase;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state}             = $scan_apc_pdu_outlet_state;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_outlet_scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_uuid"              => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_uuid}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_outlet_scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_scan_apc_pdu_uuid" => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_scan_apc_pdu_uuid}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_outlet_scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_name"              => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_name}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_outlet_scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_on_phase"          => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_on_phase}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_outlet_scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_state"             => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_outlet_scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state}, 
		}});
	}
	undef $results;
	
	# Read in the variables
	$query = "
SELECT 
    scan_apc_pdu_variable_uuid, 
    scan_apc_pdu_variable_scan_apc_pdu_uuid,
    scan_apc_pdu_variable_is_temperature, 
    scan_apc_pdu_variable_name, 
    scan_apc_pdu_variable_value 
FROM 
    scan_apc_pdu_variables 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	$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_pdu_variable_uuid              = $row->[0];
		my $scan_apc_pdu_variable_scan_apc_pdu_uuid = $row->[1];
		my $scan_apc_pdu_variable_is_temperature    = $row->[2];
		my $scan_apc_pdu_variable_name              = $row->[3];
		my $scan_apc_pdu_variable_value             = $row->[4];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
			scan_apc_pdu_variable_uuid              => $scan_apc_pdu_variable_uuid, 
			scan_apc_pdu_variable_scan_apc_pdu_uuid => $scan_apc_pdu_variable_scan_apc_pdu_uuid, 
			scan_apc_pdu_variable_is_temperature    => $scan_apc_pdu_variable_is_temperature, 
			scan_apc_pdu_variable_name              => $scan_apc_pdu_variable_name, 
			scan_apc_pdu_variable_value             => $scan_apc_pdu_variable_value, 
		}});
		
		# Store the variables under the PDU it belongs to.
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_variable_scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{$scan_apc_pdu_variable_name}{scan_apc_pdu_variable_uuid}           = $scan_apc_pdu_variable_uuid;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_variable_scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{$scan_apc_pdu_variable_name}{scan_apc_pdu_variable_is_temperature} = $scan_apc_pdu_variable_is_temperature;
		$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_variable_scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{$scan_apc_pdu_variable_name}{scan_apc_pdu_variable_value}          = $scan_apc_pdu_variable_value;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_variable_scan_apc_pdu_uuid}::scan_apc_pdu_variables::scan_apc_pdu_variable_name::${scan_apc_pdu_variable_name}::scan_apc_pdu_variable_uuid"           => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_variable_scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{$scan_apc_pdu_variable_name}{scan_apc_pdu_variable_uuid}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_variable_scan_apc_pdu_uuid}::scan_apc_pdu_variables::scan_apc_pdu_variable_name::${scan_apc_pdu_variable_name}::scan_apc_pdu_variable_is_temperature" => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_variable_scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{$scan_apc_pdu_variable_name}{scan_apc_pdu_variable_is_temperature}, 
			"sql::scan_apc_pdu_uuid::${scan_apc_pdu_variable_scan_apc_pdu_uuid}::scan_apc_pdu_variables::scan_apc_pdu_variable_name::${scan_apc_pdu_variable_name}::scan_apc_pdu_variable_value"          => $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_variable_scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{$scan_apc_pdu_variable_name}{scan_apc_pdu_variable_value}, 
		}});
	}
	
	return(0);
}

# 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} = [];
	
	# Loop through each PDU we've seen this pass
	foreach my $scan_apc_pdu_uuid (sort {$a cmp $b} keys %{$anvil->data->{pdu}{scan_apc_pdu_uuid}})
	{
		my $new_pdu                 = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{new_pdu};
		my $pdu_host_name           = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{pdu_host_name};
		my $scan_apc_pdu_fence_uuid = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_fence_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_apc_pdu_uuid       => $scan_apc_pdu_uuid, 
			new_pdu                 => $new_pdu, 
			scan_apc_pdu_fence_uuid => $scan_apc_pdu_fence_uuid, 
			pdu_host_name           => $pdu_host_name, 
		}});
		
		# Convert all the long hashes into shorter variables
		my $new_scan_apc_pdu_serial_number    = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_serial_number};
		my $new_scan_apc_pdu_model_number     = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_model_number};
		my $new_scan_apc_pdu_manufacture_date = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date};
		my $new_scan_apc_pdu_firmware_version = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_firmware_version};
		my $new_scan_apc_pdu_hardware_version = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_hardware_version};
		my $new_scan_apc_pdu_ipv4_address     = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_ipv4_address};
		my $new_scan_apc_pdu_mac_address      = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address};
		my $new_scan_apc_pdu_mtu_size         = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size};
		my $new_scan_apc_pdu_link_speed       = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed};
		my $new_scan_apc_pdu_phase_count      = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_phase_count};
		my $new_scan_apc_pdu_outlet_count     = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_outlet_count};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			new_scan_apc_pdu_serial_number    => $new_scan_apc_pdu_serial_number, 
			new_scan_apc_pdu_model_number     => $new_scan_apc_pdu_model_number, 
			new_scan_apc_pdu_manufacture_date => $new_scan_apc_pdu_manufacture_date, 
			new_scan_apc_pdu_firmware_version => $new_scan_apc_pdu_firmware_version, 
			new_scan_apc_pdu_hardware_version => $new_scan_apc_pdu_hardware_version, 
			new_scan_apc_pdu_ipv4_address     => $new_scan_apc_pdu_ipv4_address, 
			new_scan_apc_pdu_mac_address      => $new_scan_apc_pdu_mac_address, 
			new_scan_apc_pdu_mtu_size         => $new_scan_apc_pdu_mtu_size, 
			new_scan_apc_pdu_link_speed       => $new_scan_apc_pdu_link_speed, 
			new_scan_apc_pdu_phase_count      => $new_scan_apc_pdu_phase_count, 
			new_scan_apc_pdu_outlet_count     => $new_scan_apc_pdu_outlet_count, 
		}});
		
		# These are used later for checking the state of the phases. They are not stored in the 
		# database, except for max amps. They should never change.
		my $new_scan_apc_pdu_phase_max_amperage = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{maximum};
		my $new_phase_low_amp_warning           = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{low_warning};
		my $new_phase_high_amp_warning          = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning};
		my $new_phase_high_amp_critical         = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical};
		my $clear_low_amp_warning               = $new_phase_low_amp_warning   + $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_low_warning};
		my $clear_phase_high_amp_warning        = $new_phase_high_amp_warning  - $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_high_warning}; 
		my $clear_phase_high_amp_critical       = $new_phase_high_amp_critical - $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_high_critical};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			new_scan_apc_pdu_phase_max_amperage => $new_scan_apc_pdu_phase_max_amperage, 
			new_phase_low_amp_warning           => $new_phase_low_amp_warning, 
			new_phase_high_amp_warning          => $new_phase_high_amp_warning, 
			new_phase_high_amp_critical         => $new_phase_high_amp_critical, 
			clear_low_amp_warning               => $clear_low_amp_warning, 
			clear_phase_high_amp_warning        => $clear_phase_high_amp_warning, 
			clear_phase_high_amp_critical       => $clear_phase_high_amp_critical, 
		}});
		
		# Have I seen this PDU before?
		if (not $new_pdu)
		{
			# Yup. Search for changes.
			my $old_scan_apc_pdu_serial_number    = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_serial_number};
			my $old_scan_apc_pdu_model_number     = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_model_number};
			my $old_scan_apc_pdu_manufacture_date = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_manufacture_date};
			my $old_scan_apc_pdu_firmware_version = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_firmware_version};
			my $old_scan_apc_pdu_hardware_version = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_hardware_version};
			my $old_scan_apc_pdu_ipv4_address     = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_ipv4_address};
			my $old_scan_apc_pdu_mac_address      = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_mac_address};
			my $old_scan_apc_pdu_mtu_size         = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_mtu_size};
			my $old_scan_apc_pdu_link_speed       = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_link_speed};
			my $old_scan_apc_pdu_phase_count      = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phase_count};
			my $old_scan_apc_pdu_outlet_count     = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlet_count};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				old_scan_apc_pdu_serial_number    => $old_scan_apc_pdu_serial_number, 
				old_scan_apc_pdu_model_number     => $old_scan_apc_pdu_model_number, 
				old_scan_apc_pdu_manufacture_date => $old_scan_apc_pdu_manufacture_date, 
				old_scan_apc_pdu_firmware_version => $old_scan_apc_pdu_firmware_version, 
				old_scan_apc_pdu_hardware_version => $old_scan_apc_pdu_hardware_version, 
				old_scan_apc_pdu_ipv4_address     => $old_scan_apc_pdu_ipv4_address, 
				old_scan_apc_pdu_mac_address      => $old_scan_apc_pdu_mac_address, 
				old_scan_apc_pdu_mtu_size         => $old_scan_apc_pdu_mtu_size, 
				old_scan_apc_pdu_link_speed       => $old_scan_apc_pdu_link_speed, 
				old_scan_apc_pdu_phase_count      => $old_scan_apc_pdu_phase_count, 
				old_scan_apc_pdu_outlet_count     => $old_scan_apc_pdu_outlet_count, 
			}});
			
			# Has the phase data changed?
			my $changes = 0;
			if ($new_scan_apc_pdu_model_number ne $old_scan_apc_pdu_model_number)
			{
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				if ($old_scan_apc_pdu_model_number eq "DELETED")
				{
					# It's back.
					$changes = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
					
					my $variables = {
						name          => $pdu_host_name,
						serial_number => $new_scan_apc_pdu_serial_number,
						ip_address    => $new_scan_apc_pdu_ipv4_address, 
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0006", variables => $variables});
					$anvil->Alert->register({
						alert_level   => "warning", 
						message       => "scan_apc_pdu_message_0006", 
						variables     => $variables, 
						set_by        => $THIS_FILE, 
						sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
					});
				}
				else
				{
					my $variables = {
						name             => $pdu_host_name,
						old_model_number => $old_scan_apc_pdu_model_number,
						new_model_number => $new_scan_apc_pdu_model_number,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0007", variables => $variables});
					$anvil->Alert->register({
						alert_level   => "warning", 
						message       => "scan_apc_pdu_message_0007", 
						variables     => $variables, 
						set_by        => $THIS_FILE, 
						sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
					});
				}
			}
			if ($new_scan_apc_pdu_serial_number ne $old_scan_apc_pdu_serial_number)
			{
				# New PDU?
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name              => $pdu_host_name,
					old_serial_number => $old_scan_apc_pdu_serial_number,
					new_serial_number => $new_scan_apc_pdu_serial_number,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0008", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0008", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_manufacture_date ne $old_scan_apc_pdu_manufacture_date)
			{
				# New PDU?
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name                 => $pdu_host_name,
					old_manufacture_date => $old_scan_apc_pdu_manufacture_date,
					new_manufacture_date => $new_scan_apc_pdu_manufacture_date,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0009", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0009", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_firmware_version ne $old_scan_apc_pdu_firmware_version)
			{
				# Could be a new PDU, or a firmware upgrade
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name                 => $pdu_host_name,
					old_firmware_version => $old_scan_apc_pdu_firmware_version,
					new_firmware_version => $new_scan_apc_pdu_firmware_version,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0010", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0010", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_hardware_version ne $old_scan_apc_pdu_hardware_version)
			{
				# Probably a new PDU
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name                 => $pdu_host_name,
					old_hardware_version => $old_scan_apc_pdu_hardware_version,
					new_hardware_version => $new_scan_apc_pdu_hardware_version,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0011", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0011", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_ipv4_address ne $old_scan_apc_pdu_ipv4_address)
			{
				# This could change, sure.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name             => $pdu_host_name,
					old_ipv4_address => $old_scan_apc_pdu_ipv4_address,
					new_ipv4_address => $new_scan_apc_pdu_ipv4_address,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0012", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0012", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_mac_address ne $old_scan_apc_pdu_mac_address)
			{
				# New PDU, likely
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name            => $pdu_host_name,
					old_mac_address => $old_scan_apc_pdu_mac_address,
					new_mac_address => $new_scan_apc_pdu_mac_address,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0013", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0013", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_mtu_size ne $old_scan_apc_pdu_mtu_size)
			{
				# MTU size changed.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name         => $pdu_host_name,
					old_mtu_size => $old_scan_apc_pdu_mtu_size,
					new_mtu_size => $new_scan_apc_pdu_mtu_size,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0014", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0014", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_link_speed ne $old_scan_apc_pdu_link_speed)
			{
				# This could happen, too.
				   $changes                 = 1;
				my $say_new_link_speed_hr   = $anvil->Convert->bytes_to_human_readable({ 'bytes' => ($new_scan_apc_pdu_link_speed / 8) })."/#!string!suffix_0002!#";
				my $say_new_link_speed_mbps = $anvil->Convert->add_commas({number => ($new_scan_apc_pdu_link_speed / 100000)})." #!string!suffix_0050!#";
				my $say_old_link_speed_hr   = $anvil->Convert->bytes_to_human_readable({ 'bytes' => ($old_scan_apc_pdu_link_speed / 8) })."/#!string!suffix_0002!#";
				my $say_old_link_speed_mbps = $anvil->Convert->add_commas({number => ($old_scan_apc_pdu_link_speed / 100000)})." #!string!suffix_0050!#";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					changes                 => $changes, 
					say_new_link_speed_mbps => $say_new_link_speed_mbps, 
					say_new_link_speed_hr   => $say_new_link_speed_hr, 
					say_old_link_speed_mbps => $say_old_link_speed_mbps, 
					say_old_link_speed_hr   => $say_old_link_speed_hr, 
				}});
				
				my $variables = {
					name                => $pdu_host_name,
					new_link_speed_mbps => $say_new_link_speed_mbps, 
					new_link_speed_hr   => $say_new_link_speed_hr, 
					old_link_speed_mbps => $say_old_link_speed_mbps, 
					old_link_speed_hr   => $say_old_link_speed_hr, 
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0015", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0015", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_phase_count ne $old_scan_apc_pdu_phase_count)
			{
				# New PDU, probably
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name            => $pdu_host_name,
					old_phase_count => sprintf("%02d", $old_scan_apc_pdu_phase_count),
					new_phase_count => sprintf("%02d", $new_scan_apc_pdu_phase_count),
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0016", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0016", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			if ($new_scan_apc_pdu_outlet_count ne $old_scan_apc_pdu_outlet_count)
			{
				# New PDU
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name             => $pdu_host_name,
					old_outlet_count => sprintf("%02d", $old_scan_apc_pdu_outlet_count),
					new_outlet_count => sprintf("%02d", $new_scan_apc_pdu_outlet_count),
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0017", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0017", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
			if ($changes)
			{
				# Save the changes.
				my $query = "
UPDATE 
    public.scan_apc_pdus 
SET
    scan_apc_pdu_serial_number    = ".$anvil->Database->quote($new_scan_apc_pdu_serial_number).", 
    scan_apc_pdu_model_number     = ".$anvil->Database->quote($new_scan_apc_pdu_model_number).", 
    scan_apc_pdu_manufacture_date = ".$anvil->Database->quote($new_scan_apc_pdu_manufacture_date).", 
    scan_apc_pdu_firmware_version = ".$anvil->Database->quote($new_scan_apc_pdu_firmware_version).", 
    scan_apc_pdu_hardware_version = ".$anvil->Database->quote($new_scan_apc_pdu_hardware_version).", 
    scan_apc_pdu_ipv4_address     = ".$anvil->Database->quote($new_scan_apc_pdu_ipv4_address).", 
    scan_apc_pdu_mac_address      = ".$anvil->Database->quote($new_scan_apc_pdu_mac_address).", 
    scan_apc_pdu_mtu_size         = ".$anvil->Database->quote($new_scan_apc_pdu_mtu_size).", 
    scan_apc_pdu_link_speed       = ".$anvil->Database->quote($new_scan_apc_pdu_link_speed).", 
    scan_apc_pdu_phase_count      = ".$anvil->Database->quote($new_scan_apc_pdu_phase_count).", 
    scan_apc_pdu_outlet_count     = ".$anvil->Database->quote($new_scan_apc_pdu_outlet_count).", 
    modified_date                 = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_apc_pdu_uuid             = ".$anvil->Database->quote($scan_apc_pdu_uuid)." 
;";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				push @{$anvil->data->{sys}{queries}}, $query;
			}
			
			### What about other variables?
			# Do I have a previous uptime?
			my $new_uptime = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{uptime};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_uptime => $new_uptime }});
			if ($anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{uptime}{scan_apc_pdu_variable_uuid})
			{
				# Exists, change?
				my $scan_apc_pdu_variable_uuid = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{uptime}{scan_apc_pdu_variable_uuid};
				my $old_uptime                 = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{uptime}{scan_apc_pdu_variable_value};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_variable_uuid => $scan_apc_pdu_variable_uuid, 
					old_uptime                 => $old_uptime, 
					new_uptime                 => $new_uptime, 
				}});
				
				if ($new_uptime ne $old_uptime)
				{
					update_variables($anvil, $scan_apc_pdu_variable_uuid, "uptime", $new_uptime);
					
					# We expect this to change upward. If the new uptime is significantly 
					# less than the old, it rebooted. We put the 300 second buffer 
					# because it's not uncommon for the current uptime to report as 
					# slightly behind the previous read. (Thanks, APC...)
					my $variables = {
						name       => $pdu_host_name,
						old_uptime => $anvil->Convert->time({'time' => $old_uptime}),
						new_uptime => $anvil->Convert->time({'time' => $new_uptime}), 
					};
					if ($new_uptime > $old_uptime)
					{
						# Normal, info-level
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_pdu_message_0018", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "info", 
							message       => "scan_apc_pdu_message_0018", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
					}
					elsif (($new_uptime < $old_uptime) && ($new_uptime < 300))
					{
						# It's rebooted. This is notice level as it's generally just 
						# the NIC rebooting and doesn't interfere with power.
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0019", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "warning", 
							message       => "scan_apc_pdu_message_0019", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
					}
				}
			}
			else
			{
				# New, INSERT it (is_temperature is always false for now).
				insert_variables($anvil, $scan_apc_pdu_uuid, "uptime", $new_uptime);
			}
			
			# Do I have a previous wattage?
			my $new_total_wattage_draw = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{total_wattage_draw};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_total_wattage_draw => $new_total_wattage_draw }});
			if ($anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{total_wattage_draw}{scan_apc_pdu_variable_uuid})
			{
				# Exists, change?
				my $scan_apc_pdu_variable_uuid = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{total_wattage_draw}{scan_apc_pdu_variable_uuid};
				my $old_total_wattage_draw     = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{scan_apc_pdu_variable_name}{total_wattage_draw}{scan_apc_pdu_variable_value};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_variable_uuid => $scan_apc_pdu_variable_uuid, 
					old_total_wattage_draw     => $old_total_wattage_draw, 
				}});
				
				if ($new_total_wattage_draw ne $old_total_wattage_draw)
				{
					my $variables = {
						name                   => $pdu_host_name,
						old_total_wattage_draw => $old_total_wattage_draw,
						new_total_wattage_draw => $new_total_wattage_draw, 
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_pdu_message_0020", variables => $variables});
					$anvil->Alert->register({
						alert_level   => "info", 
						message       => "scan_apc_pdu_message_0020", 
						variables     => $variables, 
						set_by        => $THIS_FILE, 
						sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
					});
					
					update_variables($anvil, $scan_apc_pdu_variable_uuid, "total_wattage_draw", $new_total_wattage_draw);
				}
			}
			else
			{
				# New, INSERT it (is_temperature is always false for now).
				insert_variables($anvil, $scan_apc_pdu_uuid, "total_wattage_draw", $new_total_wattage_draw);
			}
			
			# Have any phases changed?
			foreach my $scan_apc_pdu_phase_number (sort {$a cmp $b} keys %{$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}})
			{
				my $new_scan_apc_pdu_phase_current_amperage = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_phase_number               => $scan_apc_pdu_phase_number, 
					new_scan_apc_pdu_phase_current_amperage => $new_scan_apc_pdu_phase_current_amperage, 
					new_scan_apc_pdu_phase_max_amperage     => $new_scan_apc_pdu_phase_max_amperage, 
					new_total_wattage_draw                  => $new_total_wattage_draw, 
				}});
				
				if ($anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_uuid})
				{
					# We've seen this phase before. Changes?
					my $scan_apc_pdu_phase_uuid                  = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_uuid};
					my $old_scan_apc_pdu_phase_scan_apc_pdu_uuid = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_scan_apc_pdu_uuid};
					my $old_scan_apc_pdu_phase_current_amperage  = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage};
					my $old_scan_apc_pdu_phase_max_amperage      = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_max_amperage};
					my $old_scan_apc_pdu_phase_deleted           = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_deleted};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						scan_apc_pdu_phase_uuid                  => $scan_apc_pdu_phase_uuid, 
						old_scan_apc_pdu_phase_scan_apc_pdu_uuid => $old_scan_apc_pdu_phase_scan_apc_pdu_uuid, 
						old_scan_apc_pdu_phase_current_amperage  => $old_scan_apc_pdu_phase_current_amperage, 
						old_scan_apc_pdu_phase_max_amperage      => $old_scan_apc_pdu_phase_max_amperage, 
						old_scan_apc_pdu_phase_deleted           => $old_scan_apc_pdu_phase_deleted,
					}});
					
					# If the 'deleted' was set, the phase has returned.
					if ($old_scan_apc_pdu_phase_deleted)
					{
						# The phase amperage can change all the time.
						$changes = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
						
						my $variables = {
							name  => $pdu_host_name,
							phase => sprintf("%02d", $scan_apc_pdu_phase_number),
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0021", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "warning", 
							message       => "scan_apc_pdu_message_0021", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
					}
					
					# The max amps per phase is set across all phases. 
					if ($new_scan_apc_pdu_phase_max_amperage ne $old_scan_apc_pdu_phase_max_amperage)
					{
						# This can be set by the user in the PDU's interface
						$changes = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
						
						my $variables = {
							name                   => $pdu_host_name,
							phase                  => sprintf("%02d", $scan_apc_pdu_phase_number),
							old_phase_max_amperage => $old_scan_apc_pdu_phase_max_amperage,
							new_phase_max_amperage => $new_scan_apc_pdu_phase_max_amperage,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0022", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "warning", 
							message       => "scan_apc_pdu_message_0022", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
					}
					if ($old_scan_apc_pdu_phase_current_amperage ne $new_scan_apc_pdu_phase_current_amperage)
					{
						# The phase amperage can change all the time. That said, is 
						# it over the warning or critical thresholds, or has it 
						# dropped back down?
						$changes = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
						
						my $variables = {
							name                       => $pdu_host_name,
							phase                      => sprintf("%02d", $scan_apc_pdu_phase_number),
							old_phase_current_amperage => $old_scan_apc_pdu_phase_current_amperage,
							new_phase_current_amperage => $new_scan_apc_pdu_phase_current_amperage, 
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_pdu_message_0023", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "info", 
							message       => "scan_apc_pdu_message_0023", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
						
						# Cheack for low alerts to set or high alerts to clear
						if ($new_scan_apc_pdu_phase_current_amperage < $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{low_warning})
						{
							### NOTE: We don't care about low amperage warnings, but it 
							###       is a user-configurable value. As such, we'll register alers.
							# Dropped too low, clear high warn and high crit
							my $changed = $anvil->Alert->check_alert_sent({
								debug          => 2,
								record_locator => "scan_apc-pdu::".$scan_apc_pdu_uuid."::phase::".$scan_apc_pdu_phase_number."::amp_low_warning",
								set_by         => $THIS_FILE,
							});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								# Register an alert.
								my $variables = {
									pdu_name => $pdu_host_name,
									phase    => sprintf("%02d", $scan_apc_pdu_phase_number),
								};
								$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0024", variables => $variables});
								$anvil->Alert->register({
									alert_level   => "warning", 
									message       => "scan_apc_pdu_message_0024", 
									variables     => $variables, 
									set_by        => $THIS_FILE, 
									sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
								});
							}
							
							# Clear the high-warning and high-critical, if needed.
							clear_phase_high_critical($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
							clear_phase_high_warning($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
						}
						elsif ($new_scan_apc_pdu_phase_current_amperage < $clear_phase_high_amp_warning)
						{
							# Dropped low enough to clear high warn and high crit
							clear_phase_high_critical($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
							clear_phase_high_warning($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
						}
						elsif ($new_scan_apc_pdu_phase_current_amperage < $clear_phase_high_amp_critical)
						{
							# Dropped low enough to clear high crit.
							clear_phase_high_critical($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
						}
						
						# Cheack for low alerts to clear or high alerts to set
						if ($new_scan_apc_pdu_phase_current_amperage > $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical})
						{
							# Set high crit, clear low warn
							set_phase_high_critical($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
							clear_phase_low_warning($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
						}
						elsif ($new_scan_apc_pdu_phase_current_amperage > $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning})
						{
							# Set high warn
							set_phase_high_warning($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
							clear_phase_low_warning($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
						}
						elsif ($new_scan_apc_pdu_phase_current_amperage > $clear_low_amp_warning)
						{
							# Clear the low warning
							clear_phase_low_warning($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid);
						}
					}
					
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
					if ($changes)
					{
						my $query = "
UPDATE 
    scan_apc_pdu_phases 
SET
    scan_apc_pdu_phase_scan_apc_pdu_uuid = ".$anvil->Database->quote($scan_apc_pdu_uuid).",
    scan_apc_pdu_phase_number            = ".$anvil->Database->quote($scan_apc_pdu_phase_number).", 
    scan_apc_pdu_phase_current_amperage  = ".$anvil->Database->quote($new_scan_apc_pdu_phase_current_amperage).", 
    scan_apc_pdu_phase_max_amperage      = ".$anvil->Database->quote($new_scan_apc_pdu_phase_max_amperage).", 
    modified_date                        = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_apc_pdu_phase_uuid              = ".$anvil->Database->quote($scan_apc_pdu_phase_uuid)." 
;";
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
						push @{$anvil->data->{sys}{queries}}, $query;
					}
				}
				
				delete $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number};
			}
			
			# Any phases that vanished?
			foreach my $scan_apc_pdu_phase_number (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}})
			{
				# Did it just vanish?
				my $scan_apc_pdu_phase_uuid    = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_uuid};
				my $scan_apc_pdu_phase_deleted = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_deleted};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_phase_uuid    => $scan_apc_pdu_phase_uuid, 
					scan_apc_pdu_phase_deleted => $scan_apc_pdu_phase_deleted, 
				}});
				if (not $scan_apc_pdu_phase_deleted)
				{
					# Yup
					my $query = "
UPDATE 
    scan_apc_pdu_phases 
SET 
    scan_apc_pdu_phase_deleted = 'DELETED', 
    modified_date              = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_apc_pdu_phase_uuid    = ".$anvil->Database->quote($scan_apc_pdu_phase_uuid)." 
;";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					push @{$anvil->data->{sys}{queries}}, $query;

					my $variables = {
						name  => $pdu_host_name,
						phase => sprintf("%02d", $scan_apc_pdu_phase_number),
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0030", variables => $variables});
					$anvil->Alert->register({
						alert_level   => "warning", 
						message       => "scan_apc_pdu_message_0030", 
						variables     => $variables, 
						set_by        => $THIS_FILE, 
						sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
					});
				}
			}
			
			# Have any outlets changed?
			foreach my $scan_apc_pdu_outlet_number (sort {$a cmp $b} keys %{$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}})
			{
				my $scan_apc_pdu_serial_number       = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_serial_number};
				my $new_scan_apc_pdu_outlet_name     = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_name};
				my $new_scan_apc_pdu_outlet_on_phase = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_on_phase};
				my $new_scan_apc_pdu_outlet_state    = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_serial_number       => $scan_apc_pdu_serial_number, 
					new_scan_apc_pdu_outlet_name     => $new_scan_apc_pdu_outlet_name, 
					new_scan_apc_pdu_outlet_on_phase => $new_scan_apc_pdu_outlet_on_phase, 
					new_scan_apc_pdu_outlet_state    => $new_scan_apc_pdu_outlet_state, 
				}});
				
				if (($new_scan_apc_pdu_outlet_on_phase ne "!!no_connection!!") or ($new_scan_apc_pdu_outlet_on_phase ne "#!no_value!#"))
				{
					$anvil->Alert->check_condition_age({clear => 1, name => "scan_apc_pdu::pdu::".$scan_apc_pdu_serial_number."::phase_lost::".$scan_apc_pdu_outlet_number});
				}
				if (($new_scan_apc_pdu_outlet_state eq "!!no_connection!!") or ($new_scan_apc_pdu_outlet_state eq "#!no_value!#"))
				{
					$anvil->Alert->check_condition_age({clear => 1, name => "scan_apc_pdu::pdu::".$scan_apc_pdu_serial_number."::outlet_lost::".$scan_apc_pdu_outlet_number});
				}
				
				# Do I know about this outlet?
				if ($anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_uuid})
				{
					# Yup!
					my $scan_apc_pdu_outlet_uuid         = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_uuid};
					my $old_scan_apc_pdu_outlet_name     = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_name};
					my $old_scan_apc_pdu_outlet_on_phase = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_on_phase};
					my $old_scan_apc_pdu_outlet_state    = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						scan_apc_pdu_outlet_uuid         => $scan_apc_pdu_outlet_uuid, 
						old_scan_apc_pdu_outlet_name     => $old_scan_apc_pdu_outlet_name, 
						old_scan_apc_pdu_outlet_on_phase => $old_scan_apc_pdu_outlet_on_phase, 
						old_scan_apc_pdu_outlet_state    => $old_scan_apc_pdu_outlet_state, 
					}});
					
					# Did a vanished outlet come back?
					my $changes = 0;
					if ($old_scan_apc_pdu_outlet_name eq "DELETED")
					{
						# It's back!
						$changes = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
						
						my $variables = {
							name   => $pdu_host_name,
							outlet => sprintf("%02d", $scan_apc_pdu_outlet_number),
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0031", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "warning", 
							message       => "scan_apc_pdu_message_0031", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
					}
					if ($new_scan_apc_pdu_outlet_name ne $old_scan_apc_pdu_outlet_name)
					{
						# Name changed.
						$changes = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
						
						my $variables = {
							name            => $pdu_host_name,
							outlet          => sprintf("%02d", $scan_apc_pdu_outlet_number),
							old_outlet_name => $old_scan_apc_pdu_outlet_name,
							new_outlet_name => $new_scan_apc_pdu_outlet_name,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0032", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "notice", 
							message       => "scan_apc_pdu_message_0032", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
					}
					if ($new_scan_apc_pdu_outlet_on_phase ne $old_scan_apc_pdu_outlet_on_phase)
					{
						# Phase changed. If the new phase is '!!no_connection!!', it 
						# could be contention, so check if this has been the case for 
						# at least five minutes.
						if (($new_scan_apc_pdu_outlet_on_phase eq "!!no_connection!!") or ($new_scan_apc_pdu_outlet_on_phase eq "#!no_value!#"))
						{
							my $age = $anvil->Alert->check_condition_age({name => "scan_apc_pdu::pdu::".$scan_apc_pdu_serial_number."::phase_lost::".$scan_apc_pdu_outlet_number});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }});
							
							if ($age < 600)
							{
								# Ignore it for now.
								next;
							}
						}
						$changes = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
						
						my $variables = {
							name                => $pdu_host_name,
							outlet              => sprintf("%02d", $scan_apc_pdu_outlet_number),
							old_outlet_on_phase => $old_scan_apc_pdu_outlet_on_phase,
							new_outlet_on_phase => $new_scan_apc_pdu_outlet_on_phase,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0033", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "warning", 
							message       => "scan_apc_pdu_message_0033", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
					}
					if ($new_scan_apc_pdu_outlet_state ne $old_scan_apc_pdu_outlet_state)
					{
						# If we had a contention and the new value is '!!no_connection!!'.
						if (($new_scan_apc_pdu_outlet_state eq "!!no_connection!!") or ($new_scan_apc_pdu_outlet_state eq "#!no_value!#"))
						{
							my $age = $anvil->Alert->check_condition_age({name => "scan_apc_pdu::pdu::".$scan_apc_pdu_serial_number."::outlet_lost::".$scan_apc_pdu_outlet_number});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }});
							
							if ($age < 600)
							{
								# Ignore it for now.
								next;
							}
						}
						
						# This is likely from a fence action, so we make it critical
						$changes = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
						
						my $variables = {
							name             => $pdu_host_name,
							outlet           => sprintf("%02d", $scan_apc_pdu_outlet_number),
							old_outlet_state => $old_scan_apc_pdu_outlet_state,
							new_outlet_state => $new_scan_apc_pdu_outlet_state,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0034", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "warning", 
							message       => "scan_apc_pdu_message_0034", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
					}
					
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
					if ($changes)
					{
						# Save.
						my $query = "
UPDATE 
    scan_apc_pdu_outlets 
SET
    scan_apc_pdu_outlet_scan_apc_pdu_uuid = ".$anvil->Database->quote($scan_apc_pdu_uuid).",
    scan_apc_pdu_outlet_number            = ".$anvil->Database->quote($scan_apc_pdu_outlet_number).", 
    scan_apc_pdu_outlet_name              = ".$anvil->Database->quote($new_scan_apc_pdu_outlet_name).", 
    scan_apc_pdu_outlet_on_phase          = ".$anvil->Database->quote($new_scan_apc_pdu_outlet_on_phase).", 
    scan_apc_pdu_outlet_state             = ".$anvil->Database->quote($new_scan_apc_pdu_outlet_state).", 
    modified_date                         = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_apc_pdu_outlet_uuid              = ".$anvil->Database->quote($scan_apc_pdu_outlet_uuid)." 
;";
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
						push @{$anvil->data->{sys}{queries}}, $query;
					}
				}
				else
				{
					# Nope, INSERT it.
					insert_outlets($anvil, $scan_apc_pdu_uuid, $scan_apc_pdu_outlet_number, $new_scan_apc_pdu_outlet_name, $new_scan_apc_pdu_outlet_on_phase, $new_scan_apc_pdu_outlet_state);
					
					my $say_state = "#!string!scan_apc_pdu_unit_0001!#";
					if ($new_scan_apc_pdu_outlet_state eq "on")
					{
						
						$say_state = "#!string!scan_apc_pdu_unit_0002!#";
					}
					elsif ($new_scan_apc_pdu_outlet_state eq "off")
					{
						$say_state = "#!string!scan_apc_pdu_unit_0003!#";
					}
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_apc_pdu_outlet_state => $new_scan_apc_pdu_outlet_state }});
					
					my $variables = {
						pdu_name => $pdu_host_name, 
						outlet   => sprintf("%02d", $scan_apc_pdu_outlet_number),
						'state'  => $say_state,
						on_phase => sprintf("%02d", $new_scan_apc_pdu_outlet_on_phase),
						name     => $new_scan_apc_pdu_outlet_name,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0035", variables => $variables});
					$anvil->Alert->register({
						alert_level   => "warning", 
						message       => "scan_apc_pdu_message_0035", 
						variables     => $variables, 
						set_by        => $THIS_FILE, 
						sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
					});
				}
				
				delete $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number};
			}
			
			# Any outlets vanished?
			foreach my $scan_apc_pdu_outlet_number (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}})
			{
				# Lost, update the note.
				my $scan_apc_pdu_outlet_uuid     = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_uuid};
				my $old_scan_apc_pdu_outlet_name = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_name};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_outlet_uuid     => $scan_apc_pdu_outlet_uuid, 
					old_scan_apc_pdu_outlet_name => $old_scan_apc_pdu_outlet_name, 
				}});
				
				if ($old_scan_apc_pdu_outlet_name ne "DELETED")
				{
					# Yup
					my $query = "
UPDATE 
    scan_apc_pdu_outlets 
SET 
    scan_apc_pdu_outlet_name = 'DELETED', 
    modified_date            = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_apc_pdu_outlet_uuid = ".$anvil->Database->quote($scan_apc_pdu_outlet_uuid)." 
;";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					push @{$anvil->data->{sys}{queries}}, $query;

					$changes = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
					
					my $variables = {
						name   => $pdu_host_name,
						outlet => sprintf("%02d", $scan_apc_pdu_outlet_number),
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0036", variables => $variables});
					$anvil->Alert->register({
						alert_level   => "warning", 
						message       => "scan_apc_pdu_message_0036", 
						variables     => $variables, 
						set_by        => $THIS_FILE, 
						sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
					});
				}
			}
			
			# Delete this from the SQL hash so we know it didn't vanish.
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0726", variables => { hash_key => "sql::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}" }});
			delete $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid};
		}
		else
		{
			# OK, now INSERT it.
			my $query = "
INSERT INTO 
    scan_apc_pdus
(
    scan_apc_pdu_uuid, 
    scan_apc_pdu_fence_uuid, 
    scan_apc_pdu_serial_number, 
    scan_apc_pdu_model_number, 
    scan_apc_pdu_manufacture_date, 
    scan_apc_pdu_firmware_version, 
    scan_apc_pdu_hardware_version, 
    scan_apc_pdu_ipv4_address, 
    scan_apc_pdu_mac_address, 
    scan_apc_pdu_mtu_size, 
    scan_apc_pdu_link_speed, 
    scan_apc_pdu_phase_count, 
    scan_apc_pdu_outlet_count, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_apc_pdu_uuid).", 
    ".$anvil->Database->quote($scan_apc_pdu_fence_uuid).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_serial_number).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_model_number).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_manufacture_date).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_firmware_version).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_hardware_version).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_ipv4_address).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_mac_address).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_mtu_size).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_link_speed).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_phase_count).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_outlet_count).", 
    ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			push @{$anvil->data->{sys}{queries}}, $query;
			
			# Send an alert telling the user about this new PDU.
			my $say_link_speed_hr   = "#!string!scan_apc_pdu_unit_0004!#";	# "Down"
			my $say_link_speed_mbps = "#!string!scan_apc_pdu_unit_0004!#";	# "Down"
			if (($new_scan_apc_pdu_link_speed) && ($new_scan_apc_pdu_link_speed =~ /^\d+$/))
			{
				$say_link_speed_hr   = $anvil->Convert->bytes_to_human_readable({'bytes' => ($new_scan_apc_pdu_link_speed / 8)})."/#!string!scan_apc_pdu_unit_0006!#";
				$say_link_speed_mbps = ($new_scan_apc_pdu_link_speed / 1000000)." #!string!scan_apc_pdu_unit_0005!#";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					say_link_speed_hr   => $say_link_speed_hr, 
					say_link_speed_mbps => $say_link_speed_mbps, 
				}});
			}
			
			# Record the variables (uptime and wattage)
			foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}})
			{
				my $value = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{$variable};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					variable => $variable, 
					value    => $value, 
				}});
				
				# NOTE: We don't send an alert here as we incorporated the two variables we care about above.
				insert_variables($anvil, $scan_apc_pdu_uuid, $variable, $value);
			}
			
			# Load the variables we know about.
			my $new_uptime             = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{uptime};
			my $new_total_wattage_draw = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{total_wattage_draw};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				new_uptime             => $new_uptime." (".$anvil->Convert->time({'time' => $new_uptime}).")",
				new_total_wattage_draw => $new_total_wattage_draw
			}});
			my $variables = {
				name			=>	$pdu_host_name,
				serial_number		=>	$new_scan_apc_pdu_serial_number,
				model_number		=>	$new_scan_apc_pdu_model_number,
				manufacture_date	=>	$new_scan_apc_pdu_manufacture_date." #!string!scan_apc_pdu_unit_0007!#",
				firmware_version	=>	$new_scan_apc_pdu_firmware_version,
				hardware_version	=>	$new_scan_apc_pdu_hardware_version,
				ipv4_address		=>	$new_scan_apc_pdu_ipv4_address,
				mac_address		=>	$new_scan_apc_pdu_mac_address,
				mtu_size		=>	$new_scan_apc_pdu_mtu_size,
				link_speed_hr		=>	$say_link_speed_hr,
				link_speed_mbps		=>	$say_link_speed_mbps,
				phase_count		=>	$new_scan_apc_pdu_phase_count,
				outlet_count		=>	$new_scan_apc_pdu_outlet_count,
				phase_max_amperage	=>	$new_scan_apc_pdu_phase_max_amperage,
				phase_low_amp_warning	=>	$new_phase_low_amp_warning,
				phase_high_amp_warning	=>	$new_phase_high_amp_warning,
				phase_high_amp_critical	=>	$new_phase_high_amp_critical,
				uptime			=>	$anvil->Convert->time({'time' => $new_uptime}), 
				total_wattage_draw	=>	$new_total_wattage_draw, 
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0037", variables => $variables});
			$anvil->Alert->register({
				alert_level   => "warning", 
				message       => "scan_apc_pdu_message_0037", 
				variables     => $variables, 
				set_by        => $THIS_FILE, 
				sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
			});
			
			# Insert the phase data
			foreach my $scan_apc_pdu_phase_number (sort {$a cmp $b} keys %{$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}})
			{
				my $scan_apc_pdu_phase_uuid                 = $anvil->Get->uuid();
				my $new_scan_apc_pdu_phase_current_amperage = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_phase_uuid                 => $scan_apc_pdu_phase_uuid, 
					new_scan_apc_pdu_phase_current_amperage => $new_scan_apc_pdu_phase_current_amperage, 
				}});
				
				my $query = "
INSERT INTO 
    scan_apc_pdu_phases 
(
    scan_apc_pdu_phase_uuid, 
    scan_apc_pdu_phase_scan_apc_pdu_uuid, 
    scan_apc_pdu_phase_number, 
    scan_apc_pdu_phase_current_amperage, 
    scan_apc_pdu_phase_max_amperage, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_apc_pdu_phase_uuid).", 
    ".$anvil->Database->quote($scan_apc_pdu_uuid).", 
    ".$anvil->Database->quote($scan_apc_pdu_phase_number).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_phase_current_amperage).", 
    ".$anvil->Database->quote($new_scan_apc_pdu_phase_max_amperage).", 
    ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				push @{$anvil->data->{sys}{queries}}, $query;
				
				my $variables = {
					phase => sprintf("%02d", $scan_apc_pdu_phase_number),
					amps  => $new_scan_apc_pdu_phase_current_amperage,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0038", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0038", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
			
			# Insert the outlet data
			foreach my $scan_apc_pdu_outlet_number (sort {$a cmp $b} keys %{$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}})
			{
				my $scan_apc_pdu_outlet_uuid         = $anvil->Get->uuid();
				my $new_scan_apc_pdu_outlet_name     = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_name};
				my $new_scan_apc_pdu_outlet_on_phase = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_on_phase};
				my $new_scan_apc_pdu_outlet_state    = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_outlet_uuid         => $scan_apc_pdu_outlet_uuid, 
					new_scan_apc_pdu_outlet_name     => $new_scan_apc_pdu_outlet_name, 
					new_scan_apc_pdu_outlet_on_phase => $new_scan_apc_pdu_outlet_on_phase, 
					new_scan_apc_pdu_outlet_state    => $new_scan_apc_pdu_outlet_state, 
				}});
				
				insert_outlets($anvil, $scan_apc_pdu_uuid, $scan_apc_pdu_outlet_number, $new_scan_apc_pdu_outlet_name, $new_scan_apc_pdu_outlet_on_phase, $new_scan_apc_pdu_outlet_state);
				
				my $say_state = "#!string!scan_apc_pdu_unit_0001!#";
				if ($new_scan_apc_pdu_outlet_state eq "on")
				{
					
					$say_state = "#!string!scan_apc_pdu_unit_0002!#";
				}
				elsif ($new_scan_apc_pdu_outlet_state eq "off")
				{
					$say_state = "#!string!scan_apc_pdu_unit_0003!#";
				}
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_apc_pdu_outlet_state => $new_scan_apc_pdu_outlet_state }});
				
				my $variables = {
					outlet   => sprintf("%02d", $scan_apc_pdu_outlet_number),
					'state'  => $say_state,
					on_phase => sprintf("%02d", $new_scan_apc_pdu_outlet_on_phase),
					name     => $new_scan_apc_pdu_outlet_name,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0039", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0039", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
		}
	}
	
	# Look for PDUs that we saw before that are gone now.
	foreach my $scan_apc_pdu_uuid (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_apc_pdu_uuid}})
	{
		# Gone! Is this the first time it's disappeared?
		my $scan_apc_pdu_serial_number = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_serial_number};
		my $scan_apc_pdu_model_number  = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_model_number};
		my $scan_apc_pdu_ipv4_address  = $anvil->data->{sql}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_ipv4_address};
		   $scan_apc_pdu_ipv4_address  = "--" if not defined $scan_apc_pdu_ipv4_address;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_apc_pdu_uuid          => $scan_apc_pdu_uuid, 
			scan_apc_pdu_serial_number => $scan_apc_pdu_serial_number, 
			scan_apc_pdu_model_number  => $scan_apc_pdu_model_number, 
			scan_apc_pdu_ipv4_address  => $scan_apc_pdu_ipv4_address, 
		}});
		
		
		if ($scan_apc_pdu_model_number ne "DELETED")
		{
			# The PDUs only allow one connection at a time, so if another scan agent is 
			# connected, we'll get this issue. As such, check how long it's been missing, and 
			# alert only if it's been missing for 10 minutes.
			my $age = $anvil->Alert->check_condition_age({name => "scan_apc_pdu::lost_pdu::".$scan_apc_pdu_serial_number});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }});
			
			if ($age > 600)
			{
				# Yup! send an alert.
				my $query = "
UPDATE 
    scan_apc_pdus 
SET 
    scan_apc_pdu_model_number = 'DELETED', 
    modified_date             = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_apc_pdu_uuid         = ".$anvil->Database->quote($scan_apc_pdu_uuid)." 
;";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				push @{$anvil->data->{sys}{queries}}, $query;
				
				my $variables = {
					model        => $scan_apc_pdu_model_number,
					serial_numer => $scan_apc_pdu_serial_number,
					ip_address   => $scan_apc_pdu_ipv4_address,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0040", variables => $variables});
				$anvil->Alert->register({
					alert_level   => "warning", 
					message       => "scan_apc_pdu_message_0040", 
					variables     => $variables, 
					set_by        => $THIS_FILE, 
					sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
				});
			}
		}
	}
	
	# Commit the queries.
	$anvil->Database->write({query => $anvil->data->{sys}{queries}, debug => 2, source => $THIS_FILE, line => __LINE__});
	
	return(0);
}

# Set the phase-low alert, if not clear before
sub clear_phase_low_warning
{
	my ($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid) = @_;
	
	my $changed = $anvil->Alert->check_alert_sent({
		debug          => 3,
		record_locator => "scan_apc-pdu::".$scan_apc_pdu_uuid."::phase::".$scan_apc_pdu_phase_number."::amp_low_warning",
		set_by         => $THIS_FILE,
		clear          => 1,
	});
	if ($changed)
	{
		# Register an alert-cleared event.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0029", variables => { phase => $scan_apc_pdu_phase_number, name => $pdu_host_name }});
		$anvil->Alert->register({
			alert_level => "notice", 
			clear       => 1,
			message     => "scan_apc_pdu_message_0029,!!phase!".$scan_apc_pdu_phase_number."!!,!!name!".$pdu_host_name."!!", 
			set_by      => $THIS_FILE,
		});
	}
	
	return(0);
}

# This sets the phase amparage high warning alert, if set.
sub set_phase_high_warning
{
	my ($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid) = @_;
	
	my $changed = $anvil->Alert->check_alert_sent({
		debug          => 3,
		record_locator => "scan_apc-pdu::".$scan_apc_pdu_uuid."::phase::".$scan_apc_pdu_phase_number."::amp_high_warning",
		set_by         => $THIS_FILE,
	});
	if ($changed)
	{
		# Register an alert-cleared event.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0027", variables => { phase => $scan_apc_pdu_phase_number, name => $pdu_host_name }});
		$anvil->Alert->register({
			alert_level => "notice", 
			clear       => 1,
			message     => "scan_apc_pdu_message_0027,!!phase!".$scan_apc_pdu_phase_number."!!,!!name!".$pdu_host_name."!!", 
			set_by      => $THIS_FILE,
		});
	}
	
	return(0)
}

# This clears the phase amparage high warning alert, if set.
sub clear_phase_high_warning
{
	my ($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid) = @_;
	
	my $changed = $anvil->Alert->check_alert_sent({
		debug          => 3,
		record_locator => "scan_apc-pdu::".$scan_apc_pdu_uuid."::phase::".$scan_apc_pdu_phase_number."::amp_high_warning",
		set_by         => $THIS_FILE,
		clear          => 1,
	});
	if ($changed)
	{
		# Register an alert-cleared event.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0028", variables => { phase => $scan_apc_pdu_phase_number, name => $pdu_host_name }});
		$anvil->Alert->register({
			alert_level => "notice", 
			clear       => 1,
			message     => "scan_apc_pdu_message_0028,!!phase!".$scan_apc_pdu_phase_number."!!,!!name!".$pdu_host_name."!!", 
			set_by      => $THIS_FILE,
		});
	}
	
	return(0)
}

# This sets the phase high-critical alert, if not already.
sub set_phase_high_critical
{
	my ($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid) = @_;

	my $changed = $anvil->Alert->check_alert_sent({
		debug          => 3,
		record_locator => "scan_apc-pdu::".$scan_apc_pdu_uuid."::phase::".$scan_apc_pdu_phase_number."::amp_high_critical",
		set_by         => $THIS_FILE,
	});
	if ($changed)
	{
		# Register an alert-cleared event.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0025", variables => { phase => $scan_apc_pdu_phase_number, name => $pdu_host_name }});
		$anvil->Alert->register({
			alert_level => "notice", 
			clear       => 1,
			message     => "scan_apc_pdu_message_0025,!!phase!".$scan_apc_pdu_phase_number."!!,!!name!".$pdu_host_name."!!", 
			set_by      => $THIS_FILE,
		});
	}
	
	return(0);
}

# This clears the phase amparage high critical alert, if set.
sub clear_phase_high_critical
{
	my ($anvil, $pdu_host_name, $scan_apc_pdu_phase_number, $scan_apc_pdu_uuid) = @_;
	
	my $changed = $anvil->Alert->check_alert_sent({
		debug          => 3,
		record_locator => "scan_apc-pdu::".$scan_apc_pdu_uuid."::phase::".$scan_apc_pdu_phase_number."::amp_high_critical",
		set_by         => $THIS_FILE,
		clear          => 1,
	});
	if ($changed)
	{
		# Register an alert-cleared event.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0026", variables => { phase => $scan_apc_pdu_phase_number, name => $pdu_host_name }});
		$anvil->Alert->register({
			alert_level => "notice", 
			clear       => 1,
			message     => "scan_apc_pdu_message_0026,!!phase!".$scan_apc_pdu_phase_number."!!,!!name!".$pdu_host_name."!!", 
			set_by      => $THIS_FILE,
		});
	}
	
	return(0)
}

# This INSERTs a new outlet
sub insert_outlets
{
	my ($anvil, $scan_apc_pdu_uuid, $scan_apc_pdu_outlet_number, $scan_apc_pdu_outlet_name, $scan_apc_pdu_outlet_on_phase, $scan_apc_pdu_outlet_state) = @_;
	
	my $scan_apc_pdu_outlet_uuid = $anvil->Get->uuid();
	my $query                    = "
INSERT INTO 
    scan_apc_pdu_outlets 
(
    scan_apc_pdu_outlet_uuid, 
    scan_apc_pdu_outlet_scan_apc_pdu_uuid, 
    scan_apc_pdu_outlet_number, 
    scan_apc_pdu_outlet_name, 
    scan_apc_pdu_outlet_on_phase, 
    scan_apc_pdu_outlet_state, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_apc_pdu_outlet_uuid).", 
    ".$anvil->Database->quote($scan_apc_pdu_uuid).", 
    ".$anvil->Database->quote($scan_apc_pdu_outlet_number).", 
    ".$anvil->Database->quote($scan_apc_pdu_outlet_name).", 
    ".$anvil->Database->quote($scan_apc_pdu_outlet_on_phase).", 
    ".$anvil->Database->quote($scan_apc_pdu_outlet_state).", 
    ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	push @{$anvil->data->{sys}{queries}}, $query;
	
	return($scan_apc_pdu_outlet_uuid);
}

# This UPDATEs a variable
sub update_variables
{
	my ($anvil, $scan_apc_pdu_variable_uuid, $variable, $value) = @_;
	
	my $query = "
UPDATE 
    scan_apc_pdu_variables 
SET
    scan_apc_pdu_variable_name  = ".$anvil->Database->quote($variable).", 
    scan_apc_pdu_variable_value = ".$anvil->Database->quote($value).", 
    modified_date               = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_apc_pdu_variable_uuid  = ".$anvil->Database->quote($scan_apc_pdu_variable_uuid)." 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	push @{$anvil->data->{sys}{queries}}, $query;
	
	return(0);
}

# This INSERTs a new variable
sub insert_variables
{
	my ($anvil, $scan_apc_pdu_uuid, $variable, $value) = @_;
	
	my $scan_apc_pdu_variable_uuid = $anvil->Get->uuid();
	my $query                      = "
INSERT INTO 
    scan_apc_pdu_variables 
(
    scan_apc_pdu_variable_uuid, 
    scan_apc_pdu_variable_scan_apc_pdu_uuid, 
    scan_apc_pdu_variable_is_temperature, 
    scan_apc_pdu_variable_name, 
    scan_apc_pdu_variable_value, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_apc_pdu_variable_uuid).", 
    ".$anvil->Database->quote($scan_apc_pdu_uuid).", 
    FALSE, 
    ".$anvil->Database->quote($variable).", 
    ".$anvil->Database->quote($value).", 
    ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	push @{$anvil->data->{sys}{queries}}, $query;
	
	return($scan_apc_pdu_variable_uuid);
}

# This calls each PDU, first to get the model number and update the OIDs to use if needed, then gathers the 
# information from the PDU.
sub gather_pdu_data
{
	my ($anvil) = @_;
	
	# Loop through the PDUs we found in fences.
	foreach my $fence_uuid (sort {$a cmp $b} keys %{$anvil->data->{fences}{fence_uuid}})
	{
		my $pdu_ip   = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{ip_address};
		my $pdu_name = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			fence_uuid => $fence_uuid, 
			pdu_ip     => $pdu_ip, 
			pdu_name   => $pdu_name, 
		}});
		
		# Have we seen this PDU before? We may have info in our database that's not mapped to fences 
		# yet, so we'll also check by serial number as well.
		my $scan_apc_pdu_uuid = "";
		my $new_pdu           = 1;
		if ((exists $anvil->data->{sql}{fence_uuid_to_apc_pdu_uuid}{$fence_uuid}) && (defined $anvil->data->{sql}{fence_uuid_to_apc_pdu_uuid}{$fence_uuid}))
		{
			# Yup!
			$new_pdu           = 0;
			$scan_apc_pdu_uuid = $anvil->data->{sql}{fence_uuid_to_apc_pdu_uuid}{$fence_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_apc_pdu_uuid => $scan_apc_pdu_uuid, 
				new_pdu           => $new_pdu, 
			}});
		}
		
		# Can I ping it? This returns '1' if it was pingable, '0' if not.
		my ($pinged, $average_time) = $anvil->Network->ping({ping => $pdu_ip});
		$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->{fences}{fence_uuid}{$fence_uuid}{ping}      = 0;
			$anvil->data->{fences}{fence_uuid}{$fence_uuid}{connected} = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"fences::fence_uuid::${fence_uuid}::ping"      => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{ping}, 
				"fences::fence_uuid::${fence_uuid}::connected" => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{connected}, 
			}});
			next;
		}

		$anvil->data->{fences}{fence_uuid}{$fence_uuid}{ping}         = 1;
		$anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version} = $anvil->data->{snmp}{community}{version};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"fences::fence_uuid::${fence_uuid}::ping"         => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{ping}, 
			"fences::fence_uuid::${fence_uuid}::snmp_version" => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version}, 
		}});
		
		my ($scan_apc_pdu_serial_number, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_serial_number},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_apc_pdu_serial_number => $scan_apc_pdu_serial_number,
			data_type                  => $data_type,
		}});
		
		# If the serial number is '!!no_connection!!', this might be an old PDU that only supports SNMP v1.
		if ($scan_apc_pdu_serial_number eq "!!no_connection!!")
		{
			# Try SNMP v1
			$anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version} = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"fences::fence_uuid::${fence_uuid}::snmp_version" => $anvil->data->{snmp}{community}{version}, 
			}});
			
			($scan_apc_pdu_serial_number, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $pdu_ip, 
				oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_serial_number},
				version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_apc_pdu_serial_number => $scan_apc_pdu_serial_number,
				data_type                  => $data_type,
			}});
			
			# If it's still '!!no_connection!!', something else is wrong. Is possible it's a new 
			# PDU with SNMP turned off, perhaps?
			if ($scan_apc_pdu_serial_number eq "!!no_connection!!")
			{
				# No luck
				$scan_apc_pdu_serial_number                                = "";
				$anvil->data->{fences}{fence_uuid}{$fence_uuid}{connected} = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_serial_number                     => $scan_apc_pdu_serial_number, 
					"fences::fence_uuid::${fence_uuid}::connected" => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{connected}, 
				}});
			}
		}
		
		# If we didn't find the PDU using the fence_uuid, see if we can find it by the serial number.
		if ($new_pdu)
		{
			if (($scan_apc_pdu_serial_number) && (exists $anvil->data->{sql}{serial_number_to_apc_pdu_uuid}{$scan_apc_pdu_serial_number}))
			{
				# It's new, generate the UUID now. We'll set 'scan_apc_pdu_new' so we know to INSERT 
				# it later.
				$scan_apc_pdu_uuid = $anvil->data->{sql}{serial_number_to_apc_pdu_uuid}{$scan_apc_pdu_serial_number};
				$new_pdu           = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_uuid => $scan_apc_pdu_uuid, 
					new_pdu           => $new_pdu, 
				}});
			}
			else
			{
				$scan_apc_pdu_uuid = $anvil->Get->uuid();
				$new_pdu           = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_apc_pdu_uuid => $scan_apc_pdu_uuid, 
					new_pdu           => $new_pdu, 
				}});
			}
		}
		
		$anvil->data->{fences}{fence_uuid}{$fence_uuid}{scan_apc_pdu_uuid} = $scan_apc_pdu_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"fences::fence_uuid::${fence_uuid}::scan_apc_pdu_uuid" => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{scan_apc_pdu_uuid}, 
		}});
		
		# These are set to avoid 'undefined' variable warnings later if we fail to reach this PDU.
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{pdu_host_name}                               = $pdu_name;
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{new_pdu}                                     = $new_pdu;
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_fence_uuid}       = $fence_uuid;
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_serial_number}    = $scan_apc_pdu_serial_number;
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_model_number}     = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date} = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_firmware_version} = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_hardware_version} = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_ipv4_address}     = $pdu_ip;
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address}      = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size}         = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed}       = 0;
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_phase_count}      = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_outlet_count}     = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{uptime}              = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{total_wattage_draw}  = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{maximum}                           = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{low_warning}                       = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning}                      = "";
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical}                     = "";
		
		# If I got the serial number, I found the PDU.
		next if not $scan_apc_pdu_serial_number;

		# In case this PDU disappeared before, this will clear that condition.
		$anvil->Alert->check_condition_age({clear => 1, name => "scan_apc_pdu::lost_pdu::".$scan_apc_pdu_serial_number});
		
		#############################################################################################
		# Base PDU info                                                                             #
		#############################################################################################
		
		### Get the base PDU info.
		# Model Number
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_model_number}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_model_number},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_model_number" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_model_number},
			data_type                                                                               => $data_type,
		}});
		
		# Manufacture date 
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_manufacture_date},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_manufacture_date" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date},
			data_type                                                                                   => $data_type,
		}});
		
		# Firmware version
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_firmware_version}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_firmware_version},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_firmware_version" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_firmware_version},
			data_type                                                                                   => $data_type,
		}});
		
		# Hardware version
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_hardware_version}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_hardware_version},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_hardware_version" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_hardware_version},
			data_type                                                                                   => $data_type,
		}});
		
		# MAC address. Note, this could use a couple different OIDs, depending on the version. It also requires the custom MIB
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_mac_address},
			mib       => $anvil->data->{'scan-apc-pdu'}{striker_mib}, 
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_mac_address" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address},
			data_type                                                                              => $data_type,
		}});
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address} eq "#!no_value!#")
		{
			# Some older PDUs use a different OID.
			($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $pdu_ip, 
				oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_mac_address_alt},
				mib       => $anvil->data->{'scan-apc-pdu'}{striker_mib}, 
				version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_mac_address" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address},
				data_type                                                                              => $data_type,
			}});
		}
		# Make the MAC address lower case and replace the spaces with colons
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address} =  lc($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address});
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address} =~ s/^\s+//g;
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address} =~ s/\s+$//g;
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address} =~ s/ /:/g;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_mac_address" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address},
		}});
		
		# Read the MTU. This again could be at one of two OIDs.
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_mtu_size},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_mtu_size" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size},
			data_type                                                                           => $data_type,
		}});
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size} eq "#!no_value!#")
		{
			# Some older PDUs use a different OID.
			($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $pdu_ip, 
				oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_mtu_size_alt},
				version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_mtu_size" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size},
				data_type                                                                           => $data_type,
			}});
		}
		
		# Read the link speed. Again, this could be at alternate OIDs.
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_link_speed},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_link_speed" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed},
			data_type                                                                             => $data_type,
		}});
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed} eq "#!no_value!#")
		{
			# Some older PDUs use a different OID.
			($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $pdu_ip, 
				oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_link_speed_alt},
				version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_link_speed" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed},
				data_type                                                                             => $data_type,
			}});
		}
		
		# Read in the phase count
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_phase_count}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_phase_count},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_phase_count" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_phase_count},
			data_type                                                                              => $data_type,
		}});
		
		# Read in the outlet count
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_outlet_count}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu}{scan_apc_pdu_outlet_count},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_outlet_count" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_outlet_count},
			data_type                                                                               => $data_type,
		}});
		
		### These change often and will go into the 'variables' table
		# Read the uptime
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{uptime}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu_variables}{uptime},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_variables::uptime" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{uptime},
			data_type                                                                      => $data_type,
		}});
		
		# Total watt draw
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{total_wattage_draw}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu_variables}{total_wattage_draw},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_variables::total_wattage_draw" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{total_wattage_draw},
			data_type                                                                                  => $data_type,
		}});
		
		### These are used later for checking the state of the phases. They are not stored in the database.
		# Macimum allowed amperage
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{maximum}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu_phases}{scan_apc_pdu_phase_max_amperage},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::maximum" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{maximum},
			data_type                                                         => $data_type,
		}});
		
		# Low amperage on a phase threshold
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{low_warning}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu_phases}{phase_low_amp_warning},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::low_warning" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{low_warning},
			data_type                                                             => $data_type,
		}});
		
		# High warning
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu_phases}{phase_high_amp_warning},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::high_warning" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning},
			data_type                                                              => $data_type,
		}});
		
		# Phase high amperage threshold
		($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical}, $data_type) = $anvil->Remote->read_snmp_oid({
			debug     => 3,
			target    => $pdu_ip, 
			oid       => $anvil->data->{oids}{scan_apc_pdu_phases}{phase_high_amp_critical},
			version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
			community => $anvil->data->{snmp}{community}{'read'}
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::high_critical" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical},
			data_type                                                               => $data_type,
		}});
	
		### Convert some unknown values to values we can store in the database
		# MAC address
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address} eq "#!no_value!#")
		{
			$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address} = "xx:xx:xx:xx:xx:xx";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_mac_address" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mac_address}, 
			}});
		}
		# MTU
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size} eq "#!no_value!#")
		{
			$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size} = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_mtu_size" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_mtu_size}, 
			}});
		}
		# Link speed
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed} eq "#!no_value!#")
		{
			$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed} = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_link_speed" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_link_speed}, 
			}});
		}
		# Wattage isn't available on older PDUs
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{total_wattage_draw} eq "#!no_value!#")
		{
			$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{total_wattage_draw} = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_variables::total_wattage_draw" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{total_wattage_draw}, 
			}});
		}

		### TODO: We should probably sanity check the various values. Error or set?
		# If the (high critical amperage + 'scan-apc-pdu::critical_amps_below_max') > maximum 
		# amperage, we'll set the critical warning level to be 
		# (maximum - 'scan-apc-pdu::critical_amps_below_max')
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-apc-pdu::critical_amps_below_max" => $anvil->data->{'scan-apc-pdu'}{critical_amps_below_max}, 
		}});
		if (($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical} + $anvil->data->{'scan-apc-pdu'}{critical_amps_below_max}) > $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{maximum})
		{
			$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical} = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{maximum} - $anvil->data->{'scan-apc-pdu'}{critical_amps_below_max};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::high_critical" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical}, 
			}});
		}
		
		# Make sure that the warning is at least 'scan-apc-pdu::warning_amps_below_critical'
		if (($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning} + $anvil->data->{'scan-apc-pdu'}{warning_amps_below_critical}) > $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical})
		{
			$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning} = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical} - $anvil->data->{'scan-apc-pdu'}{warning_amps_below_critical};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::high_warning" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning}, 
			}});
		}
		
		# Set the alert clear levels
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_high_critical} = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_critical} - $anvil->data->{'scan-apc-pdu'}{clear_alert_threshold};
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_high_warning}  = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{high_warning} - $anvil->data->{'scan-apc-pdu'}{clear_alert_threshold};
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_low_warning}   = $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{low_warning} + $anvil->data->{'scan-apc-pdu'}{clear_alert_threshold};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::clear_high_critical" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_high_critical}, 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::clear_high_warning"  => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_high_warning}, 
			"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::amperage::clear_low_warning"   => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{amperage}{clear_low_warning}, 
		}});
		
		# Uptime is in ticks
		$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{uptime} /= $anvil->data->{'scan-apc-pdu'}{ticks_per_second};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"pdu:${scan_apc_pdu_serial_number}::scan_apc_pdu_variables::uptime" => $anvil->Convert->add_commas({number => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{uptime}})." (".$anvil->Convert->time({'time' => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_variables}{uptime}, translate => 1}).")", 
		}});
		
		# The dates are in 'mm/dd/yyyy' or 'mm/dd/yy' format, convert them to 'yyyy/mm/dd'
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date} =~ /(\d\d)\/(\d\d)\/(\d\d\d\d)$/)
		{
			my $year  = $3;
			my $month = $1;
			my $day   = $2;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				year  => $year, 
				month => $month, 
				day   => $day, 
			}});
			
			$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date} = $year."/".$month."/".$day;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_manufacture_date" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date}, 
			}});
		}
		elsif ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date} =~ /(\d\d)\/(\d\d)\/(\d\d)$/)
		{
			my $year  = $3;
			my $month = $1;
			my $day   = $2;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"year"  => $year, 
				"month" => $month, 
				"day"   => $day, 
			}});
			
			if ($year < 70)
			{
				$year += 2000;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"year" => $year, 
				}});
			}
			else
			{
				$year += 1900;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"year" => $year, 
				}});
			}
			$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date} = $year."/".$month."/".$day;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu::scan_apc_pdu_manufacture_date" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_manufacture_date}, 
			}});
		}
		
		# If an alert (cleared) message/log is needed for either phase or outlet count, they'll use this hash 
		my $variables = {
			name          => $pdu_name, 
			ip            => $pdu_ip,
			serial_number => $scan_apc_pdu_serial_number, 
		};
		
		# Verify that the phase count is valid
		my $bad_phase_count_key = "scan_apc_pdu::".$scan_apc_pdu_uuid."::bad_phase_count";
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_phase_count} !~ /^\d+$/)
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_pdu_message_0002", variables => $variables});
			my $changed = $anvil->Alert->check_alert_sent({
				debug          => 3,
				record_locator => $bad_phase_count_key,
				set_by         => $THIS_FILE,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
			if ($changed)
			{
				# Register an alert.
				$anvil->Alert->register({alert_level => "warning", message => "scan_apc_pdu_message_0002", variables => $variables, set_by => $THIS_FILE});
			}
			$anvil->nice_exit({exit_code => 1});
		}
		else
		{
			# Clear the alert?
			my $changed = $anvil->Alert->check_alert_sent({
				debug          => 3,
				clear          => 1,
				record_locator => $bad_phase_count_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_pdu_message_0003", variables => $variables});
				$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_pdu_message_0003", variables => $variables, set_by => $THIS_FILE});
			}
		}
		# Now read the phase data
		foreach my $scan_apc_pdu_phase_number (1..$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_phase_count})
		{
			# Stick the phase onto the end of the OID.
			my $oid = $anvil->data->{oids}{scan_apc_pdu_phases}{scan_apc_pdu_phase_current_amperage}.$scan_apc_pdu_phase_number;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"scan_apc_pdu_phase_number" => $scan_apc_pdu_phase_number, 
				"oid"                       => $oid, 
			}});
			
			# Read this phase's amperage
			($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $pdu_ip, 
				oid       => $oid,
				version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_phases::${scan_apc_pdu_phase_number}::scan_apc_pdu_phase_current_amperage" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage}, 
				data_type                                                                                                                             => $data_type,
			}});
			
			# The amperage is in 1/10 amps, so divide by 10.
			if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage} =~ /^\d+$/)
			{
				$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage} /= 10;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_phases::${scan_apc_pdu_phase_number}::scan_apc_pdu_phase_current_amperage" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_phases}{$scan_apc_pdu_phase_number}{scan_apc_pdu_phase_current_amperage}, 
				}});
			}
		}
		
		# Read the outlet data, if the outlet count is sane.
		my $bad_outlet_count_key = "scan_apc_pdu::".$scan_apc_pdu_uuid."::bad_outlet_count";
		if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_outlet_count} !~ /^\d+$/)
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_pdu_message_0004", variables => $variables});
			my $changed = $anvil->Alert->check_alert_sent({
				debug          => 3,
				record_locator => $bad_outlet_count_key,
				set_by         => $THIS_FILE,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
			if ($changed)
			{
				# Register an alert.
				$anvil->Alert->register({alert_level => "warning", message => "scan_apc_pdu_message_0004", variables => $variables, set_by => $THIS_FILE});
			}
			$anvil->nice_exit({exit_code => 1});
		}
		else
		{
			# Clear the alert?
			my $changed = $anvil->Alert->check_alert_sent({
				debug          => 3,
				clear          => 1,
				record_locator => $bad_outlet_count_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_pdu_message_0005", variables => $variables});
				$anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_pdu_message_0005", variables => $variables, set_by => $THIS_FILE});
			}
		}
		# Now read the outlet data
		foreach my $scan_apc_pdu_outlet_number (1..$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu}{scan_apc_pdu_outlet_count})
		{
			# Stick the outlet onto the end of the OIDs.
			my $outlet_name_oid  = $anvil->data->{oids}{scan_apc_pdu_outlets}{scan_apc_pdu_outlet_name}.$scan_apc_pdu_outlet_number;
			my $outlet_phase_oid = $anvil->data->{oids}{scan_apc_pdu_outlets}{scan_apc_pdu_outlet_on_phase}.$scan_apc_pdu_outlet_number;
			my $outlet_state_oid = $anvil->data->{oids}{scan_apc_pdu_outlets}{scan_apc_pdu_outlet_state}.$scan_apc_pdu_outlet_number;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"outlet_name_oid"  => $outlet_name_oid, 
				"outlet_phase_oid" => $outlet_phase_oid, 
				"outlet_state_oid" => $outlet_state_oid, 
			}});
			
			### Read the OID
			# outlet name
			($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_name}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $pdu_ip, 
				oid       => $outlet_name_oid,
				version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_name" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_name}, 
				data_type                                                                                                                    => $data_type,
			}});
			
			# Outlet number on phase
			($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_on_phase}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $pdu_ip, 
				oid       => $outlet_phase_oid,
				version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_on_phase" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_on_phase}, 
				data_type                                                                                                                        => $data_type,
			}});
			
			# State of the outlet
			($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state}, $data_type) = $anvil->Remote->read_snmp_oid({
				debug     => 3,
				target    => $pdu_ip, 
				oid       => $outlet_state_oid,
				version   => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{snmp_version},
				community => $anvil->data->{snmp}{community}{'read'}
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_state" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state}, 
				data_type                                                                                                                     => $data_type,
			}});
			
			# The state is; 1 = on, 2 = off, 4 = unknown
			if ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state} eq "1")
			{
				$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state} = "on";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_state" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state}, 
				}});
			}
			elsif ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state} eq "2")
			{
				$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state} = "off";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_state" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state}, 
				}});
			}
			elsif ($anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state} eq "3")
			{
				$anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state} = "unknown";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"pdu::scan_apc_pdu_uuid::${scan_apc_pdu_uuid}::scan_apc_pdu_outlets::${scan_apc_pdu_outlet_number}::scan_apc_pdu_outlet_state" => $anvil->data->{pdu}{scan_apc_pdu_uuid}{$scan_apc_pdu_uuid}{scan_apc_pdu_outlets}{$scan_apc_pdu_outlet_number}{scan_apc_pdu_outlet_state}, 
				}});
			}
		}
	}

	return(0);
}

# This looks for APC PDUs.
sub find_pdus
{
	my ($anvil) = @_;
	
	# Search in 'fences' for agents starting with 'fence_apc_'. These aren't bound to hosts (or even 
	# Anvil! systems), so not all may be available.
	my $query = "
SELECT 
    fence_uuid, 
    fence_name, 
    fence_arguments 
FROM 
    fences 
WHERE 
    fence_agent LIKE 'fence_apc_%' 
AND 
    fence_arguments != 'DELETED' 
ORDER BY 
    fence_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 $fence_uuid      = $row->[0];
		my $fence_name      = $row->[1];
		my $fence_arguments = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
			fence_uuid      => $fence_uuid, 
			fence_name      => $fence_name, 
			fence_arguments => $fence_arguments, 
		}});
		
		if ($fence_arguments =~ /ip=\"(.*?)\"/)
		{
			my $ip_address = $1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address => $ip_address }});
			
			$anvil->data->{fences}{fence_uuid}{$fence_uuid}{name}       = $fence_name;
			$anvil->data->{fences}{fence_uuid}{$fence_uuid}{ip_address} = $ip_address;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"fences::fence_uuid::${fence_uuid}::name"       => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{name},
				"fences::fence_uuid::${fence_uuid}::ip_address" => $anvil->data->{fences}{fence_uuid}{$fence_uuid}{ip_address},
			}});
			
			# If there are two or more entries in scan_apc_pdu for this fence UUID, remove the extras.
			my $query = "
SELECT 
    scan_apc_pdu_uuid, 
    scan_apc_pdu_model_number 
FROM 
    scan_apc_pdus 
WHERE 
    scan_apc_pdu_fence_uuid = ".$anvil->Database->quote($fence_uuid)." 
;";
			$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, 
			}});
			if ($count > 1)
			{
				# Duplicate! Is one of them marked as DELETED?
				foreach my $row (@{$results})
				{
					# Is this one deleted?
					my $scan_apc_pdu_uuid         = $row->[0];
					my $scan_apc_pdu_model_number = $row->[1];
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						scan_apc_pdu_uuid         => $scan_apc_pdu_uuid, 
						scan_apc_pdu_model_number => $scan_apc_pdu_model_number, 
					}});
					
					if ($scan_apc_pdu_model_number eq "DELETED")
					{
						# Take this one out.
						my $variables = {
							name => $fence_name,
							uuid => $scan_apc_pdu_uuid,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_log_0002", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "notice", 
							message       => "scan_apc_pdu_log_0002", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
						
						delete_pdu($anvil, $scan_apc_pdu_uuid);
						$count--;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
					}
					last if $count == 1;
				}
				
				# If count is still > 1, we need to arbitrarily delete an interface.
				if ($count > 1)
				{
					foreach my $row (@{$results})
					{
						# Is this one deleted?
						my $scan_apc_pdu_uuid = $row->[0];
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_apc_pdu_uuid => $scan_apc_pdu_uuid }});
						
						my $variables = {
							name => $fence_name,
							uuid => $scan_apc_pdu_uuid,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_log_0002", variables => $variables});
						$anvil->Alert->register({
							alert_level   => "notice", 
							message       => "scan_apc_pdu_log_0002", 
							variables     => $variables, 
							set_by        => $THIS_FILE, 
							sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++,
						});
						delete_pdu($anvil, $scan_apc_pdu_uuid);
						
						$count--;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
					}
					last if $count == 1;
				}
			}
		}
	}
	
	my $pdu_count = keys %{$anvil->data->{fences}{fence_uuid}};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { pdu_count => $pdu_count }});
	return($pdu_count);
}

sub delete_pdu
{
	my ($anvil, $scan_apc_pdu_uuid) = @_;
	
	my $queries = [
		"DELETE FROM scan_apc_pdu_variables WHERE scan_apc_pdu_variable_scan_apc_pdu_uuid = ".$anvil->Database->quote($scan_apc_pdu_uuid).";", 
		"DELETE FROM scan_apc_pdu_phases    WHERE scan_apc_pdu_phase_scan_apc_pdu_uuid    = ".$anvil->Database->quote($scan_apc_pdu_uuid).";", 
		"DELETE FROM scan_apc_pdu_outlets   WHERE scan_apc_pdu_outlet_scan_apc_pdu_uuid   = ".$anvil->Database->quote($scan_apc_pdu_uuid).";", 
		"DELETE FROM scan_apc_pdus          WHERE scan_apc_pdu_uuid                       = ".$anvil->Database->quote($scan_apc_pdu_uuid).";"
	];
	$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
	
	return(0);
}
