using System.ComponentModel; using System.Windows.Input; using OperationControl.Views; using OperationControl.Helpers; using System.Windows; using OperationControl.Models; using OperationControl.Views.Operacao; using AgroBase.Models.Operacoes; using Newtonsoft.Json.Linq; using OperationControl.ViewModels.Views.Operacao; using OperationControl.Controls; using static AgroBase.Models.Enums; namespace OperationControl.ViewModels { public class DockWindowViewModel : INotifyPropertyChanged { private readonly ConfigConexaoView _viewConfig; private readonly PreparacaoMapaView _viewPreparacaoMapa; public readonly PreparacaoMapaTopView _viewPreparacaoMapaTop; private readonly PreparacaoMapaBottomView _viewPreparacaoMapaBottom; private readonly OperacaoTopView _viewOperacaoTop; private readonly OperacaoCenterView _viewOperacaoCenter; public readonly OperacaoLeftView _viewOperacaoLeft; public readonly OperacaoRightView _viewOperacaoRight; public readonly OperacaoBottomView _viewOperacaoBottom; public OperacaoBottomViewModel BottomVM => _viewOperacaoBottom?._vm; private DockStep _currentStep; public DockWindowViewModel() { // Views _viewConfig = new ConfigConexaoView(); _viewConfig._vm.TudoOkChanged += OnTudoOkChanged; _viewPreparacaoMapa = new PreparacaoMapaView(); _viewPreparacaoMapaTop = new PreparacaoMapaTopView(); _viewPreparacaoMapaBottom = new PreparacaoMapaBottomView(); _viewPreparacaoMapaBottom._vm.CarregarMapaSolicitado += OnCarregarMapaSolicitado; _viewPreparacaoMapaBottom._vm.FixarBaseSolicitado += OnFixarBaseSolicitado; _viewOperacaoTop = new OperacaoTopView(); _viewOperacaoCenter = new OperacaoCenterView(); _viewOperacaoCenter._vm.RoverSelecionadoChanged += OnRoverSelecionadoChanged; _viewOperacaoLeft = new OperacaoLeftView(); _viewOperacaoRight = new OperacaoRightView(); _viewOperacaoRight._vm.PropertyChanged += OperacaoRightVm_PropertyChanged; _viewOperacaoRight._vm.RoverSelecionadoChanged += OnRoverSelecionadoChanged; _viewOperacaoRight._vm.SecaoSelecionadaChanged += OnSecaoSelecionadaChanged; _viewOperacaoRight.areaParametrizacao._vm.LerParametrosSolicitado += OnLerParametrosSolicitado; _viewOperacaoRight.areaParametrizacao._vm.SalvarParametrosSolicitado += OnSalvarParametrosSolicitado; _viewOperacaoBottom = new OperacaoBottomView(); _viewOperacaoBottom._vm.SolicitarAbrirDiagnostico += AbrirDiagnosticoPeloAlerta; // Commands BackCommand = new RelayCommand(_ => GoBack(), _ => CanGoBack); NextCommand = new RelayCommand(_ => GoNext(), _ => CanGoNext); // Estado inicial ConfigConexaoOk = _viewConfig._vm.TudoOk; CurrentStep = DockStep.ConfigConexao; } private void OnTudoOkChanged(bool ok) { ConfigConexaoOk = ok; OnPropertyChanged(nameof(CanGoNext)); CommandManager.InvalidateRequerySuggested(); } // ====== ETAPA ATUAL ====== public ModoOperacao ModoOperacaoAtual => _viewConfig._vm.TipoOperacaoSelecionado; public DockStep CurrentStep { get => _currentStep; set { if (_currentStep != value) { _currentStep = value; OnPropertyChanged(nameof(CurrentStep)); OnPropertyChanged(nameof(CanGoBack)); OnPropertyChanged(nameof(CanGoNext)); OnPropertyChanged(nameof(MostrarPainelEsquerdo)); OnPropertyChanged(nameof(MostrarBotaoVoltarEsquerda)); OnPropertyChanged(nameof(RightPanelWidth)); OnPropertyChanged(nameof(LeftPanelWidth)); AtualizarConteudo(); CommandManager.InvalidateRequerySuggested(); } } } // ====== ESTADO ====== private bool _configConexaoOk; public bool ConfigConexaoOk { get => _configConexaoOk; set { if (_configConexaoOk != value) { _configConexaoOk = value; OnPropertyChanged(nameof(ConfigConexaoOk)); OnPropertyChanged(nameof(CanGoNext)); CommandManager.InvalidateRequerySuggested(); } } } private bool _mapaCarregado; public bool MapaCarregado { get => _mapaCarregado; set { if (_mapaCarregado != value) { _mapaCarregado = value; OnPropertyChanged(nameof(MapaCarregado)); OnPropertyChanged(nameof(CanGoNext)); CommandManager.InvalidateRequerySuggested(); } } } private bool _baseFixada = AppShell.Mock; public bool BaseFixada { get => _baseFixada; set { if (_baseFixada != value) { _baseFixada = value; OnPropertyChanged(nameof(BaseFixada)); OnPropertyChanged(nameof(CanGoNext)); CommandManager.InvalidateRequerySuggested(); } } } public bool CanGoBack => CurrentStep != DockStep.ConfigConexao; public bool CanGoNext { get { return CurrentStep switch { DockStep.ConfigConexao => PodeAvancarConfigConexao(), DockStep.PreparacaoMapa => MapaCarregado && BaseFixada, _ => false }; } } private bool PodeAvancarConfigConexao() { return ModoOperacaoAtual switch { ModoOperacao.Automatico => _viewConfig._vm.RedeOk && _viewConfig._vm.GnssOk, ModoOperacao.Manual => _viewConfig._vm.RedeOk, _ => false }; } public bool MostrarPainelEsquerdo => CurrentStep == DockStep.ParametrizacaoRover; public bool MostrarBotaoVoltarEsquerda => CurrentStep != DockStep.ParametrizacaoRover; public GridLength LeftPanelWidth { get { return CurrentStep switch { DockStep.ParametrizacaoRover => new GridLength(280), _ => new GridLength(60) }; } } public GridLength RightPanelWidth { get { return CurrentStep switch { DockStep.ParametrizacaoRover => _viewOperacaoRight?._vm?.IsCollapsed == true ? new GridLength(44) : new GridLength(320), _ => new GridLength(60) }; } } private void OperacaoRightVm_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(OperacaoRightViewModel.IsCollapsed)) { OnPropertyChanged(nameof(RightPanelWidth)); } } // ====== CONTEÚDOS ====== private object _centerContent; public object CenterContent { get => _centerContent; set { _centerContent = value; OnPropertyChanged(nameof(CenterContent)); } } private object _topContent; public object TopContent { get => _topContent; set { _topContent = value; OnPropertyChanged(nameof(TopContent)); } } private object _bottomContent; public object BottomContent { get => _bottomContent; set { _bottomContent = value; OnPropertyChanged(nameof(BottomContent)); } } private object _leftContent; public object LeftContent { get => _leftContent; set { _leftContent = value; OnPropertyChanged(nameof(LeftContent)); } } private object _rightContent; public object RightContent { get => _rightContent; set { _rightContent = value; OnPropertyChanged(nameof(RightContent)); } } // ====== COMMANDS ====== public ICommand BackCommand { get; } public ICommand NextCommand { get; } private void GoBack() { switch (CurrentStep) { case DockStep.PreparacaoMapa: CurrentStep = DockStep.ConfigConexao; break; } } private void GoNext() { if (!CanGoNext) return; switch (CurrentStep) { case DockStep.ConfigConexao: if (ModoOperacaoAtual == ModoOperacao.Manual) CurrentStep = DockStep.ParametrizacaoRover; else CurrentStep = DockStep.PreparacaoMapa; break; case DockStep.PreparacaoMapa: CurrentStep = DockStep.ParametrizacaoRover; break; } } private FrameworkElement CriarBotaoNextSimples() { return new System.Windows.Controls.Button { Content = "⮞", FontSize = 24, Width = 40, Height = 40, HorizontalAlignment = System.Windows.HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, Command = NextCommand }; } private void AtualizarConteudo() { TopContent = null; BottomContent = null; LeftContent = null; RightContent = null; CenterContent = null; switch (CurrentStep) { case DockStep.ConfigConexao: CenterContent = _viewConfig; RightContent = CriarBotaoNextSimples(); break; case DockStep.PreparacaoMapa: TopContent = _viewPreparacaoMapaTop; CenterContent = _viewPreparacaoMapa; BottomContent = _viewPreparacaoMapaBottom; RightContent = CriarBotaoNextSimples(); break; case DockStep.ParametrizacaoRover: TopContent = _viewOperacaoTop; LeftContent = _viewOperacaoLeft; CenterContent = _viewOperacaoCenter; RightContent = _viewOperacaoRight; BottomContent = _viewOperacaoBottom; AtualizarDadosMapa(null); AtualizarBarraSuperior(StatusModulo.Conectado, "BASE", "VISÃO GERAL", "Selecione um equipamento na lista à direita para configurá-lo", "NORMAL", "Aguardando"); break; } OnPropertyChanged(nameof(MostrarPainelEsquerdo)); OnPropertyChanged(nameof(MostrarBotaoVoltarEsquerda)); } // ====== INotifyPropertyChanged ====== public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string nome) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nome)); } public void AtualizarBarraSuperior(OperacaoParametrosModel rover) { var obj = rover?.DadosLeitura; if (rover == null || obj == null) return; if (rover.RoverId != VariaveisControleOperacao.SelectedRoverId) return; var eventos = new List(); double tempoSemResposta = (DateTime.Now - rover.UltimoContato).TotalSeconds; bool semComunicacao = tempoSemResposta >= VariaveisControleOperacao.TempoRoverVivo; if (semComunicacao) { eventos.Add(new MotivoTopBarModel { Prioridade = 2000, Fonte = "Comunicacao", Titulo = "PERDA DE COMUNICAÇÃO COM O ROVER", Descricao = $"Sem resposta do rover há {tempoSemResposta:F1} s. Tentando reconectar automaticamente.", StatusVisual = StatusModulo.Desconectado }); } if (obj.ModulosSaude?.All(x => (x?.status ?? StatusModulo.Desconectado) == StatusModulo.Desconectado) ?? false) { // ============================ // 0) NCP desconectado // ============================ eventos.Add(new MotivoTopBarModel { Prioridade = 1100, Fonte = "Núcleo Central de Processamento", Titulo = "NÚCLEO CENTRAL DE PROCESSAMENTO DESCONECTADO", Descricao = "O núcleo central de processamento foi desconectado, tentando reconectar...", StatusVisual = StatusModulo.Falha }); } // ============================ // 1) Emergência // ============================ if (obj.Operacao?.Emergencia == true) { eventos.Add(new MotivoTopBarModel { Prioridade = 1000, Fonte = "Emergencia", Titulo = "OPERAÇÃO BLOQUEADA POR EMERGÊNCIA", Descricao = "Parada de emergência solicitada.", StatusVisual = StatusModulo.Falha }); } // ============================ // 2) Pausa // ============================ if (obj.Operacao?.Pausa == true) { eventos.Add(new MotivoTopBarModel { Prioridade = 900, Fonte = "Pausa", Titulo = "OPERAÇÃO PAUSADA", Descricao = "Pausa operacional solicitada.", StatusVisual = StatusModulo.Alerta }); } // ============================ // 3) Controle // ============================ var motivosControle = obj.Controle?.Motivos? .Where(x => !string.IsNullOrWhiteSpace(x)) .Distinct() .ToList() ?? new List(); foreach (var motivo in motivosControle) { eventos.Add(new MotivoTopBarModel { Prioridade = 800, Fonte = "Controle", Titulo = "CONTROLE SEM LIBERAÇÃO", Descricao = motivo, StatusVisual = StatusModulo.Alerta }); } // ============================ // 4) Trajetória / autonomia // ============================ var motivosTrajetoria = obj.Trajetoria?.AutonomiaCorredor?.Motivos? .Where(x => !string.IsNullOrWhiteSpace(x)) .Distinct() .ToList() ?? new List(); foreach (var motivo in motivosTrajetoria) { eventos.Add(new MotivoTopBarModel { Prioridade = 700, Fonte = "Trajetoria", Titulo = "TRAJETÓRIA BLOQUEADA", Descricao = motivo, StatusVisual = StatusModulo.Alerta }); } // ============================ // 5) Módulos com condições operacionais críticas // ============================ var modulosCriticos = obj.ModulosSaude? .Where(mod => mod?.condicoes_operacionais?.Any(cond => cond?.severidade > 90) ?? false) .ToList() ?? new List(); foreach (var modulo in modulosCriticos) { var nomeModulo = (modulo?.modulo ?? T_Code.Vzo).ToString(); var descricoesCriticas = modulo?.condicoes_operacionais? .Where(cond => cond?.severidade > 90) .Select(cond => cond?.descricao ?? "") .Where(desc => !string.IsNullOrWhiteSpace(desc)) .Distinct() .ToList() ?? new List(); foreach (var desc in descricoesCriticas) { eventos.Add(new MotivoTopBarModel { Prioridade = 600, Fonte = "ModuloCritico", Titulo = "CONDIÇÕES OPERACIONAIS CRÍTICAS", Descricao = $"{nomeModulo}: {desc}", StatusVisual = StatusModulo.Alerta, Modulo = modulo?.modulo }); } } var ordemModulos = new Dictionary { { T_Code.Ipb, 1 }, { T_Code.Npc, 2 }, { T_Code.Bat, 3 }, { T_Code.Atu, 4 }, { T_Code.Sen, 5 } }; // ============================ // 6) Remove vazios / repetidos // ============================ var eventosOrdenados = eventos .Where(x => !string.IsNullOrWhiteSpace(x.Titulo) && !string.IsNullOrWhiteSpace(x.Descricao)) .GroupBy(x => new { x.Fonte, x.Titulo, x.Descricao, x.Prioridade, x.StatusVisual }) .Select(g => g.First()) .OrderByDescending(x => x.Prioridade) .ThenBy(x => x.Modulo.HasValue && ordemModulos.ContainsKey(x.Modulo.Value)? ordemModulos[x.Modulo.Value] : int.MaxValue) .ThenBy(x => x.Fonte) .ToList(); // ============================ // 7) Monta visual final // ============================ StatusModulo statusVisual; string linha1; string linha2; string badge; string resumo; if (eventosOrdenados.Any()) { var principal = eventosOrdenados.First(); statusVisual = principal.StatusVisual; linha1 = principal.Titulo; // Pega até 3 descrições distintas, por prioridade var descricoes = eventosOrdenados .Select(x => x.Descricao?.Trim()) .Where(x => !string.IsNullOrWhiteSpace(x)) .Distinct() .Take(3) .ToList(); linha2 = string.Join(" • ", descricoes); // Badge curto badge = principal.Fonte switch { "Comunicacao" => "DESCONECTADO", "Emergencia" => "EMERGÊNCIA", "Pausa" => "PAUSADO", "Trajetoria" => "TRAJETÓRIA", "Controle" => "CONTROLE", "ModuloCritico" => "ALERTA", _ => statusVisual.ToString().ToUpper() }; // Resumo curto resumo = principal.Fonte switch { "Comunicacao" => "Sem telemetria", "Emergencia" => "Parada imediata", "Pausa" => "Aguardando retomada", "Trajetoria" => "Operação bloqueada", "Controle" => "Controle bloqueado", "ModuloCritico" => "Atenção operacional", _ => (obj.Operacao?.Status ?? StatusOperacao.NaoIniciado).ToString() }; } else { statusVisual = obj.StatusRover == StatusModulo.Desconectado ? StatusModulo.Desconectado : StatusModulo.Operante; linha1 = "ROVER OPERANDO NORMALMENTE"; linha2 = "Trajetória, controle e operação em condição normal."; badge = statusVisual.ToString().ToUpper(); resumo = (obj.Operacao?.Status ?? StatusOperacao.NaoIniciado).ToString(); } // Segurança extra: evita linha vazia if (string.IsNullOrWhiteSpace(linha2)) linha2 = "Sem detalhes adicionais."; Variaveis.MostrarLog($"LINHA 1: {linha1}"); // ============================ // 8) Atualiza UI // ============================ System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { _viewOperacaoTop?._vm.AtualizarStatus( statusVisual, rover.RoverId, obj?.Operacao?.Status ?? StatusOperacao.NaoIniciado, linha1, linha2, badge, resumo ); })); } public void AtualizarBarraSuperior(StatusModulo status, string titulo, string linha1, string linha2, string status_str, string resumo) { System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { _viewOperacaoTop?._vm.AtualizarStatus(status, titulo, StatusOperacao.Parametrizando, linha1, linha2.Replace("\n\n", " • "), status_str, resumo); })); } public void AtualizarDadosGnss(AgroBase.Models.GPSModel dados) { var bf = Variaveis.GpsService.BaseFix; if (bf.CorrecaoEmAndamento) { AtualizarProgressoFixacaoBase(bf.Progresso, bf.ProgressoStr); if (bf.Progresso >= 100) FinalizarFixacaoBase(true, bf.ProgressoStr); } MapViewControl? Mapa = CurrentStep == DockStep.PreparacaoMapa ? _viewPreparacaoMapa?.MapaPreparacao : CurrentStep == DockStep.ParametrizacaoRover ? _viewOperacaoCenter?.Mapa : null; if (CurrentStep == DockStep.PreparacaoMapa) { _viewPreparacaoMapaTop?._vm?.AtualizarDados(dados); } CriarMarcadorBase(Mapa); Mapa?.markers?.UpdateMarkerPosition(VariaveisControleOperacao.BaseMarkerID, lat: dados?.Latitude, lon: dados?.Longitude, heading: dados?.OrientacaoReal); } public void AtualizarParametrosRover(OperacaoParametrosModel? rover) { _viewOperacaoRight?.areaParametrizacao?._vm?.AtualizarParametros(rover); AtualizarDadosMapa(rover); } public void AtualizarDadosMapa(OperacaoParametrosModel? dados) { _viewOperacaoCenter?.Mapa?.LoadMapFile(_ultimoMapaCarregado); _viewOperacaoCenter?.Mapa?.CarregarDadosMapa(dados?.Mapa, dados?.RuasPercorrer); } #region TELA 2 private string? _ultimoMapaCarregado; private void CriarMarcadorBase(MapViewControl Mapa) { string markerId = VariaveisControleOperacao.BaseMarkerID; if (!Mapa?.markers?.Added(markerId) ?? false) { Mapa?.markers?.AddMarker( markerId, true, lat: Variaveis.GpsService?.UltimaLeitura?.Latitude, lon: Variaveis.GpsService?.UltimaLeitura?.Longitude, heading: Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal, label: "Base" ); } } private void OnCarregarMapaSolicitado(string caminhoArquivo) { try { _ultimoMapaCarregado = caminhoArquivo; _viewPreparacaoMapa?.MapaPreparacao?.LoadMapFile(caminhoArquivo); MapaCarregado = true; _viewPreparacaoMapaBottom?._vm.AtualizarProgresso(0, $"Mapa carregado: {System.IO.Path.GetFileName(caminhoArquivo)}"); } catch (Exception ex) { MapaCarregado = false; _viewPreparacaoMapaBottom?._vm.AtualizarProgresso(0, $"Erro ao carregar mapa: {ex.Message}"); } } private async void OnFixarBaseSolicitado() { try { if (!Variaveis.GpsService.BaseFix.FixLiberado) { bool fixar = false; if (Variaveis.GpsService.BaseFix.PosicaoBaseFixada) { var res = System.Windows.MessageBox.Show( "Mudar posição da base?", "Tem certeza que deseja fixar a posição da base novamente?", MessageBoxButton.YesNo, MessageBoxImage.Question); if (res == MessageBoxResult.Yes) fixar = true; } else { fixar = true; } if (fixar) { _viewPreparacaoMapaBottom?._vm.IniciarFixacao(); await Task.Run(async () => await Variaveis.GpsService.ConfigurarModulo(true)); } } else { Variaveis.GpsService.BaseFix.ReiniciarFix(); BaseFixada = false; _viewPreparacaoMapaBottom?._vm.CancelarFixacao("Fixação da base interrompida pelo operador."); } } catch (Exception ex) { _viewPreparacaoMapaBottom?._vm.FinalizarFixacao(false, $"Erro na fixação da base: {ex.Message}"); } } public void AtualizarProgressoFixacaoBase(double progresso, string status) { System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { _viewPreparacaoMapaBottom?._vm.AtualizarProgresso(progresso, status); })); } public void FinalizarFixacaoBase(bool sucesso, string mensagem) { System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { BaseFixada = sucesso; _viewPreparacaoMapaBottom?._vm.FinalizarFixacao(sucesso, mensagem); })); } public void CancelarFixacaoBase(string mensagem) { System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { BaseFixada = false; _viewPreparacaoMapaBottom?._vm.CancelarFixacao(mensagem); })); } #endregion #region TELA 3 public void AtualizarListaRovers(List rovers_atual) { var cards = rovers_atual.Select(x => new RoverCardModel() { EquipamentoId = x.IP, NumeroSerie = x.RoverId, Status = x.DadosLeitura?.StatusRover ?? AgroBase.Models.Enums.StatusModulo.Desconectado }).ToArray(); _viewOperacaoRight?._vm?.AtualizarListaRovers(cards); foreach (var rover in cards) { if (!_viewOperacaoCenter?.Mapa?.markers?.Added(rover.NumeroSerie) ?? false) { var roverDados = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.RoverId == rover.NumeroSerie); if (roverDados != null) { _viewOperacaoCenter?.Mapa?.markers?.AddMarker( rover.NumeroSerie, false, lat: roverDados.DadosLeitura?.Gnss?.Latitude ?? 0, lon: roverDados.DadosLeitura?.Gnss?.Longitude ?? 0, heading: roverDados.DadosLeitura?.Gnss?.OrientacaoReal ?? 0 ); } } } } public void AtualizarDadosTela(OperacaoParametrosModel rover) { if (rover == null) return; var obj = rover.DadosLeitura; if (obj == null) return; // MAPA var simulacao = obj.Controle?.SimulacaoMPC?.Select(x => new double[] { x.longitude, x.latitude })?.ToList(); _viewOperacaoCenter?.Mapa?.markers.UpdateMarkerPosition(rover.RoverId, lat: obj.Gnss?.Latitude, lon: obj.Gnss?.Longitude, heading: obj.Gnss?.OrientacaoReal, predict: simulacao); _viewOperacaoCenter?.Mapa?.markers.UpdateMarkerInfo(rover.RoverId, status: obj.Operacao?.Status ?? AgroBase.Models.Enums.StatusOperacao.NaoIniciado); // ALERTAS _viewOperacaoBottom?._vm?.AtualizarListaAlertasTodosRovers(); if (rover.RoverId != VariaveisControleOperacao.SelectedRoverId) return; AtualizarBarraSuperior(rover); // ESQUERDA var conexao = obj.ModulosSaude?.FirstOrDefault(x => x.modulo == T_Code.Ipb); double c = 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.0; string comunicacao = $"{conexao_latencia:0.00} ms {bwTot:0.00} Mbps"; string comunicacao_extended = $"{conexao_latencia:0.00} ms {conexao_perda:F2}% {bwTot:0.00} Mbps"; _viewOperacaoLeft?._vm?.AtualizarRover( rover?.Descricao ?? "", obj.Controle?.PercentualVelocidadeSPKmh ?? 0, obj.Controle?.Angulo ?? 0, obj.Controle?.TipoMovimento ?? TipoMovimentoDirecional.Diagnostico, obj.Refrigeracao?.Temperatura ?? 0, obj.Bateria?.PercentualBateria ?? 0, obj.Atuador?.PercentualReservatorio ?? 0, $"{c}%", $"{obj.Gnss?.QualidadeFix ?? TiposCorrecaoGPS.SemCorrecao} {obj.Gnss?.PrecisaoCm:F2} cm", obj.Operacao?.Iniciada ?? false ); // DIREITA (RESUMO) _viewOperacaoRight?.areaResumo?._vm?.AtualizarResumo(r => { r.Operacao = (obj.Operacao?.Liberada ?? false) ? "🔓 Liberada" : "🔒 Bloqueada"; r.Modo = obj.Operacao == null ? "-" : obj.Operacao.Modo.ToString(); r.Status = obj.Operacao == null ? "-" : $"{obj.Operacao.Status}" + (obj.Operacao.Status == AgroBase.Models.Enums.StatusOperacao.Aguardando ? $" ({obj.Operacao.TempoAguardandoSegs:0}s)" : ""); r.Carro = obj.Trajetoria == null ? "-" : obj.Trajetoria.StatusCarro.ToString(); r.Temperatura = $"{(obj.Refrigeracao?.Temperatura ?? 0):F2} °C"; r.RuaAtual = obj.Trajetoria == null ? "-" : $"{obj.Trajetoria.CorredorAtualDistanciaPercorrida:F2} m / " + $"{obj.Trajetoria.CorredorAtualDistanciaTotal:0.00} m " + $"({obj.Trajetoria.CorredorAtualIdx + 1})"; r.AreaTotal = obj.Trajetoria == null ? "-" : $"{obj.Trajetoria.DistanciaPercorrida:0.00} m / " + $"{obj.Trajetoria.DistanciaTotal:0.00} m"; r.Bateria = obj.Bateria == null ? "-" : $"{obj.Bateria.TensaoInstantanea:0.00} V " + $"({TimeSpan.FromMinutes(obj.Bateria.TempoEstimadoRestanteMinutos):dd\\.hh\\:mm\\:ss} " + $"{obj.Bateria.DistanciaEstimadaRestanteMetros:0.00} m)"; r.Herbicida = obj.Atuador == null ? "-" : $"{obj.Atuador.VolumeReservatorioL:0.00} L " + $"({TimeSpan.FromMinutes(obj.Atuador.TempoEstimadoRestanteMinutos):hh\\:mm\\:ss} " + $"{obj.Atuador.DistanciaEstimadaRestanteMetros:0.00} m)"; r.Infestacao = obj.Atuador == null ? "-" : $"{obj.Atuador.HerbicidaPorAtuacaoMl:0.00} mL/atuação"; r.Conexao = comunicacao == null ? "-" : $"{comunicacao}"; r.Duracao = obj.Operacao == null ? "00:00:00 / 00:00:00" : $"{TimeSpan.FromSeconds(obj.Operacao.TempoDecorridoSegs):hh\\:mm\\:ss} / " + $"{(string.IsNullOrWhiteSpace(obj.Trajetoria?.TempoEstimadoOperacao) ? "00:00:00" : obj.Trajetoria.TempoEstimadoOperacao)}"; // Opcionais para progress bars, caso queira evoluir o resumo r.RuaAtualPercentual = obj.Trajetoria?.PercentualRuaAtual ?? 0; r.AreaTotalPercentual = obj.Trajetoria?.PercentualOperacao ?? 0; r.BateriaPercentual = obj.Bateria?.PercentualBateria ?? 0; r.HerbicidaPercentual = obj.Atuador?.PercentualReservatorio ?? 0; r.InfestacaoPercentual = obj.Atuador?.PercentualErvasTerreno ?? 0; }); // DIAGNOSTICO _viewOperacaoCenter?.Diagnostico?._vm?.AtualizarDados(rover); _viewOperacaoCenter?.Diagnostico?.AtualizarGraficos(); // PULVERIZADOR var bomba = obj.Atuador?.Bombas?.FirstOrDefault(); var ATU = _viewOperacaoCenter.Monitoramento.Pulverizador; ATU.ComprimentoBarraCm = AgroBase.Models.VariaveisEquipamento.ComprimentoBarraPulverizadoraCm; ATU.DistanciaEntreBicosCm = AgroBase.Models.VariaveisEquipamento.DistanciaEntreBicosCm; //ATU.AlturaBarra = obj?.Controle?.AlturaBarra ?? AgroBase.Models.VariaveisEquipamento.AlturaBarraPulverizadoraCm; ATU.IsBombaOn = bomba?.LeituraEstado ?? false; ATU.PressaoLinha = obj?.Atuador?.PressaoLinhaPsi ?? 0; ATU.VazaoInstantanea = obj?.Atuador?.VazaoInstantaneaMLs ?? 0; ATU.TempoAtuado = (bomba?.TempoAtuado ?? 0) / 1000.0; double erroLateral = ((obj?.Trajetoria?.DistanciaEsquerda ?? 0) - (obj?.Trajetoria?.DistanciaDireita ?? 0)) / 2.0 * 100.0; ATU.LarguraRuaCm = 100.0; ATU.ErroLateralCm = erroLateral; if (ATU.QtdBicos != obj?.Atuador?.Bicos?.Count) { ATU.QtdBicos = obj?.Atuador?.Bicos?.Count ?? AgroBase.Models.VariaveisEquipamento.QuantidadeBicosPulverizadores; } foreach (var bico in ATU.Bicos) { var _bc = obj?.Atuador?.Bicos?.FirstOrDefault(x => (x.Posicao - 1) == bico.Index); if (_bc == null) continue; bico.OpeningAngle = _bc.AnguloAbertura; bico.AnguloControle = _bc.ComandoAngulo; bico.IsCommandOn = _bc.ComandoEstado; bico.IsSpraying = _bc.LeituraEstado; bico.Vazao = _bc.VazaoInstantaneaMLs; bico.Atuacoes = _bc.QtdAtuacoes; bico.TempoAtuado = _bc.TempoAtuado / 1000.0; } // HEADING var HDG = _viewOperacaoCenter.Monitoramento.Heading; HDG.Heading = obj?.Gnss?.OrientacaoReal ?? double.NaN; HDG.CourseHeading = obj?.Trajetoria?.AnguloCaminho ?? double.NaN; // ATTITUDE var IMU = _viewOperacaoCenter.Monitoramento.Attitude; if (obj?.Imu?.InclinacaoFrontal != null) IMU.PitchDeg = (double)obj.Imu.InclinacaoFrontal; if (obj?.Imu?.InclinacaoLateral != null) IMU.RollDeg = (double)obj.Imu.InclinacaoLateral; IMU.LateralError = erroLateral; // CAMERAS var snr = obj?.Cameras?.FirstOrDefault(x => x.dispositivo == AgroBase.Models.Enums.T_Code.Snr); var cam = obj?.Cameras?.FirstOrDefault(x => x.dispositivo == AgroBase.Models.Enums.T_Code.Cam); _viewOperacaoCenter?.Monitoramento?._vm?.AtualizarDadosCameras(snr, cam, obj?.OperadorVisual?.StatusCarro, obj?.Atuador?.PercentualErvasNoRadar); } private void AbrirDiagnosticoPeloAlerta(AlertaModel alerta) { if (alerta == null) return; _viewOperacaoRight?._vm?.SelecionarRover(alerta.Rover_ID); _viewOperacaoRight?._vm?.SelecionarSecao(SecaoRightBar.Diagnostico); _viewOperacaoCenter?.Diagnostico?._vm?.AbrirModuloPorAlerta(alerta.Modulo, alerta.Mod_ID); } public void AdicionarAlerta(string roverId, AgroBase.Models.Enums.T_Code modulo, SeveridadeAlerta severidade, string mensagem, string modId = null) { _viewOperacaoBottom?._vm?.AdicionarAlerta(roverId, modulo, severidade, mensagem, modId); } public void RemoverAlerta(string roverId, AgroBase.Models.Enums.T_Code modulo, SeveridadeAlerta? severidade = null, string modId = null) { _viewOperacaoBottom?._vm?.RemoverAlerta(roverId, modulo, severidade, modId); } private void OnRoverSelecionadoChanged(string roverId) { _viewOperacaoRight?._vm?.DestacarRoverNoMapa(roverId); } private void OnRoverSelecionadoChanged(RoverCardModel rover) { bool dados_base = rover == null; if (dados_base) { if (!VariaveisControleOperacao.BaseEmFoco) { _viewOperacaoCenter?.Monitoramento?.PararStreamCameraFrontal(); _viewOperacaoCenter?.Monitoramento?.PararStreamCameraErvas(); VariaveisControleOperacao.EnviarComandoIniciarUDP(VariaveisControleOperacao.RoverEmFoco?.IP, false); } VariaveisControleOperacao.RoverEmFoco?.RuasPercorrer?.Clear(); AtualizarDadosMapa(VariaveisControleOperacao.RoverEmFoco); VariaveisControleOperacao.SelectedRoverId = VariaveisControleOperacao.BaseMarkerID; _viewOperacaoCenter?.Mapa?.markers?.SetMarkerFocused(VariaveisControleOperacao.SelectedRoverId, true); _viewOperacaoCenter?._vm?.SelecionarRoverLista(rover); AtualizarBarraSuperior(StatusModulo.Conectado, "BASE", "VISÃO GERAL", "Selecione um equipamento na lista à direita para configurá-lo", "NORMAL", "Aguardando"); _viewOperacaoLeft?._vm?.DefinirSemRover(); } else { VariaveisControleOperacao.SelectedRoverId = (rover.NumeroSerie ?? "").ToString(); _viewOperacaoCenter?.Mapa?.markers?.SetMarkerFocused(VariaveisControleOperacao.SelectedRoverId, true); AtualizarDadosTela(VariaveisControleOperacao.RoverEmFoco); VariaveisControleOperacao.RequisitarParametrosOperacao(); _viewOperacaoCenter?.Monitoramento?.IniciarStreamCameraFrontal(); _viewOperacaoCenter?.Monitoramento?.IniciarStreamCameraErvas(); VariaveisControleOperacao.EnviarComandoIniciarUDP(VariaveisControleOperacao.RoverEmFoco?.IP, true); _viewOperacaoCenter?._vm?.SelecionarRoverLista(rover); AtualizarDadosMapa(VariaveisControleOperacao.RoverEmFoco); AtualizarBarraSuperior(VariaveisControleOperacao.RoverEmFoco); } } private void OnSecaoSelecionadaChanged(SecaoRightBar secao) { if (secao == SecaoRightBar.Parametrizacao) _viewOperacaoRight?.areaParametrizacao?._vm?.AtualizarParametros(VariaveisControleOperacao.RoverEmFoco); _viewOperacaoCenter?._vm?.DefinirSecao(secao); AtualizarDadosMapa(VariaveisControleOperacao.RoverEmFoco); } private void OnLerParametrosSolicitado() { if (VariaveisControleOperacao.RoverEmFoco == null) return; VariaveisControleOperacao.RequisitarParametrosOperacao(); } private void OnSalvarParametrosSolicitado(OperacaoParametrosModel parametros) { var dadosMapa = _viewOperacaoCenter?.Mapa?.CriarDadosMapa(); var ruasPercorrer = _viewOperacaoCenter?.Mapa?.RuasMapaCarregado?.Where(x => x.Selected)?.Select(x => x.Id)?.ToList() ?? new List(); if ((dadosMapa?.features?.Count ?? 0) == 0 || !ruasPercorrer.Any()) { System.Windows.MessageBox.Show("Selecione as ruas no mapa onde o equipamento irá operar", "Ruas não selecionadas", MessageBoxButton.OK, MessageBoxImage.Warning); return; } if (VariaveisControleOperacao.RoverEmFoco == null) return; var rover = VariaveisControleOperacao.RoverEmFoco; var novosParametros = new OperacaoParametrosModel() { Modo = parametros.Modo, Descricao = parametros.Descricao, QtdCamerasSolo = parametros.QtdCamerasSolo, QtdBicos = parametros.QtdBicos, CapacidadeReservatorio = parametros.CapacidadeReservatorio, Controle = parametros.Controle, ModulosMandatorios = parametros?.ModulosMandatorios, ParametrosMandatorios = parametros?.ParametrosMandatorios, RuasPercorrer = _viewOperacaoCenter?.Mapa?.RuasMapaCarregado?.Where(x => x.Selected)?.Select(x => x.Id)?.ToList(), Mapa = _viewOperacaoCenter?.Mapa?.CriarDadosMapa() }; VariaveisControleOperacao.EnviarParametrosOperacao(novosParametros); VariaveisControleOperacao.RoverEmFoco.Modo = novosParametros.Modo; VariaveisControleOperacao.RoverEmFoco.Descricao = novosParametros.Descricao; VariaveisControleOperacao.RoverEmFoco.QtdCamerasSolo = novosParametros.QtdCamerasSolo; VariaveisControleOperacao.RoverEmFoco.QtdBicos = novosParametros.QtdBicos; VariaveisControleOperacao.RoverEmFoco.CapacidadeReservatorio = novosParametros.CapacidadeReservatorio; VariaveisControleOperacao.RoverEmFoco.Controle = novosParametros.Controle; VariaveisControleOperacao.RoverEmFoco.ModulosMandatorios = novosParametros.ModulosMandatorios; VariaveisControleOperacao.RoverEmFoco.ParametrosMandatorios = novosParametros.ParametrosMandatorios; VariaveisControleOperacao.RoverEmFoco.RuasPercorrer = novosParametros.RuasPercorrer; VariaveisControleOperacao.RoverEmFoco.Mapa = novosParametros.Mapa; VariaveisControleOperacao.RequisitarParametrosOperacao(); Task.Run(async () => { await Task.Delay(1000); _viewOperacaoRight?._vm?.SelecionarSecao(SecaoRightBar.Diagnostico); }); } #endregion } public enum ModoOperacao { Automatico = 1, Manual = 2 } public enum DockStep { ConfigConexao = 1, PreparacaoMapa = 2, ParametrizacaoRover = 3 } }