ajustes calculo vazao por fluxo, saude do mov por frequencia por parametro

This commit is contained in:
Diego Freitas 2026-06-22 20:33:50 -03:00
parent 9b5fdf267f
commit bbd5f4bfec
5 changed files with 401 additions and 134 deletions

View File

@ -129,16 +129,21 @@ namespace AgroBase.Models.Modules
{ {
get get
{ {
int pulsos = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.QtdPulsos)?.atual?.valor ?? 0.0); int pulsos = (int)(SensorFluxoLinha?.ValoresLeituras?
.FirstOrDefault(x => x.funcao == FuncoesPinout.QtdPulsos)?
.atual?.valor ?? 0.0);
int periodo = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Periodo)?.atual?.valor ?? 0.0); int periodo = (int)(SensorFluxoLinha?.ValoresLeituras?
.FirstOrDefault(x => x.funcao == FuncoesPinout.Periodo)?
.atual?.valor ?? 0.0);
if (pulsos <= 0 || periodo <= 0) if (pulsos <= 0 || periodo <= 0)
return 0.0; return 0.0;
const double FatorCalibracaoFluxo = 0.776;
double frequencia = (double)pulsos / periodo * 1000.0; double frequencia = (double)pulsos / periodo * 1000.0;
// Fabricante: F = 8.1*q - 3, q em L/min
double q_L_min = (frequencia + 3.0) / 8.1; double q_L_min = (frequencia + 3.0) / 8.1;
if (q_L_min < 0) if (q_L_min < 0)
@ -147,7 +152,7 @@ namespace AgroBase.Models.Modules
if (q_L_min > VazaoMaximaSensor_LMin) if (q_L_min > VazaoMaximaSensor_LMin)
q_L_min = VazaoMaximaSensor_LMin; q_L_min = VazaoMaximaSensor_LMin;
return q_L_min * 1000.0 / 60.0; return q_L_min * 1000.0 / 60.0 * FatorCalibracaoFluxo;
} }
} }

View File

