agrobase
This commit is contained in:
parent
d42a7d4005
commit
7c8da7e435
|
|
@ -30,8 +30,8 @@ namespace AgroBase.Forms.Atuador
|
||||||
nudPressaoSP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha);
|
nudPressaoSP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha);
|
||||||
txtPressaoVmin.Text = DispAtu.Dados._PressaoVmin.ToString();
|
txtPressaoVmin.Text = DispAtu.Dados._PressaoVmin.ToString();
|
||||||
txtPressaoVmax.Text = DispAtu.Dados._PressaoVmax.ToString();
|
txtPressaoVmax.Text = DispAtu.Dados._PressaoVmax.ToString();
|
||||||
txtMLRef.Text = DispAtu.Dados._FluxoMlRef.ToString();
|
txtMLRef.Text = DispAtu.Dados.VazaoFluxoMLpSReferencia.ToString();
|
||||||
txtPulsosRef.Text = DispAtu.Dados._FluxoPulsoRef.ToString();
|
//txtPulsosRef.Text = DispAtu.Dados._FluxoPulsoRef.ToString();
|
||||||
txtVolume.Text = DispAtu.Dados.VolumeVazaoAferido.ToString();
|
txtVolume.Text = DispAtu.Dados.VolumeVazaoAferido.ToString();
|
||||||
|
|
||||||
grdSensoriamento.Rows.Clear();
|
grdSensoriamento.Rows.Clear();
|
||||||
|
|
@ -207,8 +207,8 @@ namespace AgroBase.Forms.Atuador
|
||||||
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Convert.ToDouble(nudPressaoSP.Value);
|
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Convert.ToDouble(nudPressaoSP.Value);
|
||||||
DispAtu.Dados._PressaoVmin = Convert.ToDouble(txtPressaoVmin.Text);
|
DispAtu.Dados._PressaoVmin = Convert.ToDouble(txtPressaoVmin.Text);
|
||||||
DispAtu.Dados._PressaoVmax = Convert.ToDouble(txtPressaoVmax.Text);
|
DispAtu.Dados._PressaoVmax = Convert.ToDouble(txtPressaoVmax.Text);
|
||||||
DispAtu.Dados._FluxoMlRef = Convert.ToDouble(txtMLRef.Text);
|
//DispAtu.Dados._FluxoMlRef = Convert.ToDouble(txtMLRef.Text);
|
||||||
DispAtu.Dados._FluxoPulsoRef = Convert.ToDouble(txtPulsosRef.Text);
|
//DispAtu.Dados._FluxoPulsoRef = Convert.ToDouble(txtPulsosRef.Text);
|
||||||
DispAtu.Dados.VolumeVazaoAferido = Convert.ToDouble(txtVolume.Text);
|
DispAtu.Dados.VolumeVazaoAferido = Convert.ToDouble(txtVolume.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
using AgroBase.Models;
|
using AgroBase.Models;
|
||||||
using AgroBase.Models.Components;
|
using AgroBase.Models.Components;
|
||||||
using AgroBase.Models.Operadores;
|
|
||||||
using AgroBase.Services;
|
|
||||||
using AgroBase.Services.Operadores;
|
using AgroBase.Services.Operadores;
|
||||||
using Assimp;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
|
@ -264,14 +261,14 @@ namespace AgroBase.Forms.IHM
|
||||||
var cameras = CameraWorkerService.GetListaCameras();
|
var cameras = CameraWorkerService.GetListaCameras();
|
||||||
ListaCameras = cameras.Select(x => new OAKCameraModel()
|
ListaCameras = cameras.Select(x => new OAKCameraModel()
|
||||||
{
|
{
|
||||||
Index = 0,
|
Index = cameras.IndexOf(x),
|
||||||
Dispositivo = x.dispositivo,
|
Dispositivo = x.dispositivo,
|
||||||
Version = x.versao,
|
Version = x.versao,
|
||||||
Name = x.modelo,
|
Name = x.modelo,
|
||||||
Id = x.mx_id,
|
Id = x.mx_id,
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.Clone();
|
CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.Clone();
|
||||||
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo);
|
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo);
|
||||||
|
|
||||||
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
|
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
|
||||||
|
|
@ -281,7 +278,7 @@ namespace AgroBase.Forms.IHM
|
||||||
|
|
||||||
cmbCameraCaminho.Items.Clear();
|
cmbCameraCaminho.Items.Clear();
|
||||||
cmbCameraCaminho.Items.AddRange(ListaCameras.Select(x => x.Description).ToArray());
|
cmbCameraCaminho.Items.AddRange(ListaCameras.Select(x => x.Description).ToArray());
|
||||||
var cameraSelecionada = ListaCameras.FirstOrDefault(x => x.Id == CameraCaminho.Id);
|
var cameraSelecionada = ListaCameras.FirstOrDefault(x => x.Id == CameraCaminho?.Id);
|
||||||
if (cameraSelecionada != null)
|
if (cameraSelecionada != null)
|
||||||
{
|
{
|
||||||
cmbCameraCaminho.SelectedIndex = cmbCameraCaminho.Items.IndexOf(cameraSelecionada.Description);
|
cmbCameraCaminho.SelectedIndex = cmbCameraCaminho.Items.IndexOf(cameraSelecionada.Description);
|
||||||
|
|
@ -344,7 +341,7 @@ namespace AgroBase.Forms.IHM
|
||||||
CamerasSolo.Add(new OAKCameraModel());
|
CamerasSolo.Add(new OAKCameraModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
var cameraSelecionada = ListaCameras.FirstOrDefault(x => x.Id == CamerasSolo[idx].Id);
|
var cameraSelecionada = ListaCameras.FirstOrDefault(x => x.Id == CamerasSolo[idx]?.Id);
|
||||||
|
|
||||||
if (cameraSelecionada != null)
|
if (cameraSelecionada != null)
|
||||||
{
|
{
|
||||||
|
|
@ -410,11 +407,11 @@ namespace AgroBase.Forms.IHM
|
||||||
{
|
{
|
||||||
if (idx == -1)
|
if (idx == -1)
|
||||||
{
|
{
|
||||||
emUso = CamerasSolo.Any(x => x.Id == cam.Id);
|
emUso = CamerasSolo.Any(x => cam.Id != null && x.Id == cam.Id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emUso = (CameraCaminho.Id == cam.Id) || (CamerasSolo.Any(x => x.Index != idx && x.Id == cam.Id));
|
emUso = cam.Id != null && ((CameraCaminho?.Id == cam.Id) || (CamerasSolo.Any(x => x?.Index != idx && x?.Id == cam.Id)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@
|
||||||
this.flwCamerasSolo = new System.Windows.Forms.FlowLayoutPanel();
|
this.flwCamerasSolo = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
this.chbSonarAtivado = new System.Windows.Forms.CheckBox();
|
this.chbSonarAtivado = new System.Windows.Forms.CheckBox();
|
||||||
this.lblPressao = new System.Windows.Forms.Label();
|
this.lblPressao = new System.Windows.Forms.Label();
|
||||||
|
this.lblStatusCarroMapa = new System.Windows.Forms.Label();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.chartGraficos)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.chartGraficos)).BeginInit();
|
||||||
this.tabControl1.SuspendLayout();
|
this.tabControl1.SuspendLayout();
|
||||||
this.tabMapa.SuspendLayout();
|
this.tabMapa.SuspendLayout();
|
||||||
|
|
@ -352,6 +353,7 @@
|
||||||
//
|
//
|
||||||
// tabDeteccoes
|
// tabDeteccoes
|
||||||
//
|
//
|
||||||
|
this.tabDeteccoes.Controls.Add(this.lblStatusCarroMapa);
|
||||||
this.tabDeteccoes.Controls.Add(this.pnlDeteccoesRua);
|
this.tabDeteccoes.Controls.Add(this.pnlDeteccoesRua);
|
||||||
this.tabDeteccoes.Location = new System.Drawing.Point(4, 22);
|
this.tabDeteccoes.Location = new System.Drawing.Point(4, 22);
|
||||||
this.tabDeteccoes.Margin = new System.Windows.Forms.Padding(2);
|
this.tabDeteccoes.Margin = new System.Windows.Forms.Padding(2);
|
||||||
|
|
@ -721,6 +723,16 @@
|
||||||
this.lblPressao.TabIndex = 38;
|
this.lblPressao.TabIndex = 38;
|
||||||
this.lblPressao.Text = "80 psi";
|
this.lblPressao.Text = "80 psi";
|
||||||
//
|
//
|
||||||
|
// lblStatusCarroMapa
|
||||||
|
//
|
||||||
|
this.lblStatusCarroMapa.AutoSize = true;
|
||||||
|
this.lblStatusCarroMapa.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.lblStatusCarroMapa.Location = new System.Drawing.Point(10, 269);
|
||||||
|
this.lblStatusCarroMapa.Name = "lblStatusCarroMapa";
|
||||||
|
this.lblStatusCarroMapa.Size = new System.Drawing.Size(168, 16);
|
||||||
|
this.lblStatusCarroMapa.TabIndex = 1;
|
||||||
|
this.lblStatusCarroMapa.Text = "Status: Parado | Conf: 1.000";
|
||||||
|
//
|
||||||
// frmOperacaoManual
|
// frmOperacaoManual
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
|
@ -763,6 +775,7 @@
|
||||||
this.tabInformacoes.ResumeLayout(false);
|
this.tabInformacoes.ResumeLayout(false);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.gridDados)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.gridDados)).EndInit();
|
||||||
this.tabDeteccoes.ResumeLayout(false);
|
this.tabDeteccoes.ResumeLayout(false);
|
||||||
|
this.tabDeteccoes.PerformLayout();
|
||||||
this.tabPulverizador.ResumeLayout(false);
|
this.tabPulverizador.ResumeLayout(false);
|
||||||
this.tabPulverizador.PerformLayout();
|
this.tabPulverizador.PerformLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.nudPotenciaSP)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.nudPotenciaSP)).EndInit();
|
||||||
|
|
@ -835,5 +848,6 @@
|
||||||
private System.Windows.Forms.Label lblPotenciaSP;
|
private System.Windows.Forms.Label lblPotenciaSP;
|
||||||
private System.Windows.Forms.NumericUpDown nudPotenciaSP;
|
private System.Windows.Forms.NumericUpDown nudPotenciaSP;
|
||||||
private System.Windows.Forms.Label lblPressao;
|
private System.Windows.Forms.Label lblPressao;
|
||||||
|
private System.Windows.Forms.Label lblStatusCarroMapa;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -219,6 +219,9 @@ namespace AgroBase.Forms.Operacoes
|
||||||
|
|
||||||
//var frameSeg = await VisualWorkerService.GetCameraFrame(CameraFrameType.Segmentacao);
|
//var frameSeg = await VisualWorkerService.GetCameraFrame(CameraFrameType.Segmentacao);
|
||||||
//AtualizarImagemPainel(pnlDeteccoesRua, frameSeg?.image());
|
//AtualizarImagemPainel(pnlDeteccoesRua, frameSeg?.image());
|
||||||
|
|
||||||
|
var dadosSeg = Variaveis.OperacaoEmAndamento.Sensoriamento?.OperadorVisual?.Analises?.segmentacao;
|
||||||
|
lblStatusCarroMapa.Text = $"Status: {dadosSeg?.status_corredor ?? StatusCarroMapa.Indefinido} | Conf: {dadosSeg?.status_corredor_debug?.status_modelo_conf ?? 0}";
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -736,65 +736,44 @@ namespace AgroBase.Forms.Operacoes
|
||||||
{
|
{
|
||||||
new GraficoInterativoSerieModel()
|
new GraficoInterativoSerieModel()
|
||||||
{
|
{
|
||||||
Titulo = "CPU %",
|
Titulo = "GPU Geral %",
|
||||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.CPU_load ?? 0)).ToList(),
|
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_load_percent ?? 0)).ToList(),
|
||||||
Visivel = true,
|
Visivel = true,
|
||||||
MostrarValor = true
|
MostrarValor = true
|
||||||
},
|
},
|
||||||
new GraficoInterativoSerieModel()
|
new GraficoInterativoSerieModel()
|
||||||
{
|
{
|
||||||
Titulo = "GPU %",
|
Titulo = "GPU Core %",
|
||||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_load ?? 0)).ToList(),
|
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_core_load_percent ?? 0)).ToList(),
|
||||||
Visivel = true,
|
Visivel = true,
|
||||||
MostrarValor = true
|
MostrarValor = true
|
||||||
},
|
},
|
||||||
new GraficoInterativoSerieModel()
|
new GraficoInterativoSerieModel()
|
||||||
{
|
{
|
||||||
Titulo = "HDD %",
|
Titulo = "GPU Memory %",
|
||||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.HDD_load ?? 0)).ToList(),
|
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_memory_load_percent ?? 0)).ToList(),
|
||||||
Visivel = true,
|
Visivel = true,
|
||||||
MostrarValor = true
|
MostrarValor = true
|
||||||
},
|
},
|
||||||
new GraficoInterativoSerieModel()
|
new GraficoInterativoSerieModel()
|
||||||
{
|
{
|
||||||
Titulo = "RAM %",
|
Titulo = "GPU Frame Buffer %",
|
||||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.RAM_usage ?? 0)).ToList(),
|
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_frame_buffer_load_percent ?? 0)).ToList(),
|
||||||
Visivel = true,
|
Visivel = true,
|
||||||
MostrarValor = true
|
MostrarValor = true
|
||||||
},
|
},
|
||||||
new GraficoInterativoSerieModel()
|
new GraficoInterativoSerieModel()
|
||||||
{
|
{
|
||||||
Titulo = "CPU Temp",
|
Titulo = "GPU Video Engine %",
|
||||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.CPU_temp ?? 0)).ToList(),
|
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_video_engine_load_percent ?? 0)).ToList(),
|
||||||
Visivel = true,
|
Visivel = false,
|
||||||
MostrarValor = true
|
MostrarValor = true
|
||||||
},
|
},
|
||||||
new GraficoInterativoSerieModel()
|
new GraficoInterativoSerieModel()
|
||||||
{
|
{
|
||||||
Titulo = "GPU Temp",
|
Titulo = "GPU Bus Interface %",
|
||||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_temp ?? 0)).ToList(),
|
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_bus_interface_load_percent ?? 0)).ToList(),
|
||||||
Visivel = true,
|
Visivel = false,
|
||||||
MostrarValor = true
|
|
||||||
},
|
|
||||||
new GraficoInterativoSerieModel()
|
|
||||||
{
|
|
||||||
Titulo = "Threads Ativas",
|
|
||||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.ActiveThreads ?? 0)).ToList(),
|
|
||||||
Visivel = true,
|
|
||||||
MostrarValor = true
|
|
||||||
},
|
|
||||||
new GraficoInterativoSerieModel()
|
|
||||||
{
|
|
||||||
Titulo = "Threads de Trabalho %",
|
|
||||||
Valores = LogsOperacao.Select(x => (double)((x?.DadosPerformance.MaxWorkerThreads ?? 1) - (x?.DadosPerformance.WorkerThreads ?? 0)) / (x?.DadosPerformance.MaxWorkerThreads ?? 1) * 100.0).ToList(),
|
|
||||||
Visivel = true,
|
|
||||||
MostrarValor = true
|
|
||||||
},
|
|
||||||
new GraficoInterativoSerieModel()
|
|
||||||
{
|
|
||||||
Titulo = "Threads de Portas %",
|
|
||||||
Valores = LogsOperacao.Select(x => (double)((x?.DadosPerformance.MaxCompletionPortThreads ?? 1) - (x?.DadosPerformance.CompletionPortThreads ?? 0)) / (x?.DadosPerformance.MaxCompletionPortThreads ?? 1) * 100.0).ToList(),
|
|
||||||
Visivel = true,
|
|
||||||
MostrarValor = true
|
MostrarValor = true
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -1148,11 +1127,6 @@ namespace AgroBase.Forms.Operacoes
|
||||||
var Log = LogsOperacao[idxMomentoAtual];
|
var Log = LogsOperacao[idxMomentoAtual];
|
||||||
var LogAtu = LogsAtuador[idxMomentoAtual];
|
var LogAtu = LogsAtuador[idxMomentoAtual];
|
||||||
|
|
||||||
double herbicidaConsumido = Log.Atuador.HerbicidaConsumido != 0 ? Log.Atuador.HerbicidaConsumido : LogAtu.VolumeVazaoML;
|
|
||||||
double percentualHerbicidaConsumido = FuncoesMatematicas.Clamp(((herbicidaConsumido / 1000.0) / LogsAtuador.FirstOrDefault().VolumeReservatorio) * 100.0, 0, 100);
|
|
||||||
int totalAtuacoes = 0; // Log.Atuador.ErvasIdentificadas.Sum(dict => dict.Values.Sum());
|
|
||||||
double herbicidaPorErva = Log.Atuador.HerbicidaPorErva != 0 ? Log.Atuador.HerbicidaPorErva : (herbicidaConsumido / (totalAtuacoes > 0 ? totalAtuacoes : 1));
|
|
||||||
|
|
||||||
lblPercentualBateria.Text = $"Bateria {Log.Bateria.PercentualBateria.ToString("0.00")}%";
|
lblPercentualBateria.Text = $"Bateria {Log.Bateria.PercentualBateria.ToString("0.00")}%";
|
||||||
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualBateria, Log.Bateria.PercentualBateria);
|
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualBateria, Log.Bateria.PercentualBateria);
|
||||||
|
|
||||||
|
|
@ -1162,13 +1136,13 @@ namespace AgroBase.Forms.Operacoes
|
||||||
lblPercentualReservatorio.Text = $"Reservatório {LogAtu.PercentualReservatorio.ToString("0.00")}%";
|
lblPercentualReservatorio.Text = $"Reservatório {LogAtu.PercentualReservatorio.ToString("0.00")}%";
|
||||||
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualReservatorio, LogAtu.PercentualReservatorio);
|
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualReservatorio, LogAtu.PercentualReservatorio);
|
||||||
|
|
||||||
lblHerbicidaConsumido.Text = $"Consumido {herbicidaConsumido.ToString("0.00")} ml";
|
lblHerbicidaConsumido.Text = $"Consumido {LogAtu.PercentualHerbicidaConsumidoOperacao.ToString("0.00")} ml";
|
||||||
FuncoesGlobais.PreencheValorProgressBar(pgbHerbicidaConsumido, percentualHerbicidaConsumido);
|
FuncoesGlobais.PreencheValorProgressBar(pgbHerbicidaConsumido, LogAtu.PercentualHerbicidaConsumidoOperacao);
|
||||||
|
|
||||||
txtTempoMovimento.Text = FuncoesGlobais.ConverterSegundosParaHHmmss((int)Log.Movimentacao.TempoMovimentoSegs);
|
txtTempoMovimento.Text = FuncoesGlobais.ConverterSegundosParaHHmmss((int)Log.Movimentacao.TempoMovimentoSegs);
|
||||||
txtStatusOperacao.Text = Log.StatusOperacao.ToString();
|
txtStatusOperacao.Text = Log.StatusOperacao.ToString();
|
||||||
txtStatusCarro.Text = $"{Log.Trajetoria.StatusCarro}";
|
txtStatusCarro.Text = $"{Log.Trajetoria.StatusCarro}";
|
||||||
txtHerbicidaPorErva.Text = herbicidaPorErva.ToString("0.00") + " ml";
|
txtHerbicidaPorErva.Text = LogAtu.HerbicidaPorAtuacao.ToString("0.00") + " ml";
|
||||||
txtDentroRua.Text = Log.Trajetoria.CorredorAtual.Dentro ? "Sim" : "Não";
|
txtDentroRua.Text = Log.Trajetoria.CorredorAtual.Dentro ? "Sim" : "Não";
|
||||||
txtDirecaoCarro.Text = Log.Trajetoria.DirecaoCaminho.ToString() + " (" + Log.Trajetoria.CorredorAtual.Idx + " - " + Log.Trajetoria.ProximoPonto.idxPonto + " - " + Log.Trajetoria.ProximoPonto.idxPontoCorredor + ")";
|
txtDirecaoCarro.Text = Log.Trajetoria.DirecaoCaminho.ToString() + " (" + Log.Trajetoria.CorredorAtual.Idx + " - " + Log.Trajetoria.ProximoPonto.idxPonto + " - " + Log.Trajetoria.ProximoPonto.idxPontoCorredor + ")";
|
||||||
txtErvasNoRadar.Text = Log.Atuador.ErvasNoRadar.ToString() + " (" + (Log.Atuador.PercentualErvasNoRadar * 100).ToString("0.00") + "%)";
|
txtErvasNoRadar.Text = Log.Atuador.ErvasNoRadar.ToString() + " (" + (Log.Atuador.PercentualErvasNoRadar * 100).ToString("0.00") + "%)";
|
||||||
|
|
@ -1177,7 +1151,7 @@ namespace AgroBase.Forms.Operacoes
|
||||||
txtVelocidade.Text = (Log.Movimentacao.VelocidadeMedia * 3.6).ToString("0.00") + " km/h (" + Log.Movimentacao.VelocidadeMedia.ToString("0.00") + " m/s)";
|
txtVelocidade.Text = (Log.Movimentacao.VelocidadeMedia * 3.6).ToString("0.00") + " km/h (" + Log.Movimentacao.VelocidadeMedia.ToString("0.00") + " m/s)";
|
||||||
txtDirecaoControle.Text = (Log.Controle?.TiposControle?.FirstOrDefault(x => x.Tipo == Enums.T_Code.Dir)?.DirecaoAtual ?? Enums.Direcao.Parado).ToString() + " (" + (Log.Controle?.Latencia ?? 0).ToString("0.00") + " s)";
|
txtDirecaoControle.Text = (Log.Controle?.TiposControle?.FirstOrDefault(x => x.Tipo == Enums.T_Code.Dir)?.DirecaoAtual ?? Enums.Direcao.Parado).ToString() + " (" + (Log.Controle?.Latencia ?? 0).ToString("0.00") + " s)";
|
||||||
txtVelocidadeControle.Text = ((Log.Controle?.PercentualVelocidadeSP ?? 0) / VariaveisEquipamento.RPM_Max_Roda * 100).ToString() + " rpm";
|
txtVelocidadeControle.Text = ((Log.Controle?.PercentualVelocidadeSP ?? 0) / VariaveisEquipamento.RPM_Max_Roda * 100).ToString() + " rpm";
|
||||||
txtErvasIdentificadas.Text = $"{totalAtuacoes}";
|
txtErvasIdentificadas.Text = $"{Log.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0}";
|
||||||
|
|
||||||
txtDistanciasLaterais.Text = (Log.Trajetoria.DistanciaEsquerda * 100.0).ToString("0.00") + " cm / " + (Log.Trajetoria.DistanciaDireita * 100.0).ToString("0.00") + " cm";
|
txtDistanciasLaterais.Text = (Log.Trajetoria.DistanciaEsquerda * 100.0).ToString("0.00") + " cm / " + (Log.Trajetoria.DistanciaDireita * 100.0).ToString("0.00") + " cm";
|
||||||
txtErroLateral.Text = (Log.Controle.ErroLateral * 100.0).ToString("0.00") + " cm";
|
txtErroLateral.Text = (Log.Controle.ErroLateral * 100.0).ToString("0.00") + " cm";
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@
|
||||||
this.cmbAlgoritmo = new System.Windows.Forms.ComboBox();
|
this.cmbAlgoritmo = new System.Windows.Forms.ComboBox();
|
||||||
this.lblAlgoritmo = new System.Windows.Forms.Label();
|
this.lblAlgoritmo = new System.Windows.Forms.Label();
|
||||||
this.btnSalvarAlgoritmo = new System.Windows.Forms.Button();
|
this.btnSalvarAlgoritmo = new System.Windows.Forms.Button();
|
||||||
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.cmbDispositivo = new System.Windows.Forms.ComboBox();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.gridDados)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.gridDados)).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.picBussola)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.picBussola)).BeginInit();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
|
|
@ -218,12 +220,34 @@
|
||||||
this.btnSalvarAlgoritmo.UseVisualStyleBackColor = true;
|
this.btnSalvarAlgoritmo.UseVisualStyleBackColor = true;
|
||||||
this.btnSalvarAlgoritmo.Click += new System.EventHandler(this.btnSalvarAlgoritmo_Click);
|
this.btnSalvarAlgoritmo.Click += new System.EventHandler(this.btnSalvarAlgoritmo_Click);
|
||||||
//
|
//
|
||||||
|
// label4
|
||||||
|
//
|
||||||
|
this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.label4.AutoSize = true;
|
||||||
|
this.label4.Location = new System.Drawing.Point(575, 629);
|
||||||
|
this.label4.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
||||||
|
this.label4.Name = "label4";
|
||||||
|
this.label4.Size = new System.Drawing.Size(58, 13);
|
||||||
|
this.label4.TabIndex = 62;
|
||||||
|
this.label4.Text = "Dispositivo";
|
||||||
|
//
|
||||||
|
// cmbDispositivo
|
||||||
|
//
|
||||||
|
this.cmbDispositivo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.cmbDispositivo.FormattingEnabled = true;
|
||||||
|
this.cmbDispositivo.Location = new System.Drawing.Point(638, 625);
|
||||||
|
this.cmbDispositivo.Name = "cmbDispositivo";
|
||||||
|
this.cmbDispositivo.Size = new System.Drawing.Size(121, 21);
|
||||||
|
this.cmbDispositivo.TabIndex = 61;
|
||||||
|
//
|
||||||
// frmWT901C
|
// frmWT901C
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.BackColor = System.Drawing.Color.White;
|
this.BackColor = System.Drawing.Color.White;
|
||||||
this.ClientSize = new System.Drawing.Size(1088, 660);
|
this.ClientSize = new System.Drawing.Size(1088, 660);
|
||||||
|
this.Controls.Add(this.label4);
|
||||||
|
this.Controls.Add(this.cmbDispositivo);
|
||||||
this.Controls.Add(this.btnSalvarAlgoritmo);
|
this.Controls.Add(this.btnSalvarAlgoritmo);
|
||||||
this.Controls.Add(this.lblAlgoritmo);
|
this.Controls.Add(this.lblAlgoritmo);
|
||||||
this.Controls.Add(this.cmbAlgoritmo);
|
this.Controls.Add(this.cmbAlgoritmo);
|
||||||
|
|
@ -270,5 +294,7 @@
|
||||||
private System.Windows.Forms.ComboBox cmbAlgoritmo;
|
private System.Windows.Forms.ComboBox cmbAlgoritmo;
|
||||||
private System.Windows.Forms.Label lblAlgoritmo;
|
private System.Windows.Forms.Label lblAlgoritmo;
|
||||||
private System.Windows.Forms.Button btnSalvarAlgoritmo;
|
private System.Windows.Forms.Button btnSalvarAlgoritmo;
|
||||||
|
private System.Windows.Forms.Label label4;
|
||||||
|
private System.Windows.Forms.ComboBox cmbDispositivo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,6 +6,9 @@ using System.Windows.Forms;
|
||||||
using System.Drawing.Drawing2D;
|
using System.Drawing.Drawing2D;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using AgroBase.Services.Operadores;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AgroBase.Models.Operadores;
|
||||||
|
|
||||||
namespace AgroBase.Forms
|
namespace AgroBase.Forms
|
||||||
{
|
{
|
||||||
|
|
@ -17,6 +20,7 @@ namespace AgroBase.Forms
|
||||||
double AnguloZ = 0;
|
double AnguloZ = 0;
|
||||||
private Visualizador3DService visualizador3D;
|
private Visualizador3DService visualizador3D;
|
||||||
AsyncTaskTimerModel tmrLeitura;
|
AsyncTaskTimerModel tmrLeitura;
|
||||||
|
List<CameraWorkerItemModel> ListaCameras = new List<CameraWorkerItemModel>();
|
||||||
//WT901C485 WT901C = Variaveis.WT901C;
|
//WT901C485 WT901C = Variaveis.WT901C;
|
||||||
|
|
||||||
public frmWT901C()
|
public frmWT901C()
|
||||||
|
|
@ -50,6 +54,8 @@ namespace AgroBase.Forms
|
||||||
|
|
||||||
cmbAlgoritmo.Items.Clear();
|
cmbAlgoritmo.Items.Clear();
|
||||||
cmbAlgoritmo.Items.AddRange(new string[] { "6 Eixos", "9 Eixos" });
|
cmbAlgoritmo.Items.AddRange(new string[] { "6 Eixos", "9 Eixos" });
|
||||||
|
|
||||||
|
AtualizarListaCameras();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void frmWT901C_FormClosing(object sender, FormClosingEventArgs e)
|
private void frmWT901C_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
|
|
@ -59,7 +65,24 @@ namespace AgroBase.Forms
|
||||||
|
|
||||||
private async Task tmrLeitura_Tick()
|
private async Task tmrLeitura_Tick()
|
||||||
{
|
{
|
||||||
var Imu = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU;
|
if (cmbDispositivo.SelectedIndex < 0 || cmbDispositivo.SelectedIndex >= ListaCameras.Count) return;
|
||||||
|
|
||||||
|
var Camera = ListaCameras[cmbDispositivo.SelectedIndex];
|
||||||
|
if (Camera.imu == null) return;
|
||||||
|
|
||||||
|
if (Camera.mx_id == Variaveis.OperacaoEmAndamento.DispSen?.Dados?.CameraCaminho?.Id)
|
||||||
|
Camera.imu = Variaveis.OperacaoEmAndamento.DispSen.Dados?.CameraCaminho?.cam?.imu;
|
||||||
|
else if (Variaveis.OperacaoEmAndamento.DispSen.Dados?.CamerasSolo?.Any(x => x?.Id == Camera.mx_id) ?? false)
|
||||||
|
Camera.imu = Variaveis.OperacaoEmAndamento.DispSen.Dados?.CamerasSolo?.FirstOrDefault(x => x?.Id == Camera.mx_id)?.cam?.imu;
|
||||||
|
|
||||||
|
//OperacaoSensoriamentoLogImuModel Imu = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU;
|
||||||
|
OperacaoSensoriamentoLogImuModel Imu = new OperacaoSensoriamentoLogImuModel()
|
||||||
|
{
|
||||||
|
InclinacaoFrontal = Camera.imu.pitch,
|
||||||
|
InclinacaoLateral = Camera.imu.roll,
|
||||||
|
Rotacao = Camera.imu.yaw,
|
||||||
|
RotacaoCorrigida = Camera.imu.yaw,
|
||||||
|
};
|
||||||
AnguloX = Imu.InclinacaoFrontal;
|
AnguloX = Imu.InclinacaoFrontal;
|
||||||
AnguloY = Imu.InclinacaoLateral;
|
AnguloY = Imu.InclinacaoLateral;
|
||||||
AnguloZ = Imu.Rotacao;
|
AnguloZ = Imu.Rotacao;
|
||||||
|
|
@ -68,6 +91,13 @@ namespace AgroBase.Forms
|
||||||
AtualizarDadosTela();
|
AtualizarDadosTela();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AtualizarListaCameras()
|
||||||
|
{
|
||||||
|
ListaCameras = CameraWorkerService.GetListaCameras();
|
||||||
|
cmbDispositivo.Items.Clear();
|
||||||
|
cmbDispositivo.Items.AddRange(ListaCameras.Select(x => x.modelo).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
private void PopularDadosGrid()
|
private void PopularDadosGrid()
|
||||||
{
|
{
|
||||||
gridDados.Rows.Clear();
|
gridDados.Rows.Clear();
|
||||||
|
|
@ -371,6 +401,5 @@ namespace AgroBase.Forms
|
||||||
{
|
{
|
||||||
await WT901CService.AlterarAlgoritmo(cmbAlgoritmo.SelectedIndex == 1);
|
await WT901CService.AlterarAlgoritmo(cmbAlgoritmo.SelectedIndex == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,133 +86,143 @@ namespace AgroBase.Models.Modules
|
||||||
public HerbicideCounterService ContadorCarga = new HerbicideCounterService(VariaveisEquipamento.CapacidadeReservatorio, VariaveisEquipamento.DensidadeHerbicida);
|
public HerbicideCounterService ContadorCarga = new HerbicideCounterService(VariaveisEquipamento.CapacidadeReservatorio, VariaveisEquipamento.DensidadeHerbicida);
|
||||||
|
|
||||||
#region VAZAO
|
#region VAZAO
|
||||||
|
|
||||||
private SensorModel SensorFluxoLinha => Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX && x.ID == "FLXLN");
|
private SensorModel SensorFluxoLinha => Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX && x.ID == "FLXLN");
|
||||||
|
|
||||||
public double VolumeVazaoAferido { get; set; } = 0;
|
public double VolumeVazaoAferido { get; set; } = 0;
|
||||||
public double _FluxoMlRef { get; set; } = 600;
|
|
||||||
public double _FluxoPulsoRef { get; set; } = 538;
|
public double VazaoMaximaSensor_LMin { get; set; } = 20.0;
|
||||||
|
|
||||||
public double VazaoFluxoMLpSInstantanea => SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Fluxo)?.atual?.valor ?? 0;
|
public double VazaoFluxoMLpSInstantanea => SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Fluxo)?.atual?.valor ?? 0;
|
||||||
|
|
||||||
public double VazaoFluxoMLpSInstantaneaCalc
|
public double VazaoFluxoMLpSInstantaneaCalc
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int pulsos = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.QtdPulsos)?.atual?.valor ?? 0.0);
|
int pulsos = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.QtdPulsos)?.atual?.valor ?? 0.0);
|
||||||
|
|
||||||
int periodo = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Periodo)?.atual?.valor ?? 0.0);
|
int periodo = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Periodo)?.atual?.valor ?? 0.0);
|
||||||
if (pulsos <= 0 || periodo <= 0) return 0.0;
|
|
||||||
|
|
||||||
double frequencia = (double)pulsos / (double)periodo * 1000.0; // Hz
|
if (pulsos <= 0 || periodo <= 0)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
// Equação do fabricante: F = 8.1*q - 3 (q em L/min)
|
double frequencia = (double)pulsos / periodo * 1000.0;
|
||||||
|
|
||||||
|
// Fabricante: F = 8.1*q - 3, q em L/min
|
||||||
double q_L_min = (frequencia + 3.0) / 8.1;
|
double q_L_min = (frequencia + 3.0) / 8.1;
|
||||||
// Limites físicos do sensor (do próprio anúncio): 0.3–10 L/min
|
|
||||||
if (q_L_min < 0) q_L_min = 0; // evita negativo perto do zero
|
if (q_L_min < 0)
|
||||||
if (q_L_min > 10.0) q_L_min = 10.0; // opcional: clamp no máximo
|
q_L_min = 0;
|
||||||
// Converte para mL/s
|
|
||||||
double q_mL_s = q_L_min * (1000.0 / 60.0);
|
if (q_L_min > VazaoMaximaSensor_LMin)
|
||||||
return q_mL_s;
|
q_L_min = VazaoMaximaSensor_LMin;
|
||||||
|
|
||||||
|
return q_L_min * 1000.0 / 60.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private DateTime _ultimoRegistroVazao; // Armazena o horário da última atualização
|
|
||||||
|
public double VazaoFluxoMLpSReferencia
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
double direta = VazaoFluxoMLpSInstantanea;
|
||||||
|
|
||||||
|
if (direta > 0)
|
||||||
|
return direta;
|
||||||
|
|
||||||
|
return VazaoFluxoMLpSInstantaneaCalc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime _ultimoRegistroVazao = DateTime.MinValue;
|
||||||
|
|
||||||
public double VazaoMediaMLs { get; set; }
|
public double VazaoMediaMLs { get; set; }
|
||||||
public double VolumeVazadoML { get; set; }
|
public double VolumeVazadoML { get; set; }
|
||||||
public double TempoAtuado { get; set; }
|
public double TempoAtuado { get; set; }
|
||||||
private List<AtuadorBicoModel> bicosAtivosAnterior;
|
|
||||||
|
private List<AtuadorBicoModel> bicosAtivosAnterior = new List<AtuadorBicoModel>();
|
||||||
|
|
||||||
public void AtualizaTempoAtuadoGeral()
|
public void AtualizaTempoAtuadoGeral()
|
||||||
{
|
{
|
||||||
DateTime agora = DateTime.Now;
|
DateTime agora = DateTime.Now;
|
||||||
|
|
||||||
// Quem está ativo AGORA
|
var bicosAtivos = BicosPulverizadores.Where(x => x.Inicializado && x.ComandoAtuar).ToList();
|
||||||
var bicosAtivos = BicosPulverizadores.Where(x => x.Inicializado && x._EstadoLeitura == Estado.Ligado).ToList();
|
|
||||||
|
|
||||||
bool algumBicoAtivo = bicosAtivos.Count > 0;
|
bool algumBicoAtivo = bicosAtivos.Count > 0;
|
||||||
|
|
||||||
bool algumBicoAtivoAnterior = bicosAtivosAnterior?.Any() ?? false;
|
bool algumBicoAtivoAnterior = bicosAtivosAnterior?.Any() ?? false;
|
||||||
|
|
||||||
// Início de uma "sessão" (transição OFF -> ON)
|
|
||||||
if (algumBicoAtivo && !algumBicoAtivoAnterior)
|
if (algumBicoAtivo && !algumBicoAtivoAnterior)
|
||||||
{
|
_ultimoRegistroVazao = agora;
|
||||||
_ultimoRegistroVazao = agora; // inicia integração a partir daqui
|
|
||||||
|
|
||||||
// (opcional) se você quer métricas por sessão, zere volumes/médias aqui
|
|
||||||
// foreach (var b in BicosPulverizadores) { b.VolumeVazadoML = 0; b.VazaoMediaMLs = 0; }
|
|
||||||
// _tempoAtuadoBicoSeg.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fim de sessão (transição ON -> OFF)
|
|
||||||
if (!algumBicoAtivo && algumBicoAtivoAnterior)
|
if (!algumBicoAtivo && algumBicoAtivoAnterior)
|
||||||
{
|
{
|
||||||
AtualizaVazaoEVolume(bicosAtivosAnterior, agora);
|
AtualizaVazaoEVolume(bicosAtivosAnterior, agora);
|
||||||
|
|
||||||
_ultimoRegistroVazao = DateTime.MinValue;
|
_ultimoRegistroVazao = DateTime.MinValue;
|
||||||
VazaoMediaMLs = TempoAtuado > 0 ? (VolumeVazadoML / TempoAtuado) : 0;
|
|
||||||
|
|
||||||
// zera instantânea quando não tem bico ativo
|
|
||||||
foreach (var b in BicosPulverizadores)
|
foreach (var b in BicosPulverizadores)
|
||||||
b.VazaoInstantaneaMLs = 0;
|
b.VazaoInstantaneaMLs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Integra vazão/volume enquanto tiver bico ativo
|
if (algumBicoAtivo)
|
||||||
AtualizaVazaoEVolume(bicosAtivos, agora);
|
AtualizaVazaoEVolume(bicosAtivos, agora);
|
||||||
|
|
||||||
// Atualiza indicadores
|
VazaoMediaMLs = TempoAtuado > 0 ? VolumeVazadoML / TempoAtuado : 0;
|
||||||
|
|
||||||
AtualizaPercentualErvas();
|
AtualizaPercentualErvas();
|
||||||
|
|
||||||
bicosAtivosAnterior = new List<AtuadorBicoModel>(bicosAtivos);
|
bicosAtivosAnterior = new List<AtuadorBicoModel>(bicosAtivos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AtualizaVazaoEVolume(List<AtuadorBicoModel> bicosAtivos, DateTime agora)
|
private void AtualizaVazaoEVolume(List<AtuadorBicoModel> bicosAtivos, DateTime agora)
|
||||||
{
|
{
|
||||||
// Só integra se houver bicos ativos
|
|
||||||
if (bicosAtivos == null || bicosAtivos.Count == 0)
|
if (bicosAtivos == null || bicosAtivos.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Captura vazão total instantânea (ml/s)
|
if (_ultimoRegistroVazao == DateTime.MinValue)
|
||||||
double vazaoTotalInst = VazaoFluxoMLpSInstantanea;
|
{
|
||||||
|
_ultimoRegistroVazao = agora;
|
||||||
if (_ultimoRegistroVazao == default || _ultimoRegistroVazao == DateTime.MinValue)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// dt em segundos
|
|
||||||
double dt = (agora - _ultimoRegistroVazao).TotalSeconds;
|
double dt = (agora - _ultimoRegistroVazao).TotalSeconds;
|
||||||
_ultimoRegistroVazao = agora;
|
_ultimoRegistroVazao = agora;
|
||||||
|
|
||||||
if (dt <= 0) return;
|
if (dt <= 0 || dt > 2.0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double vazaoTotalInst = VazaoFluxoMLpSReferencia;
|
||||||
|
|
||||||
|
if (vazaoTotalInst <= 0)
|
||||||
|
{
|
||||||
|
foreach (var bico in bicosAtivos)
|
||||||
|
bico.VazaoInstantaneaMLs = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ======== GERAL ========
|
|
||||||
VolumeVazadoML += vazaoTotalInst * dt;
|
VolumeVazadoML += vazaoTotalInst * dt;
|
||||||
TempoAtuado += dt;
|
TempoAtuado += dt;
|
||||||
VazaoMediaMLs = TempoAtuado > 0 ? (VolumeVazadoML / TempoAtuado) : 0;
|
|
||||||
|
|
||||||
// ======== POR BICO (divide por ativos) ========
|
|
||||||
double vazaoPorBicoInst = vazaoTotalInst / bicosAtivos.Count;
|
double vazaoPorBicoInst = vazaoTotalInst / bicosAtivos.Count;
|
||||||
|
|
||||||
foreach (var bico in bicosAtivos)
|
foreach (var bico in bicosAtivos)
|
||||||
{
|
{
|
||||||
// Instantânea por bico
|
|
||||||
bico.VazaoInstantaneaMLs = vazaoPorBicoInst;
|
bico.VazaoInstantaneaMLs = vazaoPorBicoInst;
|
||||||
|
|
||||||
// Volume por bico (ml) = (ml/s) * s
|
|
||||||
bico.VolumeVazadoML += vazaoPorBicoInst * dt;
|
bico.VolumeVazadoML += vazaoPorBicoInst * dt;
|
||||||
|
|
||||||
bico.TempoAtuado += dt;
|
bico.TempoAtuado += dt;
|
||||||
|
|
||||||
bico.VazaoMediaMLs = bico.TempoAtuado > 0 ? (bico.VolumeVazadoML / bico.TempoAtuado) : 0;
|
bico.VazaoMediaMLs = bico.TempoAtuado > 0
|
||||||
|
? bico.VolumeVazadoML / bico.TempoAtuado
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AtualizaPercentualErvas()
|
private void AtualizaPercentualErvas()
|
||||||
{
|
{
|
||||||
//double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento.TempoDecorridoSeg * 1000.0;
|
double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.TempoMovimentoSegs ?? 0;
|
||||||
double tempoTotalOperacao = (Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.TempoMovimentoSegs ?? 0) * 1000.0;
|
PercentualErvasTerreno = tempoTotalOperacao > 0 ? Math.Round((TempoAtuado / tempoTotalOperacao) * 100.0, 2) : 0;
|
||||||
|
|
||||||
if (tempoTotalOperacao > 0)
|
|
||||||
{
|
|
||||||
var percentual = Math.Round((TempoAtuado / tempoTotalOperacao) * 100.0, 2);
|
|
||||||
PercentualErvasTerreno = percentual;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
PercentualErvasTerreno = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using System.Data;
|
||||||
using static AgroBase.Services.LoRaEspService;
|
using static AgroBase.Services.LoRaEspService;
|
||||||
using AgroBase.Services.Operadores;
|
using AgroBase.Services.Operadores;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using AgroBase.Models.Operadores;
|
||||||
|
|
||||||
namespace AgroBase.Models.Modules
|
namespace AgroBase.Models.Modules
|
||||||
{
|
{
|
||||||
|
|
@ -86,7 +87,7 @@ namespace AgroBase.Models.Modules
|
||||||
_TaxaAmostragem = 1000,
|
_TaxaAmostragem = 1000,
|
||||||
RequisitarDados = true,
|
RequisitarDados = true,
|
||||||
CameraCaminho = new OAKCameraModel(),
|
CameraCaminho = new OAKCameraModel(),
|
||||||
CamerasSolo = new List<OAKCameraModel>(),
|
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo ?? VariaveisEquipamento.QuantidadeCamerasSolo),
|
||||||
// 21 ~ 23
|
// 21 ~ 23
|
||||||
Sinaleiros = new List<SensorSinaleiroModel>()
|
Sinaleiros = new List<SensorSinaleiroModel>()
|
||||||
{
|
{
|
||||||
|
|
@ -2034,11 +2035,6 @@ namespace AgroBase.Models.Modules
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
|
|
||||||
{
|
|
||||||
obj.CamerasSolo.Add(new OAKCameraModel());
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2408,6 +2404,24 @@ namespace AgroBase.Models.Modules
|
||||||
Sinaleiros.First(x => x.ID == "LEDOP").Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Piscando, status_operacao: _statusOperacao);
|
Sinaleiros.First(x => x.ID == "LEDOP").Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Piscando, status_operacao: _statusOperacao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AtualizarDadosCameras()
|
||||||
|
{
|
||||||
|
if (CameraCaminho?.Id != null)
|
||||||
|
{
|
||||||
|
var att = CameraWorkerService.AtualizarDadosCamera(CameraCaminho.Id);
|
||||||
|
if (att != null) CameraCaminho = att;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < CamerasSolo?.Count; i++)
|
||||||
|
{
|
||||||
|
if (CamerasSolo[i]?.Id != null)
|
||||||
|
{
|
||||||
|
var att = CameraWorkerService.AtualizarDadosCamera(CamerasSolo[i].Id);
|
||||||
|
if (att != null) CamerasSolo[i] = att;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SensorModel
|
public class SensorModel
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ namespace AgroBase.Models
|
||||||
public double fx { get; set; }
|
public double fx { get; set; }
|
||||||
public double baseline { get; set; }
|
public double baseline { get; set; }
|
||||||
|
|
||||||
|
public CameraWorkerItemModel cam { get; set; }
|
||||||
|
|
||||||
public double DistanciaMaximaVisao { get; set; } = 5000;
|
public double DistanciaMaximaVisao { get; set; } = 5000;
|
||||||
public double DistanciaMinimaVisao { get; set; } = 500;
|
public double DistanciaMinimaVisao { get; set; } = 500;
|
||||||
public double PercentualAlturaSolo { get; set; } = 30;
|
public double PercentualAlturaSolo { get; set; } = 30;
|
||||||
|
|
@ -100,6 +102,7 @@ namespace AgroBase.Models
|
||||||
Version = Version,
|
Version = Version,
|
||||||
fx = fx,
|
fx = fx,
|
||||||
baseline = baseline,
|
baseline = baseline,
|
||||||
|
cam = cam,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,6 +170,12 @@ namespace AgroBase.Models
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OAKImuModel
|
public class OAKImuModel
|
||||||
|
{
|
||||||
|
public OAKImuDataModel dados { get; set; }
|
||||||
|
public ManagerWorkerMessageResponseModulosPendentesModel saude { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OAKImuDataModel
|
||||||
{
|
{
|
||||||
public double timestamp { get; set; }
|
public double timestamp { get; set; }
|
||||||
public double roll { get; set; }
|
public double roll { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -1197,7 +1197,12 @@ namespace AgroBase.Models
|
||||||
|
|
||||||
Controle.Reiniciar();
|
Controle.Reiniciar();
|
||||||
ControleAnterior.Reiniciar();
|
ControleAnterior.Reiniciar();
|
||||||
DispSen?.Dados?.ContadorCarga?.IniciarOperacao();
|
|
||||||
|
double distanciaPercorrida = DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0;
|
||||||
|
double tempoAtuado = DispAtu?.Dados?.TempoAtuado ?? 0;
|
||||||
|
DispSen?.Dados?.ContadorCarga?.AtualizarConsumo(distanciaPercorrida);
|
||||||
|
DispSen?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida);
|
||||||
|
DispAtu?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida, tempoAtuado);
|
||||||
|
|
||||||
GPSTrajetoria = new List<GPSModel>();
|
GPSTrajetoria = new List<GPSModel>();
|
||||||
|
|
||||||
|
|
@ -1234,6 +1239,7 @@ namespace AgroBase.Models
|
||||||
Variaveis.OperacaoEmAndamento.Finalizando = false;
|
Variaveis.OperacaoEmAndamento.Finalizando = false;
|
||||||
Variaveis.OperacaoEmAndamento.Trajetoria?.AutonomiaCorredor?.Parar();
|
Variaveis.OperacaoEmAndamento.Trajetoria?.AutonomiaCorredor?.Parar();
|
||||||
Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.FinalizarOperacao();
|
Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.FinalizarOperacao();
|
||||||
|
Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.ContadorCarga?.FinalizarOperacao();
|
||||||
|
|
||||||
if (Variaveis.OperacaoEmAndamento.Parametros.Modo == ModoOperacao.RetornoBase)
|
if (Variaveis.OperacaoEmAndamento.Parametros.Modo == ModoOperacao.RetornoBase)
|
||||||
{
|
{
|
||||||
|
|
@ -2026,6 +2032,9 @@ namespace AgroBase.Models
|
||||||
MassaReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.MassaAtual_Kg,
|
MassaReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.MassaAtual_Kg,
|
||||||
PercentualReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualAtual,
|
PercentualReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualAtual,
|
||||||
VolumeReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.VolumeAtual_L,
|
VolumeReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.VolumeAtual_L,
|
||||||
|
PercentualHerbicidaConsumido = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualConsumidoTotal,
|
||||||
|
PercentualHerbicidaConsumidoOperacao = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualConsumidoOperacao,
|
||||||
|
HerbicidaPorAtuacao = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.HerbicidaPorAtuacao_L,
|
||||||
PressaoLinha_SP = Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha,
|
PressaoLinha_SP = Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha,
|
||||||
PressaoLinha = Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha,
|
PressaoLinha = Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha,
|
||||||
PotenciaBomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?._Potencia ?? 0,
|
PotenciaBomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?._Potencia ?? 0,
|
||||||
|
|
@ -2689,16 +2698,17 @@ namespace AgroBase.Models
|
||||||
double tmp_max = Math.Max(Variaveis.OperacaoEmAndamento.DadosPerformance?.GPU_temp ?? 0, Variaveis.OperacaoEmAndamento.DadosPerformance?.CPU_temp ?? 0);
|
double tmp_max = Math.Max(Variaveis.OperacaoEmAndamento.DadosPerformance?.GPU_temp ?? 0, Variaveis.OperacaoEmAndamento.DadosPerformance?.CPU_temp ?? 0);
|
||||||
_DispMvd?.Dados?.AtualizarDadosFreio();
|
_DispMvd?.Dados?.AtualizarDadosFreio();
|
||||||
_DispSen?.Dados?.AtualizarStatusSinaleiros(Variaveis.OperacaoEmAndamento.Parametros?.Modo ?? ModoOperacao.NaoDefinido, Variaveis.OperacaoEmAndamento.StatusAtual);
|
_DispSen?.Dados?.AtualizarStatusSinaleiros(Variaveis.OperacaoEmAndamento.Parametros?.Modo ?? ModoOperacao.NaoDefinido, Variaveis.OperacaoEmAndamento.StatusAtual);
|
||||||
|
_DispSen?.Dados?.AtualizarDadosCameras();
|
||||||
_DispAtu?.Dados?.AtualizaTempoAtuadoGeral();
|
_DispAtu?.Dados?.AtualizaTempoAtuadoGeral();
|
||||||
_Cooler?.Atualizar(tmp_max, DateTime.Now);
|
_Cooler?.Atualizar(tmp_max, DateTime.Now);
|
||||||
_Bateria?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0);
|
_Bateria?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0);
|
||||||
_Reservatorio?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0, Variaveis.OperacaoEmAndamento.TempoDecorridoSegs);
|
_Reservatorio?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0, Variaveis.OperacaoEmAndamento.TempoDecorridoSegs, _DispMvd?.Dados?.VelocidadeMedia ?? 0);
|
||||||
_Reservatorio?.AtualizarAgitadorCalda(pControle?.AtuAgitadorModo ?? ModoAgitadorCalda.SemAgitacao);
|
_Reservatorio?.AtualizarAgitadorCalda(pControle?.AtuAgitadorModo ?? ModoAgitadorCalda.SemAgitacao);
|
||||||
_Trajetoria?.AtualizarDadosAutonomiaCorredor();
|
_Trajetoria?.AtualizarDadosAutonomiaCorredor();
|
||||||
|
|
||||||
//var sIMU = LivoxManagerProcess.DadosLeitura.imu;
|
//var sIMU = LivoxManagerProcess.DadosLeitura.imu;
|
||||||
string imu = RedisService.Get(RedisService.ModKey(T_Code.Imu)) ?? "";
|
string imu = RedisService.Get(RedisService.ModKey(T_Code.Imu)) ?? "";
|
||||||
var sIMU = JsonConvert.DeserializeObject<OAKImuModel>(imu);
|
var sIMU = JsonConvert.DeserializeObject<OAKImuDataModel>(imu);
|
||||||
bool imu_iniciado = sIMU?.timestamp > 0 && HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Imu)?.status != StatusModulo.Desconectado;
|
bool imu_iniciado = sIMU?.timestamp > 0 && HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Imu)?.status != StatusModulo.Desconectado;
|
||||||
var dadosIMU = sIMU != null ? new OperacaoSensoriamentoLogImuModel()
|
var dadosIMU = sIMU != null ? new OperacaoSensoriamentoLogImuModel()
|
||||||
{
|
{
|
||||||
|
|
@ -2719,9 +2729,12 @@ namespace AgroBase.Models
|
||||||
{
|
{
|
||||||
QtdCamerasSolo = _DispSen.Dados.CamerasSolo.Count,
|
QtdCamerasSolo = _DispSen.Dados.CamerasSolo.Count,
|
||||||
CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio,
|
CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio,
|
||||||
HerbicidaConsumido = _DispAtu.Dados.VolumeVazadoML,
|
HerbicidaConsumido = _Reservatorio.VolumeConsumidoTotal_L,
|
||||||
|
HerbicidaConsumidoOperacao = _Reservatorio.VolumeConsumidoOperacao_L,
|
||||||
|
PercentualHerbicidaConsumido = _Reservatorio.PercentualConsumidoTotal,
|
||||||
|
PercentualHerbicidaConsumidoOperacao = _Reservatorio.PercentualConsumidoOperacao,
|
||||||
PercentualErvasTerreno = _DispAtu.Dados.PercentualErvasTerreno,
|
PercentualErvasTerreno = _DispAtu.Dados.PercentualErvasTerreno,
|
||||||
HerbicidaPorErva = _Reservatorio.HerbicidaPorAtuacao,
|
HerbicidaPorErva = _Reservatorio.HerbicidaPorAtuacao_L,
|
||||||
ErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.ervas_no_radar ?? false,
|
ErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.ervas_no_radar ?? false,
|
||||||
PercentualErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.estatisticas?.erva?.ema_global ?? 0,
|
PercentualErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.estatisticas?.erva?.ema_global ?? 0,
|
||||||
PercentualReservatorio = _Reservatorio.PercentualAtual,
|
PercentualReservatorio = _Reservatorio.PercentualAtual,
|
||||||
|
|
@ -3029,6 +3042,9 @@ namespace AgroBase.Models
|
||||||
public int QtdCamerasSolo { get; set; }
|
public int QtdCamerasSolo { get; set; }
|
||||||
public double CapacidadeReservatorio { get; set; }
|
public double CapacidadeReservatorio { get; set; }
|
||||||
public double HerbicidaConsumido { get; set; }
|
public double HerbicidaConsumido { get; set; }
|
||||||
|
public double HerbicidaConsumidoOperacao { get; set; }
|
||||||
|
public double PercentualHerbicidaConsumido { get; set; }
|
||||||
|
public double PercentualHerbicidaConsumidoOperacao { get; set; }
|
||||||
public double PercentualErvasTerreno { get; set; }
|
public double PercentualErvasTerreno { get; set; }
|
||||||
public double HerbicidaPorErva { get; set; }
|
public double HerbicidaPorErva { get; set; }
|
||||||
public bool ErvasNoRadar { get; set; }
|
public bool ErvasNoRadar { get; set; }
|
||||||
|
|
@ -3066,6 +3082,9 @@ namespace AgroBase.Models
|
||||||
ErvasNoRadar = ErvasNoRadar,
|
ErvasNoRadar = ErvasNoRadar,
|
||||||
PercentualErvasNoRadar = PercentualErvasNoRadar,
|
PercentualErvasNoRadar = PercentualErvasNoRadar,
|
||||||
HerbicidaConsumido = HerbicidaConsumido,
|
HerbicidaConsumido = HerbicidaConsumido,
|
||||||
|
HerbicidaConsumidoOperacao = HerbicidaConsumidoOperacao,
|
||||||
|
PercentualHerbicidaConsumido = PercentualHerbicidaConsumido,
|
||||||
|
PercentualHerbicidaConsumidoOperacao = PercentualHerbicidaConsumidoOperacao,
|
||||||
HerbicidaPorErva = HerbicidaPorErva,
|
HerbicidaPorErva = HerbicidaPorErva,
|
||||||
PercentualErvasTerreno = PercentualErvasTerreno,
|
PercentualErvasTerreno = PercentualErvasTerreno,
|
||||||
PercentualReservatorio = PercentualReservatorio,
|
PercentualReservatorio = PercentualReservatorio,
|
||||||
|
|
@ -3352,6 +3371,9 @@ namespace AgroBase.Models
|
||||||
public double PressaoLinha { get; set; }
|
public double PressaoLinha { get; set; }
|
||||||
public double VolumeReservatorio { get; set; }
|
public double VolumeReservatorio { get; set; }
|
||||||
public double PercentualReservatorio { get; set; }
|
public double PercentualReservatorio { get; set; }
|
||||||
|
public double PercentualHerbicidaConsumido { get; set; }
|
||||||
|
public double PercentualHerbicidaConsumidoOperacao { get; set; }
|
||||||
|
public double HerbicidaPorAtuacao { get; set; }
|
||||||
public double PotenciaBomba { get; set; }
|
public double PotenciaBomba { get; set; }
|
||||||
public bool BombaLigada { get; set; }
|
public bool BombaLigada { get; set; }
|
||||||
public double VazaoFluxoMLpSInstantanea { get; set; }
|
public double VazaoFluxoMLpSInstantanea { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,19 @@ namespace AgroBase.Models.Operadores
|
||||||
|
|
||||||
public SaudeWorkerModel saude { get; set; }
|
public SaudeWorkerModel saude { get; set; }
|
||||||
public CameraWorkerItemPerformanceModel performance { get; set; }
|
public CameraWorkerItemPerformanceModel performance { get; set; }
|
||||||
|
public OAKImuDataModel imu { get; set; }
|
||||||
|
|
||||||
|
public OAKCameraModel ToOAK()
|
||||||
|
{
|
||||||
|
return new OAKCameraModel()
|
||||||
|
{
|
||||||
|
Id = mx_id,
|
||||||
|
Dispositivo = dispositivo,
|
||||||
|
Version = versao,
|
||||||
|
Name = modelo,
|
||||||
|
cam = this
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CameraWorkerItemPerformanceModel
|
public class CameraWorkerItemPerformanceModel
|
||||||
|
|
|
||||||
|
|
@ -592,10 +592,15 @@ namespace AgroBase.Models.Operadores
|
||||||
|
|
||||||
public class VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel
|
public class VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel
|
||||||
{
|
{
|
||||||
public double nav_global { get; set; }
|
public string origem_status { get; set; }
|
||||||
public double nav_near { get; set; }
|
public StatusCarroMapa status_modelo { get; set; }
|
||||||
public double nav_mid { get; set; }
|
public string status_modelo_nome { get; set; }
|
||||||
public double nav_far { get; set; }
|
public string status_modelo_label_name { get; set; }
|
||||||
|
public double status_modelo_conf { get; set; }
|
||||||
|
public dynamic status_modelo_probs { get; set; }
|
||||||
|
public StatusCarroMapa status_heuristico { get; set; }
|
||||||
|
public string status_heuristico_nome { get; set; }
|
||||||
|
public dynamic heuristica_debug { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VisualWorkerMessageMatrizConfiancaModel
|
public class VisualWorkerMessageMatrizConfiancaModel
|
||||||
|
|
|
||||||
|
|
@ -1,176 +1,778 @@
|
||||||
using OpenHardwareMonitor.Hardware;
|
using OpenHardwareMonitor.Hardware;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Threading;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace AgroBase.Models
|
namespace AgroBase.Models
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Snapshot rico de performance do PC.
|
||||||
|
///
|
||||||
|
/// Objetivo:
|
||||||
|
/// - telemetria em tempo real;
|
||||||
|
/// - replay de operação;
|
||||||
|
/// - diagnóstico do health_worker;
|
||||||
|
/// - correlação com performance dos workers Python.
|
||||||
|
///
|
||||||
|
/// Observação:
|
||||||
|
/// - Disk_used_space_percent representa espaço usado, não atividade do disco.
|
||||||
|
/// - GPU_load_percent é um agregado dos principais sensores de load disponíveis.
|
||||||
|
/// </summary>
|
||||||
public class PerformanceModel
|
public class PerformanceModel
|
||||||
{
|
{
|
||||||
|
private static readonly object ComputerLock = new object();
|
||||||
private static Computer computer;
|
private static Computer computer;
|
||||||
|
|
||||||
|
private DateTime _ultimaLeituraPerformance = DateTime.MinValue;
|
||||||
|
|
||||||
public PerformanceModel()
|
public PerformanceModel()
|
||||||
{
|
{
|
||||||
if (computer == null)
|
InicializarComputer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Identificação / tempo
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
public DateTime Timestamp { get; set; } = DateTime.Now;
|
||||||
|
public long TimestampUnixMs { get; set; }
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// CPU
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
public float? CPU_load_percent { get; set; }
|
||||||
|
public float? CPU_temp_package_c { get; set; }
|
||||||
|
public float? CPU_power_package_w { get; set; }
|
||||||
|
public float? CPU_power_cores_w { get; set; }
|
||||||
|
public float? CPU_power_graphics_w { get; set; }
|
||||||
|
public float? CPU_power_dram_w { get; set; }
|
||||||
|
|
||||||
|
public float? CPU_clock_avg_mhz { get; set; }
|
||||||
|
public float? CPU_clock_max_mhz { get; set; }
|
||||||
|
public float? CPU_bus_speed_mhz { get; set; }
|
||||||
|
|
||||||
|
// Compatibilidade conceitual, se você quiser usar nomes antigos depois.
|
||||||
|
public float? CPU_load => CPU_load_percent;
|
||||||
|
public float? CPU_temp => CPU_temp_package_c;
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// RAM
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
public float? RAM_usage_percent { get; set; }
|
||||||
|
public float? RAM_used_gb { get; set; }
|
||||||
|
public float? RAM_available_gb { get; set; }
|
||||||
|
public float? RAM_total_gb
|
||||||
{
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (RAM_used_gb.HasValue && RAM_available_gb.HasValue)
|
||||||
|
return RAM_used_gb.Value + RAM_available_gb.Value;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compatibilidade conceitual
|
||||||
|
public float? RAM_usage => RAM_usage_percent;
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// GPU geral
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Agregado dos sensores de carga da GPU.
|
||||||
|
/// Calculado como o máximo entre core, frame buffer, memory,
|
||||||
|
/// video engine e bus interface.
|
||||||
|
/// </summary>
|
||||||
|
public float? GPU_load_percent { get; set; }
|
||||||
|
|
||||||
|
public float? GPU_core_load_percent { get; set; }
|
||||||
|
public float? GPU_frame_buffer_load_percent { get; set; }
|
||||||
|
public float? GPU_memory_load_percent { get; set; }
|
||||||
|
public float? GPU_video_engine_load_percent { get; set; }
|
||||||
|
public float? GPU_bus_interface_load_percent { get; set; }
|
||||||
|
|
||||||
|
public float? GPU_temp_core_c { get; set; }
|
||||||
|
|
||||||
|
public float? GPU_power_w { get; set; }
|
||||||
|
|
||||||
|
public float? GPU_core_clock_mhz { get; set; }
|
||||||
|
public float? GPU_memory_clock_mhz { get; set; }
|
||||||
|
public float? GPU_shader_clock_mhz { get; set; }
|
||||||
|
|
||||||
|
public float? GPU_fan_percent { get; set; }
|
||||||
|
public float? GPU_fan_rpm { get; set; }
|
||||||
|
|
||||||
|
public float? GPU_pcie_rx { get; set; }
|
||||||
|
public float? GPU_pcie_tx { get; set; }
|
||||||
|
|
||||||
|
// Compatibilidade conceitual
|
||||||
|
public float? GPU_load => GPU_load_percent;
|
||||||
|
public float? GPU_temp => GPU_temp_core_c;
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// GPU memória / VRAM
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
public float? GPU_vram_total_mb { get; set; }
|
||||||
|
public float? GPU_vram_used_mb { get; set; }
|
||||||
|
public float? GPU_vram_free_mb { get; set; }
|
||||||
|
|
||||||
|
public float? GPU_vram_used_percent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (GPU_vram_total_mb.HasValue &&
|
||||||
|
GPU_vram_total_mb.Value > 0 &&
|
||||||
|
GPU_vram_used_mb.HasValue)
|
||||||
|
{
|
||||||
|
return 100.0f * GPU_vram_used_mb.Value / GPU_vram_total_mb.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GPU_memory_load_percent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Disco
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Espaço usado no disco.
|
||||||
|
/// Isso NÃO é atividade do disco.
|
||||||
|
/// </summary>
|
||||||
|
public float? Disk_used_space_percent { get; set; }
|
||||||
|
|
||||||
|
// Nome antigo, mas agora intencionalmente apontando para espaço usado.
|
||||||
|
public float? HDD_load => Disk_used_space_percent;
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Processo atual
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
public int Process_thread_count { get; set; }
|
||||||
|
public long Process_working_set_mb { get; set; }
|
||||||
|
public long Process_private_memory_mb { get; set; }
|
||||||
|
public long Process_virtual_memory_mb { get; set; }
|
||||||
|
public double Process_cpu_time_total_s { get; set; }
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// ThreadPool
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
public int ThreadPool_available_worker_threads { get; set; }
|
||||||
|
public int ThreadPool_available_completion_port_threads { get; set; }
|
||||||
|
|
||||||
|
public int ThreadPool_max_worker_threads { get; set; }
|
||||||
|
public int ThreadPool_max_completion_port_threads { get; set; }
|
||||||
|
|
||||||
|
public int ThreadPool_used_worker_threads
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Math.Max(0, ThreadPool_max_worker_threads - ThreadPool_available_worker_threads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ThreadPool_used_completion_port_threads
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Math.Max(0, ThreadPool_max_completion_port_threads - ThreadPool_available_completion_port_threads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float ThreadPool_used_worker_percent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (ThreadPool_max_worker_threads <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 100.0f * ThreadPool_used_worker_threads / ThreadPool_max_worker_threads;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float ThreadPool_used_completion_port_percent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (ThreadPool_max_completion_port_threads <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 100.0f * ThreadPool_used_completion_port_threads / ThreadPool_max_completion_port_threads;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// String resumida para debug rápido
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
public string PerformanceStr
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return
|
||||||
|
$"CPU={Fmt(CPU_load_percent)}% " +
|
||||||
|
$"CPU_T={Fmt(CPU_temp_package_c)}C " +
|
||||||
|
$"RAM={Fmt(RAM_usage_percent)}% " +
|
||||||
|
$"GPU={Fmt(GPU_load_percent)}% " +
|
||||||
|
$"GPU_Core={Fmt(GPU_core_load_percent)}% " +
|
||||||
|
$"GPU_Mem={Fmt(GPU_memory_load_percent)}% " +
|
||||||
|
$"VRAM={Fmt(GPU_vram_used_mb)}/{Fmt(GPU_vram_total_mb)}MB " +
|
||||||
|
$"GPU_T={Fmt(GPU_temp_core_c)}C " +
|
||||||
|
$"GPU_P={Fmt(GPU_power_w)}W";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Inicialização
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
private static void InicializarComputer()
|
||||||
|
{
|
||||||
|
if (computer != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (ComputerLock)
|
||||||
|
{
|
||||||
|
if (computer != null)
|
||||||
|
return;
|
||||||
|
|
||||||
computer = new Computer()
|
computer = new Computer()
|
||||||
{
|
{
|
||||||
CPUEnabled = true,
|
CPUEnabled = true,
|
||||||
GPUEnabled = true,
|
GPUEnabled = true,
|
||||||
RAMEnabled = true,
|
RAMEnabled = true,
|
||||||
HDDEnabled = true,
|
HDDEnabled = true,
|
||||||
|
MainboardEnabled = false,
|
||||||
|
FanControllerEnabled = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
computer.Open();
|
computer.Open();
|
||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException ex)
|
catch
|
||||||
{
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
{
|
||||||
|
computer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float? CPU_load { get; set; }
|
// ============================================================
|
||||||
public float? GPU_load { get; set; }
|
// Atualização principal
|
||||||
public float? HDD_load { get; set; }
|
// ============================================================
|
||||||
public float? RAM_usage { get; set; }
|
|
||||||
public float? CPU_temp { get; set; }
|
|
||||||
public float? GPU_temp { get; set; }
|
|
||||||
public int ActiveThreads { get; set; }
|
|
||||||
public int WorkerThreads { get; set; }
|
|
||||||
public int CompletionPortThreads { get; set; }
|
|
||||||
public int MaxWorkerThreads { get; set; }
|
|
||||||
public int MaxCompletionPortThreads { get; set; }
|
|
||||||
public string PerformanceStr
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return FuncoesGlobais.MontarStringPerformance(
|
|
||||||
GPU_load,
|
|
||||||
CPU_load,
|
|
||||||
RAM_usage,
|
|
||||||
GPU_temp,
|
|
||||||
CPU_temp,
|
|
||||||
HDD_load
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime UltimaLeituraPerformance = DateTime.Now;
|
|
||||||
|
|
||||||
public void AtualizarDadosPerformance()
|
public void AtualizarDadosPerformance()
|
||||||
{
|
{
|
||||||
|
AtualizarDadosPerformance(TimeSpan.FromSeconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AtualizarDadosPerformance(TimeSpan intervaloMinimo)
|
||||||
|
{
|
||||||
|
if (DateTime.Now < _ultimaLeituraPerformance.Add(intervaloMinimo))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_ultimaLeituraPerformance = DateTime.Now;
|
||||||
|
Timestamp = DateTime.Now;
|
||||||
|
TimestampUnixMs = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
if (computer == null || computer.Hardware == null)
|
if (computer == null || computer.Hardware == null)
|
||||||
{
|
{
|
||||||
|
InicializarComputer();
|
||||||
|
if (computer == null || computer.Hardware == null)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DateTime.Now > UltimaLeituraPerformance.AddSeconds(1))
|
// Variáveis locais, para só atualizar propriedades no final.
|
||||||
{
|
|
||||||
UltimaLeituraPerformance = DateTime.Now;
|
|
||||||
|
|
||||||
float? cpuLoad = null;
|
float? cpuLoad = null;
|
||||||
float? gpuLoad = null;
|
float? cpuTempPackage = null;
|
||||||
float? hddLoad = null;
|
float? cpuPowerPackage = null;
|
||||||
float? ramUsage = null;
|
float? cpuPowerCores = null;
|
||||||
float? cpuTemp = null;
|
float? cpuPowerGraphics = null;
|
||||||
float? gpuTemp = null;
|
float? cpuPowerDram = null;
|
||||||
|
float? cpuClockAvg = null;
|
||||||
|
float? cpuClockMax = null;
|
||||||
|
float? cpuBusSpeed = null;
|
||||||
|
|
||||||
|
float? ramUsage = null;
|
||||||
|
float? ramUsedGb = null;
|
||||||
|
float? ramAvailableGb = null;
|
||||||
|
|
||||||
|
float? gpuCoreLoad = null;
|
||||||
|
float? gpuFrameBufferLoad = null;
|
||||||
|
float? gpuMemoryLoad = null;
|
||||||
|
float? gpuVideoEngineLoad = null;
|
||||||
|
float? gpuBusInterfaceLoad = null;
|
||||||
|
|
||||||
|
float? gpuTempCore = null;
|
||||||
|
float? gpuPower = null;
|
||||||
|
|
||||||
|
float? gpuCoreClock = null;
|
||||||
|
float? gpuMemoryClock = null;
|
||||||
|
float? gpuShaderClock = null;
|
||||||
|
|
||||||
|
float? gpuFanPercent = null;
|
||||||
|
float? gpuFanRpm = null;
|
||||||
|
|
||||||
|
float? gpuVramTotalMb = null;
|
||||||
|
float? gpuVramUsedMb = null;
|
||||||
|
float? gpuVramFreeMb = null;
|
||||||
|
|
||||||
|
float? gpuPcieRx = null;
|
||||||
|
float? gpuPcieTx = null;
|
||||||
|
|
||||||
|
float? diskUsedSpace = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock (ComputerLock)
|
||||||
|
{
|
||||||
foreach (var hardwareItem in computer.Hardware)
|
foreach (var hardwareItem in computer.Hardware)
|
||||||
{
|
{
|
||||||
hardwareItem.Update();
|
hardwareItem.Update();
|
||||||
|
|
||||||
if (hardwareItem.HardwareType == HardwareType.CPU)
|
switch (hardwareItem.HardwareType)
|
||||||
{
|
{
|
||||||
|
case HardwareType.CPU:
|
||||||
|
LerCpu(hardwareItem,
|
||||||
|
ref cpuLoad,
|
||||||
|
ref cpuTempPackage,
|
||||||
|
ref cpuPowerPackage,
|
||||||
|
ref cpuPowerCores,
|
||||||
|
ref cpuPowerGraphics,
|
||||||
|
ref cpuPowerDram,
|
||||||
|
ref cpuClockAvg,
|
||||||
|
ref cpuClockMax,
|
||||||
|
ref cpuBusSpeed);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HardwareType.RAM:
|
||||||
|
LerRam(hardwareItem,
|
||||||
|
ref ramUsage,
|
||||||
|
ref ramUsedGb,
|
||||||
|
ref ramAvailableGb);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HardwareType.GpuNvidia:
|
||||||
|
case HardwareType.GpuAti:
|
||||||
|
LerGpu(hardwareItem,
|
||||||
|
ref gpuCoreLoad,
|
||||||
|
ref gpuFrameBufferLoad,
|
||||||
|
ref gpuMemoryLoad,
|
||||||
|
ref gpuVideoEngineLoad,
|
||||||
|
ref gpuBusInterfaceLoad,
|
||||||
|
ref gpuTempCore,
|
||||||
|
ref gpuPower,
|
||||||
|
ref gpuCoreClock,
|
||||||
|
ref gpuMemoryClock,
|
||||||
|
ref gpuShaderClock,
|
||||||
|
ref gpuFanPercent,
|
||||||
|
ref gpuFanRpm,
|
||||||
|
ref gpuVramTotalMb,
|
||||||
|
ref gpuVramUsedMb,
|
||||||
|
ref gpuVramFreeMb,
|
||||||
|
ref gpuPcieRx,
|
||||||
|
ref gpuPcieTx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HardwareType.HDD:
|
||||||
|
LerDisco(hardwareItem, ref diskUsedSpace);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CPU_load_percent = cpuLoad;
|
||||||
|
CPU_temp_package_c = cpuTempPackage;
|
||||||
|
CPU_power_package_w = cpuPowerPackage;
|
||||||
|
CPU_power_cores_w = cpuPowerCores;
|
||||||
|
CPU_power_graphics_w = cpuPowerGraphics;
|
||||||
|
CPU_power_dram_w = cpuPowerDram;
|
||||||
|
CPU_clock_avg_mhz = cpuClockAvg;
|
||||||
|
CPU_clock_max_mhz = cpuClockMax;
|
||||||
|
CPU_bus_speed_mhz = cpuBusSpeed;
|
||||||
|
|
||||||
|
RAM_usage_percent = ramUsage;
|
||||||
|
RAM_used_gb = ramUsedGb;
|
||||||
|
RAM_available_gb = ramAvailableGb;
|
||||||
|
|
||||||
|
GPU_core_load_percent = gpuCoreLoad;
|
||||||
|
GPU_frame_buffer_load_percent = gpuFrameBufferLoad;
|
||||||
|
GPU_memory_load_percent = gpuMemoryLoad;
|
||||||
|
GPU_video_engine_load_percent = gpuVideoEngineLoad;
|
||||||
|
GPU_bus_interface_load_percent = gpuBusInterfaceLoad;
|
||||||
|
|
||||||
|
GPU_load_percent = MaxNullable(
|
||||||
|
gpuCoreLoad,
|
||||||
|
gpuFrameBufferLoad,
|
||||||
|
gpuMemoryLoad,
|
||||||
|
gpuVideoEngineLoad,
|
||||||
|
gpuBusInterfaceLoad
|
||||||
|
);
|
||||||
|
|
||||||
|
GPU_temp_core_c = gpuTempCore;
|
||||||
|
GPU_power_w = gpuPower;
|
||||||
|
|
||||||
|
GPU_core_clock_mhz = gpuCoreClock;
|
||||||
|
GPU_memory_clock_mhz = gpuMemoryClock;
|
||||||
|
GPU_shader_clock_mhz = gpuShaderClock;
|
||||||
|
|
||||||
|
GPU_fan_percent = gpuFanPercent;
|
||||||
|
GPU_fan_rpm = gpuFanRpm;
|
||||||
|
|
||||||
|
GPU_vram_total_mb = gpuVramTotalMb;
|
||||||
|
GPU_vram_used_mb = gpuVramUsedMb;
|
||||||
|
GPU_vram_free_mb = gpuVramFreeMb;
|
||||||
|
|
||||||
|
GPU_pcie_rx = gpuPcieRx;
|
||||||
|
GPU_pcie_tx = gpuPcieTx;
|
||||||
|
|
||||||
|
Disk_used_space_percent = diskUsedSpace;
|
||||||
|
|
||||||
|
AtualizarDadosProcesso();
|
||||||
|
AtualizarDadosThreadPool();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Mantém último snapshot válido.
|
||||||
|
// Se quiser, depois podemos adicionar um campo:
|
||||||
|
// LastError, ErrorCount, LastErrorTimestamp.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Leitores por hardware
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
private static void LerCpu(
|
||||||
|
IHardware hardwareItem,
|
||||||
|
ref float? cpuLoad,
|
||||||
|
ref float? cpuTempPackage,
|
||||||
|
ref float? cpuPowerPackage,
|
||||||
|
ref float? cpuPowerCores,
|
||||||
|
ref float? cpuPowerGraphics,
|
||||||
|
ref float? cpuPowerDram,
|
||||||
|
ref float? cpuClockAvg,
|
||||||
|
ref float? cpuClockMax,
|
||||||
|
ref float? cpuBusSpeed)
|
||||||
|
{
|
||||||
|
float clockSum = 0;
|
||||||
|
int clockCount = 0;
|
||||||
|
float? clockMax = null;
|
||||||
|
|
||||||
foreach (var sensor in hardwareItem.Sensors)
|
foreach (var sensor in hardwareItem.Sensors)
|
||||||
{
|
{
|
||||||
if (sensor.SensorType == SensorType.Load && sensor.Name == "CPU Total")
|
if (!sensor.Value.HasValue)
|
||||||
{
|
continue;
|
||||||
|
|
||||||
|
string name = sensor.Name ?? "";
|
||||||
|
|
||||||
|
if (sensor.SensorType == SensorType.Load && name == "CPU Total")
|
||||||
cpuLoad = sensor.Value;
|
cpuLoad = sensor.Value;
|
||||||
}
|
|
||||||
if (sensor.SensorType == SensorType.Temperature && sensor.Name == "CPU Package")
|
else if (sensor.SensorType == SensorType.Temperature && name == "CPU Package")
|
||||||
|
cpuTempPackage = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Power && name == "CPU Package")
|
||||||
|
cpuPowerPackage = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Power && name == "CPU Cores")
|
||||||
|
cpuPowerCores = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Power && name == "CPU Graphics")
|
||||||
|
cpuPowerGraphics = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Power && name == "CPU DRAM")
|
||||||
|
cpuPowerDram = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Clock && name.StartsWith("CPU Core"))
|
||||||
{
|
{
|
||||||
cpuTemp = sensor.Value;
|
float v = sensor.Value.Value;
|
||||||
}
|
clockSum += v;
|
||||||
}
|
clockCount++;
|
||||||
|
|
||||||
|
if (!clockMax.HasValue || v > clockMax.Value)
|
||||||
|
clockMax = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hardwareItem.HardwareType == HardwareType.GpuNvidia || hardwareItem.HardwareType == HardwareType.GpuAti)
|
else if (sensor.SensorType == SensorType.Clock && name == "Bus Speed")
|
||||||
|
cpuBusSpeed = sensor.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clockCount > 0)
|
||||||
|
cpuClockAvg = clockSum / clockCount;
|
||||||
|
|
||||||
|
cpuClockMax = clockMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LerRam(
|
||||||
|
IHardware hardwareItem,
|
||||||
|
ref float? ramUsage,
|
||||||
|
ref float? ramUsedGb,
|
||||||
|
ref float? ramAvailableGb)
|
||||||
{
|
{
|
||||||
foreach (var sensor in hardwareItem.Sensors)
|
foreach (var sensor in hardwareItem.Sensors)
|
||||||
{
|
{
|
||||||
if (sensor.SensorType == SensorType.Load && sensor.Name == "GPU Core")
|
if (!sensor.Value.HasValue)
|
||||||
{
|
continue;
|
||||||
gpuLoad = sensor.Value;
|
|
||||||
}
|
|
||||||
if (sensor.SensorType == SensorType.Temperature && sensor.Name == "GPU Core")
|
|
||||||
{
|
|
||||||
gpuTemp = sensor.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hardwareItem.HardwareType == HardwareType.RAM)
|
string name = sensor.Name ?? "";
|
||||||
{
|
|
||||||
foreach (var sensor in hardwareItem.Sensors)
|
if (sensor.SensorType == SensorType.Load && name == "Memory")
|
||||||
{
|
|
||||||
if (sensor.SensorType == SensorType.Load && sensor.Name == "Memory")
|
|
||||||
{
|
|
||||||
ramUsage = sensor.Value;
|
ramUsage = sensor.Value;
|
||||||
}
|
|
||||||
|
else if (sensor.SensorType == SensorType.Data && name == "Used Memory")
|
||||||
|
ramUsedGb = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Data && name == "Available Memory")
|
||||||
|
ramAvailableGb = sensor.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hardwareItem.HardwareType == HardwareType.HDD)
|
private static void LerGpu(
|
||||||
|
IHardware hardwareItem,
|
||||||
|
ref float? gpuCoreLoad,
|
||||||
|
ref float? gpuFrameBufferLoad,
|
||||||
|
ref float? gpuMemoryLoad,
|
||||||
|
ref float? gpuVideoEngineLoad,
|
||||||
|
ref float? gpuBusInterfaceLoad,
|
||||||
|
ref float? gpuTempCore,
|
||||||
|
ref float? gpuPower,
|
||||||
|
ref float? gpuCoreClock,
|
||||||
|
ref float? gpuMemoryClock,
|
||||||
|
ref float? gpuShaderClock,
|
||||||
|
ref float? gpuFanPercent,
|
||||||
|
ref float? gpuFanRpm,
|
||||||
|
ref float? gpuVramTotalMb,
|
||||||
|
ref float? gpuVramUsedMb,
|
||||||
|
ref float? gpuVramFreeMb,
|
||||||
|
ref float? gpuPcieRx,
|
||||||
|
ref float? gpuPcieTx)
|
||||||
{
|
{
|
||||||
foreach (var sensor in hardwareItem.Sensors)
|
foreach (var sensor in hardwareItem.Sensors)
|
||||||
{
|
{
|
||||||
if (sensor.SensorType == SensorType.Load && sensor.Name == "Used Space")
|
if (!sensor.Value.HasValue)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string name = sensor.Name ?? "";
|
||||||
|
|
||||||
|
if (sensor.SensorType == SensorType.Temperature && name == "GPU Core")
|
||||||
|
gpuTempCore = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Load && name == "GPU Core")
|
||||||
|
gpuCoreLoad = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Load && name == "GPU Frame Buffer")
|
||||||
|
gpuFrameBufferLoad = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Load && name == "GPU Memory")
|
||||||
|
gpuMemoryLoad = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Load && name == "GPU Video Engine")
|
||||||
|
gpuVideoEngineLoad = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Load && name == "GPU Bus Interface")
|
||||||
|
gpuBusInterfaceLoad = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Clock && name == "GPU Core")
|
||||||
|
gpuCoreClock = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Clock && name == "GPU Memory")
|
||||||
|
gpuMemoryClock = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Clock && name == "GPU Shader")
|
||||||
|
gpuShaderClock = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Control && name == "GPU Fan")
|
||||||
|
gpuFanPercent = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Fan && name == "GPU")
|
||||||
|
gpuFanRpm = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.SmallData && name == "GPU Memory Total")
|
||||||
|
gpuVramTotalMb = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.SmallData && name == "GPU Memory Used")
|
||||||
|
gpuVramUsedMb = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.SmallData && name == "GPU Memory Free")
|
||||||
|
gpuVramFreeMb = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Power && name == "GPU Power")
|
||||||
|
gpuPower = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Throughput && name == "GPU PCIE Rx")
|
||||||
|
gpuPcieRx = sensor.Value;
|
||||||
|
|
||||||
|
else if (sensor.SensorType == SensorType.Throughput && name == "GPU PCIE Tx")
|
||||||
|
gpuPcieTx = sensor.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LerDisco(IHardware hardwareItem, ref float? diskUsedSpace)
|
||||||
{
|
{
|
||||||
hddLoad = sensor.Value;
|
foreach (var sensor in hardwareItem.Sensors)
|
||||||
}
|
{
|
||||||
}
|
if (!sensor.Value.HasValue)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string name = sensor.Name ?? "";
|
||||||
|
|
||||||
|
if (sensor.SensorType == SensorType.Load && name == "Used Space")
|
||||||
|
diskUsedSpace = sensor.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int activeThreads = Process.GetCurrentProcess().Threads.Count;
|
// ============================================================
|
||||||
ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
|
// Processo / ThreadPool
|
||||||
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
|
// ============================================================
|
||||||
|
|
||||||
CPU_load = cpuLoad;
|
private void AtualizarDadosProcesso()
|
||||||
GPU_load = gpuLoad;
|
{
|
||||||
HDD_load = hddLoad;
|
try
|
||||||
RAM_usage = ramUsage;
|
{
|
||||||
CPU_temp = cpuTemp;
|
using (var proc = Process.GetCurrentProcess())
|
||||||
GPU_temp = gpuTemp;
|
{
|
||||||
ActiveThreads = activeThreads;
|
Process_thread_count = proc.Threads.Count;
|
||||||
WorkerThreads = workerThreads;
|
Process_working_set_mb = BytesToMb(proc.WorkingSet64);
|
||||||
MaxWorkerThreads = maxWorkerThreads;
|
Process_private_memory_mb = BytesToMb(proc.PrivateMemorySize64);
|
||||||
CompletionPortThreads = completionPortThreads;
|
Process_virtual_memory_mb = BytesToMb(proc.VirtualMemorySize64);
|
||||||
MaxCompletionPortThreads = maxCompletionPortThreads;
|
Process_cpu_time_total_s = proc.TotalProcessorTime.TotalSeconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Mantém último valor.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AtualizarDadosThreadPool()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ThreadPool.GetAvailableThreads(
|
||||||
|
out int availableWorkerThreads,
|
||||||
|
out int availableCompletionPortThreads
|
||||||
|
);
|
||||||
|
|
||||||
|
ThreadPool.GetMaxThreads(
|
||||||
|
out int maxWorkerThreads,
|
||||||
|
out int maxCompletionPortThreads
|
||||||
|
);
|
||||||
|
|
||||||
|
ThreadPool_available_worker_threads = availableWorkerThreads;
|
||||||
|
ThreadPool_available_completion_port_threads = availableCompletionPortThreads;
|
||||||
|
|
||||||
|
ThreadPool_max_worker_threads = maxWorkerThreads;
|
||||||
|
ThreadPool_max_completion_port_threads = maxCompletionPortThreads;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Mantém último valor.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Clone / Snapshot
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
public PerformanceModel Clone()
|
public PerformanceModel Clone()
|
||||||
{
|
{
|
||||||
return new PerformanceModel()
|
return new PerformanceModel()
|
||||||
{
|
{
|
||||||
ActiveThreads = ActiveThreads,
|
Timestamp = this.Timestamp,
|
||||||
CompletionPortThreads = CompletionPortThreads,
|
TimestampUnixMs = this.TimestampUnixMs,
|
||||||
MaxWorkerThreads = MaxWorkerThreads,
|
|
||||||
MaxCompletionPortThreads = MaxCompletionPortThreads,
|
CPU_load_percent = this.CPU_load_percent,
|
||||||
CPU_load = CPU_load,
|
CPU_temp_package_c = this.CPU_temp_package_c,
|
||||||
GPU_load = GPU_load,
|
CPU_power_package_w = this.CPU_power_package_w,
|
||||||
RAM_usage = RAM_usage,
|
CPU_power_cores_w = this.CPU_power_cores_w,
|
||||||
CPU_temp = CPU_temp,
|
CPU_power_graphics_w = this.CPU_power_graphics_w,
|
||||||
GPU_temp = GPU_temp,
|
CPU_power_dram_w = this.CPU_power_dram_w,
|
||||||
HDD_load = HDD_load,
|
CPU_clock_avg_mhz = this.CPU_clock_avg_mhz,
|
||||||
WorkerThreads = WorkerThreads
|
CPU_clock_max_mhz = this.CPU_clock_max_mhz,
|
||||||
|
CPU_bus_speed_mhz = this.CPU_bus_speed_mhz,
|
||||||
|
|
||||||
|
RAM_usage_percent = this.RAM_usage_percent,
|
||||||
|
RAM_used_gb = this.RAM_used_gb,
|
||||||
|
RAM_available_gb = this.RAM_available_gb,
|
||||||
|
|
||||||
|
GPU_load_percent = this.GPU_load_percent,
|
||||||
|
GPU_core_load_percent = this.GPU_core_load_percent,
|
||||||
|
GPU_frame_buffer_load_percent = this.GPU_frame_buffer_load_percent,
|
||||||
|
GPU_memory_load_percent = this.GPU_memory_load_percent,
|
||||||
|
GPU_video_engine_load_percent = this.GPU_video_engine_load_percent,
|
||||||
|
GPU_bus_interface_load_percent = this.GPU_bus_interface_load_percent,
|
||||||
|
|
||||||
|
GPU_temp_core_c = this.GPU_temp_core_c,
|
||||||
|
GPU_power_w = this.GPU_power_w,
|
||||||
|
|
||||||
|
GPU_core_clock_mhz = this.GPU_core_clock_mhz,
|
||||||
|
GPU_memory_clock_mhz = this.GPU_memory_clock_mhz,
|
||||||
|
GPU_shader_clock_mhz = this.GPU_shader_clock_mhz,
|
||||||
|
|
||||||
|
GPU_fan_percent = this.GPU_fan_percent,
|
||||||
|
GPU_fan_rpm = this.GPU_fan_rpm,
|
||||||
|
|
||||||
|
GPU_vram_total_mb = this.GPU_vram_total_mb,
|
||||||
|
GPU_vram_used_mb = this.GPU_vram_used_mb,
|
||||||
|
GPU_vram_free_mb = this.GPU_vram_free_mb,
|
||||||
|
|
||||||
|
GPU_pcie_rx = this.GPU_pcie_rx,
|
||||||
|
GPU_pcie_tx = this.GPU_pcie_tx,
|
||||||
|
|
||||||
|
Disk_used_space_percent = this.Disk_used_space_percent,
|
||||||
|
|
||||||
|
Process_thread_count = this.Process_thread_count,
|
||||||
|
Process_working_set_mb = this.Process_working_set_mb,
|
||||||
|
Process_private_memory_mb = this.Process_private_memory_mb,
|
||||||
|
Process_virtual_memory_mb = this.Process_virtual_memory_mb,
|
||||||
|
Process_cpu_time_total_s = this.Process_cpu_time_total_s,
|
||||||
|
|
||||||
|
ThreadPool_available_worker_threads = this.ThreadPool_available_worker_threads,
|
||||||
|
ThreadPool_available_completion_port_threads = this.ThreadPool_available_completion_port_threads,
|
||||||
|
ThreadPool_max_worker_threads = this.ThreadPool_max_worker_threads,
|
||||||
|
ThreadPool_max_completion_port_threads = this.ThreadPool_max_completion_port_threads,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Helpers
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
private static float? MaxNullable(params float?[] values)
|
||||||
|
{
|
||||||
|
float? max = null;
|
||||||
|
|
||||||
|
foreach (float? value in values)
|
||||||
|
{
|
||||||
|
if (!value.HasValue)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!max.HasValue || value.Value > max.Value)
|
||||||
|
max = value.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long BytesToMb(long bytes)
|
||||||
|
{
|
||||||
|
return bytes / (1024L * 1024L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Fmt(float? value, int casas = 1)
|
||||||
|
{
|
||||||
|
if (!value.HasValue)
|
||||||
|
return "-";
|
||||||
|
|
||||||
|
return value.Value.ToString($"F{casas}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,88 +8,93 @@ namespace AgroBase.Services
|
||||||
{
|
{
|
||||||
public class CoulombCounterService
|
public class CoulombCounterService
|
||||||
{
|
{
|
||||||
public CoulombCounterService(double max_Ah, double w_m_base = 0.1167)
|
public CoulombCounterService(double max_Ah, double wh_m_base = 0.1167)
|
||||||
{
|
{
|
||||||
CargaMaxima_C = max_Ah * 3600.0; // Ah -> Coulombs
|
CapacidadeMaxima_Ah = max_Ah;
|
||||||
WhPorMetroBase = w_m_base;
|
CargaMaxima_C = max_Ah * 3600.0;
|
||||||
|
WhPorMetroBase = wh_m_base;
|
||||||
Iniciado = false;
|
|
||||||
BmsLigado = false;
|
|
||||||
|
|
||||||
_estadoInicializado = false;
|
|
||||||
_ultimaLeituraIntegrada = null;
|
|
||||||
|
|
||||||
CargaAtual_C = 0;
|
|
||||||
ConsumidoTotal_C = 0;
|
|
||||||
EnergiaConsumidaTotal_Wh = 0;
|
|
||||||
|
|
||||||
_socInicialInstancia = 0;
|
|
||||||
_cargaInicialInstancia_C = 0;
|
|
||||||
|
|
||||||
_socInicialOperacao = 0;
|
|
||||||
_cargaInicioOperacao_C = 0;
|
|
||||||
_consumidoTotalNoInicioOperacao_C = 0;
|
|
||||||
_energiaTotalNoInicioOperacao_Wh = 0;
|
|
||||||
|
|
||||||
MargemSegurancaAutonomia = 0.30;
|
MargemSegurancaAutonomia = 0.30;
|
||||||
|
|
||||||
ResetarHistoricosAutonomia();
|
ResetarTudo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Iniciado { get; private set; }
|
public bool Iniciado { get; private set; }
|
||||||
public bool BmsLigado { get; private set; }
|
public bool BmsLigado { get; private set; }
|
||||||
|
public bool OperacaoAtiva { get; private set; }
|
||||||
|
public bool OperacaoFinalizada { get; private set; }
|
||||||
|
|
||||||
private bool _estadoInicializado;
|
private bool _estadoInicializado;
|
||||||
private DateTime? _ultimaLeituraIntegrada;
|
private DateTime? _ultimaLeituraIntegrada;
|
||||||
|
|
||||||
// Capacidade e estado absoluto do pack
|
public double CapacidadeMaxima_Ah { get; private set; }
|
||||||
private double CargaMaxima_C { get; set; } // Coulombs
|
private double CargaMaxima_C { get; set; }
|
||||||
private double CargaAtual_C { get; set; } // Coulombs
|
|
||||||
|
|
||||||
// Snapshot inicial da instância
|
public double CargaAtual_C { get; private set; }
|
||||||
private double _socInicialInstancia { get; set; }
|
public double CargaAtualAmp => CargaAtual_C / 3600.0;
|
||||||
private double _cargaInicialInstancia_C { get; set; }
|
|
||||||
|
private double _socInicialInstancia;
|
||||||
|
private double _socInicialOperacao;
|
||||||
|
|
||||||
|
private double _distanciaInicioOperacao_m;
|
||||||
|
|
||||||
|
private double _consumidoIntegradoTotal_C;
|
||||||
|
private double _consumidoIntegradoOperacao_C;
|
||||||
|
|
||||||
// Acumuladores totais desde a criação da instância
|
|
||||||
private double ConsumidoTotal_C { get; set; }
|
|
||||||
public double ConsumidoTotal_Ah => ConsumidoTotal_C / 3600.0;
|
public double ConsumidoTotal_Ah => ConsumidoTotal_C / 3600.0;
|
||||||
|
public double ConsumidoOperacao_Ah => ConsumidoOperacao_C / 3600.0;
|
||||||
|
|
||||||
|
public double ConsumidoTotal_C
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (BmsLigado)
|
||||||
|
return Math.Max(0, (_socInicialInstancia - PercentualBateria) / 100.0 * CargaMaxima_C);
|
||||||
|
|
||||||
|
return _consumidoIntegradoTotal_C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double ConsumidoOperacao_C
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!OperacaoAtiva && !OperacaoFinalizada)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (BmsLigado)
|
||||||
|
return Math.Max(0, (_socInicialOperacao - PercentualBateria) / 100.0 * CargaMaxima_C);
|
||||||
|
|
||||||
|
return _consumidoIntegradoOperacao_C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public double PercentualConsumidoTotal
|
public double PercentualConsumidoTotal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (CargaMaxima_C <= 0) return 0;
|
if (CargaMaxima_C <= 0) return 0;
|
||||||
double calc = (ConsumidoTotal_C / CargaMaxima_C) * 100.0;
|
|
||||||
return FuncoesMatematicas.Clamp(calc, 0, 100);
|
if (BmsLigado)
|
||||||
|
return Clamp(_socInicialInstancia - PercentualBateria, 0, 100);
|
||||||
|
|
||||||
|
return Clamp((_consumidoIntegradoTotal_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double EnergiaConsumidaTotal_Wh { get; private set; }
|
|
||||||
|
|
||||||
// Snapshot do início da operação
|
|
||||||
private double _socInicialOperacao { get; set; }
|
|
||||||
private double _cargaInicioOperacao_C { get; set; }
|
|
||||||
private double _consumidoTotalNoInicioOperacao_C { get; set; }
|
|
||||||
private double _energiaTotalNoInicioOperacao_Wh { get; set; }
|
|
||||||
public bool OperacaoAtiva { get; private set; }
|
|
||||||
public bool OperacaoFinalizada { get; private set; }
|
|
||||||
|
|
||||||
private double _consumidoTotalNoFimOperacao_C;
|
|
||||||
private double _energiaTotalNoFimOperacao_Wh;
|
|
||||||
|
|
||||||
// Derivados da operação
|
|
||||||
public double ConsumidoOperacao_C { get; set; }
|
|
||||||
public double ConsumidoOperacao_Ah => ConsumidoOperacao_C / 3600.0;
|
|
||||||
|
|
||||||
public double PercentualConsumidoOperacao
|
public double PercentualConsumidoOperacao
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (CargaMaxima_C <= 0)
|
if (!OperacaoAtiva && !OperacaoFinalizada)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
double calc = (ConsumidoOperacao_C / CargaMaxima_C) * 100.0;
|
if (CargaMaxima_C <= 0) return 0;
|
||||||
return FuncoesMatematicas.Clamp(calc, 0, 100);
|
|
||||||
|
if (BmsLigado)
|
||||||
|
return Clamp(_socInicialOperacao - PercentualBateria, 0, 100);
|
||||||
|
|
||||||
|
return Clamp((_consumidoIntegradoOperacao_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,12 +102,65 @@ namespace AgroBase.Services
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_cargaInicioOperacao_C <= 0) return 0;
|
if (_socInicialOperacao <= 0) return 0;
|
||||||
double calc = (ConsumidoOperacao_C / _cargaInicioOperacao_C) * 100.0;
|
|
||||||
return FuncoesMatematicas.Clamp(calc, 0, 100);
|
double consumido = PercentualConsumidoOperacao;
|
||||||
|
return Clamp((consumido / _socInicialOperacao) * 100.0, 0, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double PercentualConsumidoTotalIntegrado
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (CargaMaxima_C <= 0) return 0;
|
||||||
|
return Clamp((_consumidoIntegradoTotal_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double PercentualConsumidoOperacaoIntegrado
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (CargaMaxima_C <= 0) return 0;
|
||||||
|
return Clamp((_consumidoIntegradoOperacao_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DiferencaSocBmsVsIntegrado_Total
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return PercentualConsumidoTotalIntegrado - PercentualConsumidoTotal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double PercentualAtual
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (BmsLigado)
|
||||||
|
return PercentualBateria;
|
||||||
|
|
||||||
|
if (CargaMaxima_C <= 0) return 0;
|
||||||
|
return Clamp((CargaAtual_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double PercentualBateria { get; private set; }
|
||||||
|
public double Temperatura { get; private set; }
|
||||||
|
public double CorrenteInstantanea { get; private set; }
|
||||||
|
public double CorrenteDescarga_A { get; private set; }
|
||||||
|
public double TensaoInstantanea { get; private set; }
|
||||||
|
public double PotenciaInstantanea { get; private set; }
|
||||||
|
public double PotenciaDescarga_W { get; private set; }
|
||||||
|
public double TempoEstimadoMinutos { get; private set; }
|
||||||
|
public double _dt { get; private set; }
|
||||||
|
|
||||||
|
public double EnergiaConsumidaTotal_Wh { get; private set; }
|
||||||
|
private double _energiaConsumidaInicioOperacao_Wh;
|
||||||
|
private double _energiaConsumidaFimOperacao_Wh;
|
||||||
|
|
||||||
public double EnergiaConsumidaOperacao_Wh
|
public double EnergiaConsumidaOperacao_Wh
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -110,32 +168,16 @@ namespace AgroBase.Services
|
||||||
if (!OperacaoAtiva && !OperacaoFinalizada)
|
if (!OperacaoAtiva && !OperacaoFinalizada)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
double referenciaFim = OperacaoFinalizada
|
double fim = OperacaoFinalizada
|
||||||
? _energiaTotalNoFimOperacao_Wh
|
? _energiaConsumidaFimOperacao_Wh
|
||||||
: EnergiaConsumidaTotal_Wh;
|
: EnergiaConsumidaTotal_Wh;
|
||||||
|
|
||||||
return Math.Max(0, referenciaFim - _energiaTotalNoInicioOperacao_Wh);
|
return Math.Max(0, fim - _energiaConsumidaInicioOperacao_Wh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estado atual
|
public double EnergiaConsumidaTotal_kWh => EnergiaConsumidaTotal_Wh / 1000.0;
|
||||||
public double PercentualAtual
|
public double EnergiaConsumidaOperacao_kWh => EnergiaConsumidaOperacao_Wh / 1000.0;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (CargaMaxima_C <= 0) return 0;
|
|
||||||
return FuncoesMatematicas.Clamp((CargaAtual_C / CargaMaxima_C) * 100.0, 0, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public double CargaAtualAmp => CargaAtual_C / 3600.0;
|
|
||||||
public double PercentualBateria { get; private set; }
|
|
||||||
public double Temperatura { get; private set; }
|
|
||||||
public double CorrenteInstantanea { get; private set; }
|
|
||||||
public double TensaoInstantanea { get; private set; }
|
|
||||||
public double PotenciaInstantanea { get; private set; }
|
|
||||||
public double TempoEstimadoMinutos { get; private set; }
|
|
||||||
public double _dt { get; private set; }
|
|
||||||
|
|
||||||
public double WhRestante
|
public double WhRestante
|
||||||
{
|
{
|
||||||
|
|
@ -149,12 +191,14 @@ namespace AgroBase.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Histórico para suavização de corrente
|
public double kWhRestante => WhRestante / 1000.0;
|
||||||
private const int BufferSize = 30;
|
|
||||||
private readonly Queue<double> _historicoCorrente = new Queue<double>();
|
private const int BufferSize = 30;
|
||||||
|
private readonly Queue<double> _historicoCorrenteDescarga = new Queue<double>();
|
||||||
|
private readonly Queue<double> _historicoPotenciaDescarga = new Queue<double>();
|
||||||
|
|
||||||
// Autonomia
|
|
||||||
public double WhPorMetro { get; private set; }
|
public double WhPorMetro { get; private set; }
|
||||||
|
public double kWhPorMetro => WhPorMetro / 1000.0;
|
||||||
public double WhPorMetroBase { get; set; }
|
public double WhPorMetroBase { get; set; }
|
||||||
public double WhPorMetroHistorico { get; private set; }
|
public double WhPorMetroHistorico { get; private set; }
|
||||||
|
|
||||||
|
|
@ -181,18 +225,17 @@ namespace AgroBase.Services
|
||||||
private double _distanciaTotalMetrosAnterior;
|
private double _distanciaTotalMetrosAnterior;
|
||||||
private double _energiaConsumidaAnterior_Wh_Total;
|
private double _energiaConsumidaAnterior_Wh_Total;
|
||||||
|
|
||||||
public void IniciarOperacao()
|
public void IniciarOperacao(double distanciaTotalMetrosAtual = 0)
|
||||||
{
|
{
|
||||||
if (!_estadoInicializado)
|
if (!_estadoInicializado)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_socInicialOperacao = PercentualBateria;
|
_socInicialOperacao = PercentualBateria;
|
||||||
_cargaInicioOperacao_C = CargaAtual_C;
|
_distanciaInicioOperacao_m = distanciaTotalMetrosAtual;
|
||||||
_consumidoTotalNoInicioOperacao_C = ConsumidoTotal_C;
|
|
||||||
_energiaTotalNoInicioOperacao_Wh = EnergiaConsumidaTotal_Wh;
|
|
||||||
|
|
||||||
_consumidoTotalNoFimOperacao_C = 0;
|
_consumidoIntegradoOperacao_C = 0;
|
||||||
_energiaTotalNoFimOperacao_Wh = 0;
|
_energiaConsumidaInicioOperacao_Wh = EnergiaConsumidaTotal_Wh;
|
||||||
|
_energiaConsumidaFimOperacao_Wh = 0;
|
||||||
|
|
||||||
OperacaoAtiva = true;
|
OperacaoAtiva = true;
|
||||||
OperacaoFinalizada = false;
|
OperacaoFinalizada = false;
|
||||||
|
|
@ -203,8 +246,7 @@ namespace AgroBase.Services
|
||||||
if (!OperacaoAtiva)
|
if (!OperacaoAtiva)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_consumidoTotalNoFimOperacao_C = ConsumidoTotal_C;
|
_energiaConsumidaFimOperacao_Wh = EnergiaConsumidaTotal_Wh;
|
||||||
_energiaTotalNoFimOperacao_Wh = EnergiaConsumidaTotal_Wh;
|
|
||||||
|
|
||||||
OperacaoAtiva = false;
|
OperacaoAtiva = false;
|
||||||
OperacaoFinalizada = true;
|
OperacaoFinalizada = true;
|
||||||
|
|
@ -212,63 +254,22 @@ namespace AgroBase.Services
|
||||||
|
|
||||||
public void AtualizarConsumo(double distanciaTotalMetrosAtual)
|
public void AtualizarConsumo(double distanciaTotalMetrosAtual)
|
||||||
{
|
{
|
||||||
var dalyBms = DalyBMSService.DadosLeitura;
|
LerFontes();
|
||||||
bool bms_iniciado = dalyBms?.Iniciado ?? false;
|
|
||||||
DateTime? bms_ultima_leitura = dalyBms?.UltimoComandoRecebido;
|
|
||||||
double bms_tensao = dalyBms?.Pack?.TensaoTotal_V ?? 0;
|
|
||||||
double bms_corrente = dalyBms?.Pack?.Corrente_A ?? 0;
|
|
||||||
double bms_soc = dalyBms?.Pack?.SOC_percent ?? 0;
|
|
||||||
double bms_tmp = dalyBms?.TemperaturaMax ?? 0;
|
|
||||||
|
|
||||||
var sensor = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Sensores?.FirstOrDefault(x => x.ID == "AB36V");
|
|
||||||
bool sen_iniciado = sensor?.Inicializado ?? false;
|
|
||||||
DateTime? sen_ultima_leitura = sensor?.UltimaLeitura;
|
|
||||||
double sen_tensao = sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Tensao)?.atual?.valor ?? 0;
|
|
||||||
double sen_corrente = (sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Corrente)?.atual?.valor ?? 0) / 1000.0;
|
|
||||||
double sen_soc = Math.Round(
|
|
||||||
FuncoesMatematicas.Map(
|
|
||||||
sen_tensao,
|
|
||||||
VariaveisEquipamento.TensaoMinimaBateria,
|
|
||||||
VariaveisEquipamento.TensaoMaximaBateria,
|
|
||||||
0.0,
|
|
||||||
100.0), 2);
|
|
||||||
double sen_tmp = sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Temperatura)?.atual?.valor ?? 0;
|
|
||||||
|
|
||||||
Iniciado = bms_iniciado || sen_iniciado;
|
|
||||||
BmsLigado = bms_iniciado;
|
|
||||||
|
|
||||||
if (!Iniciado)
|
if (!Iniciado)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DateTime? leituraAtual = BmsLigado ? bms_ultima_leitura : sen_ultima_leitura;
|
DateTime? leituraAtual = ObterDataLeituraAtual();
|
||||||
TensaoInstantanea = BmsLigado ? bms_tensao : sen_tensao;
|
|
||||||
CorrenteInstantanea = BmsLigado ? bms_corrente : sen_corrente;
|
|
||||||
PotenciaInstantanea = TensaoInstantanea * CorrenteInstantanea;
|
|
||||||
PercentualBateria = FuncoesMatematicas.Clamp(BmsLigado ? bms_soc : sen_soc, 0, 100);
|
|
||||||
Temperatura = BmsLigado ? bms_tmp : sen_tmp;
|
|
||||||
|
|
||||||
if (!leituraAtual.HasValue || leituraAtual.Value == DateTime.MinValue)
|
if (!leituraAtual.HasValue || leituraAtual.Value == DateTime.MinValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Primeira leitura válida da instância
|
|
||||||
if (!_estadoInicializado)
|
if (!_estadoInicializado)
|
||||||
{
|
{
|
||||||
_socInicialInstancia = PercentualBateria;
|
InicializarEstado(leituraAtual.Value, distanciaTotalMetrosAtual);
|
||||||
_cargaInicialInstancia_C = CargaMaxima_C * (PercentualBateria / 100.0);
|
|
||||||
CargaAtual_C = _cargaInicialInstancia_C;
|
|
||||||
|
|
||||||
ConsumidoTotal_C = 0;
|
|
||||||
EnergiaConsumidaTotal_Wh = 0;
|
|
||||||
|
|
||||||
_ultimaLeituraIntegrada = leituraAtual.Value;
|
|
||||||
_estadoInicializado = true;
|
|
||||||
|
|
||||||
_dt = 0;
|
|
||||||
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Só integra se chegou leitura nova
|
|
||||||
if (_ultimaLeituraIntegrada.HasValue && leituraAtual.Value <= _ultimaLeituraIntegrada.Value)
|
if (_ultimaLeituraIntegrada.HasValue && leituraAtual.Value <= _ultimaLeituraIntegrada.Value)
|
||||||
{
|
{
|
||||||
_dt = 0;
|
_dt = 0;
|
||||||
|
|
@ -282,45 +283,160 @@ namespace AgroBase.Services
|
||||||
if (_dt <= 0 || _dt > 10)
|
if (_dt <= 0 || _dt > 10)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[COULOMB COUNTER] dt inválido: {_dt:F3}s");
|
Console.WriteLine($"[COULOMB COUNTER] dt inválido: {_dt:F3}s");
|
||||||
|
AtualizarCargaAtualPeloSocOuIntegrador();
|
||||||
|
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumindo descarga positiva. Se no Daly a descarga vier negativa, inverter aqui.
|
CorrenteDescarga_A = NormalizarCorrenteDescarga(CorrenteInstantanea);
|
||||||
double correnteDescarga_A = Math.Max(0, CorrenteInstantanea);
|
PotenciaDescarga_W = Math.Max(0, TensaoInstantanea * CorrenteDescarga_A);
|
||||||
|
|
||||||
|
double deltaCoulombs = CorrenteDescarga_A * _dt;
|
||||||
|
double deltaEnergia_Wh = PotenciaDescarga_W * _dt / 3600.0;
|
||||||
|
|
||||||
|
_consumidoIntegradoTotal_C = Clamp(_consumidoIntegradoTotal_C + deltaCoulombs, 0, CargaMaxima_C);
|
||||||
|
|
||||||
double deltaCoulombs = correnteDescarga_A * _dt;
|
|
||||||
ConsumidoTotal_C += deltaCoulombs;
|
|
||||||
ConsumidoTotal_C = FuncoesMatematicas.Clamp(ConsumidoTotal_C, 0, CargaMaxima_C);
|
|
||||||
if (OperacaoAtiva && !OperacaoFinalizada)
|
if (OperacaoAtiva && !OperacaoFinalizada)
|
||||||
{
|
_consumidoIntegradoOperacao_C = Clamp(_consumidoIntegradoOperacao_C + deltaCoulombs, 0, CargaMaxima_C);
|
||||||
ConsumidoOperacao_C += deltaCoulombs;
|
|
||||||
ConsumidoOperacao_C = FuncoesMatematicas.Clamp(ConsumidoOperacao_C, 0, CargaMaxima_C);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Estado absoluto do pack sempre baseado no total da instância
|
|
||||||
double cargaAtualCalculada = _cargaInicialInstancia_C - ConsumidoTotal_C;
|
|
||||||
CargaAtual_C = FuncoesMatematicas.Clamp(cargaAtualCalculada, 0, CargaMaxima_C);
|
|
||||||
|
|
||||||
double deltaEnergia_Wh = PotenciaInstantanea * _dt / 3600.0;
|
|
||||||
if (deltaEnergia_Wh > 0)
|
if (deltaEnergia_Wh > 0)
|
||||||
EnergiaConsumidaTotal_Wh += deltaEnergia_Wh;
|
EnergiaConsumidaTotal_Wh += deltaEnergia_Wh;
|
||||||
|
|
||||||
_historicoCorrente.Enqueue(correnteDescarga_A);
|
AtualizarCargaAtualPeloSocOuIntegrador();
|
||||||
if (_historicoCorrente.Count > BufferSize)
|
AtualizarHistoricos();
|
||||||
_historicoCorrente.Dequeue();
|
AtualizarTempoRestante();
|
||||||
|
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
||||||
|
}
|
||||||
|
|
||||||
double correnteMedia = _historicoCorrente.Count > 0
|
private void LerFontes()
|
||||||
? _historicoCorrente.Average()
|
{
|
||||||
: 0;
|
var dalyBms = DalyBMSService.DadosLeitura;
|
||||||
|
|
||||||
if (correnteMedia > 0 && CargaAtualAmp > 0)
|
bool bms_iniciado = dalyBms?.Iniciado ?? false;
|
||||||
TempoEstimadoMinutos = (CargaAtualAmp / correnteMedia) * 60.0;
|
DateTime? bms_ultima_leitura = dalyBms?.UltimoComandoRecebido;
|
||||||
else
|
double bms_tensao = dalyBms?.Pack?.TensaoTotal_V ?? 0;
|
||||||
TempoEstimadoMinutos = 0;
|
double bms_corrente = dalyBms?.Pack?.Corrente_A ?? 0;
|
||||||
|
double bms_soc = dalyBms?.Pack?.SOC_percent ?? 0;
|
||||||
|
double bms_tmp = dalyBms?.TemperaturaMax ?? 0;
|
||||||
|
|
||||||
|
var sensor = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Sensores?
|
||||||
|
.FirstOrDefault(x => x.ID == "AB36V");
|
||||||
|
|
||||||
|
bool sen_iniciado = sensor?.Inicializado ?? false;
|
||||||
|
DateTime? sen_ultima_leitura = sensor?.UltimaLeitura;
|
||||||
|
double sen_tensao = sensor?.ValoresLeituras?
|
||||||
|
.FirstOrDefault(x => x.funcao == FuncoesPinout.Tensao)?.atual?.valor ?? 0;
|
||||||
|
|
||||||
|
double sen_corrente = (sensor?.ValoresLeituras?
|
||||||
|
.FirstOrDefault(x => x.funcao == FuncoesPinout.Corrente)?.atual?.valor ?? 0) / 1000.0;
|
||||||
|
|
||||||
|
double sen_soc = Math.Round(
|
||||||
|
FuncoesMatematicas.Map(
|
||||||
|
sen_tensao,
|
||||||
|
VariaveisEquipamento.TensaoMinimaBateria,
|
||||||
|
VariaveisEquipamento.TensaoMaximaBateria,
|
||||||
|
0.0,
|
||||||
|
100.0), 2);
|
||||||
|
|
||||||
|
double sen_tmp = sensor?.ValoresLeituras?
|
||||||
|
.FirstOrDefault(x => x.funcao == FuncoesPinout.Temperatura)?.atual?.valor ?? 0;
|
||||||
|
|
||||||
|
Iniciado = bms_iniciado || sen_iniciado;
|
||||||
|
BmsLigado = bms_iniciado;
|
||||||
|
|
||||||
|
TensaoInstantanea = BmsLigado ? bms_tensao : sen_tensao;
|
||||||
|
CorrenteInstantanea = BmsLigado ? bms_corrente : sen_corrente;
|
||||||
|
PotenciaInstantanea = TensaoInstantanea * CorrenteInstantanea;
|
||||||
|
PercentualBateria = Clamp(BmsLigado ? bms_soc : sen_soc, 0, 100);
|
||||||
|
Temperatura = BmsLigado ? bms_tmp : sen_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime? ObterDataLeituraAtual()
|
||||||
|
{
|
||||||
|
var dalyBms = DalyBMSService.DadosLeitura;
|
||||||
|
|
||||||
|
if (BmsLigado)
|
||||||
|
return dalyBms?.UltimoComandoRecebido;
|
||||||
|
|
||||||
|
var sensor = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Sensores?
|
||||||
|
.FirstOrDefault(x => x.ID == "AB36V");
|
||||||
|
|
||||||
|
return sensor?.UltimaLeitura;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InicializarEstado(DateTime leituraAtual, double distanciaTotalMetrosAtual)
|
||||||
|
{
|
||||||
|
_socInicialInstancia = PercentualBateria;
|
||||||
|
|
||||||
|
AtualizarCargaAtualPeloSocOuIntegrador();
|
||||||
|
|
||||||
|
_consumidoIntegradoTotal_C = 0;
|
||||||
|
_consumidoIntegradoOperacao_C = 0;
|
||||||
|
EnergiaConsumidaTotal_Wh = 0;
|
||||||
|
|
||||||
|
_ultimaLeituraIntegrada = leituraAtual;
|
||||||
|
_estadoInicializado = true;
|
||||||
|
|
||||||
|
_distanciaTotalMetrosAnterior = distanciaTotalMetrosAtual;
|
||||||
|
_energiaConsumidaAnterior_Wh_Total = EnergiaConsumidaTotal_Wh;
|
||||||
|
|
||||||
|
_dt = 0;
|
||||||
|
|
||||||
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AtualizarCargaAtualPeloSocOuIntegrador()
|
||||||
|
{
|
||||||
|
if (CargaMaxima_C <= 0)
|
||||||
|
{
|
||||||
|
CargaAtual_C = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BmsLigado)
|
||||||
|
{
|
||||||
|
CargaAtual_C = CargaMaxima_C * (PercentualBateria / 100.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double cargaInicial = CargaMaxima_C * (_socInicialInstancia / 100.0);
|
||||||
|
CargaAtual_C = Clamp(cargaInicial - _consumidoIntegradoTotal_C, 0, CargaMaxima_C);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double NormalizarCorrenteDescarga(double corrente)
|
||||||
|
{
|
||||||
|
if (Math.Abs(corrente) < 0.05)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Daly normalmente pode reportar descarga negativa.
|
||||||
|
// Para autonomia, queremos magnitude da descarga.
|
||||||
|
return Math.Abs(corrente);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AtualizarHistoricos()
|
||||||
|
{
|
||||||
|
_historicoCorrenteDescarga.Enqueue(CorrenteDescarga_A);
|
||||||
|
if (_historicoCorrenteDescarga.Count > BufferSize)
|
||||||
|
_historicoCorrenteDescarga.Dequeue();
|
||||||
|
|
||||||
|
_historicoPotenciaDescarga.Enqueue(PotenciaDescarga_W);
|
||||||
|
if (_historicoPotenciaDescarga.Count > BufferSize)
|
||||||
|
_historicoPotenciaDescarga.Dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AtualizarTempoRestante()
|
||||||
|
{
|
||||||
|
double potenciaMedia_W = _historicoPotenciaDescarga.Count > 0
|
||||||
|
? _historicoPotenciaDescarga.Average()
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
if (potenciaMedia_W > 1 && WhRestante > 0)
|
||||||
|
TempoEstimadoMinutos = (WhRestante / potenciaMedia_W) * 60.0;
|
||||||
|
else
|
||||||
|
TempoEstimadoMinutos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
private void AtualizarAutonomia(double distanciaTotalMetrosAtual)
|
private void AtualizarAutonomia(double distanciaTotalMetrosAtual)
|
||||||
{
|
{
|
||||||
if (!_estadoInicializado)
|
if (!_estadoInicializado)
|
||||||
|
|
@ -337,6 +453,7 @@ namespace AgroBase.Services
|
||||||
{
|
{
|
||||||
_historicoDeltaDist_m.Enqueue(deltaDist_m);
|
_historicoDeltaDist_m.Enqueue(deltaDist_m);
|
||||||
_historicoDeltaWh.Enqueue(deltaWh);
|
_historicoDeltaWh.Enqueue(deltaWh);
|
||||||
|
|
||||||
_somaDistanciaJanela_m += deltaDist_m;
|
_somaDistanciaJanela_m += deltaDist_m;
|
||||||
_somaEnergiaJanela_Wh += deltaWh;
|
_somaEnergiaJanela_Wh += deltaWh;
|
||||||
|
|
||||||
|
|
@ -366,38 +483,12 @@ namespace AgroBase.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetarHistoricosAutonomia()
|
|
||||||
{
|
|
||||||
_historicoCorrente.Clear();
|
|
||||||
|
|
||||||
_historicoDeltaDist_m.Clear();
|
|
||||||
_historicoDeltaWh.Clear();
|
|
||||||
_somaDistanciaJanela_m = 0;
|
|
||||||
_somaEnergiaJanela_Wh = 0;
|
|
||||||
|
|
||||||
_distanciaTotalMetrosAnterior = 0;
|
|
||||||
_energiaConsumidaAnterior_Wh_Total = EnergiaConsumidaTotal_Wh;
|
|
||||||
|
|
||||||
WhPorMetro = 0;
|
|
||||||
WhPorMetroHistorico = 0;
|
|
||||||
DistanciaMaximaTeorica_m = 0;
|
|
||||||
DistanciaMaximaSegura_m = 0;
|
|
||||||
DistanciaEstimadaRestante_m = 0;
|
|
||||||
|
|
||||||
TempoEstimadoMinutos = 0;
|
|
||||||
_dt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AtualizarValorConsumidoTotal(double consumoTotal_Ah)
|
public void AtualizarValorConsumidoTotal(double consumoTotal_Ah)
|
||||||
{
|
{
|
||||||
double coulombsConsumidos = consumoTotal_Ah * 3600.0;
|
double coulombsConsumidos = consumoTotal_Ah * 3600.0;
|
||||||
ConsumidoTotal_C = FuncoesMatematicas.Clamp(coulombsConsumidos, 0, CargaMaxima_C);
|
_consumidoIntegradoTotal_C = Clamp(coulombsConsumidos, 0, CargaMaxima_C);
|
||||||
|
|
||||||
if (_estadoInicializado)
|
AtualizarCargaAtualPeloSocOuIntegrador();
|
||||||
{
|
|
||||||
double cargaAtualCalculada = _cargaInicialInstancia_C - ConsumidoTotal_C;
|
|
||||||
CargaAtual_C = FuncoesMatematicas.Clamp(cargaAtualCalculada, 0, CargaMaxima_C);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ConseguePercorrer(double distanciaRequerida_m)
|
public bool ConseguePercorrer(double distanciaRequerida_m)
|
||||||
|
|
@ -408,5 +499,65 @@ namespace AgroBase.Services
|
||||||
return DistanciaMaximaSegura_m >= distanciaRequerida_m;
|
return DistanciaMaximaSegura_m >= distanciaRequerida_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ResetarTudo()
|
||||||
|
{
|
||||||
|
Iniciado = false;
|
||||||
|
BmsLigado = false;
|
||||||
|
OperacaoAtiva = false;
|
||||||
|
OperacaoFinalizada = false;
|
||||||
|
|
||||||
|
_estadoInicializado = false;
|
||||||
|
_ultimaLeituraIntegrada = null;
|
||||||
|
|
||||||
|
CargaAtual_C = 0;
|
||||||
|
_socInicialInstancia = 0;
|
||||||
|
_socInicialOperacao = 0;
|
||||||
|
|
||||||
|
_consumidoIntegradoTotal_C = 0;
|
||||||
|
_consumidoIntegradoOperacao_C = 0;
|
||||||
|
|
||||||
|
EnergiaConsumidaTotal_Wh = 0;
|
||||||
|
_energiaConsumidaInicioOperacao_Wh = 0;
|
||||||
|
_energiaConsumidaFimOperacao_Wh = 0;
|
||||||
|
|
||||||
|
PercentualBateria = 0;
|
||||||
|
Temperatura = 0;
|
||||||
|
CorrenteInstantanea = 0;
|
||||||
|
CorrenteDescarga_A = 0;
|
||||||
|
TensaoInstantanea = 0;
|
||||||
|
PotenciaInstantanea = 0;
|
||||||
|
PotenciaDescarga_W = 0;
|
||||||
|
TempoEstimadoMinutos = 0;
|
||||||
|
_dt = 0;
|
||||||
|
|
||||||
|
ResetarHistoricosAutonomia();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetarHistoricosAutonomia()
|
||||||
|
{
|
||||||
|
_historicoCorrenteDescarga.Clear();
|
||||||
|
_historicoPotenciaDescarga.Clear();
|
||||||
|
|
||||||
|
_historicoDeltaDist_m.Clear();
|
||||||
|
_historicoDeltaWh.Clear();
|
||||||
|
|
||||||
|
_somaDistanciaJanela_m = 0;
|
||||||
|
_somaEnergiaJanela_Wh = 0;
|
||||||
|
|
||||||
|
_distanciaTotalMetrosAnterior = 0;
|
||||||
|
_energiaConsumidaAnterior_Wh_Total = 0;
|
||||||
|
|
||||||
|
WhPorMetro = 0;
|
||||||
|
WhPorMetroHistorico = 0;
|
||||||
|
|
||||||
|
DistanciaMaximaTeorica_m = 0;
|
||||||
|
DistanciaMaximaSegura_m = 0;
|
||||||
|
DistanciaEstimadaRestante_m = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double Clamp(double value, double min, double max)
|
||||||
|
{
|
||||||
|
return FuncoesMatematicas.Clamp(value, min, max);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -107,8 +107,8 @@ namespace AgroBase.Services
|
||||||
string[] comandos = {
|
string[] comandos = {
|
||||||
// Bauds
|
// Bauds
|
||||||
$"config com1 115200\r\n",
|
$"config com1 115200\r\n",
|
||||||
$"config {porta_usb} 115200\r\n",
|
$"config com2 115200\r\n",
|
||||||
$"config {porta_entrada} 115200\r\n",
|
$"config com3 115200\r\n",
|
||||||
|
|
||||||
// limpa logs das portas
|
// limpa logs das portas
|
||||||
$"unlog com1\r\n",
|
$"unlog com1\r\n",
|
||||||
|
|
@ -158,8 +158,9 @@ namespace AgroBase.Services
|
||||||
string distancia_min = "0";
|
string distancia_min = "0";
|
||||||
string[] comandos = {
|
string[] comandos = {
|
||||||
// Bauds
|
// Bauds
|
||||||
$"config {porta_usb} 115200\r\n",
|
$"config com1 115200\r\n",
|
||||||
$"config {porta_saida} 115200\r\n",
|
$"config com2 115200\r\n",
|
||||||
|
$"config com3 115200\r\n",
|
||||||
|
|
||||||
// limpa logs das portas
|
// limpa logs das portas
|
||||||
$"unlog com1\r\n",
|
$"unlog com1\r\n",
|
||||||
|
|
|
||||||
|
|
@ -9,138 +9,129 @@ namespace AgroBase.Services
|
||||||
{
|
{
|
||||||
public class HerbicideCounterService
|
public class HerbicideCounterService
|
||||||
{
|
{
|
||||||
public HerbicideCounterService(double capacidadeLitros, double densidadeProduto, double l_m_base = 0.1188) // 3km/h ~ 3x 33 ml/s
|
public HerbicideCounterService(double capacidadeLitros, double densidadeProduto, double vazaoPorBicoBase_mLs = 33.0)
|
||||||
{
|
{
|
||||||
CapacidadeLitros = capacidadeLitros;
|
CapacidadeLitros = capacidadeLitros;
|
||||||
VolumeAtual_L = 0;
|
|
||||||
VolumeConsumido_L = 0;
|
|
||||||
DensidadeProduto = densidadeProduto;
|
DensidadeProduto = densidadeProduto;
|
||||||
LPorMetroBase = l_m_base;
|
|
||||||
|
|
||||||
MargemSegurancaAutonomia = 0.30; // 30% por padrão
|
QuantidadeBicos = VariaveisEquipamento.QuantidadeBicosPulverizadores;
|
||||||
|
|
||||||
|
VazaoPorBicoBase_mLs = vazaoPorBicoBase_mLs;
|
||||||
|
VazaoPorBicoBase_LMin = vazaoPorBicoBase_mLs * 60.0 / 1000.0;
|
||||||
|
VazaoTotalTodosBicos_LMin = VazaoPorBicoBase_LMin * QuantidadeBicos;
|
||||||
|
|
||||||
|
MargemSegurancaAutonomia = 0.30;
|
||||||
|
|
||||||
|
ResetarTudo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Iniciado { get; private set; }
|
public bool Iniciado { get; private set; }
|
||||||
|
public bool OperacaoAtiva { get; private set; }
|
||||||
|
public bool OperacaoFinalizada { get; private set; }
|
||||||
|
|
||||||
// ---------- CONFIGURAÇÕES / ESTADO BÁSICO ----------
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Capacidade máxima do reservatório em litros.
|
|
||||||
/// </summary>
|
|
||||||
public double CapacidadeLitros { get; }
|
public double CapacidadeLitros { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Densidade do produto.
|
|
||||||
/// </summary>
|
|
||||||
public double DensidadeProduto { get; }
|
public double DensidadeProduto { get; }
|
||||||
|
|
||||||
/// <summary>
|
public int QuantidadeBicos { get; }
|
||||||
/// Massa atual lida no reservatório (Kg).
|
|
||||||
/// </summary>
|
public double VazaoPorBicoBase_mLs { get; }
|
||||||
|
public double VazaoPorBicoBase_LMin { get; }
|
||||||
|
public double VazaoTotalTodosBicos_LMin { get; }
|
||||||
|
|
||||||
public double MassaAtual_Kg { get; private set; }
|
public double MassaAtual_Kg { get; private set; }
|
||||||
public double MassaAtual_Kg_Calc { get; private set; }
|
public double MassaAtual_Kg_Calc { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Volume atual estimado no reservatório (L).
|
|
||||||
/// </summary>
|
|
||||||
public double VolumeAtual_L { get; private set; }
|
public double VolumeAtual_L { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
private double _volumeInicialInstancia_L;
|
||||||
/// Volume total consumido desde o início (L).
|
private double _volumeInicialOperacao_L;
|
||||||
/// </summary>
|
|
||||||
public double VolumeConsumido_L { get; private set; }
|
public double VolumeConsumidoTotal_L => Math.Max(0, _volumeInicialInstancia_L - VolumeAtual_L);
|
||||||
|
|
||||||
|
public double VolumeConsumidoOperacao_L
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!OperacaoAtiva && !OperacaoFinalizada)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Math.Max(0, _volumeInicialOperacao_L - VolumeAtual_L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public double PercentualAtual
|
public double PercentualAtual
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (CapacidadeLitros <= 0) return 0;
|
if (CapacidadeLitros <= 0) return 0;
|
||||||
var p = (VolumeAtual_L / CapacidadeLitros) * 100.0;
|
return Clamp((VolumeAtual_L / CapacidadeLitros) * 100.0, 0, 100);
|
||||||
return FuncoesMatematicas.Clamp(p, 0, 100);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double PercentualConsumido
|
public double PercentualConsumidoTotal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return 100.0 - PercentualAtual;
|
if (CapacidadeLitros <= 0) return 0;
|
||||||
|
return Clamp((VolumeConsumidoTotal_L / CapacidadeLitros) * 100.0, 0, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double HerbicidaPorAtuacao { get; private set; }
|
public double PercentualConsumidoOperacao
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (CapacidadeLitros <= 0) return 0;
|
||||||
|
return Clamp((VolumeConsumidoOperacao_L / CapacidadeLitros) * 100.0, 0, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double PercentualConsumidoOperacaoDaCargaInicial
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_volumeInicialOperacao_L <= 0) return 0;
|
||||||
|
return Clamp((VolumeConsumidoOperacao_L / _volumeInicialOperacao_L) * 100.0, 0, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int BicosAtivos { get; private set; }
|
||||||
|
public bool Pulverizando { get; private set; }
|
||||||
|
public bool PulverizadorLiberado { get; private set; }
|
||||||
|
|
||||||
|
public double VazaoFluxoAtual_mLs { get; private set; }
|
||||||
|
public double VazaoFluxoAtual_LMin => VazaoFluxoAtual_mLs * 60.0 / 1000.0;
|
||||||
|
|
||||||
|
public double VazaoEstimativaBicos_mLs { get; private set; }
|
||||||
|
public double VazaoReferencia_mLs { get; private set; }
|
||||||
|
|
||||||
|
public double LPorMinuto { get; private set; }
|
||||||
|
public double LPorMinutoEstimadoBicos { get; private set; }
|
||||||
|
|
||||||
|
public double LPorMetro { get; private set; }
|
||||||
|
public double LPorMetroHistorico { get; private set; }
|
||||||
|
public double LPorMetroBase { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Margem de segurança para estimativa (0.30 = 30%).
|
|
||||||
/// </summary>
|
|
||||||
public double MargemSegurancaAutonomia { get; set; }
|
public double MargemSegurancaAutonomia { get; set; }
|
||||||
|
|
||||||
// ---------- AUTONOMIA EM METROS (L/m) ----------
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Consumo médio de herbicida por metro pulverizado (L/m),
|
|
||||||
/// calculado numa janela móvel de distância.
|
|
||||||
/// </summary>
|
|
||||||
public double LPorMetro { get; private set; }
|
|
||||||
|
|
||||||
public double LPorMetroBase { get; set; }
|
|
||||||
public double LPorMetroHistorico { get; private set; }
|
|
||||||
|
|
||||||
public double LPorMetroReferencia
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (LPorMetro > 0) return LPorMetro;
|
|
||||||
if (LPorMetroHistorico > 0) return LPorMetroHistorico;
|
|
||||||
return LPorMetroBase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Distância máxima teórica que ainda pode ser pulverizada (sem margem), em metros.
|
|
||||||
/// </summary>
|
|
||||||
public double DistanciaMaximaTeorica_m { get; private set; }
|
public double DistanciaMaximaTeorica_m { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Distância máxima segura que ainda pode ser pulverizada (com margem), em metros.
|
|
||||||
/// </summary>
|
|
||||||
public double DistanciaMaximaSegura_m { get; private set; }
|
public double DistanciaMaximaSegura_m { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Alias mais descritivo para uso direto pelo Manager.
|
|
||||||
/// </summary>
|
|
||||||
public double DistanciaEstimadaRestantePulverizando_m => DistanciaMaximaSegura_m;
|
public double DistanciaEstimadaRestantePulverizando_m => DistanciaMaximaSegura_m;
|
||||||
|
|
||||||
// ---------- AUTONOMIA EM TEMPO (L/min) ----------
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Consumo médio de herbicida por minuto (L/min) durante pulverização.
|
|
||||||
/// </summary>
|
|
||||||
public double LPorMinuto { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tempo estimado restante pulverizando, em minutos.
|
|
||||||
/// </summary>
|
|
||||||
public double TempoEstimadoMinutosPulverizando { get; private set; }
|
public double TempoEstimadoMinutosPulverizando { get; private set; }
|
||||||
|
|
||||||
// ---------- JANELAS DE MÉDIA MÓVEL ----------
|
public double HerbicidaPorAtuacao_L { get; private set; }
|
||||||
|
|
||||||
// Distância: vamos usar uma janela de ~50 m (mesma ideia da bateria)
|
|
||||||
private const double JanelaAutonomia_m = 50.0;
|
private const double JanelaAutonomia_m = 50.0;
|
||||||
|
|
||||||
// Tempo: janela de ~60 s pulverizando
|
|
||||||
private const double JanelaTempo_s = 60.0;
|
private const double JanelaTempo_s = 60.0;
|
||||||
|
|
||||||
private readonly Queue<(double deltaDist_m, double deltaVol_L)> _janelaDist = new Queue<(double deltaDist_m, double deltaVol_L)>();
|
private readonly Queue<(double dist_m, double vol_L)> _janelaDist = new Queue<(double dist_m, double vol_L)>();
|
||||||
private readonly Queue<(double deltaTempo_s, double deltaVol_L)> _janelaTempo = new Queue<(double deltaTempo_s, double deltaVol_L)>();
|
private readonly Queue<(double tempo_s, double vol_L)> _janelaTempo = new Queue<(double tempo_s, double vol_L)>();
|
||||||
|
|
||||||
private double _somaDistanciaJanela_m;
|
private double _somaDistanciaJanela_m;
|
||||||
private double _somaVolumeDistJanela_L;
|
private double _somaVolumeDistJanela_L;
|
||||||
|
|
||||||
private double _somaTempoJanela_s;
|
private double _somaTempoJanela_s;
|
||||||
private double _somaVolumeTempoJanela_L;
|
private double _somaVolumeTempoJanela_L;
|
||||||
|
|
||||||
// Valores anteriores para cálculo de deltas
|
|
||||||
private double _volumeAnterior_L;
|
private double _volumeAnterior_L;
|
||||||
private double _distanciaTotalAnterior_m;
|
private double _distanciaTotalAnterior_m;
|
||||||
private double _tempoTotalAnterior_s;
|
private double _tempoTotalAnterior_s;
|
||||||
|
|
@ -148,192 +139,258 @@ namespace AgroBase.Services
|
||||||
private bool _inicializado;
|
private bool _inicializado;
|
||||||
|
|
||||||
private SensorModel SensorMassaReservatorio => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.Sensores?.FirstOrDefault(x => x.Componente == S_Code.sMAS && x.ID == "MASRS");
|
private SensorModel SensorMassaReservatorio => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.Sensores?.FirstOrDefault(x => x.Componente == S_Code.sMAS && x.ID == "MASRS");
|
||||||
public AtuadorBombaModel AgitadorCalda => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BombasPressurizadoras?.FirstOrDefault(x => x.ID == "AGTCLD");
|
|
||||||
public bool PulverizadorLiberado { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public AtuadorBombaModel AgitadorCalda => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BombasPressurizadoras?.FirstOrDefault(x => x.ID == "AGTCLD");
|
||||||
/// Atualiza o estado do sistema de herbicida.
|
|
||||||
///
|
public void IniciarOperacao(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual)
|
||||||
/// Chamar periodicamente com:
|
{
|
||||||
/// - volumeMedido_L: leitura de nível atual do reservatório (L)
|
if (!_inicializado)
|
||||||
/// - pulverizando: true se algum bico está ativo
|
return;
|
||||||
/// - distanciaTotalMetrosAtual: distância total acumulada (m)
|
|
||||||
/// - tempoTotalSegundosAtual: tempo total de operação (s)
|
_volumeInicialOperacao_L = VolumeAtual_L;
|
||||||
/// </summary>
|
|
||||||
public void AtualizarConsumo(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual)
|
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
||||||
|
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
||||||
|
|
||||||
|
OperacaoAtiva = true;
|
||||||
|
OperacaoFinalizada = false;
|
||||||
|
|
||||||
|
ResetarJanelas();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinalizarOperacao()
|
||||||
|
{
|
||||||
|
if (!OperacaoAtiva)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OperacaoAtiva = false;
|
||||||
|
OperacaoFinalizada = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AtualizarConsumo(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual, double velocidadeAtual_m_s)
|
||||||
{
|
{
|
||||||
Iniciado = SensorMassaReservatorio?.Inicializado ?? false;
|
Iniciado = SensorMassaReservatorio?.Inicializado ?? false;
|
||||||
|
|
||||||
if (!Iniciado)
|
if (!Iniciado)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool pulverizando = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Any(x => x.Inicializado && x._EstadoLeitura == Estado.Ligado) ?? false;
|
LerReservatorio(out double massaLida_Kg, out double massaCalc_Kg, out double volumeMedido_L);
|
||||||
double massaLida_Kg = SensorMassaReservatorio?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Massa)?.atual?.valor ?? 0;
|
|
||||||
double massaLida_Kg_bruto = SensorMassaReservatorio?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraBruta)?.atual?.valor ?? 0;
|
|
||||||
|
|
||||||
double.TryParse(SensorMassaReservatorio.Parametros.FirstOrDefault(x => x.Descricao == "Offset")?.Valor ?? "0", out double offset);
|
|
||||||
double massa_calc = (massaLida_Kg_bruto * 1) + offset;
|
|
||||||
|
|
||||||
double volumeMedido_L = massa_calc / DensidadeProduto;
|
|
||||||
int qtd_atuacoes = Variaveis.OperacaoEmAndamento.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0;
|
|
||||||
|
|
||||||
// Sanitiza volume
|
|
||||||
if (volumeMedido_L < 0) volumeMedido_L = 0;
|
|
||||||
if (volumeMedido_L > CapacidadeLitros) volumeMedido_L = CapacidadeLitros;
|
|
||||||
|
|
||||||
// Inicialização
|
|
||||||
if (!_inicializado)
|
|
||||||
{
|
|
||||||
_inicializado = true;
|
|
||||||
_volumeAnterior_L = volumeMedido_L;
|
|
||||||
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
|
||||||
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
|
||||||
|
|
||||||
MassaAtual_Kg = massaLida_Kg;
|
MassaAtual_Kg = massaLida_Kg;
|
||||||
MassaAtual_Kg_Calc = massa_calc;
|
MassaAtual_Kg_Calc = massaCalc_Kg;
|
||||||
VolumeAtual_L = volumeMedido_L;
|
VolumeAtual_L = volumeMedido_L;
|
||||||
|
|
||||||
|
BicosAtivos = ObterQuantidadeBicosAtivos();
|
||||||
|
Pulverizando = BicosAtivos > 0;
|
||||||
|
|
||||||
|
VazaoFluxoAtual_mLs = ObterVazaoFluxo_mLs();
|
||||||
|
VazaoEstimativaBicos_mLs = BicosAtivos * VazaoPorBicoBase_mLs;
|
||||||
|
VazaoReferencia_mLs = VazaoFluxoAtual_mLs > 0
|
||||||
|
? VazaoFluxoAtual_mLs
|
||||||
|
: VazaoEstimativaBicos_mLs;
|
||||||
|
|
||||||
|
LPorMinutoEstimadoBicos = VazaoEstimativaBicos_mLs * 60.0 / 1000.0;
|
||||||
|
|
||||||
|
PulverizadorLiberado =
|
||||||
|
PercentualAtual >= VariaveisEquipamento.PercentualReservatorioMinCritio;
|
||||||
|
|
||||||
|
if (!_inicializado)
|
||||||
|
{
|
||||||
|
Inicializar(distanciaTotalMetrosAtual, tempoTotalSegundosAtual);
|
||||||
|
AtualizarAutonomia(velocidadeAtual_m_s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MassaAtual_Kg = massaLida_Kg;
|
double deltaVolumeMassa_L = Math.Max(0, _volumeAnterior_L - VolumeAtual_L);
|
||||||
MassaAtual_Kg_Calc = massa_calc;
|
_volumeAnterior_L = VolumeAtual_L;
|
||||||
VolumeAtual_L = volumeMedido_L;
|
|
||||||
|
|
||||||
PulverizadorLiberado = PercentualAtual >= VariaveisEquipamento.PercentualReservatorioMinCritio;
|
double deltaDist_m = Math.Max(0, distanciaTotalMetrosAtual - _distanciaTotalAnterior_m);
|
||||||
|
|
||||||
// --- Cálculo de deltas básicos ---
|
|
||||||
|
|
||||||
double deltaVolume_L = 0.0;
|
|
||||||
double diffVol = _volumeAnterior_L - volumeMedido_L;
|
|
||||||
|
|
||||||
// Só considera volume consumido (queda de nível) e apenas quando pulverizando
|
|
||||||
if (pulverizando && diffVol > 0)
|
|
||||||
{
|
|
||||||
deltaVolume_L = diffVol;
|
|
||||||
VolumeConsumido_L += deltaVolume_L;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qtd_atuacoes > 0)
|
|
||||||
{
|
|
||||||
HerbicidaPorAtuacao = VolumeConsumido_L / qtd_atuacoes;
|
|
||||||
}
|
|
||||||
|
|
||||||
_volumeAnterior_L = volumeMedido_L;
|
|
||||||
|
|
||||||
double deltaDist_m = distanciaTotalMetrosAtual - _distanciaTotalAnterior_m;
|
|
||||||
if (deltaDist_m < 0) deltaDist_m = 0;
|
|
||||||
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
||||||
|
|
||||||
double deltaTempo_s = tempoTotalSegundosAtual - _tempoTotalAnterior_s;
|
double deltaTempo_s = Math.Max(0, tempoTotalSegundosAtual - _tempoTotalAnterior_s);
|
||||||
if (deltaTempo_s < 0) deltaTempo_s = 0;
|
|
||||||
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
||||||
|
|
||||||
// --- Atualiza janela de distância (L/m) ---
|
double deltaVolumeFluxo_L = 0;
|
||||||
AtualizarJanelaDistancia(deltaDist_m, deltaVolume_L, pulverizando);
|
|
||||||
|
|
||||||
// --- Atualiza janela de tempo (L/min) ---
|
if (Pulverizando && deltaTempo_s > 0 && VazaoReferencia_mLs > 0)
|
||||||
AtualizarJanelaTempo(deltaTempo_s, deltaVolume_L, pulverizando);
|
deltaVolumeFluxo_L = VazaoReferencia_mLs * deltaTempo_s / 1000.0;
|
||||||
|
|
||||||
// --- Atualiza métricas de autonomia ---
|
double deltaVolumeParaTaxa_L = EscolherDeltaVolumeParaTaxa(deltaVolumeMassa_L, deltaVolumeFluxo_L);
|
||||||
AtualizarAutonomia();
|
|
||||||
|
if (Pulverizando && deltaVolumeParaTaxa_L > 0)
|
||||||
|
{
|
||||||
|
AtualizarJanelaDistancia(deltaDist_m, deltaVolumeParaTaxa_L);
|
||||||
|
AtualizarJanelaTempo(deltaTempo_s, deltaVolumeParaTaxa_L);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AtualizarJanelaDistancia(double deltaDist_m, double deltaVolume_L, bool pulverizando)
|
AtualizarHerbicidaPorAtuacao();
|
||||||
|
AtualizarAutonomia(velocidadeAtual_m_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double EscolherDeltaVolumeParaTaxa(double deltaMassa_L, double deltaFluxo_L)
|
||||||
{
|
{
|
||||||
// Só faz sentido atualizar se o robô andou e estava pulverizando
|
if (deltaFluxo_L > 0)
|
||||||
if (!pulverizando || deltaDist_m <= 0 || deltaVolume_L <= 0)
|
return deltaFluxo_L;
|
||||||
|
|
||||||
|
return deltaMassa_L;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LerReservatorio(out double massaLida_Kg, out double massaCalc_Kg, out double volumeMedido_L)
|
||||||
|
{
|
||||||
|
massaLida_Kg = SensorMassaReservatorio?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Massa)?.atual?.valor ?? 0;
|
||||||
|
|
||||||
|
double leituraBruta = SensorMassaReservatorio?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraBruta)?.atual?.valor ?? 0;
|
||||||
|
|
||||||
|
double.TryParse(SensorMassaReservatorio?.Parametros?.FirstOrDefault(x => x.Descricao == "Offset")?.Valor ?? "0", out double offset);
|
||||||
|
|
||||||
|
massaCalc_Kg = leituraBruta + offset;
|
||||||
|
|
||||||
|
volumeMedido_L = DensidadeProduto > 0 ? massaCalc_Kg / DensidadeProduto : 0;
|
||||||
|
|
||||||
|
volumeMedido_L = Clamp(volumeMedido_L, 0, CapacidadeLitros);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double ObterVazaoFluxo_mLs()
|
||||||
|
{
|
||||||
|
var dados = Variaveis.OperacaoEmAndamento.DispAtu?.Dados;
|
||||||
|
|
||||||
|
if (dados == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
double vazao = dados.VazaoFluxoMLpSReferencia;
|
||||||
|
|
||||||
|
if (vazao < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return vazao;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ObterQuantidadeBicosAtivos()
|
||||||
|
{
|
||||||
|
return Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Count(x => x.Inicializado && x.ComandoAtuar) ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Inicializar(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual)
|
||||||
|
{
|
||||||
|
_inicializado = true;
|
||||||
|
|
||||||
|
_volumeInicialInstancia_L = VolumeAtual_L;
|
||||||
|
_volumeAnterior_L = VolumeAtual_L;
|
||||||
|
|
||||||
|
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
||||||
|
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AtualizarJanelaDistancia(double deltaDist_m, double deltaVolume_L)
|
||||||
|
{
|
||||||
|
if (deltaDist_m <= 0 || deltaVolume_L <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_janelaDist.Enqueue((deltaDist_m, deltaVolume_L));
|
_janelaDist.Enqueue((deltaDist_m, deltaVolume_L));
|
||||||
|
|
||||||
_somaDistanciaJanela_m += deltaDist_m;
|
_somaDistanciaJanela_m += deltaDist_m;
|
||||||
_somaVolumeDistJanela_L += deltaVolume_L;
|
_somaVolumeDistJanela_L += deltaVolume_L;
|
||||||
|
|
||||||
// Mantém a janela limitada a JanelaAutonomia_m
|
|
||||||
while (_somaDistanciaJanela_m > JanelaAutonomia_m && _janelaDist.Count > 0)
|
while (_somaDistanciaJanela_m > JanelaAutonomia_m && _janelaDist.Count > 0)
|
||||||
{
|
{
|
||||||
var (dOld, vOld) = _janelaDist.Dequeue();
|
var old = _janelaDist.Dequeue();
|
||||||
_somaDistanciaJanela_m -= dOld;
|
|
||||||
_somaVolumeDistJanela_L -= vOld;
|
_somaDistanciaJanela_m -= old.dist_m;
|
||||||
|
_somaVolumeDistJanela_L -= old.vol_L;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_somaDistanciaJanela_m > 0 && _somaVolumeDistJanela_L > 0)
|
if (_somaDistanciaJanela_m > 0.5)
|
||||||
{
|
{
|
||||||
LPorMetro = _somaVolumeDistJanela_L / _somaDistanciaJanela_m;
|
LPorMetro = _somaVolumeDistJanela_L / _somaDistanciaJanela_m;
|
||||||
|
|
||||||
double alpha = 0.2;
|
const double alpha = 0.2;
|
||||||
if (LPorMetroHistorico <= 0)
|
|
||||||
LPorMetroHistorico = LPorMetro;
|
LPorMetroHistorico = LPorMetroHistorico <= 0
|
||||||
else
|
? LPorMetro
|
||||||
LPorMetroHistorico = LPorMetroHistorico * (1 - alpha) + LPorMetro * alpha;
|
: LPorMetroHistorico * (1.0 - alpha) + LPorMetro * alpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AtualizarJanelaTempo(double deltaTempo_s, double deltaVolume_L, bool pulverizando)
|
private void AtualizarJanelaTempo(double deltaTempo_s, double deltaVolume_L)
|
||||||
{
|
{
|
||||||
// Só faz sentido atualizar se o tempo avançou, estava pulverizando e houve consumo
|
if (deltaTempo_s <= 0 || deltaVolume_L <= 0)
|
||||||
if (!pulverizando || deltaTempo_s <= 0 || deltaVolume_L <= 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_janelaTempo.Enqueue((deltaTempo_s, deltaVolume_L));
|
_janelaTempo.Enqueue((deltaTempo_s, deltaVolume_L));
|
||||||
|
|
||||||
_somaTempoJanela_s += deltaTempo_s;
|
_somaTempoJanela_s += deltaTempo_s;
|
||||||
_somaVolumeTempoJanela_L += deltaVolume_L;
|
_somaVolumeTempoJanela_L += deltaVolume_L;
|
||||||
|
|
||||||
// Mantém a janela de tempo limitada a JanelaTempo_s
|
|
||||||
while (_somaTempoJanela_s > JanelaTempo_s && _janelaTempo.Count > 0)
|
while (_somaTempoJanela_s > JanelaTempo_s && _janelaTempo.Count > 0)
|
||||||
{
|
{
|
||||||
var (tOld, vOld) = _janelaTempo.Dequeue();
|
var old = _janelaTempo.Dequeue();
|
||||||
_somaTempoJanela_s -= tOld;
|
|
||||||
_somaVolumeTempoJanela_L -= vOld;
|
_somaTempoJanela_s -= old.tempo_s;
|
||||||
|
_somaVolumeTempoJanela_L -= old.vol_L;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_somaTempoJanela_s > 0 && _somaVolumeTempoJanela_L > 0)
|
if (_somaTempoJanela_s > 1.0)
|
||||||
{
|
|
||||||
// L/s * 60 = L/min
|
|
||||||
LPorMinuto = (_somaVolumeTempoJanela_L / _somaTempoJanela_s) * 60.0;
|
LPorMinuto = (_somaVolumeTempoJanela_L / _somaTempoJanela_s) * 60.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AtualizarHerbicidaPorAtuacao()
|
||||||
|
{
|
||||||
|
int qtdAtuacoes = Variaveis.OperacaoEmAndamento.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0;
|
||||||
|
|
||||||
|
if (qtdAtuacoes > 0)
|
||||||
|
HerbicidaPorAtuacao_L = VolumeConsumidoOperacao_L / qtdAtuacoes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AtualizarAutonomia()
|
private void AtualizarAutonomia(double velocidadeAtual_m_s)
|
||||||
{
|
{
|
||||||
// ----- Distância máxima pulverizando (m) -----
|
double consumoRef_LPorMetro = CalcularLPorMetroReferencia(velocidadeAtual_m_s);
|
||||||
if (VolumeAtual_L > 0 && LPorMetro > 0)
|
|
||||||
{
|
|
||||||
DistanciaMaximaTeorica_m = VolumeAtual_L / LPorMetro;
|
|
||||||
|
|
||||||
double margem = FuncoesMatematicas.Clamp(MargemSegurancaAutonomia, 0.0, 0.9);
|
|
||||||
DistanciaMaximaSegura_m = DistanciaMaximaTeorica_m * (1.0 - margem);
|
|
||||||
if (DistanciaMaximaSegura_m < 0)
|
|
||||||
DistanciaMaximaSegura_m = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DistanciaMaximaTeorica_m = 0;
|
|
||||||
DistanciaMaximaSegura_m = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- Tempo máximo pulverizando (min) -----
|
|
||||||
double consumoRef_LPorMetro = LPorMetroReferencia;
|
|
||||||
|
|
||||||
if (VolumeAtual_L > 0 && consumoRef_LPorMetro > 0)
|
if (VolumeAtual_L > 0 && consumoRef_LPorMetro > 0)
|
||||||
{
|
{
|
||||||
DistanciaMaximaTeorica_m = VolumeAtual_L / consumoRef_LPorMetro;
|
DistanciaMaximaTeorica_m = VolumeAtual_L / consumoRef_LPorMetro;
|
||||||
|
|
||||||
double margem = FuncoesMatematicas.Clamp(MargemSegurancaAutonomia, 0.0, 0.9);
|
double margem = Clamp(MargemSegurancaAutonomia, 0.0, 0.9);
|
||||||
DistanciaMaximaSegura_m = DistanciaMaximaTeorica_m * (1.0 - margem);
|
DistanciaMaximaSegura_m = DistanciaMaximaTeorica_m * (1.0 - margem);
|
||||||
if (DistanciaMaximaSegura_m < 0)
|
|
||||||
DistanciaMaximaSegura_m = 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DistanciaMaximaTeorica_m = 0;
|
DistanciaMaximaTeorica_m = 0;
|
||||||
DistanciaMaximaSegura_m = 0;
|
DistanciaMaximaSegura_m = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double consumoTempoRef_LMin = LPorMinuto > 0
|
||||||
|
? LPorMinuto
|
||||||
|
: LPorMinutoEstimadoBicos;
|
||||||
|
|
||||||
|
if (VolumeAtual_L > 0 && consumoTempoRef_LMin > 0)
|
||||||
|
{
|
||||||
|
double margem = Clamp(MargemSegurancaAutonomia, 0.0, 0.9);
|
||||||
|
|
||||||
|
TempoEstimadoMinutosPulverizando =
|
||||||
|
(VolumeAtual_L / consumoTempoRef_LMin) * (1.0 - margem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TempoEstimadoMinutosPulverizando = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double CalcularLPorMetroReferencia(double velocidadeAtual_m_s)
|
||||||
|
{
|
||||||
|
if (LPorMetroHistorico > 0)
|
||||||
|
return LPorMetroHistorico;
|
||||||
|
|
||||||
|
if (LPorMetro > 0)
|
||||||
|
return LPorMetro;
|
||||||
|
|
||||||
|
double velocidade_m_min = velocidadeAtual_m_s * 60.0;
|
||||||
|
|
||||||
|
if (velocidade_m_min > 0.1 && LPorMinutoEstimadoBicos > 0)
|
||||||
|
return LPorMinutoEstimadoBicos / velocidade_m_min;
|
||||||
|
|
||||||
|
return LPorMetroBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Helper direto para o Manager/Health:
|
|
||||||
/// indica se o volume atual é suficiente para pulverizar uma rua de certo comprimento (m).
|
|
||||||
/// </summary>
|
|
||||||
public bool ConseguePulverizarRua(double comprimentoRua_m)
|
public bool ConseguePulverizarRua(double comprimentoRua_m)
|
||||||
{
|
{
|
||||||
if (comprimentoRua_m <= 0)
|
if (comprimentoRua_m <= 0)
|
||||||
|
|
@ -342,28 +399,80 @@ namespace AgroBase.Services
|
||||||
return DistanciaMaximaSegura_m >= comprimentoRua_m;
|
return DistanciaMaximaSegura_m >= comprimentoRua_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Permite "forçar" um volume inicial (por exemplo, depois de reabastecer).
|
|
||||||
/// </summary>
|
|
||||||
public void DefinirVolumeAtual(double volume_L)
|
public void DefinirVolumeAtual(double volume_L)
|
||||||
{
|
{
|
||||||
volume_L = FuncoesMatematicas.Clamp(volume_L, 0, CapacidadeLitros);
|
volume_L = Clamp(volume_L, 0, CapacidadeLitros);
|
||||||
|
|
||||||
VolumeAtual_L = volume_L;
|
VolumeAtual_L = volume_L;
|
||||||
_volumeAnterior_L = volume_L;
|
_volumeAnterior_L = volume_L;
|
||||||
VolumeConsumido_L = CapacidadeLitros - VolumeAtual_L;
|
_volumeInicialInstancia_L = volume_L;
|
||||||
|
|
||||||
// Zera as janelas (melhor não carregar histórico de antes de reabastecer)
|
ResetarJanelas();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetarTudo()
|
||||||
|
{
|
||||||
|
Iniciado = false;
|
||||||
|
OperacaoAtiva = false;
|
||||||
|
OperacaoFinalizada = false;
|
||||||
|
|
||||||
|
MassaAtual_Kg = 0;
|
||||||
|
MassaAtual_Kg_Calc = 0;
|
||||||
|
VolumeAtual_L = 0;
|
||||||
|
|
||||||
|
_volumeInicialInstancia_L = 0;
|
||||||
|
_volumeInicialOperacao_L = 0;
|
||||||
|
|
||||||
|
BicosAtivos = 0;
|
||||||
|
Pulverizando = false;
|
||||||
|
PulverizadorLiberado = false;
|
||||||
|
|
||||||
|
VazaoFluxoAtual_mLs = 0;
|
||||||
|
VazaoEstimativaBicos_mLs = 0;
|
||||||
|
VazaoReferencia_mLs = 0;
|
||||||
|
|
||||||
|
LPorMetro = 0;
|
||||||
|
LPorMetroHistorico = 0;
|
||||||
|
LPorMetroBase = 0;
|
||||||
|
LPorMinuto = 0;
|
||||||
|
LPorMinutoEstimadoBicos = 0;
|
||||||
|
|
||||||
|
DistanciaMaximaTeorica_m = 0;
|
||||||
|
DistanciaMaximaSegura_m = 0;
|
||||||
|
TempoEstimadoMinutosPulverizando = 0;
|
||||||
|
|
||||||
|
HerbicidaPorAtuacao_L = 0;
|
||||||
|
|
||||||
|
_inicializado = false;
|
||||||
|
_volumeAnterior_L = 0;
|
||||||
|
_distanciaTotalAnterior_m = 0;
|
||||||
|
_tempoTotalAnterior_s = 0;
|
||||||
|
|
||||||
|
ResetarJanelas();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetarJanelas()
|
||||||
|
{
|
||||||
_janelaDist.Clear();
|
_janelaDist.Clear();
|
||||||
_janelaTempo.Clear();
|
_janelaTempo.Clear();
|
||||||
|
|
||||||
_somaDistanciaJanela_m = 0;
|
_somaDistanciaJanela_m = 0;
|
||||||
_somaVolumeDistJanela_L = 0;
|
_somaVolumeDistJanela_L = 0;
|
||||||
|
|
||||||
_somaTempoJanela_s = 0;
|
_somaTempoJanela_s = 0;
|
||||||
_somaVolumeTempoJanela_L = 0;
|
_somaVolumeTempoJanela_L = 0;
|
||||||
|
|
||||||
|
LPorMetro = 0;
|
||||||
|
LPorMinuto = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double Clamp(double value, double min, double max)
|
||||||
|
{
|
||||||
|
return FuncoesMatematicas.Clamp(value, min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------- AGITADOR ----------------
|
||||||
|
|
||||||
private bool _agitadorIntermitenteLigado = false;
|
private bool _agitadorIntermitenteLigado = false;
|
||||||
private DateTime _agitadorUltimaTroca = DateTime.MinValue;
|
private DateTime _agitadorUltimaTroca = DateTime.MinValue;
|
||||||
|
|
@ -378,7 +487,6 @@ namespace AgroBase.Services
|
||||||
private int AtuAgitadorTempoDesligadoMs = 30000;
|
private int AtuAgitadorTempoDesligadoMs = 30000;
|
||||||
private int AtuAgitadorBoostRetomadaMs = 15000;
|
private int AtuAgitadorBoostRetomadaMs = 15000;
|
||||||
|
|
||||||
|
|
||||||
private double PotenciaLimitePorNivel(double nivelPct)
|
private double PotenciaLimitePorNivel(double nivelPct)
|
||||||
{
|
{
|
||||||
if (nivelPct <= 5) return 0;
|
if (nivelPct <= 5) return 0;
|
||||||
|
|
@ -402,7 +510,6 @@ namespace AgroBase.Services
|
||||||
|
|
||||||
bool operacaoIniciada = Variaveis.OperacaoEmAndamento?.Iniciado ?? false;
|
bool operacaoIniciada = Variaveis.OperacaoEmAndamento?.Iniciado ?? false;
|
||||||
bool pausado = Variaveis.OperacaoEmAndamento?.Pausa ?? false;
|
bool pausado = Variaveis.OperacaoEmAndamento?.Pausa ?? false;
|
||||||
|
|
||||||
bool operacaoAtiva = operacaoIniciada && !pausado;
|
bool operacaoAtiva = operacaoIniciada && !pausado;
|
||||||
|
|
||||||
bool bicosAtuando =
|
bool bicosAtuando =
|
||||||
|
|
@ -412,7 +519,6 @@ namespace AgroBase.Services
|
||||||
double potenciaFinal = 0;
|
double potenciaFinal = 0;
|
||||||
DateTime agora = DateTime.Now;
|
DateTime agora = DateTime.Now;
|
||||||
|
|
||||||
// Boost ao iniciar/retomar operação
|
|
||||||
if (operacaoAtiva && !_agitadorOperacaoAtivaAnterior)
|
if (operacaoAtiva && !_agitadorOperacaoAtivaAnterior)
|
||||||
{
|
{
|
||||||
_agitadorBoostAte = agora.AddMilliseconds(AtuAgitadorBoostRetomadaMs);
|
_agitadorBoostAte = agora.AddMilliseconds(AtuAgitadorBoostRetomadaMs);
|
||||||
|
|
@ -438,10 +544,6 @@ namespace AgroBase.Services
|
||||||
else
|
else
|
||||||
potenciaFinal = AtuAgitadorPotenciaManutencao;
|
potenciaFinal = AtuAgitadorPotenciaManutencao;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
potenciaFinal = 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ModoAgitadorCalda.Intermitente:
|
case ModoAgitadorCalda.Intermitente:
|
||||||
|
|
@ -472,18 +574,13 @@ namespace AgroBase.Services
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
potenciaFinal = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
potenciaFinal = Math.Min(potenciaFinal, PotenciaLimitePorNivel(PercentualAtual));
|
potenciaFinal = Math.Min(potenciaFinal, PotenciaLimitePorNivel(PercentualAtual));
|
||||||
potenciaFinal = FuncoesMatematicas.Clamp(potenciaFinal, 0, 100);
|
potenciaFinal = Clamp(potenciaFinal, 0, 100);
|
||||||
|
|
||||||
AgitadorCalda.PotenciaSP = potenciaFinal;
|
AgitadorCalda.PotenciaSP = potenciaFinal;
|
||||||
_agitadorOperacaoAtivaAnterior = operacaoAtiva;
|
_agitadorOperacaoAtivaAnterior = operacaoAtiva;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,9 +104,9 @@ namespace AgroBase.Services.Operadores
|
||||||
{
|
{
|
||||||
foreach (var cam in cameras)
|
foreach (var cam in cameras)
|
||||||
{
|
{
|
||||||
var camera_str = RedisService.Get(RedisService.CamKey(cam.Key));
|
var camera_str = RedisService.Get(RedisService.CamKey(cam.Key)) ?? "";
|
||||||
var camera = JsonConvert.DeserializeObject<CameraWorkerItemModel>(camera_str);
|
var camera = JsonConvert.DeserializeObject<CameraWorkerItemModel>(camera_str);
|
||||||
if (camera.mx_id == null) continue;
|
if (camera?.mx_id == null) continue;
|
||||||
CamerasConectadas.Add(camera);
|
CamerasConectadas.Add(camera);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,5 +114,19 @@ namespace AgroBase.Services.Operadores
|
||||||
return CamerasConectadas;
|
return CamerasConectadas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static OAKCameraModel AtualizarDadosCamera(string mx_id)
|
||||||
|
{
|
||||||
|
var cam = CamerasConectadas.FirstOrDefault(x => x.mx_id == mx_id);
|
||||||
|
if (cam == null) return null;
|
||||||
|
var camera_str = RedisService.Get(RedisService.CamKey(cam.mx_id)) ?? "";
|
||||||
|
var camera = JsonConvert.DeserializeObject<CameraWorkerItemModel>(camera_str);
|
||||||
|
if (camera?.mx_id == null) return null;
|
||||||
|
var imu_str = RedisService.Get(RedisService.CamImuKey(cam.mx_id)) ?? "";
|
||||||
|
var imu = JsonConvert.DeserializeObject<OAKImuModel>(imu_str);
|
||||||
|
camera.imu = imu?.dados;
|
||||||
|
cam = camera;
|
||||||
|
return camera.ToOAK();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -221,12 +221,14 @@ namespace AgroBase.Services.Operadores
|
||||||
("path_ia_model_ruas_seg", VersionamentoService.ArquivoModeloSegStreetDetector.CaminhoCompleto),
|
("path_ia_model_ruas_seg", VersionamentoService.ArquivoModeloSegStreetDetector.CaminhoCompleto),
|
||||||
("path_ia_labelmap_ruas_seg", VersionamentoService.ArquivoLabelmapSegStreetDetector.CaminhoCompleto),
|
("path_ia_labelmap_ruas_seg", VersionamentoService.ArquivoLabelmapSegStreetDetector.CaminhoCompleto),
|
||||||
("path_ia_norm_stats_ruas_seg", VersionamentoService.ArquivoModeloNormstatsStreetDetector.CaminhoCompleto),
|
("path_ia_norm_stats_ruas_seg", VersionamentoService.ArquivoModeloNormstatsStreetDetector.CaminhoCompleto),
|
||||||
("ia_backbone_ruas_seg", "nvidia/segformer-b0-finetuned-ade-512-512"),
|
("ia_backbone_ruas_seg", "C:\\AgroBaseModels\\Backbones\\nvidia_mit_b0"),
|
||||||
|
("ia_mode_ruas", "dual_label"),
|
||||||
("path_ia_model_ruas_det", VersionamentoService.ArquivoModeloDetStreetDetector.CaminhoCompleto),
|
("path_ia_model_ruas_det", VersionamentoService.ArquivoModeloDetStreetDetector.CaminhoCompleto),
|
||||||
("path_ia_model_ervas", VersionamentoService.ArquivoModeloWeedDetector.CaminhoCompleto),
|
("path_ia_model_ervas", VersionamentoService.ArquivoModeloWeedDetector.CaminhoCompleto),
|
||||||
("path_ia_labelmap_ervas", VersionamentoService.ArquivoModeloLabelmapWeedDetector.CaminhoCompleto),
|
("path_ia_labelmap_ervas", VersionamentoService.ArquivoModeloLabelmapWeedDetector.CaminhoCompleto),
|
||||||
("path_ia_norm_stats_ervas", VersionamentoService.ArquivoModeloNormstatsWeedDetector.CaminhoCompleto),
|
("path_ia_norm_stats_ervas", VersionamentoService.ArquivoModeloNormstatsWeedDetector.CaminhoCompleto),
|
||||||
("ia_backbone_ervas", "nvidia/segformer-b1-finetuned-ade-512-512"),
|
("path_ia_module_params_ervas", VersionamentoService.ArquivoModeloModuleParamsWeedDetector.CaminhoCompleto),
|
||||||
|
("ia_backbone_ervas", "C:\\AgroBaseModels\\Backbones\\nvidia_mit_b1"),
|
||||||
("angulo_roll_max", VariaveisEquipamento.AnguloInclinacaoRollMax),
|
("angulo_roll_max", VariaveisEquipamento.AnguloInclinacaoRollMax),
|
||||||
("angulo_pitch_max", VariaveisEquipamento.AnguloInclinacaoPitchMax)
|
("angulo_pitch_max", VariaveisEquipamento.AnguloInclinacaoPitchMax)
|
||||||
);
|
);
|
||||||
|
|
@ -313,9 +315,9 @@ namespace AgroBase.Services.Operadores
|
||||||
),
|
),
|
||||||
("Snr", new
|
("Snr", new
|
||||||
{
|
{
|
||||||
percentual_altura_solo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.PercentualAlturaSolo,
|
percentual_altura_solo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.PercentualAlturaSolo ?? 0.1,
|
||||||
distancia_maxima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.DistanciaMaximaVisao,
|
distancia_maxima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.DistanciaMaximaVisao ?? 5000,
|
||||||
distancia_minima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.DistanciaMinimaVisao
|
distancia_minima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.DistanciaMinimaVisao ?? 300
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -757,15 +759,76 @@ namespace AgroBase.Services.Operadores
|
||||||
);
|
);
|
||||||
|
|
||||||
var DadosMod = _Sensoriamento.DadosPerformance;
|
var DadosMod = _Sensoriamento.DadosPerformance;
|
||||||
RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Npc),
|
RedisService.AtualizarCampos(
|
||||||
|
RedisService.ModKey(Enums.T_Code.Npc),
|
||||||
|
// Base / sincronismo
|
||||||
("timestamp", agora),
|
("timestamp", agora),
|
||||||
|
("timestamp_unix_ms", DadosMod.TimestampUnixMs),
|
||||||
("freq_base", 1.0 / Variaveis.OperacaoEmAndamento.tmrLeiturasInterval),
|
("freq_base", 1.0 / Variaveis.OperacaoEmAndamento.tmrLeiturasInterval),
|
||||||
("cpu_load", DadosMod.CPU_load ?? 0),
|
|
||||||
("gpu_load", DadosMod.GPU_load ?? 0),
|
// CPU
|
||||||
("hdd_load", DadosMod.HDD_load ?? 0),
|
("cpu_load_percent", DadosMod.CPU_load_percent ?? 0),
|
||||||
("ram_usage", DadosMod.RAM_usage ?? 0),
|
("cpu_temp_package_c", DadosMod.CPU_temp_package_c ?? 0),
|
||||||
("cpu_temp", DadosMod.CPU_temp ?? 0),
|
("cpu_power_package_w", DadosMod.CPU_power_package_w ?? 0),
|
||||||
("gpu_temp", DadosMod.GPU_temp ?? 0)
|
("cpu_power_cores_w", DadosMod.CPU_power_cores_w ?? 0),
|
||||||
|
("cpu_power_graphics_w", DadosMod.CPU_power_graphics_w ?? 0),
|
||||||
|
("cpu_power_dram_w", DadosMod.CPU_power_dram_w ?? 0),
|
||||||
|
("cpu_clock_avg_mhz", DadosMod.CPU_clock_avg_mhz ?? 0),
|
||||||
|
("cpu_clock_max_mhz", DadosMod.CPU_clock_max_mhz ?? 0),
|
||||||
|
("cpu_bus_speed_mhz", DadosMod.CPU_bus_speed_mhz ?? 0),
|
||||||
|
|
||||||
|
// RAM
|
||||||
|
("ram_usage_percent", DadosMod.RAM_usage_percent ?? 0),
|
||||||
|
("ram_used_gb", DadosMod.RAM_used_gb ?? 0),
|
||||||
|
("ram_available_gb", DadosMod.RAM_available_gb ?? 0),
|
||||||
|
("ram_total_gb", DadosMod.RAM_total_gb ?? 0),
|
||||||
|
|
||||||
|
// GPU loads
|
||||||
|
("gpu_load_percent", DadosMod.GPU_load_percent ?? 0),
|
||||||
|
("gpu_core_load_percent", DadosMod.GPU_core_load_percent ?? 0),
|
||||||
|
("gpu_frame_buffer_load_percent", DadosMod.GPU_frame_buffer_load_percent ?? 0),
|
||||||
|
("gpu_memory_load_percent", DadosMod.GPU_memory_load_percent ?? 0),
|
||||||
|
("gpu_video_engine_load_percent", DadosMod.GPU_video_engine_load_percent ?? 0),
|
||||||
|
("gpu_bus_interface_load_percent", DadosMod.GPU_bus_interface_load_percent ?? 0),
|
||||||
|
|
||||||
|
// GPU térmico / energia / clock
|
||||||
|
("gpu_temp_core_c", DadosMod.GPU_temp_core_c ?? 0),
|
||||||
|
("gpu_power_w", DadosMod.GPU_power_w ?? 0),
|
||||||
|
("gpu_core_clock_mhz", DadosMod.GPU_core_clock_mhz ?? 0),
|
||||||
|
("gpu_memory_clock_mhz", DadosMod.GPU_memory_clock_mhz ?? 0),
|
||||||
|
("gpu_shader_clock_mhz", DadosMod.GPU_shader_clock_mhz ?? 0),
|
||||||
|
|
||||||
|
// GPU fan / PCIe
|
||||||
|
("gpu_fan_percent", DadosMod.GPU_fan_percent ?? 0),
|
||||||
|
("gpu_fan_rpm", DadosMod.GPU_fan_rpm ?? 0),
|
||||||
|
("gpu_pcie_rx", DadosMod.GPU_pcie_rx ?? 0),
|
||||||
|
("gpu_pcie_tx", DadosMod.GPU_pcie_tx ?? 0),
|
||||||
|
|
||||||
|
// VRAM
|
||||||
|
("gpu_vram_total_mb", DadosMod.GPU_vram_total_mb ?? 0),
|
||||||
|
("gpu_vram_used_mb", DadosMod.GPU_vram_used_mb ?? 0),
|
||||||
|
("gpu_vram_free_mb", DadosMod.GPU_vram_free_mb ?? 0),
|
||||||
|
("gpu_vram_used_percent", DadosMod.GPU_vram_used_percent ?? 0),
|
||||||
|
|
||||||
|
// Disco
|
||||||
|
("disk_used_space_percent", DadosMod.Disk_used_space_percent ?? 0),
|
||||||
|
|
||||||
|
// Processo C#
|
||||||
|
("process_thread_count", DadosMod.Process_thread_count),
|
||||||
|
("process_working_set_mb", DadosMod.Process_working_set_mb),
|
||||||
|
("process_private_memory_mb", DadosMod.Process_private_memory_mb),
|
||||||
|
("process_virtual_memory_mb", DadosMod.Process_virtual_memory_mb),
|
||||||
|
("process_cpu_time_total_s", DadosMod.Process_cpu_time_total_s),
|
||||||
|
|
||||||
|
// ThreadPool
|
||||||
|
("threadpool_available_worker_threads", DadosMod.ThreadPool_available_worker_threads),
|
||||||
|
("threadpool_available_completion_port_threads", DadosMod.ThreadPool_available_completion_port_threads),
|
||||||
|
("threadpool_max_worker_threads", DadosMod.ThreadPool_max_worker_threads),
|
||||||
|
("threadpool_max_completion_port_threads", DadosMod.ThreadPool_max_completion_port_threads),
|
||||||
|
("threadpool_used_worker_threads", DadosMod.ThreadPool_used_worker_threads),
|
||||||
|
("threadpool_used_completion_port_threads", DadosMod.ThreadPool_used_completion_port_threads),
|
||||||
|
("threadpool_used_worker_percent", DadosMod.ThreadPool_used_worker_percent),
|
||||||
|
("threadpool_used_completion_port_percent", DadosMod.ThreadPool_used_completion_port_percent)
|
||||||
);
|
);
|
||||||
|
|
||||||
var DadosCan = CanManager.CanService;
|
var DadosCan = CanManager.CanService;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,11 @@ namespace AgroBase.Services
|
||||||
return CtxKey.DadosCameras + mx_id;
|
return CtxKey.DadosCameras + mx_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string CamImuKey(string mx_id)
|
||||||
|
{
|
||||||
|
return CtxKey.DadosCameras + mx_id + "_Imu";
|
||||||
|
}
|
||||||
|
|
||||||
public static string Get(string chave)
|
public static string Get(string chave)
|
||||||
{
|
{
|
||||||
return _db.StringGet(chave);
|
return _db.StringGet(chave);
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,16 @@ namespace AgroBase.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static VersaoArquivoModel ArquivoModeloModuleParamsWeedDetector
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_ArquivoLock)
|
||||||
|
{
|
||||||
|
return _ArquivosVersionados.Where(x => x.TipoArquivo == TipoArquivoVersionado.ModeloIA_WeedDetector).Skip(3).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public static VersaoArquivoModel ArquivoParametros(T_Code Dispositivo)
|
public static VersaoArquivoModel ArquivoParametros(T_Code Dispositivo)
|
||||||
{
|
{
|
||||||
lock (_ArquivoLock)
|
lock (_ArquivoLock)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue