Skip to content

Commit 4961d4f

Browse files
authored
Improvements to battery monitoring (#1158)
* Check whether battery values are available * Rename _degradationPercentage to _degradationLevel * Add support for temperature monitoring * Include the battery device name and tag in the hardware identifier * Set sensor index value properly * Fix temperature conversion The returned temperature value must be divided, not multiplied. * Disable sensors that have a "null" value * Fix random symbols in battery device name and manufacturer
1 parent d402b4a commit 4961d4f

3 files changed

Lines changed: 192 additions & 140 deletions

File tree

LibreHardwareMonitorLib/Hardware/Battery/Battery.cs

Lines changed: 111 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ internal sealed class Battery : Hardware
1919
private readonly Sensor _chargeDischargeCurrent;
2020
private readonly Sensor _chargeDischargeRate;
2121
private readonly Sensor _chargeLevel;
22-
private readonly Sensor _degradationPercentage;
22+
private readonly Sensor _degradationLevel;
2323
private readonly Sensor _designedCapacity;
2424
private readonly Sensor _fullChargedCapacity;
2525
private readonly Sensor _remainingCapacity;
2626
private readonly Sensor _remainingTime;
27+
private readonly Sensor _temperature;
2728
private readonly Sensor _voltage;
2829

2930
public Battery
@@ -34,7 +35,7 @@ public Battery
3435
Kernel32.BATTERY_INFORMATION batteryInfo,
3536
uint batteryTag,
3637
ISettings settings) :
37-
base(name, new Identifier("battery"), settings)
38+
base(name, new Identifier("battery", $"{name.Replace(' ', '-')}_{batteryTag}"), settings)
3839
{
3940
Name = name;
4041
Manufacturer = manufacturer;
@@ -72,61 +73,65 @@ public Battery
7273
Chemistry = BatteryChemistry.Unknown;
7374
}
7475

75-
DegradationLevel = 100f - (batteryInfo.FullChargedCapacity * 100f / batteryInfo.DesignedCapacity);
76-
DesignedCapacity = batteryInfo.DesignedCapacity;
77-
FullChargedCapacity = batteryInfo.FullChargedCapacity;
78-
76+
_designedCapacity = new Sensor("Designed Capacity", 0, SensorType.Energy, this, settings);
77+
_fullChargedCapacity = new Sensor("Fully-Charged Capacity", 1, SensorType.Energy, this, settings);
78+
_degradationLevel = new Sensor("Degradation Level", 1, SensorType.Level, this, settings);
7979
_chargeLevel = new Sensor("Charge Level", 0, SensorType.Level, this, settings);
80-
ActivateSensor(_chargeLevel);
81-
82-
_voltage = new Sensor("Voltage", 1, SensorType.Voltage, this, settings);
83-
ActivateSensor(_voltage);
84-
85-
_chargeDischargeCurrent = new Sensor("Current", 2, SensorType.Current, this, settings);
86-
ActivateSensor(_chargeDischargeCurrent);
87-
88-
_designedCapacity = new Sensor("Designed Capacity", 3, SensorType.Energy, this, settings);
89-
ActivateSensor(_designedCapacity);
90-
91-
_fullChargedCapacity = new Sensor("Full Charged Capacity", 4, SensorType.Energy, this, settings);
92-
ActivateSensor(_fullChargedCapacity);
93-
94-
_remainingCapacity = new Sensor("Remaining Capacity", 5, SensorType.Energy, this, settings);
95-
ActivateSensor(_remainingCapacity);
96-
80+
_voltage = new Sensor("Voltage", 0, SensorType.Voltage, this, settings);
81+
_remainingCapacity = new Sensor("Remaining Capacity", 2, SensorType.Energy, this, settings);
82+
_chargeDischargeCurrent = new Sensor("Charge/Discharge Current", 0, SensorType.Current, this, settings);
9783
_chargeDischargeRate = new Sensor("Charge/Discharge Rate", 0, SensorType.Power, this, settings);
98-
ActivateSensor(_chargeDischargeRate);
99-
100-
_degradationPercentage = new Sensor("Degradation Level", 0, SensorType.Level, this, settings);
101-
ActivateSensor(_degradationPercentage);
102-
10384
_remainingTime = new Sensor("Remaining Time (Estimated)", 0, SensorType.TimeSpan, this, settings);
104-
ActivateSensor(_remainingTime);
85+
_temperature = new Sensor("Battery Temperature", 0, SensorType.Temperature, this, settings);
86+
87+
if (batteryInfo.FullChargedCapacity is not Kernel32.BATTERY_UNKNOWN_CAPACITY &&
88+
batteryInfo.DesignedCapacity is not Kernel32.BATTERY_UNKNOWN_CAPACITY)
89+
{
90+
_designedCapacity.Value = batteryInfo.DesignedCapacity;
91+
_fullChargedCapacity.Value = batteryInfo.FullChargedCapacity;
92+
_degradationLevel.Value = 100f - (batteryInfo.FullChargedCapacity * 100f / batteryInfo.DesignedCapacity);
93+
DesignedCapacity = batteryInfo.DesignedCapacity;
94+
FullChargedCapacity = batteryInfo.FullChargedCapacity;
95+
96+
ActivateSensor(_designedCapacity);
97+
ActivateSensor(_fullChargedCapacity);
98+
ActivateSensor(_degradationLevel);
99+
}
105100
}
106101

