It is currently March 29th, 2024, 7:09 am

Can't get Battery Status from UsageMonitor

Get help with creating, editing & fixing problems with skins
User avatar
CodeCode
Posts: 1363
Joined: September 7th, 2020, 2:24 pm
Location: QLD, Australia

Re: Can't get Battery Status from UsageMonitor

Post by CodeCode »

Heh.

Still have to try running off battery to see if thing snap into place then. I'll update just to fulfil the curious.
ƈǟռ'ȶ ʄɨӼ ɨȶ ɨʄ ɨȶ ǟɨռ'ȶ ɮʀօӄɛ - ʊռʟɛֆֆ ɨȶ ɨֆ ɨռ ƈօɖɛ.
User avatar
SilverAzide
Rainmeter Sage
Posts: 2588
Joined: March 23rd, 2015, 5:26 pm

Re: Can't get Battery Status from UsageMonitor

Post by SilverAzide »

dvo wrote: December 3rd, 2020, 2:28 pm could this help you?

i found this to ..
That's actually the Win32_Battery class. You can query it using PowerShell or via the command line. See my post above for the syntax. This class is missing the "good stuff", like charge/discharge rates, current charge level, voltage (the amount being supplied, not the design voltage), etc. This is the stuff that is in the undocumented WMI BatteryStatus class, which is apparently missing on his machine. :confused:
Gadgets Wiki GitHub More Gadgets...
User avatar
CodeCode
Posts: 1363
Joined: September 7th, 2020, 2:24 pm
Location: QLD, Australia

Re: Can't get Battery Status from UsageMonitor

Post by CodeCode »

dvo wrote: December 3rd, 2020, 3:25 pm
this one should see all of them on a network... not tested ..

Code: Select all

# Watch-All-UPS.ps1 
# powershell v2 CP3
$WAUPS_Version = '1.0'
# Date: Feb 2016
# Latest version: Feb 2016
# Author:  Ryan Risley (SEE NOTE BELOW)

# ---------------------------NOTE--------------------------- 
# THIS SCRIPT IS BASED ENTIRELY OFF THE ORIGINAL WORK OF 
# PAUL WETERINGS AND IS A MODIFIED VERSION OF THE FOLLOWING:
# ----------------------------------------------------------
# Watch-UPS.ps1 
# powershell v2 CP3
# Version: 1.5
# Date jan 2011
# Latest version: mar 2013
# Author:  Paul Weterings
# www.servercare.nl
# ----------------------------------------------------------


# Modifications from Watch-UPS 1.5:
<#
- Updated code to recognize multiple UPS/Battery units
- Created procedures to start virtual machines when power is restored
  - This required an update to the CSV, as outlined in Description
- Changed and updated notifications and their call method
- Allow global on/off of event logging and email
- Created a self-updating status window
- Updated description to reflect changes
- Various minor tweaks that I didn't think to record
- Added troubleshooting method(s)
#>

