using System.Windows;
using OperationControl.Controls;
using OperationControl.Models;
using System.Windows.Controls;
using System.Windows.Media;
using LibVLCSharp.Shared;
using System.Windows.Input;
using System.IO;
using MediaPlayer = LibVLCSharp.Shared.MediaPlayer;
using ComboBox = System.Windows.Controls.ComboBox;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
using Brush = System.Windows.Media.Brush;
using Brushes = System.Windows.Media.Brushes;
using Label = System.Windows.Controls.Label;
using Newtonsoft.Json.Linq;
using AgroBase.Models.Operadores;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Threading;
using AgroBase.Models.Operacoes;
namespace OperationControl.Windows
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window, INotifyPropertyChanged
{
private LibVLC _libVLC;
private MediaPlayer _playerFront;
private MediaPlayer _playerWeed;
private Media _mediaFront;
private Media _mediaWeed;
public MainWindow()
{
InitializeComponent();
cmbDir_Direcao.Items.Clear();
cmbDir_Direcao.Items.Add("Parado");
cmbDir_Direcao.Items.Add("Direita");
cmbDir_Direcao.Items.Add("Esquerda");
cmbDir_Direcao.SelectedIndex = 0;
cmbDir_Movimento.Items.Clear();
foreach (var m in Enum.GetNames(typeof(AgroBase.Models.Enums.TipoMovimentoDirecional)))
cmbDir_Movimento.Items.Add(m);
cmbDir_Movimento.SelectedIndex = 0;
AtualizarListaDispositivos(new List() { VariaveisControleOperacao.SelectedRoverId });
graficoAcompanhamento = new GraficoModel(pltSaude_Acompanhamento);
DataContext = this;
//DataContext = this;
// atualizar as caixas
//BBoxes3D.SetBboxes(new[]
//{
// new AgroBase.Models.LivoxBboxModel{ cx=1.2, cy=0.5, cz=0.4, d=0.6, w=0.4, h=0.8 },
// new AgroBase.Models.LivoxBboxModel{ cx=3.0, cy=-0.7, cz=0.6, d=0.8, w=0.5, h=1.2 },
//});
// Opções focadas em baixa latência
_libVLC = new LibVLC(
"--network-caching=1000", // ms (ajusta depois)
"--clock-jitter=0",
"--clock-synchro=0"
);
// Player da câmera frontal
_playerFront = new MediaPlayer(_libVLC);
VideoFront.MediaPlayer = _playerFront;
_playerWeed = new MediaPlayer(_libVLC);
VideoWeed.MediaPlayer = _playerWeed;
Loaded += MainWindow_Loaded;
Closed += MainWindow_Closed;
_toastTimer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(6) // tempo do toast na tela
};
_toastTimer.Tick += (s, e) =>
{
_toastTimer.Stop();
ToastAlerta = null;
};
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
}
private void MainWindow_Closed(object? sender, EventArgs e)
{
PararStreamCameraFrontal(true);
PararStreamCameraErvas(true);
_libVLC?.Dispose();
}
#region DISPOSITIVOS
public void AtualizarListaDispositivos(List dispositivos)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
cmbDispositivo.Items.Clear();
foreach (var d in dispositivos)
{
cmbDispositivo.Items.Add(d);
if (!MAP.markers.Added(d))
{
if (d == VariaveisControleOperacao.BaseMarkerID)
{
MAP.markers.AddMarker(
d,
true,
lat: Variaveis.GpsService?.UltimaLeitura?.Latitude ?? 0,
lon: Variaveis.GpsService?.UltimaLeitura?.Longitude ?? 0,
heading: Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal ?? 0,
label: "Base"
);
}
else
{
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.RoverId == d);
if (rover != null)
{
MAP.markers.AddMarker(
d,
false,
lat: rover.DadosLeitura?.Gps?.Latitude ?? 0,
lon: rover.DadosLeitura?.Gps?.Longitude ?? 0,
heading: rover.DadosLeitura?.Gps?.AnguloCarroDefinido ?? 0
);
}
}
}
}
int idx_selected = dispositivos.IndexOf(VariaveisControleOperacao.SelectedRoverId);
if (idx_selected > -1)
cmbDispositivo.SelectedIndex = idx_selected;
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI lista dispositivos: {exUi.Message}");
}
}));
}
private void cmbDispositivo_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
var selecionado = ((ComboBox)sender).SelectedItem;
if (selecionado == null) return;
bool dados_base = selecionado == VariaveisControleOperacao.BaseMarkerID;
if (dados_base && !VariaveisControleOperacao.BaseEmFoco)
{
PararStreamCameraFrontal();
PararStreamCameraErvas();
}
VariaveisControleOperacao.SelectedRoverId = selecionado.ToString();
MAP.markers.SetMarkerFocused(selecionado.ToString(), true);
AtualizarDadosTela_Telemetria(selecionado.ToString());
brdResumo.IsEnabled = !dados_base;
brdDiagnostico.IsEnabled = !dados_base;
brdStatusModulo.IsEnabled = !dados_base;
brdControle.IsEnabled = !dados_base;
brdAjustesOperacao.IsEnabled = !dados_base;
if (!dados_base)
{
btnParametros_Atualizar_Click(sender, e);
IniciarStreamCameraFrontal();
IniciarStreamCameraErvas();
}
}
public void LimparDadosTela_Telemetria(string rover_id)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
if (!string.IsNullOrEmpty(rover_id))
{
//MAP.markers.RemoveMarker(rover_id);
//cmbDispositivo.Items.Remove(rover_id);
}
else
{
//cmbDispositivo.SelectedIndex = 0;
}
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI telemetria (clear): {exUi.Message}");
}
}));
}
public void AtualizarDadosTela_Telemetria(string rover_id)
{
bool dados_base = rover_id == VariaveisControleOperacao.BaseMarkerID;
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.RoverId == rover_id);
var dados_leitura = rover?.DadosLeitura;
if (dados_base)
{
MAP.markers.UpdateMarkerPosition(rover_id, lat: Variaveis.GpsService?.UltimaLeitura?.Latitude, lon: Variaveis.GpsService?.UltimaLeitura?.Longitude, heading: Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal);
}
else if (dados_leitura != null)
{
var simulacao = dados_leitura.Controle?.SimulacaoMPC?.Select(x => new double[] { x.longitude, x.latitude })?.ToList();
MAP.markers.UpdateMarkerPosition(rover_id, lat: dados_leitura.Gps?.Latitude, lon: dados_leitura.Gps?.Longitude, heading: dados_leitura.Gps?.OrientacaoReal, predict: simulacao);
MAP.markers.UpdateMarkerInfo(rover_id, status: dados_leitura.StatusOperacao);
}
if (rover != null && dados_leitura?.ModulosSaude != null)
{
SeveridadeAlerta DeParaStatus(AgroBase.Models.Enums.StatusModulo status, bool mandatorio)
{
switch (status)
{
case AgroBase.Models.Enums.StatusModulo.Operante:
return SeveridadeAlerta.Info;
case AgroBase.Models.Enums.StatusModulo.Alerta:
return SeveridadeAlerta.Warning;
case AgroBase.Models.Enums.StatusModulo.Falha:
return (mandatorio) ? SeveridadeAlerta.Critical : SeveridadeAlerta.Error;
case AgroBase.Models.Enums.StatusModulo.Conectado:
return (mandatorio) ? SeveridadeAlerta.Warning : SeveridadeAlerta.Info;
case AgroBase.Models.Enums.StatusModulo.Desconectado:
return (mandatorio) ? SeveridadeAlerta.Critical : SeveridadeAlerta.Error;
default:
return SeveridadeAlerta.Info;
}
}
foreach (var mod in dados_leitura.ModulosSaude)
{
if (mod.saude_individual.Any())
{
foreach (var ind in mod.saude_individual)
{
if (ind.status != AgroBase.Models.Enums.StatusModulo.Operante)
{
AdicionarAlerta(rover.RoverId, mod.modulo, DeParaStatus(ind.status, ind.em_uso), string.Join(", ", ind.motivos), Mod_ID: ind.label);
}
else
{
RemoverAlerta(rover.RoverId, mod.modulo, Mod_ID: ind.label);
}
}
}
else
{
if (mod.status != AgroBase.Models.Enums.StatusModulo.Operante)
{
AdicionarAlerta(rover.RoverId, mod.modulo, DeParaStatus(mod.status, rover.ModulosMandatorios?.Any(x => x.Dispositivo == mod.modulo && x.Mandatorio) ?? false), string.Join(", ", mod.motivos));
}
else
{
RemoverAlerta(rover.RoverId, mod.modulo);
}
}
}
}
if (rover_id != VariaveisControleOperacao.SelectedRoverId) return;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
if (rover_id == VariaveisControleOperacao.BaseMarkerID)
{
Variaveis.MostrarLog($"Atualizando dados da tela para a base");
lblDispositivos_Status.Content = VariaveisControleOperacao.StatusBase.ToString();
AplicarStatusModuloNaLabel(lblDispositivos_Status, VariaveisControleOperacao.StatusBase, true, false);
AtualizarDadosTela_GNSS(Variaveis.GpsService?.UltimaLeitura ?? new AgroBase.Models.GPSModel(), marker_id: VariaveisControleOperacao.BaseMarkerID);
AtualizarDadosTela_Heading(Variaveis.GpsService?.UltimaLeitura?.AnguloCarroDefinido ?? 0);
}
else
{
if (dados_leitura == null) return;
Variaveis.MostrarLog($"Atualizando dados da tela para o dispositivo {rover_id}");
lblDispositivos_Status.Content = (rover?.DadosLeitura?.Status ?? AgroBase.Models.Enums.StatusModulo.Desconectado).ToString();
AplicarStatusModuloNaLabel(lblDispositivos_Status, rover?.DadosLeitura?.Status ?? AgroBase.Models.Enums.StatusModulo.Desconectado, true, false);
AtualizarDadosTela_Diagnosticos(rover);
AtualizarDadosTela_Resumo_Conexao(dados_leitura);
if (dados_leitura.Trajetoria != null)
AtualizarDadosTela_Resumo(dados_leitura);
if (dados_leitura.Gps != null)
AtualizarDadosTela_GNSS(dados_leitura.Gps, marker_id: rover_id);
if (dados_leitura.Controle != null)
AtualizarDadosTela_Controle(dados_leitura.Controle, dados_leitura.Direcional.AnguloMedio, dados_leitura.Movimentacao.VelocidadeMedia, dados_leitura.Emergencia, !dados_leitura.OperacaoIniciada, dados_leitura.StatusOperacao == AgroBase.Models.Enums.StatusOperacao.Calibrando);
//if (rover.Value.Controle != null)
// AtualizarDadosTela_ParametrosOperacao(rover.Value.Controle);
if (dados_leitura.Trajetoria != null)
AtualizarDadosTela_Mapa(dados_leitura.Trajetoria);
if (dados_leitura.Gps != null)
AtualizarDadosTela_Heading(dados_leitura.Gps.AnguloCarroDefinido, dados_leitura.Modo == AgroBase.Models.Enums.ModoOperacao.Manual ? double.NaN : dados_leitura.Trajetoria.AnguloCaminho);
if (dados_leitura.IMU != null)
AtualizarDadosTela_IMU(dados_leitura.IMU.InclinacaoLateral, dados_leitura.IMU.InclinacaoFrontal);
if (rover.Controle != null)
AtualizarDadosTela_Pulverizador(dados_leitura);
if (dados_leitura.LivoxLidar != null)
AtualizarDadostela_LIDAR(dados_leitura.LivoxLidar.bboxes);
}
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI telemetria (set): {exUi.Message}");
}
}));
}
#endregion
#region RESUMO OPERACIONAL
public void AtualizarDadosTela_Resumo(AgroBase.Models.OperacaoSensoriamentoLogModel dados)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
pgbResumo_RuaAtual.Value = dados.Trajetoria.PercentualRuaAtual;
lblResumo_RuaAtual.Content = $"{dados.Trajetoria.CorredorAtual.DistanciaPercorridaCorredor:0.00} m / {dados.Trajetoria.CorredorAtual.DistanciaTotal:0.00} m ({dados.Trajetoria.CorredorAtual.Idx + 1})";
pgbResumo_AreaTotal.Value = dados.Trajetoria.PercentualOperacao;
lblResumo_AreaTotal.Content = $"{dados.Trajetoria.DistanciaPercorrida:0.00} m / {dados.Trajetoria.DistanciaTotal:0.00} m";
pgbResumo_Bateria.Value = dados.Bateria.PercentualBateria;
lblResumo_Bateria.Content = $"{dados.Bateria.TensaoInstantanea:0.00} V ({TimeSpan.FromMinutes(dados.Bateria.TempoEstimadoRestanteMinutos).ToString(@"dd\.hh\:mm\:ss")} {dados.Bateria.DistanciaEstimadaRestanteMetros:0.00} m)";
pgbResumo_Herbicida.Value = dados.Atuador.PercentualReservatorio;
lblResumo_Herbicida.Content = $"{dados.Atuador.VolumeReservatorio:0.00} L ({TimeSpan.FromMinutes(dados.Atuador.TempoEstimadoRestanteMinutos).ToString(@"hh\:mm\:ss")} {dados.Atuador.DistanciaEstimadaRestanteMetros:0.00} m)";
pgbResumo_Infestacao.Value = dados.Atuador.PercentualErvasTerreno;
lblResumo_Infestacao.Content = $"{dados.Atuador.HerbicidaPorErva:0.00} mL/erva";
lblResumo_OperacaoLiberada.Content = $"Operação " + (dados.OperacaoLiberada ? "🔓 Liberada" : "🔒 Bloqueada");
lblResumo_OperacaoModo.Content = $"Modo {dados.Modo}";
lblResumo_OperacaoStatus.Content = $"Status {dados.StatusOperacao}" + (dados.StatusOperacao == AgroBase.Models.Enums.StatusOperacao.Aguardando ? $" ({dados.TempoAguardandoSeg:0})" : "");
lblResumo_StatusCarro.Content = $"Carro {dados.Trajetoria.StatusCarro}";
lblResumo_TemperaturaGeral.Content = $"Temperatura {(dados.DadosPerformance.CPU_temp ?? 0):0.00} °C";
lblResumo_OperacaoDuracao.Content = $"Duração {dados.TempoDecorrido.ToString("HH:mm:ss")} / " + (string.IsNullOrEmpty(dados.Trajetoria.TempoEstimadoOperacao) ? "00:00:00" : dados.Trajetoria.TempoEstimadoOperacao);
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Resumo: {exUi.Message}");
}
}));
}
public void AtualizarDadosTela_Resumo_Conexao(AgroBase.Models.OperacaoSensoriamentoLogModel dados)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
var conexao = dados.ModulosSaude?.FirstOrDefault(x => x.modulo == AgroBase.Models.Enums.T_Code.Ipb);
double conexao_saude = conexao?.saude ?? 0;
double conexao_latencia = conexao?.detalhes?["avg_rtt"]?.Value() ?? 0.0;
double conexao_perda = conexao?.detalhes?["loss_pct"]?.Value() ?? 0.0;
double bwTot = conexao?.detalhes?["bw_total_mbps"]?.Value() ?? 0;
pgbResumo_Conexao.Value = conexao_saude;
lblResumo_Conexao.Content = $"{conexao_latencia:0.00} ms {conexao_perda:0.00}% {bwTot:0.00} Mbps";
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Resumo_Conexao: {exUi.Message}");
}
}));
}
#endregion
#region DIAGNOSTICOS
private Label _labelModuloSelecionado;
private GraficoModel graficoAcompanhamento;
private void AtualizarDadosTela_Diagnosticos(AgroBase.Models.Operacoes.OperacaoParametrosModel dados)
{
lblDiagnosticos_Impedimento.Text = "Impedimento: " + (string.IsNullOrEmpty(dados.DadosLeitura.ErroOperacaoLiberada) ? "Nenhum" : dados.DadosLeitura.ErroOperacaoLiberada.Replace("\n\n", "; "));
// Canvas que está dentro do Border
var canvas = brdDiagnostico.Child as Canvas;
if (canvas == null)
return;
// Percorre apenas labels dentro do Canvas com o prefixo desejado
foreach (var lbl in canvas.Children.OfType