Ajuste na firmware e leitura de dados brutos

This commit is contained in:
Diego Freitas 2025-12-16 14:17:26 -03:00
parent 777993dfbb
commit 7554842804
29 changed files with 1652 additions and 541 deletions

View File

@ -138,8 +138,8 @@ namespace AgroBase.Forms.Atuador
var BombaPressurizadora = DispAtu.Dados.BombasPressurizadoras.FirstOrDefault();
grdSensoriamento.Rows[0].Cells[1].Value = BombaPressurizadora.Inicializado;
grdSensoriamento.Rows[1].Cells[1].Value = BombaPressurizadora.ComandoAtuar;
grdSensoriamento.Rows[2].Cells[1].Value = BombaPressurizadora.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
grdSensoriamento.Rows[3].Cells[1].Value = BombaPressurizadora.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia).atual.valor;
grdSensoriamento.Rows[2].Cells[1].Value = BombaPressurizadora._EstadoLeitura;
grdSensoriamento.Rows[3].Cells[1].Value = BombaPressurizadora._Potencia;
grdSensoriamento.Rows[4].Cells[1].Value = DispAtu.Dados.PressaoLinha.ToString("0.00000");
grdSensoriamento.Rows[5].Cells[1].Value = DispAtu.Dados.PressaoLinhaCalc.ToString("0.00000");
grdSensoriamento.Rows[6].Cells[1].Value = DispAtu.Dados.VazaoFluxoMLpSMedia.ToString("0.00000");
@ -178,7 +178,7 @@ namespace AgroBase.Forms.Atuador
int circleY = pnl.Height / 4; // Posição Y do círculo (mais próximo ao topo)
// Desenhar o círculo
if (DispAtu.Dados.BicosPulverizadores.First(x => x.ID == ID).ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor)
if (DispAtu.Dados.BicosPulverizadores.First(x => x.ID == ID)._EstadoLeitura == Estado.Ligado)
g.FillEllipse(Brushes.Green, circleX, circleY, circleDiameter, circleDiameter); // LED aceso (círculo preenchido)
else
g.DrawEllipse(Pens.Black, circleX, circleY, circleDiameter, circleDiameter); // LED apagado (círculo vazio)

View File

@ -478,42 +478,42 @@ namespace AgroBase.Forms.IHM
double Fluxo = FluxoInicializado ? Dispositivo.Dados.VazaoFluxoMLpSInstantanea : -1;
idx = PreencheDadosLinha(grid, Testes, idx, Fluxo);
bool statusB01_1 = B01Inicializado && B01.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
bool statusB01_1 = B01Inicializado && B01._EstadoLeitura == Estado.Ligado;
idx = PreencheDadosLinha(grid, Testes, idx, statusB01_1 ? 1 : -1);
await EnviarComandoBico(B01, false, 1000);
bool statusB01_0 = B01Inicializado && !B01.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
bool statusB01_0 = B01Inicializado && B01._EstadoLeitura == Estado.Desligado;
idx = PreencheDadosLinha(grid, Testes, idx, statusB01_0 ? 0 : -1);
await EnviarComandoBico(B02, true, 1000);
bool statusB02_1 = B02Inicializado && B02.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
bool statusB02_1 = B02Inicializado && B02._EstadoLeitura == Estado.Ligado;
idx = PreencheDadosLinha(grid, Testes, idx, statusB02_1 ? 1 : -1);
await EnviarComandoBico(B02, false, 1000);
bool statusB02_0 = B02Inicializado && !B02.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
bool statusB02_0 = B02Inicializado && B02._EstadoLeitura == Estado.Desligado;
idx = PreencheDadosLinha(grid, Testes, idx, statusB02_0 ? 0 : -1);
await EnviarComandoBico(B03, true, 1000);
bool statusB03_1 = B03Inicializado && B03.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
bool statusB03_1 = B03Inicializado && B03._EstadoLeitura == Estado.Ligado;
idx = PreencheDadosLinha(grid, Testes, idx, statusB03_1 ? 1 : -1);
await EnviarComandoBico(B03, false, 1000);
bool statusB03_0 = B03Inicializado && !B03.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
bool statusB03_0 = B03Inicializado && B03._EstadoLeitura == Estado.Desligado;
idx = PreencheDadosLinha(grid, Testes, idx, statusB03_0 ? 0 : -1);
await EnviarComandoBico(B04, true, 1000);
bool statusB04_1 = B04Inicializado && B04.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
bool statusB04_1 = B04Inicializado && B04._EstadoLeitura == Estado.Ligado;
idx = PreencheDadosLinha(grid, Testes, idx, statusB04_1 ? 1 : -1);
await EnviarComandoBico(B04, false, 1000);
bool statusB04_0 = B04Inicializado && B04.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
bool statusB04_0 = B04Inicializado && B04._EstadoLeitura == Estado.Desligado;
idx = PreencheDadosLinha(grid, Testes, idx, statusB04_0 ? 0 : -1);
@ -1765,7 +1765,7 @@ namespace AgroBase.Forms.IHM
await EnviarComandoRele(Dispositivo, Rele, true, 1000);
}
Estado Status = Rele.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
Estado Status = Rele._EstadoLeitura;
idx = PreencheDadosLinha(grid, Testes, idx, Iniciado && Status == Estado.Ligado ? 1 : -1);
if (Iniciado)
@ -1773,7 +1773,7 @@ namespace AgroBase.Forms.IHM
await EnviarComandoRele(Dispositivo, Rele, false, 1000);
}
Status = Rele.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura).atual.valor;
Status = Rele._EstadoLeitura;
idx = PreencheDadosLinha(grid, Testes, idx, Iniciado && Status == Estado.Desligado ? 0 : -1);
}

View File

@ -539,7 +539,7 @@ namespace AgroBase.Forms.Operacoes
gridDados.Rows[19].Cells[1].Value = (_Barramentos.FirstOrDefault(x => x.ID == "AB24V").Tensao).ToString("0.00");
gridDados.Rows[20].Cells[1].Value = (_Barramentos.FirstOrDefault(x => x.ID == "AB24V").Corrente).ToString("0.00");
gridDados.Rows[21].Cells[1].Value = _Sensoriamento.Atuador.PercentualReservatorio.ToString("0.00");
gridDados.Rows[22].Cells[1].Value = _Sensoriamento.Atuador.VolumeReservatorio.ToString("0.000");
gridDados.Rows[22].Cells[1].Value = $"{_Sensoriamento.Atuador.VolumeReservatorio:0.000} ({Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.ContadorCarga?.MassaAtual_Kg_Calc ?? 0:0.000} Kg)";
gridDados.Rows[23].Cells[1].Value = _Sensoriamento.Atuador.LPorMetro.ToString("0.000");
gridDados.Rows[24].Cells[1].Value = _Sensoriamento.Atuador.LPorMinuto.ToString("0.000");
gridDados.Rows[25].Cells[1].Value = TimeSpan.FromMinutes(_Sensoriamento.Atuador.TempoEstimadoRestanteMinutos).ToString(@"hh\:mm\:ss");
@ -547,7 +547,7 @@ namespace AgroBase.Forms.Operacoes
gridDados.Rows[27].Cells[1].Value = _Sensoriamento.Atuador.PressaoLinha.ToString("0.00");
gridDados.Rows[28].Cells[1].Value = _Sensoriamento.Atuador.LeituraPotenciaBomba.ToString("0.00");
gridDados.Rows[29].Cells[1].Value = _Sensoriamento.Atuador.VazaoInstantanea.ToString("0.00");
gridDados.Rows[30].Cells[1].Value = _Sensoriamento.Atuador.VazaoMedia.ToString("0.00");
gridDados.Rows[30].Cells[1].Value = $"{_Sensoriamento.Atuador.VazaoMedia:0.000} ({Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.VazaoFluxoMLpSInstantaneaCalc:0.000})";
gridDados.Rows[31].Cells[1].Value = _Sensoriamento.Atuador.VolumeVazaoMl.ToString("0.00");
gridDados.Rows[32].Cells[1].Value = _Sensoriamento.Atuador.AnguloBarraEsquerda.ToString("0.00");
gridDados.Rows[33].Cells[1].Value = _Sensoriamento.Atuador.AnguloBarraDireita.ToString("0.00");
@ -660,7 +660,7 @@ namespace AgroBase.Forms.Operacoes
{
var Atuador = Variaveis.OperacaoEmAndamento.DispAtu.Dados;
bool ligado = Atuador.BombasPressurizadoras.FirstOrDefault()?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor > 0;
bool ligado = Atuador.BombasPressurizadoras.FirstOrDefault()?._Potencia > 0;
AtuadorFuncoesGerais.DesenharAtuadores(
pnlAtuadores,
e,
@ -673,7 +673,7 @@ namespace AgroBase.Forms.Operacoes
Inicializado = x.Inicializado,
MediaNivelFluxo = x.MediaNivelFluxo,
Posicao = x.Posicao,
StatusBico = x.ValoresLeituras?.FirstOrDefault(y => y.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor == Estado.Ligado,
StatusBico = x._EstadoLeitura == Estado.Ligado,
TempoAtuado = x.TempoAtuado,
}).ToList(),
ligado,

View File

@ -178,9 +178,9 @@ namespace AgroBase.Forms.Operacoes
Inicializado = x.Inicializado,
MediaNivelFluxo = x.MediaNivelFluxo,
Posicao = x.Posicao,
StatusBico = x.ValoresLeituras.FirstOrDefault(y => y.funcao == FuncoesPinout.EstadoLeitura).atual.valor ?? false,
StatusBico = x._EstadoLeitura == Enums.Estado.Ligado,
TempoAtuado = x.TempoAtuado,
}).ToList(), Atuador.BombasPressurizadoras.FirstOrDefault().ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0 > 0, Atuador.PressaoLinha, Atuador.TempoAtuado);
}).ToList(), Atuador.BombasPressurizadoras.FirstOrDefault()._Potencia > 0, Atuador.PressaoLinha, Atuador.TempoAtuado);
}
private void pnlCaminho_Paint(object sender, PaintEventArgs e)

View File

@ -134,6 +134,7 @@
sIUV = 31,
sQAR = 32,
sCHV = 33,
sSRV = 34,
}
public enum BotoesJoystick

View File

