Skip to content

Commit c9aec9e

Browse files
committed
New power calculation methods
Replacing old power calculation methods with new system. On connection, WinNUT determines what power/load data variables are available and sets an enum variable accordingly. If no such method is available, a warning is logged to the output, and future attempts to get the power value will return with 0. On every update, the appropriate method is selected from the enum variable and the calculation is returned. The hope is that this covers the majority of UPS devices. - Also cleaned up or rearranged code in the UPS_Device class.
1 parent 5faf752 commit c9aec9e

File tree

2 files changed

+63
-36
lines changed

2 files changed

+63
-36
lines changed

WinNUT_V2/WinNUT-Client_Common/Common_Enums.vb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,10 @@ Public Enum UPS_States
116116
TRIM = 1 << 11
117117
BOOST = 1 << 12
118118
End Enum
119+
120+
Public Enum PowerMethod
121+
Unavailable ' No methods are available to calculate power.
122+
RealPower ' The ups.realpower variable is available for direct reading.
123+
NominalPowerCalc ' Power can be calculated by taking the load percentage of the nominal power variable.
124+
VoltAmpCalc ' Power will have be calculated as a function of volts and amps.
125+
End Enum

WinNUT_V2/WinNUT-Client_Common/UPS_Device.vb

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ Public Class UPS_Device
6464
End Set
6565
End Property
6666

67-
Private _MaxLoad As Integer
67+
Private _PowerCalculationMethod As PowerMethod
6868

69-
Public ReadOnly Property MaxLoad As Integer
69+
Public ReadOnly Property PowerCalculationMethod As PowerMethod
7070
Get
71-
Return _MaxLoad
71+
Return _PowerCalculationMethod
7272
End Get
7373
End Property
7474

@@ -107,25 +107,14 @@ Public Class UPS_Device
107107
Private Const DEFAULT_RECONNECT_WAIT_MS As Double = 5000
108108

109109
Private WithEvents Update_Data As New Timer
110-
'Private Nut_Conn As Nut_Comm
111-
' Private LogFile As Logger
110+
Private WithEvents Reconnect_Nut As New Timer
111+
Private WithEvents Nut_Socket As Nut_Socket
112+
112113
Private Freq_Fallback As Double
113114
Private ciClone As CultureInfo
114-
115115
Public Nut_Config As Nut_Parameter
116-
117-
' Public UPSData As New UPSData
118-
119-
120-
Private WithEvents Nut_Socket As Nut_Socket
121-
122116
Public Retry As Integer = 0
123117
Public MaxRetry As Integer = 30
124-
Private WithEvents Reconnect_Nut As New System.Windows.Forms.Timer
125-
126-
127-
128-
129118
Private LogFile As Logger
130119

131120
Public Sub New(ByRef Nut_Config As Nut_Parameter, ByRef LogFile As Logger, pollInterval As Integer)
@@ -233,24 +222,44 @@ Public Class UPS_Device
233222
Trim(GetUPSVar("ups.serial", "Unknown")),
234223
Trim(GetUPSVar("ups.firmware", "Unknown")))
235224

225+
' Determine available power & load data
226+
Try
227+
GetUPSVar("ups.realpower")
228+
_PowerCalculationMethod = PowerMethod.RealPower
229+
LogFile.LogTracing("Using RealPower method to calculate power usage.", LogLvl.LOG_NOTICE, Me)
230+
Catch
231+
Try
232+
GetUPSVar("ups.realpower.nominal")
233+
GetUPSVar("ups.load")
234+
_PowerCalculationMethod = PowerMethod.NominalPowerCalc
235+
LogFile.LogTracing("Using NominalPowerCalc method to calculate power usage.", LogLvl.LOG_NOTICE, Me)
236+
Catch
237+
Try
238+
GetUPSVar("input.current.nominal")
239+
GetUPSVar("input.voltage.nominal")
240+
GetUPSVar("ups.load")
241+
_PowerCalculationMethod = PowerMethod.VoltAmpCalc
242+
LogFile.LogTracing("Using VoltAmpCalc method to calculate power usage.", LogLvl.LOG_NOTICE, Me)
243+
Catch
244+
_PowerCalculationMethod = PowerMethod.Unavailable
245+
LogFile.LogTracing("Unable to find a suitable method to calculate power usage.", LogLvl.LOG_WARNING, Me)
246+
End Try
247+
End Try
248+
End Try
249+
236250
' Other constant values for UPS calibration.
237251
freshData.UPS_Value.Batt_Capacity = Double.Parse(GetUPSVar("battery.capacity", 7), ciClone)
238252
Freq_Fallback = Double.Parse(GetUPSVar("output.frequency.nominal", (50 + CInt(Arr_Reg_Key.Item("FrequencySupply")) * 10)), ciClone)
239253

