Skip to content

Commit a068ddb

Browse files
committed
Power variable calc updates, new method for Huawei
- Added output current as new `UPS_Value` - Renamed a few `PowerMethod` enums to be more descriptive of what they do - Trying a new well-known variable initialization method that utilizes nullable values. Variable is left null if there's a problem retrieving it from the NUT server, then it will not be updated in the future. Only applying this to `output.current` since its use is limited to power calculation only. Applying this to other variables will likely require greater structural changes throughout WinNUT. - Added power calculation method involving output voltage and current, doable in a Huawei UPS (see #150) - GetUPSVar no longer prints a line assuming that the raised exception will go unhandled if a fallback value was not provided.
1 parent ccf076d commit a068ddb

File tree

3 files changed

+70
-28
lines changed

3 files changed

+70
-28
lines changed

WinNUT_V2/WinNUT-Client_Common/Common_Classes.vb

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Public Class UPS_Values
1616
Public Batt_Runtime As Double = Nothing
1717
Public Input_Voltage As Double = Nothing
1818
Public Output_Voltage As Double = Nothing
19+
Public Output_Current As Single?
1920
Public Power_Frequency As Double = Nothing
2021
Public Load As Double = Nothing
2122
Public Output_Power As Double = Nothing

WinNUT_V2/WinNUT-Client_Common/Common_Enums.vb

+6-2
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,13 @@ Public Enum UPS_States
118118
ALARM = 1 << 13
119119
End Enum
120120