@ -59,6 +59,7 @@ namespace AgroBase.Models.Modules
public List<AtuadorBicoModel> BicosPulverizadores { get; set; }
public List<AtuadorBombaModel> BombasPressurizadoras { get; set; }
public List<SensorModel> Sensores { get; set; }
public List<SensorServoModel> Servos { get; set; }
public string ScriptDeteccaoErvas { get; set; } = PythonService.ScriptWeedDetector;
public AsyncTaskTimerModel tmrRegistrador;
@ -95,14 +96,29 @@ namespace AgroBase.Models.Modules
public HerbicideCounterService ContadorCarga = new HerbicideCounterService(VariaveisEquipamento.CapacidadeReservatorio, VariaveisEquipamento.DensidadeHerbicida);
#region VAZAO
private SensorModel SensorFluxoLinha => Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX && x.ID == "FLXLN");
public double VolumeVazaoAferido { get; set; } = 0;
public double _FluxoMlRef { get; set; } = 600;
public double _FluxoPulsoRef { get; set; } = 538;
public double VazaoFluxoMLpSInstantanea
public double VazaoFluxoMLpSInstantanea => SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Fluxo)?.atual?.valor ?? 0;
public double VazaoFluxoMLpSInstantaneaCalc
{
get
{
return Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX)?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Fluxo)?.atual?.valor ?? 0;
int pulsos = SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.QtdPulsos)?.atual?.valor ?? 0;
int periodo = SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Periodo)?.atual?.valor ?? 0;
if (pulsos <= 0 || periodo <= 0) return 0.0;
double frequencia = (double)pulsos / (double)periodo * 1000.0; // Hz
// Equação do fabricante: F = 8.1*q - 3 (q em L/min)
double q_L_min = (frequencia + 3.0) / 8.1;
// Limites físicos do sensor (do próprio anúncio): 0.310 L/min
if (q_L_min < 0) q_L_min = 0; // evita negativo perto do zero
if (q_L_min > 10.0) q_L_min = 10.0; // opcional: clamp no máximo
// Converte para mL/s
double q_mL_s = q_L_min * (1000.0 / 60.0);
return q_mL_s;
}
}
private double _somaVazao; // Acumula a soma da vazão para calcular a média
@ -139,7 +155,8 @@ namespace AgroBase.Models.Modules
}
public void AtualizaPercentualErvas()
{
double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.TempoDecorridoSeg * 1000.0;
//double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.TempoDecorridoSeg * 1000.0;
double tempoTotalOperacao = (Variaveis.OperacaoEmAndamento.Parametros?.DadosLeitura?.Movimentacao?.TempoMovimentoSegs ?? 0) * 1000.0;
if (tempoTotalOperacao > 0)
{
@ -189,26 +206,24 @@ namespace AgroBase.Models.Modules
#endregion
#region PRESSAO
public double _PressaoVmin { get; set; } = 0.0;
public double _PressaoVmax { get; set; } = 4.5;
public double _PressaoMax { get; set; } = 174.045; // 1,2 MPa
public double PressaoLinha
private SensorModel SensorPressaoLinha
{
get
{
return Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS)?.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Pressao)?.atual?.valor ?? 0;
return Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS && x.ID == "PRSLN");
}
}
public double _PressaoVmin { get; set; } = 0.0;
public double _PressaoVmax { get; set; } = 4.5;
public double _PressaoMax { get; set; } = 174.045; // 1,2 MPa
public double PressaoLinha => SensorPressaoLinha?.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Pressao)?.atual?.valor ?? 0;
public double PressaoLinhaCalc
{
get
{
//double _LeituraPressao = ((FirmwareSensorPressao)Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS)?.Leitura)?.Leitura ?? 0;
double _LeituraPressao = 0;
double _LeituraPressao = SensorPressaoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraBruta)?.atual?.valor ?? 0;
double tensao = FuncoesMatematicas.Map(_LeituraPressao, 0, 4095, 0, 3300) / 1000.0;
double pressao = FuncoesMatematicas.Map(tensao, _PressaoVmin, _PressaoVmax, 0, _PressaoMax);
return pressao;
}
}
@ -224,7 +239,7 @@ namespace AgroBase.Models.Modules
_EnderecoCAN_Rx = 0x12,
_TaxaAmostragem = 1000,
RequisitarDados = true,
// 71 ~ 74
// 71 ~ 73
BicosPulverizadores = new List<AtuadorBicoModel>(),
// 51 ~ 51
BombasPressurizadoras = new List<AtuadorBombaModel>()
@ -304,10 +319,22 @@ namespace AgroBase.Models.Modules
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.QtdPulsos,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Periodo,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Fluxo,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
indice = 2,
analise_health = true,
maximo = 20,
minimo = 0,
@ -350,9 +377,15 @@ namespace AgroBase.Models.Modules
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Massa,
funcao = FuncoesPinout.LeituraBruta,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Massa,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
analise_health = true,
maximo = 35,
minimo = 0,
@ -410,9 +443,15 @@ namespace AgroBase.Models.Modules
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Pressao,
funcao = FuncoesPinout.LeituraBruta,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Pressao,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
analise_health = true,
maximo = 120,
minimo = 0,
@ -587,6 +626,103 @@ namespace AgroBase.Models.Modules
}
},
},
// 91 ~ 93
Servos = new List<SensorServoModel>()
{
new SensorServoModel()
{
ID = "SRVB1",
ID_Num = 91,
Descricao = "Articulaccao Bico 01",
Componente = S_Code.sSRV,
Controlar = true,
Mandatorio = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Servo,
},
_AnguloControle = 90,
Incremental = true,
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.ServoAnguloLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
analise_health = true
},
}
},
new SensorServoModel()
{
ID = "SRVB2",
ID_Num = 92,
Descricao = "Articulaccao Bico 02",
Componente = S_Code.sSRV,
Controlar = true,
Mandatorio = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Servo,
},
_AnguloControle = 90,
Incremental = true,
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.ServoAnguloLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
analise_health = true
},
}
},
new SensorServoModel()
{
ID = "SRVB3",
ID_Num = 93,
Descricao = "Articulaccao Bico 03",
Componente = S_Code.sSRV,
Controlar = true,
Mandatorio = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Servo,
},
_AnguloControle = 90,
Incremental = true,
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.ServoAnguloLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
analise_health = true
},
}
},
},
};
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdBicos; i++)
{
@ -595,6 +731,7 @@ namespace AgroBase.Models.Modules
{
ID = "B" + posicao.ToString("00"),
ID_Num = 70 + posicao,
Servo_ID_Num = 90 + posicao,
Componente = S_Code.sBIC,
Posicao = posicao,
Atuacoes = 0,
@ -624,6 +761,12 @@ namespace AgroBase.Models.Modules
funcao = FuncoesPinout.EstadoLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.ServoAnguloLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
}
}
});
@ -746,6 +889,10 @@ namespace AgroBase.Models.Modules
var sensoresConfig = SensoresConfig(Conectar, configurarTodos);
config.AddRange(sensoresConfig);
// Adicionar configurações dos Servos
var servosConfig = ServosConfig(Conectar, configurarTodos);
config.AddRange(servosConfig);
// Adicionar configurações dos Bicos
var bicosConfig = BicosConfig(Conectar, configurarTodos);
config.AddRange(bicosConfig);
@ -834,6 +981,27 @@ namespace AgroBase.Models.Modules
return config;
}
private List<(int, CanMessagePosicaoDados, byte[])> ServosConfig(bool Conectar, bool ConfigurarTodos)
{
var config = new List<(int, CanMessagePosicaoDados, byte[])>();
foreach (var servo in Servos.Where(x => (x.Controlar && (ConfigurarTodos ? true : x.Inicializado != Conectar)) || (!x.Controlar && x.Inicializado)))
{
if (!servo.Controlar && servo.Inicializado)
{
Conectar = false;
}
(CanMessagePosicaoDados posicao, var payload) = servo.ProtocoloConfiguracao(Pinout, Conectar);
if (payload != null)
{
config.Add((servo.ID_Num, posicao, payload));
}
}
return config;
}
public void IniciarRegistrador()
{
if (!(tmrRegistrador?.IsRunning ?? false))
@ -885,53 +1053,13 @@ namespace AgroBase.Models.Modules
AtualizaComponentesIniciados();
}
public (bool, List<string>) StatusModulosATU()
{
var Bicos = BicosPulverizadores.Where(x => x.Comandar).ToList();
var BicosComFalha = Bicos.Where(x => !x.Liberado).ToList();
bool _bicosOperantes = !BicosComFalha.Any();
var _bomba = BombasPressurizadoras.FirstOrDefault();
var _sensorFluxo = Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX);
bool _sensorFluxoOperante = !_sensorFluxo?.Liberado ?? false;
var _sensorMassa = Sensores.FirstOrDefault(x => x.Componente == S_Code.sMAS);
bool _sensorMassaOperante = !_sensorMassa?.Liberado ?? false;
var _sensorPressao = Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS);
bool _sensorPressaoOperante = !_sensorPressao?.Liberado ?? false;
List<string> ModsComFalha = BicosComFalha.Select(x => x.ID).ToList();
bool _bombaOperante = _bomba?.Liberado ?? false;
if (!_bombaOperante)
{
ModsComFalha.Add(_bomba?.ID);
}
if (!_sensorFluxoOperante)
{
ModsComFalha.Add(_sensorFluxo.ID);
}
if (!_sensorMassaOperante)
{
ModsComFalha.Add(_sensorMassa.ID);
}
if (!_sensorPressaoOperante)
{
ModsComFalha.Add(_sensorPressao.ID);
}
bool _atuadorOperante = _bombaOperante && _bicosOperantes && _sensorPressaoOperante && _sensorMassaOperante && _sensorFluxoOperante;
return (_atuadorOperante, ModsComFalha);
}
private void VerificaControleLeitura()
{
if (true) // !frmDiagnosticos.Diagnosticando
{
foreach (var bico in BicosPulverizadores.Where(x => x.Comandar && x.Inicializado))
{
Estado leituraEstado = (Estado?)(bico.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor) ?? Estado.Desligado;
Estado leituraEstado = bico._EstadoLeitura;
Estado comandoEstado = bico.ComandoAtuar ? Estado.Ligado : Estado.Desligado;
if (leituraEstado != comandoEstado)
{
@ -942,7 +1070,7 @@ namespace AgroBase.Models.Modules
var bomba = BombasPressurizadoras.FirstOrDefault(x => x.Comandar && x.Inicializado);
if (bomba != null)
{
bool leituraEstado = (bomba.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0) > 0;
bool leituraEstado = bomba._Potencia > 0;
// Desliga a bomba caso esteja ligada e o nivel de herbicida caiu
if (ContadorCarga.PercentualAtual < VariaveisEquipamento.PercentualReservatorioMin && leituraEstado == true)
@ -960,6 +1088,14 @@ namespace AgroBase.Models.Modules
GeneralJoystick.EnviarComandoAtuador(bomba.Componente, bomba.ID, Status: bomba.ComandoAtuar);
}
}
foreach (var servo in Servos.Where(x => x.Controlar && x.Inicializado))
{
if (servo._AnguloLeiutra != servo._AnguloControle)
{
GeneralJoystick.EnviarComandoSensoriamento(S_Code.sFRO, servo.ID, servo._AnguloControle);
}
}
}
}
@ -983,6 +1119,10 @@ namespace AgroBase.Models.Modules
{
sensor.Inicializado = false;
}
foreach (var servo in Servos.Where(x => x.Inicializado && x.UltimaLeitura.AddMilliseconds(TempoLimiteConexao) < Agora))
{
servo.Inicializado = false;
}
}
@ -1126,6 +1266,7 @@ namespace AgroBase.Models.Modules
public int Posicao { get; set; }
public S_Code Componente { get; set; } = S_Code.sBIC;
public bool AtuacaoNivelAlto { get; set; }
public int Servo_ID_Num { get; set; }
public double AnguloControle { get; set; }
public double AnguloAbertura { get; set; }
private bool _atuado;
@ -1162,7 +1303,7 @@ namespace AgroBase.Models.Modules
}
}
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
public Estado _EstadoLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado;
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
@ -1174,6 +1315,7 @@ namespace AgroBase.Models.Modules
(byte)Componente,
(byte)(conectar ? 1 : 0),
(byte)(AtuacaoNivelAlto ? 1 : 0),
(byte)Servo_ID_Num,
(byte)(pino?.Barramento ?? TiposBarramentos.CONTROLADOR),
(byte)(pino?.Pino ?? PinoutUtils.PINO_INVALIDO)
};
@ -1188,7 +1330,8 @@ namespace AgroBase.Models.Modules
CanMessagePosicaoDados.Command1,
new byte[]
{
(byte)(ComandoAtuar ? Estado.Ligado : Estado.Desligado)
(byte)(ComandoAtuar ? Estado.Ligado : Estado.Desligado),
(byte)AnguloControle
}
);
}
@ -1259,6 +1402,7 @@ namespace AgroBase.Models.Modules
public int ID_Num { get; set; }
public bool ComandoAtuar { get; set; }
public S_Code Componente { get; set; } = S_Code.sBMB;
public int Sensor_ID_Num { get; set; }
public bool Comandar { get; set; }
public bool Mandatorio { get; set; }
public bool Liberado
@ -1278,6 +1422,9 @@ namespace AgroBase.Models.Modules
}
}
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
public Estado _EstadoLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado;
public double _Potencia => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0;
@ -1289,6 +1436,7 @@ namespace AgroBase.Models.Modules
(byte)Componente,
(byte)(conectar ? 1 : 0),
(byte)Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha,
(byte)Sensor_ID_Num,
(byte)(pinout.Pinos.FirstOrDefault(x => x.ComponenteID == ID && x.Funcao == FuncoesPinout.ENA)?.Pino ?? PinoutUtils.PINO_INVALIDO),
(byte)(pinout.Pinos.FirstOrDefault(x => x.Funcao == FuncoesPinout.CS)?.Pino ?? PinoutUtils.PINO_INVALIDO),
};
@ -1503,21 +1651,6 @@ namespace AgroBase.Models.Modules
}
public class FirmwareBombaPressurizadora : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<Estado> Estado { get; set; } = new CanCommandFreqModel<Estado>();
public CanCommandFreqModel<double> Potencia { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> PressaoSP { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> Pressao { get; set; } = new CanCommandFreqModel<double>();
}
public class AtuadorMensagemJsonModel
{
public DateTime Momento { get; set; }
@ -1527,9 +1660,10 @@ namespace AgroBase.Models.Modules
public string Mod_ID { get; set; }
public int QualidadeWifi { get; set; }
public int LatenciaLoop { get; set; }
public List<AtuadorBicoModel> BicosPulverizadores { get; set; } = new List<AtuadorBicoModel>();
public List<AtuadorBombaModel> BombasPressurizadoras { get; set; } = new List<AtuadorBombaModel>();
public List<SensorModel> Sensores { get; set; } = new List<SensorModel>();
public List<AtuadorBicoModel> BicosPulverizadores { get; set; }
public List<AtuadorBombaModel> BombasPressurizadoras { get; set; }
public List<SensorModel> Sensores { get; set; }
public List<SensorServoModel> Servos { get; set; }
public DateTime UltimoComandoRespondido { get; set; }
}
@ -1566,8 +1700,9 @@ namespace AgroBase.Models.Modules
var sensor = Disp.Sensores.FirstOrDefault(x => x.ID_Num == ID_Num);
var bico = Disp.BicosPulverizadores.FirstOrDefault(x => x.ID_Num == ID_Num);
var bomba = Disp.BombasPressurizadoras.FirstOrDefault(x => x.ID_Num == ID_Num);
var servo = Disp.Servos.FirstOrDefault(x => x.ID_Num == ID_Num);
return sensor?.Componente ?? bico?.Componente ?? bomba?.Componente ?? S_Code.sVZO;
return sensor?.Componente ?? bico?.Componente ?? bomba?.Componente ?? servo?.Componente ?? S_Code.sVZO;
}
private void AtualizarDados(int CompID_Num, CanMessagePosicaoDados Posicao, S_Code componente, List<dynamic> Parametros)
@ -1577,12 +1712,14 @@ namespace AgroBase.Models.Modules
var sensor = Dados.Sensores.FirstOrDefault(x => x.ID_Num == CompID_Num);
var bomba = Dados.BombasPressurizadoras.FirstOrDefault(x => x.ID_Num == CompID_Num);
var bico = Dados.BicosPulverizadores.FirstOrDefault(x => x.ID_Num == CompID_Num);
var servo = Dados.Servos.FirstOrDefault(x => x.ID_Num == CompID_Num);
List<SensorValoresLeituraModel> valoresLeituras = new List<SensorValoresLeituraModel>();
if (sensor != null) valoresLeituras = sensor.ValoresLeituras;
else if (bomba != null) valoresLeituras = bomba.ValoresLeituras;
else if (bico != null) valoresLeituras = bico.ValoresLeituras;
else if (servo != null) valoresLeituras = servo.ValoresLeituras;
for (int i = 0; i < valoresLeituras.Where(x => x.posicao == Posicao).Count(); i++)
{
@ -1610,6 +1747,8 @@ namespace AgroBase.Models.Modules
bomba.Inicializado = v;
if (bico != null)
bico.Inicializado = v;
if (servo != null)
servo.Inicializado = v;
}
}
}
@ -1681,7 +1820,8 @@ namespace AgroBase.Models.Modules
case CanMessagePosicaoDados.Dados1:
{
Estado estado = (Estado)data[2];
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { estado });
int angulo = data[3];
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { estado, angulo });
break;
}
}
@ -1699,8 +1839,10 @@ namespace AgroBase.Models.Modules
}
case CanMessagePosicaoDados.Dados1:
{
double vazao = ConverterByteParaDouble(data, 2);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { vazao });
int qtdPulsos = data[2];
ushort periodo = Converter2BytesU16(data, 3);
double vazao = ConverterByteParaDouble(data, 5);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { qtdPulsos, periodo, vazao });
break;
}
}
@ -1718,8 +1860,9 @@ namespace AgroBase.Models.Modules
}
case CanMessagePosicaoDados.Dados1:
{
double massa = ConverterByteParaDouble(data, 2);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { massa });
double raw = ConverterByteParaDouble(data, 2);
double massa = ConverterByteParaDouble(data, 4);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { raw, massa });
break;
}
}
@ -1737,8 +1880,9 @@ namespace AgroBase.Models.Modules
}
case CanMessagePosicaoDados.Dados1:
{
double pressao = ConverterByteParaDouble(data, 2);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { pressao });
ushort raw = Converter2BytesU16(data, 2);
double pressao = ConverterByteParaDouble(data, 4);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { raw, pressao });
break;
}
}
@ -1787,9 +1931,28 @@ namespace AgroBase.Models.Modules
}
break;
}
case S_Code.sSRV:
{
switch (posicao)
{
case CanMessagePosicaoDados.Status:
{
bool Iniciado = data[2] == 1;
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
break;
}
case CanMessagePosicaoDados.Dados1:
{
int angulo = data[2];
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { angulo });
break;
}
}
break;
}
}
Dados.DadosLeitura.UltimoComandoRespondido = DateTime.Now;
Variaveis.OperacaoEmAndamento.DispAtu.Dados.AtualizarDadosSensoresExternos(componente, ID_Num);