# Description:
<#
This script monitors the UPS's or Batteries connected to the system in the 
$computer variable. As soon as it detects that the system is going offline
(hence starts using the UPS/Battery it will compare the percentage
power left to a a list of system names provided in the 'Watch-All-UPS.csv' file.

Each system in the .csv list has an associated percentage listed; if the 
battery level has dropped below thepercentage listed for that system, the 
script will send a shutdown request to that system.

The idea is to shut down the least critical systems first, providing them 
a 'clean shutdown' rather then an abrupt power off when the UPS is empty. 
Additionally; shutting down the least critical systems first will allow 
other, possibly more critical systems (such as a NAS or SQL server for 
example) to remain on the UPS longer, since it now has to cater to less 
systems.

example contents of the .csv file:

systemname, percentage, status, type,mac
game1, 80, 0, v
scom1, 80, 0, v
mail1, 50, 0, v
sql1, 10, 0, v
nas1, 5, 0, v
vmhost01,3,0,p

This means the game and scom servers will be shut down first, when the UPS 
is at 80% power left. Since the UPS now has 2 less servers to support, there's
more power for the other servers to remain running during a power failure.
At 50% we stop the mail server, since typically an Exchange server needs some 
time to shut down, we sent it the shutdown command fairly soon. We wait until 
the very last drops of power left (resp 10% and 5%) to sent the sql and nas 
server the shutdown command.

-systemname = needs to be a (network reachable) name of a system on the network.

-percentage = the percentage of power left in the UPS at which we need to send 
a shutdown command to this system.

-status = 0 means the system should be shut down, 
1 means ' no action' (for test situations for example) BE CAREFUL; after the power
goes off, and then on again the script will 're-arm' and status will be 0
for all servers. This means they will shut down at a second 'power failure'.

-type = p or v
p is physical (will use Wake on Lan to attempt to start)
v is virtual (will use $VMHosts and start-vm to start)

actions of this script are logged on screen and to the application eventlog of 
the system running it as well as mailed.
#>

# Troubleshooting
<#
Batteries not showing up
------------------------
If you installed battery monitoring software such as APC Agent, uninstall (and delete)
the drivers for the batteries through device manager.

Privilege not held error
------------------------
Uncomment the line down low (delete the #) for # $shutsys.psbase.Scope.Options.EnablePrivileges = $true  (CTRL+F is your friend)

Unable to start VMs
-------------------
You need to be running watch-all-ups on a server that has hyper-v or SCVMM module installed (and therefore get-vm and start-vm commandlets)
#>

###--------------------------------------------------------###
###     CUSTOMIZE THESE VARIABLES FOR YOUR ENVIRONMENT     ###
###--------------------------------------------------------###


# The computer system that we will be measuring; the UPS is connected here.
# CHANGE THIS TO YOUR SYSTEM NAME THAT HAS THE UPS CONNECTED or leave it '.' which is the local system
$computer = "." 

# Set notification methods you want.  We always write to the screen.  Logging requires PS to be run as admin or equivalent.
$bool_email = $true
$bool_log = $true
 
# We will be sending a mail at each shutdown
# Change this to whatever you want
$emailFrom = "Watch-All-UPS@fortheman.com"
# Make this your E-Mail address
$emailTo = "systemalert@fortheman.com"
$subject = "Watch-All-UPS " + $WAUPS_Version + " Notification"
# Make this your SMTP mail server IP or hostname
$smtpServer = "10.0.0.10"
$smtp = new-object Net.Mail.SmtpClient($smtpServer)

# If you want to turn on your VMs after power is restored, you'll need to add all your hosts here
$VMhosts = 'VMHost01','VMHost02','VMHost03','SCHost01'


###--------------------------------------------------------###
###     END VARIABLE CUSTOMIZATION - BEGIN MAIN SCRIPT     ###
###--------------------------------------------------------###

#-----[Other Static Declarations]-----

$namespace = "root\CIMV2" 
$batstat= @{"1"="battery is discharging";"2"="On AC";"3"="Fully Charged";"4"=`
"Low";"5"="Critical";"6"="Charging";"7"="Charging and High";"8"="Charging and`
 Low";"9"="Charging and Critical";"10"="Undefined";"11"="Partially Charged";}
 
#-----[Functions]-----
 
# Define our notify function.  Reduces repetitve clutter
# Variables are as follows:
# $report    :  The information text we're notifying
# $ID        :  Used only for eventlog, so can be anything if not writing to eventlog
# $logtype   :  Determines the log level (Information, Warning, Error)
# $do_log    :  If $true, writes the $report to eventlog
# $do_screen :  If $true, writes the $report the screen
# $do_email  :  If $true, sends $report via email
# NOTE:  The $do_**** will not override the $bool_**** settings
function f_notify ($report, $ID, $logtype, $do_log, $do_screen, $do_email) 
{
	$date = Get-Date
	$report = "$date : $report"
	# Write event log if desired
	if (($bool_log) -and ($do_log))
	{
		write-eventlog -logname Application -source Watch-All-UPS -eventID $ID -entrytype $logtype -message $report -category 1	
	}
	# Write screen
	if ($do_screen)
	{
		[string[]] $tempLogArray = @()
		$tempLogArray = $script:LogArray
		if ($templogarray.count -gt 1)
		{
			[array]::Reverse($tempLogArray)
		}
		$tempLogArray += $report
		if ($tempLogArray.Count -gt $LogRows)
		{
			$tempLogArray = $tempLogArray[1..($tempLogArray.Length-1)]
		}
		if ($templogarray.count -gt 1)
		{
			[array]::Reverse($tempLogArray)
		}
		$host.UI.RawUI.CursorPosition = $LogOrigPos
		write-output $BlankerArray  
		$host.UI.RawUI.CursorPosition = $LogOrigPos
		write-output $tempLogArray
		$script:LogArray = $tempLogArray
	}
	# Send email if desired		
	if (($bool_email) -and ($do_email))
	{
		$smtp.Send($emailFrom, $emailTo, $subject, $report)
	}
}

function f_updatestats ($batinfo, $batcount)
{
	$blankstat = "                                            "
	$i=0
	foreach ($batunit in $batinfo)
	{
		$temppos = $origpos
		$temppos.y += $i*2
		$host.UI.RawUI.CursorPosition = $temppos
		# First clear the old status - yes, those are spaces
		write-host -NoNewLine $blankstat
		$host.UI.RawUI.CursorPosition = $temppos
		# Write new status
		write-host -NoNewLine $computername ' - ' $batstat.Get_Item([string]$batunit.BatteryStatus)
		
		$temppos.y += 1
		$host.UI.RawUI.CursorPosition = $temppos
		# first clear the old status
		write-host -NoNewLine $blankstat
		$host.UI.RawUI.CursorPosition = $temppos
		# write new status
		write-host -NoNewLine $batunit.EstimatedChargeRemaining '%'
		$uptimepos = $temppos
		$i++
	}
	# Output uptime
	$uptimepos.y += 1
	$host.UI.RawUI.CursorPosition = $uptimepos
	write-host -NoNewLine $blankstat
	$host.UI.RawUI.CursorPosition = $uptimepos
	$uptime = new-timespan -start $startdate -end $(Get-Date)
	write-host -NoNewLine $uptime.Days "days" $uptime.Hours "hours" $uptime.Minutes "minutes" $uptime.Seconds "seconds"
}

function f_PowerOn ($lines)
{
	foreach ($system in $lines)				
	{
		#-----[This section is for virtual machines only]-----
		#You will want to edit your VMHost names to suite your environment
		#Or... comment this out if you're not wanting to start your VMs.
		
		# You can just choose to start all your VMs at once by using the following instead of the if
		#get-vm -computer $VMhosts | start-vm

		if (($system.status -eq 1) -and ($system.type -eq "v"))
		{
			get-vm -computer $VMHosts | where {$_.name -eq $system.systemname} | start-vm 
			$report = "Turning host " + $system.systemname +" back on"
			f_notify $report 3005 "Information" $true $true $false										
		}
		#-----[/This section is for virtual machines only]-----				
		
		$system.status = 0 	  
	}
	$lines | export-csv "$path\Watch-All-UPS.csv"
}


#-----[/Functions]-----

	
if ($bool_log)
{
	# For eventlogging purposes, we simply want to know if our script was registered with the eventlog already
	Get-EventLog -source Watch-All-UPS -LogName Application -ErrorAction silentlycontinue | Out-Null
	if (-not$?)
	{
		# there's an error, so we must not be listed yet, let's see to it we exist 
		# for eventlogging (Requires admin privileges!)
		New-EventLog -source Watch-All-UPS -LogName Application -ErrorAction silentlycontinue | Out-Null
	}
}

clear-host
write-host '----[ STATUS ]-----------------------------------------------------'

# note that any error for Get-WMI object would not be a 'terminating error',
# since the script won't stop you can't use try/catch or trap to catch any 
# errors. I choose to be silent about the error and handle the result to see
# if an error occurred.
$batinfo = Get-WmiObject -class Win32_Battery -computername $computer -ErrorAction silentlycontinue -namespace $namespace
$batcount = 1
# check for multiple batteries
if ($batinfo.count -gt 1)
{
	$batcount = $batinfo.count
}
write-host 'Battery Count        : ' $batcount
# note the starting position of the cursor for future updates to display values
$origpos = $host.UI.RawUI.CursorPosition
# sliiiiide to the right (so you only update the values, not the labels)
$origpos.x += 24
# we want to check if we could reach a system, and if we did; did it return battery info?
# powershell is so great with stuff like this!
if ($? -and $batinfo)
{
	# use computer friendly name for this output instead of a period.
	$computername = $computer
	if ($computername = ".")
	{
		$computername = $env:computername
	}
	
	foreach ($batunit in $batinfo)
	{		
	    write-host 'Battery status on    : ' $computername ' - ' $batstat.Get_Item([string]$batunit.BatteryStatus)	
		write-host 'Percentage left      : ' $batunit.EstimatedChargeRemaining '%'		
	}
	
	$StartDate=(Get-Date)
	write-host 'Watch-All-UPS uptime : '
	
    # Read and interpret the configuration comma seperated values file
    # Note this is a hardcoded path, you could also use the 'Get-Location' cmdlet
    $path = "c:\scripts\"#Get-Location
    $lines = Import-Csv "$path\Watch-All-UPS.csv"
    
	
    # Report to screen what servers we are looking after
    write-host `n'Watch-All-UPS will manage:'
	$lines | format-wide -autosize	
	# And let's show in the eventlog we started (nice to know if you start this script as a task)	
	$report = 'Watch-All-UPS ' + $WAUPS_Version + ' started'
	f_notify $report 3001 "Information" $true $false $false	
    write-host '----[ LOG ]--------------------------------------------------------'	
}
else
{
    if ($error)
    {
        "Could not find any battery/UPS information on system: " + $computername
        throw $error[0].Exception
    }
}


#-----[Screen Output setup]-----

# Note the current cursor position.  This is always where the latest update should print.
$LogOrigPos = $host.UI.RawUI.CursorPosition
 
# Get the PowerShell Host window size.  Doesn't work in ISE
$PSHost = get-host | select UI
$PSHostRows = $PSHost.ui.rawui.windowsize.height
$PSHostCols = $PSHost.ui.rawui.windowsize.width

# Log Rows is how many rows are available to print the screen log to
$LogRows = $PSHostRows - $LogOrigPos.y -2

# calculate and create an empty string to fake a 'clear-host' on the log output only
$blankrow = ""
for($i=0; $i -le $PSHostCols-2; $i++)
{
$blankrow += " "
}

# Define arrays for writing the log to the screen and for clearing it
[string[]] $script:LogArray = @()
[string[]] $BlankerArray = @()

# Build the screen clear array
for($i=0; $i -le $LogRows; $i++)
    {
        $BlankerArray += $blankrow
    }
	
#-----[/Screen Output setup]-----


#-----[Initial Power On]-----
# Assuming Watch-All-UPS runs when a system boots, we may be booting because power has been restored.
# If so, we'll have some machines that we will need to start up.  Let's take care of them.
f_PowerOn $lines	
#-----[/Initial Power On]-----

$wewereonbattery = $false
$powerstatus = $true
$partialpowernotify = $false

# Never ending story, we keep looping. Don't worry, we're not using much resources. (hardly any)
while($true)
{     
    $batinfo = Get-WmiObject -class Win32_Battery -computername $computer -ErrorAction silentlycontinue -namespace $namespace	
	#check for multiple batteries.  If only one is present, $batinfo.count would be null, so we start with the assumption that there is one.
	$batcount = 1	
	if ($batinfo.count -gt 1)
	{
		$batcount = $batinfo.count
	}
	# update battery status for all batteries
	f_updatestats $batinfo $batcount
    if ($?) # No error?
    {    
		# This setup assumes that all servers in question  are plugged into all battery units.
		# Thusly, if one unit drops, we assume it is just an isolated incident but there is no need to shut down anything.
        # Only check if we need to take action (BatteryStatus = 2 is not on AC)  		
		$allGood = $true
        $batdown = 0
		foreach ($batunit in $batinfo)
		{			
			if ($batunit.BatteryStatus -ne 2)
			{
				$allGood = $false
				$batdown++
			}		
		}
		# partial failure of only one unit
		if (($batdown -lt $batcount) -and ($allGood -eq $false))
		{
			if ($partialpowernotify -eq $false)
			{
				f_notify "Partial power failure detected, at least one UPS unit is still on AC. No shutdowns initiated." 3004 "Warning" $true $true $true	
				$partialpowernotify = $true
			}
			$wewereonbattery = $true
		}		
		# full blown power loss
        elseif (($batdown -eq $batcount) -and ($allGood -eq $false))
        {
			$date = Get-Date
			if ($powerstatus)
			{
				f_notify "Total power loss detected.  All UPS units are on battery.  Shutdowns will commence as scheduled." 3003 "Warning" $true $true $true
				$powerstatus = $false
			}
			$wewereonbattery = $true
            # Iterate through all the systems we have found in the config file
            # and check their reboot-percentages against our UPS percentage
            foreach ($system in $lines)
            {
				# Average all the battery's remaining charges together.  This assumes all devices are plugged into all batteries.
				$battotal = 0
				foreach ($batunit in $batinfo)
				{
					$battotal += $batunit.EstimatedChargeRemaining
				}
				$batAvgChargeRemaining = [int]($battotal / $batcount)
                # Do we have a winner?
                if ($batAvgChargeRemaining -le $system.percentage -and $system.status -eq 0)
                {
					$report = "Attempting to send shutdown command to " + $system.systemname + " at " + $system.percentage +"% power left"
					f_notify $report 3002 "Information" $true $true $false
                    # This assumes the script is being run with credentials
                    # that allow shutting down the remote system. 
                    # Use a service account with the correct rights to run this if you start this script as a task. 
                    #
                    # If you really want credentials:
                    # (gwmi win32_operatingsystem -ComputerName MyServer 
                    # -cred (get-credential) 
                    # where (get-credential) can be replaced with credentials 
                    # (not a good idea to put credentials in a script!)
                    
                    # msdn.microsoft.com/en-us/library/aa394058(VS.85).aspx
                    $shutsys = gwmi win32_operatingsystem -ComputerName $system.systemname -ErrorAction silentlycontinue
					#$shutsys.psbase.Scope.Options.EnablePrivileges = $true 
                    if($?) # Did the WMI operation go OK?
                    { 
						$report = "shutting down " + $system.systemname + " at " + $system.percentage +"% power left."
						f_notify $report 3002 "Warning" $true $true $true
                        # WMI has found the system, so we should be able to send it a shutdown command. 
						# Prevent output to screen to avoid messing up our pretty log
                        $shutsys.Win32Shutdown(12) > $null
                        # remember that we have sent this system a shutdown
                        # command, so we only do it once for each powerloss,
                        # we store this status (1) with the system info.
                        $system.status =1

                    }
                    else
                    {
                        $report = $system.systemname + ": The system was unreachable.  No shut down command was sent."
						f_notify $report 3003 "Error" $true $true $true
                        # it wasn't there, so we ignore it from now on
                        $system.status =-1						
                    }  
					# update the CSV.  This will allow us to restart machines in case WE lose power too.
					$lines | export-csv "$path\Watch-All-UPS.csv"		
				}
            }
        }
        else
        {   # Since the UPS is appearantly on AC, all systems need to 
            # be "shutdownable".
            # we basically " re-arm" the status after a potental powerloss 
            # may have previously shut down systems but the script kept running
            # as power was restored.
			# We only do this after we initially lost power once...
			if ($wewereonbattery)
			{
				$date = Get-Date
				if (($powerstatus -eq $false) -or ($partialpowernotify -eq $true))
				{
					f_notify "AC power has been restored." 3003 "Information" $true $true $true
					$powerstatus = $true
				}
				f_PowerOn $lines				
				# if power has returned to normal, we need to reset the system so it will again alert if partial power loss is also detected
				$partialpowernotify = $false
				$wewereonbattery = $false
			}
        }
    }
    else
    {
        $date = Get-Date
        write-host "$date : No UPS system found - was it shut down?" 
    }    
    # Let's wait a second
    Start-Sleep -Seconds 1
}
found here https://community.spiceworks.com/scripts/show/3513-watch-all-ups
Sorry, but I have no clue how all that could help me get readings from an external UPS?
ƈǟռ'ȶ ʄɨӼ ɨȶ ɨʄ ɨȶ ǟɨռ'ȶ ɮʀօӄɛ - ʊռʟɛֆֆ ɨȶ ɨֆ ɨռ ƈօɖɛ.
User avatar
CodeCode
Posts: 1363
Joined: September 7th, 2020, 2:24 pm
Location: QLD, Australia

Re: Can't get Battery Status from UsageMonitor

Post by CodeCode »

dvo wrote: December 5th, 2020, 9:31 pm one is ups on usb and one is on a network.... :)
Ok, but how can that info be used to run through rainmeter?

My battery is for a pc but has a usb link so the pc can 'see' it'

Basic info is cool, but that detailed voltage and lifetime info would be great to have a skin for.

thanks.
ƈǟռ'ȶ ʄɨӼ ɨȶ ɨʄ ɨȶ ǟɨռ'ȶ ɮʀօӄɛ - ʊռʟɛֆֆ ɨȶ ɨֆ ɨռ ƈօɖɛ.
User avatar
CodeCode
Posts: 1363
Joined: September 7th, 2020, 2:24 pm
Location: QLD, Australia

Re: Can't get Battery Status from UsageMonitor

Post by CodeCode »

So that script could be used to determine what I am using?

The brand is EATON. It says it is a 5E in 'devices and Printers', and it is a HID UPS Battery Device in Properties of the 5E.
ƈǟռ'ȶ ʄɨӼ ɨȶ ɨʄ ɨȶ ǟɨռ'ȶ ɮʀօӄɛ - ʊռʟɛֆֆ ɨȶ ɨֆ ɨռ ƈօɖɛ.