agrobot_base/AgroBase/AgroBase/Services/CoolerControlService.cs

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,
};
}
}
}