View File

@ -37,6 +37,7 @@ namespace AgroBase.Models.Modules
public string IP_Mov { get; set; } = Variaveis.FaixaIPethernet + ".10";
public string IP_Dir { get; set; } = Variaveis.FaixaIPethernet + ".11";
public DateTime UltimoTickRegistrador = DateTime.MinValue;
public static int LogsManter { get; set; } = 60;
public AsyncTaskTimerModel tmrRegistrador;
@ -138,6 +139,7 @@ namespace AgroBase.Models.Modules
Dados.DistanciaPercorridaOperacao = 0;
Dados.VelocidadeMedia = 0;
Dados.TempoEmAtividade = 0;
Dados.UltimoTickRegistrador = DateTime.MinValue;
Dados.Modulos.ForEach(x =>
{
x.MovMotor.AlarmeSensores = false;
@ -220,7 +222,11 @@ namespace AgroBase.Models.Modules
var UltimaDirecao = Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == T_Code.Mov)?.UltimaDirecao ?? Direcao.Parado;
if (UltimaDirecao != Direcao.Parado)
{
double tempo = _TaxaAmostragem / 1000.0;
//double tempo = _TaxaAmostragem / 1000.0;
DateTime agora = DateTime.Now;
double tempo = UltimoTickRegistrador == DateTime.MinValue ? 0 : (agora - UltimoTickRegistrador).TotalSeconds;
UltimoTickRegistrador = agora;
double distancia = tempo * VelocidadeMedia;
DistanciaPercorridaTotal += distancia;
DistanciaPercorridaParcial += ((UltimaDirecao == Direcao.Frente ? 1 : UltimaDirecao == Direcao.Tras ? -1 : 0) * distancia);

View File

@ -405,7 +405,7 @@ namespace AgroBase.Models.Modules
ModbusDI,
ModbusRO,
ModbusDE_RE,
ServoFreio,
Servo,
Potenciometro,
M0,
M1,
@ -432,7 +432,9 @@ namespace AgroBase.Models.Modules
CodAlarme,
LeituraBruta,
LeituraAngulo,
Cooler
Cooler,
QtdPulsos,
Periodo
}
public static class PinoutUtils

View File

@ -1211,10 +1211,16 @@ namespace AgroBase.Models.Modules
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.LeituraBruta,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.LuzUV,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
indice = 1,
analise_health = true,
maximo = 11.0,
minimo = 0.0,
@ -1263,10 +1269,16 @@ namespace AgroBase.Models.Modules
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.LeituraBruta,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Gas,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
indice = 1,
analise_health = true,
maximo = 600.0,
minimo = 0.0,
@ -1315,10 +1327,16 @@ namespace AgroBase.Models.Modules
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.LeituraBruta,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Gas,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
indice = 1,
analise_health = true,
maximo = 400.0,
minimo = 0.0,
@ -1510,10 +1528,16 @@ namespace AgroBase.Models.Modules
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.LeituraBruta,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Chuva,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
indice = 1,
analise_health = true,
maximo = 100.0,
minimo = 0.0,
@ -1753,12 +1777,12 @@ namespace AgroBase.Models.Modules
ID = "FROET",
ID_Num = 41,
Descricao = "Freio Motor ET",
Componente = S_Code.sFRO,
Componente = S_Code.sSRV,
Controlar = true,
Mandatorio = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.ServoFreio,
FuncoesPinout.Servo,
},
_AnguloControle = 0,
Incremental = true,
@ -1784,12 +1808,12 @@ namespace AgroBase.Models.Modules
ID = "FROEF",
ID_Num = 42,
Descricao = "Freio Motor EF",
Componente = S_Code.sFRO,
Componente = S_Code.sSRV,
Controlar = false,
Mandatorio = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.ServoFreio,
FuncoesPinout.Servo,
},
_AnguloControle = 0,
Incremental = true,
@ -1815,12 +1839,12 @@ namespace AgroBase.Models.Modules
ID = "FRODT",
ID_Num = 43,
Descricao = "Freio Motor DT",
Componente = S_Code.sFRO,
Componente = S_Code.sSRV,
Controlar = true,
Mandatorio = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.ServoFreio,
FuncoesPinout.Servo,
},
_AnguloControle = 180,
Incremental = false,
@ -1846,12 +1870,12 @@ namespace AgroBase.Models.Modules
ID = "FRODF",
ID_Num = 44,
Descricao = "Freio Motor DF",
Componente = S_Code.sFRO,
Componente = S_Code.sSRV,
Controlar = false,
Mandatorio = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.ServoFreio,
FuncoesPinout.Servo,
},
_AnguloControle = 180,
Incremental = false,
@ -2263,35 +2287,6 @@ namespace AgroBase.Models.Modules
AtualizaComponentesIniciados();
}
public (bool, List<string>) StatusModulosSEN()
{
var _Sensores = Sensores?.Where(x => x.Aferir).ToList();
var _SensoresComFalha = _Sensores?.Where(x => !x.Liberado).ToList();
bool _sensoresOperantes = (_SensoresComFalha?.Count() ?? 0) < (_Sensores?.Count() ?? 0);
var _Sinaleiros = Sinaleiros?.ToList();
var _SinaleirosComFalha = _Sinaleiros?.Where(x => !x.Inicializado).ToList();
bool _sinaleirosOperantes = !(_SinaleirosComFalha?.Any() ?? false);
var _Reles = Reles?.Where(x => x.Controlar).ToList();
var _RelesComFalha = _Reles?.Where(x => !x.Liberado).ToList();
bool _relesOperantes = !(_RelesComFalha?.Any() ?? false);
var _Servos = Servos?.Where(x => x.Controlar).ToList();
var _ServosComFalha = _Servos?.Where(x => !x.Liberado).ToList();
bool _servosOperantes = !(_ServosComFalha?.Any() ?? false);
bool _sensoriamentoOperante = _sinaleirosOperantes && _sensoresOperantes && _relesOperantes && _servosOperantes;
List<string> ModsComFalha =
(_SensoresComFalha?.Select(x => x.ID) ?? new List<string>())
.Union(_SinaleirosComFalha?.Select(x => x.ID) ?? new List<string>())
.Union(_RelesComFalha?.Select(x => x.ID) ?? new List<string>())
.Union(_ServosComFalha?.Select(x => x.ID) ?? new List<string>())
.ToList();
return (_sensoriamentoOperante, ModsComFalha);
}
private void VerificaControleLeitura()
{
if (true) // !frmDiagnosticos.Diagnosticando
@ -2334,8 +2329,7 @@ namespace AgroBase.Models.Modules
foreach (var servo in Servos.Where(x => x.Controlar && x.Inicializado))
{
int leituraAngulo = (int?)(servo.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.ServoAnguloLeitura)?.atual?.valor) ?? 0;
if (leituraAngulo != servo._AnguloControle)
if (servo._AnguloLeiutra != servo._AnguloControle)
{
GeneralJoystick.EnviarComandoSensoriamento(S_Code.sFRO, servo.ID, servo._AnguloControle);
}
@ -2369,73 +2363,6 @@ namespace AgroBase.Models.Modules
}
}
public void AtualizarStatusComponentes()
{
var StatusSaudaveis = new List<StatusModulo>() { StatusModulo.Desconectado, StatusModulo.Falha };
var saudeSen = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesSaudeModel>(RedisService.ModKey(T_Code.Sen), "saude");
DadosLeitura.Conectado = !StatusSaudaveis.Contains(saudeSen?.status ?? StatusModulo.Desconectado);
if (DadosLeitura.Conectado)
{
var objetos =
Sensores
.Select(x => new
{
Chave = "sensores",
Componente = x.Componente,
ID_Num = x.ID_Num
})
.Union(Servos
.Select(x => new
{
Chave = "servos",
Componente = x.Componente,
ID_Num = x.ID_Num
}))
.ToList();
foreach (var sensor in objetos)
{
string chave = sensor.Chave;
int tipo = (int)sensor.Componente;
int id = sensor.ID_Num;
string basePath = $"{chave}.{tipo}.{id}";
var saude = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesSaudeModel>(RedisService.ModKey(T_Code.Sen), $"{basePath}.saude");
bool inicializado = !StatusSaudaveis.Contains(saude?.status ?? StatusModulo.Desconectado);
switch (chave)
{
case "sensores":
Sensores.FirstOrDefault(x => x.ID_Num == sensor.ID_Num).Inicializado = inicializado;
break;
case "servos":
Servos.FirstOrDefault(x => x.ID_Num == sensor.ID_Num).Inicializado = inicializado;
break;
}
}
}
else
{
foreach (var led in Sinaleiros.Where(x => x.Inicializado))
{
led.Inicializado = false;
}
foreach (var rele in Reles.Where(x => x.Inicializado))
{
rele.Inicializado = false;
}
foreach (var servo in Servos.Where(x => x.Inicializado))
{
servo.Inicializado = false;
}
foreach (var sensor in Sensores.Where(x => x.Inicializado))
{
sensor.Inicializado = false;
}
}
}
}
public class SensorModel
@ -2562,7 +2489,6 @@ namespace AgroBase.Models.Modules
}
public bool AtuacaoNivelAlto { get; set; }
public Estado StatusControle { get; set; }
public Estado StatusLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado;
public bool Inicializado { get; set; }
public DateTime UltimaLeitura
{
@ -2572,6 +2498,8 @@ namespace AgroBase.Models.Modules
}
}
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
public Estado _EstadoLeitura => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado;
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
{
@ -2718,19 +2646,6 @@ namespace AgroBase.Models.Modules
}
}
public class SenSensorimanetoGrafico
{
public DateTime Momento { get; set; }
public string ComponenteID { get; set; }
public S_Code Componente { get; set; }
public double Leitura1 { get; set; }
public double Leitura2 { get; set; }
public double Leitura3 { get; set; }
public double Leitura4 { get; set; }
public bool AlarmeMaxima { get; set; }
public bool AlarmeMinima { get; set; }
}
public class SensorParametroModel
{
public string Descricao { get; set; }
@ -2779,247 +2694,6 @@ namespace AgroBase.Models.Modules
public string unidade_medida { get; set; }
}
public class FirmwareSensorTemperaturaNTC : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> Temperatura { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorCorrente : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> BusVoltage { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> ShuntVoltage { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> Current { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> Power { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> Energy { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> Temperature { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSinaleiro : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<StatusLED> Leitura { get; set; } = new CanCommandFreqModel<StatusLED>();
public CanCommandFreqModel<StatusLED> Comando { get; set; } = new CanCommandFreqModel<StatusLED>();
}
public class FirmwareRele : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<Estado> Leitura { get; set; } = new CanCommandFreqModel<Estado>();
}
public class FirmwareServoFreio : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> Angulo { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorFluxo : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> Vazao { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorMassa : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> Massa { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorPressao : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> Pressao { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorIMU : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public double AccX { get; set; }
public double AccY { get; set; }
public double AccZ { get; set; }
public double GyrX { get; set; }
public double GyrY { get; set; }
public double GyrZ { get; set; }
public double MagX { get; set; }
public double MagY { get; set; }
public double MagZ { get; set; }
public double Temperatura { get; set; }
public double Pressao { get; set; }
public double Altitude { get; set; }
public double Roll { get; set; }
public double Pitch { get; set; }
public double Yaw { get; set; }
public double YawFixed
{
get
{
double angulo = Yaw;
// ✅ Aplica o offset armazenado
return GPSUtils.NormalizarAngulo(GPSUtils.NormalizarAngulo(angulo) + Offset);
}
}
public double Offset { get; set; } = 0.0;
private DateTime ultimaAtualizacaoOffset = DateTime.MinValue;
public void AtualizarOffset(GPSModel UltimaLeitura)
{
// Verifica se a qualidade do GPS é boa
if (UltimaLeitura.QualidadeFix == TiposCorrecaoGPS.RTKFixo || UltimaLeitura.QualidadeFix == TiposCorrecaoGPS.RTKFlutuante)
{
// Só atualiza o offset se a última atualização foi há pelo menos 2 segundos (evita variações rápidas)
if ((DateTime.Now - ultimaAtualizacaoOffset).TotalSeconds > 2)
{
// Suaviza a mudança do offset para evitar grandes variações
double novoOffset = UltimaLeitura.OrientacaoReal - YawFixed;
Offset = (Offset * 0.8) + (novoOffset * 0.2); // Filtro exponencial
// Atualiza o tempo da última atualização
ultimaAtualizacaoOffset = DateTime.Now;
}
}
}
public FirmwareSensorIMU Clone()
{
return new FirmwareSensorIMU()
{
ID_Num = ID_Num,
Iniciado = Iniciado,
Pitch = Pitch,
Roll = Roll,
Yaw = Yaw,
Temperatura = Temperatura,
Altitude = Altitude,
Pressao = Pressao,
AccX = AccX,
AccY = AccY,
AccZ = AccZ,
MagX = MagX,
MagY = MagY,
MagZ = MagZ,
GyrX = GyrX,
GyrY = GyrY,
GyrZ = GyrZ,
Offset = Offset,
};
}
public string DadosToString()
{
return
$"[IMU] " +
$"Iniciado: {Iniciado}, " +
$"AccX: {AccX}, " +
$"AccY: {AccY}, " +
$"AccZ: {AccZ}, " +
$"GyrX: {GyrX}, " +
$"GyrY: {GyrY}, " +
$"GyrZ: {GyrZ}, " +
$"MagX: {MagX}, " +
$"MagY: {MagY}, " +
$"MagZ: {MagZ}, " +
$"Temperatura: {Temperatura}, " +
$"Pressao: {Pressao}, " +
$"Altitude: {Altitude}, " +
$"Roll: {Roll}, " +
$"Pitch: {Pitch}, " +
$"Yaw: {Yaw}, " +
$"Yaw Corrigido: {YawFixed}";
}
}
public class FirmwareSensorGas : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> PPM { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorTemperaturaSHT : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> Temperatura { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> Umidade { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorLuminosidade : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> Lux { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorLuzUV : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> IndiceUV { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorQualidadeAr : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> TVOC { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> ECO2 { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> AQI { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> Temperatura { get; set; } = new CanCommandFreqModel<double>();
public CanCommandFreqModel<double> Umidade { get; set; } = new CanCommandFreqModel<double>();
}
public class FirmwareSensorChuva : IFirmwareSensorBase
{
public DateTime Momento { get; set; }
public string ID { get; set; }
public int ID_Num { get; set; }
public bool Iniciado { get; set; }
public CanCommandFreqModel<double> Percentual { get; set; } = new CanCommandFreqModel<double>();
}
public class SensoriamentoMensagemJsonModel
{
public DateTime Momento { get; set; }
@ -3334,8 +3008,9 @@ namespace AgroBase.Models.Modules
}
case CanMessagePosicaoDados.Dados1:
{
double temperatura = ConverterByteParaDouble(data, 2);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { temperatura });
ushort raw = Converter2BytesU16(data, 2);
double temperatura = ConverterByteParaDouble(data, 4);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { raw, temperatura });
break;
}
}
@ -3410,7 +3085,7 @@ namespace AgroBase.Models.Modules
}
break;
}
case S_Code.sFRO:
case S_Code.sSRV:
{
switch (posicao)
{
@ -3494,8 +3169,9 @@ namespace AgroBase.Models.Modules
}
case CanMessagePosicaoDados.Dados1:
{
double ppm = ConverterBytesParaDouble32(data, 2);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { ppm });
ushort raw = Converter2BytesU16(data, 2);
double ppm = ConverterBytesParaDouble32(data, 4);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { raw, ppm });
break;
}
}
@ -3552,8 +3228,9 @@ namespace AgroBase.Models.Modules
}
case CanMessagePosicaoDados.Dados1:
{
double iuv = ConverterByteParaDouble(data, 2);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { iuv });
ushort raw = Converter2BytesU16(data, 2);
double iuv = ConverterByteParaDouble(data, 4);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { raw, iuv });
break;
}
}
@ -3599,8 +3276,9 @@ namespace AgroBase.Models.Modules
}
case CanMessagePosicaoDados.Dados1:
{
double percentual = ConverterByteParaDouble(data, 2);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { percentual });
ushort raw = Converter2BytesU16(data, 2);
double percentual = ConverterByteParaDouble(data, 4);
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { raw, percentual });
break;
}
}

