From df915acae544ece76ed2497abf2399b3e3c2a078 Mon Sep 17 00:00:00 2001 From: Diego Freitas Date: Thu, 11 Dec 2025 15:27:19 -0300 Subject: [PATCH] Adicionado controle do CoolerControl --- .../Models/Modules/SensoriamentoModel.cs | 2 + .../Models/Operacoes/OperacaoModel.cs | 31 +++- .../AgroBase/Services/CoolerControlService.cs | 114 ++++++++++-- AgroBase/OperationControl/Models/Variaveis.cs | 17 +- .../OperationControl/Windows/MainWindow.xaml | 104 ++++++++++- .../Windows/MainWindow.xaml.cs | 167 +++++++++++++++++- 6 files changed, 406 insertions(+), 29 deletions(-) diff --git a/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs b/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs index 4cfeee71a..e455aff66 100644 --- a/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs +++ b/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs @@ -2562,6 +2562,7 @@ namespace AgroBase.Models.Modules } public bool AtuacaoNivelAlto { get; set; } public Estado StatusControle { get; set; } + public Estado StatusLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado; public bool Inicializado { get; set; } public DateTime UltimaLeitura { @@ -2620,6 +2621,7 @@ namespace AgroBase.Models.Modules } } public int _AnguloControle { get; set; } + public int _AnguloLeiutra => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraAngulo)?.atual?.valor ?? -1; public bool Inicializado { get; set; } public DateTime UltimaLeitura { diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs index 1e76889d7..e8f142bee 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs @@ -1576,11 +1576,13 @@ namespace AgroBase.Models if (controleBase.Dispositivo == T_Code.Gps) { - VariaveisEquipamento.LeverArmFrontal = controleBase.LeverArmFrontal; - VariaveisEquipamento.LeverArmLateral = controleBase.LeverArmLateral; + var (la_frontal, la_lateral) = ((JObject)controleBase._comp_value).ToObject<(double?, double?)>(); + if (la_frontal != null) VariaveisEquipamento.LeverArmFrontal = (double)la_frontal; + if (la_lateral != null) VariaveisEquipamento.LeverArmLateral = (double)la_lateral; GPSService.UltimaLeitura.LeverArmFrontal = VariaveisEquipamento.LeverArmFrontal; GPSService.UltimaLeitura.LeverArmLateral = VariaveisEquipamento.LeverArmLateral; - GPSService.LeverArm = new GeoLeverArm(VariaveisEquipamento.LeverArmFrontal, VariaveisEquipamento.LeverArmLateral); + if (la_lateral != null || la_frontal != null) + GPSService.LeverArm = new GeoLeverArm(VariaveisEquipamento.LeverArmFrontal, VariaveisEquipamento.LeverArmLateral); return; } @@ -1665,6 +1667,13 @@ namespace AgroBase.Models return; } + if (controleBase.Dispositivo == T_Code.Npc) + { + var (modo, e_entrada, e_saida, t_ligar, t_turbo) = ((JObject)controleBase._comp_value).ToObject<(CoolerControlService.CoolerMode, Estado?, Estado?, double?, double?)>(); + Variaveis.OperacaoEmAndamento.DispSen?.Dados?.CoolerControl?.AlterarControle(modo, entrada: e_entrada, saida: e_saida, tempOn: t_ligar, tempTurbo: t_turbo); + return; + } + Variaveis.OperacaoEmAndamento.Emergencia = controleBase.Emergencia; if (Variaveis.OperacaoEmAndamento.Emergencia) return; @@ -2220,8 +2229,6 @@ namespace AgroBase.Models public bool Pausa { get; set; } public string _comp_id { get; set; } public dynamic _comp_value { get; set; } - public double LeverArmFrontal { get; set; } - public double LeverArmLateral { get; set; } public OperacaoParametrosModel Parametros { get; set; } public OperacaoComandoBaseControleModel Controle { get; set; } } @@ -2288,10 +2295,13 @@ namespace AgroBase.Models public List ModulosSaude { get; set; } public List DispositivosMapeados { get; set; } public Dictionary Temperaturas { get; set; } + public Dictionary Reles { get; set; } + public Dictionary Servos { get; set; } public Dictionary> ModsCalibragem { get; set; } public bool CanSerialAtivado { get; set; } public Dictionary Iniciados { get; set; } public List Logs { get; set; } + public CoolerControlDataModel CoolerControl { get; set; } public DateTime UltimoComandoRespondido { get; set; } public void InserirLog(T_Code dispositivo, StatusModulo status, double saude, string mensagem, string id = null, string condicoes = null) @@ -2329,10 +2339,11 @@ namespace AgroBase.Models var _Controle = Variaveis.OperacaoEmAndamento.Controle; var _Bateria = _DispSen?.Dados?.ContadorCarga; var _Reservatorio = _DispAtu?.Dados?.ContadorCarga; + var _Cooler = _DispSen?.Dados?.CoolerControl; double tmp_max = Math.Max(Variaveis.OperacaoEmAndamento.DadosPerformance?.GPU_temp ?? 0, Variaveis.OperacaoEmAndamento.DadosPerformance?.CPU_temp ?? 0); - _DispSen?.Dados?.CoolerControl?.Atualizar(tmp_max); _DispMvd?.Dados?.AtualizarDadosFreio(); + _Cooler?.Atualizar(tmp_max, DateTime.Now); _Bateria?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0); _Reservatorio?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0, Variaveis.OperacaoEmAndamento.TempoDecorridoSegs); _Trajetoria.AtualizarDadosAutonomiaCorredor(); @@ -2521,6 +2532,8 @@ namespace AgroBase.Models var dadosLivox = LivoxManagerProcess.DadosLeitura.Clone(); + var dadosCooler = _Cooler?.GetResumo(); + OperacaoSensoriamentoLogModel dadosAtualizados = new OperacaoSensoriamentoLogModel() { Momento = DateTime.Now, @@ -2556,8 +2569,11 @@ namespace AgroBase.Models DispositivosMapeados = new List(SerialService.DispositivosMapeados), ModsCalibragem = new Dictionary>(Variaveis.OperacaoEmAndamento.ModsCalibragem), Temperaturas = _DispSen?.Dados?.Sensores?.Where(x => x.Componente == S_Code.sNTC)?.ToDictionary(x => x.ID, y => (double?)(y.ValoresLeituras?.FirstOrDefault(v => v.funcao == FuncoesPinout.Temperatura)?.atual?.valor) ?? -1), + Reles = _DispSen?.Dados?.Reles?.ToDictionary(x => x.ID, y => (y.StatusControle == Estado.Ligado, y.StatusLeitura == Estado.Ligado)), + Servos = _DispSen?.Dados?.Servos?.ToDictionary(x => x.ID, y => (y._AnguloControle, y._AnguloLeiutra)), Iniciados = _DispSen?.Dados?.Servos?.Select(s => new { s.ID, s.Inicializado }).Union(_DispSen?.Dados?.Reles?.Select(r => new { r.ID, r.Inicializado })).Union(_DispSen?.Dados?.Sinaleiros?.Select(s => new { s.ID, s.Inicializado })).Union(_DispSen?.Dados?.Sensores?.Select(s => new { s.ID, s.Inicializado })).ToDictionary(s => s.ID, s => s.Inicializado), Logs = new List(Logs ?? new List()), + CoolerControl = dadosCooler, UltimoComandoRespondido = _DispSen?.Dados?.DadosLeitura?.UltimoComandoRespondido ?? DateTime.MinValue }; @@ -2608,8 +2624,11 @@ namespace AgroBase.Models DispositivosMapeados = new List(DispositivosMapeados), ModsCalibragem = new Dictionary>(ModsCalibragem), Temperaturas = new Dictionary(Temperaturas ?? new Dictionary()), + Reles = new Dictionary(Reles ?? new Dictionary()), + Servos = new Dictionary(Servos ?? new Dictionary()), Iniciados = new Dictionary(Iniciados ?? new Dictionary()), Logs = new List(Logs ?? new List()), + CoolerControl = CoolerControl?.Clone(), UltimoComandoRespondido = UltimoComandoRespondido }; } diff --git a/AgroBase/AgroBase/Services/CoolerControlService.cs b/AgroBase/AgroBase/Services/CoolerControlService.cs index 75df46e63..bc20c9d4d 100644 --- a/AgroBase/AgroBase/Services/CoolerControlService.cs +++ b/AgroBase/AgroBase/Services/CoolerControlService.cs @@ -2,27 +2,31 @@ using AgroBase.Models.Modules; using System; using System.Linq; +using static AgroBase.Models.Enums; +using static AgroBase.Services.CoolerControlService; namespace AgroBase.Services { public class CoolerControlService { // Config - public double TempOn { get; set; } = 30.0; // Liga ventilação básica - public double TempTurbo { get; set; } = 35.0; // Liga entrada+saída - public double TempCritical { get; set; } = 45.0; // Acima disso, alerta - public double Histerese { get; set; } = 1.5; // Para evitar chattering + public double TempOn { get; set; } = 55.0; // Liga ventilação básica + public double TempTurbo { get; set; } = 65.0; // Liga entrada+saída + public double TempCritical { get; set; } = 75.0; // Acima disso, alerta + public double Histerese { get; set; } = 1.5; // Para evitar chattering - public TimeSpan MinOnTime { get; set; } = TimeSpan.FromSeconds(30); + public TimeSpan MinOnTime { get; set; } = TimeSpan.FromSeconds(30); public TimeSpan MinOffTime { get; set; } = TimeSpan.FromSeconds(30); // Filtro de temperatura (EMA) - public double AlphaFiltro { get; set; } = 0.2; + public double AlphaFiltro { get; set; } = 0.2; // Estado interno public CoolerMode ModoAtual { get; private set; } = CoolerMode.Off; - public Enums.Estado CoolerEntradaEstado => ModoAtual == CoolerMode.IntakeAndExhaust ? Enums.Estado.Ligado : Enums.Estado.Desligado; - public Enums.Estado CoolerSaidaEstado => ModoAtual == CoolerMode.ExhaustOnly || ModoAtual == CoolerMode.IntakeAndExhaust ? Enums.Estado.Ligado : Enums.Estado.Desligado; + public Estado CoolerEntradaEstado { get; private set; } = Estado.Desligado; + public Estado CoolerSaidaEstado { get; private set; } = Estado.Desligado; + public Estado CoolerEntradaLeitura => ReleCoolerEntrada?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado; + public Estado CoolerSaidaLeitura => ReleCoolerSaida?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado; public double? TemperaturaFiltrada { get; private set; } public DateTime UltimaMudancaModo { get; private set; } = DateTime.MinValue; @@ -57,15 +61,29 @@ namespace AgroBase.Services TemperaturaFiltrada = null; UltimaMudancaModo = DateTime.MinValue; AlertaTemperaturaCritica = false; + CoolerEntradaEstado = Estado.Desligado; + CoolerSaidaEstado = Estado.Desligado; + + EnviarComando(); + } + + public void AlterarControle(CoolerMode modo, Estado? entrada = null, Estado? saida = null, double? tempOn = null, double? tempTurbo = null) + { + ModoAtual = modo; + + if (entrada != null) CoolerEntradaEstado = (Estado)entrada; + if (saida != null) CoolerSaidaEstado = (Estado)saida; + if (tempOn != null) TempOn = (double)tempOn; + if (tempTurbo != null) TempTurbo = (double)tempTurbo; + + EnviarComando(); } /// /// Chamar a cada tick de atualização com a temperatura interna atual /// - public void Atualizar(double temperaturaAtual_C) + public void Atualizar(double temperaturaAtual_C, DateTime agora) { - DateTime agora = DateTime.Now; - // 1) Filtrar temperatura (EMA) if (TemperaturaFiltrada == null) { @@ -79,13 +97,22 @@ namespace AgroBase.Services var temp = TemperaturaFiltrada.Value; // 2) Verificar limite crítico (para health_worker) + bool _alertaAnterior = AlertaTemperaturaCritica; AlertaTemperaturaCritica = temp >= TempCritical; + if (!_alertaAnterior && AlertaTemperaturaCritica) + { + Variaveis.OperacaoEmAndamento.Parametros?.DadosLeitura?.InserirLog(T_Code.Npc, StatusModulo.Alerta, 50, "Temperatura limite excedida no NPC"); + } + + if (ModoAtual == CoolerMode.Manual) + return; // 3) Respeitar permanência mínima de estado var tempoNoModoAtual = agora - UltimaMudancaModo; bool podeMudar = (ModoAtual == CoolerMode.Off && tempoNoModoAtual >= MinOffTime) || - (ModoAtual != CoolerMode.Off && tempoNoModoAtual >= MinOnTime); + (ModoAtual != CoolerMode.Off && tempoNoModoAtual >= MinOnTime) || + Variaveis.Fechando; if (!podeMudar) return; @@ -113,23 +140,78 @@ namespace AgroBase.Services break; } + if (Variaveis.Fechando) + novoModo = CoolerMode.Off; + + CoolerEntradaEstado = novoModo == CoolerMode.IntakeAndExhaust ? Estado.Ligado : Estado.Desligado; + CoolerSaidaEstado = novoModo == CoolerMode.ExhaustOnly || novoModo == CoolerMode.IntakeAndExhaust ? Estado.Ligado : Estado.Desligado; + if (novoModo != ModoAtual) { ModoAtual = novoModo; UltimaMudancaModo = agora; - if (ReleCoolerEntrada != null) - GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerEntrada.Componente, ReleCoolerEntrada.ID, CoolerEntradaEstado); - if (ReleCoolerSaida != null) - GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerSaida.Componente, ReleCoolerSaida.ID, CoolerSaidaEstado); + EnviarComando(); } } + private void EnviarComando() + { + if (ReleCoolerEntrada != null) + GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerEntrada.Componente, ReleCoolerEntrada.ID, CoolerEntradaEstado); + if (ReleCoolerSaida != null) + GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerSaida.Componente, ReleCoolerSaida.ID, CoolerSaidaEstado); + } + + public CoolerControlDataModel GetResumo() + { + return new CoolerControlDataModel() + { + Modo = ModoAtual, + UltimaMudanca = UltimaMudancaModo, + EstadoEntrada = CoolerEntradaEstado, + EstadoSaida = CoolerSaidaEstado, + LeituraEntrada = CoolerEntradaLeitura, + LeituraSaida = CoolerSaidaLeitura, + Temperatura = TemperaturaFiltrada ?? 0, + Alerta = AlertaTemperaturaCritica + }; + } + public enum CoolerMode { Off, + Manual, ExhaustOnly, IntakeAndExhaust } } + + public class CoolerControlDataModel + { + public CoolerMode Modo { get; set; } + public DateTime UltimaMudanca { get; set; } + public Estado EstadoEntrada { get; set; } + public Estado EstadoSaida { get; set; } + public Estado LeituraEntrada { get; set; } + public Estado LeituraSaida { get; set; } + public double Temperatura { get; set; } + public bool Alerta { get; set; } + + public CoolerControlDataModel Clone() + { + return new CoolerControlDataModel() + { + Modo = Modo, + UltimaMudanca = UltimaMudanca, + EstadoEntrada = EstadoEntrada, + EstadoSaida = EstadoSaida, + LeituraEntrada = LeituraEntrada, + LeituraSaida = LeituraSaida, + Temperatura = Temperatura, + Alerta = Alerta, + }; + } + } + } diff --git a/AgroBase/OperationControl/Models/Variaveis.cs b/AgroBase/OperationControl/Models/Variaveis.cs index f97998feb..fe075bfb7 100644 --- a/AgroBase/OperationControl/Models/Variaveis.cs +++ b/AgroBase/OperationControl/Models/Variaveis.cs @@ -308,12 +308,9 @@ namespace OperationControl.Models var cmd = new OperacaoComandoBaseModel() { Momento = DateTime.Now, - Dispositivo = AgroBase.Models.Enums.T_Code.Gps + Dispositivo = AgroBase.Models.Enums.T_Code.Gps, + _comp_value = (lateral, frontal) }; - if (lateral != null) - cmd.LeverArmLateral = Math.Round((double)lateral, 0); - if (frontal != null) - cmd.LeverArmFrontal = Math.Round((double)frontal, 0); EnviarDadosControle(SelectedRoverId, cmd); } @@ -342,6 +339,16 @@ namespace OperationControl.Models }); } + public static void EnviarComandoCoolerControl(AgroBase.Services.CoolerControlService.CoolerMode modo, AgroBase.Models.Enums.Estado? entrada = null, AgroBase.Models.Enums.Estado? saida = null, double? temp_on = null, double? temp_turbo = null) + { + EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() + { + Momento = DateTime.Now, + Dispositivo = AgroBase.Models.Enums.T_Code.Npc, + _comp_value = (modo, entrada, saida, temp_on, temp_turbo) + }); + } + public static void RequisitarParametrosOperacao() { EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel() diff --git a/AgroBase/OperationControl/Windows/MainWindow.xaml b/AgroBase/OperationControl/Windows/MainWindow.xaml index c71a3b770..7b5360758 100644 --- a/AgroBase/OperationControl/Windows/MainWindow.xaml +++ b/AgroBase/OperationControl/Windows/MainWindow.xaml @@ -151,6 +151,8 @@