Ajustes no CoolerControl e health sensoriamento

This commit is contained in:
Diego Freitas 2025-12-11 16:50:38 -03:00
parent c052d9295d
commit f8b022ce11
7 changed files with 246 additions and 8 deletions

View File

@ -690,7 +690,7 @@ namespace AgroBase
{
List<string> modsControlar = null;
if (!string.IsNullOrEmpty(ID))
modsControlar.Add(ID);
modsControlar = new List<string>() { ID };
if (MovimentosCombinados.Contains(Variaveis.OperacaoEmAndamento.Controle.TipoMovimento))
{
Task.Run(async () => await Variaveis.OperacaoEmAndamento.DispMvd.Dados.ExecutarMovimentoDirecionalCombinado(DirecaoAtual));

View File

@ -2296,7 +2296,7 @@ namespace AgroBase.Models
public List<DispositivoDetalhesModel> DispositivosMapeados { get; set; }
public Dictionary<string, double> Temperaturas { get; set; }
public Dictionary<string, (bool, bool)> Reles { get; set; }
public Dictionary<string, (int, int)> Servos { get; set; }
public Dictionary<string, (int, int, bool)> Servos { get; set; }
public Dictionary<T_Code, Dictionary<string, bool>> ModsCalibragem { get; set; }
public bool CanSerialAtivado { get; set; }
public Dictionary<string, bool> Iniciados { get; set; }
@ -2570,7 +2570,7 @@ namespace AgroBase.Models
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(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<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()),
CoolerControl = dadosCooler,
@ -2625,7 +2625,7 @@ namespace AgroBase.Models
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(ModsCalibragem),
Temperaturas = new Dictionary<string, double>(Temperaturas ?? new Dictionary<string, double>()),
Reles = new Dictionary<string, (bool, bool)>(Reles ?? new Dictionary<string, (bool, bool)>()),
Servos = new Dictionary<string, (int, int)>(Servos ?? new Dictionary<string, (int, int)>()),
Servos = new Dictionary<string, (int, int, bool)>(Servos ?? new Dictionary<string, (int, int, bool)>()),
Iniciados = new Dictionary<string, bool>(Iniciados ?? new Dictionary<string, bool>()),
Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()),
CoolerControl = CoolerControl?.Clone(),

View File

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

View File

@ -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<object>(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<object>(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),

View File

@ -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:

View File

@ -620,6 +620,51 @@
</UniformGrid>
</StackPanel>
<!-- Painel específico de Servo (SEN) -->
<StackPanel x:Name="panelOpcoes_Servo" Grid.Row="0" Visibility="Collapsed">
<!-- Título / identificação -->
<StackPanel Orientation="Horizontal">
<Label Content="Controle"/>
<Slider x:Name="sldServo_Angulo" Minimum="0" Maximum="90" TickFrequency="1" Width="130" Margin="5" ValueChanged="sldServo_Angulo_ValueChanged"/>
<Label x:Name="lblServo_Angulo" Content="0°"/>
<Button x:Name="btnServo_Enviar" Content="Enviar" Width="80" Margin="5 3 0 3" Click="btnServo_Enviar_Click"/>
</StackPanel>
<!-- “Cartõezinhos” de status -->
<UniformGrid Grid.Row="2" Rows="1" Columns="3" Margin="0,0,0,0">
<!-- Comando enviado -->
<Border BorderBrush="Gray" BorderThickness="1" Margin="2" Padding="3">
<StackPanel>
<TextBlock Text="Comando enviado" FontSize="9" FontWeight="Bold"/>
<TextBlock x:Name="txtServo_Comando" FontSize="10" Text="—"/>
</StackPanel>
</Border>
<!-- Status real -->
<Border BorderBrush="Gray" BorderThickness="1" Margin="2" Padding="3">
<StackPanel>
<TextBlock Text="Status real" FontSize="9" FontWeight="Bold"/>
<TextBlock x:Name="txtServo_Leitura" FontSize="10" Text="—"/>
</StackPanel>
</Border>
<!-- Incremental -->
<Border BorderBrush="Gray" BorderThickness="1" Margin="2" Padding="3">
<StackPanel>
<TextBlock Text="Modo" FontSize="9" FontWeight="Bold"/>
<TextBlock x:Name="txtServo_Incremental" FontSize="10" Text="—"/>
</StackPanel>
</Border>
</UniformGrid>
</StackPanel>
<!-- Painel específico de NPC -->
<StackPanel x:Name="panelOpcoes_NPC" Grid.Row="0" Visibility="Collapsed">

View File

@ -1051,6 +1051,7 @@ namespace OperationControl.Windows
panelOpcoes_Trajetoria.Visibility = Visibility.Collapsed;
panelOpcoes_Rele.Visibility = Visibility.Collapsed;
panelOpcoes_NPC.Visibility = Visibility.Collapsed;
panelOpcoes_Servo.Visibility = Visibility.Collapsed;
}
switch (modulo)
@ -1128,6 +1129,19 @@ namespace OperationControl.Windows
txtRele_StatusReal.Text = leitura ? "Ligado" : "Desligado";
break;
}
case AgroBase.Models.Enums.S_Code.sFRO:
{
panelOpcoes_Servo.Visibility = Visibility.Visible;
var servo = rover?.Servos?.FirstOrDefault(x => x.Key == label).Value;
int comando = servo?.Item1 ?? 0;
int leitura = servo?.Item2 ?? 0;
bool inc = servo?.Item3 ?? false;
txtServo_Comando.Text = $"{comando}°";
txtServo_Leitura.Text = $"{leitura}°";
txtServo_Incremental.Text = inc ? "Incremental" : "Decremental";
break;
}
default:
txtOpcoes_SemDados.Visibility = Visibility.Visible;
break;
@ -1419,6 +1433,29 @@ namespace OperationControl.Windows
#endregion
#region Servo
private void btnServo_Enviar_Click(object sender, RoutedEventArgs e)
{
(var modulo, var label, var s_code, var iniciado) = GetModuleData(_labelModuloSelecionado);
if (modulo != AgroBase.Models.Enums.T_Code.Sen && s_code != AgroBase.Models.Enums.S_Code.sFRO)
return;
var servo = VariaveisControleOperacao.RoverEmFoco?.DadosLeitura?.Servos?.FirstOrDefault(x => x.Key == label).Value;
double angulo = Convert.ToInt32(sldServo_Angulo.Value);
if (!(servo?.Item3 ?? false)) angulo = 180 - angulo;
VariaveisControleOperacao.EnviarComandoSensoriamento(label, status: angulo);
}
private void sldServo_Angulo_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (lblServo_Angulo != null)
lblServo_Angulo.Content = $"{Convert.ToInt32(sldServo_Angulo.Value):0}°";
}
#endregion
#region Cooler Control
private void btnNpc_CoolerEnviar_Click(object sender, RoutedEventArgs e)
@ -2093,6 +2130,7 @@ namespace OperationControl.Windows
#endregion