View File

@ -1461,7 +1461,7 @@ namespace AgroBase.Models
{
foreach (var Bomba in Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras)
{
bool Ligado = Bomba.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor > 0;
bool Ligado = Bomba._Potencia > 0;
if (!Ligado)
{
Variaveis.OperacaoEmAndamento.Controle.BombaAtuada = true;
@ -1694,6 +1694,7 @@ namespace AgroBase.Models
if (controleBase.Controle.PercentualVelocidadeSP != null) _Controle.PercentualVelocidadeSP = (double)controleBase.Controle.PercentualVelocidadeSP;
if (controleBase.Controle.AnguloSP != null) _Controle.Angulo = (double)controleBase.Controle.AnguloSP;
if (controleBase.Controle.TipoMovimentoDirecional != null) _Controle.TipoMovimento = (TipoMovimentoDirecional)controleBase.Controle.TipoMovimentoDirecional;
if (controleBase.Controle.EmFreio != null) _Controle.EmFreio = (bool)controleBase.Controle.EmFreio;
Keys tecla = GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.botaoJoy == controleBase.Tecla)?.key ?? Keys.Escape;
GeneralJoystick.EnviaComandoMotor(tecla, controleBase.Dispositivo, ForcarComando: true, ID: controleBase._comp_id);
@ -1821,7 +1822,7 @@ namespace AgroBase.Models
VolumeReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.VolumeAtual_L,
PressaoLinha_SP = Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha,
PressaoLinha = Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha,
PotenciaBomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0,
PotenciaBomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?._Potencia ?? 0,
BombaLigada = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault().ComandoAtuar,
VazaoFluxoMLpSInstantanea = Variaveis.OperacaoEmAndamento.DispAtu.Dados.VazaoFluxoMLpSInstantanea,
VazaoFluxoMLpSMedia = Variaveis.OperacaoEmAndamento.DispAtu.Dados.VazaoFluxoMLpSMedia,
@ -1836,7 +1837,7 @@ namespace AgroBase.Models
Atuado = Bico.ComandoAtuar,
MediaNivelFluxo = Bico.MediaNivelFluxo,
Posicao = Bico.Posicao,
StatusBico = Bico.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor == Estado.Ligado,
StatusBico = Bico._EstadoLeitura == Estado.Ligado,
Atuacoes = Bico.Atuacoes,
TempoAtuado = Bico.TempoAtuado,
}).ToList(),
@ -2245,6 +2246,7 @@ namespace AgroBase.Models
public double? PercentualVelocidadeSP { get; set; }
public double? AnguloSP { get; set; }
public TipoMovimentoDirecional? TipoMovimentoDirecional { get; set; }
public bool? EmFreio { get; set; }
public bool? Estado { get; set; }
public double? Altura { get; set; }
}
@ -2376,13 +2378,14 @@ namespace AgroBase.Models
PercentualErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.estatisticas?.erva?.ema_global ?? 0,
PercentualReservatorio = _Reservatorio.PercentualAtual,
VolumeReservatorio = _Reservatorio.VolumeAtual_L,
MassaReservatorio = _Reservatorio.MassaAtual_Kg,
PressaoLinha = _DispAtu.Dados.PressaoLinha,
VazaoInstantanea = _DispAtu.Dados.VazaoFluxoMLpSInstantanea,
VazaoMedia = _DispAtu.Dados.VazaoFluxoMLpSMedia,
TempoBombaAtuada = _DispAtu.Dados.TempoAtuado,
ComandoBomba = _DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?.ComandoAtuar ?? false,
LeituraComandoBomba = (_DispAtu.Dados.BombasPressurizadoras.FirstOrDefault().ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado) == Estado.Ligado,
LeituraPotenciaBomba = FuncoesMatematicas.Clamp(_DispAtu.Dados.BombasPressurizadoras.FirstOrDefault().ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0, 0, 100),
ComandoBomba = _DispAtu.Dados.BombasPressurizadoras.FirstOrDefault().ComandoAtuar,
LeituraComandoBomba = _DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()._EstadoLeitura == Estado.Ligado,
LeituraPotenciaBomba = FuncoesMatematicas.Clamp(_DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()._Potencia, 0, 100),
VolumeVazaoMl = _DispAtu.Dados.VolumeVazaoML,
Iniciados = _DispAtu.Dados.Sensores.Select(s => new { s.ID, s.Inicializado }).Union(_DispAtu.Dados.BicosPulverizadores.Select(b => new { b.ID, b.Inicializado })).Union(_DispAtu.Dados.BombasPressurizadoras.Select(b => new { b.ID, b.Inicializado })).ToDictionary(x => x.ID, x => x.Inicializado),
AnguloBarraEsquerda = _DispAtu.Dados.AnguloBarraEsquerda,
@ -2401,7 +2404,7 @@ namespace AgroBase.Models
Atuado = Bico.ComandoAtuar,
MediaNivelFluxo = Bico.MediaNivelFluxo,
Posicao = Bico.Posicao,
StatusBico = Bico.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor == Estado.Ligado,
StatusBico = Bico._EstadoLeitura == Estado.Ligado,
Atuacoes = Bico.Atuacoes,
TempoAtuado = Bico.TempoAtuado,
AnguloAbertura = Bico.AnguloAbertura,
@ -2577,7 +2580,7 @@ namespace AgroBase.Models
DispositivosMapeados = new List<DispositivoDetalhesModel>(SerialService.DispositivosMapeados),
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(Variaveis.OperacaoEmAndamento.ModsCalibragem),
Temperaturas = _DispSen?.Dados?.Sensores?.Where(x => x.Componente == S_Code.sNTC)?.ToDictionary(x => x.ID, y => (double?)(y.ValoresLeituras?.FirstOrDefault(v => v.funcao == FuncoesPinout.Temperatura)?.atual?.valor) ?? -1),
Reles = _DispSen?.Dados?.Reles?.ToDictionary(x => x.ID, y => (y.StatusControle == Estado.Ligado, y.StatusLeitura == Estado.Ligado)),
Reles = _DispSen?.Dados?.Reles?.ToDictionary(x => x.ID, y => (y.StatusControle == Estado.Ligado, y._EstadoLeitura == Estado.Ligado)),
Servos = _DispSen?.Dados?.Servos?.ToDictionary(x => x.ID, y => (y._AnguloControle, y._AnguloLeiutra, y.Incremental)),
Iniciados = _DispSen?.Dados?.Servos?.Select(s => new { s.ID, s.Inicializado }).Union(_DispSen?.Dados?.Reles?.Select(r => new { r.ID, r.Inicializado })).Union(_DispSen?.Dados?.Sinaleiros?.Select(s => new { s.ID, s.Inicializado })).Union(_DispSen?.Dados?.Sensores?.Select(s => new { s.ID, s.Inicializado })).ToDictionary(s => s.ID, s => s.Inicializado),
Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()),
@ -2680,6 +2683,7 @@ namespace AgroBase.Models
public bool ErvasNoRadar { get; set; }
public double PercentualErvasNoRadar { get; set; }
public double PercentualReservatorio { get; set; }
public double MassaReservatorio { get; set; }
public double VolumeReservatorio { get; set; }
public double PressaoLinha { get; set; }
public double VazaoInstantanea { get; set; }
@ -2713,6 +2717,7 @@ namespace AgroBase.Models
PercentualErvasTerreno = PercentualErvasTerreno,
PercentualReservatorio = PercentualReservatorio,
VolumeReservatorio = VolumeReservatorio,
MassaReservatorio = MassaReservatorio,
PressaoLinha = PressaoLinha,
VazaoInstantanea = VazaoInstantanea,
VazaoMedia = VazaoMedia,

