diff --git a/AgroBase/AgroBase/Models/GeneralJoystick.cs b/AgroBase/AgroBase/Models/GeneralJoystick.cs index 5f698f4cd..3d60d222a 100644 --- a/AgroBase/AgroBase/Models/GeneralJoystick.cs +++ b/AgroBase/AgroBase/Models/GeneralJoystick.cs @@ -690,7 +690,7 @@ namespace AgroBase { List modsControlar = null; if (!string.IsNullOrEmpty(ID)) - modsControlar.Add(ID); + modsControlar = new List() { ID }; if (MovimentosCombinados.Contains(Variaveis.OperacaoEmAndamento.Controle.TipoMovimento)) { Task.Run(async () => await Variaveis.OperacaoEmAndamento.DispMvd.Dados.ExecutarMovimentoDirecionalCombinado(DirecaoAtual)); diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs index 426721f2f..58c271f50 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs @@ -2296,7 +2296,7 @@ namespace AgroBase.Models public List DispositivosMapeados { get; set; } public Dictionary Temperaturas { get; set; } public Dictionary Reles { get; set; } - public Dictionary Servos { get; set; } + public Dictionary Servos { get; set; } public Dictionary> ModsCalibragem { get; set; } public bool CanSerialAtivado { get; set; } public Dictionary Iniciados { get; set; } @@ -2570,7 +2570,7 @@ namespace AgroBase.Models 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)), + Servos = _DispSen?.Dados?.Servos?.ToDictionary(x => x.ID, y => (y._AnguloControle, y._AnguloLeiutra, y.Incremental)), 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, @@ -2625,7 +2625,7 @@ namespace AgroBase.Models ModsCalibragem = new Dictionary>(ModsCalibragem), Temperaturas = new Dictionary(Temperaturas ?? new Dictionary()), Reles = new Dictionary(Reles ?? new Dictionary()), - Servos = new Dictionary(Servos ?? new Dictionary()), + Servos = new Dictionary(Servos ?? new Dictionary()), Iniciados = new Dictionary(Iniciados ?? new Dictionary()), Logs = new List(Logs ?? new List()), CoolerControl = CoolerControl?.Clone(), diff --git a/AgroBase/AgroBase/Services/CoolerControlService.cs b/AgroBase/AgroBase/Services/CoolerControlService.cs index 172b7e8cd..4c96b6641 100644 --- a/AgroBase/AgroBase/Services/CoolerControlService.cs +++ b/AgroBase/AgroBase/Services/CoolerControlService.cs @@ -150,16 +150,16 @@ namespace AgroBase.Services { ModoAtual = novoModo; UltimaMudancaModo = agora; - - EnviarComando(); } + + EnviarComando(); } private void EnviarComando() { - if (ReleCoolerEntrada != null) + if ((ReleCoolerEntrada?.StatusLeitura ?? Estado.Desligado) != CoolerEntradaEstado) GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerEntrada.Componente, ReleCoolerEntrada.ID, CoolerEntradaEstado); - if (ReleCoolerSaida != null) + if ((ReleCoolerSaida?.StatusLeitura ?? Estado.Desligado) != CoolerSaidaEstado) GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerSaida.Componente, ReleCoolerSaida.ID, CoolerSaidaEstado); } diff --git a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs index 64b0c29f8..a9bd797bc 100644 --- a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs +++ b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs @@ -437,6 +437,74 @@ namespace AgroBase.Services.Operadores } RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Sen), servosAtualizados.ToArray()); + var relesAtualizados = new List<(string caminho, object valor)>(); + foreach (var rele in DadosSen.Reles) + { + int id = rele.ID_Num; + string basePath = $"reles.{id}"; + + var saude = RedisService.GetField(RedisService.ModKey(Enums.T_Code.Sen), $"{basePath}.saude"); + + var dados = rele.ValoresLeituras + .Where(y => y.analise_health) + .Select(y => new + { + label = y.funcao.ToString(), + atual = y.atual.valor, + freq = y.atual.frequencia + }) + .ToList(); + + var releObj = new + { + conectado = rele.Inicializado, + id, + label = rele.ID, + controlar = rele.Controlar, + mandatorio = rele.Mandatorio, + dados, + timestamp = agora, + saude = saude ?? new { } + }; + + relesAtualizados.Add(($"{basePath}", releObj)); + } + RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Sen), relesAtualizados.ToArray()); + + var ledsAtualizados = new List<(string caminho, object valor)>(); + foreach (var led in DadosSen.Sinaleiros) + { + int id = led.ID_Num; + string basePath = $"sinaleiros.{id}"; + + var saude = RedisService.GetField(RedisService.ModKey(Enums.T_Code.Sen), $"{basePath}.saude"); + + var dados = led.ValoresLeituras + .Where(y => y.analise_health) + .Select(y => new + { + label = y.funcao.ToString(), + atual = y.atual.valor, + freq = y.atual.frequencia + }) + .ToList(); + + var ledObj = new + { + conectado = led.Inicializado, + id, + label = led.ID, + controlar = true, + mandatorio = true, + dados, + timestamp = agora, + saude = saude ?? new { } + }; + + ledsAtualizados.Add(($"{basePath}", ledObj)); + } + RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Sen), ledsAtualizados.ToArray()); + var DadosAtu = Variaveis.OperacaoEmAndamento.DispAtu.Dados; RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Atu), diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/sensoriamento.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/sensoriamento.py index ddc05c7ab..e9642d2bd 100644 --- a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/sensoriamento.py +++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/sensoriamento.py @@ -143,6 +143,93 @@ class ModuloSensoriamento(ModuloDiagnosticoBase): motivos_gerais.extend([f"{chave}: {m}" for m in motivos]) dados_servo["saude"] = saude_mod + for rele_id, dados_rele in dados_sen.get("reles", {}).items(): + saude = 100 + motivos = [] + condicoes_operacionais = [] + controlar = dados_rele.get("controlar", False) + conectado = dados_rele.get("conectado", False) + mandatorio = dados_rele.get("mandatorio", False) + if not conectado: + saude = 0 + motivos.append(f"desconectado") + else: + for dado in dados_rele.get("dados", {}): + label = dado.get("label") + if label is None: + continue + freq = dado.get("freq", 0.0) + if freq == 0: + saude = 0 + motivos.append(f"{label} sem resposta (freq = 0 Hz)") + else: + penalidade = penalizar_frequencia(freq, FREQ_BASE, FREQ_MIN, (100 - SAUDE_MIN_ALERTA)) + saude -= penalidade + if freq <= FREQ_MIN: + motivos.append(f"{label} frequência baixa ({freq:.2f}/{FREQ_BASE} Hz, penalidade {penalidade}%)") + + saude = max(0, saude) + chave = f"rele_{rele_id}" + saude_mod = { + "id": rele_id, + "label": dados_rele.get("label"), + "status": (StatusModulo.DESCONECTADO if not conectado else StatusModulo.OPERANTE if saude >= SAUDE_MIN_ALERTA else StatusModulo.ALERTA if saude > 0 else StatusModulo.FALHA).value, + "saude": saude, + "motivos": motivos, + "condicoes_operacionais": condicoes_operacionais, + "em_uso": controlar + } + saude_individual.append(saude_mod) + if mandatorio: + total_ativos += 1 + saude_total += saude + motivos_gerais.extend([f"{chave}: {m}" for m in motivos]) + dados_rele["saude"] = saude_mod + + for led_id, dados_led in dados_sen.get("sinaleiros", {}).items(): + saude = 100 + motivos = [] + condicoes_operacionais = [] + controlar = dados_led.get("controlar", False) + conectado = dados_led.get("conectado", False) + mandatorio = dados_led.get("mandatorio", False) + if not conectado: + saude = 0 + motivos.append(f"desconectado") + else: + for dado in dados_led.get("dados", {}): + label = dado.get("label") + if label is None: + continue + freq = dado.get("freq", 0.0) + if freq == 0: + saude = 0 + motivos.append(f"{label} sem resposta (freq = 0 Hz)") + else: + penalidade = penalizar_frequencia(freq, FREQ_BASE, FREQ_MIN, (100 - SAUDE_MIN_ALERTA)) + saude -= penalidade + if freq <= FREQ_MIN: + motivos.append(f"{label} frequência baixa ({freq:.2f}/{FREQ_BASE} Hz, penalidade {penalidade}%)") + + saude = max(0, saude) + chave = f"sinaleiro_{led_id}" + saude_mod = { + "id": led_id, + "label": dados_led.get("label"), + "status": (StatusModulo.DESCONECTADO if not conectado else StatusModulo.OPERANTE if saude >= SAUDE_MIN_ALERTA else StatusModulo.ALERTA if saude > 0 else StatusModulo.FALHA).value, + "saude": saude, + "motivos": motivos, + "condicoes_operacionais": condicoes_operacionais, + "em_uso": controlar + } + saude_individual.append(saude_mod) + if mandatorio: + total_ativos += 1 + saude_total += saude + motivos_gerais.extend([f"{chave}: {m}" for m in motivos]) + dados_led["saude"] = saude_mod + + cond_op_mod = [] penalidade_percentual_bateria = 0 if sensor_bateria_ativado: diff --git a/AgroBase/OperationControl/Windows/MainWindow.xaml b/AgroBase/OperationControl/Windows/MainWindow.xaml index 7b5360758..8d11d55f2 100644 --- a/AgroBase/OperationControl/Windows/MainWindow.xaml +++ b/AgroBase/OperationControl/Windows/MainWindow.xaml @@ -620,6 +620,51 @@ + + + + + +