diff --git a/AgroBase/.vs/AgroBase/FileContentIndex/68da06dd-8142-4af4-a5c4-ffd53833bcd6.vsidx b/AgroBase/.vs/AgroBase/FileContentIndex/68da06dd-8142-4af4-a5c4-ffd53833bcd6.vsidx new file mode 100644 index 000000000..fae7b455e Binary files /dev/null and b/AgroBase/.vs/AgroBase/FileContentIndex/68da06dd-8142-4af4-a5c4-ffd53833bcd6.vsidx differ diff --git a/AgroBase/.vs/AgroBase/FileContentIndex/a7799e93-7d26-469c-ac8f-3395dd042b55.vsidx b/AgroBase/.vs/AgroBase/FileContentIndex/a7799e93-7d26-469c-ac8f-3395dd042b55.vsidx deleted file mode 100644 index 071662112..000000000 Binary files a/AgroBase/.vs/AgroBase/FileContentIndex/a7799e93-7d26-469c-ac8f-3395dd042b55.vsidx and /dev/null differ diff --git a/AgroBase/.vs/AgroBase/v17/.suo b/AgroBase/.vs/AgroBase/v17/.suo index 12a826980..1a5d4093d 100644 Binary files a/AgroBase/.vs/AgroBase/v17/.suo and b/AgroBase/.vs/AgroBase/v17/.suo differ diff --git a/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.Designer.cs b/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.Designer.cs index 0698b0438..bd54977f7 100644 --- a/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.Designer.cs +++ b/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.Designer.cs @@ -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); diff --git a/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.cs b/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.cs index 23307c6ab..90087c817 100644 --- a/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.cs +++ b/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.cs @@ -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; diff --git a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.Designer.cs b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.Designer.cs index 59b865897..8325945d1 100644 --- a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.Designer.cs +++ b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.Designer.cs @@ -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 // diff --git a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs index d9fed78b5..39ecf7e7a 100644 --- a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs +++ b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs @@ -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"; diff --git a/AgroBase/AgroBase/Forms/Operacoes/frmResultadosOperacao.Designer.cs b/AgroBase/AgroBase/Forms/Operacoes/frmResultadosOperacao.Designer.cs index 50cd62083..0956e8281 100644 --- a/AgroBase/AgroBase/Forms/Operacoes/frmResultadosOperacao.Designer.cs +++ b/AgroBase/AgroBase/Forms/Operacoes/frmResultadosOperacao.Designer.cs @@ -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; diff --git a/AgroBase/AgroBase/Forms/Operacoes/frmResultadosOperacao.cs b/AgroBase/AgroBase/Forms/Operacoes/frmResultadosOperacao.cs index 1f0f3137c..f1d055241 100644 --- a/AgroBase/AgroBase/Forms/Operacoes/frmResultadosOperacao.cs +++ b/AgroBase/AgroBase/Forms/Operacoes/frmResultadosOperacao.cs @@ -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)"; diff --git a/AgroBase/AgroBase/Models/GPSModel.cs b/AgroBase/AgroBase/Models/GPSModel.cs index e5841b984..9e3f2daaa 100644 --- a/AgroBase/AgroBase/Models/GPSModel.cs +++ b/AgroBase/AgroBase/Models/GPSModel.cs @@ -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, diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs index eb31d3f70..48bcc5943 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs @@ -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(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(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(CtxKey.DadosOperacao, "status_modulos").ToList(); Variaveis.OperacaoEmAndamento.ErroOperacaoLiberada = RedisService.GetField(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(RedisService.ModKey(T_Code.Gps), "correcao_ntrip", false); } diff --git a/AgroBase/AgroBase/Services/GPSService.cs b/AgroBase/AgroBase/Services/GPSService.cs index 6e8552937..3704f122e 100644 --- a/AgroBase/AgroBase/Services/GPSService.cs +++ b/AgroBase/AgroBase/Services/GPSService.cs @@ -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) ); } diff --git a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs index 3b52c4f04..cc48dcca6 100644 --- a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs +++ b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs @@ -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 { diff --git a/AgroBase/AgroBase/Services/RedisService.cs b/AgroBase/AgroBase/Services/RedisService.cs index 713238078..aac03186f 100644 --- a/AgroBase/AgroBase/Services/RedisService.cs +++ b/AgroBase/AgroBase/Services/RedisService.cs @@ -146,6 +146,7 @@ namespace AgroBase.Services public static void LimparDadosIniciais() { Set(CtxKey.DadosCameras, JsonConvert.SerializeObject(new Dictionary())); + AtualizarCampos(ModKey(T_Code.Gps), ("correcao_ntrip", false)); DefinirEquipamentoDesconectado(); } diff --git a/AgroBase/AgroBase/bin/x64/Debug/AgroBase.exe b/AgroBase/AgroBase/bin/x64/Debug/AgroBase.exe index a70678930..81bf51a62 100644 Binary files a/AgroBase/AgroBase/bin/x64/Debug/AgroBase.exe and b/AgroBase/AgroBase/bin/x64/Debug/AgroBase.exe differ diff --git a/AgroBase/AgroBase/bin/x64/Debug/AgroBase.pdb b/AgroBase/AgroBase/bin/x64/Debug/AgroBase.pdb index 9a27561ab..bd3bd3ea4 100644 Binary files a/AgroBase/AgroBase/bin/x64/Debug/AgroBase.pdb and b/AgroBase/AgroBase/bin/x64/Debug/AgroBase.pdb differ diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/__pycache__/gps.cpython-311.pyc b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/__pycache__/gps.cpython-311.pyc index 5f16afd4b..05d076ca7 100644 Binary files a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/__pycache__/gps.cpython-311.pyc and b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/__pycache__/gps.cpython-311.pyc differ diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/gps.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/gps.py index 7f03f43b2..6938e7e83 100644 --- a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/gps.py +++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/health_worker/modulos/gps.py @@ -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 diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/__pycache__/contexto_global_redis.cpython-311.pyc b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/__pycache__/contexto_global_redis.cpython-311.pyc index f7ac0c4ba..0cb389e3a 100644 Binary files a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/__pycache__/contexto_global_redis.cpython-311.pyc and b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/__pycache__/contexto_global_redis.cpython-311.pyc differ diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/contexto_global_redis.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/contexto_global_redis.py index 1864a8959..90cb9d657 100644 --- a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/contexto_global_redis.py +++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/workers/shared/contexto_global_redis.py @@ -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