View File

@ -228,7 +228,7 @@ namespace AgroBase.Models
public static double PercentualReservatorioMin { get; set; } = 8.0;
public static double PercentualToleranciaPressaoLinha { get; set; } = 0.15;
public static int QuantidadeCamerasSolo { get; set; } = 1;
public static int QuantidadeBicosPulverizadores { get; set; } = 4;
public static int QuantidadeBicosPulverizadores { get; set; } = 3;
public static double AlturaBarraPulverizadoraCm { get; set; } = 80;
public static double ComprimentoBarraPulverizadoraCm { get; set; } = 103.7;
public static double DistanciaEntreBicosCm { get; set; } = 50;

View File

@ -157,9 +157,9 @@ namespace AgroBase.Services
private void EnviarComando()
{
if (ReleCoolerEntrada != null && (ReleCoolerEntrada?.StatusLeitura ?? Estado.Desligado) != CoolerEntradaEstado)
if (ReleCoolerEntrada != null && ReleCoolerEntrada._EstadoLeitura != CoolerEntradaEstado)
GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerEntrada.Componente, ReleCoolerEntrada.ID, CoolerEntradaEstado);
if (ReleCoolerSaida != null && (ReleCoolerSaida?.StatusLeitura ?? Estado.Desligado) != CoolerSaidaEstado)
if (ReleCoolerSaida != null && ReleCoolerSaida._EstadoLeitura != CoolerSaidaEstado)
GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerSaida.Componente, ReleCoolerSaida.ID, CoolerSaidaEstado);
}

View File

@ -37,6 +37,7 @@ namespace AgroBase.Services
/// Massa atual lida no reservatório (Kg).
/// </summary>
public double MassaAtual_Kg { get; private set; }
public double MassaAtual_Kg_Calc { get; private set; }
/// <summary>
/// Volume atual estimado no reservatório (L).
@ -163,8 +164,9 @@ namespace AgroBase.Services
if (!Iniciado)
return;
bool pulverizando = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Any(x => x.Inicializado && (x.ValoresLeituras?.Any(y => y.funcao == FuncoesPinout.EstadoLeitura && y.atual?.valor == Estado.Ligado) ?? false)) ?? false;
bool pulverizando = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Any(x => x.Inicializado && x._EstadoLeitura == Estado.Ligado) ?? false;
double massaLida_Kg = Sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Massa)?.atual?.valor ?? 0;
double massaLida_Kg_bruto = Sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraBruta)?.atual?.valor ?? 0;
double volumeMedido_L = massaLida_Kg / DensidadeProduto;
int qtd_atuacoes = Variaveis.OperacaoEmAndamento.Controle?.BicosAtuados?.Sum(x => x.Atuacoes) ?? 0;
@ -181,11 +183,13 @@ namespace AgroBase.Services
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
MassaAtual_Kg = massaLida_Kg;
MassaAtual_Kg_Calc = massaLida_Kg_bruto;
VolumeAtual_L = volumeMedido_L;
return;
}
MassaAtual_Kg = massaLida_Kg;
MassaAtual_Kg_Calc = massaLida_Kg_bruto;
VolumeAtual_L = volumeMedido_L;
// --- Cálculo de deltas básicos ---

View File

@ -1075,7 +1075,7 @@ namespace OperationControl.Windows
var bico = rover?.Controle?.BicosAtuados?.FirstOrDefault(x => x.ID == label);
bool comando = bico?.ComandoAtuar ?? false;
var leitura = bico?.ValoresLeituras?.FirstOrDefault(x => x.funcao == AgroBase.Models.Modules.FuncoesPinout.EstadoLeitura)?.atual?.valor;
var leitura = bico?._EstadoLeitura;
txtBico_Titulo.Text = $"Bico {label} - Testes";
txtBico_Comando.Text = comando ? "Ligado" : "Desligado";
txtBico_StatusReal.Text = leitura != null && (AgroBase.Models.Enums.Estado)Enum.Parse(typeof(AgroBase.Models.Enums.Estado), leitura.ToString(), true) == AgroBase.Models.Enums.Estado.Ligado ? "Ligado" : "Desligado";

View File

@ -0,0 +1,8 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
]
}

View File

