ntrip fallback

This commit is contained in:
Diego Freitas 2025-08-20 09:59:10 -03:00
parent be94543b9e
commit cad0bfaabd
20 changed files with 335 additions and 133 deletions

Binary file not shown.

View File

@ -63,6 +63,8 @@
this.lblModoOperacao = new System.Windows.Forms.Label();
this.txtModoOperacao = new System.Windows.Forms.TextBox();
this.pnlSensores = new System.Windows.Forms.Panel();
this.txtInclinacao = new System.Windows.Forms.TextBox();
this.lblInclinacao = new System.Windows.Forms.Label();
this.txtDT = new System.Windows.Forms.TextBox();
this.lblDT = new System.Windows.Forms.Label();
this.txtET = new System.Windows.Forms.TextBox();
@ -104,8 +106,6 @@
this.tkbVelocidade = new System.Windows.Forms.TrackBar();
this.tabMapa = new System.Windows.Forms.TabPage();
this.picFechar = new System.Windows.Forms.PictureBox();
this.txtInclinacao = new System.Windows.Forms.TextBox();
this.lblInclinacao = new System.Windows.Forms.Label();
this.pnlMapa.SuspendLayout();
this.pnlSensores.SuspendLayout();
this.statusStrip1.SuspendLayout();
@ -473,6 +473,25 @@
this.pnlSensores.Size = new System.Drawing.Size(307, 497);
this.pnlSensores.TabIndex = 32;
//
// txtInclinacao
//
this.txtInclinacao.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtInclinacao.Location = new System.Drawing.Point(164, 768);
this.txtInclinacao.Name = "txtInclinacao";
this.txtInclinacao.ReadOnly = true;
this.txtInclinacao.Size = new System.Drawing.Size(120, 26);
this.txtInclinacao.TabIndex = 53;
this.txtInclinacao.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblInclinacao
//
this.lblInclinacao.AutoSize = true;
this.lblInclinacao.Location = new System.Drawing.Point(6, 771);
this.lblInclinacao.Name = "lblInclinacao";
this.lblInclinacao.Size = new System.Drawing.Size(126, 20);
this.lblInclinacao.TabIndex = 52;
this.lblInclinacao.Text = "Inclinação (L / F)";
//
// txtDT
//
this.txtDT.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
@ -633,7 +652,7 @@
//
this.lblPrecisaoGPS.AutoSize = true;
this.lblPrecisaoGPS.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblPrecisaoGPS.Location = new System.Drawing.Point(6, 497);
this.lblPrecisaoGPS.Location = new System.Drawing.Point(18, 497);
this.lblPrecisaoGPS.Name = "lblPrecisaoGPS";
this.lblPrecisaoGPS.Size = new System.Drawing.Size(105, 15);
this.lblPrecisaoGPS.TabIndex = 35;
@ -643,11 +662,11 @@
//
this.lblCorrecaoGPS.AutoSize = true;
this.lblCorrecaoGPS.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblCorrecaoGPS.Location = new System.Drawing.Point(184, 497);
this.lblCorrecaoGPS.Location = new System.Drawing.Point(156, 497);
this.lblCorrecaoGPS.Name = "lblCorrecaoGPS";
this.lblCorrecaoGPS.Size = new System.Drawing.Size(83, 15);
this.lblCorrecaoGPS.Size = new System.Drawing.Size(117, 15);
this.lblCorrecaoGPS.TabIndex = 34;
this.lblCorrecaoGPS.Text = "SemCorrecao";
this.lblCorrecaoGPS.Text = "B 0,8: SemCorrecao";
//
// btnCodFalha
//
@ -692,7 +711,7 @@
this.pnlOrientacao.BackColor = System.Drawing.Color.White;
this.pnlOrientacao.BackgroundImage = global::AgroBase.Properties.Resources.rosa_dos_ventos;
this.pnlOrientacao.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
this.pnlOrientacao.Location = new System.Drawing.Point(184, 514);
this.pnlOrientacao.Location = new System.Drawing.Point(164, 514);
this.pnlOrientacao.Margin = new System.Windows.Forms.Padding(2);
this.pnlOrientacao.Name = "pnlOrientacao";
this.pnlOrientacao.Size = new System.Drawing.Size(100, 100);
@ -704,7 +723,7 @@
this.pnlInclinacao.BackColor = System.Drawing.Color.White;
this.pnlInclinacao.BackgroundImage = global::AgroBase.Properties.Resources.transferidor;
this.pnlInclinacao.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
this.pnlInclinacao.Location = new System.Drawing.Point(7, 514);
this.pnlInclinacao.Location = new System.Drawing.Point(27, 514);
this.pnlInclinacao.Margin = new System.Windows.Forms.Padding(2);
this.pnlInclinacao.Name = "pnlInclinacao";
this.pnlInclinacao.Size = new System.Drawing.Size(100, 100);
@ -883,25 +902,6 @@
this.picFechar.TabIndex = 1;
this.picFechar.TabStop = false;
//
// txtInclinacao
//
this.txtInclinacao.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtInclinacao.Location = new System.Drawing.Point(164, 768);
this.txtInclinacao.Name = "txtInclinacao";
this.txtInclinacao.ReadOnly = true;
this.txtInclinacao.Size = new System.Drawing.Size(120, 26);
this.txtInclinacao.TabIndex = 53;
this.txtInclinacao.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblInclinacao
//
this.lblInclinacao.AutoSize = true;
this.lblInclinacao.Location = new System.Drawing.Point(6, 771);
this.lblInclinacao.Name = "lblInclinacao";
this.lblInclinacao.Size = new System.Drawing.Size(126, 20);
this.lblInclinacao.TabIndex = 52;
this.lblInclinacao.Text = "Inclinação (L / F)";
//
// frmDialogoMapa
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

