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 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); } }