agrobot_base/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs

1407 lines
53 KiB
C#

using AgroBase.Forms.IHM;
using AgroBase.Services;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using static AgroBase.Models.Enums;
namespace AgroBase.Models.Modules
{
public class AtuadorModel : DispositivoBaseModel
{
public T_Code Dispositivo { get; set; } = T_Code.Atu;
public string Modulo_ID { get; set; } = T_Code.Atu.ToString();
public byte _EnderecoCAN { get; set; } = 0x12;
public int _TaxaAmostragem { get; set; } = 1000;
public bool RequisitarDados { get; set; } = true;
public static int PingsConsiderarConexao { get; set; } = 5;
public static int TempoLimiteConexao
{
get
{
return PingsConsiderarConexao * (Variaveis.OperacaoEmAndamento?.DispSen?._TaxaAmostragem ?? 1000);
}
}
public bool Conectado
{
get
{
return DadosLeitura.UltimoComandoRespondido.AddMilliseconds(TempoLimiteConexao * 2) >= DateTime.Now; // DadosLeitura.Conectado &&
}
}
public static PinoutDataModel Pinout { get; set; }
public static List<FuncoesPinout> Funcoes { get; set; } = new List<FuncoesPinout>()
{
FuncoesPinout.SDA,
FuncoesPinout.SCL,
};
public int QuantidadeBicos { get; set; } = 4;
public double DensidadeHerbicida { get; set; } = 1.1;
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 AtuadorBombaModel BombaPressurizadora
{
get
{
return BombasPressurizadoras.FirstOrDefault();
}
}
public string ScriptDeteccaoErvas { get; set; } = PythonService.ScriptWeedDetector;
public AsyncTaskTimerModel tmrRegistrador;
private int _TempoReconexaoComponentes = 5;
private int _VezesLeituraReconexao = 0;
public AtuadorMensagemJsonModel DadosLeitura { get; set; } = new AtuadorMensagemJsonModel();
public AtuHandler _AtuHandler = new AtuHandler();
#region MASSA
public double _MassaRef { get; set; } = 0.8;
public double _MassaLeituraRef { get; set; } = 40876.37;
public double _MassaLeituraExtra { get; set; } = 1895800; // 2015000.0;
public double MassaReservatorio
{
get
{
return ((FirmwareSensorMassa)Sensores.FirstOrDefault(x => x.Componente == S_Code.sMAS)?.Leitura)?.Massa ?? 0;
}
}
public double VolumeReservatorio
{
get
{
return MassaReservatorio / DensidadeHerbicida;
}
}
public double PercentualReservatorio
{
get
{
return VolumeReservatorio / Variaveis.OperacaoEmAndamento.CapacidadeReservatorio * 100.0;
}
}
#endregion
#region VAZAO
public double VolumeVazaoAferido { get; set; } = 0;
public double _FluxoMlRef { get; set; } = 600;
public double _FluxoPulsoRef { get; set; } = 538;
public double VazaoFluxoMLpSInstantanea
{
get
{
return ((FirmwareSensorFluxo)Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX)?.Leitura)?.Vazao ?? 0;
}
}
private double _somaVazao; // Acumula a soma da vazão para calcular a média
private int _contadorLeituras; // Conta o número de leituras feitas
private DateTime _ultimoRegistroVazao; // Armazena o horário da última atualização
public double VazaoFluxoMLpSMedia { get; set; }
public double VolumeVazaoML { get; set; }
public DateTime InicioAtuacao { get; set; } = DateTime.MinValue;
public double TempoAtuado { get; set; } = 0;
public void AtualizaTempoAtuadoGeral()
{
bool algumBicoAtivo = BicosPulverizadores.Any(x => x.Inicializado && x.ComandoAtuar);
if (algumBicoAtivo)
{
if (InicioAtuacao == DateTime.MinValue)
{
InicioAtuacao = DateTime.Now;
}
else
{
TempoAtuado += (DateTime.Now - InicioAtuacao).TotalMilliseconds;
InicioAtuacao = DateTime.Now;
}
}
else if (InicioAtuacao != DateTime.MinValue)
{
TempoAtuado += (DateTime.Now - InicioAtuacao).TotalMilliseconds;
InicioAtuacao = DateTime.MinValue;
}
AtualizaPercentualErvas();
AtualizaVazaoEVolume();
}
public void AtualizaPercentualErvas()
{
double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento.TempoDecorridoSeg * 1000.0;
if (tempoTotalOperacao > 0)
{
var percentual = Math.Round((TempoAtuado / tempoTotalOperacao) * 100.0, 2);
PercentualErvasTerreno = percentual;
}
else
{
PercentualErvasTerreno = 0;
}
}
public void AtualizaVazaoEVolume()
{
// Captura a vazão instantânea
double vazaoInstantanea = VazaoFluxoMLpSInstantanea;
if (_ultimoRegistroVazao == DateTime.MinValue)
{
_ultimoRegistroVazao = DateTime.Now;
return;
}
// Calcula o tempo decorrido desde a última atualização (em segundos)
double intervaloSegundos = (DateTime.Now - _ultimoRegistroVazao).TotalSeconds;
_ultimoRegistroVazao = DateTime.Now;
if (intervaloSegundos > 0)
{
// Atualiza o volume total vazado
VolumeVazaoML += vazaoInstantanea * intervaloSegundos;
// Acumula a vazão para o cálculo da média
_somaVazao += vazaoInstantanea;
_contadorLeituras++;
}
VazaoFluxoMLpSMedia = _contadorLeituras > 0 ? _somaVazao / _contadorLeituras : 0;
var BicosAtuados = BicosPulverizadores.Where(x => x.Inicializado && x.ComandoAtuar).ToList();
double vazaoInstantaneaBico = vazaoInstantanea / ((double)BicosAtuados.Count());
foreach (var Bico in BicosAtuados)
{
Bico.MediaNivelFluxo = vazaoInstantaneaBico;
}
}
#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
{
get
{
return ((FirmwareSensorPressao)Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS)?.Leitura)?.Pressao ?? 0;
}
}
public double PressaoLinhaCalc
{
get
{
//double _LeituraPressao = ((FirmwareSensorPressao)Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS)?.Leitura)?.Leitura ?? 0;
double _LeituraPressao = 0;
double tensao = FuncoesMatematicas.Map(_LeituraPressao, 0, 4095, 0, 3300) / 1000.0;
double pressao = FuncoesMatematicas.Map(tensao, _PressaoVmin, _PressaoVmax, 0, _PressaoMax);
return pressao;
}
}
#endregion
public double PercentualErvasTerreno { get; set; } = 0;
public static AtuadorModel CarregarParametrosIniciais()
{
AtuadorModel Atuador = new AtuadorModel()
{
_EnderecoCAN = 0x12,
_TaxaAmostragem = 1000,
RequisitarDados = true,
QuantidadeBicos = 4,
BicosPulverizadores = new List<AtuadorBicoModel>(),
BombasPressurizadoras = new List<AtuadorBombaModel>()
{
new AtuadorBombaModel()
{
ID = "BOMBA",
ID_Num = 51,
Componente = S_Code.sBMB,
Comandar = true,
Testando = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.ENA,
FuncoesPinout.CS,
FuncoesPinout.INA,
FuncoesPinout.INB,
FuncoesPinout.PWM,
}
}
},
Sensores = new List<SensorModel>()
{
new SensorModel()
{
ID = "FLXLN",
ID_Num = 61,
Descricao = "Fluxo na linha principal",
Componente = S_Code.sFLX,
Aferir = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Fluxo,
},
UnidadeMedida = "mL/s",
Parametros = new List<SensorParametroModel>()
},
new SensorModel()
{
ID = "MASRS",
ID_Num = 62,
Descricao = "Massa do reservatório de herbicida",
Componente = S_Code.sMAS,
Aferir = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.DT,
FuncoesPinout.SCK,
},
UnidadeMedida = "Kg",
Parametros = new List<SensorParametroModel>()
},
new SensorModel()
{
ID = "PRSLN",
ID_Num = 63,
Descricao = "Pressão na linha principal",
Componente = S_Code.sPRS,
Aferir = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Pressao,
},
UnidadeMedida = "psi",
Parametros = new List<SensorParametroModel>()
{
new SensorParametroModel()
{
Descricao = "Vmin",
Valor = "0",
QtdBytes = 1,
Escalar = false,
Enviar = false
},
new SensorParametroModel()
{
Descricao = "Vmax",
Valor = "4.5",
QtdBytes = 1,
Escalar = true,
Enviar = false
},
new SensorParametroModel()
{
Descricao = "Pmax",
Valor = "174",
QtdBytes = 1,
Escalar = false,
Enviar = false
},
}
},
},
};
for (int i = 0; i < Atuador.QuantidadeBicos; i++)
{
int posicao = (i + 1);
Atuador.BicosPulverizadores.Add(new AtuadorBicoModel()
{
ID = "B" + posicao.ToString("00"),
ID_Num = 70 + posicao,
Componente = S_Code.sBIC,
Posicao = posicao,
Comandar = true,
ComandoAtuar = false,
AtuacaoNivelAlto = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Solenoide,
},
MediaNivelFluxo = 0
});
}
return Atuador;
}
public void LimparDados<T>(T _dados)
{
var Dados = _dados as AtuadorModel;
Dados.DadosLeitura = new AtuadorMensagemJsonModel();
Dados.DadosLeitura.Momento = DateTime.MinValue;
Dados.PercentualErvasTerreno = 0;
Dados.BombasPressurizadoras.ForEach(x => x.Funcoes = x.Funcoes.Distinct().ToList());
ReiniciarLeituras(Dados);
}
public void ReiniciarLeituras(AtuadorModel Dados)
{
Dados.Sensores.ForEach(x =>
{
x.Leitura = null;
});
Dados.BicosPulverizadores.ForEach(x =>
{
x.ComandoAtuar = false;
x.Atuacoes = 0;
x.TempoAtuado = 0;
x.InicioAtuacao = DateTime.MinValue;
x.Leitura = null;
});
Dados.BombasPressurizadoras.ForEach(x =>
{
x.Leitura = null;
x.ComandoAtuar = false;
});
Dados.VolumeVazaoAferido = 0;
Dados._somaVazao = 0;
Dados._contadorLeituras = 0;
Dados._ultimoRegistroVazao = DateTime.MinValue;
Dados.VolumeVazaoML = 0;
Dados.VazaoFluxoMLpSMedia = 0;
Dados.TempoAtuado = 0;
Dados.InicioAtuacao = DateTime.MinValue;
}
public async Task<bool> VerificaPortaATU(SerialPort porta)
{
if (!CanService.IsConnected)
{
CanService.DefinirPortaCOM(porta);
}
CanService.RegistrarHandler(_EnderecoCAN, _AtuHandler);
if (CanService.IsConnected)
{
RequisitarDadosModulo(F_Code.ChkTx);
await Task.Delay(1000);
if (Conectado)
{
DefinirDispositivo();
Variaveis.OperacaoEmAndamento.DispAtu?.EnviarProtocolosConfiguracao();
}
}
else
{
return false;
}
if (!CanService.Iniciado)
{
CanService.Fechar();
}
return Conectado;
}
private void DefinirDispositivo()
{
if (!SerialService.DispositivosMapeados.Any(x => x.Dispositivo == Dispositivo && x.Mod_ID == Modulo_ID))
{
SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel()
{
Endereco = CanService._portName,
Dispositivo = DadosLeitura.Dispositivo,
Erro = false,
Versao = DadosLeitura.Versao.ToString(),
Mod_ID = Modulo_ID,
});
}
}
public void RequisitarDadosModulo(F_Code dado)
{
Variaveis.OperacaoEmAndamento.DispAtu?.AdicionarMensagemFila(dado);
}
public List<byte[]> ProtocoloConfiguracao(bool Conectar)
{
// Inicializar o dicionário
List<byte[]> config = new List<byte[]>();
if (!DadosLeitura.Conectado)
{
// Adicionar configuração do ProtocoloMOD
var protocoloMOD = ModConfig(Conectar);
config.AddRange(protocoloMOD);
}
// Adicionar configurações dos Sensores que devem ser aferidos
List<byte[]> sensoresConfig = SensoresConfig(Conectar);
config.AddRange(sensoresConfig);
// Adicionar configurações dos Bicos
List<byte[]> bicosConfig = BicosConfig(Conectar);
config.AddRange(bicosConfig);
// Adicionar configurações das Bombas
List<byte[]> bombasConfig = BombasConfig(Conectar);
config.AddRange(bombasConfig);
return config;
}
private List<byte[]> ModConfig(bool Conectar)
{
var config1 = new List<byte>
{
Variaveis.ID_Num_sMOD,
(byte)CanMessagePosicaoDados.Config1,
(byte)S_Code.sMOD,
(byte)(Conectar ? 1 : 0),
(byte)(_TaxaAmostragem / 10),
(byte)(RequisitarDados ? 1 : 0),
};
var config2 = new List<byte>
{
Variaveis.ID_Num_sMOD,
(byte)CanMessagePosicaoDados.Config1,
(byte)S_Code.sMOD,
};
config2.AddRange(PinoutModel.PinoProtocolo(Pinout, Funcoes, false));
return new List<byte[]>
{
config1.ToArray(),
config2.ToArray()
};
}
private List<byte[]> SensoresConfig(bool Conectar)
{
var config = new List<byte[]>();
foreach (var sensor in Sensores.Where(x => x.Aferir && x.Inicializado != Conectar))
{
byte[] payload = sensor.ProtocoloConfiguracao(Pinout, Conectar, Dispositivo);
if (payload != null)
{
config.Add(payload);
}
}
return config;
}
private List<byte[]> BicosConfig(bool Conectar)
{
var config = new List<byte[]>();
foreach (var bico in BicosPulverizadores.Where(x => x.Comandar && x.Inicializado != Conectar))
{
var payload = bico.ProtocoloConfiguracao(Pinout, Conectar);
if (payload != null)
{
config.Add(payload);
}
}
return config;
}
private List<byte[]> BombasConfig(bool Conectar)
{
var config = new List<byte[]>();
foreach (var bomba in BombasPressurizadoras.Where(x => x.Comandar && x.Inicializado != Conectar))
{
var payload = bomba.ProtocoloConfiguracao(Pinout, Conectar);
if (payload != null)
{
config.AddRange(payload);
}
}
return config;
}
public void RecebeProtocoloModulo(string Protocolo)
{
try
{
if (string.IsNullOrWhiteSpace(Protocolo))
{
Console.WriteLine("Protocolo recebido está vazio ou nulo.");
return;
}
Protocolo = Protocolo.Substring(0, Protocolo.Length - 1);
// Valida se o protocolo possui um formato esperado
if (Protocolo.Length <= 1 || !Protocolo.EndsWith("}"))
{
Console.WriteLine("Protocolo recebido está em um formato inválido.");
return;
}
//Console.WriteLine($"JSON recebido: {Protocolo}");
// Tenta desserializar o JSON
var dadosLeitura = JsonConvert.DeserializeObject<AtuadorMensagemJsonModel>(Protocolo);
if (dadosLeitura == null)
{
Console.WriteLine("Falha ao desserializar o JSON.");
return;
}
dadosLeitura.Momento = DateTime.Now;
AtualizaDadosComponentes(dadosLeitura);
}
catch (JsonException ex)
{
Console.WriteLine($"Erro ao processar o JSON recebido: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Erro inesperado no processamento do protocolo: {ex.Message}");
}
}
private void AtualizaDadosComponentes(AtuadorMensagemJsonModel dadosLeitura)
{
DadosLeitura = dadosLeitura;
}
public void IniciarRegistrador()
{
if (!(tmrRegistrador?.IsRunning ?? false))
{
LimparDados(this);
PararRegistrador();
tmrRegistrador = new AsyncTaskTimerModel("tmrRegistrador_" + T_Code.Atu.ToString(), tmrRegistrador_Tick, _TaxaAmostragem);
tmrRegistrador.Start();
}
}
public void PararRegistrador()
{
tmrRegistrador?.Dispose();
}
public async Task tmrRegistrador_Tick()
{
if (Variaveis.Fechando)
{
return;
}
tmrRegistrador.SetInterval(_TaxaAmostragem);
if (SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Atu) && (_VezesLeituraReconexao >= _TempoReconexaoComponentes))
{
Variaveis.OperacaoEmAndamento.DispAtu?.EnviarProtocolosConfiguracao();
_VezesLeituraReconexao = 0;
}
else
{
_VezesLeituraReconexao++;
}
if (DadosLeitura.Conectado)
{
if (RequisitarDados)
{
RequisitarDadosModulo(F_Code.ReqTx);
}
VerificaControleLeitura();
}
}
public (bool, List<string>) StatusModulosATU()
{
var Bicos = BicosPulverizadores.Where(x => x.Comandar).ToList();
var BicosComFalha = Bicos.Where(x => !x.Inicializado).ToList();
bool _bicosOperantes = !BicosComFalha.Any();
var _bomba = BombaPressurizadora;
var _sensorFluxo = Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX);
bool _sensorFluxoOperante = (!_sensorFluxo?.Aferir ?? false) || ((_sensorFluxo?.Aferir ?? false) && (_sensorFluxo?.Inicializado ?? false));
var _sensorMassa = Sensores.FirstOrDefault(x => x.Componente == S_Code.sMAS);
bool _sensorMassaOperante = (!_sensorMassa?.Aferir ?? false) || ((_sensorMassa?.Aferir ?? false) && (_sensorMassa?.Inicializado ?? false));
var _sensorPressao = Sensores.FirstOrDefault(x => x.Componente == S_Code.sPRS);
bool _sensorPressaoOperante = (!_sensorPressao?.Aferir ?? false) || ((_sensorPressao?.Aferir ?? false) && (_sensorPressao?.Inicializado ?? false));
List<string> ModsComFalha = BicosComFalha.Select(x => x.ID).ToList();
bool _bombaOperante = _bomba?.Inicializado ?? 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;
return (_atuadorOperante, ModsComFalha);
}
private void VerificaControleLeitura()
{
if (!frmDiagnosticos.Diagnosticando)
{
// Caso a pressao de set point da bomba seja diferente da pressao de set point de controle, reenvia o comando para garantir a integridade do controle
if (BombaPressurizadora.LeituraPressaoSP != Variaveis.OperacaoEmAndamento.Controle.PressaoLinha)
{
GeneralJoystick.EnviarComandoAtuador(S_Code.sBMB, true, BombaPressurizadora.ID);
}
if (Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico)
{
// Caso o comando do bico for diferente da leitura, reenvia o comando para garantir a integridade do controle
foreach (var bico in BicosPulverizadores.Where(x => x.Comandar && x.Inicializado))
{
if (bico.ComandoAtuar != bico.LeituraStatusBico)
{
GeneralJoystick.EnviarComandoAtuador(S_Code.sBIC, bico.ComandoAtuar, bico.ID);
}
}
}
}
}
}
public class AtuadorBicoModel
{
public string ID { get; set; }
public int ID_Num { get; set; }
public int Posicao { get; set; }
public S_Code Componente { get; set; } = S_Code.sBIC;
public bool AtuacaoNivelAlto { get; set; }
private bool _atuado;
public bool ComandoAtuar
{
get
{
return _atuado;
}
set
{
_atuado = value;
AtualizaTempoAtuado();
}
}
public bool Comandar { get; set; }
public bool Testando { get; set; }
public List<FuncoesPinout> Funcoes { get; set; }
public bool LeituraStatusBico
{
get
{
return (Leitura?.Leitura ?? Estado.Desligado) == Estado.Ligado;
}
}
public double MediaNivelFluxo { get; set; }
private FirmwareRele _leitura = null;
public FirmwareRele Leitura
{
get
{
_leitura = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.DadosLeitura?.BicosPulverizadores?.FirstOrDefault(x => x.ID == ID);
return _leitura;
}
set
{
_leitura = value;
}
}
public bool Inicializado
{
get
{
return Leitura?.Iniciado ?? false;
}
}
public byte[] ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
{
var pino = pinout.Pinos.FirstOrDefault(p => p.ComponenteID == ID);
return new byte[]
{
(byte)ID_Num,
(byte)CanMessagePosicaoDados.Config1,
(byte)Componente,
(byte)(conectar ? 1 : 0),
(byte)(AtuacaoNivelAlto ? 1 : 0),
(byte)(pino?.Barramento ?? TiposBarramentos.CONTROLADOR),
(byte)(pino?.Pino ?? PinoutUtils.PINO_INVALIDO)
};
}
public (F_Code, byte[]) ProtocoloComando()
{
return (
F_Code.CmdTx,
new byte[]
{
(byte)ID_Num,
(byte)CanMessagePosicaoDados.Command1,
(byte)(ComandoAtuar ? Estado.Ligado : Estado.Desligado)
}
);
}
public int Atuacoes { get; set; } = 0;
public DateTime InicioAtuacao { get; set; } = DateTime.MinValue;
public double TempoAtuado { get; set; } = 0;
private void AtualizaTempoAtuado()
{
if (_atuado)
{
if (InicioAtuacao == DateTime.MinValue)
{
InicioAtuacao = DateTime.Now;
}
else
{
TempoAtuado += (DateTime.Now - InicioAtuacao).TotalMilliseconds;
InicioAtuacao = DateTime.Now;
}
}
else if (InicioAtuacao != DateTime.MinValue)
{
TempoAtuado += (DateTime.Now - InicioAtuacao).TotalMilliseconds;
InicioAtuacao = DateTime.MinValue;
}
if (Variaveis.OperacaoEmAndamento.DispAtu != null)
{
Variaveis.OperacaoEmAndamento.DispAtu.Dados.AtualizaTempoAtuadoGeral();
}
}
public AtuadorBicoModel Clone()
{
AtuadorBicoModel clone = new AtuadorBicoModel()
{
Comandar = Comandar,
AtuacaoNivelAlto = AtuacaoNivelAlto,
Atuacoes = Atuacoes,
ComandoAtuar = ComandoAtuar,
Componente = Componente,
Funcoes = Funcoes,
ID = ID,
ID_Num = ID_Num,
InicioAtuacao = InicioAtuacao,
Leitura = Leitura,
MediaNivelFluxo = MediaNivelFluxo,
Posicao = Posicao,
TempoAtuado = TempoAtuado,
Testando = Testando
};
return clone;
}
}
public class AtuadorBombaModel
{
public string ID { get; set; }
public int ID_Num { get; set; }
public bool ComandoAtuar { get; set; }
public S_Code Componente { get; set; } = S_Code.sBMB;
public bool LeituraEstado
{
get
{
return (Leitura?.Estado ?? Estado.Desligado) == Estado.Ligado;
}
}
public bool Comandar { get; set; }
public bool Testando { get; set; }
public List<FuncoesPinout> Funcoes { get; set; } = new List<FuncoesPinout>();
public double LeituraPotencia
{
get
{
return Leitura?.Potencia ?? 0;
}
}
public double LeituraPressaoSP
{
get
{
return Leitura?.PressaoSP ?? 0;
}
}
public double LeituraPressao
{
get
{
return Leitura?.Pressao ?? 0;
}
}
private FirmwareBombaPressurizadora _leitura = null;
public FirmwareBombaPressurizadora Leitura
{
get
{
_leitura = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.DadosLeitura?.BombasPressurizadoras?.FirstOrDefault(x => x.ID == ID);
return _leitura;
}
set
{
_leitura = value;
}
}
public bool Inicializado
{
get
{
return Leitura?.Iniciado ?? false;
}
}
public List<byte[]> ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
{
List<byte> config1 = new List<byte>()
{
(byte)ID_Num,
(byte)CanMessagePosicaoDados.Config1,
(byte)Componente,
(byte)(conectar ? 1 : 0),
(byte)Variaveis.OperacaoEmAndamento.Controle.PressaoLinha,
(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),
};
List<byte> config2 = new List<byte>()
{
(byte)ID_Num,
(byte)CanMessagePosicaoDados.Config2,
(byte)Componente,
(byte)(pinout.Pinos.FirstOrDefault(x => x.Funcao == FuncoesPinout.INA)?.Pino ?? PinoutUtils.PINO_INVALIDO),
(byte)(pinout.Pinos.FirstOrDefault(x => x.Funcao == FuncoesPinout.INB)?.Pino ?? PinoutUtils.PINO_INVALIDO),
(byte)(pinout.Pinos.FirstOrDefault(x => x.Funcao == FuncoesPinout.PWM)?.Pino ?? PinoutUtils.PINO_INVALIDO),
};
return new List<byte[]>()
{
config1.ToArray(),
config2.ToArray()
};
}
public (F_Code, byte[]) ProtocoloComando()
{
return (
F_Code.CmdTx,
new byte[]
{
(byte)ID_Num,
(byte)CanMessagePosicaoDados.Command1,
(byte)(ComandoAtuar ? Estado.Ligado : Estado.Desligado),
(byte)(Variaveis.OperacaoEmAndamento.Controle.PressaoLinha)
}
);
}
public AtuadorBombaModel Clone()
{
AtuadorBombaModel clone = new AtuadorBombaModel()
{
ID = this.ID,
Componente = this.Componente,
ID_Num = this.ID_Num,
ComandoAtuar = this.ComandoAtuar,
Comandar = this.Comandar,
Testando = this.Testando,
Funcoes = this.Funcoes,
};
return clone;
}
}
public class CalibragemVazao
{
public bool Calibrando { get; set; } = false;
public DateTime IniciadoEm { get; set; }
public double TempoCalibragem { get; set; } = 10000.0;
public double VolumeComputado { get; set; } = 0;
public List<double> PressoesAferidas { get; set; } = new List<double>();
public double MassaInicial { get; set; } = 0.0;
public double MassaFinal { get; set; } = 0.0;
public int QtdPulsos { get; set; } = 0;
public double Periodo { get; set; } = 0.0;
public double PressaoMedia
{
get
{
return PressoesAferidas.Average();
}
}
public double MassaPerdida
{
get
{
return (MassaInicial - MassaFinal) * 1000;
}
}
public double Q
{
get
{
return (double)VolumeComputado / (double)Periodo;
}
}
public double VolumeCalculado { get; set; } = 0.0;
public double d
{
get
{
return (double)MassaPerdida / (double)VolumeComputado;
}
}
public double x
{
get
{
return (double)VolumeComputado / (double)QtdPulsos;
}
}
public double Q2
{
get
{
return (double)x * (double)QtdPulsos;
}
}
}
public class AtuadorFuncoesGerais
{
public static void DesenharAtuadores(object sender, PaintEventArgs e, List<AtuBicoSensoriamentoLogModel> Bicos, bool BombaLigada, double PressaoLinha, double TempoBombaAtuada)
{
Panel myPanel = (Panel)sender;
// Habilita o double buffering temporariamente
myPanel.GetType().GetProperty("DoubleBuffered",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
?.SetValue(myPanel, true, null);
Graphics g = e.Graphics;
int QuantidadeBicos = Bicos.Count;
int panelWidth = myPanel.Width;
int circleDiameter = 40; // Diâmetro dos círculos grandes
int smallCircleDiameter = circleDiameter / 2; // Diâmetro dos círculos pequenos
int spaceBetweenCircles = (panelWidth - (circleDiameter * QuantidadeBicos)) / (QuantidadeBicos + 1);
int yPosition = (myPanel.Height - circleDiameter) / 3; // Centralizado verticalmente
for (int i = 0; i < QuantidadeBicos; i++)
{
int xPosition = spaceBetweenCircles + (i * (circleDiameter + spaceBetweenCircles));
// Desenha o contorno do círculo
g.DrawEllipse(Pens.Red, xPosition, yPosition, circleDiameter, circleDiameter);
// Preenche o círculo se o bico estiver aceso
if (Bicos[i].Atuado)
{
g.FillEllipse(Brushes.Red, xPosition, yPosition, circleDiameter, circleDiameter);
}
// Número do bico
string bicoNumero = Bicos[i].ID;
Font font = new Font("Arial", 10, FontStyle.Bold);
SizeF stringSize = g.MeasureString(bicoNumero, font);
float textXPosition = xPosition + (circleDiameter - stringSize.Width) / 2;
float textYPosition = yPosition + (circleDiameter - stringSize.Height) / 2;
g.DrawString(bicoNumero, font, Brushes.Black, textXPosition, textYPosition);
// Média de vazão (dentro do círculo, abaixo do número do bico)
string mediaFluxoTexto = $"{Bicos[i].MediaNivelFluxo:0.0} mL/s";
Font fontMediaFluxo = new Font("Arial", 6, FontStyle.Regular);
SizeF stringSizeMediaFluxo = g.MeasureString(mediaFluxoTexto, fontMediaFluxo);
float textXPositionMediaFluxo = xPosition + circleDiameter + 3;
float textYPositionMediaFluxo = textYPosition + 3; // Abaixo do número do bico
g.DrawString(mediaFluxoTexto, fontMediaFluxo, Brushes.Gray, textXPositionMediaFluxo, textYPositionMediaFluxo);
// Quantidade de atuações (abaixo do círculo)
string bicoAtuacao = Bicos[i].Atuacoes.ToString("000");
Font fontA = new Font("Arial", 8, FontStyle.Bold);
SizeF stringSizeA = g.MeasureString(bicoAtuacao, fontA);
float textXPositionA = xPosition + (circleDiameter - stringSizeA.Width) / 2;
float textYPositionA = circleDiameter + yPosition + 5;
g.DrawString(bicoAtuacao, fontA, Brushes.Black, textXPositionA, textYPositionA);
// Tempo atuado em segundos (acima do círculo)
string tempoAtuadoSegundos = $"{(Bicos[i].TempoAtuado / 1000.0):0.0}s";
Font fontTempo = new Font("Arial", 7, FontStyle.Regular);
SizeF stringSizeTempo = g.MeasureString(tempoAtuadoSegundos, fontTempo);
float textXPositionTempo = xPosition + (circleDiameter - stringSizeTempo.Width) / 2;
float textYPositionTempo = yPosition - stringSizeTempo.Height - 3;
g.DrawString(tempoAtuadoSegundos, fontTempo, Brushes.Gray, textXPositionTempo, textYPositionTempo);
// Círculo pequeno de status
int smallCircleXPosition = Convert.ToInt32(xPosition + circleDiameter - smallCircleDiameter / 1.3);
int smallCircleYPosition = Convert.ToInt32(yPosition + circleDiameter - smallCircleDiameter / 1.3);
Pen smallCirclePen = Pens.Blue;
Brush smallCircleBrush = Bicos[i].StatusBico ? Brushes.Blue : Brushes.Transparent;
g.DrawEllipse(smallCirclePen, smallCircleXPosition, smallCircleYPosition, smallCircleDiameter, smallCircleDiameter);
g.FillEllipse(smallCircleBrush, smallCircleXPosition, smallCircleYPosition, smallCircleDiameter, smallCircleDiameter);
}
// Representação da bomba hidráulica no canto inferior direito
int bombaSize = 20; // Tamanho do círculo principal da bomba
int bombaXPosition = myPanel.Width - bombaSize - 20; // 20px de margem do canto direito
int bombaYPosition = myPanel.Height - bombaSize - 20; // 20px de margem do canto inferior
// Desenha o corpo da bomba (um círculo)
g.DrawEllipse(Pens.Black, bombaXPosition, bombaYPosition, bombaSize, bombaSize);
g.FillEllipse(BombaLigada ? Brushes.Green : Brushes.Gray, bombaXPosition, bombaYPosition, bombaSize, bombaSize);
// Define o centro do círculo para ajudar no desenho das hélices
int centerX = bombaXPosition + bombaSize / 2;
int centerY = bombaYPosition + bombaSize / 2;
int heliceSize = bombaSize - 6; // Ajuste para manter as hélices dentro do círculo
// Desenha hélices no formato de arcos ou semi-círculos dentro do círculo
Pen helicePen = new Pen(Color.Black, 1);
g.DrawArc(helicePen, centerX - heliceSize / 2, centerY - heliceSize / 2, heliceSize, heliceSize, 45, 180);
g.DrawArc(helicePen, centerX - heliceSize / 2, centerY - heliceSize / 2, heliceSize, heliceSize, 225, 180);
// Desenha o "cano" da bomba (retângulo)
int tuboLargura = 5;
int tuboAltura = 15;
int tuboXPosition = bombaXPosition + bombaSize / 2 - tuboLargura / 2;
int tuboYPosition = bombaYPosition - tuboAltura;
g.FillRectangle(Brushes.Black, tuboXPosition, tuboYPosition, tuboLargura, tuboAltura);
// Texto para o tempo de atuação acima da bomba
string tempoAtuacaoTexto = $"{(TempoBombaAtuada / 1000.0):0.0}s";
Font fontTempoAtuacao = new Font("Arial", 6, FontStyle.Regular);
SizeF stringSizeTempoAtuacao = g.MeasureString(tempoAtuacaoTexto, fontTempoAtuacao);
float textXPositionTempoAtuacao = bombaXPosition + bombaSize / 2 - stringSizeTempoAtuacao.Width / 2;
float textYPositionTempoAtuacao = bombaYPosition - stringSizeTempoAtuacao.Height - 16; // 2px acima do círculo
g.DrawString(tempoAtuacaoTexto, fontTempoAtuacao, Brushes.Gray, textXPositionTempoAtuacao, textYPositionTempoAtuacao);
// Texto pequeno para a pressão ao lado da bomba
string pressaoTexto = $"{PressaoLinha:0.0} psi";
Font fontPressao = new Font("Arial", 6, FontStyle.Regular);
SizeF stringSizePressao = g.MeasureString(pressaoTexto, fontPressao);
float textXPositionPressao = bombaXPosition + bombaSize / 2 - stringSizePressao.Width / 2;
float textYPositionPressao = bombaYPosition + bombaSize + 2; // 2px abaixo do círculo
g.DrawString(pressaoTexto, fontPressao, Brushes.Black, textXPositionPressao, textYPositionPressao);
}
}
public class FirmwareBombaPressurizadora
{
public string ID { get; set; }
public bool Iniciado { get; set; }
public Estado Estado { get; set; }
public double Potencia { get; set; }
public double PressaoSP { get; set; }
public double Pressao { get; set; }
}
public class AtuadorMensagemJsonModel
{
public DateTime Momento { get; set; }
public bool Conectado { get; set; }
public T_Code Dispositivo { get; set; }
public int Versao { get; set; }
public string Mod_ID { get; set; }
public int QualidadeWifi { get; set; }
public int LatenciaLoop { get; set; }
public List<FirmwareRele> BicosPulverizadores { get; set; } = new List<FirmwareRele>();
public List<FirmwareBombaPressurizadora> BombasPressurizadoras { get; set; } = new List<FirmwareBombaPressurizadora>();
public List<FirmwareSensorFluxo> SensoresFluxo { get; set; } = new List<FirmwareSensorFluxo>();
public List<FirmwareSensorMassa> SensoresMassa { get; set; } = new List<FirmwareSensorMassa>();
public List<FirmwareSensorPressao> SensoresPressao { get; set; } = new List<FirmwareSensorPressao>();
public DateTime UltimoComandoRespondido { get; set; }
}
public class AtuHandler : ICanMessageHandler
{
private double ConverterByteParaDouble(byte[] data, int idx)
{
int raw = (data[idx] << 8) | data[idx + 1];
short _short = (short)raw;
double _value = _short / 100.0;
return _value;
}
private S_Code DetectarComponenteDoID_Num(int ID_Num)
{
if (ID_Num == Variaveis.ID_Num_sMOD) return S_Code.sMOD;
var Disp = Variaveis.OperacaoEmAndamento.DispAtu.Dados;
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);
return sensor?.Componente ?? bico?.Componente ?? bomba?.Componente ?? S_Code.sVZO;
}
private void DefinirOuCriar(int CompID_Num, S_Code componente, bool Iniciado, List<dynamic> Parametros)
{
var Disp = Variaveis.OperacaoEmAndamento.DispAtu;
var item = Disp.Dados.DadosLeitura;
switch (componente)
{
case S_Code.sFLX:
{
var sensor = Disp.Dados.Sensores.FirstOrDefault(x => x.ID_Num == CompID_Num);
var _sensor = item.SensoresFluxo.FirstOrDefault(x => x.ID == sensor.ID);
if (_sensor == null)
{
_sensor = new FirmwareSensorFluxo()
{
ID = sensor.ID,
Iniciado = Iniciado,
Vazao = -1,
};
item.SensoresFluxo.Add(_sensor);
}
if (_sensor != null)
{
_sensor.Iniciado = Iniciado;
_sensor.Vazao = Parametros.Count > 0 ? Parametros[0] : -1;
}
break;
}
case S_Code.sPRS:
{
var sensor = Disp.Dados.Sensores.FirstOrDefault(x => x.ID_Num == CompID_Num);
var _sensor = item.SensoresPressao.FirstOrDefault(x => x.ID == sensor.ID);
if (_sensor == null)
{
_sensor = new FirmwareSensorPressao()
{
ID = sensor.ID,
Iniciado = Iniciado,
Pressao = -1,
};
item.SensoresPressao.Add(_sensor);
}
if (_sensor != null)
{
_sensor.Iniciado = Iniciado;
_sensor.Pressao = Parametros.Count > 0 ? Parametros[0] : -1;
}
break;
}
case S_Code.sMAS:
{
var sensor = Disp.Dados.Sensores.FirstOrDefault(x => x.ID_Num == CompID_Num);
var _sensor = item.SensoresMassa.FirstOrDefault(x => x.ID == sensor.ID);
if (_sensor == null)
{
_sensor = new FirmwareSensorMassa()
{
ID = sensor.ID,
Iniciado = Iniciado,
Massa = -1,
};
item.SensoresMassa.Add(_sensor);
}
if (_sensor != null)
{
_sensor.Iniciado = Iniciado;
_sensor.Massa = Parametros.Count > 0 ? Parametros[0] : -1;
}
break;
}
case S_Code.sBIC:
{
var sensor = Disp.Dados.BicosPulverizadores.FirstOrDefault(x => x.ID_Num == CompID_Num);
var _sensor = item.BicosPulverizadores.FirstOrDefault(x => x.ID == sensor.ID);
if (_sensor == null)
{
_sensor = new FirmwareRele()
{
ID = sensor.ID,
Iniciado = Iniciado,
Leitura = Estado.Desligado,
};
item.BicosPulverizadores.Add(_sensor);
}
if (_sensor != null)
{
_sensor.Iniciado = Iniciado;
_sensor.Leitura = Parametros.Count > 0 ? Parametros[0] : Estado.Desligado;
}
break;
}
case S_Code.sBMB:
{
var sensor = Disp.Dados.BombasPressurizadoras.FirstOrDefault(x => x.ID_Num == CompID_Num);
var _sensor = item.BombasPressurizadoras.FirstOrDefault(x => x.ID == sensor.ID);
if (_sensor == null)
{
_sensor = new FirmwareBombaPressurizadora()
{
ID = sensor.ID,
Iniciado = Iniciado,
Estado = Estado.Desligado,
Potencia = -1,
Pressao = -1,
PressaoSP = -1,
};
item.BombasPressurizadoras.Add(_sensor);
}
if (_sensor != null)
{
_sensor.Iniciado = Iniciado;
_sensor.Estado = Parametros.Count > 0 ? Parametros[0] : Estado.Desligado;
_sensor.Potencia = Parametros.Count > 1 ? Parametros[1] : -1;
_sensor.PressaoSP = Parametros.Count > 2 ? Parametros[2] : -1;
_sensor.Pressao = Parametros.Count > 3 ? Parametros[3] : -1;
}
break;
}
}
}
public void ProcessarMensagem(CanMessage mensagem)
{
byte ID_Num = mensagem.DataRx[0];
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)mensagem.DataRx[1];
byte id = mensagem.Id;
var data = mensagem.DataRx;
var item = Variaveis.OperacaoEmAndamento.DispAtu.Dados.DadosLeitura;
S_Code componente = DetectarComponenteDoID_Num(ID_Num);
Console.WriteLine($"[ATU] Componente={componente.ToString()}, ID_Num={ID_Num}, Data={FuncoesGlobais.ConverterComandoBytesParaTexto(data)}");
switch (posicao)
{
case CanMessagePosicaoDados.Status:
{
if (componente == S_Code.sMOD)
{
T_Code tipoModulo = (T_Code)data[2];
bool conectado = data[3] == 1;
int versao = data[4];
Console.WriteLine($"[ATU] Resposta {ID_Num} recebida. Tipo={tipoModulo}, Conectado={conectado}, Versão={versao}");
item.Conectado = conectado;
item.Dispositivo = tipoModulo;
item.Versao = versao;
}
else
{
bool Iniciado = data[2] == 1;
DefinirOuCriar(ID_Num, componente, Iniciado, new List<dynamic>());
}
break;
}
case CanMessagePosicaoDados.Dados1:
{
switch (componente)
{
case S_Code.sBIC:
{
Estado estado = (Estado)data[2];
DefinirOuCriar(ID_Num, componente, true, new List<dynamic>() { estado });
break;
}
case S_Code.sFLX:
{
double vazao = ConverterByteParaDouble(data, 2);
DefinirOuCriar(ID_Num, componente, true, new List<dynamic>() { vazao });
break;
}
case S_Code.sMAS:
{
double massa = ConverterByteParaDouble(data, 2);
DefinirOuCriar(ID_Num, componente, true, new List<dynamic>() { massa });
break;
}
case S_Code.sPRS:
{
double pressao = ConverterByteParaDouble(data, 2);
DefinirOuCriar(ID_Num, componente, true, new List<dynamic>() { pressao });
break;
}
case S_Code.sBMB:
{
Estado estado = (Estado)data[2];
int percentualPotencia = data[3];
int pressaoSp = data[4];
int pressaoAtual = data[5];
DefinirOuCriar(ID_Num, componente, true, new List<dynamic>() { estado, percentualPotencia, pressaoSp, pressaoAtual });
break;
}
default:
{
Console.WriteLine($"[ATU] Resposta do {ID_Num} recebida. Parametros nao mapeados: {FuncoesGlobais.ConverterComandoBytesParaTexto(data)}");
break;
}
}
break;
}
}
item.UltimoComandoRespondido = DateTime.Now;
}
}
}