View File

@ -184,7 +184,7 @@ namespace AgroBase.Forms.IHM
FuncoesGlobais.PreencheValorProgressBar(pgbRuaAtual, _Sensoriamento.Trajetoria.CorredorAtual.Progresso);
lblRuaAtual.Text = "Rua Atual: " + _Sensoriamento.Trajetoria.CorredorAtual.Progresso.ToString("0.00") + "%";
lblCorrecaoGPS.Text = _Sensoriamento.Gps.QualidadeFix.ToString();
lblCorrecaoGPS.Text = (_Sensoriamento.Gps.Ntrip_ativado ? "N " : "B ") + _Sensoriamento.Gps.IdadeCorrecao + ": " + _Sensoriamento.Gps.QualidadeFix.ToString();
lblPrecisaoGPS.Text = $"Precisão: {_Sensoriamento.Gps.PrecisaoCm.ToString("0.00")} cm";
bool automatico = Variaveis.OperacaoEmAndamento.Modo != Enums.ModoOperacao.Manual;

View File

@ -220,9 +220,9 @@
this.lblGPSFix.Location = new System.Drawing.Point(4, 129);
this.lblGPSFix.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lblGPSFix.Name = "lblGPSFix";
this.lblGPSFix.Size = new System.Drawing.Size(71, 13);
this.lblGPSFix.Size = new System.Drawing.Size(102, 13);
this.lblGPSFix.TabIndex = 32;
this.lblGPSFix.Text = "SemCorrecao";
this.lblGPSFix.Text = "B 0,8: SemCorrecao";
//
// lblGPSprecisao
//

View File

@ -153,7 +153,7 @@ namespace AgroBase.Forms.Operacoes
lblDistanciaEsquerda.Text = "Distancia Esq: " + _Sensoriamento.Trajetoria.DistanciaEsquerda.ToString("0.00") + " cm";
lblDistanciaDireita.Text = "Distancia Dir: " + _Sensoriamento.Trajetoria.DistanciaDireita.ToString("0.00") + " cm";
lblGPSsatelites.Text = _Sensoriamento.Gps.NumeroSatelites.valor.ToString() + " satélites";
lblGPSFix.Text = _Sensoriamento.Gps.QualidadeFix.ToString();
lblGPSFix.Text = (_Sensoriamento.Gps.Ntrip_ativado ? "N " : "B ") + _Sensoriamento.Gps.IdadeCorrecao + ": " + _Sensoriamento.Gps.QualidadeFix.ToString();
lblGPSprecisao.Text = "Precisão: " + _Sensoriamento.Gps.PrecisaoCm.ToString("0.00") + " cm";
lblGPSvelocidade.Text = "Vel.: " + _Sensoriamento.Gps.Velocidade.ToString("0.00") + " km/h";
lblGPSaltitude.Text = "Altitude: " + _Sensoriamento.Gps.Altitude.ToString("0.0") + " m";

View File