@ -235,44 +235,107 @@ namespace AgroBase.Models.Modules
} }
} }
private DateTime _ultimoEnvioControleMov = DateTime.MinValue;
private DateTime _ultimoRegistroLogMov = DateTime.MinValue;
private static readonly TimeSpan IntervaloControleMov = TimeSpan.FromSeconds(1);
private static readonly TimeSpan IntervaloLogMov = TimeSpan.FromSeconds(1);
private async Task tmrRegistradorMOV_Tick() private async Task tmrRegistradorMOV_Tick()
{ {
if (Variaveis.Fechando) return; if (Variaveis.Fechando)
return;
if (!OIDCanService.Iniciado && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Mov)) DateTime agora = DateTime.Now;
if (!OIDCanService.Iniciado &&
SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Mov))
{ {
foreach (var Leitura in OIDCanService.DadosLeitura.Where(x => x.UltimoComandoRecebido.AddSeconds(10) < DateTime.Now)) foreach (var leitura in OIDCanService.DadosLeitura
.Where(x => x.UltimoComandoRecebido.AddSeconds(10) < agora))
{ {
OIDCanService.RequisitarDado(_EnderecoCAN_Tx, _EnderecoCAN_Rx, OIDCanService.OidHandler.OidParametros.CodErro); OIDCanService.RequisitarDado(
leitura.EnderecoTx,
leitura.EnderecoRx,
OIDCanService.OidHandler.OidParametros.CodErro
);
} }
tmrRegistradorMOV.SetInterval(3000); tmrRegistradorMOV.SetInterval(3000);
return; return;
} }
bool deveEnviarControle =
foreach (var Modulo in Modulos) _ultimoEnvioControleMov == DateTime.MinValue ||
agora - _ultimoEnvioControleMov >= IntervaloControleMov;
bool deveRegistrarLog =
_ultimoRegistroLogMov == DateTime.MinValue ||
agora - _ultimoRegistroLogMov >= IntervaloLogMov;
bool enviouControle = false;
bool registrouLog = false;
var controleMov =
deveEnviarControle
? Variaveis.OperacaoEmAndamento.Controle.TiposControle?
.FirstOrDefault(x => x.Tipo == T_Code.Mov)
: null;
foreach (var modulo in Modulos)
{ {
if (Modulo.MovMotor.Inicializado) if (!modulo.MovMotor.Inicializado)
continue;
byte addrTx = modulo.MovMotor._EnderecoCAN_Tx;
byte addrRx = modulo.MovMotor._EnderecoCAN_Rx;
/*
* Esse continua em todo tick.
* O OIDCanService segura throttle, pendência e rodízio.
*/
OIDCanService.RequisitarProximoDado(addrTx, addrRx);
/*
* Desligado por enquanto para aliviar CAN.
*/
// modulo.MovMotor.RequisitarDadosSensoresExternos();
/*
* Controle a cada 1s.
* Se o EnviarComandoControle tiver dedupe interno, melhor ainda.
*/
if (deveEnviarControle && controleMov != null)
{ {
byte addrTx = Modulo.MovMotor._EnderecoCAN_Tx; modulo.MovMotor.EnviarComandoControle(controleMov.UltimaDirecao);
byte addrRx = Modulo.MovMotor._EnderecoCAN_Rx; enviouControle = true;
OIDCanService.RequisitarProximoDado(addrTx, addrRx); }
Modulo.MovMotor.RequisitarDadosSensoresExternos();
var Controle = Variaveis.OperacaoEmAndamento.Controle.TiposControle?.FirstOrDefault(x => x.Tipo == T_Code.Mov); /*
if (Controle != null) * Essa leitura é local, pode deixar no tick.
{ */
Modulo.MovMotor.EnviarComandoControle(Controle.UltimaDirecao); modulo.MovMotor.ConfigFreio.Leitura =
} modulo.MovMotor.Leitura?.Freado ?? false;
Modulo.MovMotor.ConfigFreio.Leitura = Modulo.MovMotor.Leitura?.Freado ?? false; /*
* Log a cada 1s para não virar serragem de JSON.
Variaveis.OperacaoEmAndamento.DispMvd.Dados.RegistrarLogMov(Modulo); */
if (deveRegistrarLog)
{
Variaveis.OperacaoEmAndamento.DispMvd.Dados.RegistrarLogMov(modulo);
registrouLog = true;
} }
} }
if (enviouControle)
_ultimoEnvioControleMov = agora;
if (registrouLog)
_ultimoRegistroLogMov = agora;
tmrRegistradorMOV.SetInterval(OIDCanService.TaxaAmostragem); tmrRegistradorMOV.SetInterval(OIDCanService.TaxaAmostragem);
await Task.CompletedTask;
} }
private async Task tmrRegistradorDIR_Tick() private async Task tmrRegistradorDIR_Tick()

View File

