diff --git a/WinNUT_V2/WinNUT-Client_Common/UPS_Device.vb b/WinNUT_V2/WinNUT-Client_Common/UPS_Device.vb
index 0eb955e..3d17f24 100644
--- a/WinNUT_V2/WinNUT-Client_Common/UPS_Device.vb
+++ b/WinNUT_V2/WinNUT-Client_Common/UPS_Device.vb
@@ -11,6 +11,15 @@ Imports System.Globalization
Imports System.Windows.Forms
Public Class UPS_Device
+#Region "Statics/Defaults"
+ Private ReadOnly INVARIANT_CULTURE = CultureInfo.InvariantCulture
+ Private Const CosPhi As Double = 0.6
+
+ ' How many milliseconds to wait before the Reconnect routine tries again.
+ Private Const DEFAULT_RECONNECT_WAIT_MS As Double = 5000
+ Private Const DEFAULT_UPDATE_INTERVAL_MS As Double = 1000
+#End Region
+
#Region "Properties"
Public ReadOnly Property Name As String
@@ -35,6 +44,10 @@ Public Class UPS_Device
End Get
End Property
+ '''
+ ''' How often UPS data is updated, in milliseconds.
+ '''
+ '''
Public Property PollingInterval As Integer
Get
Return Update_Data.Interval
@@ -102,16 +115,11 @@ Public Class UPS_Device
#End Region
- Private Const CosPhi As Double = 0.6
- ' How many milliseconds to wait before the Reconnect routine tries again.
- Private Const DEFAULT_RECONNECT_WAIT_MS As Double = 5000
-
Private WithEvents Update_Data As New Timer
Private WithEvents Reconnect_Nut As New Timer
Private WithEvents Nut_Socket As Nut_Socket
Private Freq_Fallback As Double
- Private ciClone As CultureInfo
Public Nut_Config As Nut_Parameter
Public Retry As Integer = 0
Public MaxRetry As Integer = 30
@@ -121,13 +129,18 @@ Public Class UPS_Device
Me.LogFile = LogFile
Me.Nut_Config = Nut_Config
PollingInterval = pollInterval
- ciClone = CType(CultureInfo.InvariantCulture.Clone(), CultureInfo)
- ciClone.NumberFormat.NumberDecimalSeparator = "."
Nut_Socket = New Nut_Socket(Me.Nut_Config, LogFile)
With Reconnect_Nut
.Interval = DEFAULT_RECONNECT_WAIT_MS
.Enabled = False
+ AddHandler .Tick, AddressOf AttemptReconnect
+ End With
+
+ With Update_Data
+ .Interval = DEFAULT_UPDATE_INTERVAL_MS
+ .Enabled = False
+ AddHandler .Tick, AddressOf Retrieve_UPS_Datas
End With
End Sub
@@ -191,7 +204,7 @@ Public Class UPS_Device
End If
End Sub
- Private Sub Reconnect_Socket(sender As Object, e As EventArgs) Handles Reconnect_Nut.Tick
+ Private Sub AttemptReconnect(sender As Object, e As EventArgs)
Retry += 1
If Retry <= MaxRetry Then
RaiseEvent New_Retry()
@@ -216,13 +229,15 @@ Public Class UPS_Device
'''
'''
Private Function GetUPSProductInfo() As UPSData
+ LogFile.LogTracing("Retrieving basic UPS product information...", LogLvl.LOG_NOTICE, Me)
+
Dim freshData = New UPSData(
Trim(GetUPSVar("ups.mfr", "Unknown")),
Trim(GetUPSVar("ups.model", "Unknown")),
Trim(GetUPSVar("ups.serial", "Unknown")),
Trim(GetUPSVar("ups.firmware", "Unknown")))
- ' Determine available power & load data
+ LogFile.LogTracing("Determining best method to calculate power usage...", LogLvl.LOG_NOTICE, Me)
Try
GetUPSVar("ups.realpower")
_PowerCalculationMethod = PowerMethod.RealPower
@@ -248,30 +263,60 @@ Public Class UPS_Device
End Try
' Other constant values for UPS calibration.
- freshData.UPS_Value.Batt_Capacity = Double.Parse(GetUPSVar("battery.capacity", 7), ciClone)
- Freq_Fallback = Double.Parse(GetUPSVar("output.frequency.nominal", (50 + CInt(Arr_Reg_Key.Item("FrequencySupply")) * 10)), ciClone)
+ freshData.UPS_Value.Batt_Capacity = Double.Parse(GetUPSVar("battery.capacity", 7), INVARIANT_CULTURE)
+ Freq_Fallback = Double.Parse(GetUPSVar("output.frequency.nominal", (50 + CInt(Arr_Reg_Key.Item("FrequencySupply")) * 10)), INVARIANT_CULTURE)
+ LogFile.LogTracing("Completed retrieval of basic UPS product information.", LogLvl.LOG_NOTICE, Me)
Return freshData
End Function
Private oldStatusBitmask As Integer
-
- Public Sub Retrieve_UPS_Datas() Handles Update_Data.Tick ' As UPSData
+ Private Sub Retrieve_UPS_Datas(sender As Object, e As EventArgs)
LogFile.LogTracing("Enter Retrieve_UPS_Datas", LogLvl.LOG_DEBUG, Me)
+
Try
Dim UPS_rt_Status As String
If IsConnected Then
With UPS_Datas.UPS_Value
- .Batt_Charge = Double.Parse(GetUPSVar("battery.charge", 255), ciClone)
- .Batt_Voltage = Double.Parse(GetUPSVar("battery.voltage", 12), ciClone)
- .Batt_Runtime = Double.Parse(GetUPSVar("battery.runtime", 86400), ciClone)
- .Power_Frequency = Double.Parse(GetUPSVar("input.frequency", Double.Parse(GetUPSVar("output.frequency", Freq_Fallback), ciClone)), ciClone)
- .Input_Voltage = Double.Parse(GetUPSVar("input.voltage", 220), ciClone)
- .Output_Voltage = Double.Parse(GetUPSVar("output.voltage", .Input_Voltage), ciClone)
- .Load = Double.Parse(GetUPSVar("ups.load", 0), ciClone)
- .Output_Power = If(_PowerCalculationMethod <> PowerMethod.Unavailable, GetPowerUsage(), 0)
+ .Batt_Charge = Double.Parse(GetUPSVar("battery.charge", 255), INVARIANT_CULTURE)
+ .Batt_Voltage = Double.Parse(GetUPSVar("battery.voltage", 12), INVARIANT_CULTURE)
+ .Batt_Runtime = Double.Parse(GetUPSVar("battery.runtime", 86400), INVARIANT_CULTURE)
+ .Power_Frequency = Double.Parse(GetUPSVar("input.frequency", Double.Parse(GetUPSVar("output.frequency", Freq_Fallback), INVARIANT_CULTURE)), INVARIANT_CULTURE)
+ .Input_Voltage = Double.Parse(GetUPSVar("input.voltage", 220), INVARIANT_CULTURE)
+ .Output_Voltage = Double.Parse(GetUPSVar("output.voltage", .Input_Voltage), INVARIANT_CULTURE)
+ .Load = Double.Parse(GetUPSVar("ups.load", 0), INVARIANT_CULTURE)
+
+ ' Retrieve and/or calculate output power if possible.
+ If _PowerCalculationMethod <> PowerMethod.Unavailable Then
+ Dim parsedValue As Double
+
+ Try
+ If _PowerCalculationMethod = PowerMethod.RealPower Then
+ parsedValue = Double.Parse(GetUPSVar("ups.realpower"), INVARIANT_CULTURE)
+
+ ElseIf _PowerCalculationMethod = PowerMethod.NominalPowerCalc Then
+ parsedValue = Double.Parse(GetUPSVar("ups.realpower.nominal"), INVARIANT_CULTURE)
+ parsedValue *= UPS_Datas.UPS_Value.Load / 100.0
+
+ ElseIf _PowerCalculationMethod = PowerMethod.VoltAmpCalc Then
+ Dim nomCurrent = Double.Parse(GetUPSVar("input.current.nominal"), INVARIANT_CULTURE)
+ Dim nomVoltage = Double.Parse(GetUPSVar("input.voltage.nominal"), INVARIANT_CULTURE)
+
+ parsedValue = (nomCurrent * nomVoltage * 0.8) * (UPS_Datas.UPS_Value.Load / 100.0)
+ Else
+ Throw New InvalidOperationException("Insufficient variables to calculate power.")
+ End If
+ Catch ex As FormatException
+ LogFile.LogTracing("Unexpected format trying to parse value from UPS. Exception:", LogLvl.LOG_ERROR, Me)
+ LogFile.LogTracing(ex.ToString(), LogLvl.LOG_ERROR, Me)
+ LogFile.LogTracing("parsedValue: " & parsedValue, LogLvl.LOG_ERROR, Me)
+ End Try
+ .Output_Power = parsedValue
+ End If
+
+ ' Handle cases of UPSs that are unable to report battery runtime or load correctly while on battery.
Dim PowerDivider As Double = 0.5
Select Case .Load
Case 76 To 100
@@ -279,14 +324,13 @@ Public Class UPS_Device
Case 51 To 75
PowerDivider = 0.3
End Select
+
If .Batt_Charge = 255 Then
Dim nBatt = Math.Floor(.Batt_Voltage / 12)
.Batt_Charge = Math.Floor((.Batt_Voltage - (11.6 * nBatt)) / (0.02 * nBatt))
End If
+
If .Batt_Runtime >= 86400 Then
- 'If Load is 0, the calculation results in infinity. This causes an exception in DataUpdated(), causing Me.Disconnect to run in the exception handler below.
- 'Thus a connection is established, but is forcefully disconneced almost immediately. This cycle repeats on each connect until load is <> 0
- '(Example: I have a 0% load if only Pi, Microtik Router, Wifi AP and switches are running)
.Load = If(.Load <> 0, .Load, 0.1)
Dim BattInstantCurrent = (.Output_Voltage * .Load) / (.Batt_Voltage * 100)
.Batt_Runtime = Math.Floor(.Batt_Capacity * 0.6 * .Batt_Charge * (1 - PowerDivider) * 3600 / (BattInstantCurrent * 100))
@@ -299,7 +343,7 @@ Public Class UPS_Device
.UPS_Status = [Enum].Parse(GetType(UPS_States), UPS_rt_Status)
Catch ex As ArgumentException
LogFile.LogTracing("Likely encountered an unknown/invalid UPS status. Using previous status." &
- vbNewLine & ex.Message, LogLvl.LOG_ERROR, Me)
+ vbNewLine & ex.Message, LogLvl.LOG_ERROR, Me)
End Try
' Get the difference between the old and new statuses, and filter only for active ones.
@@ -324,27 +368,6 @@ Public Class UPS_Device
End Try
End Sub
- '''
- ''' Attempts to get the power usage of this UPS.
- '''
- '''
- '''
- Private Function GetPowerUsage() As Double
- If _PowerCalculationMethod = PowerMethod.RealPower Then
- Return Integer.Parse(GetUPSVar("ups.realpower"))
- ElseIf _PowerCalculationMethod = PowerMethod.NominalPowerCalc Then
- Return Integer.Parse(GetUPSVar("ups.realpower.nominal")) *
- (UPS_Datas.UPS_Value.Load / 100.0)
- ElseIf _PowerCalculationMethod = PowerMethod.VoltAmpCalc Then
- Dim nomCurrent = Double.Parse(GetUPSVar("input.current.nominal"))
- Dim nomVoltage = Double.Parse(GetUPSVar("input.voltage.nominal"))
-
- Return (nomCurrent * nomVoltage * 0.8) * (UPS_Datas.UPS_Value.Load / 100.0)
- Else
- Throw New InvalidOperationException("Insufficient variables to calculate power.")
- End If
- End Function
-
Private Const MAX_VAR_RETRIES = 3
Public Function GetUPSVar(varName As String, Optional Fallback_value As Object = Nothing, Optional recursing As Boolean = False) As String
If Not IsConnected Then