@ -67,7 +67,7 @@
this.pnlOrientacaoCaminho = new System.Windows.Forms.Panel();
this.txtGPS_Data = new System.Windows.Forms.TextBox();
this.label10 = new System.Windows.Forms.Label();
this.txtGPS_Orientacao = new System.Windows.Forms.TextBox();
this.txtGPS_Correcao = new System.Windows.Forms.TextBox();
this.label11 = new System.Windows.Forms.Label();
this.txtGPS_Precisao = new System.Windows.Forms.TextBox();
this.label8 = new System.Windows.Forms.Label();
@ -367,11 +367,14 @@
this.pnlInclinacao = new System.Windows.Forms.Panel();
this.pnl3D = new System.Windows.Forms.Panel();
this.tabSonar = new System.Windows.Forms.TabPage();
this.chbSonarDeteccoes = new System.Windows.Forms.CheckBox();
this.tabControl3 = new System.Windows.Forms.TabControl();
this.tabSonarRGB = new System.Windows.Forms.TabPage();
this.picSonarRadar = new System.Windows.Forms.PictureBox();
this.tabSonarCalor = new System.Windows.Forms.TabPage();
this.picMapaCalor = new System.Windows.Forms.PictureBox();
this.tabSonarDeteccoes = new System.Windows.Forms.TabPage();
this.pnlSonarDeteccoes = new System.Windows.Forms.Panel();
this.gridObstaculos = new System.Windows.Forms.DataGridView();
this.txtSonarDecisao = new System.Windows.Forms.TextBox();
this.label99 = new System.Windows.Forms.Label();
@ -497,9 +500,6 @@
this.label36 = new System.Windows.Forms.Label();
this.txtMomento = new System.Windows.Forms.TextBox();
this.btnPlay = new System.Windows.Forms.Button();
this.tabSonarDeteccoes = new System.Windows.Forms.TabPage();
this.pnlSonarDeteccoes = new System.Windows.Forms.Panel();
this.chbSonarDeteccoes = new System.Windows.Forms.CheckBox();
((System.ComponentModel.ISupportInitialize)(this.trbMomento)).BeginInit();
this.panel1.SuspendLayout();
this.tabControl4.SuspendLayout();
@ -556,6 +556,7 @@
((System.ComponentModel.ISupportInitialize)(this.picSonarRadar)).BeginInit();
this.tabSonarCalor.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picMapaCalor)).BeginInit();
this.tabSonarDeteccoes.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.gridObstaculos)).BeginInit();
this.tabSegmentacao.SuspendLayout();
this.tabCPU.SuspendLayout();
@ -569,7 +570,6 @@
this.panel6.SuspendLayout();
this.pnlInformacoesOperacao.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picCameraCaminho)).BeginInit();
this.tabSonarDeteccoes.SuspendLayout();
this.SuspendLayout();
//
// trbMomento
@ -592,7 +592,7 @@
this.panel1.Controls.Add(this.pnlOrientacaoCaminho);
this.panel1.Controls.Add(this.txtGPS_Data);
this.panel1.Controls.Add(this.label10);
this.panel1.Controls.Add(this.txtGPS_Orientacao);
this.panel1.Controls.Add(this.txtGPS_Correcao);
this.panel1.Controls.Add(this.label11);
this.panel1.Controls.Add(this.txtGPS_Precisao);
this.panel1.Controls.Add(this.label8);
@ -743,15 +743,15 @@
this.label10.TabIndex = 39;
this.label10.Text = "Data Leitura";
//
// txtGPS_Orientacao
// txtGPS_Correcao
//
this.txtGPS_Orientacao.Location = new System.Drawing.Point(312, 488);
this.txtGPS_Orientacao.Margin = new System.Windows.Forms.Padding(2);
this.txtGPS_Orientacao.Name = "txtGPS_Orientacao";
this.txtGPS_Orientacao.ReadOnly = true;
this.txtGPS_Orientacao.Size = new System.Drawing.Size(99, 20);
this.txtGPS_Orientacao.TabIndex = 38;
this.txtGPS_Orientacao.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.txtGPS_Correcao.Location = new System.Drawing.Point(312, 488);
this.txtGPS_Correcao.Margin = new System.Windows.Forms.Padding(2);
this.txtGPS_Correcao.Name = "txtGPS_Correcao";
this.txtGPS_Correcao.ReadOnly = true;
this.txtGPS_Correcao.Size = new System.Drawing.Size(99, 20);
this.txtGPS_Correcao.TabIndex = 38;
this.txtGPS_Correcao.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// label11
//
@ -4089,6 +4089,16 @@
this.tabSonar.Text = "Sonar";
this.tabSonar.UseVisualStyleBackColor = true;
//
// chbSonarDeteccoes
//
this.chbSonarDeteccoes.AutoSize = true;
this.chbSonarDeteccoes.Location = new System.Drawing.Point(377, 329);
this.chbSonarDeteccoes.Name = "chbSonarDeteccoes";
this.chbSonarDeteccoes.Size = new System.Drawing.Size(106, 17);
this.chbSonarDeteccoes.TabIndex = 50;
this.chbSonarDeteccoes.Text = "Exibir Detecções";
this.chbSonarDeteccoes.UseVisualStyleBackColor = true;
//
// tabControl3
//
this.tabControl3.Controls.Add(this.tabSonarRGB);
@ -4144,6 +4154,27 @@
this.picMapaCalor.TabIndex = 1;
this.picMapaCalor.TabStop = false;
//
// tabSonarDeteccoes
//
this.tabSonarDeteccoes.Controls.Add(this.pnlSonarDeteccoes);
this.tabSonarDeteccoes.Location = new System.Drawing.Point(4, 22);
this.tabSonarDeteccoes.Name = "tabSonarDeteccoes";
this.tabSonarDeteccoes.Padding = new System.Windows.Forms.Padding(3);
this.tabSonarDeteccoes.Size = new System.Drawing.Size(479, 290);
this.tabSonarDeteccoes.TabIndex = 2;
this.tabSonarDeteccoes.Text = "Detecções";
this.tabSonarDeteccoes.UseVisualStyleBackColor = true;
//
// pnlSonarDeteccoes
//
this.pnlSonarDeteccoes.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
this.pnlSonarDeteccoes.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlSonarDeteccoes.Location = new System.Drawing.Point(3, 3);
this.pnlSonarDeteccoes.Name = "pnlSonarDeteccoes";
this.pnlSonarDeteccoes.Size = new System.Drawing.Size(473, 284);
this.pnlSonarDeteccoes.TabIndex = 0;
this.pnlSonarDeteccoes.Paint += new System.Windows.Forms.PaintEventHandler(this.pnlSonarDeteccoes_Paint);
//
// gridObstaculos
//
this.gridObstaculos.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
@ -5508,37 +5539,6 @@
this.btnPlay.UseVisualStyleBackColor = true;
this.btnPlay.Click += new System.EventHandler(this.btnPlay_Click);
//
// tabSonarDeteccoes
//
this.tabSonarDeteccoes.Controls.Add(this.pnlSonarDeteccoes);
this.tabSonarDeteccoes.Location = new System.Drawing.Point(4, 22);
this.tabSonarDeteccoes.Name = "tabSonarDeteccoes";
this.tabSonarDeteccoes.Padding = new System.Windows.Forms.Padding(3);
this.tabSonarDeteccoes.Size = new System.Drawing.Size(479, 290);
this.tabSonarDeteccoes.TabIndex = 2;
this.tabSonarDeteccoes.Text = "Detecções";
this.tabSonarDeteccoes.UseVisualStyleBackColor = true;
//
// pnlSonarDeteccoes
//
this.pnlSonarDeteccoes.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
this.pnlSonarDeteccoes.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlSonarDeteccoes.Location = new System.Drawing.Point(3, 3);
this.pnlSonarDeteccoes.Name = "pnlSonarDeteccoes";
this.pnlSonarDeteccoes.Size = new System.Drawing.Size(473, 284);
this.pnlSonarDeteccoes.TabIndex = 0;
this.pnlSonarDeteccoes.Paint += new System.Windows.Forms.PaintEventHandler(this.pnlSonarDeteccoes_Paint);
//
// chbSonarDeteccoes
//
this.chbSonarDeteccoes.AutoSize = true;
this.chbSonarDeteccoes.Location = new System.Drawing.Point(377, 329);
this.chbSonarDeteccoes.Name = "chbSonarDeteccoes";
this.chbSonarDeteccoes.Size = new System.Drawing.Size(106, 17);
this.chbSonarDeteccoes.TabIndex = 50;
this.chbSonarDeteccoes.Text = "Exibir Detecções";
this.chbSonarDeteccoes.UseVisualStyleBackColor = true;
//
// frmResultadosOperacao
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -5639,6 +5639,7 @@
((System.ComponentModel.ISupportInitialize)(this.picSonarRadar)).EndInit();
this.tabSonarCalor.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.picMapaCalor)).EndInit();
this.tabSonarDeteccoes.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.gridObstaculos)).EndInit();
this.tabSegmentacao.ResumeLayout(false);
this.tabSegmentacao.PerformLayout();
@ -5658,7 +5659,6 @@
this.pnlInformacoesOperacao.ResumeLayout(false);
this.pnlInformacoesOperacao.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picCameraCaminho)).EndInit();
this.tabSonarDeteccoes.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@ -5694,7 +5694,7 @@
private System.Windows.Forms.Label label9;
private System.Windows.Forms.TextBox txtGPS_Data;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.TextBox txtGPS_Orientacao;
private System.Windows.Forms.TextBox txtGPS_Correcao;
private System.Windows.Forms.Label label11;
private System.Windows.Forms.Label lblDIR_EF;
private System.Windows.Forms.PictureBox picDIR_EF;

