From bbd5f4bfec5cc39c8696b219884754c99e1996ab Mon Sep 17 00:00:00 2001 From: Diego Freitas Date: Mon, 22 Jun 2026 20:33:50 -0300 Subject: [PATCH] ajustes calculo vazao por fluxo, saude do mov por frequencia por parametro --- .../AgroBase/Models/Modules/AtuadorModel.cs | 13 +- .../Modules/MovimentacaoUnificadoModel.cs | 101 ++++- AgroBase/AgroBase/Services/OIDCanService.cs | 392 +++++++++++++----- .../Operadores/HealthWorkerService.cs | 24 +- Firmware/Modulos/SensorFluxoModel_v2.h | 5 + 5 files changed, 401 insertions(+), 134 deletions(-) diff --git a/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs b/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs index ff786dd45..9791abbe4 100644 --- a/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs +++ b/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs @@ -129,16 +129,21 @@ namespace AgroBase.Models.Modules { 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) return 0.0; + const double FatorCalibracaoFluxo = 0.776; + 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; if (q_L_min < 0) @@ -147,7 +152,7 @@ namespace AgroBase.Models.Modules if (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; } } diff --git a/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs b/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs index cb218a820..91cad6bed 100644 --- a/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs +++ b/AgroBase/AgroBase/Models/Modules/MovimentacaoUnificadoModel.cs @@ -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() { - 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); return; } - - foreach (var Modulo in Modulos) + bool deveEnviarControle = + _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 já segura throttle, pendência e rodízio. + */ + OIDCanService.RequisitarProximoDado(addrTx, addrRx); + + /* + * Desligado por enquanto para aliviar CAN. + */ + // modulo.MovMotor.RequisitarDadosSensoresExternos(); + + /* + * Controle só a cada 1s. + * Se o EnviarComandoControle já tiver dedupe interno, melhor ainda. + */ + if (deveEnviarControle && controleMov != null) { - byte addrTx = Modulo.MovMotor._EnderecoCAN_Tx; - byte addrRx = Modulo.MovMotor._EnderecoCAN_Rx; - OIDCanService.RequisitarProximoDado(addrTx, addrRx); - Modulo.MovMotor.RequisitarDadosSensoresExternos(); + modulo.MovMotor.EnviarComandoControle(controleMov.UltimaDirecao); + enviouControle = true; + } - var Controle = Variaveis.OperacaoEmAndamento.Controle.TiposControle?.FirstOrDefault(x => x.Tipo == T_Code.Mov); - if (Controle != null) - { - Modulo.MovMotor.EnviarComandoControle(Controle.UltimaDirecao); - } + /* + * Essa leitura é local, pode deixar no tick. + */ + modulo.MovMotor.ConfigFreio.Leitura = + modulo.MovMotor.Leitura?.Freado ?? false; - Modulo.MovMotor.ConfigFreio.Leitura = Modulo.MovMotor.Leitura?.Freado ?? false; - - Variaveis.OperacaoEmAndamento.DispMvd.Dados.RegistrarLogMov(Modulo); + /* + * Log só a cada 1s para não virar serragem de JSON. + */ + if (deveRegistrarLog) + { + Variaveis.OperacaoEmAndamento.DispMvd.Dados.RegistrarLogMov(modulo); + registrouLog = true; } } + if (enviouControle) + _ultimoEnvioControleMov = agora; + + if (registrouLog) + _ultimoRegistroLogMov = agora; + tmrRegistradorMOV.SetInterval(OIDCanService.TaxaAmostragem); + + await Task.CompletedTask; } private async Task tmrRegistradorDIR_Tick() diff --git a/AgroBase/AgroBase/Services/OIDCanService.cs b/AgroBase/AgroBase/Services/OIDCanService.cs index c2eec9eeb..6ef538e18 100644 --- a/AgroBase/AgroBase/Services/OIDCanService.cs +++ b/AgroBase/AgroBase/Services/OIDCanService.cs @@ -11,8 +11,7 @@ namespace AgroBase.Services { public class OIDCanService { - public static List DadosLeitura = - new List(); + public static List DadosLeitura = new List(); private static T_Code Dispositivo { get; set; } = T_Code.Oid; @@ -22,72 +21,33 @@ namespace AgroBase.Services private static AsyncTaskTimerModel tmrHeartbeat; - private static readonly object _sync = - new object(); - - private static readonly HashSet _handlersRegistrados = - new HashSet(); - - private static readonly Dictionary - _ultimoEnvioConsultaPorDriver = - new Dictionary(); - - private static readonly Dictionary - _ultimoEnvioParametro = - new Dictionary(); - - private static readonly Dictionary - _ultimaConsultaPendente = - new Dictionary(); - - private static readonly Dictionary - _cursorPollingPorDriver = - new Dictionary(); - - private static readonly Dictionary - _ultimoComandoControleAssinatura = - new Dictionary(); - - private static readonly Dictionary - _ultimoComandoControleQuando = - new Dictionary(); + private static readonly object _sync = new object(); + private static readonly HashSet _handlersRegistrados = new HashSet(); + private static readonly Dictionary _ultimoEnvioConsultaPorDriver = new Dictionary(); + private static readonly Dictionary _ultimoEnvioParametro = new Dictionary(); + private static readonly Dictionary _ultimaConsultaPendente = new Dictionary(); + private static readonly Dictionary _cursorPollingPorDriver = new Dictionary(); + private static readonly Dictionary _ultimoComandoControleAssinatura = new Dictionary(); + private static readonly Dictionary _ultimoComandoControleQuando = new Dictionary(); /* * Consultas síncronas do OID respondem sempre com DATA[0]=0x0F. * A diferença fica em DATA[1]. Para evitar confusão no CanService, * enviaremos no máximo uma consulta pendente por driver. */ - private static readonly TimeSpan IntervaloMinimoConsultaPorDriver = - TimeSpan.FromMilliseconds(120); - - private static readonly TimeSpan IntervaloMinimoMesmoParametro = - TimeSpan.FromMilliseconds(300); - - private static readonly TimeSpan JanelaConsultaPendente = - 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); + private static readonly TimeSpan IntervaloMinimoConsultaPorDriver = TimeSpan.FromMilliseconds(120); + private static readonly TimeSpan IntervaloMinimoMesmoParametro = TimeSpan.FromMilliseconds(300); + private static readonly TimeSpan JanelaConsultaPendente = 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); + private static readonly TimeSpan PeriodoHeartbeat = TimeSpan.FromMilliseconds(500); /* * Polling recomendado. Se outro ponto do sistema ainda chamar * RequisitarDado() em massa, o throttle interno também segura. */ - private static readonly OidParametros[] OrdemPolling = + public static readonly OidParametros[] OrdemPolling = { OidParametros.VelocidadeAtual, OidParametros.CorrenteMotor, @@ -101,24 +61,264 @@ namespace AgroBase.Services OidParametros.IO_Status, }; - private static readonly Dictionary - IntervaloParametro = - new Dictionary + private static readonly Dictionary IntervaloParametro = new Dictionary + { + { 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 HealthParametroConfig = new Dictionary + { + /* + * Runtime importante. + */ + { + OidParametros.VelocidadeAtual, + new OidParametroHealthConfig { - { 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) }, - }; + Parametro = OidParametros.VelocidadeAtual, + RedisKey = "rpm", + FreqBaseHz = 1.0, + FreqMinHz = 0.45, + EmUsoHealth = true + } + }, + { + OidParametros.CorrenteMotor, + new OidParametroHealthConfig + { + Parametro = OidParametros.CorrenteMotor, + 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 { @@ -542,47 +742,25 @@ namespace AgroBase.Services private static OidParametros? EscolherProximoParametro(byte idTx) { - DateTime agora = - DateTime.Now; + DateTime agora = DateTime.Now; - int cursor = - _cursorPollingPorDriver.TryGetValue( - idTx, - out int c - ) - ? c - : 0; + int cursor = _cursorPollingPorDriver.TryGetValue(idTx, out int c) ? c : 0; - for (int tentativa = 0; - tentativa < OrdemPolling.Length; - tentativa++) + for (int tentativa = 0; tentativa < OrdemPolling.Length; tentativa++) { - int index = - (cursor + tentativa) % - OrdemPolling.Length; + int index = (cursor + tentativa) % OrdemPolling.Length; - OidParametros parametro = - OrdemPolling[index]; + OidParametros parametro = OrdemPolling[index]; - string chave = - idTx.ToString("X2") + - ":" + - ((byte)parametro).ToString("X2"); + string chave = idTx.ToString("X2") + ":" + ((byte)parametro).ToString("X2"); - TimeSpan intervalo = - IntervaloParametro.TryGetValue( - parametro, - out TimeSpan valor - ) - ? valor - : TimeSpan.FromMilliseconds(500); + TimeSpan intervalo = IntervaloParametro.TryGetValue(parametro, out TimeSpan valor) + ? valor + : TimeSpan.FromMilliseconds(500); - if (!_ultimoEnvioParametro.TryGetValue(chave, out DateTime ultimo) || - agora - ultimo >= intervalo) + if (!_ultimoEnvioParametro.TryGetValue(chave, out DateTime ultimo) || agora - ultimo >= intervalo) { - _cursorPollingPorDriver[idTx] = - (index + 1) % - OrdemPolling.Length; + _cursorPollingPorDriver[idTx] = (index + 1) % OrdemPolling.Length; return parametro; } diff --git a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs index cc7c24f7a..3399784c1 100644 --- a/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs +++ b/AgroBase/AgroBase/Services/Operadores/HealthWorkerService.cs @@ -424,13 +424,20 @@ namespace AgroBase.Services.Operadores ); int endereco_mov = mod.MovMotor._EnderecoCAN_Tx; - RedisService.AtualizarCampos( - RedisService.ModKey(Enums.T_Code.Mov), + var camposMov = new List<(string campo, object valor)> + { ($"{endereco_mov}.timestamp", agora), ($"{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}.mod_id", mod.Modulo_ID), + ($"{endereco_mov}.cod_erro", mod.MovMotor.CodigoAlarme), ($"{endereco_mov}.rpm", mod.MovMotor.RPM_Roda), ($"{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_motor", mod.MovMotor.Temperatura), ($"{endereco_mov}.freado", mod.MovMotor.Leitura?.Freado ?? false), + ($"{endereco_mov}.freq.erro", mod.MovMotor.Leitura?.CodigoAlarme?.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.corrente_motor", mod.MovMotor.Leitura?.CorrenteMotor?.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); diff --git a/Firmware/Modulos/SensorFluxoModel_v2.h b/Firmware/Modulos/SensorFluxoModel_v2.h index 13b84e36a..804a07121 100644 --- a/Firmware/Modulos/SensorFluxoModel_v2.h +++ b/Firmware/Modulos/SensorFluxoModel_v2.h @@ -152,6 +152,8 @@ class SensorFluxo_v2 : public ComponenteCAN { float CalcularVazao(uint16_t pulsos, unsigned long periodoMs) { if (periodoMs == 0) return 0.0f; + const float FATOR_CALIBRACAO_FLUXO = 0.776f; + float frequenciaHz = ((float)pulsos) * 1000.0f / (float)periodoMs; 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; float q_mL_s = q_L_min * (1000.0f / 60.0f); + + q_mL_s *= FATOR_CALIBRACAO_FLUXO; + return q_mL_s; }