From 83af117ea43ba1989a996fa5e389f85f7304b087 Mon Sep 17 00:00:00 2001 From: Markus Zucker <16736730+irminsul@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:42:11 +0200 Subject: [PATCH] Add Aqua Computer high flow NEXT support (#1268) * Add support for electrical conductivity measurements * Add Aqua Computer high flow NEXT support * Expose alarm flags as hidden binary sensors * Update HighFlowNext.cs * Update ISensor.cs --------- Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com> --- LibreHardwareMonitor/UI/PlotPanel.cs | 1 + LibreHardwareMonitor/UI/SensorGadget.cs | 3 + LibreHardwareMonitor/UI/SensorNode.cs | 3 + LibreHardwareMonitor/UI/SensorNotifyIcon.cs | 3 + LibreHardwareMonitor/UI/TypeNode.cs | 4 + LibreHardwareMonitor/Utilities/HttpServer.cs | 2 + .../AquaComputer/AquaComputerGroup.cs | 8 + .../Controller/AquaComputer/HighFlowNext.cs | 139 ++++++++++++++++++ LibreHardwareMonitorLib/Hardware/ISensor.cs | 1 + 9 files changed, 164 insertions(+) create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/HighFlowNext.cs diff --git a/LibreHardwareMonitor/UI/PlotPanel.cs b/LibreHardwareMonitor/UI/PlotPanel.cs index bb0802b..cd3957d 100644 --- a/LibreHardwareMonitor/UI/PlotPanel.cs +++ b/LibreHardwareMonitor/UI/PlotPanel.cs @@ -231,6 +231,7 @@ public class PlotPanel : UserControl { SensorType.Frequency, "Hz" }, { SensorType.Energy, "mWh" }, { SensorType.Noise, "dBA" }, + { SensorType.Conductivity, "µS/cm" }, { SensorType.Humidity, "%" } }; diff --git a/LibreHardwareMonitor/UI/SensorGadget.cs b/LibreHardwareMonitor/UI/SensorGadget.cs index 84e93c5..f986ff3 100644 --- a/LibreHardwareMonitor/UI/SensorGadget.cs +++ b/LibreHardwareMonitor/UI/SensorGadget.cs @@ -650,6 +650,9 @@ public class SensorGadget : Gadget case SensorType.Noise: format = "{0:F0} dBA"; break; + case SensorType.Conductivity: + format = "{0:F1} µS/cm"; + break; } if (sensor.SensorType == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) diff --git a/LibreHardwareMonitor/UI/SensorNode.cs b/LibreHardwareMonitor/UI/SensorNode.cs index 505977a..bf2ab7f 100644 --- a/LibreHardwareMonitor/UI/SensorNode.cs +++ b/LibreHardwareMonitor/UI/SensorNode.cs @@ -82,6 +82,9 @@ public class SensorNode : Node case SensorType.Noise: Format = "{0:F0} dBA"; break; + case SensorType.Conductivity: + Format = "{0:F1} µS/cm"; + break; case SensorType.Humidity: Format = "{0:F0} %"; break; diff --git a/LibreHardwareMonitor/UI/SensorNotifyIcon.cs b/LibreHardwareMonitor/UI/SensorNotifyIcon.cs index 5987efb..33d2e5e 100644 --- a/LibreHardwareMonitor/UI/SensorNotifyIcon.cs +++ b/LibreHardwareMonitor/UI/SensorNotifyIcon.cs @@ -174,6 +174,7 @@ public class SensorNotifyIcon : IDisposable case SensorType.SmallData: case SensorType.Factor: case SensorType.Throughput: + case SensorType.Conductivity: return $"{Sensor.Value:F1}"; case SensorType.Control: case SensorType.Frequency: @@ -260,8 +261,10 @@ public class SensorNotifyIcon : IDisposable case SensorType.Factor: format = "\n{0}: {1:F3} GB"; break; case SensorType.Energy: format = "\n{0}: {0:F0} mWh"; break; case SensorType.Noise: format = "\n{0}: {0:F0} dBA"; break; + case SensorType.Conductivity: format = "\n{0}: {0:F1} µS/cm"; break; case SensorType.Humidity: format = "\n{0}: {0:F0} %"; break; } + string formattedValue = string.Format(format, Sensor.Name, Sensor.Value); if (Sensor.SensorType == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) diff --git a/LibreHardwareMonitor/UI/TypeNode.cs b/LibreHardwareMonitor/UI/TypeNode.cs index 96d3ea7..f2a8178 100644 --- a/LibreHardwareMonitor/UI/TypeNode.cs +++ b/LibreHardwareMonitor/UI/TypeNode.cs @@ -95,6 +95,10 @@ public sealed class TypeNode : Node, IExpandPersistNode Image = Utilities.EmbeddedResources.GetImage("loudspeaker.png"); Text = "Noise Levels"; break; + case SensorType.Conductivity: + Image = Utilities.EmbeddedResources.GetImage("voltage.png"); + Text = "Conductivities"; + break; case SensorType.Humidity: Image = Utilities.EmbeddedResources.GetImage("humidity.png"); Text = "Humidity Levels"; diff --git a/LibreHardwareMonitor/Utilities/HttpServer.cs b/LibreHardwareMonitor/Utilities/HttpServer.cs index 1d7d203..14d0d19 100644 --- a/LibreHardwareMonitor/Utilities/HttpServer.cs +++ b/LibreHardwareMonitor/Utilities/HttpServer.cs @@ -677,6 +677,8 @@ public class HttpServer return "power.png"; case SensorType.Noise: return "loudspeaker.png"; + case SensorType.Conductivity: + return "voltage.png"; case SensorType.Throughput: return "throughput.png"; case SensorType.Humidity: diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquaComputerGroup.cs b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquaComputerGroup.cs index c753063..482fa11 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquaComputerGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquaComputerGroup.cs @@ -86,6 +86,14 @@ public class AquaComputerGroup : IGroup _hardware.Add(farbwerk); break; + case 0xF012: + var highflownext = new HighFlowNext(dev, settings); + _report.AppendLine($"Device name: {productName}"); + _report.AppendLine($"Firmware version: {highflownext.FirmwareVersion}"); + _report.AppendLine(); + _hardware.Add(highflownext); + break; + default: _report.AppendLine($"Unknown Hardware PID: {dev.ProductID} Name: {productName}"); _report.AppendLine(); diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/HighFlowNext.cs b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/HighFlowNext.cs new file mode 100644 index 0000000..646f21e --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/HighFlowNext.cs @@ -0,0 +1,139 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) LibreHardwareMonitor and Contributors. +// All Rights Reserved. + +using System; +using HidSharp; + +namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer; + +internal sealed class HighFlowNext : Hardware +{ + private readonly byte[] _rawData = new byte[1025]; + private readonly HidStream _stream; + private readonly Sensor[] _temperatures = new Sensor[2]; + private readonly Sensor[] _flows = new Sensor[1]; + private readonly Sensor[] _levels = new Sensor[1]; + private readonly Sensor[] _powers = new Sensor[1]; + private readonly Sensor[] _conductivities = new Sensor[1]; + private readonly Sensor[] _voltages = new Sensor[2]; + private readonly Sensor[] _alarms = new Sensor[4]; + + public HighFlowNext(HidDevice dev, ISettings settings) : base("high flow NEXT", new Identifier("aquacomputer", "hfn", dev.GetSerialNumber().Replace(" ", "")), settings) + { + if (dev.TryOpen(out _stream)) + { + // Reading output report instead of feature report, as the measurements are in the output report. + _stream.Read(_rawData); + + FirmwareVersion = ReadUInt16BE(_rawData, 13); + + _temperatures[0] = new Sensor("Water Temperature", 0, SensorType.Temperature, this, settings); + ActivateSensor(_temperatures[0]); + + _temperatures[1] = new Sensor("External Temperature", 1, SensorType.Temperature, this, settings); + ActivateSensor(_temperatures[1]); + + _flows[0] = new Sensor("Flow", 0, SensorType.Flow, this, settings); + ActivateSensor(_flows[0]); + + _levels[0] = new Sensor("Water Quality", 0, SensorType.Level, this, settings); + ActivateSensor(_levels[0]); + + _powers[0] = new Sensor("Dissipated Power", 0, SensorType.Power, this, settings); + ActivateSensor(_powers[0]); + + _conductivities[0] = new Sensor("Conductivity", 0, SensorType.Conductivity, this, settings); + ActivateSensor(_conductivities[0]); + + _voltages[0] = new Sensor("VCC", 0, SensorType.Voltage, this, settings); + ActivateSensor(_voltages[0]); + + _voltages[1] = new Sensor("VCC USB", 1, SensorType.Voltage, this, settings); + ActivateSensor(_voltages[1]); + + _alarms[0] = new Sensor("Flow Alarm", 0, true, SensorType.Factor, this, null, settings); + ActivateSensor(_alarms[0]); + + _alarms[1] = new Sensor("Water Temperature Alarm", 1, true, SensorType.Factor, this, null, settings); + ActivateSensor(_alarms[0]); + + _alarms[2] = new Sensor("External Temperature Alarm", 2, true, SensorType.Factor, this, null, settings); + ActivateSensor(_alarms[0]); + + _alarms[3] = new Sensor("Water Quality Alarm", 3, true, SensorType.Factor, this, null, settings); + ActivateSensor(_alarms[0]); + } + } + + public ushort FirmwareVersion { get; } + + public override HardwareType HardwareType + { + get { return HardwareType.Cooler; } + } + + public override void Close() + { + _stream.Close(); + base.Close(); + } + + public override void Update() + { + // Reading output report instead of feature report, as the measurements are in the output report. + _stream.Read(_rawData); + + _temperatures[0].Value = ReadUInt16BE(_rawData, 85) / 100f; // Water Temperature + + // External Temperature. + ushort rawExtTempValue = ReadUInt16BE(_rawData, 87); + bool externalTempSensorConnected = rawExtTempValue != short.MaxValue; + + if (externalTempSensorConnected) + { + _temperatures[1].Value = rawExtTempValue / 100f; + } + else + { + // No external temp sensor connected. + _temperatures[1].Value = null; + } + + _flows[0].Value = ReadUInt16BE(_rawData, 81) / 10f; // Flow + + + _levels[0].Value = ReadUInt16BE(_rawData, 89) / 100f; // Water Quality + + // Dissipated Power. + if (externalTempSensorConnected) + { + _powers[0].Value = ReadUInt16BE(_rawData, 91); + } + else + { + // Power calculation requires the external temp sensor to be connected. + _powers[0].Value = null; + } + + _conductivities[0].Value = ReadUInt16BE(_rawData, 95) / 10f; // Conductivity + + _voltages[0].Value = ReadUInt16BE(_rawData, 97) / 100f; // VCC + _voltages[1].Value = ReadUInt16BE(_rawData, 99) / 100f; // VCC USB + + _alarms[0].Value = (_rawData[116] & 0x02) >> 1; // Flow alarm + _alarms[1].Value = (_rawData[116] & 0x04) >> 2; // Water temperature alarm + _alarms[2].Value = (_rawData[116] & 0x08) >> 3; // External temperature alarm + _alarms[3].Value = (_rawData[116] & 0x10) >> 4; // Water quality alarm + + // Unused: + // _rawData[101..104] -> Total pumped volume liters + // _rawData[105..109] -> Internal impulse counter from flow meter + } + + private ushort ReadUInt16BE(byte[] value, int startIndex) + { + return (ushort)(value[startIndex + 1] | (value[startIndex] << 8)); + } +} diff --git a/LibreHardwareMonitorLib/Hardware/ISensor.cs b/LibreHardwareMonitorLib/Hardware/ISensor.cs index 802c5db..f0e9bcb 100644 --- a/LibreHardwareMonitorLib/Hardware/ISensor.cs +++ b/LibreHardwareMonitorLib/Hardware/ISensor.cs @@ -32,6 +32,7 @@ public enum SensorType TimeSpan, // Seconds Energy, // milliwatt-hour (mWh) Noise, // dBA + Conductivity, // µS/cm Humidity // % }