View File

@ -1168,7 +1168,7 @@ namespace AgroBase.Forms.Operacoes
txtGPS_Data.Text = (Log?.DataHora ?? MomentoAtual).ToString("dd/MM HH:mm:ss");
txtGPS_Latitude.Text = (Log?.Latitude ?? 0).ToString();
txtGPS_Longitude.Text = (Log?.Longitude ?? 0).ToString();
txtGPS_Orientacao.Text = (Log?.QualidadeFix ?? Enums.TiposCorrecaoGPS.SemCorrecao).ToString();
txtGPS_Correcao.Text = ((Log?.Ntrip_ativado ?? false) ? "N " : "B ") + (Log?.IdadeCorrecao ?? -1) + ": " + (Log?.QualidadeFix ?? Enums.TiposCorrecaoGPS.SemCorrecao).ToString();
txtGPS_Precisao.Text = (Log?.PrecisaoCm ?? 0).ToString("0.00") + " cm";
txtGPS_Satelites.Text = (Log?.NumeroSatelites?.valor ?? 0).ToString();
txtGPS_Velocidade.Text = (Log?.Velocidade ?? 0).ToString("0.00") + " (" + ((Log?.Velocidade ?? 0) * GPSUtils.ConversaoNosKmh).ToString("0.00") + " km/h)";

View File

