diff --git a/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs b/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs
index 483cf560f..f2e84f635 100644
--- a/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs
+++ b/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs
@@ -403,7 +403,7 @@ namespace AgroBase.Models.Modules
RPM_SP = RpmCorrigido;
FatorCompensacaoCurvasAnterior = FatorCompensacaoCurvas;
- Variaveis.OperacaoEmAndamento.SimulacaoRpmControle = Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP;
+ Variaveis.OperacaoEmAndamento.SimulacaoRpmControle = _Controle.PercentualVelocidadeSP;
//Console.WriteLine($"RPM Atualizado para {Variaveis.OperacaoEmAndamento.SimulacaoRpmControle}");
switch (DirecaoAtual)
diff --git a/AgroBase/AgroBase/Services/EthernetService.cs b/AgroBase/AgroBase/Services/EthernetService.cs
index 9219c3df5..202d06eef 100644
--- a/AgroBase/AgroBase/Services/EthernetService.cs
+++ b/AgroBase/AgroBase/Services/EthernetService.cs
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
@@ -613,6 +614,134 @@ public class EthernetService
return sucesso;
}
-
+
+
+
+
+ public class StatusRedeInfo
+ {
+ public bool AdaptadorEncontrado { get; set; }
+ public bool AdaptadorOperacional { get; set; }
+ public bool CaboConectado { get; set; }
+ public bool IpValido { get; set; }
+ public bool GatewayValido { get; set; }
+
+ public string NomeInterface { get; set; } = "";
+ public string Ip { get; set; } = "";
+ public string Mascara { get; set; } = "";
+ public string Gateway { get; set; } = "";
+
+ public bool RedeOk { get; set; }
+ public string Detalhes { get; set; } = "";
+ }
+
+ public static StatusRedeInfo ObterStatusRede(string nomeInterface = null, bool exigirGateway = false)
+ {
+ var info = new StatusRedeInfo();
+
+ try
+ {
+ var interfaces = NetworkInterface.GetAllNetworkInterfaces()
+ .Where(ni =>
+ ni.NetworkInterfaceType != NetworkInterfaceType.Loopback &&
+ ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel &&
+ ni.Description.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) < 0 &&
+ ni.Name.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) < 0)
+ .ToList();
+
+ NetworkInterface niSelecionada = null;
+
+ if (!string.IsNullOrWhiteSpace(nomeInterface))
+ {
+ niSelecionada = interfaces.FirstOrDefault(ni =>
+ ni.Name.Equals(nomeInterface, StringComparison.OrdinalIgnoreCase) ||
+ ni.Description.Equals(nomeInterface, StringComparison.OrdinalIgnoreCase) ||
+ ni.Name.IndexOf(nomeInterface, StringComparison.OrdinalIgnoreCase) >= 0 ||
+ ni.Description.IndexOf(nomeInterface, StringComparison.OrdinalIgnoreCase) >= 0);
+ }
+ else
+ {
+ niSelecionada = interfaces
+ .Where(ni =>
+ ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
+ ni.NetworkInterfaceType == NetworkInterfaceType.GigabitEthernet ||
+ ni.Description.IndexOf("Ethernet", StringComparison.OrdinalIgnoreCase) >= 0 ||
+ ni.Name.IndexOf("Ethernet", StringComparison.OrdinalIgnoreCase) >= 0)
+ .OrderByDescending(ni => ni.OperationalStatus == OperationalStatus.Up)
+ .FirstOrDefault();
+ }
+
+ if (niSelecionada == null)
+ {
+ info.Detalhes = "Nenhum adaptador de rede compatível encontrado.";
+ return info;
+ }
+
+ info.AdaptadorEncontrado = true;
+ info.NomeInterface = niSelecionada.Name;
+ info.AdaptadorOperacional = niSelecionada.OperationalStatus == OperationalStatus.Up;
+ info.CaboConectado = info.AdaptadorOperacional;
+
+ var props = niSelecionada.GetIPProperties();
+
+ var ipv4 = props.UnicastAddresses
+ .FirstOrDefault(a => a.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
+
+ var gateway = props.GatewayAddresses
+ .FirstOrDefault(g => g.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
+
+ if (ipv4 != null)
+ {
+ info.Ip = ipv4.Address.ToString();
+ info.Mascara = ipv4.IPv4Mask?.ToString() ?? "";
+ info.IpValido = IpEhValido(info.Ip);
+ }
+
+ if (gateway != null)
+ {
+ info.Gateway = gateway.Address.ToString();
+ info.GatewayValido = IpEhValido(info.Gateway);
+ }
+
+ info.RedeOk =
+ info.AdaptadorEncontrado &&
+ info.CaboConectado &&
+ info.IpValido &&
+ (!exigirGateway || info.GatewayValido);
+
+ info.Detalhes =
+ $"{info.NomeInterface}\n" +
+ $"Cabo: {(info.CaboConectado ? "Conectado" : "Desconectado")}\n" +
+ $"IP: {(!string.IsNullOrWhiteSpace(info.Ip) ? info.Ip : "Não definido")}\n" +
+ $"Máscara: {(!string.IsNullOrWhiteSpace(info.Mascara) ? info.Mascara : "Não definida")}\n" +
+ $"Gateway: {(!string.IsNullOrWhiteSpace(info.Gateway) ? info.Gateway : "Não definido")}\n" +
+ $"Rede OK: {(info.RedeOk ? "Sim" : "Não")}";
+ }
+ catch (Exception ex)
+ {
+ info.RedeOk = false;
+ info.Detalhes = "Erro ao obter status da rede: " + ex.Message;
+ }
+
+ return info;
+ }
+
+ private static bool IpEhValido(string ip)
+ {
+ if (string.IsNullOrWhiteSpace(ip))
+ return false;
+
+ if (!IPAddress.TryParse(ip, out var endereco))
+ return false;
+
+ if (IPAddress.Any.Equals(endereco))
+ return false;
+
+ // APIPA: geralmente indica ausência de DHCP/conectividade útil
+ if (ip.StartsWith("169.254."))
+ return false;
+
+ return true;
+ }
}
diff --git a/AgroBase/OperationControl/Controls/MapViewControl.xaml b/AgroBase/OperationControl/Controls/MapViewControl.xaml
index 14e323179..c697c4882 100644
--- a/AgroBase/OperationControl/Controls/MapViewControl.xaml
+++ b/AgroBase/OperationControl/Controls/MapViewControl.xaml
@@ -16,7 +16,7 @@
-
+
\ No newline at end of file
diff --git a/AgroBase/OperationControl/Controls/MapViewControl.xaml.cs b/AgroBase/OperationControl/Controls/MapViewControl.xaml.cs
index 2ab5e94d3..58c9d1d20 100644
--- a/AgroBase/OperationControl/Controls/MapViewControl.xaml.cs
+++ b/AgroBase/OperationControl/Controls/MapViewControl.xaml.cs
@@ -930,6 +930,14 @@ namespace OperationControl.Controls
}
}
+
+ public void LimparRastrosRover(string? roverId, bool limparPredicao = true)
+ {
+ if (string.IsNullOrWhiteSpace(roverId))
+ return;
+
+ markers?.ClearMarkerTrail(roverId, limparPredicao);
+ }
}
public class MapMarkerManager
@@ -1089,6 +1097,19 @@ namespace OperationControl.Controls
UpdateFeatures();
}
+
+ public void ClearMarkerTrail(string id, bool clearPrediction = true)
+ {
+ if (string.IsNullOrWhiteSpace(id)) return;
+
+ var marker = _features.FirstOrDefault(x => x.Id == id);
+ if (marker == null) return;
+
+ marker.ClearTrajectory(clearPrediction);
+ _map.Refresh();
+ }
+
+
public class MapMarkerDictionaryModel
{
public void CreateTrajectory(MapControl _map)
@@ -1344,6 +1365,34 @@ namespace OperationControl.Controls
}
+ public void ClearTrajectory(bool clearPrediction = true)
+ {
+ _trajFeatures.Clear();
+
+ if (_trajLayer != null)
+ {
+ _trajLayer.DataSource = new MemoryProvider(_trajFeatures);
+ _trajLayer.DataHasChanged();
+ }
+
+ if (clearPrediction)
+ {
+ _predFeatures.Clear();
+
+ if (_predLayer != null)
+ {
+ _predLayer.DataSource = new MemoryProvider(_predFeatures);
+ _predLayer.DataHasChanged();
+ }
+ }
+
+ // Reseta a posição base do rastro para a posição atual do rover,
+ // evitando que ao voltar a andar ele desenhe uma linha gigante do passado.
+ var (x, y) = Mapsui.Projections.SphericalMercator.FromLonLat(Lon, Lat);
+ Position = new Coordinate(x, y);
+ }
+
+
#region TRAJETORIA
private MemoryProvider _trajProvider;
diff --git a/AgroBase/OperationControl/Models/AlertaModel.cs b/AgroBase/OperationControl/Models/AlertaModel.cs
index b0cc04b75..9b71e6a47 100644
--- a/AgroBase/OperationControl/Models/AlertaModel.cs
+++ b/AgroBase/OperationControl/Models/AlertaModel.cs
@@ -30,7 +30,8 @@ namespace OperationControl.Models
? $"{Modulo} ({Mod_ID})"
: Modulo.ToString();
- return $"[{Rover_ID}] {mod} — {ResumoSeveridade}";
+ //return $"[{Rover_ID}] {mod} — {ResumoSeveridade}";
+ return $"{mod} — {ResumoSeveridade}";
}
}
diff --git a/AgroBase/OperationControl/Models/AppShell.cs b/AgroBase/OperationControl/Models/AppShell.cs
index bf9e38b57..3e25cf1af 100644
--- a/AgroBase/OperationControl/Models/AppShell.cs
+++ b/AgroBase/OperationControl/Models/AppShell.cs
@@ -204,7 +204,7 @@ namespace OperationControl.Models
{
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
- (Dock?.DataContext as DockWindowViewModel)?.AdicionarAlerta(roverId, modulo, severidade, mensagem, modId);
+ Dock?._vm?.AdicionarAlerta(roverId, modulo, severidade, mensagem, modId);
}));
}
@@ -212,7 +212,7 @@ namespace OperationControl.Models
{
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
- (Dock?.DataContext as DockWindowViewModel)?.RemoverAlerta(roverId, modulo, severidade, modId);
+ Dock?._vm?.RemoverAlerta(roverId, modulo, severidade, modId);
}));
}
diff --git a/AgroBase/OperationControl/Models/Variaveis.cs b/AgroBase/OperationControl/Models/Variaveis.cs
index 63fd96d5b..317bc9adf 100644
--- a/AgroBase/OperationControl/Models/Variaveis.cs
+++ b/AgroBase/OperationControl/Models/Variaveis.cs
@@ -5,6 +5,7 @@ using OperationControl.Services;
using AgroMonitor;
using Application = System.Windows.Application;
using AgroBase.Models.Operacoes;
+using OperationControl.Windows;
namespace OperationControl.Models
{
@@ -15,6 +16,8 @@ namespace OperationControl.Models
public static UdpReliableChannel UdpChannel;
public static ManualControlSender ControlSenderDir;
public static ManualControlSender ControlSenderMov;
+ public static AppShell? Shell => ((App)Application.Current)?.Shell;
+ public static DockWindow? Dock => Shell?.Dock;
public static void MostrarLog(string message)
{
@@ -163,11 +166,11 @@ namespace OperationControl.Models
rover.UltimoContato = DateTime.Now;
}
}
- ((App)Application.Current).Shell.Main?.AtualizarDadosTela_Telemetria(device_id);
+ //((App)Application.Current).Shell.Main?.AtualizarDadosTela_Telemetria(device_id);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
- ((App)Application.Current).Shell.Dock?._vm?.AtualizarDadosTela(rover);
+ Variaveis.Dock?._vm?.AtualizarDadosTela(rover);
}));
}
catch (Exception ex)
@@ -195,9 +198,9 @@ namespace OperationControl.Models
RoversNaRede[index] = obj;
}
}
- ((App)Application.Current).Shell.Main?.AtualizarDadosTela_ParametrosOperacao(obj.Controle);
- ((App)Application.Current).Shell.Main?.MAP?.CarregarDadosMapa(obj.Mapa, obj.RuasPercorrer);
- ((App)Application.Current).Shell.Dock?._vm?.AtualizarParametrosRover(obj);
+ //((App)Application.Current).Shell.Main?.AtualizarDadosTela_ParametrosOperacao(obj.Controle);
+ //((App)Application.Current).Shell.Main?.MAP?.CarregarDadosMapa(obj.Mapa, obj.RuasPercorrer);
+ Variaveis.Dock?._vm?.AtualizarParametrosRover(obj);
}
catch (Exception ex)
{
@@ -211,7 +214,7 @@ namespace OperationControl.Models
{
dispositivos_ids = dispositivos_ids.Union(RoversNaRede.Select(x => x.RoverId).ToList()).ToList();
}
- ((App)Application.Current).Shell.Main?.AtualizarListaDispositivos(dispositivos_ids);
+ //((App)Application.Current).Shell.Main?.AtualizarListaDispositivos(dispositivos_ids);
RequisitarParametrosOperacao();
}
@@ -244,24 +247,24 @@ namespace OperationControl.Models
rover.DadosLeitura.Momento = DateTime.Now;
if (rover.DadosLeitura.Operacao == null) rover.DadosLeitura.Operacao = new OperacaoParametrosDadosOperacaoModel();
rover.DadosLeitura.Operacao.Status = AgroBase.Models.Enums.StatusOperacao.Erro;
- ((App)Application.Current)?.Shell?.Main?.AtualizarDadosTela_Telemetria(rover.RoverId);
- ((App)Application.Current)?.Shell?.Main?.AdicionarAlerta(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb, SeveridadeAlerta.Critical, "Perda de comunicação com o equipamento!");
+ //((App)Application.Current)?.Shell?.Main?.AtualizarDadosTela_Telemetria(rover.RoverId);
+ //((App)Application.Current)?.Shell?.Main?.AdicionarAlerta(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb, SeveridadeAlerta.Critical, "Perda de comunicação com o equipamento!");
- ((App)Application.Current)?.Shell?.AdicionarAlertaDock(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb, SeveridadeAlerta.Critical, "Perda de comunicação com o equipamento!");
- ((App)Application.Current)?.Shell?.Dock?._vm?._viewOperacaoCenter?.Mapa?.markers?.UpdateMarkerInfo(rover.RoverId, status: AgroBase.Models.Enums.StatusOperacao.Erro);
+ Variaveis.Shell?.AdicionarAlertaDock(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb, SeveridadeAlerta.Critical, "Perda de comunicação com o equipamento!");
+ Variaveis.Dock?._vm?._viewOperacaoCenter?.Mapa?.markers?.UpdateMarkerInfo(rover.RoverId, status: AgroBase.Models.Enums.StatusOperacao.Erro);
}
else
{
- ((App)Application.Current)?.Shell?.Main?.RemoverAlerta(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb);
- ((App)Application.Current)?.Shell?.RemoverAlertaDock(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb);
+ //((App)Application.Current)?.Shell?.Main?.RemoverAlerta(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb);
+ Variaveis.Shell?.RemoverAlertaDock(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb);
}
- ((App)Application.Current)?.Shell?.Dock?._vm?.AtualizarBarraSuperior(rover);
+ Variaveis.Shell?.Dock?._vm?.AtualizarBarraSuperior(rover);
}
Application.Current?.Dispatcher?.BeginInvoke(new Action(() =>
{
- ((App)Application.Current)?.Shell?.Dock?._vm?.AtualizarListaRovers(rovers_atual);
+ Variaveis.Shell?.Dock?._vm?.AtualizarListaRovers(rovers_atual);
}));
}
finally
diff --git a/AgroBase/OperationControl/OperationControl.csproj.user b/AgroBase/OperationControl/OperationControl.csproj.user
index 642fee9a8..f8855aa93 100644
--- a/AgroBase/OperationControl/OperationControl.csproj.user
+++ b/AgroBase/OperationControl/OperationControl.csproj.user
@@ -52,6 +52,9 @@
Code
+
+ Code
+
Code
@@ -138,6 +141,9 @@
Designer
+
+ Designer
+
Designer
diff --git a/AgroBase/OperationControl/Services/GpsService.cs b/AgroBase/OperationControl/Services/GpsService.cs
index 8ca9e514c..57de27536 100644
--- a/AgroBase/OperationControl/Services/GpsService.cs
+++ b/AgroBase/OperationControl/Services/GpsService.cs
@@ -368,8 +368,7 @@ namespace OperationControl.Services
}
Models.Variaveis.MostrarLog(mensagem);
- ((App)Application.Current)?.Shell?.Dock?._vm?._viewPreparacaoMapaBottom?._vm?.FinalizarFixacao(sucesso, mensagem);
- ((App)Application.Current)?.Shell?.Dock?._vm?.FinalizarFixacaoBase(sucesso, mensagem);
+ Models.Variaveis.Dock?._vm?.FinalizarFixacaoBase(sucesso, mensagem);
}
private async Task ConfigurarModuloBase(string porta_usb = "com3", string porta_saida = "com2", int tempo_fixacao = 60)
@@ -1223,9 +1222,9 @@ namespace OperationControl.Services
{
try
{
- ((App)Application.Current).Shell.Main?.AtualizarDadosTela_Telemetria(VariaveisControleOperacao.BaseMarkerID);
+ //((App)Application.Current).Shell.Main?.AtualizarDadosTela_Telemetria(VariaveisControleOperacao.BaseMarkerID);
- ((App)Application.Current).Shell.Dock?._vm?.AtualizarDadosGnss(UltimaLeitura);
+ Models.Variaveis.Dock?._vm?.AtualizarDadosGnss(UltimaLeitura);
}
catch (Exception exUi)
{
diff --git a/AgroBase/OperationControl/ViewModels/Views/ConfigConexao/ConfigConexaoViewModel.cs b/AgroBase/OperationControl/ViewModels/Views/ConfigConexao/ConfigConexaoViewModel.cs
index 8f746d599..2b0453d7b 100644
--- a/AgroBase/OperationControl/ViewModels/Views/ConfigConexao/ConfigConexaoViewModel.cs
+++ b/AgroBase/OperationControl/ViewModels/Views/ConfigConexao/ConfigConexaoViewModel.cs
@@ -248,21 +248,17 @@ namespace OperationControl.ViewModels
{
try
{
- // 1) Escolhe a interface “ativa” ou a que você usa pra ponte IP
- // Se você já tem isso fixo, melhor ainda: use sempre a mesma.
- var interfaces = EthernetService.ObterNomesInterfaces().Where(x => x.Contains("Ativa")).Select(x => x.Split('(')[0].Trim()).ToList();
- var iface = interfaces[0]; // <-- se tiver
- // ou se você já sabe o nome: var iface = "Ethernet 2";
+ var interfaces = EthernetService.ObterNomesInterfaces()
+ .Where(x => x.Contains(AppShell.Mock ? "Ativa" : "Ethernet"))
+ .Select(x => x.Split('(')[0].Trim())
+ .ToList();
- var ip = EthernetService.ObterIpAtual(iface);
- var sub = EthernetService.ObterSubnetMaskAtual(iface);
- var gw = EthernetService.ObterIpGateway(iface);
+ string? iface = interfaces.FirstOrDefault();
- DetalhesRede = $"{iface}\nIP: {ip}\nMáscara: {sub}\nGateway: {gw}";
+ var status = EthernetService.ObterStatusRede(iface, exigirGateway: false);
- // 2) Define RedeOk do jeito que faz sentido pra você:
- // exemplo simples: tem IP válido + gateway válido
- RedeOk = !string.IsNullOrWhiteSpace(ip) && ip != "0.0.0.0";
+ RedeOk = status.RedeOk;
+ DetalhesRede = status.Detalhes;
}
catch (Exception ex)
{
diff --git a/AgroBase/OperationControl/ViewModels/Views/Operacao/Monitoramento/HistoricoViewModel.cs b/AgroBase/OperationControl/ViewModels/Views/Operacao/Monitoramento/HistoricoViewModel.cs
new file mode 100644
index 000000000..f7983b6bc
--- /dev/null
+++ b/AgroBase/OperationControl/ViewModels/Views/Operacao/Monitoramento/HistoricoViewModel.cs
@@ -0,0 +1,397 @@
+using OperationControl.Models;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Windows.Data;
+
+namespace OperationControl.ViewModels.Views.Operacao.Monitoramento
+{
+ public class HistoricoViewModel : INotifyPropertyChanged
+ {
+ public HistoricoViewModel()
+ {
+ EventosView = CollectionViewSource.GetDefaultView(Eventos);
+ EventosView.Filter = FiltrarEvento;
+
+ _ordenacaoSelecionada = "Mais recentes";
+
+ AplicarOrdenacao();
+ AtualizarFiltros();
+ }
+
+ private List _eventosTopBarAnteriores = new();
+
+ private ObservableCollection _eventos = new();
+ public ObservableCollection Eventos
+ {
+ get => _eventos;
+ set
+ {
+ _eventos = value;
+ OnPropertyChanged(nameof(Eventos));
+
+ EventosView = CollectionViewSource.GetDefaultView(Eventos);
+ EventosView.Filter = FiltrarEvento;
+ AplicarOrdenacao();
+
+ OnPropertyChanged(nameof(EventosView));
+ OnPropertyChanged(nameof(QuantidadeEventos));
+ OnPropertyChanged(nameof(QuantidadeEventosFiltrados));
+ }
+ }
+
+ private ICollectionView _eventosView;
+ public ICollectionView EventosView
+ {
+ get => _eventosView;
+ set
+ {
+ _eventosView = value;
+ OnPropertyChanged(nameof(EventosView));
+ OnPropertyChanged(nameof(QuantidadeEventosFiltrados));
+ }
+ }
+
+ public int QuantidadeEventos => Eventos?.Count ?? 0;
+
+ public int QuantidadeEventosFiltrados
+ {
+ get
+ {
+ if (EventosView == null) return 0;
+ return EventosView.Cast