@ -11,8 +11,7 @@ namespace AgroBase.Services
{ {
public class OIDCanService public class OIDCanService
{ {
public static List<OIDModel> DadosLeitura = public static List<OIDModel> DadosLeitura = new List<OIDModel>();
new List<OIDModel>();
private static T_Code Dispositivo { get; set; } = private static T_Code Dispositivo { get; set; } =
T_Code.Oid; T_Code.Oid;
@ -22,72 +21,33 @@ namespace AgroBase.Services
private static AsyncTaskTimerModel tmrHeartbeat; private static AsyncTaskTimerModel tmrHeartbeat;
private static readonly object _sync = private static readonly object _sync = new object();
new object(); private static readonly HashSet<byte> _handlersRegistrados = new HashSet<byte>();
private static readonly Dictionary<byte, DateTime> _ultimoEnvioConsultaPorDriver = new Dictionary<byte, DateTime>();
private static readonly HashSet<byte> _handlersRegistrados = private static readonly Dictionary<string, DateTime> _ultimoEnvioParametro = new Dictionary<string, DateTime>();
new HashSet<byte>(); private static readonly Dictionary<byte, OidParametros> _ultimaConsultaPendente = new Dictionary<byte, OidParametros>();
private static readonly Dictionary<byte, int> _cursorPollingPorDriver = new Dictionary<byte, int>();
private static readonly Dictionary<byte, DateTime> private static readonly Dictionary<string, string> _ultimoComandoControleAssinatura = new Dictionary<string, string>();
_ultimoEnvioConsultaPorDriver = private static readonly Dictionary<string, DateTime> _ultimoComandoControleQuando = new Dictionary<string, DateTime>();
new Dictionary<byte, DateTime>();
private static readonly Dictionary<string, DateTime>
_ultimoEnvioParametro =
new Dictionary<string, DateTime>();
private static readonly Dictionary<byte, OidParametros>
_ultimaConsultaPendente =
new Dictionary<byte, OidParametros>();
private static readonly Dictionary<byte, int>
_cursorPollingPorDriver =
new Dictionary<byte, int>();
private static readonly Dictionary<string, string>
_ultimoComandoControleAssinatura =
new Dictionary<string, string>();
private static readonly Dictionary<string, DateTime>
_ultimoComandoControleQuando =
new Dictionary<string, DateTime>();
/* /*
* Consultas síncronas do OID respondem sempre com DATA[0]=0x0F. * Consultas síncronas do OID respondem sempre com DATA[0]=0x0F.
* A diferença fica em DATA[1]. Para evitar confusão no CanService, * A diferença fica em DATA[1]. Para evitar confusão no CanService,
* enviaremos no máximo uma consulta pendente por driver. * enviaremos no máximo uma consulta pendente por driver.
*/ */
private static readonly TimeSpan IntervaloMinimoConsultaPorDriver = private static readonly TimeSpan IntervaloMinimoConsultaPorDriver = TimeSpan.FromMilliseconds(120);
TimeSpan.FromMilliseconds(120); private static readonly TimeSpan IntervaloMinimoMesmoParametro = TimeSpan.FromMilliseconds(300);
private static readonly TimeSpan JanelaConsultaPendente = TimeSpan.FromMilliseconds(450);
private static readonly TimeSpan IntervaloMinimoMesmoParametro = private static readonly TimeSpan JanelaDedupeComandoControle = TimeSpan.FromMilliseconds(80);
TimeSpan.FromMilliseconds(300); private static readonly TimeSpan TempoRespostaRecente = TimeSpan.FromSeconds(3);
private static readonly TimeSpan TempoRemoverDriver = TimeSpan.FromSeconds(15);
private static readonly TimeSpan JanelaConsultaPendente = private static readonly TimeSpan PeriodoHeartbeat = TimeSpan.FromMilliseconds(500);
TimeSpan.FromMilliseconds(450);
private static readonly TimeSpan JanelaDedupeComandoControle =
TimeSpan.FromMilliseconds(80);
private static readonly TimeSpan TempoRespostaRecente =
TimeSpan.FromSeconds(3);
private static readonly TimeSpan TempoRemoverDriver =
TimeSpan.FromSeconds(15);
/*
* O manual sugere heartbeat com período metade do timeout.
* O timer continua em 500ms, mas o payload passa a seguir o manual:
* DATA[0] = 0x00.
*/
private static readonly TimeSpan PeriodoHeartbeat =
TimeSpan.FromMilliseconds(500);
/* /*
* Polling recomendado. Se outro ponto do sistema ainda chamar * Polling recomendado. Se outro ponto do sistema ainda chamar
* RequisitarDado() em massa, o throttle interno também segura. * RequisitarDado() em massa, o throttle interno também segura.
*/ */
private static readonly OidParametros[] OrdemPolling = public static readonly OidParametros[] OrdemPolling =
{ {
OidParametros.VelocidadeAtual, OidParametros.VelocidadeAtual,
OidParametros.CorrenteMotor, OidParametros.CorrenteMotor,
@ -101,24 +61,264 @@ namespace AgroBase.Services
OidParametros.IO_Status, OidParametros.IO_Status,
}; };
private static readonly Dictionary<OidParametros, TimeSpan> private static readonly Dictionary<OidParametros, TimeSpan> IntervaloParametro = new Dictionary<OidParametros, TimeSpan>
IntervaloParametro = {
new Dictionary<OidParametros, TimeSpan> { OidParametros.VelocidadeAtual, TimeSpan.FromMilliseconds(160) },
{ OidParametros.CorrenteMotor, TimeSpan.FromMilliseconds(300) },
{ OidParametros.CorrenteBarramento, TimeSpan.FromMilliseconds(350) },
{ OidParametros.CodErro, TimeSpan.FromMilliseconds(750) },
{ OidParametros.Tensao, TimeSpan.FromSeconds(1) },
{ OidParametros.Temperatura, TimeSpan.FromSeconds(1) },
{ OidParametros.CicloTrabalho, TimeSpan.FromMilliseconds(500) },
{ OidParametros.Potencia, TimeSpan.FromMilliseconds(500) },
{ OidParametros.PosicaoAbsoluta, TimeSpan.FromMilliseconds(500) },
{ OidParametros.PosicaoRelativa, TimeSpan.FromMilliseconds(500) },
{ OidParametros.ModoCodificador, TimeSpan.FromSeconds(2) },
{ OidParametros.ErroLerCache, TimeSpan.FromSeconds(5) },
{ OidParametros.IO_Status, TimeSpan.FromSeconds(2) },
};
public class OidParametroHealthConfig
{
public OidParametros Parametro { get; set; }
public string RedisKey { get; set; }
/*
* Frequência esperada para health.
* Não precisa ser a frequência máxima possível.
* É o que consideramos saudável para operação.
*/
public double FreqBaseHz { get; set; }
/*
* Abaixo disso começa alerta.
* Sugestão: 50% a 60% da base, dependendo da importância.
*/
public double FreqMinHz { get; set; }
public bool EmUsoHealth { get; set; } = true;
}
public static readonly Dictionary<OidParametros, OidParametroHealthConfig> HealthParametroConfig = new Dictionary<OidParametros, OidParametroHealthConfig>
{
/*
* Runtime importante.
*/
{
OidParametros.VelocidadeAtual,
new OidParametroHealthConfig
{ {
{ OidParametros.VelocidadeAtual, TimeSpan.FromMilliseconds(160) }, Parametro = OidParametros.VelocidadeAtual,
{ OidParametros.CorrenteMotor, TimeSpan.FromMilliseconds(300) }, RedisKey = "rpm",
{ OidParametros.CorrenteBarramento, TimeSpan.FromMilliseconds(350) }, FreqBaseHz = 1.0,
{ OidParametros.CodErro, TimeSpan.FromMilliseconds(750) }, FreqMinHz = 0.45,
{ OidParametros.Tensao, TimeSpan.FromSeconds(1) }, EmUsoHealth = true
{ OidParametros.Temperatura, TimeSpan.FromSeconds(1) }, }
{ OidParametros.CicloTrabalho, TimeSpan.FromMilliseconds(500) }, },
{ OidParametros.Potencia, TimeSpan.FromMilliseconds(500) }, {
{ OidParametros.PosicaoAbsoluta, TimeSpan.FromMilliseconds(500) }, OidParametros.CorrenteMotor,
{ OidParametros.PosicaoRelativa, TimeSpan.FromMilliseconds(500) }, new OidParametroHealthConfig
{ OidParametros.ModoCodificador, TimeSpan.FromSeconds(2) }, {
{ OidParametros.ErroLerCache, TimeSpan.FromSeconds(5) }, Parametro = OidParametros.CorrenteMotor,
{ OidParametros.IO_Status, TimeSpan.FromSeconds(2) }, RedisKey = "corrente_motor",
}; FreqBaseHz = 1.0,
FreqMinHz = 0.45,
EmUsoHealth = true
}
},
{
OidParametros.CorrenteBarramento,
new OidParametroHealthConfig
{
Parametro = OidParametros.CorrenteBarramento,
RedisKey = "corrente_barramento",
FreqBaseHz = 1.0,
FreqMinHz = 0.45,
EmUsoHealth = true
}
},
/*
* Estado elétrico/térmico. Pode ser mais lento.
*/
{
OidParametros.Tensao,
new OidParametroHealthConfig
{
Parametro = OidParametros.Tensao,
RedisKey = "tensao",
FreqBaseHz = 0.5,
FreqMinHz = 0.20,
EmUsoHealth = true
}
},
{
OidParametros.Temperatura,
new OidParametroHealthConfig
{
Parametro = OidParametros.Temperatura,
RedisKey = "temperatura",
FreqBaseHz = 0.5,
FreqMinHz = 0.20,
EmUsoHealth = true
}
},
/*
* Diagnóstico/telemetria secundária.
*/
{
OidParametros.CodErro,
new OidParametroHealthConfig
{
Parametro = OidParametros.CodErro,
RedisKey = "erro",
FreqBaseHz = 0.5,
FreqMinHz = 0.20,
EmUsoHealth = true
}
},
{
OidParametros.CicloTrabalho,
new OidParametroHealthConfig
{
Parametro = OidParametros.CicloTrabalho,
RedisKey = "ciclo_trabalho",
FreqBaseHz = 0.5,
FreqMinHz = 0.20,
EmUsoHealth = true
}
},
{
OidParametros.Potencia,
new OidParametroHealthConfig
{
Parametro = OidParametros.Potencia,
RedisKey = "potencia",
FreqBaseHz = 0.5,
FreqMinHz = 0.20,
EmUsoHealth = true
}
},
/*
* Por enquanto, não cobra no health se não for usado.
*/
{
OidParametros.PosicaoAbsoluta,
new OidParametroHealthConfig
{
Parametro = OidParametros.PosicaoAbsoluta,
RedisKey = "posicao_absoluta",
FreqBaseHz = 0.2,
FreqMinHz = 0.08,
EmUsoHealth = false
}
},
{
OidParametros.IO_Status,
new OidParametroHealthConfig
{
Parametro = OidParametros.IO_Status,
RedisKey = "io_status",
FreqBaseHz = 0.2,
FreqMinHz = 0.08,
EmUsoHealth = false
}
},
};
public static OidParametroHealthConfig ObterConfigHealth(OidParametros parametro)
{
if (HealthParametroConfig.TryGetValue(parametro, out var cfg))
{
return cfg;
}
return new OidParametroHealthConfig
{
Parametro = parametro,
RedisKey = parametro.ToString().ToLowerInvariant(),
FreqBaseHz = 0.5,
FreqMinHz = 0.2,
EmUsoHealth = false
};
}
public static double ObterFreqBaseHz(OidParametros parametro)
{
return ObterConfigHealth(parametro).FreqBaseHz;
}
public static double ObterFreqMinHz(OidParametros parametro)
{
return ObterConfigHealth(parametro).FreqMinHz;
}
public static bool ParametroEmUsoHealth(OidParametros parametro)
{
return ObterConfigHealth(parametro).EmUsoHealth;
}
public static double ObterIntervaloPollingParametroMs(OidParametros parametro)
{
if (IntervaloParametro.TryGetValue(parametro, out TimeSpan intervalo))
{
return intervalo.TotalMilliseconds;
}
return 500.0;
}
public static (string campo, object valor)[] GerarCamposRedisHealthBase(int enderecoMov)
{
var campos = new List<(string campo, object valor)>();
foreach (var kv in HealthParametroConfig)
{
var cfg = kv.Value;
string key = cfg.RedisKey;
campos.Add((
$"{enderecoMov}.freq_base.{key}",
cfg.FreqBaseHz
));
campos.Add((
$"{enderecoMov}.freq_min.{key}",
cfg.FreqMinHz
));
campos.Add((
$"{enderecoMov}.freq_uso.{key}",
cfg.EmUsoHealth
));
campos.Add((
$"{enderecoMov}.polling_ms.{key}",
ObterIntervaloPollingParametroMs(kv.Key)
));
}
campos.Add((
$"{enderecoMov}.polling.intervalo_timer_ms",
TaxaAmostragem
));
campos.Add((
$"{enderecoMov}.polling.qtd_parametros",
OrdemPolling.Length
));
campos.Add((
$"{enderecoMov}.polling.ordem",
OrdemPolling.Select(x => ObterConfigHealth(x).RedisKey).ToList()
));
return campos.ToArray();
}
public static bool Iniciado public static bool Iniciado
{ {
@ -542,47 +742,25 @@ namespace AgroBase.Services
private static OidParametros? EscolherProximoParametro(byte idTx) private static OidParametros? EscolherProximoParametro(byte idTx)
{ {
DateTime agora = DateTime agora = DateTime.Now;
DateTime.Now;
int cursor = int cursor = _cursorPollingPorDriver.TryGetValue(idTx, out int c) ? c : 0;
_cursorPollingPorDriver.TryGetValue(
idTx,
out int c
)
? c
: 0;
for (int tentativa = 0; for (int tentativa = 0; tentativa < OrdemPolling.Length; tentativa++)
tentativa < OrdemPolling.Length;
tentativa++)
{ {
int index = int index = (cursor + tentativa) % OrdemPolling.Length;
(cursor + tentativa) %
OrdemPolling.Length;
OidParametros parametro = OidParametros parametro = OrdemPolling[index];
OrdemPolling[index];
string chave = string chave = idTx.ToString("X2") + ":" + ((byte)parametro).ToString("X2");
idTx.ToString("X2") +
":" +
((byte)parametro).ToString("X2");
TimeSpan intervalo = TimeSpan intervalo = IntervaloParametro.TryGetValue(parametro, out TimeSpan valor)
IntervaloParametro.TryGetValue( ? valor
parametro, : TimeSpan.FromMilliseconds(500);
out TimeSpan valor
)
? valor
: TimeSpan.FromMilliseconds(500);
if (!_ultimoEnvioParametro.TryGetValue(chave, out DateTime ultimo) || if (!_ultimoEnvioParametro.TryGetValue(chave, out DateTime ultimo) || agora - ultimo >= intervalo)
agora - ultimo >= intervalo)
{ {
_cursorPollingPorDriver[idTx] = _cursorPollingPorDriver[idTx] = (index + 1) % OrdemPolling.Length;
(index + 1) %
OrdemPolling.Length;
return parametro; return parametro;
} }

View File

@ -424,13 +424,20 @@ namespace AgroBase.Services.Operadores
); );
int endereco_mov = mod.MovMotor._EnderecoCAN_Tx; int endereco_mov = mod.MovMotor._EnderecoCAN_Tx;
RedisService.AtualizarCampos( var camposMov = new List<(string campo, object valor)>
RedisService.ModKey(Enums.T_Code.Mov), {
($"{endereco_mov}.timestamp", agora), ($"{endereco_mov}.timestamp", agora),
($"{endereco_mov}.conectado", mod.MovMotor.Inicializado), ($"{endereco_mov}.conectado", mod.MovMotor.Inicializado),
($"{endereco_mov}.freq_base", 1),
// legado
($"{endereco_mov}.freq_base",
OIDCanService.ObterFreqBaseHz(
OIDCanService.OidHandler.OidParametros.VelocidadeAtual
)),
($"{endereco_mov}.endereco", mod.MovMotor._EnderecoCAN_Tx), ($"{endereco_mov}.endereco", mod.MovMotor._EnderecoCAN_Tx),
($"{endereco_mov}.mod_id", mod.Modulo_ID), ($"{endereco_mov}.mod_id", mod.Modulo_ID),
($"{endereco_mov}.cod_erro", mod.MovMotor.CodigoAlarme), ($"{endereco_mov}.cod_erro", mod.MovMotor.CodigoAlarme),
($"{endereco_mov}.rpm", mod.MovMotor.RPM_Roda), ($"{endereco_mov}.rpm", mod.MovMotor.RPM_Roda),
($"{endereco_mov}.rpm_sp", mod.MovMotor.RPM_SP_Leitura), ($"{endereco_mov}.rpm_sp", mod.MovMotor.RPM_SP_Leitura),
@ -440,12 +447,21 @@ namespace AgroBase.Services.Operadores
($"{endereco_mov}.temperatura_driver", mod.MovMotor.TemperaturaDriver), ($"{endereco_mov}.temperatura_driver", mod.MovMotor.TemperaturaDriver),
($"{endereco_mov}.temperatura_motor", mod.MovMotor.Temperatura), ($"{endereco_mov}.temperatura_motor", mod.MovMotor.Temperatura),
($"{endereco_mov}.freado", mod.MovMotor.Leitura?.Freado ?? false), ($"{endereco_mov}.freado", mod.MovMotor.Leitura?.Freado ?? false),
($"{endereco_mov}.freq.erro", mod.MovMotor.Leitura?.CodigoAlarme?.frequencia ?? 0), ($"{endereco_mov}.freq.erro", mod.MovMotor.Leitura?.CodigoAlarme?.frequencia ?? 0),
($"{endereco_mov}.freq.rpm", mod.MovMotor.Leitura?.ERPM?.frequencia ?? 0), ($"{endereco_mov}.freq.rpm", mod.MovMotor.Leitura?.ERPM?.frequencia ?? 0),
($"{endereco_mov}.freq.tensao", mod.MovMotor.Leitura?.Tensao?.frequencia ?? 0), ($"{endereco_mov}.freq.tensao", mod.MovMotor.Leitura?.Tensao?.frequencia ?? 0),
($"{endereco_mov}.freq.corrente_motor", mod.MovMotor.Leitura?.CorrenteMotor?.frequencia ?? 0), ($"{endereco_mov}.freq.corrente_motor", mod.MovMotor.Leitura?.CorrenteMotor?.frequencia ?? 0),
($"{endereco_mov}.freq.corrente_barramento", mod.MovMotor.Leitura?.CorrenteBarramento?.frequencia ?? 0), ($"{endereco_mov}.freq.corrente_barramento", mod.MovMotor.Leitura?.CorrenteBarramento?.frequencia ?? 0),
($"{endereco_mov}.freq.temperatura", mod.MovMotor.Leitura?.Temperatura?.frequencia ?? 0) ($"{endereco_mov}.freq.temperatura", mod.MovMotor.Leitura?.Temperatura?.frequencia ?? 0),
($"{endereco_mov}.freq.ciclo_trabalho", mod.MovMotor.Leitura?.CicloTrabalho?.frequencia ?? 0),
($"{endereco_mov}.freq.potencia", mod.MovMotor.Leitura?.Potencia?.frequencia ?? 0),
};
camposMov.AddRange(OIDCanService.GerarCamposRedisHealthBase(endereco_mov));
RedisService.AtualizarCampos(
RedisService.ModKey(Enums.T_Code.Mov),
camposMov.ToArray()
); );
dirAtivos.Add(endereco_dir); dirAtivos.Add(endereco_dir);

View File

@ -152,6 +152,8 @@ class SensorFluxo_v2 : public ComponenteCAN {
float CalcularVazao(uint16_t pulsos, unsigned long periodoMs) { float CalcularVazao(uint16_t pulsos, unsigned long periodoMs) {
if (periodoMs == 0) return 0.0f; if (periodoMs == 0) return 0.0f;
const float FATOR_CALIBRACAO_FLUXO = 0.776f;
float frequenciaHz = ((float)pulsos) * 1000.0f / (float)periodoMs; float frequenciaHz = ((float)pulsos) * 1000.0f / (float)periodoMs;
float q_L_min = (frequenciaHz + 3.0f) / 8.1f; float q_L_min = (frequenciaHz + 3.0f) / 8.1f;
@ -159,6 +161,9 @@ class SensorFluxo_v2 : public ComponenteCAN {
if (q_L_min > 10.0f) q_L_min = 10.0f; if (q_L_min > 10.0f) q_L_min = 10.0f;
float q_mL_s = q_L_min * (1000.0f / 60.0f); float q_mL_s = q_L_min * (1000.0f / 60.0f);
q_mL_s *= FATOR_CALIBRACAO_FLUXO;
return q_mL_s; return q_mL_s;
} }