@ -11,6 +11,7 @@ namespace AgroBase.Models
{
public DateTime Momento { get; set; }
public bool Inicializado { get; set; }
public bool Ntrip_ativado { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public DateTime DataHora { get; set; }
@ -58,6 +59,7 @@ namespace AgroBase.Models
{
return new GPSModel()
{
Ntrip_ativado = Ntrip_ativado,
NumeroSatelites = NumeroSatelites,
Altitude = Altitude,
DataHora = DataHora,

View File

@ -75,21 +75,16 @@ namespace AgroBase.Models
public void AtualizarDadosContexto()
{
DateTime t0 = DateTime.Now;
HealthWorkerService.AtualizarDadosContexto();
DateTime t1 = DateTime.Now;
Variaveis.OperacaoEmAndamento.StatusAtual = (StatusOperacao)RedisService.GetField<int>(CtxKey.DadosOperacao, "status", 0);
Variaveis.OperacaoEmAndamento.OperacaoLiberada = RedisService.GetField(CtxKey.DadosOperacao, "liberado", false);
Variaveis.OperacaoEmAndamento.OperacaoConfigurada = RedisService.GetField(CtxKey.DadosOperacao, "configurado", false);
var tempoAguardando = RedisService.GetField<long>(CtxKey.DadosOperacao, "tempo_aguardando", 0);
Variaveis.OperacaoEmAndamento.TempoAguardando = DateTimeOffset.FromUnixTimeSeconds(tempoAguardando).UtcDateTime.AddSeconds(tempoAguardando % 1).ToLocalTime();
//Console.WriteLine(Variaveis.OperacaoEmAndamento.OperacaoConfigurada);
HealthWorkerService.ModulosSaude = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesModel[]>(CtxKey.DadosOperacao, "status_modulos").ToList();
Variaveis.OperacaoEmAndamento.ErroOperacaoLiberada = RedisService.GetField<string>(CtxKey.DadosOperacao, "motivo_nao_liberado");
DateTime t2 = DateTime.Now;
//Console.WriteLine($"Atualizacao de Contexto: {Math.Round((t1 - t0).TotalSeconds), 4}, Saude Modulos: {Math.Round((t2 - t1).TotalSeconds), 4}, Total: {Math.Round((t2 - t0).TotalSeconds),4}");
GPSService.CorrecaoRTK_Ntrip = RedisService.GetField<bool>(RedisService.ModKey(T_Code.Gps), "correcao_ntrip", false);
}

View File

@ -42,6 +42,7 @@ namespace AgroBase.Services
public static int TaxaAmostragemHz { get; set; } = 5;
private static int rtk_timeout = 60;
private static int TempoMin_Ntrip = 10;
private static bool LoopRTK_Ntrip = false;
public static bool CorrecaoRTK_Ntrip = false;
public static DateTime UltimoEnvioCorrecaoRTK = DateTime.MinValue;
@ -70,7 +71,7 @@ namespace AgroBase.Services
{
DefinirDispositivo();
Task.Run(async () => await ConfigurarModulo());
if (LoopRTK_Ntrip)
if (!Variaveis.IsAgroMonitor && CorrecaoRTK_Ntrip)
{
Task.Run(async () => await AplicarCorrecaoRTK_Ntrip());
}
@ -145,7 +146,7 @@ namespace AgroBase.Services
}
}
private static async Task ConfigurarModuloBase(int tempo_fixacao = 60, string porta_usb = "com3", string porta_saida = "com2")
private static async Task ConfigurarModuloBase(string porta_usb = "com3", string porta_saida = "com2", int tempo_fixacao = 60)
{
string[] comandos = {
// Bauds
@ -401,7 +402,7 @@ namespace AgroBase.Services
UltimaLeitura.PrecisaoHorizontal = precisao;
UltimaLeitura.NumeroSatelites.valor = nsatelites;
UltimaLeitura.QualidadeFix = (TiposCorrecaoGPS)fix;
UltimaLeitura.IdadeCorrecao = idadeCorrecao;
UltimaLeitura.IdadeCorrecao = string.IsNullOrEmpty(idadeCorrecaoRaw) ? -1 : idadeCorrecao;
// Parse a hora do formato HHmmss.ss
if (!string.IsNullOrEmpty(horaUTC) && TimeSpan.TryParseExact(horaUTC.Substring(0, 6), "hhmmss", CultureInfo.InvariantCulture, out TimeSpan timeOfDay))
@ -792,7 +793,7 @@ namespace AgroBase.Services
private static async Task AplicarCorrecaoRTK_Ntrip()
{
if (LoopRTK_Ntrip)
if (LoopRTK_Ntrip || !APIService.HasInternet)
return;
LoopRTK_Ntrip = true;
@ -804,7 +805,7 @@ namespace AgroBase.Services
string username = "Zendion"; // Geralmente vazio para RTK2Go
string password = "vyNEF$5*"; // Geralmente vazio para RTK2Go
while (LoopRTK_Ntrip) // Loop para reconectar em caso de falha
while (CorrecaoRTK_Ntrip && APIService.HasInternet) // Loop para reconectar em caso de falha
{
try
{
@ -832,7 +833,7 @@ namespace AgroBase.Services
using (StreamReader reader = new StreamReader(stream, Encoding.ASCII))
{
string response = await reader.ReadLineAsync();
if (LoopRTK_Ntrip)
if (CorrecaoRTK_Ntrip)
{
if ((response ?? "").Contains("200 OK"))
{
@ -840,9 +841,9 @@ namespace AgroBase.Services
byte[] buffer = new byte[4096];
int bytesRead;
while (LoopRTK_Ntrip && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
while (CorrecaoRTK_Ntrip && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
if (CorrecaoRTK_Ntrip && (PortaGPS?.IsOpen ?? false))
if (PortaGPS?.IsOpen ?? false)
{
PortaGPS.Write(buffer, 0, bytesRead); // Envia os dados RTCM para o GPS
//Console.WriteLine($"Enviando {bytesRead} bytes de correção RTCM para o GPS");
@ -865,12 +866,17 @@ namespace AgroBase.Services
await Task.Delay(5000); // Aguarde antes de tentar novamente
}
}
LoopRTK_Ntrip = false;
}
public static void AtualizarCoordenadasGPS()
{
PenultimaLeitura.Ntrip_ativado = UltimaLeitura.Ntrip_ativado;
UltimaLeitura.Ntrip_ativado = CorrecaoRTK_Ntrip;
if (Variaveis.IsAgroMonitor)
{
EnviarCoordenadasParaMapa(UltimaLeitura.Latitude, UltimaLeitura.Longitude, UltimaLeitura.AnguloCarroDefinido, false, LoRaBaseService.parametrosModel.address);
@ -934,7 +940,7 @@ namespace AgroBase.Services
PenultimaLeitura.Inicializado = UltimaLeitura.Inicializado;
UltimaLeitura.Inicializado = Iniciado;
if (CorrecaoRTK_Ntrip && UltimoEnvioCorrecaoRTK.AddSeconds(10) < DateTime.Now)
if (CorrecaoRTK_Ntrip && UltimoEnvioCorrecaoRTK.AddSeconds(TempoMin_Ntrip) < DateTime.Now)
{
UltimoEnvioCorrecaoRTK = DateTime.Now;
LoopRTK_Ntrip = false;
@ -1202,6 +1208,7 @@ namespace AgroBase.Services
("hAcc", UltimaLeitura.PrecisaoCm),
("nSatelites", UltimaLeitura.NumeroSatelites.valor),
("freq", UltimaLeitura.NumeroSatelites.frequencia),
("age", UltimaLeitura.IdadeCorrecao),
("heartbeat", UltimaLeitura.Heartbeat)
);
}

View File

@ -191,6 +191,7 @@ namespace AgroBase.Services.Operadores
("modo", Variaveis.OperacaoEmAndamento.Modo),
("tempo_aguardar_inicio_operacao", Variaveis.OperacaoEmAndamento.TempoIniciarOperacao),
("modulos_mandatorios", Variaveis.OperacaoEmAndamento.ModulosMandatorios.Where(x => x.Mandatorio && x.Utilizar).Select(x => (int)x.Dispositivo).ToArray()),
("modulos_opcionais", Variaveis.OperacaoEmAndamento.ModulosMandatorios.Where(x => !x.Mandatorio && x.Utilizar).Select(x => (int)x.Dispositivo).ToArray()),
("parametros_mandatorios", Variaveis.OperacaoEmAndamento.ParametrosMandatorios.Where(x => x.Mandatorio && x.Utilizar).Select(x => (int)x.Parametro).ToArray()),
("Mov", new
{

View File

@ -146,6 +146,7 @@ namespace AgroBase.Services
public static void LimparDadosIniciais()
{
Set(CtxKey.DadosCameras, JsonConvert.SerializeObject(new Dictionary<string, CameraWorkerItemModel>()));
AtualizarCampos(ModKey(T_Code.Gps), ("correcao_ntrip", false));
DefinirEquipamentoDesconectado();
}

View File

@ -21,6 +21,8 @@ class ModuloGPS(ModuloDiagnosticoBase):
fix = modulo.get("fix", 0)
rtk = modulo.get("rtk", False)
hAcc = modulo.get("hAcc", 0)
age = modulo.get("age", -1)
ntrip = modulo.get("correcao_ntrip", False)
saude = 100
motivos = []
@ -34,25 +36,32 @@ class ModuloGPS(ModuloDiagnosticoBase):
else:
f = min(freq_hz, FREQ_BASE)
erro = (FREQ_BASE - f) / FREQ_BASE
p = min(int(erro * 100), 40)
saude -= abs(p)
if abs(p) > 0:
motivos.append(f"Frequência baixa: {f:.2f} Hz (penalidade {p}%)")
p_freq = min(int(erro * 100), 40)
saude -= abs(p_freq)
if abs(p_freq) > 0:
motivos.append(f"Frequência baixa: {f:.2f} Hz (penalidade {p_freq}%)")
# 🔹 Fix
penalidades_fix = { 0: 90, 1: 70, 2: 40, 3: 30, 4: 5, 5: 0 }
p = penalidades_fix.get(fix, 100)
saude -= p
p_fix = self._penalidade_fix(fix)
saude -= p_fix
if fix < 4:
motivos.append(f"Fix inadequado: {fix} (penalidade {p}%)")
motivos.append(f"Fix inadequado: {fix} (penalidade {p_fix}%)")
# 🔹 RTK
p_age = self._penalidade_age(age)
if not rtk:
saude -= 20
motivos.append("RTK inativo")
p_rtk = max(20, p_age)
saude -= p_rtk
motivos.append(f"RTK inativo (penalidade {p_rtk}%; age={age:.1f}s)")
else:
# RTK reporta ativo, mas pode estar degradado se age alto
if p_age > 0:
saude -= p_age
motivos.append(f"Correção RTK degradada (age={age:.1f}s, penalidade {p_age}%, ntrip: {ntrip})")
# 🔹 hAcc
p = self._penalidade_hacc(hAcc)
if p > 0:
saude -= p
motivos.append(f"hAcc {'nao definido' if hAcc == 0 else 'alto'}: {hAcc:.2f} cm (penalidade {p}%)")
p_hacc = self._penalidade_hacc(hAcc)
if p_hacc > 0:
saude -= p_hacc
motivos.append(f"hAcc {'nao definido' if hAcc == 0 else 'alto'}: {hAcc:.2f} cm (penalidade {p_hacc}%)")
saude = max(saude, 0)
@ -73,16 +82,164 @@ class ModuloGPS(ModuloDiagnosticoBase):
}
ContextoGlobalRedis.atualizar_ctx_dict(
ContextoGlobalRedis.ModKey(self.t_code),
ContextoGlobalRedis.ModKey(self.t_code),
saude=saude_geral
)
# Fallback de correcao RTK via NTRIP
if conectado:
AGE_HI = 5 # s (ruim)
AGE_LO = 2 # s (bem estabilizado)
HACC_OK = 40 # cm
T_BAD = 4 # s p/ ligar NTRIP
T_GOOD = 10 # s p/ desligar NTRIP
MIN_ON = 25 # s mínimo ligado
MIN_OFF = 12 # s mínimo desligado
# ---- NOVOS PARÂMETROS DE RETENTATIVA/BACKOFF ----
MAX_TRIES = 3 # nº máx de tentativas falhas de voltar ao LoRa
PROBE_EVAL_WINDOW = 30 # s: janela máxima de avaliação ao desligar NTRIP p/ testar LoRa
PROBE_BACKOFF = 5 * 60 # s: espera entre testes após esgotar tentativas
PROBE_MIN_OFF = max(MIN_OFF, 5) # s: mínimo off durante um "probe" curto
estado = ContextoGlobalRedis.get_modulo(self.t_code) or {}
correcao_ntrip = bool(estado.get("correcao_ntrip", False))
last_switch_ts = float(estado.get("ntrip_last_switch_ts", 0))
bad_since_ts = float(estado.get("ntrip_bad_since_ts", 0))
good_since_ts = float(estado.get("ntrip_good_since_ts", 0))
# ---- NOVOS CAMPOS DE CONTROLE ----
probe_attempts = int(estado.get("ntrip_probe_attempts", 0)) # falhas acumuladas
probe_start_ts = float(estado.get("ntrip_probe_start_ts", 0)) # quando começou o teste atual (NTRIP desligado)
next_probe_ts = float(estado.get("ntrip_next_probe_ts", 0)) # quando pode tentar de novo (backoff)
now = time.time()
# Qualidade atual
qual_ruim = (fix < 4) or (age > AGE_HI) or (hAcc >= HACC_OK and hAcc > 0)
qual_boa = (fix >= 4) and (age < AGE_LO) and (0 < hAcc < HACC_OK)
severa = (fix <= 2) or (age > 15)
# Atualiza contadores de estabilidade
if qual_ruim:
bad_since_ts = bad_since_ts or now
good_since_ts = 0
elif qual_boa:
good_since_ts = good_since_ts or now
bad_since_ts = 0
else:
bad_since_ts = 0
good_since_ts = 0
# Cooldowns
tempo_desde_troca = now - last_switch_ts
pode_ligar = (not correcao_ntrip) and (tempo_desde_troca >= MIN_OFF)
pode_deslig = correcao_ntrip and (tempo_desde_troca >= MIN_ON)
# --------------------------------------------------
# LÓGICA COM TENTATIVAS/BACKOFF
# --------------------------------------------------
ligar = False
desligar = False
if not correcao_ntrip:
# Estamos em LoRa (ou sem correção) → decidir ligar NTRIP
if severa:
ligar = True
elif qual_ruim and bad_since_ts and (now - bad_since_ts >= T_BAD) and pode_ligar:
ligar = True
# Se estamos em um "probe" (testando LoRa) e já passou a janela sem estabilizar, contabiliza falha
if probe_start_ts and (now - probe_start_ts >= PROBE_EVAL_WINDOW) and not qual_boa:
# falha de tentativa
probe_attempts += 1
# força ligar NTRIP e inicia backoff
ligar = True
next_probe_ts = now + PROBE_BACKOFF
probe_start_ts = 0 # encerra janela de teste
else:
# Estamos com NTRIP ligado → decidir desligar (testar LoRa)
# Regra normal: só desliga se qualidade está boa e estável
pronto_pra_desligar = qual_boa and good_since_ts and (now - good_since_ts >= T_GOOD) and pode_deslig
if pronto_pra_desligar:
if probe_attempts >= MAX_TRIES and now < next_probe_ts:
# Em modo "persistente NTRIP": já falhou muitas vezes, respeitar backoff (não desliga ainda)
desligar = False
else:
# Podemos testar o LoRa: desliga NTRIP e inicia janela de avaliação ("probe")
desligar = True
probe_start_ts = now
# zera good_since_ts para exigir nova estabilidade sem NTRIP
good_since_ts = 0
# Aplicar decisão
if ligar and pode_ligar:
correcao_ntrip = True
last_switch_ts = now
# ao ligar NTRIP, encerra probe (se existia)
probe_start_ts = 0
elif desligar and pode_deslig:
correcao_ntrip = False
last_switch_ts = now
# iniciar "probe": garantir um off mínimo
if next_probe_ts and now < next_probe_ts:
# segurança: se por algum motivo desligou antes do backoff, reativa NTRIP rápido
pass
# mantém off por pelo menos PROBE_MIN_OFF (garantido indiretamente via pode_ligar)
# Se NTRIP está desligado e qualidade ficou realmente estável dentro do probe, considera sucesso
if (not correcao_ntrip) and probe_start_ts:
# sucesso se já atingiu estabilidade boa por T_GOOD enquanto NTRIP está off
if qual_boa and good_since_ts and (now - good_since_ts >= T_GOOD):
# sucesso: permanece em LoRa e zera contadores
probe_attempts = 0
next_probe_ts = 0
probe_start_ts = 0
# Persistir estado
ContextoGlobalRedis.atualizar_ctx_dict(
ContextoGlobalRedis.ModKey(self.t_code),
correcao_ntrip=correcao_ntrip,
ntrip_last_switch_ts=last_switch_ts,
ntrip_bad_since_ts=bad_since_ts,
ntrip_good_since_ts=good_since_ts,
ntrip_probe_attempts=probe_attempts,
ntrip_probe_start_ts=probe_start_ts,
ntrip_next_probe_ts=next_probe_ts
)
except Exception as e:
print(f"Erro ao atualizar saude do modulo {self.t_code.name}: {e}")
def _penalidade_hacc(self, h):
def _penalidade_fix(self, fix) -> int:
if fix == 0: return 90 # inválido
if fix == 1: return 70 # single
if fix == 2: return 40 # DGPS
if fix == 3: return 30 # PPS
if fix == 4: return 0 # RTK Fixed (melhor caso)
if fix == 5: return 5 # RTK Float (quase bom)
if fix == 6: return 50 # dead reckoning
if fix == 7: return 80 # manual
if fix == 8: return 80 # simulador
return 90
def _penalidade_hacc(self, h) -> int:
if h == 0: return 30
if h < 40: return 0
if h < 80: return 5
if h < 120: return 10
if h < 200: return 20
if h == 0: return 30
return 30
def _penalidade_age(self, age) -> int:
if age < 0: return 35
if age < 0.5: return 0
if age < 2.0: return 5
if age < 5.0: return 10
if age < 10.0: return 18
if age < 15.0: return 25
return 35

View File

@ -187,7 +187,9 @@ class ContextoGlobalRedis:
tempo_aguardando=0,
status_modulos=[],
modulos_mandatorios_pendentes=[],
parametros_mandatorios=[]
parametros_mandatorios=[],
modulos_opcionais_presentes=[],
modulos_opcionais_configurados=[]
)
@ -200,9 +202,11 @@ class ContextoGlobalRedis:
@classmethod
def _atualizar_operacao_liberada(cls):
_operacao = cls.get_operacao()
# 🔹 Check se todos os módulos mandatórios estão disponíveis
# 🔹 Conjuntos de módulos
modulos_mandatorios = set(_operacao.get("modulos_mandatorios", []))
modulos_opcionais = set(_operacao.get("modulos_opcionais", []))
modulos_presentes = set()
status_modulos = []
motivos_dos_modulos = []
@ -219,46 +223,81 @@ class ContextoGlobalRedis:
saude = _saude.get("saude", 0.0)
motivos = _saude.get("motivos", ["Modulo desconectado"])
saude_individual = _saude.get("saude_individual", [])
if status == StatusModulo.OPERANTE.value:
modulos_presentes.add(t_code.value)
status_modulos.append({
"modulo": t_code.value,
"status": status,
"saude": saude,
"motivos": motivos,
"modulo": t_code.value,
"status": status,
"saude": saude,
"motivos": motivos,
"saude_individual": saude_individual
})
# 🔹 Apenas adicionar motivo se for módulo obrigatório e status ruim
# 🔹 Apenas registrar motivo se for módulo obrigatório e estiver ruim
if t_code.value in modulos_mandatorios and status != StatusModulo.OPERANTE.value:
motivo_txt = "Desconectado" if status == StatusModulo.DESCONECTADO.value else "; ".join(motivos)
motivos_dos_modulos.append(f"{t_code.name}: {motivo_txt}")
except Exception as e:
# Garante que saude_individual exista aqui
status_modulos.append({
"modulo": t_code.value,
"status": StatusModulo.FALHA.value,
"modulo": t_code.value,
"status": StatusModulo.FALHA.value,
"saude": 0.0,
"motivos": [f"Erro ao verificar {t_code.name}: {e}"],
"saude_individual": saude_individual
"saude_individual": []
})
todos_presentes = modulos_mandatorios.issubset(modulos_presentes)
modulos_pendentes = modulos_mandatorios - modulos_presentes
# 🔹 Checagens de presença
todos_mandatorios_presentes = modulos_mandatorios.issubset(modulos_presentes)
modulos_mandatorios_pend = modulos_mandatorios - modulos_presentes
# 🔹 Parâmetros mandatórios
# Se não há mandatórios, exigimos pelo menos 1 opcional presente
tem_mandatorio_config = len(modulos_mandatorios) > 0
ao_menos_um_opcional_presente = len(modulos_opcionais & modulos_presentes) > 0 if len(modulos_opcionais) > 0 else False
# 🔹 Parâmetros mandatórios (mantive sua lógica)
parametros = _operacao.get("parametros_mandatorios", [])
parametros_ok = True
parametros_ok = True # ajuste aqui se tiver validação
# 🔹 Define status da operação
# 🔹 Debug mode
debug_mode = _operacao.get("debug_mode", False)
# 🔹 Atualiza status de liberação
liberou = (todos_presentes and parametros_ok) or debug_mode
# 🔹 Lógica de liberação:
# - se há mandatórios => precisa TODOS os mandatórios + parâmetros ok
# - se NÃO há mandatórios => precisa AO MENOS 1 opcional + parâmetros ok
if tem_mandatorio_config:
base_ok = todos_mandatorios_presentes
if not base_ok and modulos_mandatorios_pend:
# Motivos de mandatório já adicionados acima por módulo
pass
else:
# Sem mandatórios: exigir ao menos um opcional presente
base_ok = ao_menos_um_opcional_presente
if not base_ok:
if len(modulos_opcionais) > 0:
nomes = [tc.name for tc in T_Code if tc.value in modulos_opcionais]
motivos_dos_modulos.append(
"Nenhum módulo opcional presente (é necessário pelo menos 1): " + ", ".join(nomes)
)
else:
# Nem mandatório nem opcional configurado: por segurança, não libera
motivos_dos_modulos.append(
"Nenhum módulo mandatório configurado e nenhum opcional definido — operação não pode iniciar."
)
liberou = (base_ok and parametros_ok) or debug_mode
cls.atualizar_ctx_dict(
CtxKey.DadosOperacao,
CtxKey.DadosOperacao,
liberado=liberou,
motivo_nao_liberado="\n\n".join(motivos_dos_modulos) if not liberou else None,
status_modulos=status_modulos,
modulos_mandatorios_pendentes=list(modulos_pendentes)
status_modulos=status_modulos,
modulos_mandatorios_pendentes=list(modulos_mandatorios_pend),
modulos_opcionais_presentes=list(modulos_opcionais & modulos_presentes),
modulos_opcionais_configurados=list(modulos_opcionais)
)
@classmethod