121+
''' <summary>
122+
''' Ref. https://github.com/nutdotnet/WinNUT-Client/pull/112
123+
''' </summary>
121124
Public Enum PowerMethod
122125
Unavailable ' No methods are available to calculate power.
123126
RealPower ' The ups.realpower variable is available for direct reading.
124-
NominalPowerCalc ' Power can be calculated by taking the load percentage of the nominal power variable.
125-
VoltAmpCalc ' Power will have be calculated as a function of volts and amps.
127+
RPNomLoadPct ' Power is calcualted as the load percentage of nominal realpower.
128+
InputNomVALoadPct ' Power is given as the nominal power calculated from nominal input volts/amps (and PF), multiplied by the percent load.
129+
OutputVACalc ' Power is calculated with output voltage and current (seen on Huawei, issue #150)
126130
End Enum

WinNUT_V2/WinNUT-Client_Common/UPS_Device.vb

+63-26
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Imports System.Windows.Forms
1313
Public Class UPS_Device
1414
#Region "Statics/Defaults"
1515
Private ReadOnly INVARIANT_CULTURE = CultureInfo.InvariantCulture
16-
Private Const CosPhi As Double = 0.6
16+
Private Const POWER_FACTOR = 0.8
1717

1818
' How many milliseconds to wait before the Reconnect routine tries again.
1919
Private Const DEFAULT_RECONNECT_WAIT_MS As Double = 5000
@@ -238,27 +238,57 @@ Public Class UPS_Device
238238
Trim(GetUPSVar("ups.serial", "Unknown")),
239239
Trim(GetUPSVar("ups.firmware", "Unknown")))
240240

241+
With freshData.UPS_Value
242+
LogFile.LogTracing("Initializing other well-known UPS variables...", LogLvl.LOG_DEBUG, Me)
243+
Try
244+
Dim value = Single.Parse(GetUPSVar("output.current"), INVARIANT_CULTURE)
245+
.Output_Current = value
246+
LogFile.LogTracing("output.current: " & value, LogLvl.LOG_DEBUG, Me)
247+
Catch ex As Exception
248+
If ex.GetType() <> GetType(NutException) Then
249+
LogFile.LogException(ex, Me)
250+
End If
251+
End Try
252+
Try
253+
Dim value = Single.Parse(GetUPSVar("output.voltage"), INVARIANT_CULTURE)
254+
.Output_Voltage = value
255+
LogFile.LogTracing("output.voltage: " & value, LogLvl.LOG_DEBUG, Me)
256+
Catch ex As Exception
257+
If ex.GetType() <> GetType(NutException) Then
258+
LogFile.LogException(ex, Me)
259+
End If
260+
End Try
261+
End With
262+
263+
' Determine optimal method for measuring power output from the UPS.
241264
LogFile.LogTracing("Determining best method to calculate power usage...", LogLvl.LOG_NOTICE, Me)
265+
' Start with directly reading a variable from the UPS.
242266
Try
243267
GetUPSVar("ups.realpower")
244268
_PowerCalculationMethod = PowerMethod.RealPower
245-
LogFile.LogTracing("Using RealPower method to calculate power usage.", LogLvl.LOG_NOTICE, Me)
269+
LogFile.LogTracing("Using RealPower method.", LogLvl.LOG_NOTICE, Me)
246270
Catch
247271
Try
248272
GetUPSVar("ups.realpower.nominal")
249273
GetUPSVar("ups.load")
250-
_PowerCalculationMethod = PowerMethod.NominalPowerCalc
251-
LogFile.LogTracing("Using NominalPowerCalc method to calculate power usage.", LogLvl.LOG_NOTICE, Me)
274+
_PowerCalculationMethod = PowerMethod.RPNomLoadPct
275+
LogFile.LogTracing("Using RPNomLoadPct method.", LogLvl.LOG_NOTICE, Me)
252276
Catch
253277
Try
254278
GetUPSVar("input.current.nominal")
255279
GetUPSVar("input.voltage.nominal")
256280
GetUPSVar("ups.load")
257-
_PowerCalculationMethod = PowerMethod.VoltAmpCalc
258-
LogFile.LogTracing("Using VoltAmpCalc method to calculate power usage.", LogLvl.LOG_NOTICE, Me)
281+
_PowerCalculationMethod = PowerMethod.InputNomVALoadPct
282+
LogFile.LogTracing("Using InputNomVALoadPct method.", LogLvl.LOG_NOTICE, Me)
259283
Catch
260-
_PowerCalculationMethod = PowerMethod.Unavailable
261-
LogFile.LogTracing("Unable to find a suitable method to calculate power usage.", LogLvl.LOG_WARNING, Me)
284+
If freshData.UPS_Value.Output_Current IsNot Nothing AndAlso
285+
freshData.UPS_Value.Output_Voltage <> Nothing Then
286+
_PowerCalculationMethod = PowerMethod.OutputVACalc
287+
LogFile.LogTracing("Using OutputVACalc method.", LogLvl.LOG_NOTICE, Me)
288+
Else
289+
_PowerCalculationMethod = PowerMethod.Unavailable
290+
LogFile.LogTracing("Unable to find a suitable method to calculate power usage.", LogLvl.LOG_WARNING, Me)
291+
End If
262292
End Try
263293
End Try
264294
End Try
@@ -283,35 +313,43 @@ Public Class UPS_Device
283313
.Batt_Charge = Double.Parse(GetUPSVar("battery.charge", -1), INVARIANT_CULTURE)
284314
.Batt_Voltage = Double.Parse(GetUPSVar("battery.voltage", -1), INVARIANT_CULTURE)
285315
.Batt_Runtime = Double.Parse(GetUPSVar("battery.runtime", -1), INVARIANT_CULTURE)
286-
.Power_Frequency = Double.Parse(GetUPSVar("input.frequency", Double.Parse(GetUPSVar("output.frequency", Freq_Fallback), INVARIANT_CULTURE)), INVARIANT_CULTURE)
316+
.Power_Frequency = Double.Parse(GetUPSVar("input.frequency", Freq_Fallback), INVARIANT_CULTURE)
287317
.Input_Voltage = Double.Parse(GetUPSVar("input.voltage", -1), INVARIANT_CULTURE)
288-
.Output_Voltage = Double.Parse(GetUPSVar("output.voltage", .Input_Voltage), INVARIANT_CULTURE)
318+
.Output_Voltage = Double.Parse(GetUPSVar("output.voltage", -1), INVARIANT_CULTURE)
289319
.Load = Double.Parse(GetUPSVar("ups.load", 0), INVARIANT_CULTURE)
290320

291321
' Retrieve and/or calculate output power if possible.
292322
If _PowerCalculationMethod <> PowerMethod.Unavailable Then
293323
Dim parsedValue As Double
294324

295325
Try
296-
If _PowerCalculationMethod = PowerMethod.RealPower Then
297-
parsedValue = Double.Parse(GetUPSVar("ups.realpower"), INVARIANT_CULTURE)
298-
299-
ElseIf _PowerCalculationMethod = PowerMethod.NominalPowerCalc Then
300-
parsedValue = Double.Parse(GetUPSVar("ups.realpower.nominal"), INVARIANT_CULTURE)
301-
parsedValue *= UPS_Datas.UPS_Value.Load / 100.0
302-
303-
ElseIf _PowerCalculationMethod = PowerMethod.VoltAmpCalc Then
304-
Dim nomCurrent = Double.Parse(GetUPSVar("input.current.nominal"), INVARIANT_CULTURE)
305-
Dim nomVoltage = Double.Parse(GetUPSVar("input.voltage.nominal"), INVARIANT_CULTURE)
306-
307-
parsedValue = (nomCurrent * nomVoltage * 0.8) * (UPS_Datas.UPS_Value.Load / 100.0)
308-
Else
309-
Throw New InvalidOperationException("Insufficient variables to calculate power.")
310-
End If
326+
Select Case _PowerCalculationMethod
327+
Case PowerMethod.RealPower
328+
parsedValue = Double.Parse(GetUPSVar("ups.realpower"), INVARIANT_CULTURE)
329+
330+
Case PowerMethod.RPNomLoadPct
331+
parsedValue = Double.Parse(GetUPSVar("ups.realpower.nominal"), INVARIANT_CULTURE)
332+
parsedValue *= UPS_Datas.UPS_Value.Load / 100.0
333+
334+
Case PowerMethod.InputNomVALoadPct
335+
Dim nomCurrent = Double.Parse(GetUPSVar("input.current.nominal"), INVARIANT_CULTURE)
336+
Dim nomVoltage = Double.Parse(GetUPSVar("input.voltage.nominal"), INVARIANT_CULTURE)
337+
338+
parsedValue = nomCurrent * nomVoltage * POWER_FACTOR
339+
parsedValue = UPS_Datas.UPS_Value.Load / 100.0
340+
Case PowerMethod.OutputVACalc
341+
.Output_Current = Single.Parse(GetUPSVar("output.current"), INVARIANT_CULTURE)
342+
parsedValue = .Output_Current * .Output_Voltage * POWER_FACTOR
343+
Case Else
344+
' Should not trigger - something has gone wrong.
345+
Throw New InvalidOperationException("Insufficient variables to calculate power.")
346+
End Select
311347
Catch ex As FormatException
312348
LogFile.LogTracing("Unexpected format trying to parse value from UPS. Exception:", LogLvl.LOG_ERROR, Me)
313349
LogFile.LogTracing(ex.ToString(), LogLvl.LOG_ERROR, Me)
314350
LogFile.LogTracing("parsedValue: " & parsedValue, LogLvl.LOG_ERROR, Me)
351+
Catch ex As Exception
352+
LogFile.LogException(ex, Me)
315353
End Try
316354

317355
.Output_Power = parsedValue
@@ -428,7 +466,6 @@ Public Class UPS_Device
428466
LogFile.LogTracing("Apply Fallback Value when retrieving " & varName, LogLvl.LOG_WARNING, Me)
429467
Return Fallback_value
430468
Else
431-
LogFile.LogTracing("Unhandled error while getting " & varName, LogLvl.LOG_ERROR, Me)
432469
Throw
433470
End If
434471
End Try

0 commit comments

Comments
 (0)