diff --git a/csharp/App/SchneiderMeterDriver/Config.cs b/csharp/App/SchneiderMeterDriver/Config.cs index dbe60ebf8..eb127b489 100644 --- a/csharp/App/SchneiderMeterDriver/Config.cs +++ b/csharp/App/SchneiderMeterDriver/Config.cs @@ -19,33 +19,33 @@ public static class Config public static readonly TimeSpan UpdatePeriod = TimeSpan.FromSeconds(1); public static readonly IReadOnlyList Signals = new List - { - // new(s => s..CurrentL1, "/Ac/L1/Current", "0.0 A"), - // new(s => s..CurrentL2, "/Ac/L2/Current", "0.0 A"), - // new(s => s..CurrentL3, "/Ac/L3/Current", "0.0 A"), - // new(s => s..CurrentL1 + s.Ac.L2.Current + s.Ac.L3.Current, "/Ac/Current", "0.0 A"), + { + new Signal(s => s._CurrentL1, "/Ac/L1/Current", "0.0 A"), + new Signal(s => s._CurrentL2, "/Ac/L2/Current", "0.0 A"), + new Signal(s => s._CurrentL3, "/Ac/L3/Current", "0.0 A"), + new Signal(s => s._CurrentL1 + s._CurrentL2 + s._CurrentL3, "/Ac/Current", "0.0 A"), - // new(s => s.Ac.L1.Voltage, "/Ac/L1/Voltage", "0.0 A"), - // new(s => s.Ac.L2.Voltage, "/Ac/L2/Voltage", "0.0 A"), - // new(s => s.Ac.L3.Voltage, "/Ac/L3/Voltage", "0.0 A"), - // new(s => (s.Ac.L1.Voltage + s.Ac.L2.Voltage + s.Ac.L3.Voltage) / 3.0m, "/Ac/Voltage", "0.0 A"), + new Signal(s => s._VoltageL1N, "/Ac/L1/Voltage", "0.0 V"), + new Signal(s => s._VoltageL2N, "/Ac/L2/Voltage", "0.0 V"), + new Signal(s => s._VoltageL3N, "/Ac/L3/Voltage", "0.0 V"), + new Signal(s => (s._VoltageL1N + s._VoltageL2N + s._VoltageL3N) / 3.0f, "/Ac/Voltage", "0.0 V"), new Signal(s => s.ActivePowerL1, "/Ac/L1/Power", "0 W"), new Signal(s => s.ActivePowerL2, "/Ac/L2/Power", "0 W"), new Signal(s => s.ActivePowerL3, "/Ac/L3/Power", "0 W"), - new Signal(s => s.ActivePowerL1 + s.ActivePowerL2 + s.ActivePowerL3, "/Ac/Power", "0 W"), - - // new(s => s.EnergyImportL123, "Ac/Energy/Forward", "0.00 kWh"), - // new(s => s.EnergyExportL123, "Ac/Energy/Reverse", "0.00 kWh"), - // - // new(s => s.EnergyImportL1, "Ac/L1/Energy/Forward", "0.00 kWh"), - // new(s => s.EnergyExportL1, "Ac/L1/Energy/Reverse", "0.00 kWh"), - // - // new(s => s.EnergyImportL2, "Ac/L2/Energy/Forward", "0.00 kWh"), - // new(s => s.EnergyExportL2, "Ac/L2/Energy/Reverse", "0.00 kWh"), - // - // new(s => s.EnergyImportL3, "Ac/L3/Energy/Forward", "0.00 kWh"), - // new(s => s.EnergyExportL3, "Ac/L3/Energy/Reverse", "0.00 kWh"), + new Signal(s => s.ActivePowerL1 + s.ActivePowerL2 + s.ActivePowerL3, "/Ac/Power", "0 W"), + + + new Signal(s => s.TotalActiveImport, "Ac/Energy/Forward", "0.00 kWh"), + new Signal(s => s.TotalActiveExport, "Ac/Energy/Reverse", "0.00 kWh"), + new Signal(s => s.ActiveEnergyImportL1, "Ac/L1/Energy/Forward", "0.00 kWh"), + // new(s => s.EnergyExportL1, "Ac/L1/Energy/Reverse", "0.00 kWh"), + // + new Signal(s => s.ActiveEnergyImportL2, "Ac/L2/Energy/Forward", "0.00 kWh"), + // new(s => s.EnergyExportL2, "Ac/L2/Energy/Reverse", "0.00 kWh"), + // + new Signal(s => s.ActiveEnergyImportL3, "Ac/L3/Energy/Forward", "0.00 kWh"), + // new(s => s.EnergyExportL3, "Ac/L3/Energy/Reverse", "0.00 kWh"), }; public static VeProperties DefaultProperties => new VeProperties diff --git a/csharp/App/SchneiderMeterDriver/Program.cs b/csharp/App/SchneiderMeterDriver/Program.cs index b447c8933..404068d21 100644 --- a/csharp/App/SchneiderMeterDriver/Program.cs +++ b/csharp/App/SchneiderMeterDriver/Program.cs @@ -13,10 +13,26 @@ Console.WriteLine("Starting Schneider Driver " + Config.Version); var networkInterfaces = await Nic.GetNetworkInterfaces(); +Console.WriteLine("Retrieved network interfaces"); + +// Log all network interfaces and their properties +foreach (var nic in networkInterfaces) +{ + Console.WriteLine($"Interface: {nic.Name}"); + Console.WriteLine($" IsUp: {nic.IsUp}"); + Console.WriteLine($" IsEthernet: {nic.IsEthernet}"); + Console.WriteLine($" IP4 Addresses: {string.Join(", ", nic.Ip4Addresses)}"); +} + var candidates = networkInterfaces.Where(n => n.IsUp && n.IsEthernet && (!n.Ip4Addresses.Any() || n.Ip4Addresses.Contains(Config.OwnAddress))); +if (!candidates.Any()) +{ + Console.WriteLine("No suitable network interfaces found."); +} + foreach (var nic in candidates) { Console.WriteLine($"Found new network interface: {nic.Name}"); @@ -43,7 +59,10 @@ foreach (var nic in candidates) if (ping) { Console.WriteLine($"Got answer from {Config.PeerAddress}"); - var ex = await SchneiderMeterDriver.Run($"{Config.PeerAddress}:{Config.PeerPort}", Bus.System); + //SchneiderMeterDriver.Run(Config.PeerAddress, Config.PeerPort, Bus.System); + + //Console.WriteLine($"{nameof(SchneiderMeterDriver)} FAILED with\n"); + var ex = await SchneiderMeterDriver.Run(Config.PeerAddress, Config.PeerPort, Bus.System); Console.WriteLine($"{nameof(SchneiderMeterDriver)} FAILED with\n{ex}"); } diff --git a/csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.cs b/csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.cs index 2953e9cd4..5a5fb4280 100644 --- a/csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.cs +++ b/csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.cs @@ -1,4 +1,4 @@ -/*using System.Reactive.Linq; +using System.Reactive.Linq; using InnovEnergy.Lib.Devices.IEM3kGridMeter; using InnovEnergy.Lib.Protocols.DBus; using InnovEnergy.Lib.Protocols.Modbus.Clients; @@ -10,11 +10,11 @@ namespace InnovEnergy.App.SchneiderDriver; public static class SchneiderMeterDriver { + public static Task Run(String hostName, Bus dbusAddress) { return Run(hostName, ModbusTcpClient.DefaultPort, dbusAddress); } - public static async Task Run(String hostName, UInt16 port, Bus dbusAddress) { // var ep = new UnixDomainSocketEndPoint("/home/eef/graber_dbus.sock"); @@ -30,39 +30,72 @@ public static class SchneiderMeterDriver .Publish(); var x = schneider.Read(); - - x?.ActivePowerL1.WriteLine(); - x?.ActivePowerL2.WriteLine(); - x?.ActivePowerL3.WriteLine(); + // Print the output of schneider.Read() + if (x != null) + { + Console.WriteLine("Schneider Read Output:"); + Console.WriteLine($"ActivePowerL1: {x.ActivePowerL1}"); + Console.WriteLine($"ActivePowerL2: {x.ActivePowerL2}"); + Console.WriteLine($"ActivePowerL3: {x.ActivePowerL3}"); + // Add more properties if needed + } + else + { + Console.WriteLine("Failed to read data from Schneider device."); + } var poller = schneiderStatus.Connect(); var properties = Config.DefaultProperties; - - foreach (var p in properties) - { - p.WriteLine(" Signal"); - } + // Step 1: Access Config.Signals var signalsCollection = Config.Signals; - - foreach (var s in signalsCollection) - { - s.WriteLine(" Signal"); - } - var signals = Config + /*var signals = Config .Signals .Select(signal => schneiderStatus.Select(signal.ToVeProperty)) .Merge() - .Do(p => properties.Set(p)); + .Do(p => properties.Set(p));*/ + + var signals = Config + .Signals + .Select(signal => schneiderStatus + .Select(reading => + { + var property = signal.ToVeProperty(reading); + if (property == null) + { + Console.WriteLine($"Warning: Signal {signal} produced a null property."); + } + else + { + Console.WriteLine($"Transformed Signal to Property: {property}"); + } + return property; + }) + .Where(property => property != null)) + .Merge() + .Do(p => + { + Console.WriteLine($"Setting property: {p}"); + properties.Set(p); + }); + + // Log initial signals + /*Console.WriteLine("Initial Signals:"); + foreach (var signal in signalsCollection) + { + Console.WriteLine($"Signal: {signal}"); + }*/ // TODO: remove when possible // Apparently some VE services need to be periodically reminded that // this service is /Connected + Console.WriteLine("Goes to subscribe"); schneiderStatus.Subscribe(_ => properties.Set("/Connected", 1)); + Console.WriteLine("Subscribed successfully"); // Wait until status is read once to make sure all // properties are set when we go onto the bus. @@ -72,9 +105,9 @@ public static class SchneiderMeterDriver .SelectMany(_ => PublishPropertiesOnDBus(properties, dbusAddress)); return await signals - .MergeErrors(dbus) - .Finally(poller.Dispose) - .SelectErrors(); + .MergeErrors(dbus) + .Finally(poller.Dispose) + .SelectErrors(); } @@ -84,70 +117,6 @@ public static class SchneiderMeterDriver Console.WriteLine($"Connecting to DBus {bus}"); return properties.PublishOnDBus(bus, Config.BusName); } -}*/ - -using System; -using System.Reactive.Linq; -using InnovEnergy.Lib.Devices.IEM3kGridMeter; -using InnovEnergy.Lib.Protocols.DBus; -using InnovEnergy.Lib.Protocols.Modbus.Clients; -using InnovEnergy.Lib.Utils; -using InnovEnergy.Lib.Victron.VeDBus; - -namespace InnovEnergy.App.SchneiderDriver -{ - public static class SchneiderMeterDriver - { - public static Task Run(string hostName, Bus dbusAddress) - { - return Run(hostName, ModbusTcpClient.DefaultPort, dbusAddress); - } - - public static async Task Run(string hostName, ushort port, Bus dbusAddress) - { - var schneider = new Iem3KGridMeterDevice(hostName, port, Config.ModbusNodeId); - var schneiderStatus = Observable - .Interval(Config.UpdatePeriod) - .Select(_ => - { - var status = schneider.Read(); - if (status == null) - { - Console.WriteLine("Failed to read data from Iem3KGridMeterDevice"); - } - return status; - }) - .Where(status => status != null) // Ignore null readings - .Publish(); - - var poller = schneiderStatus.Connect(); - var properties = Config.DefaultProperties; - - var signals = Config - .Signals - .Select(signal => schneiderStatus.Select(signal.ToVeProperty)) - .Merge() - .Do(p => properties.Set(p)); - - schneiderStatus.Subscribe(_ => properties.Set("/Connected", 1)); - - var dbus = schneiderStatus - .Skip(1) - .Take(1) - .SelectMany(_ => PublishPropertiesOnDBus(properties, dbusAddress)); - - return await signals - .MergeErrors(dbus) - .Finally(poller.Dispose) - .SelectErrors(); - } - - private static Task PublishPropertiesOnDBus(VeProperties properties, Bus bus) - { - Console.WriteLine($"Connecting to DBus {bus}"); - return properties.PublishOnDBus(bus, Config.BusName); - } - } } diff --git a/csharp/App/SchneiderMeterDriver/Signal.cs b/csharp/App/SchneiderMeterDriver/Signal.cs index e7eba2bec..a6354878e 100644 --- a/csharp/App/SchneiderMeterDriver/Signal.cs +++ b/csharp/App/SchneiderMeterDriver/Signal.cs @@ -20,7 +20,45 @@ using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes; using InnovEnergy.Lib.Victron.VeDBus; using System; + namespace InnovEnergy.App.SchneiderDriver +{ + public record Signal(Func Source, ObjectPath Path, string Format = "") + { + // Converts the status object to a VeProperty, handling null status gracefully + public VeProperty ToVeProperty(Iem3KGridMeterRegisters status) + { + // Check if status is null and log a message + if (status == null) + { + Console.WriteLine($"Status is null for path: {Path}"); + // Return a default VeProperty if status is null + return new VeProperty(Path, default(double), string.Format($"{{0:{Format}}}", default(double))); + } + + // Retrieve the value using the provided source function + var value = Source(status); + + // Handle the case where the value itself might be null + if (value == null) + { + Console.WriteLine($"Value is null for path: {Path}"); + // Return a default VeProperty if value is null + return new VeProperty(Path, default(double), string.Format($"{{0:{Format}}}", default(double))); + } + + if (value is float floatValue) + { + value = (double)floatValue; + } + + // Create and return the VeProperty with the actual value and format + return new VeProperty(Path, value, string.Format($"{{0:{Format}}}", value)); + } + } +} + +/*namespace InnovEnergy.App.SchneiderDriver { public record Signal(Func Source, ObjectPath Path, string Format = "") { @@ -37,7 +75,7 @@ namespace InnovEnergy.App.SchneiderDriver return new VeProperty(Path, value, String.Format($"{{0:{Format}}}", value)); } } -} +}*/ diff --git a/csharp/App/SchneiderMeterDriver/debug.sh b/csharp/App/SchneiderMeterDriver/debug.sh index e68489b70..a274b1111 100755 --- a/csharp/App/SchneiderMeterDriver/debug.sh +++ b/csharp/App/SchneiderMeterDriver/debug.sh @@ -4,15 +4,21 @@ csproj="SchneiderMeterDriver.csproj" exe="SchneiderMeterDriver" #remote="10.2.1.6" remote="10.2.4.155" - -netVersion="net6.0" platform="linux-arm" +netVersion="net6.0" config="Release" host="root@$remote" dir="/opt/innovenergy/$exe" set -e +# Detect the current platform +#if uname -m | grep -i 'arm' > /dev/null; then + +#else + # platform="linux-x64" +#fi + dotnet publish "$csproj" -c $config -r $platform -p:SuppressTrimmAnalysisWarnings=true -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false --self-contained true rsync -av "bin/$config/$netVersion/$platform/publish/" "$host:$dir" #clear diff --git a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs index 7a1106c5f..e93e75cb0 100644 --- a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs +++ b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs @@ -1,4 +1,4 @@ -/*using InnovEnergy.Lib.Protocols.Modbus.Channels; +using InnovEnergy.Lib.Protocols.Modbus.Channels; using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Slaves; using InnovEnergy.Lib.Utils; @@ -49,83 +49,7 @@ public class Iem3KGridMeterDevice: ModbusDevice } -}*/ - -using InnovEnergy.Lib.Protocols.Modbus.Channels; -using InnovEnergy.Lib.Protocols.Modbus.Clients; -using InnovEnergy.Lib.Protocols.Modbus.Slaves; -using InnovEnergy.Lib.Utils; -using System; - -namespace InnovEnergy.Lib.Devices.IEM3kGridMeter -{ - public class Iem3KGridMeterDevice : ModbusDevice - { - private readonly string _hostname; - private readonly ushort _port; - private readonly byte _slaveId; - - public Iem3KGridMeterDevice(string hostname, ushort port = 502, byte slaveId = 1) - : this(new TcpChannel(hostname, port), slaveId) - { - _hostname = hostname ?? throw new ArgumentNullException(nameof(hostname)); - _port = port; - _slaveId = slaveId; - } - - private Iem3KGridMeterDevice(TcpChannel channel, byte slaveId = 1) - : base(new ModbusTcpClient(channel, slaveId)) - { - _hostname = channel.Host; - _port = channel.Port; - _slaveId = slaveId; - Console.WriteLine($"Initializing Iem3KGridMeterDevice with channel: {channel.Host}:{channel.Port}"); - } - - public Iem3KGridMeterDevice(ModbusClient client) - : base(client) - { - if (client is ModbusTcpClient tcpClient) - { - _hostname = tcpClient.Channel.Host; - _port = tcpClient.Channel.Port; - _slaveId = tcpClient.SlaveId; - } - else - { - throw new ArgumentException("Invalid client type", nameof(client)); - } - Console.WriteLine("Initializing Iem3KGridMeterDevice with ModbusClient"); - } - - public new Iem3KGridMeterRegisters? Read() - { - try - { - Console.WriteLine($"Attempting to read data from {_hostname}:{_port} with slaveId {_slaveId}"); - return base.Read(); - } - catch (Exception ex) - { - Console.WriteLine($"Failed to read data from {nameof(Iem3KGridMeterDevice)}: {ex.Message}"); - return null; - } - } - - public new void Write(Iem3KGridMeterRegisters registers) - { - try - { - base.Write(registers); - } - catch (Exception ex) - { - Console.WriteLine($"Failed to write data to {nameof(Iem3KGridMeterDevice)}: {ex.Message}"); - } - } - } } - diff --git a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs index fb0183b76..b6e16b630 100644 --- a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs +++ b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs @@ -22,13 +22,24 @@ public class Iem3KGridMeterRegisters //: IAc3Meter [HoldingRegister(3056)] public Float32 ActivePowerL2; [HoldingRegister(3058)] public Float32 ActivePowerL3; - //[HoldingRegister(3000)] private Float32 _CurrentL1; - //[HoldingRegister(3002)] private Float32 _CurrentL2; - //[HoldingRegister(3004)] private Float32 _CurrentL3; + [HoldingRegister(3000)] public Float32 _CurrentL1; + [HoldingRegister(3002)] public Float32 _CurrentL2; + [HoldingRegister(3004)] public Float32 _CurrentL3; // - //[HoldingRegister(3028)] private Float32 _VoltageL1N; - //[HoldingRegister(3030)] private Float32 _VoltageL2N; - //[HoldingRegister(3032)] private Float32 _VoltageL3N; + [HoldingRegister(3028)] public Float32 _VoltageL1N; + [HoldingRegister(3030)] public Float32 _VoltageL2N; + [HoldingRegister(3032)] public Float32 _VoltageL3N; + + [HoldingRegister(3518)] public Float32 ActiveEnergyImportL1; + [HoldingRegister(3522)] public Float32 ActiveEnergyImportL2; + [HoldingRegister(3526)] public Float32 ActiveEnergyImportL3; + + [HoldingRegister(45100)] public Float32 TotalActiveImport; + [HoldingRegister(45102)] public Float32 TotalActiveExport; + + + + // //[HoldingRegister(3110)] private Float32 _Frequency; @@ -36,10 +47,6 @@ public class Iem3KGridMeterRegisters //: IAc3Meter //[HoldingRegister(9014)] private Float32 _ReactivePowerL2; //[HoldingRegister(9016)] private Float32 _ReactivePowerL3; - //[HoldingRegister(9012)] private Float32 _ReactivePowerL1; - //[HoldingRegister(9014)] private Float32 _ReactivePowerL2; - //[HoldingRegister(9016)] private Float32 _ReactivePowerL3; - //[HoldingRegister(9022)] private Float32 _ApparentPowerL1; //[HoldingRegister(9024)] private Float32 _ApparentPowerL2; //[HoldingRegister(9026)] private Float32 _ApparentPowerL3; diff --git a/csharp/Lib/Protocols/Modbus/Channels/RemoteSerialChannel.cs b/csharp/Lib/Protocols/Modbus/Channels/RemoteSerialChannel.cs index c42299221..98ecd1cd5 100644 --- a/csharp/Lib/Protocols/Modbus/Channels/RemoteSerialChannel.cs +++ b/csharp/Lib/Protocols/Modbus/Channels/RemoteSerialChannel.cs @@ -4,7 +4,7 @@ using System.Reactive.Linq; using CliWrap; using InnovEnergy.Lib.Utils; -/*namespace InnovEnergy.Lib.Protocols.Modbus.Channels; +namespace InnovEnergy.Lib.Protocols.Modbus.Channels; public record RemoteSerialConnection ( @@ -207,93 +207,4 @@ public class RemoteSerialChannel : ConnectionChannel { connection.Write(data); } -}*/ - -using System; -using System.IO.Ports; -using CliWrap; -using InnovEnergy.Lib.Utils; - -namespace InnovEnergy.Lib.Protocols.Modbus.Channels -{ - public class RemoteSerialChannel : ConnectionChannel, IDisposable - { - private readonly Command _Command; - private readonly TcpChannel _TcpChannel; - - const string SsDir = "/opt/victronenergy/serial-starter"; - const string KillTasks = "kill $!"; - - private CancellationTokenSource _CancellationTokenSource = new CancellationTokenSource(); - - private CommandTask? _CommandTask; - - public RemoteSerialChannel(SshHost host, string tty, int baudRate, Parity parity, int dataBits, int stopBits) - { - const int port = 6855; - - tty = tty.EnsureStartsWith("/dev/"); - - var configureTty = ConfigureTty(tty, baudRate, parity, stopBits, dataBits); - - var stopTty = $"{SsDir}/stop-tty.sh {tty}"; - var startTty = $"{SsDir}/start-tty.sh {tty}"; - - var socat = $"socat TCP-LISTEN:{port},nodelay {tty},raw"; - - var script = $"{configureTty} && {socat}"; - - _Command = host.Command.AppendArgument(script); - _TcpChannel = new TcpChannel(host.HostName, port); - } - - private static string ConfigureTty(string tty, int baudRate, Parity parity, int stopBits, int dataBits) - { - var oParity = parity switch - { - Parity.Even => "parenb -parodd", - Parity.Odd => "parenb parodd", - Parity.None => "-parenb", - _ => throw new NotImplementedException() - }; - - var oStopBits = stopBits switch - { - 1 => "-cstopb", - 2 => "cstopb", - _ => throw new NotImplementedException() - }; - - var oDataBits = "cs" + dataBits; - - return $"stty -F {tty} {baudRate} {oDataBits} {oStopBits} {oParity}"; - } - - protected override TcpChannel Open() - { - return _TcpChannel; - } - - protected override void Close(TcpChannel connection) - { - _CancellationTokenSource.Cancel(); - connection.Dispose(); - _CancellationTokenSource = new CancellationTokenSource(); - } - - protected override IReadOnlyList Read(TcpChannel connection, int nBytes) - { - return connection.Read(nBytes); - } - - protected override void Write(TcpChannel connection, IReadOnlyList data) - { - connection.Write(data); - } - - public void Dispose() - { - Close(_TcpChannel); - } - } -} +} \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs b/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs index f1f39a09a..22a20d018 100644 --- a/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs +++ b/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs @@ -2,7 +2,7 @@ using System.Net.Sockets; using InnovEnergy.Lib.Protocols.Modbus.Protocol; using InnovEnergy.Lib.Utils.Net; -/*namespace InnovEnergy.Lib.Protocols.Modbus.Channels; +namespace InnovEnergy.Lib.Protocols.Modbus.Channels; public class TcpChannel : ConnectionChannel { @@ -82,104 +82,4 @@ public class TcpChannel : ConnectionChannel var array = data.ToArray(); tcpClient.GetStream().Write(array, 0, array.Length); } -}*/ - -using System; -using System.Net.Sockets; - -namespace InnovEnergy.Lib.Protocols.Modbus.Channels -{ - public class TcpChannel : Channel, IDisposable - { - public string Host { get; } - public ushort Port { get; } - - private const int TimeoutMs = 500; // TODO: parametrize - private Socket? Socket { get; set; } - private byte[] Buffer { get; } - - public TcpChannel(string hostname, ushort port) - { - Host = hostname ?? throw new ArgumentNullException(nameof(hostname)); - Port = port; - Buffer = new byte[8192]; // Buffer size can be adjusted - } - - public override IReadOnlyList Read(int nBytes) - { - if (Socket == null) - throw new InvalidOperationException("Socket is not connected."); - - var buffer = new byte[nBytes]; - int bytesRead = 0; - - while (bytesRead < nBytes) - { - var read = Socket.Receive(buffer, bytesRead, nBytes - bytesRead, SocketFlags.None); - if (read == 0) - throw new Exception("Socket closed."); - - bytesRead += read; - } - - return buffer; - } - - public override void Write(IReadOnlyList bytes) - { - if (Socket == null) - throw new InvalidOperationException("Socket is not connected."); - - Socket.Send(bytes.ToArray(), SocketFlags.None); - } - - public void Connect() - { - if (Socket != null) - return; - - Socket = new Socket(SocketType.Stream, ProtocolType.Tcp) - { - Blocking = true, - NoDelay = true, - LingerState = new LingerOption(false, 0), - ReceiveTimeout = TimeoutMs, - SendTimeout = TimeoutMs - }; - - var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeoutMs); - - try - { - Socket.ConnectAsync(Host, Port).Wait(TimeoutMs); - } - catch - { - Socket = null; - throw; - } - } - - public void Disconnect() - { - if (Socket == null) - return; - - try - { - Socket.Close(); - } - finally - { - Socket = null; - } - } - - public void Dispose() - { - Disconnect(); - } - } -} - +} \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs b/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs index 7966bacb4..ff206717f 100644 --- a/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs +++ b/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs @@ -12,7 +12,7 @@ namespace InnovEnergy.Lib.Protocols.Modbus.Clients; using UInt16s = IReadOnlyCollection; using Booleans = IReadOnlyCollection; -/*public class ModbusTcpClient : ModbusClient +public class ModbusTcpClient : ModbusClient { public const UInt16 DefaultPort = 502; private UInt16 _Id; @@ -184,171 +184,4 @@ using Booleans = IReadOnlyCollection; return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian); } -}*/ - -public class ModbusTcpClient : ModbusClient -{ - public const ushort DefaultPort = 502; - private ushort _Id; - public TcpChannel Channel { get; } - - public ModbusTcpClient(TcpChannel channel, byte slaveId) : base(channel, slaveId) - { - Channel = channel; - Channel.Connect(); - } - - private ushort NextId() => unchecked(++_Id); - - public override MbData ReadCoils(ushort readAddress, ushort nValues) - { - var id = NextId(); // TODO: check response id - - var cmd = new ReadCoilsCommandFrame(SlaveId, readAddress, nValues); - var hdr = new MbapHeader(id, cmd.Data.Count); - var frm = new ModbusTcpFrame(hdr, cmd); - - Channel.Write(frm.Data); - - var hData = Channel.Read(MbapHeader.Size).ToArray(); - var rxHdr = new MbapHeader(hData); - - var rxFrm = Channel - .Read(rxHdr.FrameLength) - .ToArray() - .Apply(ReadCoilsResponseFrame.Parse) - .Apply(cmd.VerifyResponse); - - return new MbData(rxFrm.Coils.RawData, readAddress, Endian); - } - - public override MbData ReadDiscreteInputs(ushort readAddress, ushort nValues) - { - var id = NextId(); // TODO: check response id - - var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, readAddress, nValues); - var hdr = new MbapHeader(id, cmd.Data.Count); - var frm = new ModbusTcpFrame(hdr, cmd); - - Channel.Write(frm.Data); - - var hData = Channel.Read(MbapHeader.Size).ToArray(); - var rxHdr = new MbapHeader(hData); - - var rxFrm = Channel - .Read(rxHdr.FrameLength) - .ToArray() - .Apply(ReadDiscreteInputsResponseFrame.Parse) - .Apply(cmd.VerifyResponse); - - return new MbData(rxFrm.Inputs.RawData, readAddress, Endian); - } - - public override MbData ReadInputRegisters(ushort readAddress, ushort nValues) - { - var id = NextId(); // TODO: check response id - - var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues); - var hdr = new MbapHeader(id, cmd.Data.Count); - var frm = new ModbusTcpFrame(hdr, cmd); - - Channel.Write(frm.Data); - - var hData = Channel.Read(MbapHeader.Size).ToArray(); - var rxHdr = new MbapHeader(hData); - - var rxFrm = Channel - .Read(rxHdr.FrameLength) - .ToArray() - .Apply(ReadInputRegistersResponseFrame.Parse) - .Apply(cmd.VerifyResponse); - - return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian); - } - - public override MbData ReadHoldingRegisters(ushort readAddress, ushort nValues) - { - var id = NextId(); // TODO: check response id - - var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues); - var hdr = new MbapHeader(id, cmd.Data.Count); - var frm = new ModbusTcpFrame(hdr, cmd); - - Channel.Write(frm.Data); - - var hData = Channel.Read(MbapHeader.Size).ToArray(); - var rxHdr = new MbapHeader(hData); - - var rxFrm = Channel - .Read(rxHdr.FrameLength) - .ToArray() - .Apply(ReadHoldingRegistersResponseFrame.Parse) - .Apply(cmd.VerifyResponse); - - return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian); - } - - public override ushort WriteCoils(ushort writeAddress, Booleans coils) - { - var id = NextId(); // TODO: check response id - var cmd = new WriteCoilsCommandFrame(SlaveId, writeAddress, coils); - var hdr = new MbapHeader(id, cmd.Data.Count); - var frm = new ModbusTcpFrame(hdr, cmd); - - Channel.Write(frm.Data); - - var hData = Channel.Read(MbapHeader.Size).ToArray(); - var rxHdr = new MbapHeader(hData); - - var rxFrm = Channel - .Read(rxHdr.FrameLength) - .ToArray() - .Apply(WriteCoilsResponseFrame.Parse) - .Apply(cmd.VerifyResponse); - - return rxFrm.NbWritten; - } - - public override ushort WriteRegisters(ushort writeAddress, UInt16s values) - { - var id = NextId(); // TODO: check response id - var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values); - var hdr = new MbapHeader(id, cmd.Data.Count); - var frm = new ModbusTcpFrame(hdr, cmd); - - Channel.Write(frm.Data); - - var hData = Channel.Read(MbapHeader.Size).ToArray(); - var rxHdr = new MbapHeader(hData); - - var rxFrm = Channel - .Read(rxHdr.FrameLength) - .ToArray() - .Apply(WriteRegistersResponseFrame.Parse) - .Apply(cmd.VerifyResponse); - - return rxFrm.NbWritten; - } - - public override MbData ReadWriteRegisters(ushort readAddress, ushort nbToRead, ushort writeAddress, UInt16s registersToWrite) - { - var id = NextId(); // TODO: check response id - - var cmd = new ReadWriteRegistersCommandFrame(SlaveId, readAddress, nbToRead, writeAddress, registersToWrite); - - var hdr = new MbapHeader(id, cmd.Data.Count); - var frm = new ModbusTcpFrame(hdr, cmd); - - Channel.Write(frm.Data); - - var hData = Enumerable.ToArray(Channel.Read(MbapHeader.Size)); - var rxHdr = new MbapHeader(hData); - - var fData = Enumerable.ToArray(Channel.Read(rxHdr.FrameLength)); - var rxFrm = fData - .Apply(ReadWriteRegistersResponseFrame.Parse) - .Apply(cmd.VerifyResponse); - - return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian); - } } \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Slaves/ModbusSlave.cs b/csharp/Lib/Protocols/Modbus/Slaves/ModbusSlave.cs index 8c78dbb31..622de280e 100644 --- a/csharp/Lib/Protocols/Modbus/Slaves/ModbusSlave.cs +++ b/csharp/Lib/Protocols/Modbus/Slaves/ModbusSlave.cs @@ -1,7 +1,7 @@ using InnovEnergy.Lib.Protocols.Modbus.Channels; using InnovEnergy.Lib.Protocols.Modbus.Clients; -/*namespace InnovEnergy.Lib.Protocols.Modbus.Slaves; +namespace InnovEnergy.Lib.Protocols.Modbus.Slaves; public static class ModbusSlave { @@ -52,58 +52,4 @@ public static class ModbusSlave return new ModbusDevice(modbusClient); } -}*/ - -using InnovEnergy.Lib.Protocols.Modbus.Channels; -using InnovEnergy.Lib.Protocols.Modbus.Clients; - -namespace InnovEnergy.Lib.Protocols.Modbus.Slaves -{ - public static class ModbusSlave - { - public static Func ModbusTcp(this Channel channel) - { - ModbusTcpClient SlaveId(byte slaveId) => new ModbusTcpClient((TcpChannel)channel, slaveId); - return SlaveId; - } - - public static Func ModbusRtu(this Channel channel) - { - ModbusRtuClient SlaveId(byte slaveId) => new ModbusRtuClient(channel, slaveId); - return SlaveId; - } - - public static Func ModbusTcp(this Channel channel) where R : notnull, new() - { - ModbusTcpClient SlaveId(byte slaveId) - { - return new ModbusTcpClient((TcpChannel)channel, slaveId); - } - - return SlaveId; - } - - public static Func ModbusRtu(this Channel channel) where R : notnull, new() - { - ModbusRtuClient SlaveId(byte slaveId) => new ModbusRtuClient(channel, slaveId); - return SlaveId; - } - - public static ModbusDevice TcpSlave(this Channel channel, byte slaveId) where T : notnull, new() - { - var client = new ModbusTcpClient((TcpChannel)channel, slaveId); - return new ModbusDevice(client); - } - - public static ModbusDevice RtuSlave(this Channel channel, byte slaveId) where T : notnull, new() - { - var client = new ModbusRtuClient(channel, slaveId); - return new ModbusDevice(client); - } - - public static ModbusDevice Slave(this ModbusClient modbusClient) where T : notnull, new() - { - return new ModbusDevice(modbusClient); - } - } } diff --git a/python/dbus-fz-sonick-48tl-with-s3/dbus-fzsonick-48tl.py b/python/dbus-fz-sonick-48tl-with-s3/dbus-fzsonick-48tl.py index cec68cd43..3caef9188 100755 --- a/python/dbus-fz-sonick-48tl-with-s3/dbus-fzsonick-48tl.py +++ b/python/dbus-fz-sonick-48tl-with-s3/dbus-fzsonick-48tl.py @@ -193,17 +193,19 @@ def update_state_from_dictionaries(current_warnings, current_alarms, node_number alarms_number_list = [] for node_number in node_numbers: cnt = 0 - for alarm_value in current_alarms.values(): - if alarm_value: - cnt+=1 + for i, alarm_value in enumerate(current_alarms.values()): + if list(current_alarms.keys())[i].split("/")[3] == node_number: + if alarm_value: + cnt+=1 alarms_number_list.append(cnt) warnings_number_list = [] for node_number in node_numbers: cnt = 0 - for warning_value in current_warnings.values(): - if warning_value: - cnt+=1 + for i, alarm_value in enumerate(current_warnings.values()): + if list(current_warnings.keys())[i].split("/")[3] == node_number: + if warning_value: + cnt+=1 warnings_number_list.append(cnt) # Evaluate alarms