240254
Return freshData
241255
End Function
242256

243-
Private Function FindMaxLoad() As Integer
244-
245-
End Function
246-
247257
Private oldStatusBitmask As Integer
248258

249259
Public Sub Retrieve_UPS_Datas() Handles Update_Data.Tick ' As UPSData
250260
LogFile.LogTracing("Enter Retrieve_UPS_Datas", LogLvl.LOG_DEBUG, Me)
251261
Try
252262
Dim UPS_rt_Status As String
253-
Dim InputA As Double
254263

255264
If IsConnected Then
256265
With UPS_Datas.UPS_Value
@@ -260,20 +269,9 @@ Public Class UPS_Device
260269
.Power_Frequency = Double.Parse(GetUPSVar("input.frequency", Double.Parse(GetUPSVar("output.frequency", Freq_Fallback), ciClone)), ciClone)
261270
.Input_Voltage = Double.Parse(GetUPSVar("input.voltage", 220), ciClone)
262271
.Output_Voltage = Double.Parse(GetUPSVar("output.voltage", .Input_Voltage), ciClone)
263-
.Load = Double.Parse(GetUPSVar("ups.load", 100), ciClone)
264-
UPS_rt_Status = GetUPSVar("ups.status", UPS_States.None)
265-
.Output_Power = Double.Parse((GetUPSVar("ups.realpower.nominal", 0)), ciClone)
266-
If .Output_Power = 0 Then
267-
.Output_Power = Double.Parse((GetUPSVar("ups.power.nominal", 0)), ciClone)
268-
If .Output_Power = 0 Then
269-
InputA = Double.Parse(GetUPSVar("ups.current.nominal", 1), ciClone)
270-
.Output_Power = Math.Round(.Input_Voltage * 0.95 * InputA * CosPhi)
271-
Else
272-
.Output_Power = Math.Round(.Output_Power * (.Load / 100) * CosPhi)
273-
End If
274-
Else
275-
.Output_Power = Math.Round(.Output_Power * (.Load / 100))
276-
End If
272+
.Load = Double.Parse(GetUPSVar("ups.load", 0), ciClone)
273+
.Output_Power = If(_PowerCalculationMethod <> PowerMethod.Unavailable, GetPowerUsage(), 0)
274+
277275
Dim PowerDivider As Double = 0.5
278276
Select Case .Load
279277
Case 76 To 100
@@ -294,6 +292,7 @@ Public Class UPS_Device
294292
.Batt_Runtime = Math.Floor(.Batt_Capacity * 0.6 * .Batt_Charge * (1 - PowerDivider) * 3600 / (BattInstantCurrent * 100))
295293
End If
296294

295+
UPS_rt_Status = GetUPSVar("ups.status", UPS_States.None)
297296
' Prepare the status string for Enum parsing by replacing spaces with commas.
298297
UPS_rt_Status = UPS_rt_Status.Replace(" ", ",")
299298
Try
@@ -325,6 +324,27 @@ Public Class UPS_Device
325324
End Try
326325
End Sub
327326

327+
''' <summary>
328+
''' Attempts to get the power usage of this UPS.
329+
''' </summary>
330+
''' <returns></returns>
331+
''' <throws><see cref="NutException"/></throws>
332+
Private Function GetPowerUsage() As Double
333+
If _PowerCalculationMethod = PowerMethod.RealPower Then
334+
Return Integer.Parse(GetUPSVar("ups.realpower"))
335+
ElseIf _PowerCalculationMethod = PowerMethod.NominalPowerCalc Then
336+
Return Integer.Parse(GetUPSVar("ups.realpower.nominal")) *
337+
(UPS_Datas.UPS_Value.Load / 100.0)
338+
ElseIf _PowerCalculationMethod = PowerMethod.VoltAmpCalc Then
339+
Dim nomCurrent = Double.Parse(GetUPSVar("input.current.nominal"))
340+
Dim nomVoltage = Double.Parse(GetUPSVar("input.voltage.nominal"))
341+
342+
Return (nomCurrent * nomVoltage * 0.8) * (UPS_Datas.UPS_Value.Load / 100.0)
343+
Else
344+
Throw New InvalidOperationException("Insufficient variables to calculate power.")
345+
End If
346+
End Function
347+
328348
Private Const MAX_VAR_RETRIES = 3
329349
Public Function GetUPSVar(varName As String, Optional Fallback_value As Object = Nothing, Optional recursing As Boolean = False) As String
330350
If Not IsConnected Then

0 commit comments

Comments
 (0)