224 lines
8.3 KiB
C#
224 lines
8.3 KiB
C#
using AgroBase.Models;
|
|
using AgroBase.Models.Modules;
|
|
using System;
|
|
using System.Linq;
|
|
using static AgroBase.Models.Enums;
|
|
using static AgroBase.Services.CoolerControlService;
|
|
|
|
namespace AgroBase.Services
|
|
{
|
|
public class CoolerControlService
|
|
{
|
|
// Config
|
|
public double TempOn { get; set; } = 55.0; // Liga ventilação básica
|
|
public double TempTurbo { get; set; } = 65.0; // Liga entrada+saída
|
|
public double TempCritical { get; set; } = 75.0; // Acima disso, alerta
|
|
public double Histerese { get; set; } = 1.5; // Para evitar chattering
|
|
|
|
public TimeSpan MinOnTime { get; set; } = TimeSpan.FromSeconds(30);
|
|
public TimeSpan MinOffTime { get; set; } = TimeSpan.FromSeconds(30);
|
|
|
|
// Filtro de temperatura (EMA)
|
|
public double AlphaFiltro { get; set; } = 0.2;
|
|
|
|
// Estado interno
|
|
public CoolerMode ModoAtual { get; private set; } = CoolerMode.Off;
|
|
public Estado CoolerEntradaEstado { get; private set; } = Estado.Desligado;
|
|
public Estado CoolerSaidaEstado { get; private set; } = Estado.Desligado;
|
|
public Estado CoolerEntradaLeitura => ReleCoolerEntrada?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado;
|
|
public Estado CoolerSaidaLeitura => ReleCoolerSaida?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? Estado.Desligado;
|
|
|
|
public double? TemperaturaFiltrada { get; private set; }
|
|
public DateTime UltimaMudancaModo { get; private set; } = DateTime.MinValue;
|
|
|
|
public bool AlertaTemperaturaCritica { get; private set; }
|
|
|
|
private SensorReleModel ReleCoolerEntrada
|
|
{
|
|
get
|
|
{
|
|
var sRLE = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Reles?.FirstOrDefault(x => x.ID == "RLCIN" && x.Inicializado && x.Controlar);
|
|
return sRLE;
|
|
}
|
|
}
|
|
|
|
private SensorReleModel ReleCoolerSaida
|
|
{
|
|
get
|
|
{
|
|
var sRLE = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Reles?.FirstOrDefault(x => x.ID == "RLCOUT" && x.Inicializado && x.Controlar);
|
|
return sRLE;
|
|
}
|
|
}
|
|
|
|
public CoolerControlService()
|
|
{
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
ModoAtual = CoolerMode.Off;
|
|
TemperaturaFiltrada = null;
|
|
UltimaMudancaModo = DateTime.MinValue;
|
|
AlertaTemperaturaCritica = false;
|
|
CoolerEntradaEstado = Estado.Desligado;
|
|
CoolerSaidaEstado = Estado.Desligado;
|
|
|
|
EnviarComando();
|
|
}
|
|
|
|
public void AlterarControle(CoolerMode modo, Estado? entrada = null, Estado? saida = null, double? tempOn = null, double? tempTurbo = null)
|
|
{
|
|
ModoAtual = modo;
|
|
|
|
if (entrada != null) CoolerEntradaEstado = (Estado)entrada;
|
|
if (saida != null) CoolerSaidaEstado = (Estado)saida;
|
|
if (tempOn != null) TempOn = (double)tempOn;
|
|
if (tempTurbo != null) TempTurbo = (double)tempTurbo;
|
|
|
|
EnviarComando();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Chamar a cada tick de atualização com a temperatura interna atual
|
|
/// </summary>
|
|
public void Atualizar(double temperaturaAtual_C, DateTime agora)
|
|
{
|
|
// 1) Filtrar temperatura (EMA)
|
|
if (TemperaturaFiltrada == null)
|
|
{
|
|
TemperaturaFiltrada = temperaturaAtual_C;
|
|
}
|
|
else
|
|
{
|
|
TemperaturaFiltrada = AlphaFiltro * temperaturaAtual_C + (1 - AlphaFiltro) * TemperaturaFiltrada.Value;
|
|
}
|
|
|
|
var temp = TemperaturaFiltrada.Value;
|
|
|
|
// 2) Verificar limite crítico (para health_worker)
|
|
bool _alertaAnterior = AlertaTemperaturaCritica;
|
|
AlertaTemperaturaCritica = temp >= TempCritical;
|
|
if (!_alertaAnterior && AlertaTemperaturaCritica)
|
|
{
|
|
Variaveis.OperacaoEmAndamento.Parametros?.DadosLeitura?.InserirLog(T_Code.Npc, StatusModulo.Alerta, 50, "Temperatura limite excedida no NPC");
|
|
}
|
|
|
|
if (ModoAtual == CoolerMode.Manual)
|
|
return;
|
|
|
|
// 3) Respeitar permanência mínima de estado
|
|
var tempoNoModoAtual = agora - UltimaMudancaModo;
|
|
bool podeMudar =
|
|
(ModoAtual == CoolerMode.Off && tempoNoModoAtual >= MinOffTime) ||
|
|
(ModoAtual != CoolerMode.Off && tempoNoModoAtual >= MinOnTime) ||
|
|
Variaveis.Fechando;
|
|
|
|
if (!podeMudar)
|
|
return;
|
|
|
|
// 4) Lógica com histerese
|
|
CoolerMode novoModo = ModoAtual;
|
|
|
|
switch (ModoAtual)
|
|
{
|
|
case CoolerMode.Off:
|
|
if (temp >= TempOn + Histerese)
|
|
novoModo = CoolerMode.ExhaustOnly;
|
|
break;
|
|
|
|
case CoolerMode.ExhaustOnly:
|
|
if (temp <= TempOn - Histerese)
|
|
novoModo = CoolerMode.Off;
|
|
else if (temp >= TempTurbo + Histerese)
|
|
novoModo = CoolerMode.IntakeAndExhaust;
|
|
break;
|
|
|
|
case CoolerMode.IntakeAndExhaust:
|
|
if (temp <= TempTurbo - Histerese)
|
|
novoModo = CoolerMode.ExhaustOnly;
|
|
break;
|
|
}
|
|
|
|
if (Variaveis.Fechando)
|
|
novoModo = CoolerMode.Off;
|
|
|
|
CoolerEntradaEstado = novoModo == CoolerMode.IntakeAndExhaust ? Estado.Ligado : Estado.Desligado;
|
|
CoolerSaidaEstado = novoModo == CoolerMode.ExhaustOnly || novoModo == CoolerMode.IntakeAndExhaust ? Estado.Ligado : Estado.Desligado;
|
|
|
|
if (novoModo != ModoAtual)
|
|
{
|
|
ModoAtual = novoModo;
|
|
UltimaMudancaModo = agora;
|
|
}
|
|
|
|
EnviarComando();
|
|
}
|
|
|
|
private void EnviarComando()
|
|
{
|
|
if (ReleCoolerEntrada != null && (ReleCoolerEntrada?.StatusLeitura ?? Estado.Desligado) != CoolerEntradaEstado)
|
|
GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerEntrada.Componente, ReleCoolerEntrada.ID, CoolerEntradaEstado);
|
|
if (ReleCoolerSaida != null && (ReleCoolerSaida?.StatusLeitura ?? Estado.Desligado) != CoolerSaidaEstado)
|
|
GeneralJoystick.EnviarComandoSensoriamento(ReleCoolerSaida.Componente, ReleCoolerSaida.ID, CoolerSaidaEstado);
|
|
}
|
|
|
|
public CoolerControlDataModel GetResumo()
|
|
{
|
|
return new CoolerControlDataModel()
|
|
{
|
|
Modo = ModoAtual,
|
|
UltimaMudanca = UltimaMudancaModo,
|
|
TemperaturaLigar = TempOn,
|
|
TemperaturaTurbo = TempTurbo,
|
|
EstadoEntrada = CoolerEntradaEstado,
|
|
EstadoSaida = CoolerSaidaEstado,
|
|
LeituraEntrada = CoolerEntradaLeitura,
|
|
LeituraSaida = CoolerSaidaLeitura,
|
|
Temperatura = TemperaturaFiltrada ?? 0,
|
|
Alerta = AlertaTemperaturaCritica
|
|
};
|
|
}
|
|
|
|
public enum CoolerMode
|
|
{
|
|
Off,
|
|
Manual,
|
|
ExhaustOnly,
|
|
IntakeAndExhaust
|
|
}
|
|
}
|
|
|
|
public class CoolerControlDataModel
|
|
{
|
|
public CoolerMode Modo { get; set; }
|
|
public DateTime UltimaMudanca { get; set; }
|
|
public double TemperaturaLigar { get; set; }
|
|
public double TemperaturaTurbo { get; set; }
|
|
public Estado EstadoEntrada { get; set; }
|
|
public Estado EstadoSaida { get; set; }
|
|
public Estado LeituraEntrada { get; set; }
|
|
public Estado LeituraSaida { get; set; }
|
|
public double Temperatura { get; set; }
|
|
public bool Alerta { get; set; }
|
|
|
|
public CoolerControlDataModel Clone()
|
|
{
|
|
return new CoolerControlDataModel()
|
|
{
|
|
Modo = Modo,
|
|
UltimaMudanca = UltimaMudanca,
|
|
TemperaturaLigar = TemperaturaLigar,
|
|
TemperaturaTurbo = TemperaturaTurbo,
|
|
EstadoEntrada = EstadoEntrada,
|
|
EstadoSaida = EstadoSaida,
|
|
LeituraEntrada = LeituraEntrada,
|
|
LeituraSaida = LeituraSaida,
|
|
Temperatura = Temperatura,
|
|
Alerta = Alerta,
|
|
};
|
|
}
|
|
}
|
|
|
|
}
|