jmarucha / FanControl.Liquidctl

Get access to the pump and temperature sensors of your AIO in FanControl
GNU General Public License v3.0
40 stars 17 forks source link

Can I upgrade only liquidctl.exe? #34

Open sp00n opened 3 months ago

sp00n commented 3 months ago

I have an NZXT Controller hub that apparently is not recognized by this plugin. Executing the included liquidctl.exe with liquidctl.exe list --debug also showed nothing (and a version number 0.0.0-unknown?), so I went to the liquidctl repository and downloaded and build the latest revision, which then did show two recognized units:

I actually wanted to control the Fan Controller, so it should be fine, however the plugin still doesn't recognize anything in Fan Control after having replaced the liquidctl.exe with the newly built one. Do I need to compile the whole project again, or does the code of the DLL itself also need to be updated to support anything new that has been added to liquidtctl?

sp00n commented 3 months ago

Ok, after digging further, the new liquidctl version returns a string value for a status entry ("Fan x control mode"), whereas the DLL only expects float values there:

Log entry:

28/05/2024 03:29:52: Newtonsoft.Json.JsonReaderException: Could not convert string to double: DC. Path '[0].status[0].value', line 1, position 229.
   at Newtonsoft.Json.JsonReader.ReadDoubleString(String s)
   at Newtonsoft.Json.JsonTextReader.FinishReadQuotedNumber(ReadType readType)
   at Newtonsoft.Json.JsonTextReader.ReadAsDouble()
   at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at FanControl.Liquidctl.LiquidctlCLIWrapper.ReadStatus()
   at FanControl.Liquidctl.LiquidctlPlugin.Load(IPluginSensorsContainer _container)
   at FanControl.Domain.BackendProviders.Plugin.PluginBackendProvider.Open()

Result from liquidctl --json --address {address} status:

[
    {
        "address": "\\\\?\\HID#VID_1E71&PID_2011#7&3b3f9bd5&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}",
        "bus": "hid",
        "description": "NZXT RGB & Fan Controller (3+6 channels)",
        "status": [
            {
                "key": "Fan 1 control mode",
                "unit": "",
                "value": "DC"
            },
            {
                "key": "Fan 1 duty",
                "unit": "%",
                "value": 25
            },
        ]
    }
]

The class used for deserializing the result LiquidctlStatusJSON.cs, which expects float as the value type:

using System.Collections.Generic;
namespace FanControl.Liquidctl
{
    public class LiquidctlStatusJSON
    {
        public class StatusRecord
        {
            public string key { get; set; }
            public float? value { get; set; }
            public string unit { get; set; }
        }
        public string bus { get; set; }
        public string address { get; set; }

        public string description { get; set; }

        public List<StatusRecord> status { get; set; }
    }
}
sp00n commented 3 months ago

I fixed this issue by replacing public float? value { get; set; } with public dynamic value { get; set; }

There are other issues however, the current plugin can't handle outputs for multiple fans, e.g. "Fan 1 speed", "Fan 2 speed", etc. I tried to fix this in my modded version, but since I have no real idea about C#, I'm not creating a PR for this. It seems to work though. https://github.com/sp00n/FanControl.Liquidctl