2025-05-30 20:11:31 +00:00
using AgroBase.Services ;
2026-06-19 15:33:46 +00:00
using Newtonsoft.Json ;
2024-01-03 10:52:37 +00:00
using System ;
using System.Collections.Generic ;
2026-06-19 12:15:05 +00:00
using System.Diagnostics ;
2024-10-29 19:53:27 +00:00
using System.Drawing ;
2024-01-03 10:52:37 +00:00
using System.Linq ;
using System.Threading.Tasks ;
2024-10-29 19:53:27 +00:00
using System.Windows.Forms ;
2024-07-26 19:54:25 +00:00
using static AgroBase . Models . Enums ;
2024-01-03 10:52:37 +00:00
namespace AgroBase.Models.Modules
{
public class AtuadorModel : DispositivoBaseModel
{
2025-04-09 21:11:40 +00:00
public T_Code Dispositivo { get ; set ; } = T_Code . Atu ;
2024-06-08 01:20:23 +00:00
public string Modulo_ID { get ; set ; } = T_Code . Atu . ToString ( ) ;
2025-05-01 18:27:01 +00:00
public byte _EnderecoCAN_Tx { get ; set ; } = 0x13 ;
public byte _EnderecoCAN_Rx { get ; set ; } = 0x14 ;
2025-04-09 21:11:40 +00:00
public int _TaxaAmostragem { get ; set ; } = 1000 ;
2025-07-23 15:14:50 +00:00
public double FrequenciaBase
{
get
{
return 1.0 / ( _TaxaAmostragem / 1000.0 ) ;
}
}
2025-04-09 21:11:40 +00:00
public bool RequisitarDados { get ; set ; } = true ;
2025-12-09 12:19:36 +00:00
public static int TempoLimiteConexao { get ; set ; } = 8000 ;
2025-07-23 15:14:50 +00:00
public bool Conectado
{
get
{
2025-12-10 16:37:47 +00:00
DateTime Agora = DateTime . Now ;
bool modConectado = DadosLeitura . UltimoComandoRespondido . AddMilliseconds ( TempoLimiteConexao ) > Agora ;
return modConectado ;
2025-07-23 15:14:50 +00:00
}
}
2025-05-30 20:11:31 +00:00
public bool ConexaoAtiva
2025-04-09 21:11:40 +00:00
{
get
{
2026-06-26 20:00:49 +00:00
return Variaveis . OperacaoEmAndamento . Sensoriamento ? . OperadorSaude ? . ModulosSaude ? . Any ( x = > x . modulo = = Dispositivo & & x . status = = StatusModulo . Operante ) ? ? false ;
2025-04-09 21:11:40 +00:00
}
}
2025-07-11 16:38:08 +00:00
public bool AtuPronto { get ; set ; } = false ;
2025-04-09 21:11:40 +00:00
2025-12-05 18:25:29 +00:00
public double AnguloBarraEsquerda { get ; set ; }
public double AnguloBarraDireita { get ; set ; }
2024-04-15 10:57:37 +00:00
public static PinoutDataModel Pinout { get ; set ; }
2024-04-01 11:03:25 +00:00
public static List < FuncoesPinout > Funcoes { get ; set ; } = new List < FuncoesPinout > ( )
2024-04-15 10:57:37 +00:00
{
2024-04-01 11:03:25 +00:00
FuncoesPinout . SDA ,
FuncoesPinout . SCL ,
} ;
2025-11-24 16:05:50 +00:00
//public int QuantidadeBicos { get; set; } = 4;
2025-08-22 18:36:19 +00:00
public double DensidadeHerbicida { get ; set ; } = 1.0 ;
2025-12-15 13:41:05 +00:00
public List < AtuadorBicoModel > BicosPulverizadores { get ; set ; }
public List < AtuadorBombaModel > BombasPressurizadoras { get ; set ; }
public List < SensorModel > Sensores { get ; set ; }
2024-04-01 11:03:25 +00:00
2026-06-30 13:13:23 +00:00
[JsonIgnore]
2024-11-27 17:38:56 +00:00
public AsyncTaskTimerModel tmrRegistrador ;
2024-12-05 12:52:28 +00:00
private int _TempoReconexaoComponentes = 5 ;
2024-11-29 20:28:25 +00:00
private int _VezesLeituraReconexao = 0 ;
public AtuadorMensagemJsonModel DadosLeitura { get ; set ; } = new AtuadorMensagemJsonModel ( ) ;
2026-06-30 13:13:23 +00:00
[JsonIgnore]
2025-04-09 21:11:40 +00:00
public AtuHandler _AtuHandler = new AtuHandler ( ) ;
2024-11-27 17:38:56 +00:00
2026-06-19 15:33:46 +00:00
[JsonIgnore]
2026-06-19 12:15:05 +00:00
public AtuadorBombaModel BombaPressurizadora
{
get
{
var Bomba = BombasPressurizadoras ? . FirstOrDefault ( x = > x . ID . Contains ( "BMBLN" ) ) ;
return Bomba ;
}
}
2026-06-19 15:33:46 +00:00
[JsonIgnore]
2026-06-19 12:15:05 +00:00
public AtuadorBombaModel AgitadorDeCalda
{
get
{
var Bomba = BombasPressurizadoras ? . FirstOrDefault ( x = > x . ID . Contains ( "BMBAGT" ) ) ;
return Bomba ;
}
}
2026-06-19 15:33:46 +00:00
[JsonIgnore]
2026-06-19 12:15:05 +00:00
public SensorModel SensorMassaReservatorio
{
get
{
var sMAS = Sensores ? . FirstOrDefault ( x = > x . Componente = = S_Code . sMAS & & x . ID . Contains ( "MASRS" ) ) ;
return sMAS ;
}
}
2026-06-19 15:33:46 +00:00
[JsonIgnore]
2025-12-15 13:41:05 +00:00
private SensorModel SensorAnguloBarraEsquerda
2025-12-05 18:25:29 +00:00
{
get
{
var sMAG = Sensores ? . FirstOrDefault ( x = > x . Componente = = S_Code . sMAG & & x . ID . Contains ( "ESQ" ) ) ;
return sMAG ;
}
}
2026-06-19 15:33:46 +00:00
[JsonIgnore]
2025-12-15 13:41:05 +00:00
private SensorModel SensorAnguloBarraDireita
2025-12-05 18:25:29 +00:00
{
get
{
var sMAG = Sensores ? . FirstOrDefault ( x = > x . Componente = = S_Code . sMAG & & x . ID . Contains ( "DIR" ) ) ;
return sMAG ;
}
}
2026-04-02 17:38:24 +00:00
2025-12-09 16:47:53 +00:00
public HerbicideCounterService ContadorCarga = new HerbicideCounterService ( VariaveisEquipamento . CapacidadeReservatorio , VariaveisEquipamento . DensidadeHerbicida ) ;
2024-04-01 11:03:25 +00:00
#region VAZAO
2026-05-21 22:48:36 +00:00
2026-06-19 15:33:46 +00:00
[JsonIgnore]
2025-12-16 17:17:26 +00:00
private SensorModel SensorFluxoLinha = > Sensores . FirstOrDefault ( x = > x . Componente = = S_Code . sFLX & & x . ID = = "FLXLN" ) ;
2026-05-21 22:48:36 +00:00
2026-06-25 18:17:42 +00:00
const double FatorCalibracaoFluxo = 0.55 ;
2026-06-24 16:32:47 +00:00
2026-05-21 22:48:36 +00:00
public double VazaoMaximaSensor_LMin { get ; set ; } = 20.0 ;
2026-06-25 18:17:42 +00:00
public double VazaoFluxoMLpSInstantanea = > SensorFluxoLinha ? . ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . Fluxo ) ? . atual ? . valor ? ? 0 ;
2026-05-21 22:48:36 +00:00
2026-06-24 16:32:47 +00:00
public double VazaoFluxoMLpSInstantaneaCorrigida = > VazaoFluxoMLpSInstantanea * FatorCalibracaoFluxo ;
2025-12-16 17:17:26 +00:00
public double VazaoFluxoMLpSInstantaneaCalc
2024-12-05 12:52:28 +00:00
{
2024-04-01 11:03:25 +00:00
get
{
2026-06-22 23:33:50 +00:00
int pulsos = ( int ) ( SensorFluxoLinha ? . ValoresLeituras ?
. FirstOrDefault ( x = > x . funcao = = FuncoesPinout . QtdPulsos ) ?
. atual ? . valor ? ? 0.0 ) ;
2026-05-21 22:48:36 +00:00
2026-06-22 23:33:50 +00:00
int periodo = ( int ) ( SensorFluxoLinha ? . ValoresLeituras ?
. FirstOrDefault ( x = > x . funcao = = FuncoesPinout . Periodo ) ?
. atual ? . valor ? ? 0.0 ) ;
2025-12-16 17:17:26 +00:00
2026-05-21 22:48:36 +00:00
if ( pulsos < = 0 | | periodo < = 0 )
return 0.0 ;
double frequencia = ( double ) pulsos / periodo * 1000.0 ;
2025-12-16 17:17:26 +00:00
double q_L_min = ( frequencia + 3.0 ) / 8.1 ;
2026-05-21 22:48:36 +00:00
if ( q_L_min < 0 )
q_L_min = 0 ;
if ( q_L_min > VazaoMaximaSensor_LMin )
q_L_min = VazaoMaximaSensor_LMin ;
2026-06-22 23:33:50 +00:00
return q_L_min * 1000.0 / 60.0 * FatorCalibracaoFluxo ;
2026-05-21 22:48:36 +00:00
}
}
public double VazaoFluxoMLpSReferencia
{
get
{
2026-06-22 19:09:41 +00:00
return ObterVazaoAtualConfiavelMLs ( DateTime . Now ) ;
2024-04-01 11:03:25 +00:00
}
}
2026-05-21 22:48:36 +00:00
2026-06-22 19:09:41 +00:00
[JsonIgnore]
public double VazaoMaximaSensor_mLs = > VazaoMaximaSensor_LMin * 1000.0 / 60.0 ;
2025-12-19 12:01:58 +00:00
public double VazaoMediaMLs { get ; set ; }
public double VolumeVazadoML { get ; set ; }
public double TempoAtuado { get ; set ; }
2026-05-21 22:48:36 +00:00
2026-06-19 12:15:05 +00:00
#endregion
2026-05-21 22:48:36 +00:00
2026-06-19 12:15:05 +00:00
#region PRESSAO
2026-06-19 15:33:46 +00:00
[JsonIgnore]
2026-06-19 12:15:05 +00:00
private SensorModel SensorPressaoLinha
{
get
{
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
2026-06-25 18:17:42 +00:00
public double PressaoLinha = > SensorPressaoLinha ? . ValoresLeituras . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . Pressao ) ? . atual ? . valor ? ? 0 ;
2026-06-19 12:15:05 +00:00
public double PressaoLinhaCalc
2024-10-10 19:58:57 +00:00
{
2026-06-19 12:15:05 +00:00
get
{
2026-06-25 18:17:42 +00:00
double _LeituraPressao = SensorPressaoLinha ? . ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . LeituraBruta ) ? . atual ? . valor ? ? 0 ;
2026-06-19 12:15:05 +00:00
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 ;
#region METRICAS GERAIS DE TEMPO E VAZAO
private readonly object _metricasLock = new object ( ) ;
private long _ultimoTickMetricas ;
private HashSet < int > _bicosAtivosIntervaloAnterior = new HashSet < int > ( ) ;
private HashSet < int > _bombasAtivasIntervaloAnterior = new HashSet < int > ( ) ;
private Dictionary < int , double > _potenciaBombasIntervaloAnterior = new Dictionary < int , double > ( ) ;
private double _vazaoIntervaloAnteriorMLs ;
2026-06-22 16:46:34 +00:00
private const double IntervaloMaximoIntegracaoSeg = 2.0 ;
2026-06-19 12:15:05 +00:00
private const double IdadeMaximaTelemetriaSeg = 2.5 ;
private double _tempoMovimentoAnteriorSeg ;
private bool LeituraSensorRecente ( SensorValoresLeituraModel leitura , DateTime agora )
{
if ( leitura ? . atual = = null | | leitura . atual . lidoEm = = DateTime . MinValue )
{
return false ;
}
2025-12-18 20:14:27 +00:00
2026-06-19 12:15:05 +00:00
double idadeSeg = ( agora - leitura . atual . lidoEm ) . TotalSeconds ;
return idadeSeg > = - 1.0 & & idadeSeg < = IdadeMaximaTelemetriaSeg ;
}
2024-10-29 19:53:27 +00:00
2026-06-19 12:15:05 +00:00
private double ObterVazaoAtualConfiavelMLs ( DateTime agora )
{
var sensor = SensorFluxoLinha ;
2026-06-25 18:17:42 +00:00
if ( sensor = = null | | ! sensor . Inicializado | | sensor . ValoresLeituras = = null )
2026-06-19 12:15:05 +00:00
return 0 ;
2025-12-19 12:01:58 +00:00
2026-06-22 19:09:41 +00:00
double maximaMLs =
VazaoMaximaSensor_LMin *
1000.0 /
60.0 ;
2026-06-25 18:17:42 +00:00
var leituraFluxo = sensor . ValoresLeituras . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . Fluxo ) ;
2025-12-18 20:14:27 +00:00
2026-06-19 12:15:05 +00:00
/ *
2026-06-22 19:09:41 +00:00
* IMPORTANTE :
* A leitura direta FuncoesPinout . Fluxo já está em mL / s no modelo .
* Não converter novamente de L / min para mL / s .
*
* Zero recente é válido . Se a linha está sem fluxo , o sensor deve
* poder dizer zero sem cair no fallback por pulso antigo .
2026-06-19 12:15:05 +00:00
* /
if ( LeituraSensorRecente ( leituraFluxo , agora ) )
2024-10-10 19:58:57 +00:00
{
2026-06-22 19:09:41 +00:00
double vazaoMLs ;
2025-12-18 20:14:27 +00:00
2026-06-19 12:15:05 +00:00
try
{
2026-06-25 18:17:42 +00:00
vazaoMLs = Convert . ToDouble ( leituraFluxo . atual . valor ) ;
2026-06-19 12:15:05 +00:00
}
catch
{
return 0 ;
}
2026-06-22 19:09:41 +00:00
if ( double . IsNaN ( vazaoMLs ) | |
double . IsInfinity ( vazaoMLs ) | |
vazaoMLs < 0 )
2026-06-19 12:15:05 +00:00
{
return 0 ;
}
2026-06-25 18:17:42 +00:00
double vazaoCorrigidaMLs = vazaoMLs * FatorCalibracaoFluxo ;
2026-06-22 19:09:41 +00:00
return FuncoesMatematicas . Clamp (
2026-06-25 18:17:42 +00:00
vazaoCorrigidaMLs ,
2026-06-19 12:15:05 +00:00
0.0 ,
2026-06-22 19:09:41 +00:00
maximaMLs
2026-06-19 12:15:05 +00:00
) ;
2024-10-10 19:58:57 +00:00
}
2024-10-29 19:53:27 +00:00
2026-06-19 12:15:05 +00:00
/ *
2026-06-22 19:09:41 +00:00
* Fallback por pulso :
* aqui sim a fórmula calcula q em L / min e depois converte para mL / s .
2026-06-19 12:15:05 +00:00
* /
2026-06-25 18:17:42 +00:00
var leituraPulsos = sensor . ValoresLeituras . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . QtdPulsos ) ;
var leituraPeriodo = sensor . ValoresLeituras . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . Periodo ) ;
2026-06-19 12:15:05 +00:00
2026-06-25 18:17:42 +00:00
if ( ! LeituraSensorRecente ( leituraPulsos , agora ) | | ! LeituraSensorRecente ( leituraPeriodo , agora ) )
2026-06-19 12:15:05 +00:00
return 0 ;
2026-06-25 18:17:42 +00:00
2026-06-19 12:15:05 +00:00
double calculadaMLs =
VazaoFluxoMLpSInstantaneaCalc ;
2026-05-21 22:48:36 +00:00
2026-06-25 18:17:42 +00:00
if ( double . IsNaN ( calculadaMLs ) | | double . IsInfinity ( calculadaMLs ) | | calculadaMLs < 0 )
2026-06-19 12:15:05 +00:00
return 0 ;
2026-06-25 18:17:42 +00:00
2026-06-19 12:15:05 +00:00
return FuncoesMatematicas . Clamp (
calculadaMLs ,
0.0 ,
maximaMLs
) ;
2024-10-10 19:58:57 +00:00
}
2026-05-21 22:48:36 +00:00
2026-06-19 12:15:05 +00:00
private double ObterPotenciaAtualConfiavelPct ( AtuadorBombaModel bomba , DateTime agora )
2024-12-05 12:52:28 +00:00
{
2026-06-25 18:17:42 +00:00
if ( bomba = = null | | ! bomba . Inicializado | | bomba . ValoresLeituras = = null )
2026-06-19 12:15:05 +00:00
return 0 ;
2025-12-18 20:14:27 +00:00
2026-06-25 18:17:42 +00:00
var leituraPotencia = bomba . ValoresLeituras . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . Potencia ) ;
2026-06-19 12:15:05 +00:00
2026-06-25 18:17:42 +00:00
if ( ! LeituraSensorRecente ( leituraPotencia , agora ) )
2026-06-19 12:15:05 +00:00
return 0 ;
2024-12-05 12:52:28 +00:00
2026-06-19 12:15:05 +00:00
double potencia ;
2025-12-18 20:14:27 +00:00
2026-06-19 12:15:05 +00:00
try
{
2026-06-25 18:17:42 +00:00
potencia = Convert . ToDouble ( leituraPotencia . atual . valor ) ;
2026-06-19 12:15:05 +00:00
}
catch
{
return 0 ;
}
2026-05-21 22:48:36 +00:00
2026-06-25 18:17:42 +00:00
if ( double . IsNaN ( potencia ) | | double . IsInfinity ( potencia ) )
2026-06-19 12:15:05 +00:00
return 0 ;
2026-05-21 22:48:36 +00:00
2026-06-19 12:15:05 +00:00
return FuncoesMatematicas . Clamp (
potencia ,
0.0 ,
100.0
) ;
}
public void AtualizarMetricasOperacao ( )
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2026-06-19 12:15:05 +00:00
lock ( _metricasLock )
2026-05-21 22:48:36 +00:00
{
2026-06-26 20:00:49 +00:00
long agoraTicks = Stopwatch . GetTimestamp ( ) ;
DateTime agora = DateTime . Now ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
bool operacaoConcluida = op . Sensoriamento ? . Operacao ? . StatusOperacaoAtual = = StatusOperacao . Concluido ;
bool operacaoAtiva = op . Sensoriamento ? . Operacao ? . OperacaoIniciada = = true & & ! operacaoConcluida ;
2026-06-19 12:15:05 +00:00
2026-06-22 16:46:34 +00:00
bool atuadorComTelemetriaRecente =
DadosLeitura ! = null & &
DadosLeitura . UltimoComandoRespondido ! = DateTime . MinValue & &
2026-06-26 20:00:49 +00:00
DadosLeitura . UltimoComandoRespondido . AddMilliseconds ( TempoLimiteConexao ) > agora ;
2026-06-22 16:46:34 +00:00
2026-06-26 20:00:49 +00:00
bool atuadorTemEstrutura = ( BicosPulverizadores ? . Count ? ? 0 ) > 0 ;
2026-06-22 16:46:34 +00:00
2026-06-19 12:15:05 +00:00
bool atuadorDisponivel =
operacaoAtiva & &
2026-06-22 16:46:34 +00:00
atuadorTemEstrutura & &
atuadorComTelemetriaRecente ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
bool pulverizadorAutomatico = op . Parametros ? . Controle ? . PulverizadorAutomatico ? ? false ;
2026-06-19 12:15:05 +00:00
/ *
* Bicos são contabilizados pelo comando de alta resolução .
* O retorno CAN permanece sendo telemetria e diagnóstico .
* /
2026-06-26 20:00:49 +00:00
var bicosAtivosAgora = atuadorDisponivel
? BicosPulverizadores
. Where ( b = >
b ! = null & &
b . Inicializado & &
b . Comandar & &
b . ComandoAtuar )
. Select ( b = > b . ID_Num )
. ToHashSet ( )
: new HashSet < int > ( ) ;
2026-06-19 12:15:05 +00:00
/ *
* O mesmo estado usado nas métricas governa
* abertura e fechamento dos trechos .
* /
2026-06-26 20:00:49 +00:00
foreach ( var bico in BicosPulverizadores ? ? new List < AtuadorBicoModel > ( ) )
2026-06-19 12:15:05 +00:00
{
2026-06-26 20:00:49 +00:00
bool atuandoComandado = bicosAtivosAgora . Contains ( bico . ID_Num ) ;
bico . AtualizarEstadoTrecho ( atuandoComandado ) ;
2026-06-19 12:15:05 +00:00
}
/ *
* Em pulverização automática , respeita a mesma liberação
* utilizada por VerificaControleLeitura ( ) .
* /
bool bombasLiberadas =
! pulverizadorAutomatico | |
ContadorCarga . PulverizadorLiberado ;
var bombasAtivasAgora =
atuadorDisponivel & &
bombasLiberadas
? BombasPressurizadoras
. Where ( b = >
b ! = null & &
b . Inicializado & &
b . Comandar & &
b . ComandoAtuar )
. Select ( b = > b . ID_Num )
. ToHashSet ( )
: new HashSet < int > ( ) ;
2026-06-26 20:00:49 +00:00
double vazaoAtualMLs = operacaoAtiva ? ObterVazaoAtualConfiavelMLs ( agora ) : 0.0 ;
double tempoMovimentoAtualSeg = op . Sensoriamento ? . Movimentacao ? . TempoMovimentoSegs ? ? 0.0 ;
2026-06-19 12:15:05 +00:00
if ( _ultimoTickMetricas ! = 0 )
{
2026-06-26 20:00:49 +00:00
double dt = ( agoraTicks - _ultimoTickMetricas ) / ( double ) Stopwatch . Frequency ;
2026-06-19 12:15:05 +00:00
2026-06-22 16:46:34 +00:00
if ( dt > 0 & & dt < = IntervaloMaximoIntegracaoSeg )
2026-06-19 12:15:05 +00:00
{
double deltaMovimentoSeg = 0 ;
2026-06-26 20:00:49 +00:00
if ( tempoMovimentoAtualSeg > = _tempoMovimentoAnteriorSeg )
2026-06-19 12:15:05 +00:00
{
2026-06-26 20:00:49 +00:00
deltaMovimentoSeg = tempoMovimentoAtualSeg - _tempoMovimentoAnteriorSeg ;
2026-06-19 12:15:05 +00:00
}
/ *
* O tempo em movimento não pode exceder
* o tempo físico do intervalo integrado .
* /
2026-06-26 20:00:49 +00:00
deltaMovimentoSeg = FuncoesMatematicas . Clamp ( deltaMovimentoSeg , 0.0 , dt ) ;
IntegrarIntervaloAnterior ( dt , deltaMovimentoSeg ) ;
2026-06-19 12:15:05 +00:00
}
else
{
/ *
* Houve pausa anormal no loop .
* Não inventa tempo nem volume .
* /
ZerarVazoesInstantaneas ( ) ;
2026-06-22 16:46:34 +00:00
if ( dt > IntervaloMaximoIntegracaoSeg )
{
Variaveis . MostrarLog ( "[ATU/METRICAS] Integração ignorada por dt alto: " + dt . ToString ( "0.000" ) + "s" ) ;
2026-06-26 20:00:49 +00:00
op . Sensoriamento . InserirLog ( Dispositivo , StatusModulo . Alerta , 50 , "[ATU/METRICAS] Integração ignorada por dt alto: " + dt . ToString ( "0.000" ) + "s" ) ;
2026-06-22 16:46:34 +00:00
}
2026-06-19 12:15:05 +00:00
}
}
/ *
* Contagem de atuações das bombas por borda
* do comando efetivo OFF - > ON .
* /
2026-06-26 20:00:49 +00:00
foreach ( var bomba in BombasPressurizadoras ? ? new List < AtuadorBombaModel > ( ) )
2026-06-19 12:15:05 +00:00
{
2026-06-26 20:00:49 +00:00
bool estavaLigada = _bombasAtivasIntervaloAnterior . Contains ( bomba . ID_Num ) ;
bool estaLigada = bombasAtivasAgora . Contains ( bomba . ID_Num ) ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
if ( ! estavaLigada & & estaLigada )
2026-06-19 12:15:05 +00:00
{
bomba . Atuacoes + + ;
}
}
/ *
* Atualiza o snapshot que representará
* o próximo intervalo .
* /
2026-06-26 20:00:49 +00:00
_ultimoTickMetricas = agoraTicks ;
_tempoMovimentoAnteriorSeg = tempoMovimentoAtualSeg ;
_bicosAtivosIntervaloAnterior = bicosAtivosAgora ;
_bombasAtivasIntervaloAnterior = bombasAtivasAgora ;
_potenciaBombasIntervaloAnterior = ( BombasPressurizadoras ? ?
new List < AtuadorBombaModel > ( ) )
. ToDictionary (
b = > b . ID_Num ,
b = >
ObterPotenciaAtualConfiavelPct (
b ,
agora
)
) ;
_vazaoIntervaloAnteriorMLs = vazaoAtualMLs ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
AtualizarVazoesInstantaneas ( bicosAtivosAgora , vazaoAtualMLs ) ;
VazaoMediaMLs = TempoAtuado > 0 ? VolumeVazadoML / TempoAtuado : 0 ;
2026-06-19 12:15:05 +00:00
AtualizaPercentualErvas ( ) ;
2026-05-21 22:48:36 +00:00
}
2026-06-19 12:15:05 +00:00
}
private void IntegrarIntervaloAnterior ( double dt , double tempoMovimentoIntervaloSeg )
{
2026-06-26 20:00:49 +00:00
var bicosDoIntervalo = ( BicosPulverizadores ? ?
new List < AtuadorBicoModel > ( ) )
. Where ( b = >
_bicosAtivosIntervaloAnterior
. Contains ( b . ID_Num ) )
. ToList ( ) ;
2026-06-19 12:15:05 +00:00
/ *
* Tempo geral de pulverização :
* tempo durante o qual pelo menos um bico
* permaneceu comandado .
* /
if ( bicosDoIntervalo . Count > 0 )
{
TempoAtuado + = dt ;
2026-06-26 20:00:49 +00:00
foreach ( var bico in bicosDoIntervalo )
2026-06-19 12:15:05 +00:00
{
bico . TempoAtuado + = dt ;
2026-06-26 20:00:49 +00:00
bico . TempoAtuadoEmMovimento + = tempoMovimentoIntervaloSeg ;
2026-06-19 12:15:05 +00:00
}
2025-12-19 12:01:58 +00:00
2026-06-26 20:00:49 +00:00
double vazaoTotalMLs = Math . Max ( 0 , _vazaoIntervaloAnteriorMLs ) ;
2026-06-19 12:15:05 +00:00
if ( vazaoTotalMLs > 0 )
{
2026-06-26 20:00:49 +00:00
double volumeIntervaloML = vazaoTotalMLs * dt ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
VolumeVazadoML + = volumeIntervaloML ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
double volumePorBicoML = volumeIntervaloML / bicosDoIntervalo . Count ;
2026-06-19 12:15:05 +00:00
2026-06-22 19:09:41 +00:00
foreach ( var bico in bicosDoIntervalo )
2026-06-19 12:15:05 +00:00
{
bico . TempoComFluxo + = dt ;
2026-06-22 19:09:41 +00:00
bico . VolumeVazadoML + = volumePorBicoML ;
2026-06-19 12:15:05 +00:00
}
}
2025-12-18 20:14:27 +00:00
2026-06-19 12:15:05 +00:00
/ *
* A média precisa ser recalculada mesmo quando
* não existe fluxo . O tempo continua crescendo ,
* logo a média operacional deve diminuir .
* /
2026-06-26 20:00:49 +00:00
foreach ( var bico in bicosDoIntervalo )
2026-06-19 12:15:05 +00:00
{
2026-06-26 20:00:49 +00:00
bico . VazaoMediaMLs = bico . TempoAtuado > 0 ? bico . VolumeVazadoML / bico . TempoAtuado : 0 ;
2026-06-19 12:15:05 +00:00
}
}
2024-12-05 12:52:28 +00:00
2026-06-19 12:15:05 +00:00
/ *
* Bombas incluem BMBLN e BMBAGT .
* TempoAtuado é baseado no comando efetivo .
* TempoComPotencia usa telemetria CAN recente .
* /
2026-06-26 20:00:49 +00:00
foreach ( var bomba in BombasPressurizadoras ? ? new List < AtuadorBombaModel > ( ) )
2024-12-05 12:52:28 +00:00
{
2026-06-26 20:00:49 +00:00
if ( ! _bombasAtivasIntervaloAnterior . Contains ( bomba . ID_Num ) )
2026-06-19 12:15:05 +00:00
{
continue ;
}
2024-12-05 12:52:28 +00:00
2026-06-19 12:15:05 +00:00
bomba . TempoAtuado + = dt ;
2026-06-26 20:00:49 +00:00
double potencia = _potenciaBombasIntervaloAnterior
. TryGetValue (
bomba . ID_Num ,
out double valorPotencia )
? valorPotencia
: 0 ;
2026-06-19 12:15:05 +00:00
if ( potencia > 0 )
{
bomba . TempoComPotencia + = dt ;
2026-06-26 20:00:49 +00:00
bomba . PotenciaAcumuladaPctSeg + = potencia * dt ;
2026-06-19 12:15:05 +00:00
}
/ *
* Como o nome é PotenciaMediaAtiva ,
* o denominador deve ser o período com
* potência efetivamente observada .
* /
2026-06-26 20:00:49 +00:00
bomba . PotenciaMediaAtiva = bomba . TempoComPotencia > 0 ? bomba . PotenciaAcumuladaPctSeg / bomba . TempoComPotencia : 0 ;
2025-12-19 12:01:58 +00:00
}
}
2026-05-21 22:48:36 +00:00
2026-06-19 12:15:05 +00:00
private void AtualizarVazoesInstantaneas ( HashSet < int > ativos , double vazaoTotalMLs )
2025-12-19 12:01:58 +00:00
{
2026-06-19 12:15:05 +00:00
foreach ( var bico in BicosPulverizadores )
bico . VazaoInstantaneaMLs = 0 ;
2024-12-05 12:52:28 +00:00
2026-06-19 12:15:05 +00:00
if ( ativos . Count = = 0 | | vazaoTotalMLs < = 0 )
{
return ;
}
2024-04-01 11:03:25 +00:00
2026-06-19 12:15:05 +00:00
double vazaoPorBico = vazaoTotalMLs / ativos . Count ;
foreach ( var bico in BicosPulverizadores )
2024-12-02 19:12:39 +00:00
{
2026-06-19 12:15:05 +00:00
if ( ativos . Contains ( bico . ID_Num ) )
{
bico . VazaoInstantaneaMLs = vazaoPorBico ;
}
2024-12-02 19:12:39 +00:00
}
}
2026-06-19 12:15:05 +00:00
private void AtualizaPercentualErvas ( )
2024-04-01 11:03:25 +00:00
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
double tempoMovimentoSeg = op . Sensoriamento ? . Movimentacao ? . TempoMovimentoSegs ? ? 0 ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
var bicosConsiderados = BicosPulverizadores ?
. Where ( b = > b ! = null & & b . Comandar )
. ToList ( )
? ? new List < AtuadorBicoModel > ( ) ;
if ( tempoMovimentoSeg < = 0 | | bicosConsiderados . Count = = 0 )
2024-04-01 11:03:25 +00:00
{
2026-06-19 12:15:05 +00:00
PercentualErvasTerreno = 0 ;
return ;
2024-04-01 11:03:25 +00:00
}
2026-06-19 12:15:05 +00:00
/ *
* Soma somente atuação ocorrida enquanto
* o rover acumulava tempo de movimento .
* /
2026-06-26 20:00:49 +00:00
double somaBicoSegEmMovimento = bicosConsiderados . Sum ( b = > b . TempoAtuadoEmMovimento ) ;
2026-06-19 12:15:05 +00:00
/ *
* Capacidade total :
* tempo de movimento x quantidade de regiões / bicos .
* /
2026-06-26 20:00:49 +00:00
double capacidadeTotalBicoSeg = tempoMovimentoSeg * bicosConsiderados . Count ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
double percentual = capacidadeTotalBicoSeg > 0 ? somaBicoSegEmMovimento / capacidadeTotalBicoSeg * 100.0 : 0 ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
percentual = FuncoesMatematicas . Clamp ( percentual , 0.0 , 100.0 ) ;
PercentualErvasTerreno = Math . Round ( percentual , 2 ) ;
2024-04-01 11:03:25 +00:00
}
2024-01-03 10:52:37 +00:00
2026-06-19 12:15:05 +00:00
private void ZerarVazoesInstantaneas ( )
{
foreach ( var bico in BicosPulverizadores )
bico . VazaoInstantaneaMLs = 0 ;
}
#endregion
2024-01-03 10:52:37 +00:00
public static AtuadorModel CarregarParametrosIniciais ( )
{
AtuadorModel Atuador = new AtuadorModel ( )
{
2025-05-30 20:11:31 +00:00
_EnderecoCAN_Tx = 0x12 ,
_EnderecoCAN_Rx = 0x12 ,
2025-04-09 21:11:40 +00:00
_TaxaAmostragem = 1000 ,
2026-03-21 01:48:37 +00:00
RequisitarDados = true ,
// 11 ~ 50
Sensores = new List < SensorModel > ( )
2024-04-01 11:03:25 +00:00
{
2026-03-21 01:48:37 +00:00
// pressao 11 ~ 20
new SensorModel ( )
2024-04-01 11:03:25 +00:00
{
2026-03-21 01:48:37 +00:00
ID = "PRSLN" ,
ID_Num = 11 ,
Descricao = "Pressão na linha principal" ,
Componente = S_Code . sPRS ,
Aferir = true ,
2025-05-07 16:54:45 +00:00
Mandatorio = true ,
2024-11-29 20:28:25 +00:00
Funcoes = new List < FuncoesPinout > ( )
{
2026-03-21 01:48:37 +00:00
FuncoesPinout . Pressao ,
2025-05-30 20:11:31 +00:00
} ,
2026-03-21 01:48:37 +00:00
Parametros = new List < SensorParametroModel > ( )
2025-05-30 20:11:31 +00:00
{
2026-03-21 01:48:37 +00:00
new SensorParametroModel ( )
2025-05-30 20:11:31 +00:00
{
2026-03-21 01:48:37 +00:00
Descricao = "Vmin" ,
Valor = "0" ,
QtdBytes = 1 ,
Escalar = false ,
Enviar = false
2025-05-30 20:11:31 +00:00
} ,
2026-03-21 01:48:37 +00:00
new SensorParametroModel ( )
2025-05-30 20:11:31 +00:00
{
2026-03-21 01:48:37 +00:00
Descricao = "Vmax" ,
Valor = "4.5" ,
QtdBytes = 1 ,
Escalar = true ,
Enviar = false
2025-05-30 20:11:31 +00:00
} ,
2026-03-21 01:48:37 +00:00
new SensorParametroModel ( )
{
Descricao = "Pmax" ,
Valor = "174" ,
QtdBytes = 1 ,
Escalar = false ,
Enviar = false
} ,
} ,
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
2025-05-30 20:11:31 +00:00
new SensorValoresLeituraModel ( )
{
2026-03-21 01:48:37 +00:00
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
indice = 0 ,
2025-05-30 20:11:31 +00:00
} ,
new SensorValoresLeituraModel ( )
{
2026-03-21 01:48:37 +00:00
funcao = FuncoesPinout . LeituraBruta ,
2025-05-30 20:11:31 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
2026-03-21 01:48:37 +00:00
indice = 0 ,
2025-05-30 20:11:31 +00:00
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Pressao ,
posicao = CanMessagePosicaoDados . Dados1 ,
2026-03-21 01:48:37 +00:00
indice = 1 ,
analise_health = true ,
maximo = 120 ,
minimo = 0 ,
nominal = 85 ,
unidade_medida = "PSI"
2025-05-30 20:11:31 +00:00
}
2024-11-29 20:28:25 +00:00
}
2026-03-21 01:48:37 +00:00
} ,
// fluxo 21 ~ 30
2024-02-21 19:40:38 +00:00
new SensorModel ( )
{
ID = "FLXLN" ,
2026-03-21 01:48:37 +00:00
ID_Num = 21 ,
2024-02-21 19:40:38 +00:00
Descricao = "Fluxo na linha principal" ,
Componente = S_Code . sFLX ,
2025-04-09 21:11:40 +00:00
Aferir = true ,
2026-03-21 01:48:37 +00:00
Mandatorio = true ,
2024-02-21 19:40:38 +00:00
Funcoes = new List < FuncoesPinout > ( )
{
FuncoesPinout . Fluxo ,
} ,
2025-05-30 20:11:31 +00:00
Parametros = new List < SensorParametroModel > ( ) ,
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
new SensorValoresLeituraModel ( )
{
2026-03-21 01:48:37 +00:00
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
2025-05-30 20:11:31 +00:00
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
2025-12-16 17:17:26 +00:00
{
funcao = FuncoesPinout . QtdPulsos ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Periodo ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 1 ,
} ,
new SensorValoresLeituraModel ( )
2025-05-30 20:11:31 +00:00
{
funcao = FuncoesPinout . Fluxo ,
2026-03-21 01:48:37 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 2 ,
analise_health = true ,
maximo = 20 ,
minimo = 0 ,
nominal = 0 ,
2025-05-30 20:11:31 +00:00
unidade_medida = "mL/s"
}
}
2024-02-21 19:40:38 +00:00
} ,
2026-06-09 13:39:44 +00:00
// massa 31 ~ 35
2024-02-21 19:40:38 +00:00
new SensorModel ( )
{
ID = "MASRS" ,
2026-03-21 01:48:37 +00:00
ID_Num = 31 ,
2024-02-21 19:40:38 +00:00
Descricao = "Massa do reservatório de herbicida" ,
Componente = S_Code . sMAS ,
2025-04-09 21:11:40 +00:00
Aferir = true ,
2026-03-21 01:48:37 +00:00
Mandatorio = true ,
2024-02-21 19:40:38 +00:00
Funcoes = new List < FuncoesPinout > ( )
{
FuncoesPinout . DT ,
FuncoesPinout . SCK ,
} ,
2025-04-09 21:11:40 +00:00
Parametros = new List < SensorParametroModel > ( )
2025-05-01 18:27:01 +00:00
{
new SensorParametroModel ( )
{
2026-03-21 01:48:37 +00:00
Descricao = "Offset" ,
2025-05-01 18:27:01 +00:00
Enviar = true ,
2025-12-10 16:37:47 +00:00
Escalar = true ,
2025-05-01 18:27:01 +00:00
QtdBytes = 2 ,
2025-12-16 19:33:06 +00:00
Valor = "0.0"
2025-05-01 18:27:01 +00:00
}
2025-05-30 20:11:31 +00:00
} ,
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
2025-12-16 17:17:26 +00:00
funcao = FuncoesPinout . LeituraBruta ,
2025-05-30 20:11:31 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 0 ,
2025-12-16 17:17:26 +00:00
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Massa ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 1 ,
2025-05-30 20:11:31 +00:00
analise_health = true ,
2026-06-24 16:32:47 +00:00
maximo = VariaveisEquipamento . CapacidadeReservatorio + 10.0 ,
minimo = VariaveisEquipamento . PercentualReservatorioMinCritio ,
nominal = VariaveisEquipamento . CapacidadeReservatorio ,
2025-05-30 20:11:31 +00:00
unidade_medida = "Kg"
}
2025-05-01 18:27:01 +00:00
}
2024-02-21 19:40:38 +00:00
} ,
2026-06-15 20:02:05 +00:00
// botoeira 36 ~ 40
2026-06-09 13:39:44 +00:00
new SensorModel ( )
{
ID = "BOTLAV" ,
ID_Num = 36 ,
Descricao = "Botão para lavagem do sistema hidráulico" ,
Componente = S_Code . sBOT ,
Aferir = true ,
Mandatorio = false ,
Funcoes = new List < FuncoesPinout > ( )
{
FuncoesPinout . Botao ,
} ,
Parametros = new List < SensorParametroModel > ( ) ,
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Botao ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . LeituraBruta ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 1 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . EstadoLeitura ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 2 ,
} ,
}
} ,
2026-03-21 01:48:37 +00:00
// magnetico 41 ~ 50
2025-12-04 13:51:11 +00:00
new SensorModel ( )
{
ID = "MAGESQ" ,
Descricao = "Angulo Barra Esquerda" ,
2026-03-21 01:48:37 +00:00
ID_Num = 41 ,
2025-12-04 13:51:11 +00:00
Componente = S_Code . sMAG ,
2026-06-19 15:33:46 +00:00
Aferir = false ,
Mandatorio = false ,
2025-12-04 13:51:11 +00:00
Funcoes = new List < FuncoesPinout > ( )
{
FuncoesPinout . I2C ,
} ,
Parametros = new List < SensorParametroModel > ( )
{
new SensorParametroModel ( )
{
Descricao = "Endereço I2C" ,
Valor = "0x36" ,
QtdBytes = 1 ,
Escalar = false ,
Enviar = true
} ,
new SensorParametroModel ( )
{
Descricao = "Canal MUX" ,
Valor = "0" ,
QtdBytes = 1 ,
Escalar = false ,
Enviar = true
} ,
} ,
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . LeituraBruta ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 0 ,
unidade_medida = ""
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . LeituraAngulo ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 1 ,
unidade_medida = "°"
} ,
}
} ,
new SensorModel ( )
{
ID = "MAGDIR" ,
Descricao = "Angulo Barra Direita" ,
2026-03-21 01:48:37 +00:00
ID_Num = 42 ,
2025-12-04 13:51:11 +00:00
Componente = S_Code . sMAG ,
2026-06-19 15:33:46 +00:00
Aferir = false ,
Mandatorio = false ,
2025-12-04 13:51:11 +00:00
Funcoes = new List < FuncoesPinout > ( )
{
FuncoesPinout . I2C ,
} ,
Parametros = new List < SensorParametroModel > ( )
{
new SensorParametroModel ( )
{
Descricao = "Endereço I2C" ,
Valor = "0x36" ,
QtdBytes = 1 ,
Escalar = false ,
Enviar = true
} ,
new SensorParametroModel ( )
{
Descricao = "Canal MUX" ,
Valor = "1" ,
QtdBytes = 1 ,
Escalar = false ,
Enviar = true
} ,
} ,
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . LeituraBruta ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 0 ,
unidade_medida = ""
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . LeituraAngulo ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 1 ,
unidade_medida = "°"
} ,
}
} ,
2024-02-21 19:40:38 +00:00
} ,
2026-04-02 17:38:24 +00:00
// 51 ~ 60
2026-03-21 01:48:37 +00:00
BombasPressurizadoras = new List < AtuadorBombaModel > ( )
2025-12-16 17:17:26 +00:00
{
2026-03-21 01:48:37 +00:00
new AtuadorBombaModel ( )
2025-12-16 17:17:26 +00:00
{
2026-03-21 01:48:37 +00:00
ID = "BMBLN" ,
ID_Num = 51 ,
Sensor_ID_Num = 11 ,
ComandoAtuar = false ,
2026-04-02 17:38:24 +00:00
PressaoSP = 100 ,
2026-06-18 16:38:44 +00:00
PotenciaSP = 100 ,
2026-03-21 01:48:37 +00:00
Componente = S_Code . sBMB ,
Comandar = true ,
Mandatorio = true ,
2025-12-16 17:17:26 +00:00
Funcoes = new List < FuncoesPinout > ( )
{
2026-04-01 17:03:04 +00:00
FuncoesPinout . IN1 ,
FuncoesPinout . IN2 ,
2025-12-16 17:17:26 +00:00
} ,
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
indice = 0 ,
} ,
2026-06-25 18:17:42 +00:00
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . MalhaFechada ,
posicao = CanMessagePosicaoDados . Status ,
indice = 1 ,
} ,
2025-12-16 17:17:26 +00:00
new SensorValoresLeituraModel ( )
{
2026-03-21 01:48:37 +00:00
funcao = FuncoesPinout . EstadoLeitura ,
2025-12-16 17:17:26 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
2026-04-02 17:38:24 +00:00
funcao = FuncoesPinout . PotenciaSP ,
2026-03-21 01:48:37 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 1 ,
2025-12-16 17:17:26 +00:00
} ,
new SensorValoresLeituraModel ( )
{
2026-04-02 17:38:24 +00:00
funcao = FuncoesPinout . Potencia ,
2025-12-16 17:17:26 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
2026-03-21 01:48:37 +00:00
indice = 2 ,
2025-12-16 17:17:26 +00:00
} ,
2026-03-21 01:48:37 +00:00
new SensorValoresLeituraModel ( )
{
2026-04-02 17:38:24 +00:00
funcao = FuncoesPinout . PressaoSP ,
2026-03-21 01:48:37 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 3 ,
2026-04-02 17:38:24 +00:00
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Pressao ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 4 ,
2026-06-09 13:39:44 +00:00
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . ModoControleBomba ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 5 ,
2026-06-25 18:17:42 +00:00
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . QtdPulsos ,
posicao = CanMessagePosicaoDados . Dados2 ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . PotenciaSP ,
posicao = CanMessagePosicaoDados . Dados2 ,
indice = 1 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Potencia ,
posicao = CanMessagePosicaoDados . Dados2 ,
indice = 2 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Pressao ,
posicao = CanMessagePosicaoDados . Dados2 ,
indice = 3 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . PressaoSP ,
posicao = CanMessagePosicaoDados . Dados2 ,
indice = 4 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . PressaoSPExtra ,
posicao = CanMessagePosicaoDados . Dados2 ,
indice = 5 ,
} ,
2026-06-09 13:39:44 +00:00
} ,
Controle = new AtuadorBombaModel . BombaModoControleModel ( )
{
Modo = ModoControleBomba . PID ,
PotenciaMinPID = 40 ,
2026-06-26 20:00:49 +00:00
Kp = 1.10 ,
Ki = 0.12 ,
2026-06-09 13:39:44 +00:00
Kd = 0.0 ,
2025-12-16 17:17:26 +00:00
}
} ,
2026-03-21 01:48:37 +00:00
new AtuadorBombaModel ( )
2025-12-16 17:17:26 +00:00
{
2026-03-21 01:48:37 +00:00
ID = "BMBAGT" ,
ID_Num = 52 ,
Sensor_ID_Num = - 1 ,
ComandoAtuar = false ,
Componente = S_Code . sBMB ,
2026-04-02 17:38:24 +00:00
PotenciaSP = 100 ,
2026-03-21 01:48:37 +00:00
Comandar = true ,
Mandatorio = true ,
2025-12-16 17:17:26 +00:00
Funcoes = new List < FuncoesPinout > ( )
{
2026-04-01 17:03:04 +00:00
FuncoesPinout . IN1 ,
FuncoesPinout . IN2 ,
2025-12-16 17:17:26 +00:00
} ,
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
indice = 0 ,
} ,
2026-06-25 18:17:42 +00:00
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . MalhaFechada ,
posicao = CanMessagePosicaoDados . Status ,
indice = 1 ,
} ,
2025-12-16 17:17:26 +00:00
new SensorValoresLeituraModel ( )
{
2026-03-21 01:48:37 +00:00
funcao = FuncoesPinout . EstadoLeitura ,
2025-12-16 17:17:26 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 0 ,
} ,
2026-03-21 01:48:37 +00:00
new SensorValoresLeituraModel ( )
{
2026-04-02 17:38:24 +00:00
funcao = FuncoesPinout . PotenciaSP ,
2026-03-21 01:48:37 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 1 ,
} ,
new SensorValoresLeituraModel ( )
{
2026-04-02 17:38:24 +00:00
funcao = FuncoesPinout . Potencia ,
2026-03-21 01:48:37 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 2 ,
} ,
new SensorValoresLeituraModel ( )
{
2026-04-02 17:38:24 +00:00
funcao = FuncoesPinout . PressaoSP ,
2026-03-21 01:48:37 +00:00
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 3 ,
2026-04-02 17:38:24 +00:00
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Pressao ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 4 ,
2026-06-09 13:39:44 +00:00
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . ModoControleBomba ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 5 ,
2026-03-21 01:48:37 +00:00
}
2026-06-09 13:39:44 +00:00
} ,
Controle = new AtuadorBombaModel . BombaModoControleModel ( )
{
Modo = ModoControleBomba . OnOff ,
2025-12-16 17:17:26 +00:00
}
2026-03-21 01:48:37 +00:00
} ,
2025-12-16 17:17:26 +00:00
} ,
2026-04-02 17:38:24 +00:00
// 61 ~ 70
2026-03-21 01:48:37 +00:00
BicosPulverizadores = new List < AtuadorBicoModel > ( ) ,
2026-04-02 17:38:24 +00:00
2024-01-03 10:52:37 +00:00
} ;
2026-06-30 18:59:15 +00:00
for ( int i = 0 ; i < VariaveisEquipamento . QuantidadeBicosPulverizadores ; i + + )
2024-01-03 10:52:37 +00:00
{
2025-04-09 21:11:40 +00:00
int posicao = ( i + 1 ) ;
2024-01-03 10:52:37 +00:00
Atuador . BicosPulverizadores . Add ( new AtuadorBicoModel ( )
{
2025-04-09 21:11:40 +00:00
ID = "B" + posicao . ToString ( "00" ) ,
2026-03-21 01:48:37 +00:00
ID_Num = 60 + posicao ,
2024-11-29 20:28:25 +00:00
Componente = S_Code . sBIC ,
2025-04-09 21:11:40 +00:00
Posicao = posicao ,
2025-12-02 18:42:15 +00:00
Inicializado = false ,
2026-04-01 11:26:37 +00:00
AnguloNeutro = 90 ,
AnguloControle = 90 ,
2026-02-26 19:57:22 +00:00
AnguloAbertura = 30 ,
2025-04-09 21:11:40 +00:00
Comandar = true ,
2025-05-07 16:54:45 +00:00
Mandatorio = true ,
2024-12-02 19:12:39 +00:00
ComandoAtuar = false ,
2025-04-09 21:11:40 +00:00
AtuacaoNivelAlto = true ,
2024-01-03 10:52:37 +00:00
Funcoes = new List < FuncoesPinout > ( )
{
FuncoesPinout . Solenoide ,
2026-03-21 01:48:37 +00:00
FuncoesPinout . Servo ,
2024-01-03 10:52:37 +00:00
} ,
2025-12-18 20:14:27 +00:00
VazaoMediaMLs = 0 ,
2025-05-30 20:11:31 +00:00
ValoresLeituras = new List < SensorValoresLeituraModel > ( )
{
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . Iniciado ,
posicao = CanMessagePosicaoDados . Status ,
indice = 0 ,
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . EstadoLeitura ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 0 ,
2025-12-16 17:17:26 +00:00
} ,
new SensorValoresLeituraModel ( )
{
funcao = FuncoesPinout . ServoAnguloLeitura ,
posicao = CanMessagePosicaoDados . Dados1 ,
indice = 1 ,
2025-05-30 20:11:31 +00:00
}
}
2024-01-03 10:52:37 +00:00
} ) ;
}
return Atuador ;
}
2024-12-02 19:12:39 +00:00
public void LimparDados < T > ( T _dados )
2024-07-18 18:00:14 +00:00
{
2024-12-02 19:12:39 +00:00
var Dados = _dados as AtuadorModel ;
2024-11-29 20:28:25 +00:00
Dados . DadosLeitura = new AtuadorMensagemJsonModel ( ) ;
Dados . DadosLeitura . Momento = DateTime . MinValue ;
2025-07-11 16:38:08 +00:00
Dados . AtuPronto = false ;
2025-02-06 19:01:41 +00:00
Dados . PercentualErvasTerreno = 0 ;
2024-12-02 19:12:39 +00:00
Dados . BombasPressurizadoras . ForEach ( x = > x . Funcoes = x . Funcoes . Distinct ( ) . ToList ( ) ) ;
2026-04-02 17:38:24 +00:00
2024-10-29 19:53:27 +00:00
ReiniciarLeituras ( Dados ) ;
2026-06-22 16:46:34 +00:00
PrepararAtuadorParaOperacao ( Dados , resetarComandos : true ) ;
2024-10-29 19:53:27 +00:00
}
2024-12-02 19:12:39 +00:00
public void ReiniciarLeituras ( AtuadorModel Dados )
2024-10-29 19:53:27 +00:00
{
2024-11-29 20:28:25 +00:00
Dados . Sensores . ForEach ( x = >
{
2025-06-06 20:46:08 +00:00
x . ValoresLeituras . ForEach ( l = >
{
l . atual = new CanCommandFreqModel < dynamic > ( ) ;
} ) ;
2024-11-29 20:28:25 +00:00
} ) ;
2024-10-29 19:53:27 +00:00
Dados . BicosPulverizadores . ForEach ( x = >
{
2024-12-02 19:12:39 +00:00
x . ComandoAtuar = false ;
2026-03-21 01:48:37 +00:00
x . AnguloControle = 0 ;
2026-06-22 16:46:34 +00:00
x . Atuacoes = 0 ;
2025-12-19 12:01:58 +00:00
x . VazaoInstantaneaMLs = 0 ;
x . VolumeVazadoML = 0 ;
x . VazaoMediaMLs = 0 ;
x . TempoAtuado = 0 ;
2026-06-19 12:15:05 +00:00
x . TempoAtuadoEmMovimento = 0 ;
x . TempoComFluxo = 0 ;
2026-06-22 16:46:34 +00:00
2026-06-19 12:15:05 +00:00
x . ReiniciarHistoricoAtuacao ( true ) ;
2026-06-22 16:46:34 +00:00
2025-06-06 20:46:08 +00:00
x . ValoresLeituras . ForEach ( l = >
{
l . atual = new CanCommandFreqModel < dynamic > ( ) ;
} ) ;
2024-07-18 18:00:14 +00:00
} ) ;
2024-10-29 19:53:27 +00:00
2024-11-29 20:28:25 +00:00
Dados . BombasPressurizadoras . ForEach ( x = >
2024-07-18 18:00:14 +00:00
{
2024-12-02 19:12:39 +00:00
x . ComandoAtuar = false ;
2026-04-02 17:38:24 +00:00
x . PotenciaSP = 0 ;
x . PressaoSP = 0 ;
2026-06-19 12:15:05 +00:00
x . Atuacoes = 0 ;
x . TempoAtuado = 0 ;
x . TempoComPotencia = 0 ;
x . PotenciaAcumuladaPctSeg = 0 ;
x . PotenciaMediaAtiva = 0 ;
2025-06-06 20:46:08 +00:00
x . ValoresLeituras . ForEach ( l = >
{
l . atual = new CanCommandFreqModel < dynamic > ( ) ;
} ) ;
2024-07-18 18:00:14 +00:00
} ) ;
2024-10-29 19:53:27 +00:00
2025-12-19 12:01:58 +00:00
Dados . VolumeVazadoML = 0 ;
Dados . VazaoMediaMLs = 0 ;
2024-10-10 19:58:57 +00:00
Dados . TempoAtuado = 0 ;
2025-12-19 12:01:58 +00:00
Dados . AnguloBarraDireita = 0 ;
Dados . AnguloBarraEsquerda = 0 ;
Dados . PercentualErvasTerreno = 0 ;
2026-06-19 12:15:05 +00:00
lock ( Dados . _metricasLock )
{
Dados . _ultimoTickMetricas = 0 ;
Dados . _tempoMovimentoAnteriorSeg = 0 ;
Dados . _bicosAtivosIntervaloAnterior . Clear ( ) ;
Dados . _bombasAtivasIntervaloAnterior . Clear ( ) ;
Dados . _potenciaBombasIntervaloAnterior . Clear ( ) ;
Dados . _vazaoIntervaloAnteriorMLs = 0 ;
}
2024-07-18 18:00:14 +00:00
}
2026-06-22 16:46:34 +00:00
public void PrepararAtuadorParaOperacao ( )
{
PrepararAtuadorParaOperacao ( this , resetarComandos : false ) ;
}
private void PrepararAtuadorParaOperacao ( AtuadorModel Dados , bool resetarComandos )
2026-06-19 15:33:46 +00:00
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2026-06-19 15:33:46 +00:00
var dadosAtuador = Dados ;
2026-06-30 18:59:15 +00:00
var controle = op ? . Parametros ? . Controle ;
2026-06-19 15:33:46 +00:00
2026-06-30 18:59:15 +00:00
if ( op = = null | | dadosAtuador = = null | | controle = = null )
2026-06-19 15:33:46 +00:00
return ;
var bomba = dadosAtuador . BombaPressurizadora ;
if ( bomba ! = null )
{
2026-06-22 16:46:34 +00:00
if ( resetarComandos )
bomba . ComandoAtuar = false ;
/ *
* Estes setpoints precisam existir antes do primeiro comando
* físico da bomba em operação automática .
* /
2026-06-19 15:33:46 +00:00
bomba . PotenciaSP = 100 ;
bomba . PressaoSP = controle . AtuPressaoLinha ;
bomba . Controle . Modo = controle . AtuModoControle ;
}
var agitador = dadosAtuador . AgitadorDeCalda ;
if ( agitador ! = null )
{
2026-06-22 16:46:34 +00:00
if ( resetarComandos )
agitador . ComandoAtuar = false ;
/ *
* O agitador tem a própria fonte de verdade em
* HerbicideCounterService . AtualizarAgitadorCalda ( ) .
* /
2026-06-19 15:33:46 +00:00
agitador . PotenciaSP = 0 ;
agitador . PressaoSP = - 1 ;
}
}
2026-06-22 16:46:34 +00:00
public void SincronizarBombaPressurizadoraAutomatica ( bool forcar = false )
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2026-06-22 16:46:34 +00:00
2026-06-26 20:00:49 +00:00
var controle = op ? . Parametros ? . Controle ;
2026-06-22 16:46:34 +00:00
var bomba = BombaPressurizadora ;
2026-06-26 20:00:49 +00:00
if ( op = = null | | controle = = null | | bomba = = null | | ! bomba . Inicializado )
2026-06-22 16:46:34 +00:00
return ;
bool pulverizadorAutomatico = controle . PulverizadorAutomatico ;
if ( ! pulverizadorAutomatico )
return ;
2026-06-26 20:00:49 +00:00
bool operacaoConcluida = op . Sensoriamento ? . Operacao ? . StatusOperacaoAtual = = StatusOperacao . Concluido ;
2026-06-22 16:46:34 +00:00
bool atuacaoPermitida =
2026-06-26 20:00:49 +00:00
op . Sensoriamento . Operacao . OperacaoIniciada & &
! op . Sensoriamento . Operacao . Finalizando & &
! op . Sensoriamento . Operacao . Emergencia & &
2026-06-22 16:46:34 +00:00
! operacaoConcluida & &
2026-06-26 20:00:49 +00:00
! op . Sensoriamento . Operacao . Pausa ;
2026-06-22 16:46:34 +00:00
/ *
* Reaplica setpoints sempre antes de sincronizar .
* Assim , se ReiniciarLeituras ( ) zerou a bomba no início da operação ,
* ela não fica presa em potência / pressão zero .
* /
PrepararAtuadorParaOperacao ( ) ;
bool statusDesejado =
bomba . Comandar & &
atuacaoPermitida & &
ContadorCarga . PulverizadorLiberado ;
/ *
* ComandoAtuar passa a representar também o comando lógico automático .
* Isso deixa o log BombaLigada coerente com o que o software deseja .
* /
bomba . ComandoAtuar = statusDesejado ;
2026-06-26 20:00:49 +00:00
double potenciaEfetiva = statusDesejado ? bomba . PotenciaSP : 0 ;
2026-06-22 16:46:34 +00:00
2026-06-26 20:00:49 +00:00
double pressaoEfetiva = bomba . Sensor_ID_Num > - 1 ? ( statusDesejado ? bomba . PressaoSP : 0 ) : bomba . PressaoSP ;
Estado estadoDesejado = statusDesejado ? Estado . Ligado : Estado . Desligado ;
bool estadoDivergente = estadoDesejado ! = bomba . _EstadoLeitura ;
2026-06-22 16:46:34 +00:00
2026-06-26 20:00:49 +00:00
bool potenciaDivergente = Math . Abs ( bomba . _PotenciaSP - potenciaEfetiva ) > 1.0 ;
bool pressaoDivergente = bomba . Sensor_ID_Num > - 1 & & Math . Abs ( bomba . _PressaoSP - pressaoEfetiva ) > 0.05 ;
if ( forcar | | estadoDivergente | | potenciaDivergente | | pressaoDivergente )
2026-06-22 16:46:34 +00:00
{
EnviarComandoFisicoBomba (
bomba ,
statusDesejado ,
potenciaEfetiva ,
pressaoEfetiva
) ;
}
}
2025-05-06 18:47:59 +00:00
public async Task < bool > VerificaDispositivoConectado ( )
2024-01-03 10:52:37 +00:00
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2025-07-17 17:53:42 +00:00
if ( ! CanManager . CanService . IsConnected ) return false ;
2024-06-08 01:20:23 +00:00
2026-06-30 18:59:15 +00:00
if ( op ? . DispAtu = = null ) return false ;
2024-11-29 20:28:25 +00:00
2025-07-17 17:53:42 +00:00
CanManager . CanService . RegistrarHandler ( _EnderecoCAN_Rx , _AtuHandler ) ;
2024-06-08 01:20:23 +00:00
2026-06-11 22:40:44 +00:00
RequisitarDadosDescoberta ( ) ;
2025-05-06 18:47:59 +00:00
DateTime Inicio = DateTime . Now ;
2026-06-26 20:00:49 +00:00
bool Respondido ( ) = > op . DispAtu . Dados . DadosLeitura . UltimoComandoRespondido > Inicio ;
2025-05-06 18:47:59 +00:00
await FuncoesGlobais . AguardarCondicaoAsync ( Respondido , 500 , 50 ) ;
2024-06-08 01:20:23 +00:00
2025-07-23 15:14:50 +00:00
if ( Conectado )
2024-12-02 19:12:39 +00:00
{
2025-05-06 18:47:59 +00:00
DefinirDispositivo ( ) ;
2026-06-26 20:00:49 +00:00
op . DispAtu ? . EnviarProtocolosConfiguracao ( ) ;
2024-12-02 19:12:39 +00:00
}
2024-11-29 20:28:25 +00:00
2025-07-23 15:14:50 +00:00
return Conectado ;
2024-11-29 20:28:25 +00:00
}
2025-04-09 21:11:40 +00:00
private void DefinirDispositivo ( )
2024-11-29 20:28:25 +00:00
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2025-04-09 21:11:40 +00:00
if ( ! SerialService . DispositivosMapeados . Any ( x = > x . Dispositivo = = Dispositivo & & x . Mod_ID = = Modulo_ID ) )
{
SerialService . DispositivosMapeados . Add ( new DispositivoDetalhesModel ( )
{
Dispositivo = DadosLeitura . Dispositivo ,
2025-07-17 17:53:42 +00:00
Endereco = CanManager . CanService . _portName ,
2025-04-09 21:11:40 +00:00
Versao = DadosLeitura . Versao . ToString ( ) ,
2025-05-06 18:47:59 +00:00
Mod_ID = Modulo_ID
2025-04-09 21:11:40 +00:00
} ) ;
2025-10-21 19:23:36 +00:00
2026-06-26 20:00:49 +00:00
op . Sensoriamento . Operacao . ModsCalibragem [ Dispositivo ] = new Dictionary < string , bool > ( ) ;
op . Sensoriamento . InserirLog ( Dispositivo , StatusModulo . Conectado , 0 , "Dispositivo conectado" ) ;
2025-04-09 21:11:40 +00:00
}
2024-11-29 20:28:25 +00:00
}
2024-06-28 20:14:24 +00:00
2026-06-11 22:40:44 +00:00
private void RequisitarDadosDescoberta ( )
{
Variaveis . OperacaoEmAndamento . DispAtu ? . AdicionarMensagemFila ( Variaveis . ID_Num_sMOD , CanMessagePosicaoDados . Status , CanMessagePosicaoDados . Status , null , true , false , true ) ;
}
2025-05-01 18:27:01 +00:00
public void RequisitarDadosModulo ( int ID_Num , CanMessagePosicaoDados posicaoTx , CanMessagePosicaoDados posicaoRx , bool aguardaResposta )
2024-11-29 20:28:25 +00:00
{
2025-05-01 18:27:01 +00:00
Variaveis . OperacaoEmAndamento . DispAtu ? . AdicionarMensagemFila ( ID_Num , posicaoTx , posicaoRx , null , aguardaResposta ) ;
2024-11-29 20:28:25 +00:00
}
2024-06-08 01:20:23 +00:00
2025-12-18 18:11:30 +00:00
public ( int , CanMessagePosicaoDados , byte [ ] ) ProtocoloComandoReset ( )
{
return (
Variaveis . ID_Num_sMOD ,
CanMessagePosicaoDados . Command1 ,
new byte [ ]
{
( byte ) Estado . Reset
}
) ;
}
2025-05-01 18:27:01 +00:00
public List < ( int , CanMessagePosicaoDados , byte [ ] ) > ProtocoloConfiguracao ( bool Conectar )
2024-11-29 20:28:25 +00:00
{
2025-04-09 21:11:40 +00:00
// Inicializar o dicionário
2025-05-01 18:27:01 +00:00
List < ( int , CanMessagePosicaoDados , byte [ ] ) > config = new List < ( int , CanMessagePosicaoDados , byte [ ] ) > ( ) ;
2025-04-09 21:11:40 +00:00
2025-04-10 20:59:50 +00:00
if ( ! DadosLeitura . Conectado )
2025-04-09 21:11:40 +00:00
{
// Adicionar configuração do ProtocoloMOD
var protocoloMOD = ModConfig ( Conectar ) ;
2025-04-14 12:52:19 +00:00
config . AddRange ( protocoloMOD ) ;
2025-04-09 21:11:40 +00:00
}
2025-04-24 21:11:33 +00:00
bool configurarTodos = ! DadosLeitura . Conectado & & Conectar ;
2025-04-10 20:59:50 +00:00
// Adicionar configurações dos Sensores que devem ser aferidos
2026-04-08 18:35:31 +00:00
//var sensoresConfig = SensoresConfig(Conectar, configurarTodos);
//config.AddRange(sensoresConfig);
2025-04-10 20:59:50 +00:00
2025-04-09 21:11:40 +00:00
// Adicionar configurações dos Bicos
2026-04-08 18:35:31 +00:00
//var bicosConfig = BicosConfig(Conectar, configurarTodos);
//config.AddRange(bicosConfig);
2025-04-09 21:11:40 +00:00
// Adicionar configurações das Bombas
2026-04-08 18:35:31 +00:00
//var bombasConfig = BombasConfig(Conectar, configurarTodos);
//config.AddRange(bombasConfig);
2025-04-09 21:11:40 +00:00
return config ;
2024-01-03 10:52:37 +00:00
}
2024-11-29 20:28:25 +00:00
2025-05-01 18:27:01 +00:00
private List < ( int , CanMessagePosicaoDados , byte [ ] ) > ModConfig ( bool Conectar )
2024-11-29 20:28:25 +00:00
{
2025-07-23 15:14:50 +00:00
var config = new List < byte >
2025-04-09 21:11:40 +00:00
{
( byte ) ( Conectar ? 1 : 0 ) ,
2026-04-08 20:10:57 +00:00
( byte ) ( _TaxaAmostragem / 1000 ) ,
2025-04-09 21:11:40 +00:00
( byte ) ( RequisitarDados ? 1 : 0 ) ,
} ;
2025-07-23 15:14:50 +00:00
config . AddRange ( PinoutModel . PinoProtocolo ( Pinout , Funcoes , false ) ) ;
2025-04-14 12:52:19 +00:00
2025-05-01 18:27:01 +00:00
return new List < ( int , CanMessagePosicaoDados , byte [ ] ) >
2025-04-14 12:52:19 +00:00
{
2025-07-23 15:14:50 +00:00
( Variaveis . ID_Num_sMOD , CanMessagePosicaoDados . Config1 , config . ToArray ( ) ) ,
2025-04-14 12:52:19 +00:00
} ;
2024-11-29 20:28:25 +00:00
}
2025-05-01 18:27:01 +00:00
private List < ( int , CanMessagePosicaoDados , byte [ ] ) > SensoresConfig ( bool Conectar , bool ConfigurarTodos )
2024-06-28 20:14:24 +00:00
{
2025-05-01 18:27:01 +00:00
var config = new List < ( int , CanMessagePosicaoDados , byte [ ] ) > ( ) ;
2024-06-28 20:14:24 +00:00
2025-04-24 21:11:33 +00:00
foreach ( var sensor in Sensores . Where ( x = > ( x . Aferir & & ( ConfigurarTodos ? true : x . Inicializado ! = Conectar ) ) | | ( ! x . Aferir & & x . Inicializado ) ) )
2024-06-28 20:14:24 +00:00
{
2025-04-24 21:11:33 +00:00
if ( ! sensor . Aferir & & sensor . Inicializado )
{
Conectar = false ;
}
2025-05-01 18:27:01 +00:00
( CanMessagePosicaoDados posicao , byte [ ] payload ) = sensor . ProtocoloConfiguracao ( Pinout , Conectar , Dispositivo ) ;
2025-04-09 21:11:40 +00:00
if ( payload ! = null )
{
2025-05-01 18:27:01 +00:00
config . Add ( ( sensor . ID_Num , posicao , payload ) ) ;
2025-04-09 21:11:40 +00:00
}
}
return config ;
}
2024-06-28 20:14:24 +00:00
2025-05-01 18:27:01 +00:00
private List < ( int , CanMessagePosicaoDados , byte [ ] ) > BicosConfig ( bool Conectar , bool ConfigurarTodos )
2025-04-09 21:11:40 +00:00
{
2025-05-01 18:27:01 +00:00
var config = new List < ( int , CanMessagePosicaoDados , byte [ ] ) > ( ) ;
2025-04-09 21:11:40 +00:00
2025-04-24 21:11:33 +00:00
foreach ( var bico in BicosPulverizadores . Where ( x = > ( x . Comandar & & ( ConfigurarTodos ? true : x . Inicializado ! = Conectar ) ) | | ( ! x . Comandar & & x . Inicializado ) ) )
2025-04-09 21:11:40 +00:00
{
2025-04-24 21:11:33 +00:00
if ( ! bico . Comandar & & bico . Inicializado )
{
Conectar = false ;
}
2025-05-01 18:27:01 +00:00
( CanMessagePosicaoDados posicao , var payload ) = bico . ProtocoloConfiguracao ( Pinout , Conectar ) ;
2025-04-09 21:11:40 +00:00
if ( payload ! = null )
{
2025-05-01 18:27:01 +00:00
config . Add ( ( bico . ID_Num , posicao , payload ) ) ;
2025-04-09 21:11:40 +00:00
}
2024-06-28 20:14:24 +00:00
}
2025-04-09 21:11:40 +00:00
return config ;
2024-06-28 20:14:24 +00:00
}
2024-01-03 10:52:37 +00:00
2025-05-01 18:27:01 +00:00
private List < ( int , CanMessagePosicaoDados , byte [ ] ) > BombasConfig ( bool Conectar , bool ConfigurarTodos )
2024-01-03 10:52:37 +00:00
{
2025-05-01 18:27:01 +00:00
var config = new List < ( int , CanMessagePosicaoDados , byte [ ] ) > ( ) ;
2025-04-09 21:11:40 +00:00
2025-04-24 21:11:33 +00:00
foreach ( var bomba in BombasPressurizadoras . Where ( x = > ( x . Comandar & & ( ConfigurarTodos ? true : x . Inicializado ! = Conectar ) ) | | ( ! x . Comandar & & x . Inicializado ) ) )
2025-04-09 21:11:40 +00:00
{
2025-04-24 21:11:33 +00:00
if ( ! bomba . Comandar & & bomba . Inicializado )
{
Conectar = false ;
}
2025-05-01 18:27:01 +00:00
List < ( CanMessagePosicaoDados , byte [ ] ) > dados = bomba . ProtocoloConfiguracao ( Pinout , Conectar ) ;
foreach ( var dado in dados )
2025-04-09 21:11:40 +00:00
{
2025-05-01 18:27:01 +00:00
config . Add ( ( bomba . ID_Num , dado . Item1 , dado . Item2 ) ) ;
2025-04-09 21:11:40 +00:00
}
}
return config ;
2024-11-29 20:28:25 +00:00
}
2024-11-27 17:38:56 +00:00
2025-12-16 17:17:26 +00:00
2024-01-03 10:52:37 +00:00
public void IniciarRegistrador ( )
{
2024-11-29 20:28:25 +00:00
if ( ! ( tmrRegistrador ? . IsRunning ? ? false ) )
2024-11-27 17:38:56 +00:00
{
LimparDados ( this ) ;
PararRegistrador ( ) ;
tmrRegistrador = new AsyncTaskTimerModel ( "tmrRegistrador_" + T_Code . Atu . ToString ( ) , tmrRegistrador_Tick , _TaxaAmostragem ) ;
tmrRegistrador . Start ( ) ;
}
}
2024-01-03 10:52:37 +00:00
2024-11-27 17:38:56 +00:00
public void PararRegistrador ( )
{
tmrRegistrador ? . Dispose ( ) ;
2024-01-03 10:52:37 +00:00
}
2024-11-27 17:38:56 +00:00
public async Task tmrRegistrador_Tick ( )
2024-06-14 09:37:22 +00:00
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2025-12-18 18:11:30 +00:00
if ( Variaveis . Fechando ) return ;
2025-03-27 11:47:00 +00:00
2024-11-27 17:38:56 +00:00
tmrRegistrador . SetInterval ( _TaxaAmostragem ) ;
2026-06-26 20:00:49 +00:00
if ( SerialService . DispositivosMapeados . Any ( x = > x . Dispositivo = = Dispositivo ) & & ( _VezesLeituraReconexao > = _TempoReconexaoComponentes ) )
2026-06-23 10:46:11 +00:00
{
2026-06-26 20:00:49 +00:00
op . DispAtu ? . EnviarProtocolosConfiguracao ( ) ;
2026-06-23 10:46:11 +00:00
_VezesLeituraReconexao = 0 ;
}
else
{
_VezesLeituraReconexao + + ;
}
2024-11-29 20:28:25 +00:00
2025-04-10 20:59:50 +00:00
if ( DadosLeitura . Conectado )
2024-11-29 20:28:25 +00:00
{
2024-12-03 20:55:25 +00:00
if ( RequisitarDados )
{
2025-05-01 18:27:01 +00:00
RequisitarDadosModulo ( Variaveis . ID_Num_sTOD , CanMessagePosicaoDados . DadosAll , CanMessagePosicaoDados . DadosAll , true ) ;
2024-12-03 20:55:25 +00:00
}
2025-09-16 13:31:32 +00:00
VerificaControleLeitura ( ) ;
2024-11-29 20:28:25 +00:00
}
2025-04-16 16:44:06 +00:00
AtualizaComponentesIniciados ( ) ;
}
2024-11-29 20:28:25 +00:00
2025-09-16 13:31:32 +00:00
private void VerificaControleLeitura ( )
{
2026-06-19 12:15:05 +00:00
if ( Variaveis . Fechando )
return ;
2025-12-18 18:11:30 +00:00
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
if ( op ? . DispAtu ? . Dados ? . Conectado ! = true )
2026-06-19 12:15:05 +00:00
return ;
2026-04-01 11:26:37 +00:00
2026-06-26 20:00:49 +00:00
bool operacaoConcluida = op . Sensoriamento ? . Operacao ? . StatusOperacaoAtual = = StatusOperacao . Concluido ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
bool pulverizadorAutomatico = op . Parametros ? . Controle ? . PulverizadorAutomatico ? ? false ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
bool calibrando = op . Sensoriamento ? . Operacao ? . Calibrando = = true ;
2026-06-19 12:15:05 +00:00
/ *
* Bloqueios absolutos .
*
* Nem mesmo a calibração deve conseguir atuar
* durante emergência , finalização ou após a
* operação ter sido encerrada .
* /
bool bloqueioGeral =
2026-06-26 20:00:49 +00:00
! op . Sensoriamento . Operacao . OperacaoIniciada | |
op . Sensoriamento . Operacao . Finalizando | |
op . Sensoriamento . Operacao . Emergencia | |
2026-06-19 12:15:05 +00:00
operacaoConcluida ;
/ *
* Durante a calibração , Pausa = true é intencional .
* Portanto , a pausa somente bloqueia atuação fora
* da calibração .
* /
2026-06-26 20:00:49 +00:00
bool atuacaoPermitida = ! bloqueioGeral & & ( ! op . Sensoriamento . Operacao . Pausa | | calibrando ) ;
2026-06-19 12:15:05 +00:00
/ *
* BICOS
*
* ComandoAtuar continua representando a intenção
* gerada pelo Weed Worker , operador ou calibração .
*
* Este método apenas calcula o comando físico .
* /
2026-06-26 20:00:49 +00:00
foreach ( var bico in BicosPulverizadores . Where ( x = > x ! = null & & x . Inicializado ) )
{
bool comandoSolicitado = bico . Comandar & & bico . ComandoAtuar ;
bool statusDesejado = comandoSolicitado & & atuacaoPermitida ;
2026-06-19 12:15:05 +00:00
/ *
* Fora da calibração , a pulverização automática
* somente pode abrir bicos com reservatório liberado .
*
* Durante a calibração , permite o pulso de teste
* explicitamente solicitado pelo método de calibração .
* /
2026-06-26 20:00:49 +00:00
if ( pulverizadorAutomatico & & ! calibrando )
2026-06-19 12:15:05 +00:00
{
2026-06-26 20:00:49 +00:00
statusDesejado & = ContadorCarga . PulverizadorLiberado ;
2026-06-19 12:15:05 +00:00
}
2026-04-01 11:26:37 +00:00
2026-06-26 20:00:49 +00:00
Estado estadoDesejado = statusDesejado ? Estado . Ligado : Estado . Desligado ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
double anguloDesejado = statusDesejado ? bico . AnguloControle : bico . AnguloNeutro ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
bool estadoDivergente = estadoDesejado ! = bico . _EstadoLeitura ;
2026-06-19 12:15:05 +00:00
/ *
* Verifica o â ngulo também quando desligado ,
* para garantir o retorno à posição neutra .
* /
2026-06-26 20:00:49 +00:00
bool anguloDivergente = Math . Abs ( anguloDesejado - bico . _AnguloBicoLeitura ) > 1.0 ;
if ( estadoDivergente | | anguloDivergente )
2025-09-16 13:31:32 +00:00
{
2026-06-19 12:15:05 +00:00
EnviarComandoFisicoBico (
bico ,
statusDesejado ,
anguloDesejado
2026-04-01 11:26:37 +00:00
) ;
2025-09-16 13:31:32 +00:00
}
2025-12-17 19:27:06 +00:00
}
2025-09-16 13:31:32 +00:00
2026-06-19 12:15:05 +00:00
/ *
* BOMBAS
* /
2026-06-26 20:00:49 +00:00
foreach ( var bomba in BombasPressurizadoras . Where ( x = > x ! = null & & x . Inicializado ) )
{
bool ehBombaPrincipal = bomba . ID = = BombaPressurizadora ? . ID ;
bool comandoSolicitado = bomba . Comandar & & bomba . ComandoAtuar ;
2026-06-19 12:15:05 +00:00
bool statusDesejado ;
/ *
* Durante a calibração , respeita exatamente
* o comando colocado por RealizarTestesIniciais ( ) .
*
* Isso vale tanto para a bomba quanto para o
* agitador .
* /
if ( calibrando )
{
2026-06-26 20:00:49 +00:00
statusDesejado = comandoSolicitado & & atuacaoPermitida ;
2026-06-19 12:15:05 +00:00
}
/ *
* Fora da calibração , a bomba principal automática
* deve permanecer ligada enquanto a operação estiver
* autorizada e houver produto suficiente .
*
* Ela não depende de um ComandoAtuar antigo .
* /
2026-06-22 16:46:34 +00:00
else if ( ehBombaPrincipal & & pulverizadorAutomatico )
2026-06-19 12:15:05 +00:00
{
2026-06-26 20:00:49 +00:00
statusDesejado = bomba . Comandar & & atuacaoPermitida & & ContadorCarga . PulverizadorLiberado ;
2026-06-22 16:46:34 +00:00
/ *
* Mantém o modelo coerente com o comando automático .
* Sem isso , o log BombaLigada pode ficar false mesmo quando
* o controle automático deseja a bomba ligada .
* /
bomba . ComandoAtuar = statusDesejado ;
2026-06-19 12:15:05 +00:00
}
/ *
* Agitador e comandos manuais .
*
* Para o agitador , AtualizarAgitadorCalda ( )
* já definiu ComandoAtuar e PotenciaSP .
* /
else
{
2026-06-26 20:00:49 +00:00
statusDesejado = comandoSolicitado & & atuacaoPermitida ;
2026-06-19 12:15:05 +00:00
}
2025-10-24 11:45:47 +00:00
2026-06-26 20:00:49 +00:00
Estado estadoDesejado = statusDesejado ? Estado . Ligado : Estado . Desligado ;
2026-06-19 12:15:05 +00:00
/ *
* Valores efetivamente enviados ao hardware .
*
* Os setpoints armazenados no modelo não são
* alterados quando existir um bloqueio temporário .
* /
2026-06-26 20:00:49 +00:00
double potenciaEfetiva = statusDesejado ? bomba . PotenciaSP : 0 ;
2026-06-19 12:15:05 +00:00
double pressaoEfetiva ;
if ( bomba . Sensor_ID_Num > - 1 )
{
2026-06-26 20:00:49 +00:00
pressaoEfetiva = statusDesejado ? bomba . PressaoSP : 0 ;
2026-06-19 12:15:05 +00:00
}
else
{
/ *
* Mantém - 1 como marcador de bomba sem
* sensor de pressão , como o agitador .
* /
2026-06-26 20:00:49 +00:00
pressaoEfetiva = bomba . PressaoSP ;
2026-06-19 12:15:05 +00:00
}
2026-04-01 11:26:37 +00:00
2026-06-26 20:00:49 +00:00
bool estadoDivergente = estadoDesejado ! = bomba . _EstadoLeitura ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
bool potenciaDivergente = Math . Abs ( bomba . _PotenciaSP - potenciaEfetiva ) > 1.0 ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
bool pressaoDivergente = bomba . Sensor_ID_Num > - 1 & & Math . Abs ( bomba . _PressaoSP - pressaoEfetiva ) > 0.05 ;
2026-06-19 12:15:05 +00:00
2026-06-26 20:00:49 +00:00
if ( estadoDivergente | | potenciaDivergente | | pressaoDivergente )
2026-04-01 11:26:37 +00:00
{
2026-06-19 12:15:05 +00:00
EnviarComandoFisicoBomba (
bomba ,
statusDesejado ,
potenciaEfetiva ,
pressaoEfetiva
2026-04-01 11:26:37 +00:00
) ;
2025-09-16 13:31:32 +00:00
}
2025-12-17 19:27:06 +00:00
}
2025-09-16 13:31:32 +00:00
}
2026-06-19 15:33:46 +00:00
private void EnviarComandoFisicoBico ( AtuadorBicoModel bico , bool status , double angulo )
2026-06-19 12:15:05 +00:00
{
2026-06-19 15:33:46 +00:00
var dispAtu = Variaveis . OperacaoEmAndamento ? . DispAtu ;
2026-06-19 12:15:05 +00:00
2026-06-19 15:33:46 +00:00
if ( dispAtu ? . Dados ? . Conectado ! = true | | bico = = null )
2026-06-19 12:15:05 +00:00
return ;
2026-06-19 15:33:46 +00:00
byte anguloByte = ( byte ) Math . Round ( FuncoesMatematicas . Clamp ( angulo , 0 , 255 ) ) ;
2026-06-19 12:15:05 +00:00
byte [ ] data =
{
2026-06-19 15:33:46 +00:00
( byte ) ( status ? Estado . Ligado : Estado . Desligado ) ,
anguloByte
} ;
dispAtu . AdicionarMensagemFila ( bico . ID_Num , CanMessagePosicaoDados . Command1 , CanMessagePosicaoDados . Command1 , data , false ) ;
2026-06-24 16:32:47 +00:00
bico . UltimoComandoEnviado = DateTime . Now ;
bico . UltimoStatusDesejado = status ;
bico . UltimoAnguloDesejado = angulo ;
2026-06-19 12:15:05 +00:00
}
2026-06-19 15:33:46 +00:00
private void EnviarComandoFisicoBomba ( AtuadorBombaModel bomba , bool status , double potencia , double pressao )
2026-06-19 12:15:05 +00:00
{
2026-06-19 15:33:46 +00:00
var dispAtu = Variaveis . OperacaoEmAndamento ? . DispAtu ;
2026-06-19 12:15:05 +00:00
2026-06-19 15:33:46 +00:00
if ( dispAtu ? . Dados ? . Conectado ! = true | | bomba = = null )
2026-06-19 12:15:05 +00:00
return ;
2026-06-19 15:33:46 +00:00
byte potenciaByte = ( byte ) Math . Round ( FuncoesMatematicas . Clamp ( potencia , 0 , 100 ) ) ;
2026-06-19 12:15:05 +00:00
/ *
* - 1 é usado para indicar ausência de sensor
* de pressão . No protocolo atual , representa 255.
* /
2026-06-19 15:33:46 +00:00
byte pressaoByte = pressao < 0 ? byte . MaxValue : ( byte ) Math . Round ( FuncoesMatematicas . Clamp ( pressao , 0 , 255 ) ) ;
2026-06-19 12:15:05 +00:00
byte [ ] data =
{
2026-06-19 15:33:46 +00:00
( byte ) ( status ? Estado . Ligado : Estado . Desligado ) ,
potenciaByte ,
pressaoByte
} ;
dispAtu . AdicionarMensagemFila ( bomba . ID_Num , CanMessagePosicaoDados . Command1 , CanMessagePosicaoDados . Command1 , data , false ) ;
2026-06-24 16:32:47 +00:00
bomba . UltimoComandoEnviado = DateTime . Now ;
bomba . UltimoStatusDesejado = status ;
bomba . UltimaPotenciaDesejada = potencia ;
bomba . UltimaPressaoDesejada = pressao ;
2026-06-19 12:15:05 +00:00
}
2025-04-16 16:44:06 +00:00
private void AtualizaComponentesIniciados ( )
{
DateTime Agora = DateTime . Now ;
bool modConectado = DadosLeitura . UltimoComandoRespondido . AddMilliseconds ( TempoLimiteConexao ) > Agora ;
if ( ! modConectado & & DadosLeitura . Conectado )
{
DadosLeitura . Conectado = false ;
}
2025-05-30 20:11:31 +00:00
foreach ( var bomba in BombasPressurizadoras . Where ( x = > x . Inicializado & & x . UltimaLeitura . AddMilliseconds ( TempoLimiteConexao ) < Agora ) )
2025-04-16 16:44:06 +00:00
{
2025-05-30 20:11:31 +00:00
bomba . Inicializado = false ;
2025-04-16 16:44:06 +00:00
}
2025-05-30 20:11:31 +00:00
foreach ( var bico in BicosPulverizadores . Where ( x = > x . Inicializado & & x . UltimaLeitura . AddMilliseconds ( TempoLimiteConexao ) < Agora ) )
2025-04-16 16:44:06 +00:00
{
2025-05-30 20:11:31 +00:00
bico . Inicializado = false ;
2026-06-19 12:15:05 +00:00
bico . AtualizarEstadoTrecho ( false ) ;
2025-04-16 16:44:06 +00:00
}
2025-05-30 20:11:31 +00:00
foreach ( var sensor in Sensores . Where ( x = > x . Inicializado & & x . UltimaLeitura . AddMilliseconds ( TempoLimiteConexao ) < Agora ) )
2025-04-16 16:44:06 +00:00
{
2025-05-30 20:11:31 +00:00
sensor . Inicializado = false ;
2025-04-16 16:44:06 +00:00
}
}
2025-07-11 16:38:08 +00:00
2026-06-19 12:15:05 +00:00
private async Task < bool > RealizarTestesIniciais ( bool forcar )
2025-07-11 16:38:08 +00:00
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
var calAtu = op . Sensoriamento . Operacao . ModsCalibragem [ Dispositivo ] ;
2025-07-11 16:38:08 +00:00
2025-10-21 19:23:36 +00:00
// Ligar bomba
foreach ( var Bomba in BombasPressurizadoras . Where ( x = > x . Comandar ) )
2025-07-11 16:38:08 +00:00
{
2025-10-21 19:23:36 +00:00
calAtu . TryGetValue ( Bomba . ID , out var cal ) ;
2025-10-24 11:45:47 +00:00
if ( ! forcar & & cal & & calAtu [ Bomba . ID ] ) continue ;
2025-10-21 19:23:36 +00:00
calAtu [ Bomba . ID ] = false ;
// Sem herbicida no reservatorio, bomba nao precisa ligar
2025-12-09 16:47:53 +00:00
if ( ! Bomba . Inicializado | | ContadorCarga . PercentualAtual < VariaveisEquipamento . PercentualReservatorioMin )
2025-10-21 19:23:36 +00:00
{
2026-04-01 11:26:37 +00:00
Variaveis . MostrarLog ( $"[AtuadorModel] [RealizarTestesIniciais] Bomba não iniciada ou nível do reservatório baixo, não irá ligar a bomba {Bomba.ID}" ) ;
2026-06-26 20:00:49 +00:00
op . Sensoriamento . InserirLog ( Dispositivo , StatusModulo . Alerta , 50 , $"Bomba não iniciada ou nível do reservatório baixo, não irá ligar a bomba {Bomba.ID}" , id : Bomba . ID ) ;
2026-04-01 11:26:37 +00:00
continue ;
2025-10-21 19:23:36 +00:00
}
2026-04-02 17:38:24 +00:00
Bomba . PotenciaSP = 100 ;
2026-06-19 12:15:05 +00:00
if ( Bomba . ID = = BombaPressurizadora . ID )
2026-06-09 13:39:44 +00:00
{
2026-06-26 20:00:49 +00:00
Bomba . Controle . Modo = op . Parametros . Controle . AtuModoControle ;
Bomba . PressaoSP = op . Parametros . Controle . AtuPressaoLinha ;
2026-06-19 12:15:05 +00:00
GeneralJoystick . EnviarComandoAtuador ( Bomba . Componente , Bomba . ID , Status : true , Valores : new List < double? > ( ) { ( int ) Bomba . Controle . Modo , Bomba . Controle . PotenciaMinPID , Bomba . Controle . Kp , Bomba . Controle . Ki , Bomba . Controle . Kd } , Comando : CanMessagePosicaoDados . Command2 , Forcar : true ) ;
2026-06-09 13:39:44 +00:00
GeneralJoystick . EnviarComandoAtuador ( Bomba . Componente , Bomba . ID , Status : true , Valores : new List < double? > ( ) { Bomba . PotenciaSP , Bomba . PressaoSP } , Comando : CanMessagePosicaoDados . Command1 , Forcar : true ) ;
}
else
{
Bomba . PressaoSP = - 1 ;
2026-06-26 20:00:49 +00:00
bool ligar = op . Parametros . Controle . AtuAgitadorModo ! = ModoAgitadorCalda . SemAgitacao ;
2026-06-19 12:15:05 +00:00
GeneralJoystick . EnviarComandoAtuador ( Bomba . Componente , Bomba . ID , Status : ligar , Valores : new List < double? > ( ) { Bomba . PotenciaSP , Bomba . PressaoSP } , Comando : CanMessagePosicaoDados . Command1 , Forcar : true ) ;
2026-06-09 13:39:44 +00:00
}
2026-04-01 11:26:37 +00:00
if ( Bomba . Sensor_ID_Num = = - 1 )
{
Variaveis . MostrarLog ( $"[AtuadorModel] [RealizarTestesIniciais] Bomba {Bomba.ID} não possui um sensor de pressão, será controlada mecanicamente pelo pressostato" ) ;
2026-06-26 20:00:49 +00:00
op . Sensoriamento . InserirLog ( Dispositivo , StatusModulo . Alerta , 50 , $"Bomba {Bomba.ID} não possui um sensor de pressão, será controlada mecanicamente pelo pressostato" , id : Bomba . ID ) ;
2026-04-01 11:26:37 +00:00
calAtu [ Bomba . ID ] = true ;
continue ;
}
2025-07-11 16:38:08 +00:00
2025-10-21 19:23:36 +00:00
await FuncoesGlobais . AguardarCondicaoAsync ( Bomba . AtingiuPressao , 3000 , 200 ) ;
bool BombaOk = Bomba . AtingiuPressao ( ) ;
if ( BombaOk )
{
calAtu [ Bomba . ID ] = true ;
}
else
{
foreach ( var Bico in BicosPulverizadores . Where ( x = > x . Comandar & & x . Inicializado ) )
{
2026-04-01 11:26:37 +00:00
GeneralJoystick . EnviarComandoAtuador ( Bico . Componente , Bico . ID , Status : true , Forcar : true ) ;
2025-10-21 19:23:36 +00:00
}
2025-07-11 16:38:08 +00:00
2025-10-21 19:23:36 +00:00
await Task . Delay ( 3000 ) ;
2025-07-11 16:38:08 +00:00
2025-10-21 19:23:36 +00:00
foreach ( var Bico in BicosPulverizadores . Where ( x = > x . Comandar & & x . Inicializado ) )
{
2026-04-01 11:26:37 +00:00
GeneralJoystick . EnviarComandoAtuador ( Bico . Componente , Bico . ID , Status : false , Forcar : true ) ;
2025-10-21 19:23:36 +00:00
}
await FuncoesGlobais . AguardarCondicaoAsync ( Bomba . AtingiuPressao , 4000 , 200 ) ;
BombaOk = Bomba . AtingiuPressao ( ) ;
2026-04-01 11:26:37 +00:00
calAtu [ Bomba . ID ] = BombaOk ;
2025-10-21 19:23:36 +00:00
}
2025-07-11 16:38:08 +00:00
}
// Testar os bicos
2025-10-21 19:23:36 +00:00
foreach ( var Bico in BicosPulverizadores . Where ( x = > x . Comandar ) )
2025-07-11 16:38:08 +00:00
{
2025-10-21 19:23:36 +00:00
calAtu . TryGetValue ( Bico . ID , out var cal ) ;
2025-10-24 11:45:47 +00:00
if ( ! forcar & & cal & & calAtu [ Bico . ID ] ) continue ;
2025-10-21 19:23:36 +00:00
calAtu [ Bico . ID ] = false ;
2025-07-11 16:38:08 +00:00
if ( Bico . Inicializado )
{
2026-04-01 11:26:37 +00:00
GeneralJoystick . EnviarComandoAtuador ( Bico . Componente , Bico . ID , Status : true , Forcar : true ) ;
2025-07-11 16:38:08 +00:00
await Task . Delay ( 200 ) ;
2026-04-01 11:26:37 +00:00
GeneralJoystick . EnviarComandoAtuador ( Bico . Componente , Bico . ID , Status : false , Forcar : true ) ;
await Task . Delay ( 200 ) ;
2025-10-21 19:23:36 +00:00
calAtu [ Bico . ID ] = true ;
2025-07-11 16:38:08 +00:00
}
}
await Task . Delay ( 1000 ) ;
2025-10-21 19:23:36 +00:00
bool sucesso = calAtu . All ( x = > x . Value ) ;
return sucesso ;
2025-07-11 16:38:08 +00:00
}
2025-10-24 11:45:47 +00:00
public List < Task > RealizarCalibragemAsync ( bool forcar )
2025-07-11 16:38:08 +00:00
{
2026-06-26 20:00:49 +00:00
var op = Variaveis . OperacaoEmAndamento ;
2025-07-17 11:19:42 +00:00
List < Task > tasks = new List < Task > ( ) ;
2026-06-30 18:59:15 +00:00
if ( op ? . DispAtu ? . Dados = = null )
return tasks ;
tasks . Add ( Task . Run ( async ( ) = >
2025-10-24 11:45:47 +00:00
{
2026-06-30 18:59:15 +00:00
try
{
bool sucesso = await op . DispAtu . Dados . RealizarTestesIniciais ( forcar ) ;
var calAtu = op . Sensoriamento . Operacao . ModsCalibragem [ Dispositivo ] ;
var v = calAtu . Select ( x = > $"{x.Key} " + ( x . Value ? "Sim" : "Não" ) ) ;
if ( sucesso )
2026-06-19 12:15:05 +00:00
{
2026-06-30 18:59:15 +00:00
Variaveis . MostrarLog ( $"[AtuadorModel] [RealizarCalibragemAsync] Teste do módulo {Modulo_ID} finalizado com sucesso: " + string . Join ( ", " , v ) ) ;
op . Sensoriamento . InserirLog ( Dispositivo , StatusModulo . Operante , 100 , $"Teste do módulo {Modulo_ID} finalizado com sucesso: " + string . Join ( ", " , v ) ) ;
2026-06-19 12:15:05 +00:00
}
2026-06-30 18:59:15 +00:00
else
2025-10-21 19:23:36 +00:00
{
2026-06-30 18:59:15 +00:00
Variaveis . MostrarLog ( $"[AtuadorModel] [RealizarCalibragemAsync] Teste do módulo {Modulo_ID} finalizado com pendências: " + string . Join ( ", " , v ) ) ;
op . Sensoriamento . InserirLog ( Dispositivo , StatusModulo . Alerta , 50 , $"Teste do módulo {Modulo_ID} finalizado com pendências: " + string . Join ( ", " , v ) ) ;
2025-10-21 19:23:36 +00:00
}
2026-06-30 18:59:15 +00:00
}
catch ( Exception ex )
{
Variaveis . MostrarLog ( $"[AtuadorModel] [RealizarCalibragemAsync] Erro no teste do módulo {Modulo_ID}: {ex.Message}" ) ;
op . Sensoriamento . InserirLog ( Dispositivo , StatusModulo . Falha , 0 , $"Erro no teste do módulo {Modulo_ID}: {ex.Message}" ) ;
throw ;
}
} ) ) ;
2025-07-17 11:19:42 +00:00
return tasks ;
2025-07-11 16:38:08 +00:00
}
2025-12-05 18:25:29 +00:00
public void RequisitarDadosSensoresExternos ( )
{
if ( SensorAnguloBarraEsquerda ! = null )
RequisitarDadosModulo ( SensorAnguloBarraEsquerda . ID_Num , CanMessagePosicaoDados . Dados1 , CanMessagePosicaoDados . Dados1 , true ) ;
if ( SensorAnguloBarraDireita ! = null )
RequisitarDadosModulo ( SensorAnguloBarraDireita . ID_Num , CanMessagePosicaoDados . Dados1 , CanMessagePosicaoDados . Dados1 , true ) ;
}
public void AtualizarDadosSensoresExternos ( S_Code componente , int id_num )
{
switch ( componente )
{
case S_Code . sMAG :
{
var sensor = Sensores . FirstOrDefault ( x = > x . ID_Num = = id_num ) ;
2025-12-17 19:27:06 +00:00
if ( sensor = = null ) return ;
2026-06-25 18:17:42 +00:00
double angulo = sensor . ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . LeituraAngulo ) ? . atual ? . valor ? ? double . NaN ;
2025-12-05 18:25:29 +00:00
if ( sensor . ID_Num = = SensorAnguloBarraEsquerda . ID_Num )
AnguloBarraEsquerda = angulo ;
else if ( sensor . ID_Num = = SensorAnguloBarraDireita . ID_Num )
AnguloBarraDireita = angulo ;
}
break ;
}
}
2024-01-03 10:52:37 +00:00
}
public class AtuadorBicoModel
{
public string ID { get ; set ; }
2025-04-09 21:11:40 +00:00
public int ID_Num { get ; set ; }
2024-01-03 10:52:37 +00:00
public int Posicao { get ; set ; }
2024-11-29 20:28:25 +00:00
public S_Code Componente { get ; set ; } = S_Code . sBIC ;
public bool AtuacaoNivelAlto { get ; set ; }
2026-04-01 11:26:37 +00:00
public double AnguloNeutro { get ; set ; }
2025-12-02 18:42:15 +00:00
public double AnguloControle { get ; set ; }
public double AnguloAbertura { get ; set ; }
2025-12-17 19:27:06 +00:00
public bool ComandoAtuar { get ; set ; }
2024-01-03 10:52:37 +00:00
public bool Comandar { get ; set ; }
2025-05-07 16:54:45 +00:00
public bool Mandatorio { get ; set ; }
public bool Liberado
{
get
{
return ! Mandatorio | | ( Comandar & & Inicializado ) ;
}
}
2024-01-03 10:52:37 +00:00
public List < FuncoesPinout > Funcoes { get ; set ; }
2025-12-18 20:14:27 +00:00
public double VazaoMediaMLs { get ; set ; }
public double VazaoInstantaneaMLs { get ; set ; }
public double VolumeVazadoML { get ; set ; }
2026-06-19 12:15:05 +00:00
public double TempoComFluxo { get ; set ; }
2025-05-30 20:11:31 +00:00
public bool Inicializado { get ; set ; }
public DateTime UltimaLeitura
2024-11-29 20:28:25 +00:00
{
get
{
2025-05-30 20:11:31 +00:00
return ValoresLeituras . OrderByDescending ( x = > x . atual . lidoEm ) . FirstOrDefault ( ) ? . atual ? . lidoEm ? ? DateTime . MinValue ;
2024-11-29 20:28:25 +00:00
}
}
2025-12-15 13:41:05 +00:00
public List < SensorValoresLeituraModel > ValoresLeituras { get ; set ; }
2026-06-25 18:17:42 +00:00
public Estado _EstadoLeitura = > ( Estado ) ( ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . EstadoLeitura ) ? . atual ? . valor ? ? 0 ) ;
public double _AnguloBicoLeitura = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . ServoAnguloLeitura ) ? . atual ? . valor ? ? 0 ;
2024-01-03 10:52:37 +00:00
2026-06-24 16:32:47 +00:00
public DateTime UltimoComandoEnviado { get ; set ; } = DateTime . MinValue ;
public bool UltimoStatusDesejado { get ; set ; } = false ;
public double UltimoAnguloDesejado { get ; set ; } = 0 ;
2024-01-03 10:52:37 +00:00
2025-05-01 18:27:01 +00:00
public ( CanMessagePosicaoDados , byte [ ] ) ProtocoloConfiguracao ( PinoutDataModel pinout , bool conectar )
2024-01-03 10:52:37 +00:00
{
2025-04-09 21:11:40 +00:00
var pino = pinout . Pinos . FirstOrDefault ( p = > p . ComponenteID = = ID ) ;
2025-05-01 18:27:01 +00:00
var data = new byte [ ]
2024-04-15 10:57:37 +00:00
{
2025-04-11 20:13:15 +00:00
( byte ) Componente ,
2025-04-09 21:11:40 +00:00
( byte ) ( conectar ? 1 : 0 ) ,
( byte ) ( AtuacaoNivelAlto ? 1 : 0 ) ,
2026-03-21 01:48:37 +00:00
0x00 , //(byte)Servo_ID_Num,
2025-04-09 21:11:40 +00:00
( byte ) ( pino ? . Barramento ? ? TiposBarramentos . CONTROLADOR ) ,
( byte ) ( pino ? . Pino ? ? PinoutUtils . PINO_INVALIDO )
2024-04-15 10:57:37 +00:00
} ;
2025-05-01 18:27:01 +00:00
return ( CanMessagePosicaoDados . Config1 , data ) ;
2024-01-03 10:52:37 +00:00
}
2025-05-01 18:27:01 +00:00
public ( int , CanMessagePosicaoDados , byte [ ] ) ProtocoloComando ( )
2024-01-03 10:52:37 +00:00
{
2025-04-09 21:11:40 +00:00
return (
2025-05-01 18:27:01 +00:00
ID_Num ,
CanMessagePosicaoDados . Command1 ,
2025-04-09 21:11:40 +00:00
new byte [ ]
{
2025-12-16 17:17:26 +00:00
( byte ) ( ComandoAtuar ? Estado . Ligado : Estado . Desligado ) ,
( byte ) AnguloControle
2025-04-09 21:11:40 +00:00
}
) ;
2024-01-03 10:52:37 +00:00
}
2024-03-11 20:04:48 +00:00
2026-06-19 12:15:05 +00:00
private readonly object _trechosLock = new object ( ) ;
private List < PontoGeo > _trechoAtivo ;
2026-06-18 19:55:07 +00:00
public List < List < PontoGeo > > TrechosAtuado { get ; set ; } = new List < List < PontoGeo > > ( ) ;
2026-06-19 12:15:05 +00:00
2025-12-19 12:01:58 +00:00
public int Atuacoes { get ; set ; } = 0 ;
public double TempoAtuado { get ; set ; } = 0 ;
2026-06-19 12:15:05 +00:00
public double TempoAtuadoEmMovimento { get ; set ; }
2024-10-29 19:53:27 +00:00
2026-06-19 12:15:05 +00:00
public Estado _estadoLeituraAnterior { get ; private set ; } = Estado . Desligado ;
2024-10-29 19:53:27 +00:00
2026-06-19 12:15:05 +00:00
/// <summary>
/// Atualiza o ciclo de vida do trecho com base no estado real do bico.
/// </summary>
public void AtualizarEstadoTrecho ( bool atuandoAgora )
2026-06-18 19:55:07 +00:00
{
2026-06-19 12:15:05 +00:00
lock ( _trechosLock )
2026-06-18 19:55:07 +00:00
{
2026-06-19 12:15:05 +00:00
bool atuavaAntes = _estadoLeituraAnterior = = Estado . Ligado ;
// Borda de subida: OFF -> ON
if ( ! atuavaAntes & & atuandoAgora )
{
_trechoAtivo = new List < PontoGeo > ( ) ;
2026-06-18 19:55:07 +00:00
2026-06-19 12:15:05 +00:00
if ( TrechosAtuado = = null )
TrechosAtuado = new List < List < PontoGeo > > ( ) ;
2026-06-18 19:55:07 +00:00
2026-06-19 12:15:05 +00:00
TrechosAtuado . Add ( _trechoAtivo ) ;
2026-06-18 19:55:07 +00:00
2026-06-19 12:15:05 +00:00
Atuacoes + + ;
}
// Borda de descida: ON -> OFF
else if ( atuavaAntes & & ! atuandoAgora )
{
/ *
* Se foi um pulso tão curto que nenhum GGA chegou ,
* remove o trecho vazio , mas mantém a contagem da atuação .
* /
if ( _trechoAtivo ! = null & & _trechoAtivo . Count = = 0 )
{
TrechosAtuado ? . Remove ( _trechoAtivo ) ;
}
_trechoAtivo = null ;
}
/ *
* Recuperação defensiva :
* o estado diz ligado , mas a referência ativa foi perdida ,
* por exemplo após carga , clone ou reconstrução do objeto .
* /
else if ( atuandoAgora & & _trechoAtivo = = null )
{
_trechoAtivo = new List < PontoGeo > ( ) ;
if ( TrechosAtuado = = null )
TrechosAtuado = new List < List < PontoGeo > > ( ) ;
TrechosAtuado . Add ( _trechoAtivo ) ;
}
_estadoLeituraAnterior = atuandoAgora ? Estado . Ligado : Estado . Desligado ;
}
}
public bool AdicionarPontoTrechoAtivo ( double latitude , double longitude )
{
lock ( _trechosLock )
{
if ( _trechoAtivo = = null )
return false ;
_trechoAtivo . Add ( new PontoGeo ( )
2026-06-18 19:55:07 +00:00
{
Latitude = latitude ,
Longitude = longitude
} ) ;
2026-06-19 12:15:05 +00:00
return true ;
}
}
2026-06-26 20:00:49 +00:00
public void ReiniciarHistoricoAtuacao ( bool limparTrechos = true )
{
2026-06-19 12:15:05 +00:00
lock ( _trechosLock )
{
_trechoAtivo = null ;
_estadoLeituraAnterior = Estado . Desligado ;
Atuacoes = 0 ;
if ( limparTrechos )
{
if ( TrechosAtuado = = null )
TrechosAtuado = new List < List < PontoGeo > > ( ) ;
else
TrechosAtuado . Clear ( ) ;
}
2026-06-18 19:55:07 +00:00
}
}
2024-03-11 20:04:48 +00:00
public AtuadorBicoModel Clone ( )
{
AtuadorBicoModel clone = new AtuadorBicoModel ( )
{
2024-12-06 20:19:59 +00:00
Comandar = Comandar ,
AtuacaoNivelAlto = AtuacaoNivelAlto ,
Atuacoes = Atuacoes ,
ComandoAtuar = ComandoAtuar ,
2025-12-02 18:42:15 +00:00
AnguloAbertura = AnguloAbertura ,
AnguloControle = AnguloControle ,
Inicializado = Inicializado ,
Mandatorio = Mandatorio ,
2024-12-06 20:19:59 +00:00
Componente = Componente ,
Funcoes = Funcoes ,
ID = ID ,
2025-04-09 21:11:40 +00:00
ID_Num = ID_Num ,
2025-12-19 12:01:58 +00:00
VolumeVazadoML = VolumeVazadoML ,
2026-06-19 12:15:05 +00:00
TrechosAtuado =
TrechosAtuado ?
. Select ( trecho = >
trecho ?
. Select ( ponto = > new PontoGeo ( )
{
Latitude = ponto . Latitude ,
Longitude = ponto . Longitude
} )
. ToList ( )
? ? new List < PontoGeo > ( )
)
. ToList ( )
? ? new List < List < PontoGeo > > ( ) ,
2025-12-19 12:01:58 +00:00
VazaoInstantaneaMLs = VazaoInstantaneaMLs ,
_estadoLeituraAnterior = _estadoLeituraAnterior ,
2025-05-30 20:11:31 +00:00
ValoresLeituras = new List < SensorValoresLeituraModel > ( ValoresLeituras ) ,
2025-12-18 20:14:27 +00:00
VazaoMediaMLs = VazaoMediaMLs ,
2024-12-06 20:19:59 +00:00
Posicao = Posicao ,
2025-12-19 12:01:58 +00:00
TempoAtuado = TempoAtuado ,
2026-06-19 12:15:05 +00:00
TempoAtuadoEmMovimento = TempoAtuadoEmMovimento ,
AnguloNeutro = AnguloNeutro ,
TempoComFluxo = TempoComFluxo ,
2024-03-11 20:04:48 +00:00
} ;
return clone ;
}
2024-01-03 10:52:37 +00:00
}
2024-04-01 11:03:25 +00:00
public class AtuadorBombaModel
{
public string ID { get ; set ; }
2025-04-09 21:11:40 +00:00
public int ID_Num { get ; set ; }
2024-12-02 19:12:39 +00:00
public bool ComandoAtuar { get ; set ; }
2026-04-02 17:38:24 +00:00
public double PotenciaSP { get ; set ; }
public double PressaoSP { get ; set ; }
2024-11-29 20:28:25 +00:00
public S_Code Componente { get ; set ; } = S_Code . sBMB ;
2025-12-16 17:17:26 +00:00
public int Sensor_ID_Num { get ; set ; }
2024-04-01 11:03:25 +00:00
public bool Comandar { get ; set ; }
2025-05-07 16:54:45 +00:00
public bool Mandatorio { get ; set ; }
public bool Liberado
{
get
{
return ! Mandatorio | | ( Comandar & & Inicializado ) ;
}
}
2025-12-15 13:41:05 +00:00
public List < FuncoesPinout > Funcoes { get ; set ; }
2025-05-30 20:11:31 +00:00
public bool Inicializado { get ; set ; }
public DateTime UltimaLeitura
2024-12-02 19:12:39 +00:00
{
get
{
2025-05-30 20:11:31 +00:00
return ValoresLeituras . OrderByDescending ( x = > x . atual . lidoEm ) . FirstOrDefault ( ) ? . atual ? . lidoEm ? ? DateTime . MinValue ;
2024-12-03 20:55:25 +00:00
}
}
2025-12-15 13:41:05 +00:00
public List < SensorValoresLeituraModel > ValoresLeituras { get ; set ; }
2026-06-09 13:39:44 +00:00
public BombaModoControleModel Controle { get ; set ; }
2026-06-25 18:17:42 +00:00
public Estado _EstadoLeitura = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . EstadoLeitura ) ? . atual ? . valor ? ? Estado . Desligado ;
public double _Potencia = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . Potencia ) ? . atual ? . valor ? ? 0 ;
2025-12-17 19:27:06 +00:00
public bool _BombaLigada = > _Potencia > 0 ;
2026-06-25 18:17:42 +00:00
public double _PressaoSP = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . PressaoSP ) ? . atual ? . valor ? ? 0 ;
public double _PotenciaSP = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . PotenciaSP ) ? . atual ? . valor ? ? 0 ;
public double _PressaoAtual = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados1 & & x . funcao = = FuncoesPinout . Pressao ) ? . atual ? . valor ? ? 0 ;
public int _QtdBicosLigados = > ( int ) ( ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados2 & & x . funcao = = FuncoesPinout . QtdPulsos ) ? . atual ? . valor ? ? 0 ) ;
public double _PotenciaFeedForwared = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados2 & & x . funcao = = FuncoesPinout . PotenciaSP ) ? . atual ? . valor ? ? 0 ;
public double _PotenciaFinal = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados2 & & x . funcao = = FuncoesPinout . Potencia ) ? . atual ? . valor ? ? 0 ;
public double _PressaoSensor = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados2 & & x . funcao = = FuncoesPinout . Pressao ) ? . atual ? . valor ? ? 0 ;
public double _PressaoSPControle = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados2 & & x . funcao = = FuncoesPinout . PressaoSP ) ? . atual ? . valor ? ? 0 ;
public bool _PressaoSPForaDoMapa = > ValoresLeituras ? . FirstOrDefault ( x = > x . posicao = = CanMessagePosicaoDados . Dados2 & & x . funcao = = FuncoesPinout . PressaoSPExtra ) ? . atual ? . valor ? ? false ;
2025-12-16 17:17:26 +00:00
2024-04-01 11:03:25 +00:00
2026-06-19 12:15:05 +00:00
public int Atuacoes { get ; set ; }
/// <summary>
/// Tempo em segundos com estado real Ligado.
/// </summary>
public double TempoAtuado { get ; set ; }
/// <summary>
/// Tempo em segundos com potência real maior que zero.
/// </summary>
public double TempoComPotencia { get ; set ; }
public double PotenciaAcumuladaPctSeg { get ; set ; }
public double PotenciaMediaAtiva { get ; set ; }
2024-11-29 20:28:25 +00:00
2026-06-24 16:32:47 +00:00
public DateTime UltimoComandoEnviado { get ; set ; } = DateTime . MinValue ;
public bool UltimoStatusDesejado { get ; set ; } = false ;
public double UltimaPotenciaDesejada { get ; set ; } = 0 ;
public double UltimaPressaoDesejada { get ; set ; } = 0 ;
2024-04-01 11:03:25 +00:00
2024-11-29 20:28:25 +00:00
2025-05-01 18:27:01 +00:00
public List < ( CanMessagePosicaoDados , byte [ ] ) > ProtocoloConfiguracao ( PinoutDataModel pinout , bool conectar )
2024-04-01 11:03:25 +00:00
{
2025-04-14 12:52:19 +00:00
List < byte > config1 = new List < byte > ( )
2024-04-15 10:57:37 +00:00
{
2025-04-11 20:13:15 +00:00
( byte ) Componente ,
2025-04-09 21:11:40 +00:00
( byte ) ( conectar ? 1 : 0 ) ,
2026-04-02 17:38:24 +00:00
( byte ) PressaoSP ,
2025-12-16 17:17:26 +00:00
( byte ) Sensor_ID_Num ,
2026-04-01 17:03:04 +00:00
( byte ) ( pinout . Pinos . FirstOrDefault ( x = > x . ComponenteID = = ID & & x . Funcao = = FuncoesPinout . IN1 ) ? . Pino ? ? PinoutUtils . PINO_INVALIDO ) ,
( byte ) ( pinout . Pinos . FirstOrDefault ( x = > x . ComponenteID = = ID & & x . Funcao = = FuncoesPinout . IN2 ) ? . Pino ? ? PinoutUtils . PINO_INVALIDO ) ,
2025-04-14 12:52:19 +00:00
} ;
2025-04-10 20:59:50 +00:00
2025-05-01 18:27:01 +00:00
return new List < ( CanMessagePosicaoDados , byte [ ] ) > ( )
2025-04-16 16:44:06 +00:00
{
2025-05-01 18:27:01 +00:00
( CanMessagePosicaoDados . Config1 , config1 . ToArray ( ) ) ,
} ;
2024-04-01 11:03:25 +00:00
}
2026-06-09 13:39:44 +00:00
public ( int , CanMessagePosicaoDados , byte [ ] ) ProtocoloComando ( CanMessagePosicaoDados comando )
2024-04-01 11:03:25 +00:00
{
2026-06-09 13:39:44 +00:00
byte ConverterPIDParaByte ( double valor )
{
// Escala x10:
// 8.0 -> 80
// 0.4 -> 4
// 1.5 -> 15
valor = FuncoesMatematicas . Clamp ( valor , 0.0 , 25.5 ) ;
return ( byte ) Math . Round ( valor * 10.0 ) ;
}
switch ( comando )
{
case CanMessagePosicaoDados . Command1 :
return (
ID_Num ,
comando ,
new byte [ ]
{
( byte ) ( ComandoAtuar ? Estado . Ligado : Estado . Desligado ) ,
( byte ) ( PotenciaSP ) ,
( byte ) ( PressaoSP )
}
) ;
case CanMessagePosicaoDados . Command2 :
return (
ID_Num ,
comando ,
new byte [ ]
{
( byte ) Controle . Modo ,
( byte ) Controle . PotenciaMinPID ,
ConverterPIDParaByte ( Controle . Kp ) ,
ConverterPIDParaByte ( Controle . Ki ) ,
ConverterPIDParaByte ( Controle . Kd ) ,
}
) ;
default :
throw new ArgumentOutOfRangeException (
nameof ( comando ) ,
comando ,
"Comando CAN não suportado pela bomba pressurizadora." ) ;
}
2024-04-01 11:03:25 +00:00
}
2026-04-02 17:38:24 +00:00
public bool AtingiuPressao ( ) = > _PressaoAtual > = Variaveis . OperacaoEmAndamento . Parametros . Controle . AtuPressaoLinha ;
2025-10-21 19:23:36 +00:00
2026-06-09 13:39:44 +00:00
public class BombaModoControleModel
{
public ModoControleBomba Modo { get ; set ; } = ModoControleBomba . OnOff ;
2026-06-25 18:17:42 +00:00
public double PotenciaMinPID { get ; set ; } = 40.0 ;
2026-06-09 13:39:44 +00:00
2026-06-25 18:17:42 +00:00
public double Kp { get ; set ; } = 0.08 ;
public double Ki { get ; set ; } = 0.008 ;
2026-06-09 13:39:44 +00:00
public double Kd { get ; set ; } = 0.0 ;
}
2024-04-01 11:03:25 +00:00
}
2024-04-02 18:33:15 +00:00
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 ;
}
}
}
2024-04-01 11:03:25 +00:00
2024-10-29 19:53:27 +00:00
public class AtuadorFuncoesGerais
{
2026-06-26 20:00:49 +00:00
public static void DesenharAtuadores ( object sender , PaintEventArgs e , List < AtuadorBicoLogModel > Bicos , bool BombaLigada , double PressaoLinha , double TempoBombaAtuada )
2024-10-29 19:53:27 +00:00
{
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 ) ;
2024-12-05 12:52:28 +00:00
// 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 ) ;
2024-10-29 19:53:27 +00:00
// 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)
2026-06-19 12:15:05 +00:00
string tempoAtuadoSegundos = $"{(Bicos[i].TempoAtuado):0.0}s" ;
2024-10-29 19:53:27 +00:00
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
2026-06-19 12:15:05 +00:00
string tempoAtuacaoTexto = $"{(TempoBombaAtuada):0.0}s" ;
2024-10-29 19:53:27 +00:00
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 ) ;
}
}
2024-11-29 20:28:25 +00:00
public class AtuadorMensagemJsonModel
{
2024-12-05 17:11:38 +00:00
public DateTime Momento { get ; set ; }
2024-11-29 20:28:25 +00:00
public bool Conectado { get ; set ; }
2025-04-09 21:11:40 +00:00
public T_Code Dispositivo { get ; set ; }
public int Versao { get ; set ; }
2024-11-29 20:28:25 +00:00
public string Mod_ID { get ; set ; }
2024-12-05 17:11:38 +00:00
public int QualidadeWifi { get ; set ; }
public int LatenciaLoop { get ; set ; }
2025-12-16 17:17:26 +00:00
public List < AtuadorBicoModel > BicosPulverizadores { get ; set ; }
public List < AtuadorBombaModel > BombasPressurizadoras { get ; set ; }
public List < SensorModel > Sensores { get ; set ; }
public List < SensorServoModel > Servos { get ; set ; }
2025-04-09 21:11:40 +00:00
public DateTime UltimoComandoRespondido { get ; set ; }
}
public class AtuHandler : ICanMessageHandler
{
2025-05-06 18:47:59 +00:00
public T_Code Dispositivo { get ; set ; } = Variaveis . OperacaoEmAndamento . DispAtu ? . Dados ? . Dispositivo ? ? T_Code . Atu ;
2025-04-10 20:59:50 +00:00
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 ;
}
2025-12-04 13:51:11 +00:00
private ushort Converter2BytesU16 ( byte [ ] data , int idx )
{
return ( ushort ) ( ( data [ idx ] < < 8 ) | data [ idx + 1 ] ) ;
}
private double ConverterAngle100 ( byte [ ] data , int idx )
{
ushort v = ( ushort ) ( ( data [ idx ] < < 8 ) | data [ idx + 1 ] ) ;
return v / 100.0 ;
}
2025-04-11 20:13:15 +00:00
private S_Code DetectarComponenteDoID_Num ( int ID_Num )
{
if ( ID_Num = = Variaveis . ID_Num_sMOD ) return S_Code . sMOD ;
2025-07-24 16:15:42 +00:00
if ( ID_Num = = Variaveis . ID_Num_sTOD ) return S_Code . sTOD ;
2025-04-11 20:13:15 +00:00
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 ) ;
2026-04-02 17:38:24 +00:00
2026-03-21 01:48:37 +00:00
return sensor ? . Componente ? ? bico ? . Componente ? ? bomba ? . Componente ? ? S_Code . sVZO ;
2025-04-11 20:13:15 +00:00
}
2025-07-23 15:14:50 +00:00
private void AtualizarDados ( int CompID_Num , CanMessagePosicaoDados Posicao , S_Code componente , List < dynamic > Parametros )
2025-04-11 20:13:15 +00:00
{
2025-05-30 20:11:31 +00:00
var Dados = Variaveis . OperacaoEmAndamento . DispAtu . Dados ;
2025-04-11 20:13:15 +00:00
2025-05-30 20:11:31 +00:00
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 ) ;
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 ;
for ( int i = 0 ; i < valoresLeituras . Where ( x = > x . posicao = = Posicao ) . Count ( ) ; i + + )
2025-04-11 20:13:15 +00:00
{
2025-07-23 15:14:50 +00:00
try
2025-05-30 20:11:31 +00:00
{
2025-07-23 15:14:50 +00:00
var valor = valoresLeituras . FirstOrDefault ( x = > x . posicao = = Posicao & & x . indice = = i ) ;
if ( valor ! = null )
{
var v = Parametros . Count > i ? ( Parametros [ i ] ) : - 1 ;
if ( v is sbyte | | v is byte | | v is short | | v is ushort | | v is int | | v is uint | | v is long | | v is ulong | | v is float | | v is double | | v is decimal )
{
v + = valor . offset ;
valor . atual . valor = v ;
}
else
{
valor . atual . valor = v ;
}
2026-06-30 18:59:15 +00:00
if ( valor . funcao = = FuncoesPinout . Iniciado & & valor . posicao = = CanMessagePosicaoDados . Status )
2025-07-23 15:14:50 +00:00
{
if ( sensor ! = null )
sensor . Inicializado = v ;
if ( bomba ! = null )
bomba . Inicializado = v ;
if ( bico ! = null )
bico . Inicializado = v ;
}
}
}
catch ( Exception ex )
{
2026-06-19 12:15:05 +00:00
Variaveis . MostrarLog (
$"[AtuHandler.AtualizarDados] " +
$"Erro ao atualizar componente={componente}, " +
$"ID_Num={CompID_Num}, " +
$"posicao={Posicao}: {ex}"
) ;
2025-05-30 20:11:31 +00:00
}
2025-04-11 20:13:15 +00:00
}
}
2025-04-10 20:59:50 +00:00
2025-04-09 21:11:40 +00:00
public void ProcessarMensagem ( CanMessage mensagem )
{
2025-05-01 18:27:01 +00:00
CanMessagePosicaoDados posicao = ( CanMessagePosicaoDados ) mensagem . DataRx [ 0 ] ;
byte ID_Num = mensagem . DataRx [ 1 ] ;
2025-04-09 21:11:40 +00:00
var data = mensagem . DataRx ;
2025-04-11 20:13:15 +00:00
S_Code componente = DetectarComponenteDoID_Num ( ID_Num ) ;
2025-07-23 15:14:50 +00:00
var Dados = Variaveis . OperacaoEmAndamento . DispAtu . Dados ;
2025-07-24 16:15:42 +00:00
//Console.WriteLine($"[ATU] Componente={componente.ToString()}, ID_Num={ID_Num}, Data={FuncoesGlobais.ConverterComandoBytesParaTexto(data)}");
2025-04-11 20:13:15 +00:00
2025-05-30 20:11:31 +00:00
switch ( componente )
2025-04-09 21:11:40 +00:00
{
2025-05-30 20:11:31 +00:00
case S_Code . sMOD :
2025-04-09 21:11:40 +00:00
{
2025-05-30 20:11:31 +00:00
switch ( posicao )
2025-04-11 20:13:15 +00:00
{
2025-05-30 20:11:31 +00:00
case CanMessagePosicaoDados . Status :
{
T_Code tipoModulo = ( T_Code ) data [ 2 ] ;
bool conectado = data [ 3 ] = = 1 ;
int versao = data [ 4 ] ;
2025-04-09 21:11:40 +00:00
2025-08-22 18:36:19 +00:00
//Console.WriteLine($"[ATU] Resposta {ID_Num} recebida. Tipo={tipoModulo}, Conectado={conectado}, Versão={versao}");
2025-04-09 21:11:40 +00:00
2025-05-30 20:11:31 +00:00
Dados . DadosLeitura . Conectado = conectado ;
Dados . DadosLeitura . Dispositivo = tipoModulo ;
Dados . DadosLeitura . Versao = versao ;
break ;
}
2025-04-11 20:13:15 +00:00
}
2025-05-30 20:11:31 +00:00
break ;
}
case S_Code . sTOD :
{
switch ( posicao )
2025-04-11 20:13:15 +00:00
{
2025-05-30 20:11:31 +00:00
case CanMessagePosicaoDados . DadosAll :
{
double latenciaLoop = ConverterByteParaDouble ( data , 2 ) * 100 ;
Dados . DadosLeitura . LatenciaLoop = Convert . ToInt32 ( latenciaLoop ) ;
2025-08-22 18:36:19 +00:00
//Console.WriteLine($"[ATU] Ciclo concluido. Latencia de loop: {latenciaLoop} ms");
2025-05-30 20:11:31 +00:00
break ;
}
2025-04-11 20:13:15 +00:00
}
break ;
2025-04-09 21:11:40 +00:00
}
2025-05-30 20:11:31 +00:00
case S_Code . sBIC :
2025-04-10 20:59:50 +00:00
{
2025-05-30 20:11:31 +00:00
switch ( posicao )
2025-04-10 20:59:50 +00:00
{
2025-07-23 15:14:50 +00:00
case CanMessagePosicaoDados . Status :
{
bool Iniciado = data [ 2 ] = = 1 ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { Iniciado } ) ;
2026-06-19 12:15:05 +00:00
var bico = Dados . BicosPulverizadores . FirstOrDefault ( x = > x . ID_Num = = ID_Num ) ;
if ( bico ! = null & & ! Iniciado )
bico . AtualizarEstadoTrecho ( false ) ;
2025-07-23 15:14:50 +00:00
break ;
}
2025-05-30 20:11:31 +00:00
case CanMessagePosicaoDados . Dados1 :
2025-04-10 20:59:50 +00:00
{
2025-04-11 20:13:15 +00:00
Estado estado = ( Estado ) data [ 2 ] ;
2025-12-16 17:17:26 +00:00
int angulo = data [ 3 ] ;
2026-06-19 12:15:05 +00:00
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { estado , angulo } ) ;
2025-04-10 20:59:50 +00:00
break ;
}
2025-05-30 20:11:31 +00:00
}
break ;
}
case S_Code . sFLX :
{
switch ( posicao )
{
2025-07-23 15:14:50 +00:00
case CanMessagePosicaoDados . Status :
{
bool Iniciado = data [ 2 ] = = 1 ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { Iniciado } ) ;
break ;
}
2025-05-30 20:11:31 +00:00
case CanMessagePosicaoDados . Dados1 :
2025-04-10 20:59:50 +00:00
{
2025-12-16 17:17:26 +00:00
int qtdPulsos = data [ 2 ] ;
ushort periodo = Converter2BytesU16 ( data , 3 ) ;
double vazao = ConverterByteParaDouble ( data , 5 ) ;
2026-04-02 17:38:24 +00:00
//Variaveis.MostrarLog($"[AtuadorModel] Vazao: {vazao}, pulsos: {qtdPulsos}, Periodo: {periodo}");
2025-12-16 17:17:26 +00:00
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { qtdPulsos , periodo , vazao } ) ;
2025-04-10 20:59:50 +00:00
break ;
}
2025-05-30 20:11:31 +00:00
}
break ;
}
case S_Code . sMAS :
{
switch ( posicao )
{
2025-07-23 15:14:50 +00:00
case CanMessagePosicaoDados . Status :
{
bool Iniciado = data [ 2 ] = = 1 ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { Iniciado } ) ;
break ;
}
2025-05-30 20:11:31 +00:00
case CanMessagePosicaoDados . Dados1 :
2025-04-10 20:59:50 +00:00
{
2025-12-16 17:17:26 +00:00
double raw = ConverterByteParaDouble ( data , 2 ) ;
double massa = ConverterByteParaDouble ( data , 4 ) ;
2026-04-02 17:38:24 +00:00
//Variaveis.MostrarLog($"[AtuadorModel] Massa: {massa}, Raw: {raw}");
2025-12-16 17:17:26 +00:00
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { raw , massa } ) ;
2025-04-10 20:59:50 +00:00
break ;
}
2025-05-30 20:11:31 +00:00
}
break ;
}
case S_Code . sPRS :
{
switch ( posicao )
{
2025-07-23 15:14:50 +00:00
case CanMessagePosicaoDados . Status :
{
bool Iniciado = data [ 2 ] = = 1 ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { Iniciado } ) ;
break ;
}
2025-05-30 20:11:31 +00:00
case CanMessagePosicaoDados . Dados1 :
2025-04-10 20:59:50 +00:00
{
2025-12-16 17:17:26 +00:00
ushort raw = Converter2BytesU16 ( data , 2 ) ;
double pressao = ConverterByteParaDouble ( data , 4 ) ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { raw , pressao } ) ;
2025-04-10 20:59:50 +00:00
break ;
}
2025-05-30 20:11:31 +00:00
}
break ;
}
case S_Code . sBMB :
{
switch ( posicao )
{
2025-07-23 15:14:50 +00:00
case CanMessagePosicaoDados . Status :
{
2026-06-25 18:17:42 +00:00
bool iniciado = data . Length > 2 & & data [ 2 ] = = 1 ;
bool malhaFechada = data . Length > 3 & & data [ 3 ] = = 1 ;
AtualizarDados (
ID_Num ,
posicao ,
componente ,
new List < dynamic > ( ) {
iniciado ,
malhaFechada ,
}
) ;
2026-06-30 18:59:15 +00:00
var bomba = Dados . BombasPressurizadoras ? . FirstOrDefault ( x = > x . ID_Num = = ID_Num ) ;
2025-07-23 15:14:50 +00:00
break ;
}
2025-05-30 20:11:31 +00:00
case CanMessagePosicaoDados . Dados1 :
2025-04-10 20:59:50 +00:00
{
2026-06-25 18:17:42 +00:00
Estado estado = data . Length > 2 ? ( Estado ) data [ 2 ] : Estado . Desligado ;
int potenciaSp = data . Length > 3 ? data [ 3 ] : 0 ;
int percentualPotencia = data . Length > 4 ? data [ 4 ] : 0 ;
int pressaoSp = data . Length > 5 ? data [ 5 ] : 0 ;
int pressaoAtual = data . Length > 6 ? data [ 6 ] : 0 ;
ModoControleBomba modo = data . Length > 7 ? ( ModoControleBomba ) data [ 7 ] : ModoControleBomba . OnOff ;
AtualizarDados (
ID_Num ,
posicao ,
componente ,
new List < dynamic > ( )
{
estado ,
potenciaSp ,
percentualPotencia ,
pressaoSp ,
pressaoAtual ,
modo
}
) ;
break ;
}
case CanMessagePosicaoDados . Dados2 :
{
int qtdBicosLigados = data . Length > 2 ? data [ 2 ] : 0 ;
int potenciaFeedForward = data . Length > 3 ? data [ 3 ] : 0 ;
int potenciaFinal = data . Length > 4 ? data [ 4 ] : 0 ;
int pressaoSensor = data . Length > 5 ? data [ 5 ] : 0 ;
int pressaoSpControle = data . Length > 6 ? data [ 6 ] : 0 ;
bool pressaoSpForaDoMapa = data . Length > 7 & & data [ 7 ] = = 1 ;
AtualizarDados (
ID_Num ,
posicao ,
componente ,
new List < dynamic > ( )
{
qtdBicosLigados ,
potenciaFeedForward ,
potenciaFinal ,
pressaoSensor ,
pressaoSpControle ,
pressaoSpForaDoMapa
}
) ;
2025-04-10 20:59:50 +00:00
break ;
}
}
break ;
}
2025-12-04 13:51:11 +00:00
case S_Code . sMAG :
{
switch ( posicao )
{
case CanMessagePosicaoDados . Status :
{
bool Iniciado = data [ 2 ] = = 1 ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { Iniciado } ) ;
break ;
}
case CanMessagePosicaoDados . Dados1 :
{
ushort raw = Converter2BytesU16 ( data , 2 ) ;
double angle = ConverterAngle100 ( data , 4 ) ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { raw , angle } ) ;
//Console.WriteLine($"[sMAG] {ID_Num}, Raw: {raw}, Angulo: {angle}");
break ;
}
}
break ;
}
2026-06-09 13:39:44 +00:00
case S_Code . sBOT :
{
switch ( posicao )
{
case CanMessagePosicaoDados . Status :
{
bool Iniciado = data [ 2 ] = = 1 ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { Iniciado } ) ;
break ;
}
case CanMessagePosicaoDados . Dados1 :
{
bool pressionado = data [ 2 ] = = 1 ;
bool leitura = data [ 3 ] = = 1 ;
bool mudou = data [ 4 ] = = 1 ;
AtualizarDados ( ID_Num , posicao , componente , new List < dynamic > ( ) { pressionado , leitura , mudou } ) ;
break ;
}
}
break ;
}
2025-12-16 17:17:26 +00:00
2025-04-09 21:11:40 +00:00
}
2025-12-16 17:17:26 +00:00
2025-05-30 20:11:31 +00:00
Dados . DadosLeitura . UltimoComandoRespondido = DateTime . Now ;
2025-12-05 18:25:29 +00:00
Variaveis . OperacaoEmAndamento . DispAtu . Dados . AtualizarDadosSensoresExternos ( componente , ID_Num ) ;
2025-04-09 21:11:40 +00:00
}
2024-11-29 20:28:25 +00:00
}
2024-01-03 10:52:37 +00:00
}