diff --git a/Plugins.Modbus/Contracts/IModbusClient.cs b/Plugins.Modbus/Contracts/IModbusClient.cs index f7f08100a..ed3246d7b 100644 --- a/Plugins.Modbus/Contracts/IModbusClient.cs +++ b/Plugins.Modbus/Contracts/IModbusClient.cs @@ -2,11 +2,7 @@ public interface IModbusClient : IDisposable { - Task ReadInt32Value(byte unitIdentifier, ushort startingAddress, ushort quantity, - string ipAddressString, - int port, int connectDelay, int timeout, int? minimumResult); - bool DiconnectIfConnected(); - Task ReadInt16Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, int port, int connectDelay, int timeout, int? minimumResult); - Task ReadFloatValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, int port, int connectDelay, int timeout, int? minimumResult); + Task GetByteArray(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, + int port, int connectDelay, int timeout); } diff --git a/Plugins.Modbus/Contracts/IModbusService.cs b/Plugins.Modbus/Contracts/IModbusService.cs index 5550865da..a1fcb1340 100644 --- a/Plugins.Modbus/Contracts/IModbusService.cs +++ b/Plugins.Modbus/Contracts/IModbusService.cs @@ -2,9 +2,6 @@ public interface IModbusService { - Task ReadInt32Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, - int port, int connectDelay, int timeout, int? minimumResult); - - Task ReadInt16Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, int port, int connectDelaySeconds, int timeoutSeconds, int? minimumResult); - Task ReadFloatValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, int port, int connectDelaySeconds, int timeoutSeconds, int? minimumResult); -} \ No newline at end of file + Task ReadValue(byte unitIdentifier, ushort startingAddress, ushort quantity, + string ipAddressString, int port, int connectDelay, int timeout) where T : struct; +} diff --git a/Plugins.Modbus/Controllers/ModbusController.cs b/Plugins.Modbus/Controllers/ModbusController.cs index ddd9f5f7e..2c44b48cc 100644 --- a/Plugins.Modbus/Controllers/ModbusController.cs +++ b/Plugins.Modbus/Controllers/ModbusController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using Plugins.Modbus.Contracts; +using TeslaSolarCharger.Shared.Enums; namespace Plugins.Modbus.Controllers { @@ -14,6 +15,27 @@ public ModbusController(IModbusService modbusService) _modbusService = modbusService; } + public Task GetTypedValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, + int port, int connectDelaySeconds, int timeoutSeconds, ModbusValueType modbusValueType) + { + return modbusValueType switch + { + ModbusValueType.Int => _modbusService.ReadValue(unitIdentifier, startingAddress, quantity, ipAddress, port, + connectDelaySeconds, timeoutSeconds), + ModbusValueType.Float => _modbusService.ReadValue(unitIdentifier, startingAddress, quantity, ipAddress, port, + connectDelaySeconds, timeoutSeconds), + ModbusValueType.Short => _modbusService.ReadValue(unitIdentifier, startingAddress, quantity, ipAddress, port, + connectDelaySeconds, timeoutSeconds), + ModbusValueType.UInt => _modbusService.ReadValue(unitIdentifier, startingAddress, quantity, ipAddress, port, + connectDelaySeconds, timeoutSeconds), + ModbusValueType.UShort => _modbusService.ReadValue(unitIdentifier, startingAddress, quantity, ipAddress, port, + connectDelaySeconds, timeoutSeconds), + ModbusValueType.Ulong => _modbusService.ReadValue(unitIdentifier, startingAddress, quantity, ipAddress, port, + connectDelaySeconds, timeoutSeconds), + _ => throw new ArgumentOutOfRangeException(nameof(modbusValueType), modbusValueType, null) + }; + } + /// /// Gets a Modbus Integer value /// @@ -24,13 +46,12 @@ public ModbusController(IModbusService modbusService) /// The modbus port of the modbus device /// /// - /// Sets a minimum return result. This ist important, if your inverter does not send 0 as power if it is off. /// [Obsolete] [HttpGet] - public Task GetValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, - int port, int connectDelaySeconds, int timeoutSeconds, int? minimumResult = null) - => GetInt32Value(unitIdentifier, startingAddress, quantity, ipAddress, port, connectDelaySeconds, timeoutSeconds, minimumResult); + public Task GetValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, + int port, int connectDelaySeconds, int timeoutSeconds) + => GetTypedValue(unitIdentifier, startingAddress, quantity, ipAddress, port, connectDelaySeconds, timeoutSeconds, ModbusValueType.Int); /// /// Gets a Modbus Int32 value @@ -42,12 +63,12 @@ public Task GetValue(byte unitIdentifier, ushort startingAddress, ushort qu /// The modbus port of the modbus device /// /// - /// Sets a minimum return result. This ist important, if your inverter does not send 0 as power if it is off. /// Modbus value converted to Int32 + [Obsolete] [HttpGet] - public Task GetInt32Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, - int port, int connectDelaySeconds, int timeoutSeconds, int? minimumResult = null) - => _modbusService.ReadInt32Value(unitIdentifier, startingAddress, quantity, ipAddress, port, connectDelaySeconds, timeoutSeconds, minimumResult); + public Task GetInt32Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, + int port, int connectDelaySeconds, int timeoutSeconds) + => GetTypedValue(unitIdentifier, startingAddress, quantity, ipAddress, port, connectDelaySeconds, timeoutSeconds, ModbusValueType.Int); /// /// Gets a Modbus Int16 value @@ -61,10 +82,11 @@ public Task GetInt32Value(byte unitIdentifier, ushort startingAddress, usho /// /// Sets a minimum return result. This ist important, if your inverter does not send 0 as power if it is off. /// Modbus value converted to Int16 + [Obsolete] [HttpGet] - public Task GetInt16Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, + public Task GetInt16Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, int port, int connectDelaySeconds, int timeoutSeconds, int? minimumResult = null) - => _modbusService.ReadInt16Value(unitIdentifier, startingAddress, quantity, ipAddress, port, connectDelaySeconds, timeoutSeconds, minimumResult); + => GetTypedValue(unitIdentifier, startingAddress, quantity, ipAddress, port, connectDelaySeconds, timeoutSeconds, ModbusValueType.Short); /// /// Gets a Modbus Float value @@ -78,10 +100,11 @@ public Task GetInt16Value(byte unitIdentifier, ushort startingAddress, us /// /// Sets a minimum return result. This ist important, if your inverter does not send 0 as power if it is off. /// Modbus value converted to float + [Obsolete] [HttpGet] - public Task GetFloatValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, + public Task GetFloatValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddress, int port, int connectDelaySeconds, int timeoutSeconds, int? minimumResult = null) - => _modbusService.ReadFloatValue(unitIdentifier, startingAddress, quantity, ipAddress, port, connectDelaySeconds, timeoutSeconds, minimumResult); + => GetTypedValue(unitIdentifier, startingAddress, quantity, ipAddress, port, connectDelaySeconds, timeoutSeconds, ModbusValueType.Float); } } diff --git a/Plugins.Modbus/Plugins.Modbus.csproj b/Plugins.Modbus/Plugins.Modbus.csproj index d4643d0a1..ce1915514 100644 --- a/Plugins.Modbus/Plugins.Modbus.csproj +++ b/Plugins.Modbus/Plugins.Modbus.csproj @@ -17,6 +17,10 @@ + + + + PreserveNewest diff --git a/Plugins.Modbus/Services/ModbusClient.cs b/Plugins.Modbus/Services/ModbusClient.cs index e984d7135..db6f6b058 100644 --- a/Plugins.Modbus/Services/ModbusClient.cs +++ b/Plugins.Modbus/Services/ModbusClient.cs @@ -15,26 +15,8 @@ public ModbusClient(ILogger logger) _semaphoreSlim = new SemaphoreSlim(1); } - public async Task ReadInt32Value(byte unitIdentifier, ushort startingAddress, ushort quantity, - string ipAddressString, int port, int connectDelay, int timeout, int? minimumResult) - { - _logger.LogTrace("{method}({unitIdentifier}, {startingAddress}, {quantity}, {ipAddressString}, {port}, " + - "{connectDelay}, {timeout}, {minimumResult})", - nameof(ReadInt32Value), unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout, minimumResult); - - var tmpArrayPowerComplete = await GetByteArray(unitIdentifier, startingAddress, quantity, ipAddressString, port, connectDelay, timeout).ConfigureAwait(false); - _logger.LogTrace("Converting {array} to Int value...", Convert.ToHexString(tmpArrayPowerComplete)); - var intValue = BitConverter.ToInt32(tmpArrayPowerComplete, 0); - if (minimumResult == null) - { - return intValue; - } - return intValue < minimumResult ? (int)minimumResult : intValue; - } - - private async Task GetByteArray(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, - int port, int connectDelay, int timeout) + public async Task GetByteArray(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, + int port, int connectDelay, int timeout) { var tmpArrayPowerComplete = await GetRegisterValue(unitIdentifier, startingAddress, quantity, ipAddressString, port, connectDelay, timeout) @@ -56,44 +38,8 @@ public bool DiconnectIfConnected() return false; } - public async Task ReadInt16Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, int port, - int connectDelay, int timeout, int? minimumResult) - { - _logger.LogTrace("{method}({unitIdentifier}, {startingAddress}, {quantity}, {ipAddressString}, {port}, " + - "{connectDelay}, {timeout}, {minimumResult})", - nameof(ReadInt16Value), unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout, minimumResult); - - var tmpArrayPowerComplete = await GetByteArray(unitIdentifier, startingAddress, quantity, ipAddressString, port, connectDelay, timeout).ConfigureAwait(false); - _logger.LogTrace("Converting {array} to Int value...", Convert.ToHexString(tmpArrayPowerComplete)); - var intValue = BitConverter.ToInt16(tmpArrayPowerComplete, 0); - if (minimumResult == null) - { - return intValue; - } - return intValue < minimumResult ? (short)minimumResult : intValue; - } - - public async Task ReadFloatValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, int port, - int connectDelay, int timeout, int? minimumResult) - { - _logger.LogTrace("{method}({unitIdentifier}, {startingAddress}, {quantity}, {ipAddressString}, {port}, " + - "{connectDelay}, {timeout}, {minimumResult})", - nameof(ReadInt16Value), unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout, minimumResult); - - var tmpArrayPowerComplete = await GetByteArray(unitIdentifier, startingAddress, quantity, ipAddressString, port, connectDelay, timeout).ConfigureAwait(false); - _logger.LogTrace("Converting {array} to Int value...", Convert.ToHexString(tmpArrayPowerComplete)); - var intValue = BitConverter.ToSingle(tmpArrayPowerComplete, 0); - if (minimumResult == null) - { - return intValue; - } - return intValue < minimumResult ? (short)minimumResult : intValue; - } - private async Task GetRegisterValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, - int port, int connectDelay, int timeout) + int port, int connectDelay, int timeout) { ReadTimeout = (int)TimeSpan.FromSeconds(timeout).TotalMilliseconds; WriteTimeout = (int)TimeSpan.FromSeconds(timeout).TotalMilliseconds; @@ -136,18 +82,4 @@ private async Task GetRegisterValue(byte unitIdentifier, ushort starting }); } } - - public static byte[] StringToByteArray(string hex) - { - return Enumerable.Range(0, hex.Length) - .Where(x => x % 2 == 0) - .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) - .ToArray(); - } - - public void Dispose() - { - DiconnectIfConnected(); - _semaphoreSlim.Dispose(); - } } diff --git a/Plugins.Modbus/Services/ModbusService.cs b/Plugins.Modbus/Services/ModbusService.cs index b9bb5fa55..c49306e2c 100644 --- a/Plugins.Modbus/Services/ModbusService.cs +++ b/Plugins.Modbus/Services/ModbusService.cs @@ -14,77 +14,66 @@ public ModbusService(ILogger logger, IServiceProvider serviceProv _serviceProvider = serviceProvider; } - public async Task ReadInt32Value(byte unitIdentifier, ushort startingAddress, ushort quantity, - string ipAddressString, int port, int connectDelay, int timeout, int? minimumResult) + public async Task ReadValue(byte unitIdentifier, ushort startingAddress, ushort quantity, + string ipAddressString, int port, int connectDelay, int timeout) where T : struct { _logger.LogTrace("{method}({unitIdentifier}, {startingAddress}, {quantity}, {ipAddressString}, {port}, " + - "{connectDelay}, {timeout}, {minimumResult})", - nameof(ReadInt32Value), unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout,minimumResult); + "{connectDelay}, {timeout})", + nameof(ReadValue), unitIdentifier, startingAddress, quantity, ipAddressString, port, + connectDelay, timeout); var modbusClient = GetModbusClient(ipAddressString, port); - + byte[] byteArray; + if (timeout < 1) + { + _logger.LogDebug("Timeout is reduced to minimum value of 1 second"); + timeout = 1; + } try { - var value = await modbusClient.ReadInt32Value(unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout, minimumResult).ConfigureAwait(false); - return value; + byteArray = await modbusClient.GetByteArray(unitIdentifier, startingAddress, quantity, ipAddressString, port, connectDelay, timeout) + .ConfigureAwait(false); } catch (Exception ex) { - _logger.LogError(ex, "Could not get value. Dispose modbus client"); + _logger.LogError(ex, "Could not get byte array. Dispose modbus client"); modbusClient.Dispose(); _modbusClients.Remove(GetKeyString(ipAddressString, port)); throw; } - - } - public async Task ReadInt16Value(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, int port, - int connectDelay, int timeout, int? minimumResult) - { - _logger.LogTrace("{method}({unitIdentifier}, {startingAddress}, {quantity}, {ipAddressString}, {port}, " + - "{connectDelay}, {timeout}, {minimumResult})", - nameof(ReadInt16Value), unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout, minimumResult); - var modbusClient = GetModbusClient(ipAddressString, port); + if (typeof(T) == typeof(int)) + { + return (T) Convert.ChangeType(BitConverter.ToInt32(byteArray, 0), typeof(T)); + } - try + if (typeof(T) == typeof(float)) { - var value = await modbusClient.ReadInt16Value(unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout, minimumResult).ConfigureAwait(false); - return value; + return (T)Convert.ChangeType(BitConverter.ToSingle(byteArray, 0), typeof(T)); } - catch (Exception ex) + + if (typeof(T) == typeof(short)) { - _logger.LogError(ex, "Could not get value. Dispose modbus client"); - modbusClient.Dispose(); - _modbusClients.Remove(GetKeyString(ipAddressString, port)); - throw; + return (T)Convert.ChangeType(BitConverter.ToInt16(byteArray, 0), typeof(T)); } - } - public async Task ReadFloatValue(byte unitIdentifier, ushort startingAddress, ushort quantity, string ipAddressString, int port, - int connectDelay, int timeout, int? minimumResult) - { - _logger.LogTrace("{method}({unitIdentifier}, {startingAddress}, {quantity}, {ipAddressString}, {port}, " + - "{connectDelay}, {timeout}, {minimumResult})", - nameof(ReadInt16Value), unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout, minimumResult); - var modbusClient = GetModbusClient(ipAddressString, port); - try + if (typeof(T) == typeof(uint)) { - var value = await modbusClient.ReadFloatValue(unitIdentifier, startingAddress, quantity, ipAddressString, port, - connectDelay, timeout, minimumResult).ConfigureAwait(false); - return value; + return (T)Convert.ChangeType(BitConverter.ToUInt32(byteArray, 0), typeof(T)); } - catch (Exception ex) + + if (typeof(T) == typeof(ushort)) { - _logger.LogError(ex, "Could not get value. Dispose modbus client"); - modbusClient.Dispose(); - _modbusClients.Remove(GetKeyString(ipAddressString, port)); - throw; + return (T)Convert.ChangeType(BitConverter.ToUInt16(byteArray, 0), typeof(T)); } + + if (typeof(T) == typeof(ulong)) + { + return (T)Convert.ChangeType(BitConverter.ToUInt64(byteArray, 0), typeof(T)); + } + + throw new NotImplementedException($"Can not convert value of type: {typeof(T)}"); + } private IModbusClient GetModbusClient(string ipAddressString, int port) diff --git a/TeslaSolarCharger/Shared/Enums/ModbusValueType.cs b/TeslaSolarCharger/Shared/Enums/ModbusValueType.cs new file mode 100644 index 000000000..3557f854f --- /dev/null +++ b/TeslaSolarCharger/Shared/Enums/ModbusValueType.cs @@ -0,0 +1,11 @@ +namespace TeslaSolarCharger.Shared.Enums; + +public enum ModbusValueType +{ + Int, + Float, + Short, + UInt, + UShort, + Ulong, +}