Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models.MongoModels;
|
||||
using adas_core.module.Relays.Models;
|
||||
|
||||
namespace adas_core.module.Relays.Devices;
|
||||
|
||||
internal class FakeRelay(Relay relay, RelaySettings relaySettings) : RelayDevice(relay, relaySettings)
|
||||
{
|
||||
public override bool CheckDevice()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool GetStatusRelay()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void PowerOffRelay(int outletId)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PowerOnRelay(int outletId)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PowerOffAll()
|
||||
{
|
||||
}
|
||||
|
||||
public override void PowerOnAll()
|
||||
{
|
||||
}
|
||||
|
||||
public override RelayEnum.Status GetStatusRelay(int outletId)
|
||||
{
|
||||
const string status = "00000000";
|
||||
|
||||
if (status.Length == 0) return RelayEnum.Status.On;
|
||||
return status.Substring(outletId - 1, 1) == "0" ? RelayEnum.Status.Off : RelayEnum.Status.On;
|
||||
}
|
||||
|
||||
public override void RebootOutlet(int outletId)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reboot()
|
||||
{
|
||||
PowerOffAll();
|
||||
if (Relay.RebootDelay is > 0) Thread.Sleep(Relay.RebootDelay!.Value);
|
||||
PowerOnAll();
|
||||
}
|
||||
|
||||
public override Task<bool> GetStatusRelayAsync()
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public override void CheckStatus()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models.MongoModels;
|
||||
using adas_core.module.Relays.Models;
|
||||
using Serilog;
|
||||
|
||||
namespace adas_core.module.Relays.Devices;
|
||||
|
||||
public class KmTronicRelay(Relay relay, RelaySettings relaySettings)
|
||||
: RelayDevice(relay, relaySettings)
|
||||
{
|
||||
private UdpClient? _udpClient;
|
||||
|
||||
public bool DeviceStatus { get; set; }
|
||||
|
||||
public override bool CheckDevice()
|
||||
{
|
||||
CheckStatus();
|
||||
var result = GetStatusRelay(1);
|
||||
return result != RelayEnum.Status.Unknown;
|
||||
}
|
||||
|
||||
public override bool GetStatusRelay()
|
||||
{
|
||||
var status = Send("FF0000");
|
||||
//while (!status.IsCompleted)
|
||||
//{
|
||||
|
||||
//}
|
||||
//return !string.IsNullOrEmpty(status.Result);
|
||||
|
||||
return !string.IsNullOrEmpty(status);
|
||||
}
|
||||
|
||||
public override RelayEnum.Status GetStatusRelay(int outletId)
|
||||
{
|
||||
var status = Send("FF0000");
|
||||
|
||||
//while (!status.IsCompleted)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
|
||||
//if (!string.IsNullOrEmpty(status.Result))
|
||||
//{
|
||||
// if (status.Result.Substring(outlet.outlet - 1, 1) == "0")
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
//}
|
||||
|
||||
if (!string.IsNullOrEmpty(status))
|
||||
try
|
||||
{
|
||||
if (status.Substring(outletId - 1, 1) == "0")
|
||||
//return RelayStatus.Off;
|
||||
return Relay.Mode == RelayEnum.Mode.OpenedOffClosedOn
|
||||
? RelayEnum.Status.On
|
||||
: RelayEnum.Status.Off;
|
||||
}
|
||||
catch (ArgumentOutOfRangeException e)
|
||||
{
|
||||
Log.Error(
|
||||
"There isn't an outlet {Outlet} in the rele {Ip}. Please check the configuration.\nException: {Ex}",
|
||||
outletId, Relay.Ip, e.Message);
|
||||
}
|
||||
|
||||
//return RelayStatus.On;
|
||||
return Relay.Mode == RelayEnum.Mode.OpenedOffClosedOn ? RelayEnum.Status.Off : RelayEnum.Status.On;
|
||||
}
|
||||
|
||||
public override void PowerOffRelay(int outletId)
|
||||
{
|
||||
if (Relay.Mode == RelayEnum.Mode.OpenedOffClosedOn) OpenRelay(outletId);
|
||||
else CloseRelay(outletId);
|
||||
}
|
||||
|
||||
public void OpenRelay(int outletId)
|
||||
{
|
||||
//Activa el relé por lo que corta la corriente del dispositivo conectado
|
||||
Send("FF0" + outletId + "01");
|
||||
}
|
||||
|
||||
public override void PowerOnRelay(int outletId)
|
||||
{
|
||||
if (Relay.Mode == RelayEnum.Mode.OpenedOffClosedOn) CloseRelay(outletId);
|
||||
else OpenRelay(outletId);
|
||||
}
|
||||
|
||||
public void CloseRelay(int outletId)
|
||||
{
|
||||
//Desactiva el relé por lo que deja pasar la corriente del dispositivo conectado
|
||||
Send("FF0" + outletId + "00");
|
||||
}
|
||||
|
||||
public override void PowerOffAll()
|
||||
{
|
||||
//Activa el relé por lo que corta la corriente de todos los dispositivo conectados
|
||||
Send("FFE0FF");
|
||||
}
|
||||
|
||||
public override void PowerOnAll()
|
||||
{
|
||||
//Desactiva el relé por lo que deja pasar la corriente a todos dispositivo conectados
|
||||
Send("FFE000");
|
||||
}
|
||||
|
||||
public override void CheckStatus()
|
||||
{
|
||||
DeviceStatus = GetStatusRelay();
|
||||
}
|
||||
|
||||
|
||||
public override void RebootOutlet(int outletId)
|
||||
{
|
||||
//Reinicia el relé del dispositivo conectado
|
||||
PowerOnOffRelay(outletId, 2000);
|
||||
}
|
||||
|
||||
public override void Reboot()
|
||||
{
|
||||
PowerOffAll();
|
||||
if (Relay.RebootDelay is > 0) Thread.Sleep(Relay.RebootDelay!.Value);
|
||||
PowerOnAll();
|
||||
}
|
||||
|
||||
public override Task<bool> GetStatusRelayAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void Connect()
|
||||
{
|
||||
if (_udpClient == null)
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Relay.Ip)) _udpClient = new UdpClient(Relay.Ip, Relay.Port);
|
||||
//var ipaddress = IPAddress.Parse(RelayConfig.Ip);
|
||||
//sourceipendpoint = new IPEndPoint(ipaddress, port); //source port IPEndpoint
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Debug("UdpClient not connect {Host}: {Port} Ex: {Ex}", Relay.Ip, Relay.Port, e.Message);
|
||||
|
||||
try
|
||||
{
|
||||
if (_udpClient != null)
|
||||
{
|
||||
_udpClient.Close();
|
||||
_udpClient = null;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
else
|
||||
try
|
||||
{
|
||||
_udpClient.Close();
|
||||
_udpClient = null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string Send(string datagrama)
|
||||
{
|
||||
if (_udpClient == null) Connect();
|
||||
|
||||
if (_udpClient == null) return string.Empty;
|
||||
|
||||
var command = Encoding.ASCII.GetBytes(datagrama.ToUpper());
|
||||
_udpClient.Send(command, command.Length);
|
||||
|
||||
var returnData = string.Empty;
|
||||
try
|
||||
{
|
||||
var t = Task.Run(() =>
|
||||
{
|
||||
var taskReceiveBytes = _udpClient.ReceiveAsync();
|
||||
returnData = Encoding.ASCII.GetString(taskReceiveBytes.Result.Buffer);
|
||||
});
|
||||
var ts = TimeSpan.FromSeconds(5);
|
||||
if (!t.Wait(ts))
|
||||
{
|
||||
if (!t.IsCompletedSuccessfully) returnData = string.Empty;
|
||||
if (t.Exception != null) throw t.Exception;
|
||||
}
|
||||
|
||||
if (t.Status == TaskStatus.RanToCompletion) t.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Debug("UdpClient not connect {Host}: {Port} Ex: {Ex}", Relay.Ip, Relay.Port, ex.Message);
|
||||
returnData = string.Empty;
|
||||
}
|
||||
|
||||
if (returnData == string.Empty)
|
||||
Log.Debug("UdpClient not connect {Host}: {Port}", Relay.Ip, Relay.Port);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models.MongoModels;
|
||||
using adas_core.module.Relays.Models;
|
||||
using adas_core.module.Relays.Utils;
|
||||
using Serilog;
|
||||
|
||||
namespace adas_core.module.Relays.Devices;
|
||||
|
||||
public class KmTronicV2Relay : RelayDevice
|
||||
{
|
||||
public KmTronicV2Relay(Relay relay, RelaySettings relaySettings) : base(relay, relaySettings)
|
||||
{
|
||||
CheckDevice();
|
||||
}
|
||||
|
||||
public sealed override bool CheckDevice()
|
||||
{
|
||||
CheckStatus();
|
||||
var result = GetStatusRelay(1);
|
||||
return result != RelayEnum.Status.Unknown;
|
||||
}
|
||||
|
||||
public override void CheckStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
var httpResponse = SendRequest("status.xml", HttpMethod.Get);
|
||||
|
||||
if (httpResponse.StatusCode.Equals(HttpStatusCode.OK))
|
||||
{
|
||||
var responseContent = httpResponse.Content;
|
||||
var responseString = responseContent.ReadAsStringAsync().Result;
|
||||
if (!string.IsNullOrEmpty(responseString))
|
||||
{
|
||||
var response = new XmlDocument();
|
||||
response.LoadXml(responseString);
|
||||
foreach (XmlNode node in response.SelectNodes("//response")!)
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
if (!childNode.Name.StartsWith("relay") || string.IsNullOrEmpty(childNode.InnerText)) continue;
|
||||
var id = int.Parse(childNode.Name[5..]);
|
||||
if (id <= 0 || id > Relay.Total) continue;
|
||||
var value = int.Parse(childNode.InnerText);
|
||||
var relayStatus = value.Equals(0) ? RelayEnum.Status.Off :
|
||||
value.Equals(1) ? RelayEnum.Status.On : RelayEnum.Status.Unknown;
|
||||
Tuple.Create(Relay.Ip, Relay.Port, id);
|
||||
SetStatusRelay(id, relayStatus);
|
||||
}
|
||||
}
|
||||
|
||||
Log.Debug(responseContent.ReadAsStringAsync().Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Debug("Status code = " + httpResponse.StatusCode);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex.ToString());
|
||||
Enumerable.Range(1, Relay.Total).ToList().ForEach(outletId =>
|
||||
{
|
||||
SetStatusRelay(outletId, RelayEnum.Status.Unknown);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override bool GetStatusRelay()
|
||||
{
|
||||
return GetStatusRelay(1) == RelayEnum.Status.On;
|
||||
}
|
||||
|
||||
public override Task<bool> GetStatusRelayAsync()
|
||||
{
|
||||
var result = GetStatusRelay();
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void PowerOnRelay(int outletId)
|
||||
{
|
||||
PowerRelay(outletId, RelayEnum.Status.On);
|
||||
}
|
||||
|
||||
public override void PowerOffRelay(int outletId)
|
||||
{
|
||||
PowerRelay(outletId, RelayEnum.Status.Off);
|
||||
}
|
||||
|
||||
private Uri GetUri(string path, string? query = null)
|
||||
{
|
||||
var uriBuilder = new UriBuilder
|
||||
{ Scheme = "http", Host = Relay.Ip, Port = Relay.Port, Path = path };
|
||||
if (!string.IsNullOrEmpty(query)) uriBuilder.Query = query;
|
||||
return uriBuilder.Uri;
|
||||
}
|
||||
|
||||
private HttpRequestMessage GetRequest(string path, HttpMethod method, string? query = null)
|
||||
{
|
||||
var uri = GetUri(path, query);
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
RequestUri = uri,
|
||||
Method = method
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(Relay.Username) && !string.IsNullOrEmpty(Relay.Password))
|
||||
HttpUtils.AddBasicAuth(Relay.Username, Relay.Password, request.Headers);
|
||||
return request;
|
||||
}
|
||||
|
||||
private HttpResponseMessage SendRequest(string path, HttpMethod method, string? query = null)
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
client.Timeout = TimeSpan.FromSeconds(15);
|
||||
try
|
||||
{
|
||||
return client.Send(GetRequest(path, method, query));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Warning("Error sending request to kmtronic ip {IP} port {Port}: {Message}", Relay.Ip,
|
||||
Relay.Port, e.Message);
|
||||
return new HttpResponseMessage(HttpStatusCode.Gone);
|
||||
}
|
||||
}
|
||||
|
||||
private void PowerRelay(int outletId, RelayEnum.Status toState, bool checkStatus = true)
|
||||
{
|
||||
if (Relay.Mode == RelayEnum.Mode.OpenedOffClosedOn)
|
||||
toState = toState == RelayEnum.Status.Off ? RelayEnum.Status.On : RelayEnum.Status.Off;
|
||||
|
||||
var status = GetStatusRelay(outletId);
|
||||
|
||||
if (status == toState) return;
|
||||
|
||||
|
||||
//No entiendo esto así, siempre enciende/apaga el mismo uriBuilder.Query = $"relay={outlet.outlet}";
|
||||
//me quedo con el nombre y solo con el número del rele que es la llamada que el hace realmente desde la web
|
||||
//No uso una regex porque es mucho más lento
|
||||
|
||||
try
|
||||
{
|
||||
SendRequest("relays.cgi", HttpMethod.Post, $"relay={outletId}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Debug(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (checkStatus) CheckStatus();
|
||||
}
|
||||
}
|
||||
|
||||
public override void PowerOnAll()
|
||||
{
|
||||
PowerAll(RelayEnum.Status.On);
|
||||
}
|
||||
|
||||
public override void PowerOffAll()
|
||||
{
|
||||
PowerAll(RelayEnum.Status.Off);
|
||||
}
|
||||
|
||||
private void PowerAll(RelayEnum.Status toState)
|
||||
{
|
||||
Enumerable.Range(1, Relay.Total).ToList().ForEach(outletId => { PowerRelay(outletId, toState, false); });
|
||||
CheckStatus();
|
||||
}
|
||||
|
||||
public override void Reboot()
|
||||
{
|
||||
PowerOffAll();
|
||||
if (Relay.RebootDelay is > 0) Thread.Sleep(Relay.RebootDelay!.Value);
|
||||
PowerOnAll();
|
||||
}
|
||||
|
||||
public override void RebootOutlet(int outletId)
|
||||
{
|
||||
PowerOffRelay(outletId);
|
||||
Thread.Sleep(30000);
|
||||
PowerOnRelay(outletId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System.Collections.Concurrent;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models.MongoModels;
|
||||
using adas_core.module.Relays.Models;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace adas_core.module.Relays.Devices;
|
||||
|
||||
public abstract class RelayDevice
|
||||
{
|
||||
private readonly ConcurrentDictionary<int, RelayEnum.Status> _relaysStatus = new();
|
||||
private readonly Timer? _timer;
|
||||
public readonly Relay Relay;
|
||||
public readonly RelaySettings RelaySettings;
|
||||
|
||||
//string host, int port, int relays, int? refreshTime, EventHandler refreshEvent
|
||||
protected RelayDevice(Relay relay, RelaySettings relaySettings)
|
||||
{
|
||||
Relay = relay;
|
||||
RelaySettings = relaySettings;
|
||||
if (relaySettings.RefreshTime is > 0)
|
||||
{
|
||||
_timer = new Timer();
|
||||
_timer.Interval = relaySettings.RefreshTime.Value * 1000;
|
||||
_timer.Elapsed += delegate
|
||||
{
|
||||
_timer.Stop();
|
||||
CheckStatus();
|
||||
_timer.Start();
|
||||
};
|
||||
_timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<int>? RelayStatusChanged;
|
||||
|
||||
public abstract bool CheckDevice();
|
||||
public abstract void CheckStatus();
|
||||
public abstract bool GetStatusRelay();
|
||||
|
||||
public abstract Task<bool> GetStatusRelayAsync();
|
||||
|
||||
public virtual RelayEnum.Status GetStatusRelay(int outletId)
|
||||
{
|
||||
lock (_relaysStatus)
|
||||
{
|
||||
return _relaysStatus.GetValueOrDefault(outletId, RelayEnum.Status.Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetStatusRelay(int outletId, RelayEnum.Status status)
|
||||
{
|
||||
lock (_relaysStatus)
|
||||
{
|
||||
if (!_relaysStatus.ContainsKey(outletId) || _relaysStatus[outletId] != status)
|
||||
RelayStatusChanged?.Invoke(this, outletId);
|
||||
_relaysStatus[outletId] = status;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void PowerOnOffRelay(int outletId, int milliseconds)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
PowerOffRelay(outletId);
|
||||
Task.Delay(milliseconds);
|
||||
PowerOnRelay(outletId);
|
||||
});
|
||||
}
|
||||
|
||||
public virtual void Refresh()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract void PowerOnRelay(int outletId);
|
||||
|
||||
public abstract void PowerOffRelay(int outletId);
|
||||
|
||||
public abstract void PowerOnAll();
|
||||
|
||||
public abstract void PowerOffAll();
|
||||
|
||||
public abstract void RebootOutlet(int outletId);
|
||||
|
||||
public abstract void Reboot();
|
||||
}
|
||||
Reference in New Issue
Block a user