@ -0,0 +1,355 @@
// Dispositivo: Atuador
// Versão Firmware: 12
// Ultima atualização: 16/12/2025
// Atualização: Adicionado controle dos bicos pulverizadores
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SerialService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\CanService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\EepromService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\I2CService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Utils.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Pinout.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\BicoPulverizadorModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\BombaPressurizadoraModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorFluxoModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMassaModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorPressaoModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMagneticoModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ServoAgroModel.h"
// Configurações do CAN
uint8_t CanID = 0x12;
CanService canService = CanService(CanID);
#define D_Code Atu
int VERSION = 12;
const String Mod_ID = "Atu";
#define _pinoLED RGB_BUILTIN
bool Conectado = false;
bool Conectar = false;
int _TaxaAmostragem = 1000;
volatile bool RequisitarDados = false;
int latenciaLoop = 0;
int qtdEnviosStatus = 0;
int maxEnviosStatus = 5;
std::vector<Bico*> listaBicos;
std::vector<BombaPressurizadora*> listaBombas;
std::vector<SensorFluxo*> listaSensoresFluxo;
std::vector<SensorMassa*> listaSensoresMassa;
std::vector<SensorPressao*> listaSensoresPressao;
std::vector<SensorMagnetico*> listaSensoresMagneticos;
std::vector<ServoAgro*> listaServos;
void MostrarLog(String mensagem) {
bool _debugMode = false;
if (_debugMode) {
PrintTela(String("[ATU] ") + mensagem);
}
}
void inicializarDependenciasI2C() {
I2CService::IniciarI2C();
I2CService::IniciarMUX();
}
void setup() {
delay(5000);
inicializarDependenciasI2C();
// Registrar callback para processar mensagens CAN recebidas
canService.setReceiveCallback([](int packetSize, int senderId, CanMessagePosicaoDados posicao, byte* data, int dataLength) {
std::vector<uint8_t> fullData;
fullData.push_back(static_cast<uint8_t>(posicao)); // Primeiro byte é sempre a posicao
for (int i = 0; i < dataLength; i++) {
fullData.push_back(data[i]);
}
ProcessarFrameCAN(posicao, fullData);
});
canService.begin();
}
void loop() {
if (!RequisitarDados) {
enviarLogsPeriodicamente();
}
for (auto* bomba : listaBombas) {
bomba->Loop();
}
for (auto* sensor : listaSensoresFluxo) {
sensor->Loop();
}
delay(1);
}
// Função para enviar logs do sensor periodicamente
unsigned long ultimoEnvioLogs = 0;
const unsigned long intervaloEnvioLogs = 1000; // 1 segundo
void enviarLogsPeriodicamente() {
unsigned long tempoAtual = millis();
// Verifica se o intervalo de 5 segundos já passou
if (tempoAtual - ultimoEnvioLogs >= intervaloEnvioLogs) {
ultimoEnvioLogs = tempoAtual; // Atualiza o tempo do último envio
enviarDadosSensores(canService.ID_Num_sTOD, CanMessagePosicaoDados::DadosAll);
}
}
void enviarDadosSensores(uint8_t id_num, CanMessagePosicaoDados posicao) {
if (Conectado || posicao == CanMessagePosicaoDados::Status) {
unsigned long startLoop = millis();
bool enviarStatus = qtdEnviosStatus >= maxEnviosStatus && posicao != CanMessagePosicaoDados::Status;
bool todosDados = posicao == CanMessagePosicaoDados::DadosAll;
bool todosIDs = id_num == canService.ID_Num_sTOD;
if (id_num == canService.ID_Num_sMOD) {
EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION));
return;
}
MostrarLog("Atualizando dados dos sensores...");
if (todosIDs && enviarStatus) {
EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION));
}
ComponenteCAN::ProcessarComponentesCAN(listaBombas, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaBicos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresFluxo, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresMassa, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresPressao, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresMagneticos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaServos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
if (enviarStatus) {
qtdEnviosStatus = 0;
}
else {
qtdEnviosStatus++;
}
latenciaLoop = millis() - startLoop;
if (posicao == CanMessagePosicaoDados::DadosAll) {
EnviarDadosCAN(canService.MontarFrameReqDadosFim(latenciaLoop));
}
MostrarLog("Ciclo concluido, latencia de loop: " + String(latenciaLoop));
}
}
void EnviarDadosCAN(std::vector<uint8_t> data) {
if (data.size() > 2) {
canService.adicionarMensagemFila(data);
}
}
void ProcessarFrameCAN(CanMessagePosicaoDados posicao, std::vector<uint8_t> data) {
if (data.size() < 1) return;
F_Code funcao = canService.FuncaoPorPosicao(posicao);
switch (funcao) {
case F_Code::ReqTx: ProcessarReq(data); break;
case F_Code::CmdTx: ProcessarCmd(data); break;
case F_Code::CfgTx: ProcessarCfg(data); break;
}
}
void ProcessarReq(std::vector<uint8_t> data) {
if (data.size() < 2) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
enviarDadosSensores(id, posicao);
}
void ProcessarCfg(std::vector<uint8_t> data) {
if (data.size() < 4) return;
std::vector<uint8_t> _chkRx;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
S_Code componente = DetectarComponente(id);
if (componente == S_Code::sMOD) {
switch (posicao) {
case CanMessagePosicaoDados::Config1: {
if (data.size() < 7) return;
bool conectar = data[2] == 1;
int taxa = data[3] * 10;
bool requisitar = data[4] == 1;
int pinoSDA = data[5];
int pinoSCL = data[6];
_TaxaAmostragem = taxa;
RequisitarDados = requisitar;
LimparListasComponentes();
if (pinoSDA != PINO_INVALIDO && pinoSCL != PINO_INVALIDO) {
if (I2CService::DefinirPinos(pinoSDA, pinoSCL) || !I2CService::I2CIniciado) {
//inicializarDependenciasI2C();
}
}
vTaskDelay(pdMS_TO_TICKS(100));
Conectado = conectar;
_chkRx = canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION);
MostrarLog("Configuracao do modulo concluida");
break;
}
}
}
else {
componente = (S_Code)data[2];
switch (componente) {
case sBIC: {
_chkRx = Bico::ConfigurarBico(listaBicos, data, Mod_ID, listaServos);
break;
}
case sFLX: {
_chkRx = SensorFluxo::ConfigurarSensor(listaSensoresFluxo, data, Mod_ID);
break;
}
case sPRS: {
_chkRx = SensorPressao::ConfigurarSensor(listaSensoresPressao, data, Mod_ID);
break;
}
case sMAS: {
_chkRx = SensorMassa::ConfigurarSensor(listaSensoresMassa, data, Mod_ID);
break;
}
case sBMB: {
_chkRx = BombaPressurizadora::ConfigurarBomba(listaBombas, data, Mod_ID, listaSensoresPressao);
break;
}
case sMAG: {
_chkRx = SensorMagnetico::ConfigurarSensor(listaSensoresMagneticos, data, Mod_ID);
break;
}
case sSRV: {
_chkRx = ServoAgro::ConfigurarServo(listaServos, data, Mod_ID);
break;
}
}
}
EnviarDadosCAN(_chkRx);
}
void ProcessarCmd(std::vector<uint8_t> data) {
if (data.size() < 2) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
S_Code componente = DetectarComponente(id);
switch (componente) {
case sBIC: {
Bico::ComandarBico(listaBicos, data);
ComponenteCAN::ProcessarComponentesCAN(listaBicos, {}, false, id, false, false, CanMessagePosicaoDados::Dados1, EnviarDadosCAN);
break;
}
case sBMB: {
BombaPressurizadora::ComandarBomba(listaBombas, data);
break;
}
default:
break;
}
}
void LimparListasComponentes() {
for (auto* bico : listaBicos) {
if (bico) {
bico->Desligar();
MostrarLog("Bico " + bico->_ID + " desligado.");
delete bico;
}
}
listaBicos.clear();
for (auto* bomba : listaBombas) {
if (bomba) {
bomba->Desligar();
MostrarLog("Bomba Pressurizadora " + bomba->_ID + " desligada.");
delete bomba;
}
}
listaBombas.clear();
for (auto* sensor : listaSensoresFluxo) {
if (sensor) {
sensor->Desligar();
MostrarLog("Sensor de Fluxo " + sensor->_ID + " desligado.");
delete sensor;
}
}
listaSensoresFluxo.clear();
for (auto* sensor : listaSensoresMassa) {
if (sensor) {
sensor->Desligar();
MostrarLog("Sensor de Massa " + sensor->_ID + " desligado.");
delete sensor;
}
}
listaSensoresMassa.clear();
for (auto* sensor : listaSensoresPressao) {
if (sensor) {
sensor->Desligar();
MostrarLog("Sensor de Pressao " + sensor->_ID + " desligado.");
delete sensor;
}
}
listaSensoresPressao.clear();
for (auto* sensor : listaSensoresMagneticos) {
sensor->Desligar();
MostrarLog("Sensor magnetico " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresMagneticos.clear();
for (auto* servo : listaServos) {
servo->Desligar();
MostrarLog("Servo " + servo->_ID + " desligado.");
delete servo;
}
listaServos.clear();
}
S_Code DetectarComponente(uint8_t idNum) {
if (idNum == canService.ID_Num_sMOD) return S_Code::sMOD;
for (auto* s : listaBicos) {
if (s->ID_Num == idNum) return S_Code::sBIC;
}
for (auto* s : listaBombas) {
if (s->ID_Num == idNum) return S_Code::sBMB;
}
for (auto* s : listaSensoresFluxo) {
if (s->ID_Num == idNum) return S_Code::sFLX;
}
for (auto* s : listaSensoresMassa) {
if (s->ID_Num == idNum) return S_Code::sMAS;
}
for (auto* s : listaSensoresPressao) {
if (s->ID_Num == idNum) return S_Code::sPRS;
}
for (auto* s : listaSensoresMagneticos) {
if (s->ID_Num == idNum) return S_Code::sMAG;
}
for (auto* s : listaServos) {
if (s->ID_Num == idNum) return S_Code::sSRV;
}
return S_Code::sVZO;
}

View File

@ -0,0 +1,216 @@
#include "SerialService.h"
#include "Pinout.h"
#include "Utils.h"
#include "IComponenteCAN.h"
#include "ServoAgroModel.h"
#ifndef BicoModel
#define BicoModel
class Bico : public ComponenteCAN {
public:
Bico(String _modID, String _id) {
Mod_ID = _modID;
_ID = _id;
}
String Mod_ID;
String _ID;
int ID_Num;
PinoModel _pino;
bool Iniciado = false;
bool AtuacaoNivelAlto = true;
Estado _Status = Desligado;
ServoAgro* servoMov = nullptr;
void Inicializar() {
if (Iniciado) {
MostrarLog("Bico ja inicializado");
return;
}
if (servoMov == nullptr) {
PrintTela("Servo nao definido, bico nao tera controle de movimento");
//Iniciado = false;
//return;
}
_pino.Conectar(!AtuacaoNivelAlto);
Iniciado = _pino.Definido();
if (Iniciado) {
MostrarLog("Bico iniciado");
}
else
{
MostrarLog("Bico nao iniciado");
}
}
void Desligar() {
if (!Iniciado) {
MostrarLog("Bico nao esta inicializado");
return;
}
servoMov = nullptr;
// Redefinir as configurações para os valores iniciais
_pino.Desconectar();
MostrarLog("Bico Desligado");
Iniciado = false;
}
void AtualizarStatus(Estado novoEstado, int novoAngulo) {
if (Iniciado) {
bool status = novoEstado == Ligado;
if (!AtuacaoNivelAlto) {
status = !status;
}
MostrarLog("Atualizando status do bico de " + String(_Status) + " para " + String(novoEstado));
_pino.set(status);
_Status = (Estado)_pino.get();
if (servoMov != nullptr) {
servoMov->AtualizarAngulo(novoAngulo);
}
}
}
void AtualizarLeitura() {
if (Iniciado) {
_Status = (Estado)_pino.get();
}
}
void RequisitarDados() {
AtualizarLeitura();
}
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(posicao));
data.push_back(ID_Num);
switch (posicao) {
case CanMessagePosicaoDados::Status: {
data.push_back(Iniciado ? 1 : 0);
break;
}
case CanMessagePosicaoDados::Dados1: {
data.push_back(static_cast<uint8_t>(_Status));
data.push_back(servoMov->_Angulo);
break;
}
}
return data;
}
static std::vector<uint8_t> ConfigurarBico(std::vector<Bico*>& lista, std::vector<uint8_t>& data, const String& Mod_ID, std::vector<ServoAgro*>& servos) {
std::vector<uint8_t> status;
if (data.size() < 2) return status;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t idNum = data[1];
auto it = std::find_if(lista.begin(), lista.end(), [idNum](Bico* s) { return s->ID_Num == idNum; });
bool jaExiste = it != lista.end();
Bico* bico;
switch (posicao) {
case CanMessagePosicaoDados::Config1: {
if (data.size() < 8) return status;
bool conectar = data[3] == 1;
bool atuacaoNivelAlto = data[4] == 1;
int servo_id = (data[5] == 0xFF) ? -1 : (int)data[5];
TiposBarramentos tipoBarramento = (TiposBarramentos)data[6];
int pino = data[7];
if (conectar) {
if (!jaExiste) {
bico = new Bico(Mod_ID, "sBIC_" + String(idNum));
}
else {
bico = *it;
}
if (!bico->Iniciado) {
bool com_movimento = servo_id >= 0;
if (com_movimento) {
if (servos.size() > 0) {
auto srv = std::find_if(servos.begin(), servos.end(), [servo_id](ServoAgro* s) { return s->ID_Num == servo_id; });
bool servo_encontrado = srv != servos.end();
if (servo_encontrado && (*srv)->Iniciado) {
bico->servoMov = *srv;
}
}
if (bico->servoMov == nullptr) {
PrintTela("O servo " + String(servo_id) + " nao foi encontrado para ser associado ao bico.");
delete bico;
return status;
}
}
bico->ID_Num = idNum;
bico->_pino = PinoModel(pino, tipoBarramento, _OUTPUT);
bico->AtuacaoNivelAlto = atuacaoNivelAlto;
bico->Inicializar();
if (!jaExiste) {
lista.push_back(bico);
bico->MostrarLog("Bico adicionado via CAN: sBIC_" + String(idNum));
}
}
status = bico->MontarMensagemCAN(CanMessagePosicaoDados::Status);
} else {
if (jaExiste) {
bico = *it;
bico->Desligar();
status = bico->MontarMensagemCAN(CanMessagePosicaoDados::Status);
bico->MostrarLog("Bico removido via CAN: sBIC_" + String(idNum));
delete bico;
lista.erase(it);
}
}
break;
}
}
return status;
}
static void ComandarBico(std::vector<Bico*>& lista, std::vector<uint8_t>& data) {
if (data.size() < 4) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t idNum = data[1];
for (auto* _bico : lista) {
if (_bico->ID_Num == idNum) {
switch (posicao) {
case CanMessagePosicaoDados::Command1: {
Estado novoEstado = (Estado)data[2];
int novoAngulo = data[3];
_bico->AtualizarStatus(novoEstado, novoAngulo);
break;
}
}
return;
}
}
}
private:
bool DebugMode = false;
void MostrarLog(String mensagem) {
if (DebugMode) {
PrintTela("[BIC " + _ID + "] " + mensagem);
}
}
};
#endif

View File

