Update for DiskInfoToolkit Version 2.0.0. (#2298)

* Update for DiskInfoToolkit Version 2.0.0.

* PR comments

* PR comments.

* Apply suggestion from @PhyxionNL

---------

Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com>
This commit is contained in:
Blacktempel
2026-04-06 19:26:02 +02:00
committed by GitHub
co-authored by PhyxionNL
parent 9d9bb0084b
commit 9e831e07b2
6 changed files with 180 additions and 1869 deletions
@@ -4,6 +4,8 @@
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using DiskInfoToolkit;
namespace LibreHardwareMonitor.Hardware.Storage;
public sealed class SmartAttribute
@@ -26,7 +28,7 @@ public sealed class SmartAttribute
/// no sensor is created.
/// </param>
/// <param name="defaultHiddenSensor">True to hide the sensor initially.</param>
public SmartAttribute(DiskInfoToolkit.SmartAttribute smartAttribute, SensorType? sensorType, int sensorChannel, string sensorName, bool defaultHiddenSensor = false)
public SmartAttribute(SmartAttributeEntry smartAttribute, SensorType? sensorType, int sensorChannel, string sensorName, bool defaultHiddenSensor = false)
{
Attribute = smartAttribute;
SensorType = sensorType;
@@ -35,16 +37,16 @@ public sealed class SmartAttribute
IsHiddenByDefault = defaultHiddenSensor;
}
public DiskInfoToolkit.SmartAttribute Attribute { get; internal set; }
public SmartAttributeEntry Attribute { get; internal set; }
public byte Id => Attribute.Info.ID;
public string Name => Attribute.Info.Name;
public byte Id => Attribute.ID;
public string Name => Attribute.Name;
public SensorType? SensorType { get; }
public int SensorChannel { get; }
public string SensorName { get; }
public bool IsHiddenByDefault { get; }
public float Value => Attribute.Attribute.RawValueULong;
public byte Threshold => Attribute.Attribute.Threshold;
public float Value => Attribute.RawValue;
public byte Threshold => Attribute.ThresholdValue;
}
File diff suppressed because it is too large Load Diff
@@ -13,11 +13,13 @@ using System.Linq;
using System.Text;
using BlackSharp.Core.Converters;
using BlackSharp.Core.Converters.Enums;
using DiskInfoToolkit.Interop.Enums;
using DiskInfoToolkit.Smart;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Storage.FileSystem;
using Windows.Win32.System.Ioctl;
using StorageDeviceDIT = DiskInfoToolkit.StorageDevice;
using StorageDIT = DiskInfoToolkit.Storage;
namespace LibreHardwareMonitor.Hardware.Storage;
@@ -26,7 +28,9 @@ public sealed class StorageDevice : Hardware, ISmart
private readonly PerformanceValue _perfRead = new();
private readonly PerformanceValue _perfTotal = new();
private readonly PerformanceValue _perfWrite = new();
private readonly DiskInfoToolkit.Storage _storage;
private readonly StorageDeviceDIT _storage;
private bool _initialized;
private long _lastReadCount;
private long _lastTime;
@@ -45,8 +49,8 @@ public sealed class StorageDevice : Hardware, ISmart
private Sensor _usageSensor;
private Sensor _freeSpaceSensor;
public StorageDevice(DiskInfoToolkit.Storage storage, string id, ISettings settings)
: base(storage.Model, new Identifier(id, storage.DriveNumber.ToString(CultureInfo.InvariantCulture)), settings)
public StorageDevice(StorageDeviceDIT storage, string id, ISettings settings)
: base(storage.ProductName, new Identifier(id, storage.StorageDeviceNumber.GetValueOrDefault().ToString(CultureInfo.InvariantCulture)), settings)
{
_storage = storage;
@@ -57,16 +61,15 @@ public sealed class StorageDevice : Hardware, ISmart
public override HardwareType HardwareType => HardwareType.Storage;
public DiskInfoToolkit.Storage Storage => _storage;
public StorageDeviceDIT Storage => _storage;
public IReadOnlyList<SmartAttribute> Attributes => _attributes;
///<inheritdoc cref="DiskInfoToolkit.Storage.ForceWakeup"/>
public bool ForceWakeup
{
get { return _storage.ForceWakeup; }
set { _storage.ForceWakeup = value; }
}
/// <summary>
/// Forces disk to wake up, if disk is asleep.
/// </summary>
/// <remarks>See <see cref="StorageDIT.TryWakeUp"/> for more information.</remarks>
public bool ForceWakeup { get; set; }
public static TimeSpan ThrottleInterval { get; set; }
@@ -77,18 +80,37 @@ public sealed class StorageDevice : Hardware, ISmart
return;
}
// If storage device has no changes, skip update
if (!StorageDIT.Refresh(_storage))
{
// If not initialized, we need to initialize sensors with initial values, even if there are no changes
if (!_initialized)
{
_initialized = true;
}
else
{
return;
}
}
// Try waking up storage device if it is asleep and ForceWakeup is enabled
if (ForceWakeup && !_storage.IsDevicePowerOn.GetValueOrDefault(true))
{
StorageDIT.TryWakeUp(_storage);
}
_lastUpdate = DateTime.UtcNow;
ToggleSpaceSensors();
UpdatePerformanceSensors();
_storage.Update();
UpdateSpaceSensors();
// Update attributes
foreach (var attribute in _storage.Smart.SmartAttributes)
foreach (var attribute in _storage.SmartAttributes)
{
// Try to find attribute
var found = _attributes.Find(sa => sa.Id == attribute.Info.ID);
var found = _attributes.Find(sa => sa.Id == attribute.ID);
// Found attribute, update it
if (found != null)
@@ -106,15 +128,34 @@ public sealed class StorageDevice : Hardware, ISmart
var r = new StringBuilder();
r.AppendLine("Storage");
r.AppendLine();
r.AppendLine($"Drive Name: {_storage.Model}");
r.AppendLine($"Firmware Version and Revision: {_storage.Firmware}; {_storage.FirmwareRev}");
r.AppendLine();
r.AppendLine("Smart Attributes:");
r.AppendLine("ID, Description, Value, Threshold");
r.AppendLine($"Drive Name: {_storage.ProductName}");
if (_storage.HealthStatus.HasValue)
{
r.AppendLine($"Health Status: {_storage.HealthStatus}");
}
if (_storage.HealthStatusReason != null)
{
r.AppendLine($"Health Status Reason:");
r.AppendLine(_storage.HealthStatusReason);
}
r.AppendLine($"Revision: {_storage.ProductRevision}");
r.AppendLine($"Bus type: {_storage.BusType}");
r.AppendLine($"Controller information:");
r.AppendLine($" Service: {_storage.Controller.Service}"); // Important
r.AppendLine($" Vendor: 0x{_storage.Controller.VendorID:X4} ('{_storage.Controller.VendorName}')");
r.AppendLine($" Device: 0x{_storage.Controller.DeviceID:X4} ('{_storage.Controller.DeviceName}')");
r.AppendLine($" Family: {_storage.Controller.Family}");
r.AppendLine($"Smart Attributes (Profile: '{_storage.SmartAttributeProfile}'):");
r.AppendLine(" ID, Description, Value, Threshold");
foreach (var attribute in _attributes)
{
r.AppendLine($"{attribute.Id,3}, {attribute.Name,60}, {attribute.Value,18}, {attribute.Threshold,3}");
r.AppendLine($" {attribute.Id,3}, {attribute.Name,60}, {attribute.Value,18}, {attribute.Threshold,3}");
}
r.AppendLine();
@@ -125,28 +166,30 @@ public sealed class StorageDevice : Hardware, ISmart
foreach (var partition in _storage.Partitions)
{
r.AppendLine($"Partition #{partition.PartitionNumber}");
r.AppendLine($" Partition #{partition.PartitionNumber}");
if (partition.DriveLetter != null)
{
r.AppendLine($"Drive Letter: {partition.DriveLetter}");
r.AppendLine($" Drive Letter: {partition.DriveLetter}");
}
if (partition.AvailableFreeSpace != null)
if (partition.AvailableFreeSpaceBytes != null)
{
r.AppendLine($"Available Free Space: {partition.AvailableFreeSpace}");
r.AppendLine($" Available Free Space: {partition.AvailableFreeSpaceBytes}");
}
r.AppendLine($" Contains other OS: {partition.IsOtherOperatingSystemPartition}");
}
r.AppendLine();
if (_storage.TotalFreeSize != null)
if (_storage.TotalPartitionFreeSpaceBytes != null)
{
r.AppendLine($"Total Free Size: {_storage.TotalFreeSize}");
r.AppendLine($"Total Free Size: {_storage.TotalPartitionFreeSpaceBytes}");
}
}
r.AppendLine($"Total Size: {_storage.TotalSize}");
r.AppendLine($"Total Size: {_storage.DiskSizeBytes}");
return r.ToString();
}
@@ -161,52 +204,62 @@ public sealed class StorageDevice : Hardware, ISmart
{
_attributes.Clear();
var attributes = SmartAttributeTranslator.GetAttributesFor(_storage);
var attributes = _storage.SmartAttributes.Select(a => new SmartAttribute(a, null, 0, null));
_attributes.AddRange(attributes.Where(a => a != null));
}
private void CreateSensors()
{
if (_storage.IsNVMe)
if (_storage.Temperature.HasValue)
{
// Different name for NVMe
AddSensor("Composite Temperature", 0, false, SensorType.Temperature, s => s.Smart.Temperature.GetValueOrDefault());
TryAddTemperatureSensor(1, false, 1, SmartAttributeType.TemperatureSensor1);
TryAddTemperatureSensor(2, false, 2, SmartAttributeType.TemperatureSensor2);
TryAddTemperatureSensor(3, false, 3, SmartAttributeType.TemperatureSensor3);
TryAddTemperatureSensor(4, false, 4, SmartAttributeType.TemperatureSensor4);
TryAddTemperatureSensor(5, false, 5, SmartAttributeType.TemperatureSensor5);
TryAddTemperatureSensor(6, false, 6, SmartAttributeType.TemperatureSensor6);
TryAddTemperatureSensor(7, false, 7, SmartAttributeType.TemperatureSensor7);
TryAddTemperatureSensor(8, false, 8, SmartAttributeType.TemperatureSensor8);
AddSensor("Warning Temperature", 10, false, SensorType.Temperature, s => s.Smart.TemperatureWarning.GetValueOrDefault());
AddSensor("Critical Temperature", 11, false, SensorType.Temperature, s => s.Smart.TemperatureCritical.GetValueOrDefault());
}
else
{
AddSensor("Temperature", 0, false, SensorType.Temperature, s => s.Smart.Temperature.GetValueOrDefault());
AddSensor("Temperature", 0, false, SensorType.Temperature, s => s.Temperature.GetValueOrDefault());
}
if (_storage.Smart.Life.HasValue)
// NVMe specific temperature sensors, if available
TryAddTemperatureSensor(_storage, 1, false, 1, SmartTextKeys.TemperatureSensor1);
TryAddTemperatureSensor(_storage, 2, false, 2, SmartTextKeys.TemperatureSensor2);
TryAddTemperatureSensor(_storage, 3, false, 3, SmartTextKeys.TemperatureSensor3);
TryAddTemperatureSensor(_storage, 4, false, 4, SmartTextKeys.TemperatureSensor4);
TryAddTemperatureSensor(_storage, 5, false, 5, SmartTextKeys.TemperatureSensor5);
TryAddTemperatureSensor(_storage, 6, false, 6, SmartTextKeys.TemperatureSensor6);
TryAddTemperatureSensor(_storage, 7, false, 7, SmartTextKeys.TemperatureSensor7);
TryAddTemperatureSensor(_storage, 8, false, 8, SmartTextKeys.TemperatureSensor8);
if (_storage.TemperatureWarning.HasValue)
{
AddSensor("Life", 20, false, SensorType.Level, s => s.Smart.Life.GetValueOrDefault());
AddSensor("Warning Temperature", 10, false, SensorType.Temperature, s => s.TemperatureWarning.GetValueOrDefault());
}
if (_storage.Smart.HostReads.HasValue)
if (_storage.TemperatureCritical.HasValue)
{
AddSensor("Data Read", 21, false, SensorType.Data, s => s.Smart.HostReads.GetValueOrDefault());
AddSensor("Critical Temperature", 11, false, SensorType.Temperature, s => s.TemperatureCritical.GetValueOrDefault());
}
if (_storage.Smart.HostWrites.HasValue)
if (_storage.Health.HasValue)
{
AddSensor("Data Written", 22, false, SensorType.Data, s => s.Smart.HostWrites.GetValueOrDefault());
AddSensor("Life", 20, false, SensorType.Level, s => s.Health.GetValueOrDefault());
}
AddSensor("Power On Count", 23, false, SensorType.Factor, s => s.Smart.PowerOnCount);
AddSensor("Power On Hours", 24, false, SensorType.Factor, s => Math.Max(s.Smart.MeasuredPowerOnHours, s.Smart.DetectedPowerOnHours));
if (_storage.HostReads.HasValue)
{
AddSensor("Data Read", 21, false, SensorType.Data, s => s.HostReads.GetValueOrDefault());
}
if (_storage.HostWrites.HasValue)
{
AddSensor("Data Written", 22, false, SensorType.Data, s => s.HostWrites.GetValueOrDefault());
}
if (_storage.PowerOnCount.HasValue)
{
AddSensor("Power On Count", 23, false, SensorType.Factor, s => s.PowerOnCount.GetValueOrDefault());
}
if (_storage.PowerOnHours.HasValue)
{
AddSensor("Power On Hours", 24, false, SensorType.Factor, s => s.PowerOnHours.GetValueOrDefault());
}
_usageSensor = new Sensor("Used Space", 30, SensorType.Load, this, _settings);
_freeSpaceSensor = new Sensor("Free Space", 31, SensorType.Data, this, _settings);
@@ -214,7 +267,7 @@ public sealed class StorageDevice : Hardware, ISmart
var totalSpaceSensor = new Sensor("Total Space", 32, SensorType.Data, this, _settings)
{
Value = (float)DataUnitConverter.ToGigaByte(_storage.TotalSize, DataUnit.Byte)
Value = (float)DataUnitConverter.ToGigaByte(_storage.DiskSizeBytes.GetValueOrDefault(), DataUnit.Byte)
};
ActivateSensor(totalSpaceSensor);
@@ -236,17 +289,18 @@ public sealed class StorageDevice : Hardware, ISmart
AddSmartAttributeSensors();
}
private void TryAddTemperatureSensor(int index, bool defaultHidden, int thermalSensorIndex, SmartAttributeType type)
private void TryAddTemperatureSensor(StorageDeviceDIT storage, int index, bool defaultHidden, int thermalSensorIndex, string smartTextKey)
{
var attr = GetSmartAttribute(type);
if (attr != null && attr.Attribute.RawValueULong > 0)
var attr = storage.SmartAttributes.FirstOrDefault(a => a.TextKey == smartTextKey);
if (attr != null && attr.RawValue > 0)
{
AddSensor($"Temperature #{thermalSensorIndex}", index, defaultHidden, SensorType.Temperature, s =>
{
var a = GetSmartAttribute(type);
var a = s.SmartAttributes.FirstOrDefault(a => a.TextKey == smartTextKey);
if (a != null)
{
return TemperatureConverter.KelvinToCelsius(a.Attribute.RawValueULong);
return TemperatureConverter.KelvinToCelsius(a.RawValue);
}
return 0;
@@ -254,11 +308,6 @@ public sealed class StorageDevice : Hardware, ISmart
}
}
private DiskInfoToolkit.SmartAttribute GetSmartAttribute(SmartAttributeType type)
{
return _storage.Smart.SmartAttributes.FirstOrDefault(sa => sa.Info.Type == type);
}
private void AddSensor(string name, int index, bool defaultHidden, SensorType sensorType, GetStorageDeviceSensorValue getValue)
{
var sensor = new StorageDeviceSensor(name, index, defaultHidden, sensorType, this, _settings, getValue)
@@ -274,7 +323,7 @@ public sealed class StorageDevice : Hardware, ISmart
{
DISK_PERFORMANCE diskPerformance = new();
using var handle = PInvoke.CreateFile(_storage.PhysicalPath,
using var handle = PInvoke.CreateFile(_storage.DevicePath,
(uint)FileAccess.ReadWrite,
FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE,
null,
@@ -336,11 +385,11 @@ public sealed class StorageDevice : Hardware, ISmart
private void UpdateSpaceSensors()
{
if (_storage.TotalSize > 0)
if (_storage.DiskSizeBytes > 0)
{
// Set sensor value
_usageSensor.Value = 100.0f - (100.0f * _storage.TotalFreeSize / _storage.TotalSize);
_freeSpaceSensor.Value = (float)DataUnitConverter.ToGigaByte(_storage.TotalFreeSize.GetValueOrDefault(), DataUnit.Byte);
_usageSensor.Value = 100.0f - (100.0f * _storage.TotalPartitionFreeSpaceBytes / _storage.DiskSizeBytes);
_freeSpaceSensor.Value = (float)DataUnitConverter.ToGigaByte(_storage.TotalPartitionFreeSpaceBytes.GetValueOrDefault(), DataUnit.Byte);
}
else
{
@@ -4,9 +4,11 @@
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using StorageDeviceDIT = DiskInfoToolkit.StorageDevice;
namespace LibreHardwareMonitor.Hardware.Storage;
internal delegate float GetStorageDeviceSensorValue(DiskInfoToolkit.Storage storage);
internal delegate float GetStorageDeviceSensorValue(StorageDeviceDIT storage);
internal class StorageDeviceSensor : Sensor
{
@@ -18,7 +20,7 @@ internal class StorageDeviceSensor : Sensor
_getValue = getValue;
}
public void Update(DiskInfoToolkit.Storage storage)
public void Update(StorageDeviceDIT storage)
{
var value = _getValue(storage);
@@ -7,7 +7,8 @@
using System.Collections.Generic;
using System.Linq;
using DiskInfoToolkit;
using DiskInfoToolkit.Events;
using StorageDeviceDIT = DiskInfoToolkit.StorageDevice;
using StorageDIT = DiskInfoToolkit.Storage;
namespace LibreHardwareMonitor.Hardware.Storage;
@@ -34,49 +35,66 @@ internal class StorageGroup : IGroup, IHardwareChanged
private void AddHardware(ISettings settings)
{
StorageManager.StoragesChanged -= OnStoragesChanged;
StorageDIT.DevicesChanged -= OnStoragesChanged;
//Reload storage devices
StorageManager.ReloadStorages();
//Get all disks
var disks = StorageDIT.GetDisks();
//Transform storage device to hardware
_hardware.AddRange(StorageManager.Storages.Select(s => new StorageDevice(s, GetID(s), settings)));
_hardware.AddRange(disks.Select(s => new StorageDevice(s, GetID(s), settings)));
StorageManager.StoragesChanged += OnStoragesChanged;
StorageDIT.DevicesChanged += OnStoragesChanged;
}
private void OnStoragesChanged(StoragesChangedEventArgs e)
private void OnStoragesChanged(object sender, StorageDevicesChangedEventArgs e)
{
StorageDevice storageDevice = null;
switch (e.StorageChangeIdentifier)
foreach (var added in e.Added)
{
case StorageChangeIdentifier.Added:
storageDevice = new StorageDevice(e.Storage, GetID(e.Storage), _settings);
var storageDevice = new StorageDevice(added, GetID(added), _settings);
_hardware.Add(storageDevice);
HardwareAdded?.Invoke(storageDevice);
break;
case StorageChangeIdentifier.Removed:
storageDevice = _hardware.Find(sd => sd.Storage == e.Storage);
_hardware.Add(storageDevice);
HardwareAdded?.Invoke(storageDevice);
}
if (storageDevice != null)
{
_hardware.Remove(storageDevice);
HardwareRemoved?.Invoke(storageDevice);
}
break;
foreach (var removed in e.Removed)
{
var storageDevice = _hardware.Find(sd => sd.Storage == removed);
if (storageDevice != null)
{
_hardware.Remove(storageDevice);
HardwareRemoved?.Invoke(storageDevice);
}
}
}
private string GetID(DiskInfoToolkit.Storage storage)
private string GetID(StorageDeviceDIT disk)
{
if (storage.IsNVMe)
return "nvme";
else if (storage.IsSSD)
return "ssd";
else
return "hdd";
switch (disk.TransportKind)
{
case StorageTransportKind.Ata:
return "ata";
case StorageTransportKind.Scsi:
return "scsi";
case StorageTransportKind.Nvme:
return "nvme";
case StorageTransportKind.Usb:
return "usb";
case StorageTransportKind.Sd:
return "sd";
case StorageTransportKind.Mmc:
return "mmc";
case StorageTransportKind.Raid:
return "raid";
case StorageTransportKind.Sas:
return "sas";
case StorageTransportKind.Ahci:
return "ahci";
case StorageTransportKind.Virtual:
return "virtual";
case StorageTransportKind.Unknown:
default:
return "disk";
}
}
public void Close() { }
@@ -70,7 +70,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="DiskInfoToolkit" Version="1.2.1" />
<PackageReference Include="DiskInfoToolkit" Version="2.0.0" />
<PackageReference Include="HidSharp" Version="2.6.4" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.269">
<PrivateAssets>all</PrivateAssets>