107-
public float ChargeDischargeCurrent { get; private set; }
102+
public float? ChargeDischargeCurrent { get; private set; }
108103

109-
public float ChargeDischargeRate { get; private set; }
104+
public float? ChargeDischargeRate { get; private set; }
110105

111-
public float ChargeLevel { get; private set; }
106+
public float? ChargeLevel => _chargeLevel.Value;
112107

113108
public BatteryChemistry Chemistry { get; }
114109

115-
public float DegradationLevel { get; }
110+
public float? DegradationLevel => _degradationLevel.Value;
116111

117-
public float DesignedCapacity { get; }
112+
public float? DesignedCapacity { get; }
118113

119-
public float FullChargedCapacity { get; }
114+
public float? FullChargedCapacity { get; }
120115

121116
public override HardwareType HardwareType => HardwareType.Battery;
122117

123118
public string Manufacturer { get; }
124119

125-
public float RemainingCapacity { get; private set; }
120+
public float? RemainingCapacity => _remainingCapacity.Value;
121+
122+
public float? RemainingTime => _remainingTime.Value;
126123

127-
public uint RemainingTime { get; private set; }
124+
public float? Temperature => _temperature.Value;
128125

129-
public float Voltage { get; private set; }
126+
public float? Voltage => _voltage.Value;
127+
128+
private void ActivateSensorIfValueNotNull(ISensor sensor)
129+
{
130+
if (sensor.Value != null)
131+
ActivateSensor(sensor);
132+
else
133+
DeactivateSensor(sensor);
134+
}
130135