@ -33,7 +33,7 @@ class BombaPressurizadora : public ComponenteCAN {
bool bombaDesligadaPorPressao = false;
//PID* _PID = nullptr;
SensorPressao* sensorPressao;
SensorPressao* sensorPressao = nullptr;
int ZeroRampa = 0;
int RampaMax = 1023;
@ -184,11 +184,12 @@ class BombaPressurizadora : public ComponenteCAN {
BombaPressurizadora* bomba;
switch (posicao) {
case CanMessagePosicaoDados::Config1: {
if (data.size() < 7) return status;
if (data.size() < 8) return status;
bool conectar = data[3] == 1;
int pressaoSp = (int)data[4];
int pinoEn = data[5];
int pinoCs = data[6];
int sensor_id = (data[5] == 0xFF) ? -1 : (int)data[5];
int pinoEn = data[6];
int pinoCs = data[7];
if (conectar) {
if (!jaExiste) {
bomba = new BombaPressurizadora(Mod_ID, "sBMB_" + String(idNum));
@ -197,15 +198,20 @@ class BombaPressurizadora : public ComponenteCAN {
bomba = *it;
}
if (!bomba->Iniciado) {
if (sensoresPressao.size() > 0) {
if (sensoresPressao[0]->Iniciado) {
bomba->sensorPressao = sensoresPressao[0];
bool malha_fechada = sensor_id >= 0;
if (malha_fechada) {
auto prs = std::find_if(sensoresPressao.begin(), sensoresPressao.end(), [sensor_id](SensorPressao* s) { return s->ID_Num == sensor_id; });
bool sensor_encontrado = prs != sensoresPressao.end();
if (sensoresPressao.size() > 0) {
if (sensor_encontrado && (*prs)->Iniciado) {
bomba->sensorPressao = *prs;
}
}
if (bomba->sensorPressao == nullptr) {
PrintTela("Sensor de pressao " + String(sensor_id) + " nao encontrado para associar à bomba.");
delete bomba;
return status;
}
}
if (bomba->sensorPressao == nullptr) {
PrintTela("Nenhum sensor de pressão disponível para associar à bomba.");
delete bomba;
return status;
}
bomba->ID_Num = idNum;
bomba->_pinoEN = PinoModel(pinoEn, CONTROLADOR, _OUTPUT);

View File

@ -81,6 +81,7 @@ enum S_Code {
sIUV = 31,
sQAR = 32,
sCHV = 33,
sSRV = 34,
};
enum Estado {

View File

@ -19,6 +19,7 @@ class SensorChuva : public ComponenteCAN {
int ID_Num;
PinoModel _pino;
int leitura = 0;
double tensao = 0;
double percentual = -1;
@ -65,8 +66,8 @@ class SensorChuva : public ComponenteCAN {
}
case CanMessagePosicaoDados::Dados1: {
int16_t pInt = static_cast<int16_t>(round(percentual * 100.0f));
data.push_back((uint8_t)(pInt >> 8));
data.push_back((uint8_t)(pInt & 0xFF));
data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF));
data.push_back((uint8_t)(pInt >> 8)); data.push_back((uint8_t)(pInt & 0xFF));
break;
}
}
@ -141,7 +142,7 @@ class SensorChuva : public ComponenteCAN {
void AferirChuva() {
if (!Iniciado) return;
int leitura = _pino.get();
leitura = _pino.get();
tensao = (float)leitura / 4095.0f * Vs;
tensao = tensao * divisor * vOffset;

View File

@ -101,8 +101,9 @@ class SensorFluxo : public ComponenteCAN {
}
case CanMessagePosicaoDados::Dados1: {
uint16_t vazaoEscalada = (uint16_t)(_Vazao * 100);
data.push_back(vazaoEscalada >> 8);
data.push_back(vazaoEscalada & 0xFF);
data.push_back(_PulsosLeitura);
data.push_back((uint8_t)(_PeriodoTotalLeitura >> 8)); data.push_back((uint8_t)(_PeriodoTotalLeitura & 0xFF));
data.push_back(vazaoEscalada >> 8); data.push_back(vazaoEscalada & 0xFF);
break;
}
}
@ -183,16 +184,25 @@ class SensorFluxo : public ComponenteCAN {
}
float CalcularVazao(uint16_t pulsos, unsigned long periodoMs) {
if (periodoMs == 0) return 0;
if (periodoMs == 0) return 0.0f; // evita divisão por zero
float frequencia = (float)pulsos / (float)periodoMs * 1000.0; // Hz
const float Rh = 0.0047; // raio interno do tubo
const float Rt = 0.0037; // raio interno do rotor
// F = pulsos / (periodoMs/1000) => Hz
float F = ((float)pulsos) * 1000.0f / (float)periodoMs;
float vazao_m3s = frequencia * 2.0 * PI * Rh * PI * (Rt * Rt); // m³/s
float vazao_ml_s = vazao_m3s * 1e6; // ml/s
// Equação do anúncio: F = 8.1*q - 3 (q em L/min)
float q_L_min = (F + 3.0f) / 8.1f;
return vazao_ml_s;
// evita valores negativos perto do zero (offset -3)
if (q_L_min < 0.0f) q_L_min = 0.0f;
// limites do sensor informados: 0.310 L/min (opcional "clamp")
// se você quiser respeitar mínimo físico, pode usar 0.3f ao invés de 0.0f
if (q_L_min > 10.0f) q_L_min = 10.0f;
// L/min -> mL/s (1 L = 1000 mL; 1 min = 60 s)
float q_mL_s = q_L_min * (1000.0f / 60.0f);
return q_mL_s;
}

View File

@ -28,6 +28,7 @@ class SensorGas : public ComponenteCAN {
float ppm = -1;
float tensao = -1;
int leitura = 0;
bool Iniciado = false;
bool Checando = false;
@ -71,11 +72,9 @@ class SensorGas : public ComponenteCAN {
break;
}
case CanMessagePosicaoDados::Dados1: {
int32_t leituraInt = static_cast<int32_t>(round(ppm * 100.0f));
data.push_back((uint8_t)(leituraInt >> 24));
data.push_back((uint8_t)(leituraInt >> 16));
data.push_back((uint8_t)(leituraInt >> 8));
data.push_back((uint8_t)(leituraInt & 0xFF));
int32_t ppmInt = static_cast<int32_t>(round(ppm * 100.0f));
data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF));
data.push_back((uint8_t)(ppmInt >> 24)); data.push_back((uint8_t)(ppmInt >> 16)); data.push_back((uint8_t)(ppmInt >> 8)); data.push_back((uint8_t)(ppmInt & 0xFF));
break;
}
}
@ -143,7 +142,7 @@ class SensorGas : public ComponenteCAN {
void AferirGas() {
if (!Iniciado) return;
float leitura = _pino.get();
leitura = _pino.get();
ppm = CalcularPPM(leitura);
MostrarLog("Leitura Gas: " + String(leitura) + ", Tensao: " + String(tensao) + ", PPM estimado: " + String(ppm));
}

View File

@ -21,6 +21,7 @@ class SensorLuzUV : public ComponenteCAN {
double tensao = 0;
double uv_index = -1;
int leitura = 0;
bool Iniciado = false;
bool Checando = false;
@ -65,8 +66,8 @@ class SensorLuzUV : public ComponenteCAN {
}
case CanMessagePosicaoDados::Dados1: {
int16_t uvInt = static_cast<int16_t>(round(uv_index * 100.0f));
data.push_back((uint8_t)(uvInt >> 8));
data.push_back((uint8_t)(uvInt & 0xFF));
data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF));
data.push_back((uint8_t)(uvInt >> 8)); data.push_back((uint8_t)(uvInt & 0xFF));
break;
}
}
@ -137,7 +138,7 @@ class SensorLuzUV : public ComponenteCAN {
void AferirUV() {
if (!Iniciado) return;
int leitura = _pino.get();
leitura = _pino.get();
float Vadc = (float)leitura / 4095.0f * Vs;
Vadc = Vadc * divisor * vOffset;

View File

@ -30,6 +30,7 @@ class SensorMassa : public ComponenteCAN {
SimpleKalmanFilter filtro = SimpleKalmanFilter(0.05, 0.05, 0.25);
float Massa = 0;
float leitura = 0;
bool Iniciado = false;
@ -85,8 +86,8 @@ class SensorMassa : public ComponenteCAN {
}
case CanMessagePosicaoDados::Dados1: {
uint16_t massaEscalada = (uint16_t)(Massa * 100);
data.push_back(massaEscalada >> 8);
data.push_back(massaEscalada & 0xFF);
data.push_back(leitura >> 8); data.push_back(leitura & 0xFF);
data.push_back(massaEscalada >> 8); data.push_back(massaEscalada & 0xFF);
break;
}
}
@ -147,9 +148,10 @@ class SensorMassa : public ComponenteCAN {
private:
void AferirMassa() {
if (Iniciado) {
float leitura = -balanca.get_units(5);
leitura += _OffsetMassa;
Massa = filtro.updateEstimate(leitura);
leitura = balanca.get_units(5);
float _leitura = -leitura;
_leitura += _OffsetMassa;
Massa = filtro.updateEstimate(_leitura);
}
}

View File

@ -25,7 +25,7 @@ class SensorPressao : public ComponenteCAN {
double _Vmax = 4.5;
double _Pmax = 174.045;
double leitura = 0;
int leitura = 0;
double Pressao = 0;
SimpleKalmanFilter filtro = SimpleKalmanFilter(2, 2, 0.01);
@ -80,8 +80,8 @@ class SensorPressao : public ComponenteCAN {
}
case CanMessagePosicaoDados::Dados1: {
uint16_t pressaoEscalada = (uint16_t)(Pressao * 100);
data.push_back(pressaoEscalada >> 8);
data.push_back(pressaoEscalada & 0xFF);
data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF));
data.push_back(pressaoEscalada >> 8); data.push_back(pressaoEscalada & 0xFF);
break;
}
}

View File

@ -21,7 +21,7 @@ class SensorTemperatura : public ComponenteCAN {
int ID_Num;
PinoModel _pino;
double leitura = 0;
int leitura = 0;
double temperatura = -1;
double tensao = 0;
@ -73,8 +73,8 @@ class SensorTemperatura : public ComponenteCAN {
}
case CanMessagePosicaoDados::Dados1: {
int16_t leituraInt = static_cast<int16_t>(round(temperatura * 100.0f));
data.push_back((uint8_t)(leituraInt >> 8));
data.push_back((uint8_t)(leituraInt & 0xFF));
data.push_back((uint8_t)(leitura >> 8)); data.push_back((uint8_t)(leitura & 0xFF));
data.push_back((uint8_t)(leituraInt >> 8)); data.push_back((uint8_t)(leituraInt & 0xFF));
break;
}
}

View File

@ -0,0 +1,181 @@
#include "SerialService.h"
#include "Pinout.h"
#include "Utils.h"
#include "IComponenteCAN.h"
#include <ESP32Servo.h>
#ifndef ServoAgroModel
#define ServoAgroModel
class ServoAgro : public ComponenteCAN {
public:
ServoAgro(String _modID, String _id) {
Mod_ID = _modID;
_ID = _id;
}
String Mod_ID;
String _ID;
int ID_Num;
PinoModel _pino;
bool Incremental = true;
bool Iniciado = false;
int _Angulo = 0;
Servo _Servo;
void Inicializar() {
if (Iniciado) {
MostrarLog("Servo ja inicializado");
return;
}
if (_pino.Definido()) {
_Servo.attach(_pino.num);
AtualizarAngulo(Incremental ? 0 : 180);
Iniciado = true;
MostrarLog("Servo iniciado");
}
else {
MostrarLog("Servo nao iniciado");
}
}
void Desligar() {
if (!Iniciado) {
MostrarLog("Servo nao esta inicializado");
return;
}
// Redefinir as configurações para os valores iniciais
if (_pino.Definido()) {
_Servo.detach();
}
MostrarLog("Servo Desligado");
Iniciado = false;
}
void AtualizarAngulo(int novoAngulo) {
if (Iniciado) {
MostrarLog("Angulo atualizado de " + String(_Angulo) + " para " + String(novoAngulo));
_Angulo = novoAngulo;
_Servo.write(_Angulo);
}
}
void RequisitarDados() {
}
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(posicao));
data.push_back(ID_Num);
switch (posicao) {
case CanMessagePosicaoDados::Status: {
data.push_back(Iniciado ? 1 : 0);
break;
}
case CanMessagePosicaoDados::Dados1: {
data.push_back(_Angulo); // 0 a 180
break;
}
}
return data;
}
static std::vector<uint8_t> ConfigurarServo(std::vector<ServoAgro*>& lista, std::vector<uint8_t>& data, const String& Mod_ID) {
std::vector<uint8_t> status;
if (data.size() < 2) return status;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t idNum = data[1];
auto it = std::find_if(lista.begin(), lista.end(), [idNum](ServoAgro* s) { return s->ID_Num == idNum; });
bool jaExiste = it != lista.end();
ServoAgro* sensor;
switch (posicao) {
case CanMessagePosicaoDados::Config1: {
if (data.size() < 7) return status;
bool conectar = data[3] == 1;
bool incremental = data[4] == 1;
TiposBarramentos tipoBarramento = (TiposBarramentos)data[5];
int pino = data[6];
if (conectar) {
if (!jaExiste) {
sensor = new ServoAgro(Mod_ID, "sSRV_" + String(idNum));
}
else {
sensor = *it;
}
if (!sensor->Iniciado) {
sensor->ID_Num = idNum;
sensor->Incremental = incremental;
sensor->_pino = PinoModel(pino, tipoBarramento, _OUTPUT);
sensor->Inicializar();
if (!jaExiste) {
lista.push_back(sensor);
sensor->MostrarLog("Servo adicionado via CAN: sSRV_" + String(idNum));
}
}
status = sensor->MontarMensagemCAN(CanMessagePosicaoDados::Status);
} else {
if (jaExiste) {
sensor = *it;
sensor->Desligar();
status = sensor->MontarMensagemCAN(CanMessagePosicaoDados::Status);
sensor->MostrarLog("Servo removido via CAN: sSRV_" + String(idNum));
delete sensor;
lista.erase(it);
}
}
break;
}
}
return status;
}
static void ComandarServo(std::vector<ServoAgro*>& lista, std::vector<uint8_t>& data) {
if (data.size() < 3) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t idNum = data[1];
for (auto* _servo : lista) {
if (_servo->ID_Num == idNum) {
switch (posicao) {
case CanMessagePosicaoDados::Command1: {
int novoAngulo = (int)data[2];
_servo->AtualizarAngulo(novoAngulo);
break;
}
}
return;
}
}
}
private:
bool DebugMode = false;
void MostrarLog(String mensagem) {
if (DebugMode) {
PrintTela("[SRV " + _ID + "] " + mensagem);
}
}
};
#endif

View File

@ -0,0 +1,8 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
]
}

View File

@ -0,0 +1,464 @@
// Dispositivo: Sensoriamento
// Versão Firmware: 21
// Ultima atualização: 16/12/2025
// Atualização: Padronizado uso do componente ServoAgro
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SerialService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\CanService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\LoRaService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\EepromService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\I2CService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Utils.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Pinout.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorTemperaturaModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorCorrenteModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorIMUModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SinaleiroModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ReleModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ServoAgroModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorGasModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorTemperaturaSHTModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorLuminosidadeModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorLuzUVModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorQualidadeArModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorChuvaModel.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMagneticoModel.h"
// Configurações do CAN
uint8_t CanID = 0x11;
CanService canService(CanID);
LoRaService loraService(&canService);
#define D_Code Sen
int VERSION = 21;
String Mod_ID = "Sen";
#define _pinoLED RGB_BUILTIN
bool Conectado = false;
bool Conectar = false;
int _TaxaAmostragem = 1000;
volatile bool RequisitarDados = false;
int latenciaLoop = 0;
int qtdEnviosStatus = 0;
int maxEnviosStatus = 5;
std::vector<SensorTemperatura*> listaSensoresTemperaturaNTC;
std::vector<SensorCorrente*> listaSensoresCorrente;
std::vector<Sinaleiro*> listaSinaleiros;
std::vector<Rele*> listaReles;
std::vector<ServoAgro*> listaServos;
std::vector<SensorIMU*> listaSensoresIMU;
std::vector<SensorGas*> listaSensoresGas;
std::vector<SensorTemperaturaSHT*> listaSensoresTemperaturaSHT;
std::vector<SensorLuminosidade*> listaSensoresLuminosidade;
std::vector<SensorLuzUV*> listaSensoresLuzUV;
std::vector<SensorQualidadeAr*> listaSensoresQualidadeAr;
std::vector<SensorChuva*> listaSensoresChuva;
std::vector<SensorMagnetico*> listaSensoresMagneticos;
void MostrarLog(String mensagem) {
bool _debugMode = false;
if (_debugMode) {
PrintTela(String("[SEN] ") + mensagem);
}
}
void inicializarDependenciasI2C() {
I2CService::IniciarI2C();
I2CService::IniciarMUX();
I2CService::IniciarMCP();
}
void setup() {
delay(2000);
inicializarDependenciasI2C();
// Registrar callback para processar mensagens CAN recebidas
canService.setReceiveCallback([](int packetSize, int senderId, CanMessagePosicaoDados posicao, byte* data, int dataLength) {
std::vector<uint8_t> fullData;
fullData.push_back(static_cast<uint8_t>(posicao)); // Primeiro byte é sempre a posicao
for (int i = 0; i < dataLength; i++) {
fullData.push_back(data[i]);
}
ProcessarFrameCAN(posicao, fullData);
});
canService.begin();
}
void loop() {
if (!RequisitarDados) {
enviarLogsPeriodicamente();
}
delay(1);
}
// Função para enviar logs do sensor periodicamente
unsigned long ultimoEnvioLogs = 0;
const unsigned long intervaloEnvioLogs = 1000; // 1 segundo
void enviarLogsPeriodicamente() {
unsigned long tempoAtual = millis();
// Verifica se o intervalo de 5 segundos já passou
if (tempoAtual - ultimoEnvioLogs >= intervaloEnvioLogs) {
ultimoEnvioLogs = tempoAtual; // Atualiza o tempo do último envio
enviarDadosSensores(canService.ID_Num_sTOD, CanMessagePosicaoDados::DadosAll);
}
}
void enviarDadosSensores(uint8_t id_num, CanMessagePosicaoDados posicao) {
if (Conectado || posicao == CanMessagePosicaoDados::Status) {
unsigned long startLoop = millis();
bool enviarStatus = qtdEnviosStatus >= maxEnviosStatus && posicao != CanMessagePosicaoDados::Status;
bool todosDados = posicao == CanMessagePosicaoDados::DadosAll;
bool todosIDs = id_num == canService.ID_Num_sTOD;
if (id_num == canService.ID_Num_sMOD) {
EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION));
return;
}
if (id_num == canService.ID_Num_sLRA) {
EnviarDadosCAN(loraService.MontarMensagemCAN(posicao));
return;
}
MostrarLog("Atualizando dados dos sensores...");
if (todosIDs && enviarStatus) {
EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION));
EnviarDadosCAN(loraService.MontarMensagemCAN(CanMessagePosicaoDados::Status));
}
ComponenteCAN::ProcessarComponentesCAN(listaSensoresTemperaturaNTC, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresCorrente, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSinaleiros, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaReles, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaServos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresGas, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresTemperaturaSHT, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresLuminosidade, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresLuzUV, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresQualidadeAr, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresChuva, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresIMU, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponentesCAN(listaSensoresMagneticos, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
if (enviarStatus) {
qtdEnviosStatus = 0;
}
else {
qtdEnviosStatus++;
}
latenciaLoop = millis() - startLoop;
if (posicao == CanMessagePosicaoDados::DadosAll) {
EnviarDadosCAN(canService.MontarFrameReqDadosFim(latenciaLoop));
}
MostrarLog("Ciclo concluido, latencia de loop: " + String(latenciaLoop));
}
}
void EnviarDadosCAN(std::vector<uint8_t> data) {
if (data.size() > 2) {
canService.adicionarMensagemFila(data);
}
}
void ProcessarFrameCAN(CanMessagePosicaoDados posicao, std::vector<uint8_t> data) {
if (data.size() < 1) return;
F_Code funcao = canService.FuncaoPorPosicao(posicao);
switch (funcao) {
case F_Code::ReqTx: ProcessarReq(data); break;
case F_Code::CmdTx: ProcessarCmd(data); break;
case F_Code::CfgTx: ProcessarCfg(data); break;
}
}
void ProcessarReq(std::vector<uint8_t> data) {
if (data.size() < 2) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
enviarDadosSensores(id, posicao);
}
void ProcessarCfg(std::vector<uint8_t> data) {
if (data.size() < 4) return;
std::vector<uint8_t> _chkRx;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
S_Code componente = DetectarComponente(id);
if (componente == S_Code::sMOD) {
switch (posicao) {
case CanMessagePosicaoDados::Config1: {
if (data.size() < 8) return;
bool conectar = data[2] == 1;
int taxa = data[3] * 10;
bool requisitar = data[4] == 1;
loraService.AddressBase = data[5];
int pinoSDA = data[6];
int pinoSCL = data[7];
_TaxaAmostragem = taxa;
RequisitarDados = requisitar;
LimparListasComponentes();
if (pinoSDA != PINO_INVALIDO && pinoSCL != PINO_INVALIDO) {
if (I2CService::DefinirPinos(pinoSDA, pinoSCL) || !I2CService::I2CIniciado) {
inicializarDependenciasI2C();
}
}
vTaskDelay(pdMS_TO_TICKS(100));
Conectado = conectar;
_chkRx = canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION);
MostrarLog("Configuracao do modulo concluida");
break;
}
}
}
if (componente == S_Code::sLRA) {
_chkRx = loraService.ConfigurarModulo(data);
}
else {
componente = (S_Code)data[2];
switch (componente) {
case sNTC: {
_chkRx = SensorTemperatura::ConfigurarSensor(listaSensoresTemperaturaNTC, data, Mod_ID);
break;
}
case sCOR: {
_chkRx = SensorCorrente::ConfigurarSensor(listaSensoresCorrente, data, Mod_ID);
break;
}
case sLED: {
_chkRx = Sinaleiro::ConfigurarSinaleiro(listaSinaleiros, data, Mod_ID);
break;
}
case sRLE: {
_chkRx = Rele::ConfigurarRele(listaReles, data, Mod_ID);
break;
}
case sSRV: {
_chkRx = ServoAgro::ConfigurarServo(listaServos, data, Mod_ID);
break;
}
case sIMU: {
_chkRx = SensorIMU::ConfigurarSensor(listaSensoresIMU, data, Mod_ID);
break;
}
case sGAS: {
_chkRx = SensorGas::ConfigurarSensor(listaSensoresGas, data, Mod_ID);
break;
}
case sSHT: {
_chkRx = SensorTemperaturaSHT::ConfigurarSensor(listaSensoresTemperaturaSHT, data, Mod_ID);
break;
}
case sLUZ: {
_chkRx = SensorLuminosidade::ConfigurarSensor(listaSensoresLuminosidade, data, Mod_ID);
break;
}
case sIUV: {
_chkRx = SensorLuzUV::ConfigurarSensor(listaSensoresLuzUV, data, Mod_ID);
break;
}
case sQAR: {
_chkRx = SensorQualidadeAr::ConfigurarSensor(listaSensoresQualidadeAr, data, Mod_ID);
break;
}
case sCHV: {
_chkRx = SensorChuva::ConfigurarSensor(listaSensoresChuva, data, Mod_ID);
break;
}
case sMAG: {
_chkRx = SensorMagnetico::ConfigurarSensor(listaSensoresMagneticos, data, Mod_ID);
break;
}
}
}
EnviarDadosCAN(_chkRx);
}
void ProcessarCmd(std::vector<uint8_t> data) {
if (data.size() < 2) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
S_Code componente = DetectarComponente(id);
switch (componente) {
case sLED: {
Sinaleiro::ComandarSinaleiro(listaSinaleiros, data);
break;
}
case sRLE: {
Rele::ComandarRele(listaReles, data);
break;
}
case sSRV: {
ServoAgro::ComandarServo(listaServos, data);
break;
}
case sLRA: {
loraService.EnviarComando(data);
break;
}
default:
break;
}
}
void LimparListasComponentes() {
for (auto* rele : listaReles) {
rele->Desligar();
MostrarLog("Rele " + rele->_ID + " desligado.");
delete rele;
}
listaReles.clear();
for (auto* sinaleiro : listaSinaleiros) {
sinaleiro->Desligar();
MostrarLog("Sinaleiro " + sinaleiro->_ID + " desligado.");
delete sinaleiro;
}
listaSinaleiros.clear();
for (auto* servo : listaServos) {
servo->Desligar();
MostrarLog("Servo " + servo->_ID + " desligado.");
delete servo;
}
listaServos.clear();
for (auto* sensor : listaSensoresCorrente) {
sensor->Desligar();
MostrarLog("Sensor de Corrente " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresCorrente.clear();
for (auto* sensor : listaSensoresTemperaturaNTC) {
sensor->Desligar();
MostrarLog("Sensor de Temperatura " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresTemperaturaNTC.clear();
for (auto* sensor : listaSensoresIMU) {
sensor->Desligar();
MostrarLog("Sensor IMU " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresIMU.clear();
for (auto* sensor : listaSensoresGas) {
sensor->Desligar();
MostrarLog("Sensor de gas " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresGas.clear();
for (auto* sensor : listaSensoresTemperaturaSHT) {
sensor->Desligar();
MostrarLog("Sensor de temperatura e umidade " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresTemperaturaSHT.clear();
for (auto* sensor : listaSensoresLuminosidade) {
sensor->Desligar();
MostrarLog("Sensor de luminosidade " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresLuminosidade.clear();
for (auto* sensor : listaSensoresLuzUV) {
sensor->Desligar();
MostrarLog("Sensor de luz UV " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresLuzUV.clear();
for (auto* sensor : listaSensoresQualidadeAr) {
sensor->Desligar();
MostrarLog("Sensor de qualidade do ar " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresQualidadeAr.clear();
for (auto* sensor : listaSensoresChuva) {
sensor->Desligar();
MostrarLog("Sensor de chuva " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresChuva.clear();
for (auto* sensor : listaSensoresMagneticos) {
sensor->Desligar();
MostrarLog("Sensor magnetico " + sensor->_ID + " desligado.");
delete sensor;
}
listaSensoresMagneticos.clear();
}
S_Code DetectarComponente(uint8_t idNum) {
if (idNum == canService.ID_Num_sMOD) return S_Code::sMOD;
if (idNum == canService.ID_Num_sTOD) return S_Code::sTOD;
if (idNum == canService.ID_Num_sLRA) return S_Code::sLRA;
for (auto* s : listaSensoresTemperaturaNTC) {
if (s->ID_Num == idNum) return S_Code::sNTC;
}
for (auto* s : listaSensoresCorrente) {
if (s->ID_Num == idNum) return S_Code::sCOR;
}
for (auto* s : listaSinaleiros) {
if (s->ID_Num == idNum) return S_Code::sLED;
}
for (auto* s : listaReles) {
if (s->ID_Num == idNum) return S_Code::sRLE;
}
for (auto* s : listaServos) {
if (s->ID_Num == idNum) return S_Code::sSRV;
}
for (auto* s : listaSensoresIMU) {
if (s->ID_Num == idNum) return S_Code::sIMU;
}
for (auto* s : listaSensoresGas) {
if (s->ID_Num == idNum) return S_Code::sGAS;
}
for (auto* s : listaSensoresTemperaturaSHT) {
if (s->ID_Num == idNum) return S_Code::sSHT;
}
for (auto* s : listaSensoresLuminosidade) {
if (s->ID_Num == idNum) return S_Code::sLUZ;
}
for (auto* s : listaSensoresLuzUV) {
if (s->ID_Num == idNum) return S_Code::sIUV;
}
for (auto* s : listaSensoresQualidadeAr) {
if (s->ID_Num == idNum) return S_Code::sQAR;
}
for (auto* s : listaSensoresChuva) {
if (s->ID_Num == idNum) return S_Code::sCHV;
}
for (auto* s : listaSensoresMagneticos) {
if (s->ID_Num == idNum) return S_Code::sMAG;
}
return S_Code::sVZO;
}