ajuste no gerenciamento de cameras no lado do c#, versionamento de arquivos e atualizacao das metricas do atuador

This commit is contained in:
Diego Freitas 2026-06-22 13:46:34 -03:00
parent 4de10bdb67
commit 824f2bad58
19 changed files with 1786 additions and 545 deletions

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using AgroBase.Models; using AgroBase.Models;
using AgroBase.Services; using AgroBase.Services;
using AgroBase.Services.Operadores;
using Microsoft.Web.WebView2.WinForms; using Microsoft.Web.WebView2.WinForms;
using Newtonsoft.Json; using Newtonsoft.Json;
using static MqttService; using static MqttService;
@ -27,7 +28,7 @@ namespace AgroBase.Forms
cameraSolo = new CameraSoloModel() cameraSolo = new CameraSoloModel()
{ {
Nome = "T", Nome = "T",
Posicao = Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo.Count(), Posicao = CameraWorkerService.CamerasSolo.Count(),
ArquivoLeitura = "ervas_T.json", ArquivoLeitura = "ervas_T.json",
browser = null, browser = null,
camera = new CameraService(), camera = new CameraService(),

View File

@ -36,9 +36,10 @@ namespace AgroBase.Forms.IHM
}); });
FuncoesGlobais.DefinirEventosPicBtn(picSalvar, "Erro ao salvar parâmetros!", async () => FuncoesGlobais.DefinirEventosPicBtn(picSalvar, "Erro ao salvar parâmetros!", async () =>
{ {
Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho = CameraCaminho.Clone(); VariaveisEquipamento.Parametros.camera_caminhho_id = CameraCaminho.Id;
Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo = new List<OAKCameraModel>(CamerasSolo); VariaveisEquipamento.Parametros.camera_ervas_id = CamerasSolo?.Select(x => x.Id)?.ToList();
VariaveisEquipamento.Parametros.SalvarParametros();
CustomDialog.ShowDialog( CustomDialog.ShowDialog(
"Sucesso", "Sucesso",
"Configuração de câmeras salva com sucesso!", "Configuração de câmeras salva com sucesso!",
@ -258,7 +259,7 @@ namespace AgroBase.Forms.IHM
private async Task AtualizarCameras() private async Task AtualizarCameras()
{ {
flwCamerasSolo.Controls.Clear(); flwCamerasSolo.Controls.Clear();
var cameras = CameraWorkerService.GetListaCameras(); var cameras = CameraWorkerService.ListaCameras;
ListaCameras = cameras.Select(x => new OAKCameraModel() ListaCameras = cameras.Select(x => new OAKCameraModel()
{ {
Index = cameras.IndexOf(x), Index = cameras.IndexOf(x),
@ -268,8 +269,8 @@ namespace AgroBase.Forms.IHM
Id = x.mx_id, Id = x.mx_id,
}).ToList(); }).ToList();
CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.Clone(); CameraCaminho = CameraWorkerService.CameraCaminho?.Clone();
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo); CamerasSolo = new List<OAKCameraModel>(CameraWorkerService.CamerasSolo);
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++) for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
{ {

View File

@ -1467,7 +1467,7 @@ namespace AgroBase.Forms.IHM
} }
}); });
foreach (var camera in Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo) foreach (var camera in CameraWorkerService.CamerasSolo)
{ {
Testes.AddRange(new List<ColunasDiagnosticoModel>() Testes.AddRange(new List<ColunasDiagnosticoModel>()
{ {
@ -1508,7 +1508,7 @@ namespace AgroBase.Forms.IHM
List<string> CamerasIDs = CameraService.ObterListaCameras().Values.ToList(); List<string> CamerasIDs = CameraService.ObterListaCameras().Values.ToList();
string IDcamRua = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.Id;//.Replace("\\", "#").ToLower(); string IDcamRua = CameraWorkerService.CameraCaminho.Id;//.Replace("\\", "#").ToLower();
bool RuaConfigurado = !string.IsNullOrEmpty(IDcamRua) && IDcamRua != "Sem video"; bool RuaConfigurado = !string.IsNullOrEmpty(IDcamRua) && IDcamRua != "Sem video";
idx = PreencheDadosLinha(grid, Testes, idx, RuaConfigurado ? 1 : 0); idx = PreencheDadosLinha(grid, Testes, idx, RuaConfigurado ? 1 : 0);
@ -1519,9 +1519,9 @@ namespace AgroBase.Forms.IHM
bool RuaVideo = await VerificaImagemCamera(CamerasIDs, IDcamRua, RuaConectado); bool RuaVideo = await VerificaImagemCamera(CamerasIDs, IDcamRua, RuaConectado);
idx = PreencheDadosLinha(grid, Testes, idx, RuaVideo ? 1 : 0); idx = PreencheDadosLinha(grid, Testes, idx, RuaVideo ? 1 : 0);
foreach (var camera in Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo) foreach (var camera in CameraWorkerService.CamerasSolo)
{ {
string IDcamSolo = (Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo[0].Id);//.Replace("\\", "#").ToLower(); string IDcamSolo = (CameraWorkerService.CamerasSolo[0].Id);//.Replace("\\", "#").ToLower();
bool SoloConfigurado = !string.IsNullOrEmpty(IDcamSolo) && IDcamSolo != "Sem video"; bool SoloConfigurado = !string.IsNullOrEmpty(IDcamSolo) && IDcamSolo != "Sem video";
idx = PreencheDadosLinha(grid, Testes, idx, SoloConfigurado ? 1 : 0); idx = PreencheDadosLinha(grid, Testes, idx, SoloConfigurado ? 1 : 0);

View File

@ -160,7 +160,7 @@ namespace AgroBase.Forms.IHM
private async Task AtualizarControlesUI() private async Task AtualizarControlesUI()
{ {
var Labels = this.Controls.OfType<Label>().Where(y => y.Name.Contains("lblD_")).ToList(); var Labels = this.Controls.OfType<Label>().Where(y => y.Name.Contains("lblD_")).ToList();
var listaCameras = CameraWorkerService.GetListaCameras(); var listaCameras = CameraWorkerService.ListaCameras;
foreach (var lbl in Labels) foreach (var lbl in Labels)
{ {
T_Code Dispositivo = (T_Code)Enum.Parse(typeof(T_Code), lbl.Name.Split('_')[1]); T_Code Dispositivo = (T_Code)Enum.Parse(typeof(T_Code), lbl.Name.Split('_')[1]);
@ -172,7 +172,7 @@ namespace AgroBase.Forms.IHM
bool modDesconectado = Modulo == null || Modulo.Status == StatusModulo.Desconectado; bool modDesconectado = Modulo == null || Modulo.Status == StatusModulo.Desconectado;
int idx = Convert.ToInt32(Mod_ID); int idx = Convert.ToInt32(Mod_ID);
Mod_ID = T_Code.Cam.ToString() + "_" + Mod_ID; Mod_ID = T_Code.Cam.ToString() + "_" + Mod_ID;
var CameraSolo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo.Count() > idx ? Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo[idx] : null; var CameraSolo = CameraWorkerService.CamerasSolo.Count() > idx ? CameraWorkerService.CamerasSolo[idx] : null;
lbl.ForeColor = modDesconectado || CameraSolo?.Id == null ? lbl.ForeColor = modDesconectado || CameraSolo?.Id == null ?
Color.Black Color.Black
: !listaCameras.Any(x => x.mx_id == CameraSolo.Id) ? : !listaCameras.Any(x => x.mx_id == CameraSolo.Id) ?
@ -183,7 +183,7 @@ namespace AgroBase.Forms.IHM
{ {
var Modulo = SerialService.DispositivosMapeados.FirstOrDefault(x => x.Dispositivo == Dispositivo); var Modulo = SerialService.DispositivosMapeados.FirstOrDefault(x => x.Dispositivo == Dispositivo);
bool modDesconectado = Modulo == null || Modulo.Status == StatusModulo.Desconectado; bool modDesconectado = Modulo == null || Modulo.Status == StatusModulo.Desconectado;
var CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho; var CameraCaminho = CameraWorkerService.CameraCaminho;
lbl.ForeColor = modDesconectado || CameraCaminho?.Id == null ? lbl.ForeColor = modDesconectado || CameraCaminho?.Id == null ?
Color.Black Color.Black
: !listaCameras.Any(x => x.mx_id == CameraCaminho.Id) : !listaCameras.Any(x => x.mx_id == CameraCaminho.Id)
@ -195,7 +195,7 @@ namespace AgroBase.Forms.IHM
var Modulo = SerialService.DispositivosMapeados.FirstOrDefault(x => x.Dispositivo == T_Code.Snr); var Modulo = SerialService.DispositivosMapeados.FirstOrDefault(x => x.Dispositivo == T_Code.Snr);
bool modDesconectado = Modulo == null || Modulo.Status == StatusModulo.Desconectado; bool modDesconectado = Modulo == null || Modulo.Status == StatusModulo.Desconectado;
var saudeImu = HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == Dispositivo); var saudeImu = HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == Dispositivo);
var CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho; var CameraCaminho = CameraWorkerService.CameraCaminho;
lbl.ForeColor = lbl.ForeColor =
modDesconectado || saudeImu == null ? Color.Black modDesconectado || saudeImu == null ? Color.Black
: saudeImu.status == StatusModulo.Conectado ? Color.Blue : saudeImu.status == StatusModulo.Conectado ? Color.Blue

View File

@ -68,11 +68,11 @@ namespace AgroBase.Forms.Operacoes
nudPotenciaAgitador.Value = 100; nudPotenciaAgitador.Value = 100;
flwCamerasSolo.Controls.Clear(); flwCamerasSolo.Controls.Clear();
for (int i = 0; i < Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo.Count(); i++) for (int i = 0; i < CameraWorkerService.CamerasSolo.Count(); i++)
{ {
Panel pnlCam = new Panel() Panel pnlCam = new Panel()
{ {
Name = "pnlCamSolo_" + Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo[i].Name, Name = "pnlCamSolo_" + CameraWorkerService.CamerasSolo[i].Name,
Width = 290, Width = 290,
Height = 166, Height = 166,
BackgroundImageLayout = ImageLayout.Zoom, BackgroundImageLayout = ImageLayout.Zoom,
@ -230,7 +230,7 @@ namespace AgroBase.Forms.Operacoes
try try
{ {
var frame = await WeedWorkerService.GetCameraFrame(TipoFrameCamera.Debug); var frame = await WeedWorkerService.GetCameraFrame(TipoFrameCamera.Debug);
Panel pnl = FuncoesGlobais.FindControlRecursive<Panel>(flwCamerasSolo, "pnlCamSolo_" + Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo[0].Name); Panel pnl = FuncoesGlobais.FindControlRecursive<Panel>(flwCamerasSolo, "pnlCamSolo_" + CameraWorkerService.CamerasSolo[0].Name);
AtualizarImagemPainel(pnl, frame?.image()); AtualizarImagemPainel(pnl, frame?.image());
} }
finally finally

View File

@ -2,6 +2,7 @@
using AgroBase.Models; using AgroBase.Models;
using AgroBase.Models.Modules; using AgroBase.Models.Modules;
using AgroBase.Services; using AgroBase.Services;
using AgroBase.Services.Operadores;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -69,7 +70,7 @@ namespace AgroBase.Forms.Sensoriamento
Cameras = CameraService.ObterListaCameras(); Cameras = CameraService.ObterListaCameras();
cmbCaminho.Items.Clear(); cmbCaminho.Items.Clear();
cmbCaminho.Items.AddRange(Cameras.Values.ToArray()); cmbCaminho.Items.AddRange(Cameras.Values.ToArray());
string IDrua = ((SensoriamentoModel)Disp.Dados).CameraCaminho.Id; string IDrua = CameraWorkerService.CameraCaminho.Id;
if (Cameras.Any(x => x.Value == IDrua)) if (Cameras.Any(x => x.Value == IDrua))
{ {
cmbCaminho.SelectedIndex = cmbCaminho.Items.IndexOf(IDrua); cmbCaminho.SelectedIndex = cmbCaminho.Items.IndexOf(IDrua);
@ -79,7 +80,7 @@ namespace AgroBase.Forms.Sensoriamento
cmbCaminho.Text = IDrua; cmbCaminho.Text = IDrua;
} }
var CamerasSolo = ((SensoriamentoModel)Disp.Dados).CamerasSolo; var CamerasSolo = CameraWorkerService.CamerasSolo;
cmbSoloEsq.Items.Clear(); cmbSoloEsq.Items.Clear();
cmbSoloEsq.Items.AddRange(Cameras.Values.ToArray()); cmbSoloEsq.Items.AddRange(Cameras.Values.ToArray());
@ -196,7 +197,7 @@ namespace AgroBase.Forms.Sensoriamento
_Disp.Dados._EnderecoCAN_Rx = FuncoesGlobais.StringToHexByte(txtEnderecoCAN_Rx.Text); _Disp.Dados._EnderecoCAN_Rx = FuncoesGlobais.StringToHexByte(txtEnderecoCAN_Rx.Text);
_Disp.Dados.RequisitarDados = chbRequisitarDados.Checked; _Disp.Dados.RequisitarDados = chbRequisitarDados.Checked;
_Disp.Dados.Sensores = Sensores.ToList(); _Disp.Dados.Sensores = Sensores.ToList();
_Disp.Dados.CameraCaminho.Id = cmbCaminho.Text; CameraWorkerService.CameraCaminho.Id = cmbCaminho.Text;
//_Disp.Dados.CamerasSolo.Clear(); //_Disp.Dados.CamerasSolo.Clear();
//_Disp.Dados.CameraID_Solo.AddRange(new string[] { cmbSoloEsq.Text, cmbSoloDir.Text }); //_Disp.Dados.CameraID_Solo.AddRange(new string[] { cmbSoloEsq.Text, cmbSoloDir.Text });
_Disp.SalvarParametros(_Disp.Dados); _Disp.SalvarParametros(_Disp.Dados);

View File

@ -141,6 +141,8 @@ namespace AgroBase.Forms
RedisService.Iniciar(); RedisService.Iniciar();
RedisService.LimparDadosIniciais(); RedisService.LimparDadosIniciais();
GeneralJoystick.IniciarRotinas();
await Variaveis.IniciarMqttAsync(_appCts.Token) await Variaveis.IniciarMqttAsync(_appCts.Token)
.ConfigureAwait(false); .ConfigureAwait(false);
@ -148,10 +150,9 @@ namespace AgroBase.Forms
* Hoje pode ficar comentado se UDP não for usado no rover, * Hoje pode ficar comentado se UDP não for usado no rover,
* mas o método fica aqui no lugar certo do lifecycle. * mas o método fica aqui no lugar certo do lifecycle.
*/ */
//Variaveis.IniciarUDP(); Variaveis.IniciarUDP();
APIService.IniciarRotinas(); APIService.IniciarRotinas();
GeneralJoystick.IniciarRotinas();
VersionamentoService.IniciarRotinas(); VersionamentoService.IniciarRotinas();
LivoxManagerProcess.Start(); LivoxManagerProcess.Start();

View File

@ -41,7 +41,7 @@ namespace AgroBase.Forms
private void AtualizarListaCameras() private void AtualizarListaCameras()
{ {
cmbCameras.Items.Clear(); cmbCameras.Items.Clear();
cmbCameras.Items.AddRange(CameraWorkerService.GetListaCameras().Select(x => x.modelo).ToArray()); cmbCameras.Items.AddRange(CameraWorkerService.ListaCameras.Select(x => x.modelo).ToArray());
cmbCameras.SelectedIndex = -1; cmbCameras.SelectedIndex = -1;
} }

View File

@ -84,10 +84,10 @@ namespace AgroBase.Forms
var Camera = ListaCameras[cmbDispositivo.SelectedIndex]; var Camera = ListaCameras[cmbDispositivo.SelectedIndex];
if (Camera.imu == null) return; if (Camera.imu == null) return;
if (Camera.mx_id == Variaveis.OperacaoEmAndamento.DispSen?.Dados?.CameraCaminho?.Id) if (Camera.mx_id == CameraWorkerService.CameraCaminho?.Id)
Camera.imu = Variaveis.OperacaoEmAndamento.DispSen.Dados?.CameraCaminho?.cam?.imu; Camera.imu = CameraWorkerService.CameraCaminho?.cam?.imu;
else if (Variaveis.OperacaoEmAndamento.DispSen.Dados?.CamerasSolo?.Any(x => x?.Id == Camera.mx_id) ?? false) else if (CameraWorkerService.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; Camera.imu = CameraWorkerService.CamerasSolo?.FirstOrDefault(x => x?.Id == Camera.mx_id)?.cam?.imu;
Imu = new OperacaoSensoriamentoLogImuModel() Imu = new OperacaoSensoriamentoLogImuModel()
{ {
@ -108,7 +108,7 @@ namespace AgroBase.Forms
private void AtualizarListaCameras() private void AtualizarListaCameras()
{ {
ListaCameras = CameraWorkerService.GetListaCameras(); ListaCameras = CameraWorkerService.ListaCameras;
cmbDispositivo.Items.Clear(); cmbDispositivo.Items.Clear();
cmbDispositivo.Items.AddRange(ListaCameras.Select(x => x.modelo).ToArray()); cmbDispositivo.Items.AddRange(ListaCameras.Select(x => x.modelo).ToArray());

View File

@ -206,7 +206,7 @@ namespace AgroBase.Models.Modules
private HashSet<int> _bombasAtivasIntervaloAnterior = new HashSet<int>(); private HashSet<int> _bombasAtivasIntervaloAnterior = new HashSet<int>();
private Dictionary<int, double> _potenciaBombasIntervaloAnterior = new Dictionary<int, double>(); private Dictionary<int, double> _potenciaBombasIntervaloAnterior = new Dictionary<int, double>();
private double _vazaoIntervaloAnteriorMLs; private double _vazaoIntervaloAnteriorMLs;
private const double IntervaloMaximoIntegracaoSeg = 0.5; private const double IntervaloMaximoIntegracaoSeg = 2.0;
private const double IdadeMaximaTelemetriaSeg = 2.5; private const double IdadeMaximaTelemetriaSeg = 2.5;
private double _tempoMovimentoAnteriorSeg; private double _tempoMovimentoAnteriorSeg;
@ -382,10 +382,20 @@ namespace AgroBase.Models.Modules
Variaveis.OperacaoEmAndamento.Iniciado && Variaveis.OperacaoEmAndamento.Iniciado &&
!operacaoConcluida; !operacaoConcluida;
bool atuadorComTelemetriaRecente =
DadosLeitura != null &&
DadosLeitura.UltimoComandoRespondido != DateTime.MinValue &&
DadosLeitura
.UltimoComandoRespondido
.AddMilliseconds(TempoLimiteConexao) > agora;
bool atuadorTemEstrutura =
(BicosPulverizadores?.Count ?? 0) > 0;
bool atuadorDisponivel = bool atuadorDisponivel =
operacaoAtiva && operacaoAtiva &&
DadosLeitura != null && atuadorTemEstrutura &&
DadosLeitura.Conectado; atuadorComTelemetriaRecente;
bool pulverizadorAutomatico = bool pulverizadorAutomatico =
Variaveis.OperacaoEmAndamento Variaveis.OperacaoEmAndamento
@ -470,8 +480,7 @@ namespace AgroBase.Models.Modules
_ultimoTickMetricas) / _ultimoTickMetricas) /
(double)Stopwatch.Frequency; (double)Stopwatch.Frequency;
if (dt > 0 && if (dt > 0 && dt <= IntervaloMaximoIntegracaoSeg)
dt <= IntervaloMaximoIntegracaoSeg)
{ {
double deltaMovimentoSeg = 0; double deltaMovimentoSeg = 0;
@ -506,6 +515,12 @@ namespace AgroBase.Models.Modules
* Não inventa tempo nem volume. * Não inventa tempo nem volume.
*/ */
ZerarVazoesInstantaneas(); ZerarVazoesInstantaneas();
if (dt > IntervaloMaximoIntegracaoSeg)
{
Variaveis.MostrarLog("[ATU/METRICAS] Integração ignorada por dt alto: " + dt.ToString("0.000") + "s");
Variaveis.OperacaoEmAndamento.Sensoriamento.InserirLog(Dispositivo, StatusModulo.Alerta, 50, "[ATU/METRICAS] Integração ignorada por dt alto: " + dt.ToString("0.000") + "s");
}
} }
} }
@ -1320,7 +1335,7 @@ namespace AgroBase.Models.Modules
Dados.BombasPressurizadoras.ForEach(x => x.Funcoes = x.Funcoes.Distinct().ToList()); Dados.BombasPressurizadoras.ForEach(x => x.Funcoes = x.Funcoes.Distinct().ToList());
ReiniciarLeituras(Dados); ReiniciarLeituras(Dados);
PrepararAtuadorParaOperacao(Dados); PrepararAtuadorParaOperacao(Dados, resetarComandos: true);
} }
public void ReiniciarLeituras(AtuadorModel Dados) public void ReiniciarLeituras(AtuadorModel Dados)
@ -1337,13 +1352,18 @@ namespace AgroBase.Models.Modules
{ {
x.ComandoAtuar = false; x.ComandoAtuar = false;
x.AnguloControle = 0; x.AnguloControle = 0;
x.Atuacoes = 0;
x.VazaoInstantaneaMLs = 0; x.VazaoInstantaneaMLs = 0;
x.VolumeVazadoML = 0; x.VolumeVazadoML = 0;
x.VazaoMediaMLs = 0; x.VazaoMediaMLs = 0;
x.TempoAtuado = 0; x.TempoAtuado = 0;
x.TempoAtuadoEmMovimento = 0; x.TempoAtuadoEmMovimento = 0;
x.TempoComFluxo = 0; x.TempoComFluxo = 0;
x.ReiniciarHistoricoAtuacao(true); x.ReiniciarHistoricoAtuacao(true);
x.ValoresLeituras.ForEach(l => x.ValoresLeituras.ForEach(l =>
{ {
l.atual = new CanCommandFreqModel<dynamic>(); l.atual = new CanCommandFreqModel<dynamic>();
@ -1386,10 +1406,19 @@ namespace AgroBase.Models.Modules
} }
} }
private void PrepararAtuadorParaOperacao(AtuadorModel Dados) public void PrepararAtuadorParaOperacao()
{
PrepararAtuadorParaOperacao(this, resetarComandos: false);
}
private void PrepararAtuadorParaOperacao(AtuadorModel Dados, bool resetarComandos)
{ {
var dadosAtuador = Dados; var dadosAtuador = Dados;
var controle = Variaveis.OperacaoEmAndamento.Parametros?.Controle; var controle =
Variaveis
.OperacaoEmAndamento
.Parametros?
.Controle;
if (dadosAtuador == null || controle == null) if (dadosAtuador == null || controle == null)
return; return;
@ -1398,7 +1427,13 @@ namespace AgroBase.Models.Modules
if (bomba != null) if (bomba != null)
{ {
bomba.ComandoAtuar = false; if (resetarComandos)
bomba.ComandoAtuar = false;
/*
* Estes setpoints precisam existir antes do primeiro comando
* físico da bomba em operação automática.
*/
bomba.PotenciaSP = 100; bomba.PotenciaSP = 100;
bomba.PressaoSP = controle.AtuPressaoLinha; bomba.PressaoSP = controle.AtuPressaoLinha;
bomba.Controle.Modo = controle.AtuModoControle; bomba.Controle.Modo = controle.AtuModoControle;
@ -1408,12 +1443,113 @@ namespace AgroBase.Models.Modules
if (agitador != null) if (agitador != null)
{ {
agitador.ComandoAtuar = false; if (resetarComandos)
agitador.ComandoAtuar = false;
/*
* O agitador tem a própria fonte de verdade em
* HerbicideCounterService.AtualizarAgitadorCalda().
*/
agitador.PotenciaSP = 0; agitador.PotenciaSP = 0;
agitador.PressaoSP = -1; agitador.PressaoSP = -1;
} }
} }
public void SincronizarBombaPressurizadoraAutomatica(bool forcar = false)
{
var operacao = Variaveis.OperacaoEmAndamento;
var controle =
operacao?
.Parametros?
.Controle;
var bomba = BombaPressurizadora;
if (operacao == null || controle == null || bomba == null || !bomba.Inicializado)
return;
bool pulverizadorAutomatico = controle.PulverizadorAutomatico;
if (!pulverizadorAutomatico)
return;
bool operacaoConcluida = operacao.Sensoriamento?.StatusOperacao == StatusOperacao.Concluido;
bool atuacaoPermitida =
operacao.Iniciado &&
!operacao.Finalizando &&
!operacao.Emergencia &&
!operacaoConcluida &&
!operacao.Pausa;
/*
* Reaplica setpoints sempre antes de sincronizar.
* Assim, se ReiniciarLeituras() zerou a bomba no início da operação,
* ela não fica presa em potência/pressão zero.
*/
PrepararAtuadorParaOperacao();
bool statusDesejado =
bomba.Comandar &&
atuacaoPermitida &&
ContadorCarga.PulverizadorLiberado;
/*
* ComandoAtuar passa a representar também o comando lógico automático.
* Isso deixa o log BombaLigada coerente com o que o software deseja.
*/
bomba.ComandoAtuar = statusDesejado;
double potenciaEfetiva =
statusDesejado
? bomba.PotenciaSP
: 0;
double pressaoEfetiva =
bomba.Sensor_ID_Num > -1
? (
statusDesejado
? bomba.PressaoSP
: 0
)
: bomba.PressaoSP;
Estado estadoDesejado =
statusDesejado
? Estado.Ligado
: Estado.Desligado;
bool estadoDivergente =
estadoDesejado != bomba._EstadoLeitura;
bool potenciaDivergente =
Math.Abs(
bomba._PotenciaSP -
potenciaEfetiva
) > 1.0;
bool pressaoDivergente =
bomba.Sensor_ID_Num > -1 &&
Math.Abs(
bomba._PressaoSP -
pressaoEfetiva
) > 0.05;
if (forcar ||
estadoDivergente ||
potenciaDivergente ||
pressaoDivergente)
{
EnviarComandoFisicoBomba(
bomba,
statusDesejado,
potenciaEfetiva,
pressaoEfetiva
);
}
}
public async Task<bool> VerificaDispositivoConectado() public async Task<bool> VerificaDispositivoConectado()
{ {
if (!CanManager.CanService.IsConnected) return false; if (!CanManager.CanService.IsConnected) return false;
@ -1797,15 +1933,19 @@ namespace AgroBase.Models.Modules
* *
* Ela não depende de um ComandoAtuar antigo. * Ela não depende de um ComandoAtuar antigo.
*/ */
else if ( else if (ehBombaPrincipal && pulverizadorAutomatico)
ehBombaPrincipal &&
pulverizadorAutomatico
)
{ {
statusDesejado = statusDesejado =
bomba.Comandar && bomba.Comandar &&
atuacaoPermitida && atuacaoPermitida &&
ContadorCarga.PulverizadorLiberado; ContadorCarga.PulverizadorLiberado;
/*
* Mantém o modelo coerente com o comando automático.
* Sem isso, o log BombaLigada pode ficar false mesmo quando
* o controle automático deseja a bomba ligada.
*/
bomba.ComandoAtuar = statusDesejado;
} }
/* /*
* Agitador e comandos manuais. * Agitador e comandos manuais.

View File

@ -56,8 +56,6 @@ namespace AgroBase.Models.Modules
public List<SensorSinaleiroModel> Sinaleiros { get; set; } public List<SensorSinaleiroModel> Sinaleiros { get; set; }
public List<SensorReleModel> Reles { get; set; } public List<SensorReleModel> Reles { get; set; }
public List<SensorServoModel> Servos { get; set; } public List<SensorServoModel> Servos { get; set; }
public OAKCameraModel CameraCaminho { get; set; } = new OAKCameraModel();
public List<OAKCameraModel> CamerasSolo { get; set; } = new List<OAKCameraModel>();
public UltrasonicA05Configuracoes ConfiguracaoSensorUltrassom { get; set; } public UltrasonicA05Configuracoes ConfiguracaoSensorUltrassom { get; set; }
private SenHandler _SenHandler = new SenHandler(); private SenHandler _SenHandler = new SenHandler();
public LoRaEspService loRaService { get; set; } = new LoRaEspService(); public LoRaEspService loRaService { get; set; } = new LoRaEspService();
@ -86,8 +84,6 @@ namespace AgroBase.Models.Modules
_EnderecoCAN_Rx = 0x11, _EnderecoCAN_Rx = 0x11,
_TaxaAmostragem = 1000, _TaxaAmostragem = 1000,
RequisitarDados = true, RequisitarDados = true,
CameraCaminho = new OAKCameraModel(),
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo ?? VariaveisEquipamento.QuantidadeCamerasSolo),
// 21 ~ 23 // 21 ~ 23
Sinaleiros = new List<SensorSinaleiroModel>() Sinaleiros = new List<SensorSinaleiroModel>()
{ {
@ -1169,7 +1165,7 @@ namespace AgroBase.Models.Modules
Descricao = "Luminosidade Ambiente", Descricao = "Luminosidade Ambiente",
ID_Num = 31, ID_Num = 31,
Componente = S_Code.sLUZ, Componente = S_Code.sLUZ,
Aferir = true, Aferir = false,
Mandatorio = false, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
@ -1221,7 +1217,7 @@ namespace AgroBase.Models.Modules
Descricao = "Indice de radiacao UV Ambiente", Descricao = "Indice de radiacao UV Ambiente",
ID_Num = 32, ID_Num = 32,
Componente = S_Code.sIUV, Componente = S_Code.sIUV,
Aferir = true, Aferir = false,
Mandatorio = false, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
@ -1271,7 +1267,7 @@ namespace AgroBase.Models.Modules
Descricao = "Gas e Fumaca", Descricao = "Gas e Fumaca",
ID_Num = 33, ID_Num = 33,
Componente = S_Code.sGAS, Componente = S_Code.sGAS,
Aferir = true, Aferir = false,
Mandatorio = false, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
@ -1329,7 +1325,7 @@ namespace AgroBase.Models.Modules
Descricao = "Monoxido de carbono", Descricao = "Monoxido de carbono",
ID_Num = 34, ID_Num = 34,
Componente = S_Code.sGAS, Componente = S_Code.sGAS,
Aferir = true, Aferir = false,
Mandatorio = false, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
@ -1387,7 +1383,7 @@ namespace AgroBase.Models.Modules
Descricao = "Qualidade do ar", Descricao = "Qualidade do ar",
ID_Num = 35, ID_Num = 35,
Componente = S_Code.sQAR, Componente = S_Code.sQAR,
Aferir = true, Aferir = false,
Mandatorio = false, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
@ -1475,7 +1471,7 @@ namespace AgroBase.Models.Modules
Descricao = "Temperatura e Umidade Ambiente", Descricao = "Temperatura e Umidade Ambiente",
ID_Num = 36, ID_Num = 36,
Componente = S_Code.sSHT, Componente = S_Code.sSHT,
Aferir = true, Aferir = false,
Mandatorio = false, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
@ -1538,7 +1534,7 @@ namespace AgroBase.Models.Modules
Descricao = "Chuva", Descricao = "Chuva",
ID_Num = 37, ID_Num = 37,
Componente = S_Code.sCHV, Componente = S_Code.sCHV,
Aferir = true, Aferir = false,
Mandatorio = false, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
@ -1589,8 +1585,8 @@ namespace AgroBase.Models.Modules
Descricao = "Angulo Direcional ET", Descricao = "Angulo Direcional ET",
ID_Num = 91, ID_Num = 91,
Componente = S_Code.sMAG, Componente = S_Code.sMAG,
Aferir = true, Aferir = false,
Mandatorio = true, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
FuncoesPinout.I2C, FuncoesPinout.I2C,
@ -1644,8 +1640,8 @@ namespace AgroBase.Models.Modules
Descricao = "Angulo Direcional DT", Descricao = "Angulo Direcional DT",
ID_Num = 92, ID_Num = 92,
Componente = S_Code.sMAG, Componente = S_Code.sMAG,
Aferir = true, Aferir = false,
Mandatorio = true, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
FuncoesPinout.I2C, FuncoesPinout.I2C,
@ -1699,8 +1695,8 @@ namespace AgroBase.Models.Modules
Descricao = "Angulo Direcional EF", Descricao = "Angulo Direcional EF",
ID_Num = 93, ID_Num = 93,
Componente = S_Code.sMAG, Componente = S_Code.sMAG,
Aferir = true, Aferir = false,
Mandatorio = true, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
FuncoesPinout.I2C, FuncoesPinout.I2C,
@ -1754,8 +1750,8 @@ namespace AgroBase.Models.Modules
Descricao = "Angulo Direcional DF", Descricao = "Angulo Direcional DF",
ID_Num = 94, ID_Num = 94,
Componente = S_Code.sMAG, Componente = S_Code.sMAG,
Aferir = true, Aferir = false,
Mandatorio = true, Mandatorio = false,
Funcoes = new List<FuncoesPinout>() Funcoes = new List<FuncoesPinout>()
{ {
FuncoesPinout.I2C, FuncoesPinout.I2C,
@ -2409,24 +2405,6 @@ 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

View File

@ -1188,6 +1188,10 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.Sensoriamento.UltimoRegistroLog = DateTime.Now; Variaveis.OperacaoEmAndamento.Sensoriamento.UltimoRegistroLog = DateTime.Now;
tmrLogs?.Start(); tmrLogs?.Start();
var dispSen = Variaveis.OperacaoEmAndamento.DispSen;
var dispAtu = Variaveis.OperacaoEmAndamento.DispAtu;
var dispMvd = Variaveis.OperacaoEmAndamento.DispMvd;
Variaveis.OperacaoEmAndamento.Iniciado = true; Variaveis.OperacaoEmAndamento.Iniciado = true;
Variaveis.OperacaoEmAndamento.Simulando = false; Variaveis.OperacaoEmAndamento.Simulando = false;
Variaveis.OperacaoEmAndamento.Treinando = false; Variaveis.OperacaoEmAndamento.Treinando = false;
@ -1204,9 +1208,10 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.Sensoriamento.AtualizarDados(); Variaveis.OperacaoEmAndamento.Sensoriamento.AtualizarDados();
Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.ReiniciarLeituras(DispMvd?.Dados); dispMvd?.Dados?.ReiniciarLeituras(dispMvd?.Dados);
Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.ReiniciarLeituras(DispAtu?.Dados); dispAtu?.Dados?.ReiniciarLeituras(dispAtu?.Dados);
Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ReiniciarLeituras(DispSen?.Dados); dispSen?.Dados?.ReiniciarLeituras(dispSen?.Dados);
dispAtu?.Dados?.PrepararAtuadorParaOperacao();
Variaveis.OperacaoEmAndamento.ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>() Variaveis.OperacaoEmAndamento.ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>()
{ {
@ -1222,19 +1227,36 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.Controle.Reiniciar(); Variaveis.OperacaoEmAndamento.Controle.Reiniciar();
Variaveis.OperacaoEmAndamento.ControleAnterior.Reiniciar(); Variaveis.OperacaoEmAndamento.ControleAnterior.Reiniciar();
double distanciaPercorrida = DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0; double distanciaPercorrida = dispMvd?.Dados?.DistanciaPercorridaTotal ?? 0;
double tempoAtuado = DispAtu?.Dados?.TempoAtuado ?? 0; double tempoAtuado = dispAtu?.Dados?.TempoAtuado ?? 0;
Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.AtualizarConsumo(distanciaPercorrida); dispSen?.Dados?.ContadorCarga?.AtualizarConsumo(distanciaPercorrida);
Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida); dispSen?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida);
Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida, tempoAtuado); dispAtu?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida, tempoAtuado);
Variaveis.OperacaoEmAndamento.GPSTrajetoria = new List<GPSModel>(); Variaveis.OperacaoEmAndamento.GPSTrajetoria = new List<GPSModel>();
Variaveis.OperacaoEmAndamento.Trajetoria?.ProjetarTrajetoriaFixa(); Trajetoria?.ProjetarTrajetoriaFixa();
Variaveis.OperacaoEmAndamento.Trajetoria.VerificacaoInicialMeioRuaConcluida = false; Trajetoria.VerificacaoInicialMeioRuaConcluida = false;
RedisService.Publish(CmdKey.ManagerWorkerRx, JsonConvert.SerializeObject(new { cmd = ManagerWorkerCommandType.IniciarMPC }));
/*
* Mantém a operação bloqueada enquanto calibra/prepara.
* O Manager/MPC deve começar depois da calibração.
*/
Pausa = true;
await RealizarCalibragemInicialAsync(true); await RealizarCalibragemInicialAsync(true);
Pausa = false;
RedisService.Publish(
CmdKey.ManagerWorkerRx,
JsonConvert.SerializeObject(
new
{
cmd = ManagerWorkerCommandType.IniciarMPC
}
)
);
} }
public async Task FinalizarOperacao() public async Task FinalizarOperacao()
@ -1291,8 +1313,14 @@ namespace AgroBase.Models
{ {
if (Variaveis.OperacaoEmAndamento.Calibrando) return; if (Variaveis.OperacaoEmAndamento.Calibrando) return;
bool modsCalibrados = Variaveis.OperacaoEmAndamento.ModsCalibragem.All(x => x.Value.Values.Count > 0 && x.Value.Values.All(y => y == true)); var modsCalibragem = Variaveis.OperacaoEmAndamento.ModsCalibragem;
if (!forcar && modsCalibrados) return;
bool modsCalibrados = modsCalibragem.All(x => x.Value.Values.Count > 0 && x.Value.Values.All(y => y == true));
if (!forcar && modsCalibrados)
{
Variaveis.OperacaoEmAndamento.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Operante, 100, "Todos os módulos já foram calibrados anteriormente, não irá calibrar novamente.");
return;
}
var DispAtu = Variaveis.OperacaoEmAndamento.DispAtu; var DispAtu = Variaveis.OperacaoEmAndamento.DispAtu;
var DispMvd = Variaveis.OperacaoEmAndamento.DispMvd; var DispMvd = Variaveis.OperacaoEmAndamento.DispMvd;
@ -1301,9 +1329,9 @@ namespace AgroBase.Models
var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle; var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle;
var _Controle = Variaveis.OperacaoEmAndamento.Controle; var _Controle = Variaveis.OperacaoEmAndamento.Controle;
bool calibragemAtuNecessaria = pControle.PulverizadorAutomatico && (DispAtu?.Dados != null && sv.Contains(s.FirstOrDefault(x => x.modulo == T_Code.Atu)?.status ?? StatusModulo.Desconectado) && (forcar || Variaveis.OperacaoEmAndamento.ModsCalibragem[T_Code.Atu].Any(x => !x.Value) || !Variaveis.OperacaoEmAndamento.ModsCalibragem[T_Code.Atu].Any())); bool calibragemAtuNecessaria = pControle.PulverizadorAutomatico && (DispAtu?.Dados != null && sv.Contains(s.FirstOrDefault(x => x.modulo == T_Code.Atu)?.status ?? StatusModulo.Desconectado) && (forcar || modsCalibragem[T_Code.Atu].Any(x => !x.Value) || !modsCalibragem[T_Code.Atu].Any()));
bool calibragemDirNecessaria = (DispMvd?.Dados != null && sv.Contains(s.FirstOrDefault(x => x.modulo == T_Code.Dir)?.status ?? StatusModulo.Desconectado) && (forcar || Variaveis.OperacaoEmAndamento.ModsCalibragem[T_Code.Dir].Any(x => !x.Value) || !Variaveis.OperacaoEmAndamento.ModsCalibragem[T_Code.Dir].Any())); bool calibragemDirNecessaria = (DispMvd?.Dados != null && sv.Contains(s.FirstOrDefault(x => x.modulo == T_Code.Dir)?.status ?? StatusModulo.Desconectado) && (forcar || modsCalibragem[T_Code.Dir].Any(x => !x.Value) || !modsCalibragem[T_Code.Dir].Any()));
bool calibragemMovNecessaria = (DispMvd?.Dados != null && sv.Contains(s.FirstOrDefault(x => x.modulo == T_Code.Mov)?.status ?? StatusModulo.Desconectado) && (forcar || Variaveis.OperacaoEmAndamento.ModsCalibragem[T_Code.Mov].Any(x => !x.Value) || !Variaveis.OperacaoEmAndamento.ModsCalibragem[T_Code.Mov].Any())); bool calibragemMovNecessaria = (DispMvd?.Dados != null && sv.Contains(s.FirstOrDefault(x => x.modulo == T_Code.Mov)?.status ?? StatusModulo.Desconectado) && (forcar || modsCalibragem[T_Code.Mov].Any(x => !x.Value) || !modsCalibragem[T_Code.Mov].Any()));
if (!calibragemAtuNecessaria && !calibragemDirNecessaria && !calibragemMovNecessaria) return; if (!calibragemAtuNecessaria && !calibragemDirNecessaria && !calibragemMovNecessaria) return;
@ -1633,6 +1661,8 @@ namespace AgroBase.Models
} }
case T_Code.Atu: case T_Code.Atu:
{ {
Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.SincronizarBombaPressurizadoraAutomatica();
for (int i = 0; i < _Controle.Bicos.Count; i++) for (int i = 0; i < _Controle.Bicos.Count; i++)
{ {
Estado comandoEstado = _Controle.Bicos[i].ComandoAtuar ? Estado.Ligado : Estado.Desligado; Estado comandoEstado = _Controle.Bicos[i].ComandoAtuar ? Estado.Ligado : Estado.Desligado;
@ -2971,6 +3001,27 @@ namespace AgroBase.Models
SalvarLogLine(T_Code.Dir.ToString(), logDir); SalvarLogLine(T_Code.Dir.ToString(), logDir);
}); });
try
{
var dispMvd = Variaveis.OperacaoEmAndamento.DispMvd;
var dispAtu = Variaveis.OperacaoEmAndamento.DispAtu;
dispAtu?.Dados?.AtualizarMetricasOperacao();
dispAtu?.Dados?.ContadorCarga?.AtualizarConsumo(
dispMvd?.Dados?.DistanciaPercorridaTotal ?? 0,
Variaveis.OperacaoEmAndamento.TempoDecorridoSegs,
dispMvd?.Dados?.VelocidadeMedia ?? 0
);
}
catch (Exception ex)
{
Variaveis.MostrarLog(
"[SalvarLogs/ATU] Erro ao atualizar métricas antes do log: " +
ex.Message
);
}
AtuSensoriamentoLogModel logAtu = new AtuSensoriamentoLogModel() AtuSensoriamentoLogModel logAtu = new AtuSensoriamentoLogModel()
{ {
Momento = Agora, Momento = Agora,
@ -3041,7 +3092,7 @@ namespace AgroBase.Models
atu = T_Code.Atu.ToString(), atu = T_Code.Atu.ToString(),
sen = T_Code.Sen.ToString(), sen = T_Code.Sen.ToString(),
cam_caminho = T_Code.Snr.ToString(), cam_caminho = T_Code.Snr.ToString(),
cam_solo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo.Select((x, i) => x.Dispositivo.ToString() + i).ToList(), cam_solo = CameraWorkerService.CamerasSolo.Select((x, i) => x.Dispositivo.ToString() + i).ToList(),
}; };
File.WriteAllText(ArquivoOp, JsonConvert.SerializeObject(data)); File.WriteAllText(ArquivoOp, JsonConvert.SerializeObject(data));
} }
@ -3078,9 +3129,9 @@ namespace AgroBase.Models
private void SalvarLogCameraSolo() private void SalvarLogCameraSolo()
{ {
foreach (var Camera in Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo) foreach (var Camera in CameraWorkerService.CamerasSolo)
{ {
string camera_name = Camera.Dispositivo.ToString() + Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo.IndexOf(Camera); string camera_name = Camera.Dispositivo.ToString() + CameraWorkerService.CamerasSolo.IndexOf(Camera);
string Caminho = Variaveis.CaminhoOperacoes + Variaveis.OperacaoEmAndamento.ID + "/" + camera_name; string Caminho = Variaveis.CaminhoOperacoes + Variaveis.OperacaoEmAndamento.ID + "/" + camera_name;
if (!Directory.Exists(Caminho)) if (!Directory.Exists(Caminho))
{ {
@ -3104,7 +3155,9 @@ namespace AgroBase.Models
private void SalvarLogCameraCaminho() private void SalvarLogCameraCaminho()
{ {
var Camera = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho; var Camera = CameraWorkerService.CameraCaminho;
if (Camera == null)
return;
string Caminho = Variaveis.CaminhoOperacoes + Variaveis.OperacaoEmAndamento.ID + "/" + Camera.Dispositivo; string Caminho = Variaveis.CaminhoOperacoes + Variaveis.OperacaoEmAndamento.ID + "/" + Camera.Dispositivo;
if (!Directory.Exists(Caminho)) if (!Directory.Exists(Caminho))
@ -3602,6 +3655,7 @@ namespace AgroBase.Models
public List<ManagerWorkerMessageResponseModulosPendentesModel> ModulosSaude { get; set; } public List<ManagerWorkerMessageResponseModulosPendentesModel> ModulosSaude { get; set; }
public List<DispositivoDetalhesModel> DispositivosMapeados { get; set; } public List<DispositivoDetalhesModel> DispositivosMapeados { get; set; }
public Dictionary<T_Code, Dictionary<string, bool>> ModsCalibragem { get; set; } public Dictionary<T_Code, Dictionary<string, bool>> ModsCalibragem { get; set; }
public Dictionary<string, Dictionary<string, bool>> ModsCalibragemView { get; set; }
public CanServiceTipo TipoCanAtivo { get; set; } public CanServiceTipo TipoCanAtivo { get; set; }
public List<OperacaoSensoriamentoLogErrosModel> Logs { get; set; } public List<OperacaoSensoriamentoLogErrosModel> Logs { get; set; }
public DateTime UltimoRegistroLog { get; set; } = DateTime.MinValue; public DateTime UltimoRegistroLog { get; set; } = DateTime.MinValue;
@ -3631,6 +3685,7 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.DadosPerformance.AtualizarDadosPerformance(); Variaveis.OperacaoEmAndamento.DadosPerformance.AtualizarDadosPerformance();
VisualWorkerService.AtualizarAnalise(); VisualWorkerService.AtualizarAnalise();
WeedWorkerService.AtualizarAnalise(); WeedWorkerService.AtualizarAnalise();
CameraWorkerService.AtualizarDadosCameras();
GPSService.AtualizaDadosRedis(); GPSService.AtualizaDadosRedis();
LivoxManagerProcess.AtualizarLeitura(); LivoxManagerProcess.AtualizarLeitura();
MovimentacaoMovimentoCompensadoModel.AtualizarDados(); MovimentacaoMovimentoCompensadoModel.AtualizarDados();
@ -3649,7 +3704,6 @@ 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?.AtualizarMetricasOperacao(); _DispAtu?.Dados?.AtualizarMetricasOperacao();
_Cooler?.Atualizar(tmp_max, DateTime.Now); _Cooler?.Atualizar(tmp_max, DateTime.Now);
_Bateria?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0); _Bateria?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0);
@ -3665,7 +3719,7 @@ namespace AgroBase.Models
var bombaLinha = _DispAtu?.Dados?.BombaPressurizadora; var bombaLinha = _DispAtu?.Dados?.BombaPressurizadora;
var dadosAtuador = _DispAtu != null ? new OperacaoSensoriamentoLogAtuModel() var dadosAtuador = _DispAtu != null ? new OperacaoSensoriamentoLogAtuModel()
{ {
QtdCamerasSolo = _DispSen.Dados.CamerasSolo.Count, QtdCamerasSolo = CameraWorkerService.CamerasSolo.Count,
CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio, CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio,
HerbicidaConsumido = _Reservatorio.VolumeConsumidoTotal_L, HerbicidaConsumido = _Reservatorio.VolumeConsumidoTotal_L,
HerbicidaConsumidoOperacao = _Reservatorio.VolumeConsumidoOperacao_L, HerbicidaConsumidoOperacao = _Reservatorio.VolumeConsumidoOperacao_L,
@ -3885,6 +3939,7 @@ namespace AgroBase.Models
ModulosSaude = HealthWorkerService.ModulosSaude.ToList(), ModulosSaude = HealthWorkerService.ModulosSaude.ToList(),
DispositivosMapeados = new List<DispositivoDetalhesModel>(SerialService.DispositivosMapeados), DispositivosMapeados = new List<DispositivoDetalhesModel>(SerialService.DispositivosMapeados),
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(Variaveis.OperacaoEmAndamento.ModsCalibragem), ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(Variaveis.OperacaoEmAndamento.ModsCalibragem),
ModsCalibragemView = Variaveis.OperacaoEmAndamento.ModsCalibragem?.ToDictionary(x => x.Key.ToString(), x => new Dictionary<string, bool>(x.Value ?? new Dictionary<string, bool>())) ?? new Dictionary<string, Dictionary<string, bool>>(),
Logs = Logs != null ? Logs.Where(x => x?.Momento >= UltimoRegistroLog).ToList() : new List<OperacaoSensoriamentoLogErrosModel>(), Logs = Logs != null ? Logs.Where(x => x?.Momento >= UltimoRegistroLog).ToList() : new List<OperacaoSensoriamentoLogErrosModel>(),
CoolerControl = dadosCooler CoolerControl = dadosCooler
}; };
@ -3936,6 +3991,7 @@ namespace AgroBase.Models
ModulosSaude = new List<ManagerWorkerMessageResponseModulosPendentesModel>(ModulosSaude), ModulosSaude = new List<ManagerWorkerMessageResponseModulosPendentesModel>(ModulosSaude),
DispositivosMapeados = new List<DispositivoDetalhesModel>(DispositivosMapeados), DispositivosMapeados = new List<DispositivoDetalhesModel>(DispositivosMapeados),
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(ModsCalibragem), ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(ModsCalibragem),
ModsCalibragemView = new Dictionary<string, Dictionary<string, bool>>(ModsCalibragemView),
Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()), Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()),
UltimoRegistroLog = UltimoRegistroLog, UltimoRegistroLog = UltimoRegistroLog,
CoolerControl = CoolerControl?.Clone(), CoolerControl = CoolerControl?.Clone(),

View File

@ -1149,12 +1149,8 @@ namespace AgroBase.Models.Operacoes
private void AtualizarCameras() private void AtualizarCameras()
{ {
CameraWorkerService.GetListaCameras();
Cameras = CameraWorkerService.ListaCameras != null Cameras = CameraWorkerService.ListaCameras != null
? new List<CameraWorkerItemModel>( ? new List<CameraWorkerItemModel>(CameraWorkerService.ListaCameras)
CameraWorkerService.ListaCameras
)
: new List<CameraWorkerItemModel>(); : new List<CameraWorkerItemModel>();
} }

View File

@ -34,22 +34,30 @@ namespace AgroBase.Models.Operadores
public class CameraWorkerItemModel public class CameraWorkerItemModel
{ {
public T_Code dispositivo { get; set; } // Novos campos identificados no seu JSON
public double timestamp { get; set; }
public bool presente_scan { get; set; }
public string status_scan { get; set; }
public double manager_reset_ts { get; set; }
public bool iniciando { get; set; } // Presente no JSON
// Campos que já existiam na sua classe
public string mx_id { get; set; } public string mx_id { get; set; }
public string versao { get; set; }
public string modelo { get; set; }
public bool iniciado { get; set; } public bool iniciado { get; set; }
public bool rodando { get; set; } public bool rodando { get; set; }
// Campos opcionais (coloque '?' para evitar erros se forem nulos ou ausentes)
public T_Code dispositivo { get; set; }
public string versao { get; set; }
public string modelo { get; set; }
public bool tem_depth { get; set; } public bool tem_depth { get; set; }
public bool tem_imu { get; set; } public bool tem_imu { get; set; }
public bool streaming { get; set; } public bool streaming { get; set; }
public double fps { get; set; } public double fps { get; set; }
public int stream_w { get; set; } public int stream_w { get; set; }
public int stream_h { get; set; } public int stream_h { get; set; }
public double stream_kbps { get; set; } public double stream_kbps { get; set; }
public double stream_last_frame { get; set; } public double stream_last_frame { get; set; }
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 OAKImuDataModel imu { get; set; }
@ -60,8 +68,8 @@ namespace AgroBase.Models.Operadores
{ {
Id = mx_id, Id = mx_id,
Dispositivo = dispositivo, Dispositivo = dispositivo,
Version = versao, Version = versao ?? "Desconhecida",
Name = modelo, Name = modelo ?? "Desconhecido",
cam = this cam = this
}; };
} }

View File

@ -136,31 +136,59 @@ namespace AgroBase.Services
private double _distanciaTotalAnterior_m; private double _distanciaTotalAnterior_m;
private double _tempoTotalAnterior_s; private double _tempoTotalAnterior_s;
private bool _inicioOperacaoPendente;
private double _distanciaInicioOperacaoPendente_m;
private double _tempoInicioOperacaoPendente_s;
private bool _inicializado; private bool _inicializado;
public void IniciarOperacao(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual) public void IniciarOperacao(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual)
{ {
/*
* Antes, se o contador ainda não tivesse recebido uma leitura
* válida do reservatório, o início era ignorado.
*
* Isso fazia VolumeConsumidoOperacao_L ficar zero durante toda
* a operação quando a primeira leitura válida chegava depois
* do comando de iniciar.
*/
if (!_inicializado) if (!_inicializado)
{
OperacaoAtiva = true;
OperacaoFinalizada = false;
_inicioOperacaoPendente = true;
_distanciaInicioOperacaoPendente_m =
distanciaTotalMetrosAtual;
_tempoInicioOperacaoPendente_s =
tempoTotalSegundosAtual;
ResetarJanelas();
return; return;
}
_volumeInicialOperacao_L = VolumeAtual_L; _volumeInicialOperacao_L = VolumeAtual_L;
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual; _distanciaTotalAnterior_m =
_tempoTotalAnterior_s = tempoTotalSegundosAtual; distanciaTotalMetrosAtual;
_tempoTotalAnterior_s =
tempoTotalSegundosAtual;
OperacaoAtiva = true; OperacaoAtiva = true;
OperacaoFinalizada = false; OperacaoFinalizada = false;
_inicioOperacaoPendente = false;
ResetarJanelas(); ResetarJanelas();
} }
public void FinalizarOperacao() public void FinalizarOperacao()
{ {
if (!OperacaoAtiva) if (!OperacaoAtiva && !_inicioOperacaoPendente)
return; return;
OperacaoAtiva = false; OperacaoAtiva = false;
OperacaoFinalizada = true; OperacaoFinalizada = true;
_inicioOperacaoPendente = false;
} }
public void AtualizarConsumo(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual, double velocidadeAtual_m_s) public void AtualizarConsumo(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual, double velocidadeAtual_m_s)
@ -202,6 +230,26 @@ namespace AgroBase.Services
if (!_inicializado) if (!_inicializado)
{ {
Inicializar(distanciaTotalMetrosAtual, tempoTotalSegundosAtual); Inicializar(distanciaTotalMetrosAtual, tempoTotalSegundosAtual);
if (OperacaoAtiva || _inicioOperacaoPendente)
{
/*
* Primeira leitura válida depois do comando de iniciar.
* A operação passa a usar o volume atual como referência
* inicial, sem perder o estado de OperacaoAtiva.
*/
_volumeInicialOperacao_L = VolumeAtual_L;
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
OperacaoAtiva = true;
OperacaoFinalizada = false;
_inicioOperacaoPendente = false;
ResetarJanelas();
}
AtualizarAutonomia(velocidadeAtual_m_s); AtualizarAutonomia(velocidadeAtual_m_s);
return; return;
} }
@ -341,10 +389,21 @@ namespace AgroBase.Services
private void AtualizarHerbicidaPorAtuacao() private void AtualizarHerbicidaPorAtuacao()
{ {
int qtdAtuacoes = Variaveis.OperacaoEmAndamento.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0; int qtdAtuacoes =
Variaveis
.OperacaoEmAndamento
.DispAtu?
.Dados?
.BicosPulverizadores?
.Sum(x => x?.Atuacoes ?? 0)
?? 0;
if (qtdAtuacoes > 0) if (qtdAtuacoes > 0)
HerbicidaPorAtuacao_L = VolumeConsumidoOperacao_L / qtdAtuacoes; HerbicidaPorAtuacao_L =
VolumeConsumidoOperacao_L /
qtdAtuacoes;
else
HerbicidaPorAtuacao_L = 0;
} }
private void AtualizarAutonomia(double velocidadeAtual_m_s) private void AtualizarAutonomia(double velocidadeAtual_m_s)
@ -399,9 +458,9 @@ namespace AgroBase.Services
velocidadeReferencia_m_s = velocidadeReferencia_m_s =
FuncoesMatematicas.CalculaVelocidadeMsPercentual( FuncoesMatematicas.CalculaVelocidadeMsPercentual(
Variaveis.OperacaoEmAndamento Variaveis.OperacaoEmAndamento
.Parametros .Parametros?
.Controle .Controle?
.MovVelocidadeCErvasPercent .MovVelocidadeCErvasPercent ?? 30
); );
} }
@ -476,6 +535,10 @@ namespace AgroBase.Services
_distanciaTotalAnterior_m = 0; _distanciaTotalAnterior_m = 0;
_tempoTotalAnterior_s = 0; _tempoTotalAnterior_s = 0;
_inicioOperacaoPendente = false;
_distanciaInicioOperacaoPendente_m = 0;
_tempoInicioOperacaoPendente_s = 0;
ResetarJanelas(); ResetarJanelas();
} }

View File

@ -1,12 +1,12 @@
using AgroBase.Models.Operadores;
using AgroBase.Models; using AgroBase.Models;
using AgroBase.Models.Operadores;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Threading.Tasks;
using static AgroBase.Models.Operadores.OperadoresModels;
using System.Collections.Generic; using System.Collections.Generic;
using static AgroBase.Models.Enums;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
using static AgroBase.Models.Operadores.OperadoresModels;
namespace AgroBase.Services.Operadores namespace AgroBase.Services.Operadores
{ {
@ -14,17 +14,87 @@ namespace AgroBase.Services.Operadores
{ {
public CameraWorkerModel DadosLeitura = new CameraWorkerModel(); public CameraWorkerModel DadosLeitura = new CameraWorkerModel();
public SaudeWorkerModel Saude { get; set; } = new SaudeWorkerModel(); public SaudeWorkerModel Saude { get; set; } = new SaudeWorkerModel();
private static List<CameraWorkerItemModel> CamerasConectadas = new List<CameraWorkerItemModel>();
public static List<CameraWorkerItemModel> ListaCameras => CamerasConectadas.Skip(1).ToList(); private static readonly object _cameraLock = new object();
private static readonly object _refreshLock = new object();
private static readonly JsonSerializerSettings _jsonSettings =
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
Error = (sender, args) =>
{
args.ErrorContext.Handled = true;
}
};
private static List<CameraWorkerItemModel> CamerasConectadas =
CriarListaVaziaComPlaceholder();
private static DateTime _ultimoRefreshUtc = DateTime.MinValue;
private static bool _refreshEmAndamento;
/*
* Pode chamar AtualizarDadosCameras() em tmrLeitura_Tick sem medo.
* Se o tick estiver em 100 ms, este throttle evita martelar Redis.
*/
private static readonly TimeSpan IntervaloMinimoRefresh =
TimeSpan.FromMilliseconds(500);
private bool DebugMode = true; private bool DebugMode = true;
public static List<CameraWorkerItemModel> ListaCameras
{
get
{
lock (_cameraLock)
{
return CamerasConectadas.Skip(1).ToList();
}
}
}
public static OAKCameraModel CameraCaminho
{
get
{
CameraWorkerItemModel item =
ListaCameras.FirstOrDefault(
x => x.dispositivo == T_Code.Snr
);
return item?.ToOAK();
}
}
public static List<OAKCameraModel> CamerasSolo
{
get
{
return ListaCameras
.Where(x => x.dispositivo == T_Code.Cam)
.Select(x => x.ToOAK())
.Where(x => x != null)
.ToList();
}
}
public void MostrarLog(string message, int limite = 500) public void MostrarLog(string message, int limite = 500)
{ {
if (DebugMode) if (!DebugMode)
{ return;
Console.WriteLine($"[CameraWorker] {message.Substring(0, Math.Min(limite, message.Length))}{(message.Length > limite ? "..." : "")}");
} message = message ?? string.Empty;
Console.WriteLine(
"[CameraWorker] " +
message.Substring(
0,
Math.Min(limite, message.Length)
) +
(message.Length > limite ? "..." : "")
);
} }
public async Task<bool> IniciarProcessamento() public async Task<bool> IniciarProcessamento()
@ -35,7 +105,9 @@ namespace AgroBase.Services.Operadores
DadosLeitura.Iniciado = true; DadosLeitura.Iniciado = true;
bool pronto() => DadosLeitura.Pronto; bool pronto() => DadosLeitura.Pronto;
await FuncoesGlobais.AguardarCondicaoAsync(pronto, 5000); await FuncoesGlobais.AguardarCondicaoAsync(pronto, 5000);
if (pronto()) if (pronto())
{ {
MostrarLog("Processamento iniciado com sucesso"); MostrarLog("Processamento iniciado com sucesso");
@ -51,28 +123,39 @@ namespace AgroBase.Services.Operadores
{ {
try try
{ {
var comando = JsonConvert.DeserializeObject<ComandoRedis>(mensagem); if (string.IsNullOrWhiteSpace(mensagem))
return;
var comando =
JsonConvert.DeserializeObject<ComandoRedis>(
mensagem,
_jsonSettings
);
if (comando == null)
return;
var cmd = (CameraWorkerCommandType)comando.cmd; var cmd = (CameraWorkerCommandType)comando.cmd;
//MostrarLog($"Comando recebido: cmd = {cmd.ToString()}");
switch (cmd) switch (cmd)
{ {
case CameraWorkerCommandType.ScriptCarregado: case CameraWorkerCommandType.ScriptCarregado:
DadosLeitura.Pronto = true; DadosLeitura.Pronto = true;
DadosLeitura.ProntoEm = DateTime.Now; DadosLeitura.ProntoEm = DateTime.Now;
MostrarLog($"Comando recebido: cmd = {cmd.ToString()}"); MostrarLog("Comando recebido: cmd = " + cmd);
break; break;
default: default:
MostrarLog($"Comando não reconhecido: {comando.cmd}"); MostrarLog("Comando não reconhecido: " + comando.cmd);
break; break;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
MostrarLog($"Erro ao deserializar resposta: {ex.Message}"); MostrarLog(
"Erro ao deserializar resposta: " +
ex.Message
);
} }
finally finally
{ {
@ -82,51 +165,295 @@ namespace AgroBase.Services.Operadores
public void AtualizarSaude() public void AtualizarSaude()
{ {
Saude = OperadoresModels.AtualizarSaude(CtxKey.DadosCameraWorker); Saude =
OperadoresModels.AtualizarSaude(
CtxKey.DadosCameraWorker
);
} }
/// <summary>
/// Lê câmeras diretamente do Redis e retorna uma lista nova.
/// Não atualiza o snapshot global. Para runtime, use AtualizarDadosCameras().
/// </summary>
public static List<CameraWorkerItemModel> GetListaCameras() public static List<CameraWorkerItemModel> GetListaCameras()
{ {
CamerasConectadas = new List<CameraWorkerItemModel>() return LerCamerasDoRedis();
}
/// <summary>
/// Atualiza o snapshot global das câmeras.
/// Pode ser chamado no tmrLeitura_Tick. Internamente possui throttle.
/// </summary>
public static void AtualizarDadosCameras()
{
AtualizarDadosCameras(false);
}
public static void AtualizarDadosCameras(bool forcar)
{
DateTime agoraUtc = DateTime.UtcNow;
if (!forcar &&
agoraUtc - _ultimoRefreshUtc < IntervaloMinimoRefresh)
{ {
new CameraWorkerItemModel() return;
}
lock (_refreshLock)
{
if (_refreshEmAndamento)
return;
if (!forcar &&
DateTime.UtcNow - _ultimoRefreshUtc <
IntervaloMinimoRefresh)
{
return;
}
_refreshEmAndamento = true;
}
try
{
List<CameraWorkerItemModel> novaLista =
LerCamerasDoRedis();
lock (_cameraLock)
{
CamerasConectadas = novaLista;
_ultimoRefreshUtc = DateTime.UtcNow;
}
}
catch (Exception ex)
{
Console.WriteLine(
"[CameraWorkerService] Erro ao atualizar câmeras: " +
ex.Message
);
}
finally
{
lock (_refreshLock)
{
_refreshEmAndamento = false;
}
}
}
private static OAKCameraModel AtualizarDadosCamera(string mx_id)
{
if (string.IsNullOrWhiteSpace(mx_id))
return null;
CameraWorkerItemModel camera = LerCameraDoRedis(mx_id);
if (camera == null ||
string.IsNullOrWhiteSpace(camera.mx_id))
{
return null;
}
lock (_cameraLock)
{
int index =
CamerasConectadas.FindIndex(
x => x.mx_id == mx_id
);
if (index >= 0)
CamerasConectadas[index] = camera;
else
CamerasConectadas.Add(camera);
OrdenarCamerasMantendoPlaceholder(CamerasConectadas);
}
return camera.ToOAK();
}
private static List<CameraWorkerItemModel> LerCamerasDoRedis()
{
var resultado = CriarListaVaziaComPlaceholder();
string camerasStr = RedisService.Get(CtxKey.DadosCameras);
if (string.IsNullOrWhiteSpace(camerasStr))
return resultado;
Dictionary<string, CameraWorkerItemModel> cameras;
try
{
cameras =
JsonConvert.DeserializeObject<
Dictionary<string, CameraWorkerItemModel>
>(
camerasStr,
_jsonSettings
);
}
catch (Exception ex)
{
Console.WriteLine(
"[CameraWorkerService] Falha ao ler índice de câmeras: " +
ex.Message
);
return resultado;
}
if (cameras == null || cameras.Count == 0)
return resultado;
foreach (string key in cameras.Keys.ToList())
{
CameraWorkerItemModel camera = LerCameraDoRedis(key);
if (camera == null)
continue;
if (string.IsNullOrWhiteSpace(camera.mx_id))
continue;
resultado.Add(camera);
}
OrdenarCamerasMantendoPlaceholder(resultado);
return resultado;
}
private static CameraWorkerItemModel LerCameraDoRedis(
string redisIdOuMxId)
{
if (string.IsNullOrWhiteSpace(redisIdOuMxId))
return null;
string cameraStr =
RedisService.Get(
RedisService.CamKey(redisIdOuMxId)
);
if (string.IsNullOrWhiteSpace(cameraStr))
return null;
CameraWorkerItemModel camera;
try
{
camera =
JsonConvert.DeserializeObject<CameraWorkerItemModel>(
cameraStr,
_jsonSettings
);
}
catch (Exception ex)
{
Console.WriteLine(
"[CameraWorkerService] Falha ao ler câmera " +
redisIdOuMxId + ": " + ex.Message
);
Console.WriteLine(
"[CameraWorkerService] JSON câmera: " +
cameraStr
);
return null;
}
if (camera == null ||
string.IsNullOrWhiteSpace(camera.mx_id))
{
return null;
}
string imuStr =
RedisService.Get(
RedisService.CamImuKey(camera.mx_id)
);
if (!string.IsNullOrWhiteSpace(imuStr))
{
try
{
var imu =
JsonConvert.DeserializeObject<OAKImuModel>(
imuStr,
_jsonSettings
);
camera.imu = imu?.dados;
}
catch (Exception ex)
{
Console.WriteLine(
"[CameraWorkerService] Falha ao ler IMU da câmera " +
camera.mx_id + ": " + ex.Message
);
}
}
return camera;
}
private static List<CameraWorkerItemModel>
CriarListaVaziaComPlaceholder()
{
return new List<CameraWorkerItemModel>
{
new CameraWorkerItemModel
{ {
dispositivo = T_Code.Vzo, dispositivo = T_Code.Vzo,
modelo = "Sem Video" modelo = "Sem Video"
} }
}; };
var cameras_str = RedisService.Get(CtxKey.DadosCameras);
var cameras = JsonConvert.DeserializeObject<Dictionary<string, CameraWorkerItemModel>>(cameras_str);
if (cameras.Any())
{
foreach (var cam in cameras)
{
var camera_str = RedisService.Get(RedisService.CamKey(cam.Key)) ?? "";
var camera = JsonConvert.DeserializeObject<CameraWorkerItemModel>(camera_str);
if (camera?.mx_id == null) continue;
CamerasConectadas.Add(camera);
}
}
return CamerasConectadas;
} }
public static OAKCameraModel AtualizarDadosCamera(string mx_id) private static void OrdenarCamerasMantendoPlaceholder(
List<CameraWorkerItemModel> cameras)
{ {
var cam = CamerasConectadas.FirstOrDefault(x => x.mx_id == mx_id); if (cameras == null || cameras.Count <= 1)
if (cam == null) return null; return;
var camera_str = RedisService.Get(RedisService.CamKey(cam.mx_id)) ?? "";
var camera = JsonConvert.DeserializeObject<CameraWorkerItemModel>(camera_str); CameraWorkerItemModel placeholder =
if (camera?.mx_id == null) return null; cameras.FirstOrDefault(
var imu_str = RedisService.Get(RedisService.CamImuKey(cam.mx_id)) ?? ""; x => x.dispositivo == T_Code.Vzo &&
var imu = JsonConvert.DeserializeObject<OAKImuModel>(imu_str); x.modelo == "Sem Video"
camera.imu = imu?.dados; );
cam = camera;
return camera.ToOAK(); var reais =
cameras
.Where(x =>
!(x.dispositivo == T_Code.Vzo &&
x.modelo == "Sem Video"))
.OrderBy(PrioridadeCamera)
.ThenBy(x => x.mx_id)
.ToList();
cameras.Clear();
if (placeholder != null)
cameras.Add(placeholder);
else
cameras.Add(CriarListaVaziaComPlaceholder()[0]);
cameras.AddRange(reais);
} }
private static int PrioridadeCamera(CameraWorkerItemModel camera)
{
if (camera == null)
return 99;
if (camera.dispositivo == T_Code.Snr)
return 0;
if (camera.dispositivo == T_Code.Cam)
return 1;
return 2;
}
} }
} }

View File

@ -216,8 +216,8 @@ namespace AgroBase.Services.Operadores
("qtd_bicos", VariaveisEquipamento.QuantidadeBicosPulverizadores), ("qtd_bicos", VariaveisEquipamento.QuantidadeBicosPulverizadores),
("percentual_reservatorio_min", VariaveisEquipamento.PercentualReservatorioMin), ("percentual_reservatorio_min", VariaveisEquipamento.PercentualReservatorioMin),
("percentual_tensao_bateria_min", VariaveisEquipamento.PercentualTensaoBateriaMin), ("percentual_tensao_bateria_min", VariaveisEquipamento.PercentualTensaoBateriaMin),
("camera_caminho_id", Variaveis.OperacaoEmAndamento.DispSen?.Dados?.CameraCaminho?.Id ?? ""), ("camera_caminho_id", VariaveisEquipamento.Parametros.camera_caminhho_id ?? ""),
("camera_solo_id", Variaveis.OperacaoEmAndamento.DispSen?.Dados?.CamerasSolo?.FirstOrDefault()?.Id ?? ""), ("camera_solo_id", VariaveisEquipamento.Parametros.camera_ervas_id?.FirstOrDefault() ?? ""),
("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),
@ -320,9 +320,9 @@ namespace AgroBase.Services.Operadores
), ),
("Snr", new ("Snr", new
{ {
percentual_altura_solo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.PercentualAlturaSolo ?? 0.1, percentual_altura_solo = CameraWorkerService.CameraCaminho?.PercentualAlturaSolo ?? 0.1,
distancia_maxima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.DistanciaMaximaVisao ?? 5000, distancia_maxima = CameraWorkerService.CameraCaminho?.DistanciaMaximaVisao ?? 5000,
distancia_minima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.DistanciaMinimaVisao ?? 300 distancia_minima = CameraWorkerService.CameraCaminho?.DistanciaMinimaVisao ?? 300
} }
) )
); );

File diff suppressed because it is too large Load Diff

View File

@ -121,7 +121,7 @@ class CameraManager:
dispositivos_serializados = list(set(dispositivos_serializados)) dispositivos_serializados = list(set(dispositivos_serializados))
#self.mostrar_log("Dispositivos Serializados", dispositivos_serializados) #print("Dispositivos Serializados", dispositivos_serializados)
cameras_mapeadas = ContextoGlobalRedis.get_cameras() or {} cameras_mapeadas = ContextoGlobalRedis.get_cameras() or {}
@ -138,6 +138,7 @@ class CameraManager:
} }
else: else:
#cam_existente["timestamp"] = agora #cam_existente["timestamp"] = agora
#cam_existente["mx_id"] = mx_id
cam_existente["presente_scan"] = True cam_existente["presente_scan"] = True
cam_existente["status_scan"] = "detectada" cam_existente["status_scan"] = "detectada"
@ -191,15 +192,23 @@ class CameraManager:
ContextoGlobalRedis.set(CtxKey.DadosCameras, cameras_mapeadas) ContextoGlobalRedis.set(CtxKey.DadosCameras, cameras_mapeadas)
#self.mostrar_log("Cameras Mapeadas", cameras_mapeadas) #print("Cameras Mapeadas", cameras_mapeadas)
equipamento = ContextoGlobalRedis.get_equipamento() or {} equipamento = ContextoGlobalRedis.get_equipamento() or {}
visual_worker_camera_id = equipamento.get("camera_caminho_id") visual_worker_camera_id = equipamento.get("camera_caminho_id")
weed_worker_camera_id = equipamento.get("camera_solo_id") weed_worker_camera_id = equipamento.get("camera_solo_id")
#self.mostrar_log(
# "[CameraManager] IDs configurados | "
# f"visual_worker_camera_id={visual_worker_camera_id!r} | "
# f"weed_worker_camera_id={weed_worker_camera_id!r} | "
# f"detectadas={list(cameras_mapeadas.keys())}"
#)
# 3) Só tenta iniciar se a câmera estiver realmente válida # 3) Só tenta iniciar se a câmera estiver realmente válida
if self._camera_pode_iniciar(visual_worker_camera_id, cameras_mapeadas, agora): if self._camera_pode_iniciar(visual_worker_camera_id, cameras_mapeadas, agora):
#self.mostrar_log(f"[CameraManager] Enviando iniciar VisualWorker para câmera {visual_worker_camera_id}")
ContextoGlobalRedis.publicar_comando( ContextoGlobalRedis.publicar_comando(
CmdKey.VisualWorkerRx, CmdKey.VisualWorkerRx,
{ {
@ -209,6 +218,7 @@ class CameraManager:
) )
if self._camera_pode_iniciar(weed_worker_camera_id, cameras_mapeadas, agora): if self._camera_pode_iniciar(weed_worker_camera_id, cameras_mapeadas, agora):
#self.mostrar_log(f"[CameraManager] Enviando iniciar WeedWorker para câmera {weed_worker_camera_id}")
ContextoGlobalRedis.publicar_comando( ContextoGlobalRedis.publicar_comando(
CmdKey.WeedWorkerRx, CmdKey.WeedWorkerRx,
{ {