131136
public override void Update()
132137
{
@@ -142,53 +147,55 @@ public override void Update()
142147
out _,
143148
IntPtr.Zero))
144149
{
145-
_designedCapacity.Value = Convert.ToSingle(_batteryInformation.DesignedCapacity);
146-
_fullChargedCapacity.Value = Convert.ToSingle(_batteryInformation.FullChargedCapacity);
147-
148-
_remainingCapacity.Value = Convert.ToSingle(batteryStatus.Capacity);
149-
RemainingCapacity = Convert.ToSingle(batteryStatus.Capacity);
150-
151-
_voltage.Value = Convert.ToSingle(batteryStatus.Voltage) / 1000f;
152-
Voltage = Convert.ToSingle(batteryStatus.Voltage) / 1000f;
150+
if (batteryStatus.Capacity != Kernel32.BATTERY_UNKNOWN_CAPACITY)
151+
_remainingCapacity.Value = batteryStatus.Capacity;
152+
else
153+
_remainingCapacity.Value = null;
153154

154155
_chargeLevel.Value = _remainingCapacity.Value * 100f / _fullChargedCapacity.Value;
155-
ChargeLevel = (_remainingCapacity.Value * 100f / _fullChargedCapacity.Value).GetValueOrDefault();
156156

157-
ChargeDischargeRate = batteryStatus.Rate / 1000f;
157+
if (batteryStatus.Voltage is not Kernel32.BATTERY_UNKNOWN_VOLTAGE)
158+
_voltage.Value = batteryStatus.Voltage / 1000f;
159+
else
160+
_voltage.Value = null;
158161

159-
switch (batteryStatus.Rate)
162+
if (batteryStatus.Rate is Kernel32.BATTERY_UNKNOWN_RATE)
160163
{
161-
case > 0:
162-
_chargeDischargeRate.Name = "Charge Rate";
163-
_chargeDischargeRate.Value = batteryStatus.Rate / 1000f;
164+
ChargeDischargeCurrent = null;
165+
_chargeDischargeCurrent.Value = null;
164166

167+
ChargeDischargeRate = null;
168+
_chargeDischargeRate.Value = null;
169+
}
170+
else
171+
{
172+
float rateWatts = batteryStatus.Rate / 1000f;
173+
ChargeDischargeRate = rateWatts;
174+
_chargeDischargeRate.Value = Math.Abs(rateWatts);
175+
176+
float? current = rateWatts / _voltage.Value;
177+
ChargeDischargeCurrent = current;
178+
if (current is not null)
179+
_chargeDischargeCurrent.Value = Math.Abs(current.Value);
180+
else
181+
_chargeDischargeCurrent.Value = null;
182+
183+
if (rateWatts > 0)
184+
{
185+
_chargeDischargeRate.Name = "Charge Rate";
165186
_chargeDischargeCurrent.Name = "Charge Current";
166-
_chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value;
167-
ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault();
168-
169-
break;
170-
case < 0:
187+
}
188+
else if (rateWatts < 0)
189+
{
171190
_chargeDischargeRate.Name = "Discharge Rate";
172-
_chargeDischargeRate.Value = Math.Abs(batteryStatus.Rate / 1000f);
173-
174191
_chargeDischargeCurrent.Name = "Discharge Current";
175-
_chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value;
176-
ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault();
177-
178-
break;
179-
default:
192+
}
193+
else
194+
{
180195
_chargeDischargeRate.Name = "Charge/Discharge Rate";
181-
_chargeDischargeRate.Value = 0f;
182-
ChargeDischargeRate = 0f;
183-
184196
_chargeDischargeCurrent.Name = "Charge/Discharge Current";
185-
_chargeDischargeCurrent.Value = 0f;
186-
ChargeDischargeCurrent = 0f;
187-
188-
break;
197+
}
189198
}
190-
191-
_degradationPercentage.Value = 100f - (_fullChargedCapacity.Value * 100f / _designedCapacity.Value);
192199
}
193200

194201
uint estimatedRunTime = 0;
@@ -204,17 +211,41 @@ public override void Update()
204211
out _,
205212
IntPtr.Zero))
206213
{
207-
RemainingTime = estimatedRunTime;
208214
if (estimatedRunTime != Kernel32.BATTERY_UNKNOWN_TIME)
209-
{
210-
ActivateSensor(_remainingTime);
211215
_remainingTime.Value = estimatedRunTime;
212-
}
213216
else
214-
{
215-
DeactivateSensor(_remainingTime);
216-
}
217+
_remainingTime.Value = null;
218+
}
219+
else
220+
{
221+
_remainingTime.Value = null;
222+
}
223+
224+
uint temperature = 0;
225+
bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryTemperature;
226+
if (Kernel32.DeviceIoControl(_batteryHandle,
227+
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION,
228+
ref bqi,
229+
Marshal.SizeOf(bqi),
230+
ref temperature,
231+
Marshal.SizeOf<uint>(),
232+
out _,
233+
IntPtr.Zero))
234+
{
235+
_temperature.Value = (temperature / 10f) - 273.15f;
236+
}
237+
else
238+
{
239+
_temperature.Value = null;
217240
}
241+
242+
ActivateSensorIfValueNotNull(_remainingCapacity);
243+
ActivateSensorIfValueNotNull(_chargeLevel);
244+
ActivateSensorIfValueNotNull(_voltage);
245+
ActivateSensorIfValueNotNull(_chargeDischargeCurrent);
246+
ActivateSensorIfValueNotNull(_chargeDischargeRate);
247+
ActivateSensorIfValueNotNull(_remainingTime);
248+
ActivateSensorIfValueNotNull(_temperature);
218249
}
219250

220251
public override void Close()

0 commit comments

Comments
 (0)