ajustes finais timeout bateria e movimentacao
This commit is contained in:
parent
c306c8727b
commit
724391826b
|
|
@ -1749,16 +1749,16 @@ namespace AgroBase.Models.Modules
|
||||||
|
|
||||||
tmrRegistrador.SetInterval(_TaxaAmostragem);
|
tmrRegistrador.SetInterval(_TaxaAmostragem);
|
||||||
|
|
||||||
//if (SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Atu) && (_VezesLeituraReconexao >= _TempoReconexaoComponentes))
|
if (SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Atu) && (_VezesLeituraReconexao >= _TempoReconexaoComponentes))
|
||||||
//{
|
{
|
||||||
// Variaveis.OperacaoEmAndamento.DispAtu?.EnviarProtocolosConfiguracao();
|
Variaveis.OperacaoEmAndamento.DispAtu?.EnviarProtocolosConfiguracao();
|
||||||
//
|
|
||||||
// _VezesLeituraReconexao = 0;
|
_VezesLeituraReconexao = 0;
|
||||||
//}
|
}
|
||||||
//else
|
else
|
||||||
//{
|
{
|
||||||
// _VezesLeituraReconexao++;
|
_VezesLeituraReconexao++;
|
||||||
//}
|
}
|
||||||
|
|
||||||
if (DadosLeitura.Conectado)
|
if (DadosLeitura.Conectado)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2313,16 +2313,16 @@ namespace AgroBase.Models.Modules
|
||||||
|
|
||||||
tmrRegistrador.SetInterval(_TaxaAmostragem);
|
tmrRegistrador.SetInterval(_TaxaAmostragem);
|
||||||
|
|
||||||
//if (SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Sen) && (_VezesLeituraReconexao >= _TempoReconexaoComponentes))
|
if (SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Sen) && (_VezesLeituraReconexao >= _TempoReconexaoComponentes))
|
||||||
//{
|
{
|
||||||
// Variaveis.OperacaoEmAndamento.DispSen?.EnviarProtocolosConfiguracao();
|
Variaveis.OperacaoEmAndamento.DispSen?.EnviarProtocolosConfiguracao();
|
||||||
//
|
|
||||||
// _VezesLeituraReconexao = 0;
|
_VezesLeituraReconexao = 0;
|
||||||
//}
|
}
|
||||||
//else
|
else
|
||||||
//{
|
{
|
||||||
// _VezesLeituraReconexao++;
|
_VezesLeituraReconexao++;
|
||||||
//}
|
}
|
||||||
|
|
||||||
if (DadosLeitura.Conectado)
|
if (DadosLeitura.Conectado)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -631,16 +631,16 @@ namespace AgroBase.Services
|
||||||
_ultimaConsultaPendente[idTx] = dado;
|
_ultimaConsultaPendente[idTx] = dado;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(
|
//Console.WriteLine(
|
||||||
"[OID/TX] idTx=" +
|
// "[OID/TX] idTx=" +
|
||||||
idTx.ToString("X2") +
|
// idTx.ToString("X2") +
|
||||||
" idRx=" +
|
// " idRx=" +
|
||||||
idRx.ToString("X2") +
|
// idRx.ToString("X2") +
|
||||||
" param=" +
|
// " param=" +
|
||||||
dado +
|
// dado +
|
||||||
" data=0F-" +
|
// " data=0F-" +
|
||||||
((byte)dado).ToString("X2")
|
// ((byte)dado).ToString("X2")
|
||||||
);
|
//);
|
||||||
|
|
||||||
EnviarComando(
|
EnviarComando(
|
||||||
Dispositivo,
|
Dispositivo,
|
||||||
|
|
@ -1350,14 +1350,14 @@ namespace AgroBase.Services
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(
|
//Console.WriteLine(
|
||||||
"[OID/RX] idTx=" +
|
// "[OID/RX] idTx=" +
|
||||||
mensagem.IdTx.ToString("X") +
|
// mensagem.IdTx.ToString("X") +
|
||||||
" idRx=" +
|
// " idRx=" +
|
||||||
mensagem.IdRx.ToString("X") +
|
// mensagem.IdRx.ToString("X") +
|
||||||
" data=" +
|
// " data=" +
|
||||||
BitConverter.ToString(mensagem.DataRx ?? new byte[0])
|
// BitConverter.ToString(mensagem.DataRx ?? new byte[0])
|
||||||
);
|
//);
|
||||||
|
|
||||||
OidParametros parametro =
|
OidParametros parametro =
|
||||||
(OidParametros)mensagem.DataRx[1];
|
(OidParametros)mensagem.DataRx[1];
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,51 @@ class ModuloBateria(ModuloDiagnosticoBase):
|
||||||
else:
|
else:
|
||||||
return StatusModulo.FALHA
|
return StatusModulo.FALHA
|
||||||
|
|
||||||
|
def _normalizar_timestamp_segundos(self, valor):
|
||||||
|
"""
|
||||||
|
Normaliza timestamps vindos do Redis para Unix epoch em segundos.
|
||||||
|
|
||||||
|
Aceita:
|
||||||
|
- segundos Unix: 1782158000.123
|
||||||
|
- milissegundos: 1782158000123
|
||||||
|
- valor ausente/inválido: 0.0
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
ts = float(valor or 0.0)
|
||||||
|
except Exception:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
if ts <= 0:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
if ts > 1_000_000_000_000:
|
||||||
|
return ts / 1000.0
|
||||||
|
|
||||||
|
if ts > 1_000_000_000:
|
||||||
|
return ts
|
||||||
|
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
def _calcular_idade_telemetria_s(self, dados):
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
|
momento = self._normalizar_timestamp_segundos(
|
||||||
|
dados.get("timestamp")
|
||||||
|
)
|
||||||
|
|
||||||
|
if momento <= 0:
|
||||||
|
return 9999.0
|
||||||
|
|
||||||
|
dt = now - momento
|
||||||
|
|
||||||
|
if dt < 0 and dt > -5.0:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
if dt < -5.0:
|
||||||
|
return 9999.0
|
||||||
|
|
||||||
|
return dt
|
||||||
|
|
||||||
def atualizar_saude(self):
|
def atualizar_saude(self):
|
||||||
try:
|
try:
|
||||||
SAUDE_MIN_ALERTA = 80
|
SAUDE_MIN_ALERTA = 80
|
||||||
|
|
@ -26,7 +71,6 @@ class ModuloBateria(ModuloDiagnosticoBase):
|
||||||
condicoes = []
|
condicoes = []
|
||||||
saude_individual = []
|
saude_individual = []
|
||||||
|
|
||||||
now = time.perf_counter()
|
|
||||||
saude = 0
|
saude = 0
|
||||||
|
|
||||||
dados = ContextoGlobalRedis.get_modulo(self.t_code) or {}
|
dados = ContextoGlobalRedis.get_modulo(self.t_code) or {}
|
||||||
|
|
@ -36,8 +80,7 @@ class ModuloBateria(ModuloDiagnosticoBase):
|
||||||
saude = 0
|
saude = 0
|
||||||
motivos.append("Desconectado")
|
motivos.append("Desconectado")
|
||||||
else:
|
else:
|
||||||
momento = float(dados.get("timestamp") or 0.0)
|
dt = self._calcular_idade_telemetria_s(dados)
|
||||||
dt = now - momento if momento > 0 else 9999.0
|
|
||||||
|
|
||||||
# ------------ LEITURA DOS DADOS DA BATERIA ------------
|
# ------------ LEITURA DOS DADOS DA BATERIA ------------
|
||||||
v_total = dados.get("tensao_total_v")
|
v_total = dados.get("tensao_total_v")
|
||||||
|
|
@ -349,7 +392,7 @@ class ModuloBateria(ModuloDiagnosticoBase):
|
||||||
"temp_min_c": locals().get("t_min", 0),
|
"temp_min_c": locals().get("t_min", 0),
|
||||||
"temp_max_c": locals().get("t_max", 0),
|
"temp_max_c": locals().get("t_max", 0),
|
||||||
"bms_life_raw": locals().get("bms_life", 0),
|
"bms_life_raw": locals().get("bms_life", 0),
|
||||||
"tempo_desde_ultimo_update_s": locals().get("dt", 0),
|
"tempo_desde_ultimo_update_s": max(0, round(locals().get("dt", 9999.0), 3)),
|
||||||
"qtd_alarmes_ativos": len(locals().get("alarmes_ativos", [])),
|
"qtd_alarmes_ativos": len(locals().get("alarmes_ativos", [])),
|
||||||
"alarmes_ativos": locals().get("alarmes_ativos", []),
|
"alarmes_ativos": locals().get("alarmes_ativos", []),
|
||||||
"score_com": round(locals().get("score_com", 0), 1),
|
"score_com": round(locals().get("score_com", 0), 1),
|
||||||
|
|
|
||||||
|
|
@ -1,217 +1,713 @@
|
||||||
import time
|
import time
|
||||||
from shared.enums import T_Code, StatusModulo
|
from shared.enums import T_Code, StatusModulo
|
||||||
from shared.utils import penalizar_frequencia
|
|
||||||
from health_worker.modulos.base import ModuloDiagnosticoBase
|
from health_worker.modulos.base import ModuloDiagnosticoBase
|
||||||
from health_worker.aprendizado.padrao_dinamico import PadraoDinamico
|
from health_worker.aprendizado.padrao_dinamico import PadraoDinamico
|
||||||
from shared.contexto_global_redis import ContextoGlobalRedis
|
from shared.contexto_global_redis import ContextoGlobalRedis
|
||||||
|
|
||||||
class ModuloMovimentacaoPadroes():
|
|
||||||
|
class ModuloMovimentacaoPadroes:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.padrao_tensao = PadraoDinamico("tensao", faixa_inicial=(30, 42))
|
self.padrao_tensao = PadraoDinamico("tensao", faixa_inicial=(30, 42))
|
||||||
self.padrao_corrente_motor = PadraoDinamico("corrente_motor", faixa_inicial=(0, 45))
|
self.padrao_corrente_motor = PadraoDinamico("corrente_motor", faixa_inicial=(-45, 45))
|
||||||
self.padrao_corrente_barramento = PadraoDinamico("corrente_barramento", faixa_inicial=(0, 15))
|
self.padrao_corrente_barramento = PadraoDinamico("corrente_barramento", faixa_inicial=(-10, 20))
|
||||||
self.padrao_temperatura_motor = PadraoDinamico("temperatura_motor", faixa_inicial=(10, 60))
|
self.padrao_temperatura_motor = PadraoDinamico("temperatura_motor", faixa_inicial=(10, 70))
|
||||||
self.padrao_temperatura_driver = PadraoDinamico("temperatura_driver", faixa_inicial=(10, 60))
|
self.padrao_temperatura_driver = PadraoDinamico("temperatura_driver", faixa_inicial=(10, 70))
|
||||||
|
|
||||||
|
|
||||||
class ModuloMovimentacao(ModuloDiagnosticoBase):
|
class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.t_code = T_Code.Mov
|
self.t_code = T_Code.Mov
|
||||||
self.nome = "Movimentacao"
|
self.nome = "Movimentacao"
|
||||||
self.timeout = 3 # segundos
|
self.timeout = 3
|
||||||
self.padroes = {}
|
self.padroes = {}
|
||||||
|
|
||||||
|
# Fallback caso o C# ainda não envie freq_base/freq_min/freq_uso por parâmetro.
|
||||||
|
# As chaves aqui precisam bater com Redis:
|
||||||
|
# freq.rpm, freq.tensao, freq.corrente_motor, etc.
|
||||||
|
self.freq_defaults = {
|
||||||
|
"rpm": {
|
||||||
|
"label": "rpm",
|
||||||
|
"base": 1.0,
|
||||||
|
"min": 0.45,
|
||||||
|
"peso": 1.25,
|
||||||
|
"em_uso": True,
|
||||||
|
},
|
||||||
|
"corrente_motor": {
|
||||||
|
"label": "corrente_motor",
|
||||||
|
"base": 1.0,
|
||||||
|
"min": 0.45,
|
||||||
|
"peso": 1.15,
|
||||||
|
"em_uso": True,
|
||||||
|
},
|
||||||
|
"corrente_barramento": {
|
||||||
|
"label": "corrente_barramento",
|
||||||
|
"base": 1.0,
|
||||||
|
"min": 0.45,
|
||||||
|
"peso": 1.15,
|
||||||
|
"em_uso": True,
|
||||||
|
},
|
||||||
|
"tensao": {
|
||||||
|
"label": "tensao",
|
||||||
|
"base": 0.5,
|
||||||
|
"min": 0.20,
|
||||||
|
"peso": 0.85,
|
||||||
|
"em_uso": True,
|
||||||
|
},
|
||||||
|
"temperatura": {
|
||||||
|
"label": "temperatura",
|
||||||
|
"base": 0.5,
|
||||||
|
"min": 0.20,
|
||||||
|
"peso": 0.85,
|
||||||
|
"em_uso": True,
|
||||||
|
},
|
||||||
|
"erro": {
|
||||||
|
"label": "erro",
|
||||||
|
"base": 0.5,
|
||||||
|
"min": 0.20,
|
||||||
|
"peso": 0.80,
|
||||||
|
"em_uso": True,
|
||||||
|
},
|
||||||
|
# Telemetrias úteis, mas não devem derrubar o módulo se ficarem lentas.
|
||||||
|
"ciclo_trabalho": {
|
||||||
|
"label": "ciclo_trabalho",
|
||||||
|
"base": 0.5,
|
||||||
|
"min": 0.20,
|
||||||
|
"peso": 0.35,
|
||||||
|
"em_uso": False,
|
||||||
|
},
|
||||||
|
"potencia": {
|
||||||
|
"label": "potencia",
|
||||||
|
"base": 0.5,
|
||||||
|
"min": 0.20,
|
||||||
|
"peso": 0.35,
|
||||||
|
"em_uso": False,
|
||||||
|
},
|
||||||
|
"posicao_absoluta": {
|
||||||
|
"label": "posicao_absoluta",
|
||||||
|
"base": 0.2,
|
||||||
|
"min": 0.08,
|
||||||
|
"peso": 0.20,
|
||||||
|
"em_uso": False,
|
||||||
|
},
|
||||||
|
"io_status": {
|
||||||
|
"label": "io_status",
|
||||||
|
"base": 0.2,
|
||||||
|
"min": 0.08,
|
||||||
|
"peso": 0.20,
|
||||||
|
"em_uso": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
self.oid_erros_penalidades = {
|
||||||
|
0: 0,
|
||||||
|
1: 100, # Sobretensão
|
||||||
|
2: 80, # Subtensão
|
||||||
|
3: 100, # Corrente máxima excedida
|
||||||
|
4: 80, # Temperatura MOS
|
||||||
|
5: 60, # Subtensão MCU
|
||||||
|
6: 100, # Watchdog
|
||||||
|
7: 60, # Erro SPI
|
||||||
|
8: 100, # Flash danificado
|
||||||
|
9: 30,
|
||||||
|
10: 30,
|
||||||
|
11: 30,
|
||||||
|
12: 70,
|
||||||
|
13: 100,
|
||||||
|
14: 100,
|
||||||
|
15: 10,
|
||||||
|
16: 0,
|
||||||
|
17: 0,
|
||||||
|
18: 40,
|
||||||
|
19: 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _status_por_score(self, score):
|
||||||
|
if score >= 80:
|
||||||
|
return StatusModulo.OPERANTE
|
||||||
|
if score > 0:
|
||||||
|
return StatusModulo.ALERTA
|
||||||
|
return StatusModulo.FALHA
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _to_float(valor, default=0.0):
|
||||||
|
try:
|
||||||
|
if valor is None:
|
||||||
|
return default
|
||||||
|
return float(valor)
|
||||||
|
except Exception:
|
||||||
|
return default
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _to_int(valor, default=0):
|
||||||
|
try:
|
||||||
|
if valor is None:
|
||||||
|
return default
|
||||||
|
return int(float(valor))
|
||||||
|
except Exception:
|
||||||
|
return default
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _to_bool(valor, default=False):
|
||||||
|
if isinstance(valor, bool):
|
||||||
|
return valor
|
||||||
|
if valor is None:
|
||||||
|
return default
|
||||||
|
if isinstance(valor, (int, float)):
|
||||||
|
return valor != 0
|
||||||
|
if isinstance(valor, str):
|
||||||
|
return valor.strip().lower() in ("1", "true", "sim", "yes", "on")
|
||||||
|
return default
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _as_dict(valor):
|
||||||
|
return valor if isinstance(valor, dict) else {}
|
||||||
|
|
||||||
|
def _normalizar_timestamp_segundos(self, valor):
|
||||||
|
try:
|
||||||
|
ts = float(valor or 0.0)
|
||||||
|
except Exception:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
if ts <= 0:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
# Unix ms
|
||||||
|
if ts > 1_000_000_000_000:
|
||||||
|
return ts / 1000.0
|
||||||
|
|
||||||
|
# Unix s
|
||||||
|
if ts > 1_000_000_000:
|
||||||
|
return ts
|
||||||
|
|
||||||
|
# Valor relativo/perf_counter ou inválido para comparar com time.time.
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
def _idade_modulo_s(self, modulo):
|
||||||
|
ts = self._normalizar_timestamp_segundos(modulo.get("timestamp"))
|
||||||
|
if ts <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
dt = time.time() - ts
|
||||||
|
|
||||||
|
# Pequena diferença de relógio não deve gerar alerta.
|
||||||
|
if -5.0 < dt < 0:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
if dt < -5.0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return dt
|
||||||
|
|
||||||
|
def _listar_ativos(self, dados_mov):
|
||||||
|
ativos = dados_mov.get("ativos", [])
|
||||||
|
|
||||||
|
if isinstance(ativos, list) and ativos:
|
||||||
|
return [str(x) for x in ativos]
|
||||||
|
|
||||||
|
# Fallback legado: percorre chaves numéricas.
|
||||||
|
resultado = []
|
||||||
|
for chave, valor in dados_mov.items():
|
||||||
|
if isinstance(valor, dict):
|
||||||
|
try:
|
||||||
|
int(chave)
|
||||||
|
resultado.append(str(chave))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return resultado
|
||||||
|
|
||||||
|
def _ler_freq_config(self, modulo, parametro):
|
||||||
|
freqs = self._as_dict(modulo.get("freq"))
|
||||||
|
freq_base_map = self._as_dict(modulo.get("freq_base"))
|
||||||
|
freq_min_map = self._as_dict(modulo.get("freq_min"))
|
||||||
|
freq_uso_map = self._as_dict(modulo.get("freq_uso"))
|
||||||
|
|
||||||
|
default = self.freq_defaults.get(
|
||||||
|
parametro,
|
||||||
|
{
|
||||||
|
"label": parametro,
|
||||||
|
"base": 0.5,
|
||||||
|
"min": 0.2,
|
||||||
|
"peso": 0.3,
|
||||||
|
"em_uso": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
freq_real = self._to_float(freqs.get(parametro), 0.0)
|
||||||
|
|
||||||
|
# Compatibilidade com campo antigo freq_base escalar.
|
||||||
|
freq_base_bruto = modulo.get("freq_base", None)
|
||||||
|
freq_base_legado = self._to_float(freq_base_bruto, default["base"])
|
||||||
|
|
||||||
|
if isinstance(freq_base_bruto, dict):
|
||||||
|
freq_base_legado = default["base"]
|
||||||
|
|
||||||
|
base = self._to_float(
|
||||||
|
freq_base_map.get(parametro),
|
||||||
|
freq_base_legado,
|
||||||
|
)
|
||||||
|
|
||||||
|
minimo = self._to_float(
|
||||||
|
freq_min_map.get(parametro),
|
||||||
|
default["min"],
|
||||||
|
)
|
||||||
|
|
||||||
|
if minimo <= 0 and base > 0:
|
||||||
|
minimo = base * 0.5
|
||||||
|
|
||||||
|
if base <= 0:
|
||||||
|
base = default["base"]
|
||||||
|
|
||||||
|
if minimo > base:
|
||||||
|
minimo = base * 0.5
|
||||||
|
|
||||||
|
em_uso = self._to_bool(
|
||||||
|
freq_uso_map.get(parametro),
|
||||||
|
default["em_uso"],
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"parametro": parametro,
|
||||||
|
"freq": freq_real,
|
||||||
|
"base": base,
|
||||||
|
"min": minimo,
|
||||||
|
"peso": default["peso"],
|
||||||
|
"em_uso": em_uso,
|
||||||
|
"existe_no_redis": parametro in freqs,
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _score_frequencia(freq, base, minimo):
|
||||||
|
if base <= 0:
|
||||||
|
return 100.0
|
||||||
|
|
||||||
|
if freq >= base:
|
||||||
|
return 100.0
|
||||||
|
|
||||||
|
if minimo <= 0:
|
||||||
|
minimo = base * 0.5
|
||||||
|
|
||||||
|
if freq <= 0:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
if freq <= minimo:
|
||||||
|
return max(0.0, min(50.0, 50.0 * (freq / minimo)))
|
||||||
|
|
||||||
|
faixa = base - minimo
|
||||||
|
if faixa <= 0:
|
||||||
|
return 50.0
|
||||||
|
|
||||||
|
return max(50.0, min(100.0, 50.0 + 50.0 * ((freq - minimo) / faixa)))
|
||||||
|
|
||||||
|
def _avaliar_frequencias(self, modulo):
|
||||||
|
motivos = []
|
||||||
|
detalhes = []
|
||||||
|
soma = 0.0
|
||||||
|
peso_total = 0.0
|
||||||
|
algum_parametro_avaliado = False
|
||||||
|
algum_freq_viva = False
|
||||||
|
|
||||||
|
# Avalia união entre defaults e frequências que vierem do Redis.
|
||||||
|
freqs = self._as_dict(modulo.get("freq"))
|
||||||
|
parametros = list(self.freq_defaults.keys())
|
||||||
|
for p in freqs.keys():
|
||||||
|
if p not in parametros:
|
||||||
|
parametros.append(p)
|
||||||
|
|
||||||
|
for parametro in parametros:
|
||||||
|
cfg = self._ler_freq_config(modulo, parametro)
|
||||||
|
|
||||||
|
# Se o C# disse explicitamente que não está em uso, ignora.
|
||||||
|
if not cfg["em_uso"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Se não existe no Redis e não é um default crítico, ignora para não criar alerta falso.
|
||||||
|
if not cfg["existe_no_redis"] and parametro not in self.freq_defaults:
|
||||||
|
continue
|
||||||
|
|
||||||
|
algum_parametro_avaliado = True
|
||||||
|
|
||||||
|
freq = cfg["freq"]
|
||||||
|
base = cfg["base"]
|
||||||
|
minimo = cfg["min"]
|
||||||
|
peso = cfg["peso"]
|
||||||
|
|
||||||
|
if freq > 0:
|
||||||
|
algum_freq_viva = True
|
||||||
|
|
||||||
|
score = self._score_frequencia(freq, base, minimo)
|
||||||
|
|
||||||
|
detalhes.append({
|
||||||
|
"parametro": parametro,
|
||||||
|
"freq": round(freq, 3),
|
||||||
|
"freq_base": round(base, 3),
|
||||||
|
"freq_min": round(minimo, 3),
|
||||||
|
"score": round(score, 1),
|
||||||
|
"em_uso": cfg["em_uso"],
|
||||||
|
})
|
||||||
|
|
||||||
|
soma += score * peso
|
||||||
|
peso_total += peso
|
||||||
|
|
||||||
|
if freq <= 0:
|
||||||
|
motivos.append(
|
||||||
|
f"Frequencia {parametro} ausente/zerada ({freq:.2f}/{base:.2f} Hz)."
|
||||||
|
)
|
||||||
|
elif freq < minimo:
|
||||||
|
motivos.append(
|
||||||
|
f"Frequencia {parametro} baixa ({freq:.2f}/{base:.2f} Hz, mínimo {minimo:.2f} Hz)."
|
||||||
|
)
|
||||||
|
|
||||||
|
if not algum_parametro_avaliado:
|
||||||
|
return 0.0, ["Nenhuma frequência de telemetria MOV disponível."], detalhes, False
|
||||||
|
|
||||||
|
score_final = soma / peso_total if peso_total > 0 else 0.0
|
||||||
|
return score_final, motivos, detalhes, algum_freq_viva
|
||||||
|
|
||||||
|
def _adicionar_padrao_se_valido(self, padrao, valor):
|
||||||
|
if valor is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
v = float(valor)
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Evita que zeros de boot contaminem o padrão dinâmico.
|
||||||
|
if v == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
padrao.adicionar_valor(v)
|
||||||
|
|
||||||
|
def _avaliar_valores_operacionais(self, endereco, modulo):
|
||||||
|
condicoes = []
|
||||||
|
motivos = []
|
||||||
|
penalidade_total = 0.0
|
||||||
|
|
||||||
|
mod_id = modulo.get("mod_id")
|
||||||
|
rpm = self._to_float(modulo.get("rpm"), 0.0)
|
||||||
|
rpm_sp = self._to_float(modulo.get("rpm_sp"), 0.0)
|
||||||
|
cod_erro = self._to_int(modulo.get("cod_erro"), 0)
|
||||||
|
tensao = self._to_float(modulo.get("tensao"), 0.0)
|
||||||
|
corrente_motor = self._to_float(modulo.get("corrente_motor"), 0.0)
|
||||||
|
corrente_barramento = self._to_float(modulo.get("corrente_barramento"), 0.0)
|
||||||
|
temperatura_motor = self._to_float(modulo.get("temperatura_motor"), 0.0)
|
||||||
|
temperatura_driver = self._to_float(modulo.get("temperatura_driver"), 0.0)
|
||||||
|
freado = self._to_bool(modulo.get("freado"), False)
|
||||||
|
|
||||||
|
padroes = self.padroes.get(endereco)
|
||||||
|
if not isinstance(padroes, ModuloMovimentacaoPadroes):
|
||||||
|
padroes = ModuloMovimentacaoPadroes()
|
||||||
|
self.padroes[endereco] = padroes
|
||||||
|
|
||||||
|
self._adicionar_padrao_se_valido(padroes.padrao_tensao, tensao)
|
||||||
|
self._adicionar_padrao_se_valido(padroes.padrao_corrente_motor, corrente_motor)
|
||||||
|
self._adicionar_padrao_se_valido(padroes.padrao_corrente_barramento, corrente_barramento)
|
||||||
|
self._adicionar_padrao_se_valido(padroes.padrao_temperatura_driver, temperatura_driver)
|
||||||
|
self._adicionar_padrao_se_valido(padroes.padrao_temperatura_motor, temperatura_motor)
|
||||||
|
|
||||||
|
penalidade_erro = self.oid_erros_penalidades.get(cod_erro, 0)
|
||||||
|
if penalidade_erro > 0:
|
||||||
|
penalidade_total += min(100.0, penalidade_erro)
|
||||||
|
desc = f"Erro ativo no OID: código {cod_erro}."
|
||||||
|
motivos.append(desc)
|
||||||
|
condicoes.append({
|
||||||
|
"label": "Erro OID",
|
||||||
|
"valor": cod_erro,
|
||||||
|
"severidade": int(penalidade_erro),
|
||||||
|
"descricao": desc,
|
||||||
|
"acoes": [
|
||||||
|
"Verificar código de falha do driver OID.",
|
||||||
|
"Reduzir comando de movimento se o erro persistir.",
|
||||||
|
"Inspecionar alimentação, cabos de fase e comunicação CAN."
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Erro de RPM só pesa quando existe SP significativo.
|
||||||
|
limite_sp_rpm = 30.0
|
||||||
|
limite_erro_pct = 0.30
|
||||||
|
|
||||||
|
if abs(rpm_sp) > limite_sp_rpm:
|
||||||
|
erro_percentual_rpm = abs(rpm - rpm_sp) / max(abs(rpm_sp), 1.0)
|
||||||
|
if erro_percentual_rpm > limite_erro_pct:
|
||||||
|
penalidade = min(35, int(erro_percentual_rpm * 100))
|
||||||
|
penalidade_total += penalidade
|
||||||
|
desc = (
|
||||||
|
f"RPM divergente (SP: {rpm_sp:.0f}, atual: {rpm:.0f}, "
|
||||||
|
f"erro: {erro_percentual_rpm * 100:.1f}%)."
|
||||||
|
)
|
||||||
|
motivos.append(desc)
|
||||||
|
condicoes.append({
|
||||||
|
"label": "Acompanhamento de RPM",
|
||||||
|
"valor": rpm,
|
||||||
|
"severidade": penalidade,
|
||||||
|
"descricao": desc,
|
||||||
|
"acoes": [
|
||||||
|
"Verificar se há roda travando, baixa aderência ou limitação de corrente.",
|
||||||
|
"Conferir comando enviado ao OID e leitura de RPM.",
|
||||||
|
"Reduzir velocidade de operação se houver oscilação persistente."
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
if freado and abs(rpm) > 30:
|
||||||
|
penalidade = min(35, int(abs(rpm) / 5))
|
||||||
|
penalidade_total += penalidade
|
||||||
|
desc = f"Motor aparenta movimento com freio ativo (RPM atual: {rpm:.0f})."
|
||||||
|
motivos.append(desc)
|
||||||
|
condicoes.append({
|
||||||
|
"label": "Freio / movimento",
|
||||||
|
"valor": rpm,
|
||||||
|
"severidade": penalidade,
|
||||||
|
"descricao": desc,
|
||||||
|
"acoes": [
|
||||||
|
"Verificar estado real do freio.",
|
||||||
|
"Verificar comando de parada e retorno do driver.",
|
||||||
|
"Inspecionar encoder/RPM se a roda estiver parada fisicamente."
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Limites absolutos simples, sem depender só do padrão dinâmico.
|
||||||
|
if tensao > 0 and (tensao < 28 or tensao > 45):
|
||||||
|
penalidade = 30
|
||||||
|
penalidade_total += penalidade
|
||||||
|
desc = f"Tensão MOV fora da faixa esperada: {tensao:.1f} V."
|
||||||
|
motivos.append(desc)
|
||||||
|
condicoes.append({
|
||||||
|
"label": "Tensão do driver",
|
||||||
|
"valor": tensao,
|
||||||
|
"severidade": penalidade,
|
||||||
|
"descricao": desc,
|
||||||
|
"acoes": ["Verificar alimentação dos drivers de movimento."]
|
||||||
|
})
|
||||||
|
|
||||||
|
if abs(corrente_motor) > 45:
|
||||||
|
penalidade = min(50, int(abs(corrente_motor) - 30))
|
||||||
|
penalidade_total += penalidade
|
||||||
|
desc = f"Corrente do motor elevada: {corrente_motor:.1f} A."
|
||||||
|
motivos.append(desc)
|
||||||
|
condicoes.append({
|
||||||
|
"label": "Corrente do motor",
|
||||||
|
"valor": corrente_motor,
|
||||||
|
"severidade": penalidade,
|
||||||
|
"descricao": desc,
|
||||||
|
"acoes": [
|
||||||
|
"Verificar esforço mecânico, roda travada ou terreno pesado.",
|
||||||
|
"Reduzir aceleração/velocidade se o pico persistir."
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
if temperatura_driver > 70:
|
||||||
|
penalidade = min(60, int(temperatura_driver - 50))
|
||||||
|
penalidade_total += penalidade
|
||||||
|
desc = f"Temperatura do driver elevada: {temperatura_driver:.1f} °C."
|
||||||
|
motivos.append(desc)
|
||||||
|
condicoes.append({
|
||||||
|
"label": "Temperatura do driver",
|
||||||
|
"valor": temperatura_driver,
|
||||||
|
"severidade": penalidade,
|
||||||
|
"descricao": desc,
|
||||||
|
"acoes": [
|
||||||
|
"Reduzir carga dos motores.",
|
||||||
|
"Verificar ventilação do compartimento dos drivers."
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Padrões dinâmicos entram como alerta leve/moderado, para não assustar amanhã.
|
||||||
|
checks_padrao = [
|
||||||
|
("tensão fora do padrão", tensao, padroes.padrao_tensao),
|
||||||
|
("corrente do motor fora do padrão", corrente_motor, padroes.padrao_corrente_motor),
|
||||||
|
("corrente no barramento fora do padrão", corrente_barramento, padroes.padrao_corrente_barramento),
|
||||||
|
("temperatura do driver fora do padrão", temperatura_driver, padroes.padrao_temperatura_driver),
|
||||||
|
]
|
||||||
|
|
||||||
|
for label, valor, padrao in checks_padrao:
|
||||||
|
if valor == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not padrao.esta_dentro_do_padrao(valor):
|
||||||
|
grau = min(25, int(padrao.calcular_quao_anormal(valor)))
|
||||||
|
if grau > 0:
|
||||||
|
penalidade_total += grau * 0.3
|
||||||
|
condicoes.append({
|
||||||
|
"label": "Padrão dinâmico MOV",
|
||||||
|
"valor": valor,
|
||||||
|
"severidade": grau,
|
||||||
|
"descricao": f"{label}: {valor:.1f}",
|
||||||
|
"acoes": [
|
||||||
|
"Acompanhar se o desvio persiste.",
|
||||||
|
"Comparar com outros drivers e com o esforço mecânico no momento."
|
||||||
|
]
|
||||||
|
})
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
valor_score = max(0.0, 100.0 - penalidade_total)
|
||||||
|
|
||||||
|
detalhes = {
|
||||||
|
"mod_id": mod_id,
|
||||||
|
"rpm": rpm,
|
||||||
|
"rpm_sp": rpm_sp,
|
||||||
|
"cod_erro": cod_erro,
|
||||||
|
"tensao": tensao,
|
||||||
|
"corrente_motor": corrente_motor,
|
||||||
|
"corrente_barramento": corrente_barramento,
|
||||||
|
"temperatura_motor": temperatura_motor,
|
||||||
|
"temperatura_driver": temperatura_driver,
|
||||||
|
"freado": freado,
|
||||||
|
"score_valores": round(valor_score, 1),
|
||||||
|
"penalidade_valores": round(penalidade_total, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
return valor_score, motivos, condicoes, detalhes
|
||||||
|
|
||||||
def atualizar_saude(self):
|
def atualizar_saude(self):
|
||||||
try:
|
try:
|
||||||
saude_total = 0
|
SAUDE_MIN_ALERTA = 80
|
||||||
|
|
||||||
|
dados_mov = ContextoGlobalRedis.get_modulo(self.t_code) or {}
|
||||||
|
|
||||||
|
saude_total = 0.0
|
||||||
total_drivers_em_uso = 0
|
total_drivers_em_uso = 0
|
||||||
motivos_dos_ativos = []
|
motivos_dos_ativos = []
|
||||||
saude_individual = []
|
saude_individual = []
|
||||||
|
|
||||||
SAUDE_MIN_ALERTA = 80
|
|
||||||
LIMITE_ERRO_RPM = 30
|
|
||||||
mod_conectado = False
|
mod_conectado = False
|
||||||
|
|
||||||
dados_mov = ContextoGlobalRedis.get_modulo(self.t_code)
|
ativos = self._listar_ativos(dados_mov)
|
||||||
|
|
||||||
ativos = dados_mov.get("ativos", [])
|
|
||||||
for endereco in ativos:
|
for endereco in ativos:
|
||||||
endereco = str(endereco) # Redis costuma serializar chave como string
|
endereco = str(endereco)
|
||||||
modulo = dados_mov.get(endereco)
|
modulo = dados_mov.get(endereco)
|
||||||
if not modulo:
|
|
||||||
continue # ativo listado, mas sem dados (race condition)
|
if not isinstance(modulo, dict):
|
||||||
#for endereco_str, modulo in dados_mov.items():
|
continue
|
||||||
# try:
|
|
||||||
# endereco = int(endereco_str)
|
mod_id = modulo.get("mod_id", endereco)
|
||||||
# except ValueError:
|
conectado = self._to_bool(modulo.get("conectado"), False)
|
||||||
# continue
|
comandar = self._to_bool(modulo.get("comandar"), True)
|
||||||
mod_id = modulo.get("mod_id")
|
|
||||||
FREQ_BASE = modulo.get("freq_base", 1)
|
|
||||||
FREQ_MIN = FREQ_BASE * 0.5
|
|
||||||
saude = 100
|
|
||||||
motivos = []
|
motivos = []
|
||||||
condicoes_operacionais = []
|
condicoes_operacionais = []
|
||||||
conectado = modulo.get("conectado", False)
|
detalhes = {}
|
||||||
comandar = modulo.get("comandar", True)
|
|
||||||
freqs = modulo.get("freq", {})
|
|
||||||
maior_freq = max(freqs.values() if freqs != {} else [0])
|
|
||||||
if not conectado:
|
if not conectado:
|
||||||
saude = 0
|
saude = 0.0
|
||||||
motivos.append("Desconectado")
|
motivos.append("Desconectado")
|
||||||
elif maior_freq == 0:
|
|
||||||
saude = 0
|
|
||||||
motivos.append("Sem resposta de todos os parametros (freq = 0 Hz)")
|
|
||||||
else:
|
else:
|
||||||
for label, freq in freqs.items():
|
idade = self._idade_modulo_s(modulo)
|
||||||
pen = penalizar_frequencia(freq, FREQ_BASE, FREQ_MIN, 5)
|
if idade is not None:
|
||||||
saude -= pen
|
detalhes["idade_telemetria_s"] = round(idade, 3)
|
||||||
if (freq <= FREQ_MIN):
|
|
||||||
motivos.append(f"Frequencia {label} baixa ({freq:.2f}/{FREQ_BASE} Hz, penalidade {pen}%)")
|
|
||||||
# Verificações de contexto
|
|
||||||
rpm = modulo.get("rpm", 0)
|
|
||||||
rpm_sp = modulo.get("rpm_sp", 0)
|
|
||||||
cod_erro = modulo.get("cod_erro", 0)
|
|
||||||
tensao = modulo.get("tensao", 0)
|
|
||||||
corrente_motor = modulo.get("corrente_motor", 0)
|
|
||||||
corrente_barramento = modulo.get("corrente_barramento", 0)
|
|
||||||
temperatura_motor = modulo.get("temperatura_motor", 0)
|
|
||||||
temperatura_driver = modulo.get("temperatura_driver", 0)
|
|
||||||
freado = modulo.get("freado", False)
|
|
||||||
|
|
||||||
padroes = self.padroes.get(endereco)
|
score_freq, motivos_freq, detalhes_freq, alguma_freq_viva = \
|
||||||
if not isinstance(padroes, ModuloMovimentacaoPadroes):
|
self._avaliar_frequencias(modulo)
|
||||||
padroes = ModuloMovimentacaoPadroes()
|
|
||||||
self.padroes[endereco] = padroes
|
|
||||||
padroes.padrao_tensao.adicionar_valor(tensao)
|
|
||||||
padroes.padrao_corrente_motor.adicionar_valor(corrente_motor)
|
|
||||||
padroes.padrao_corrente_barramento.adicionar_valor(corrente_barramento)
|
|
||||||
padroes.padrao_temperatura_driver.adicionar_valor(temperatura_driver)
|
|
||||||
|
|
||||||
OID_ERROS_PENALIDADES = {
|
valor_score, motivos_valores, cond_valores, detalhes_valores = \
|
||||||
0: 0,
|
self._avaliar_valores_operacionais(endereco, modulo)
|
||||||
1: 100,
|
|
||||||
2: 80,
|
|
||||||
3: 100,
|
|
||||||
4: 80,
|
|
||||||
5: 60,
|
|
||||||
6: 100,
|
|
||||||
7: 60,
|
|
||||||
8: 100,
|
|
||||||
9: 30,
|
|
||||||
10: 30,
|
|
||||||
11: 30,
|
|
||||||
12: 70,
|
|
||||||
13: 100,
|
|
||||||
14: 100,
|
|
||||||
15: 10,
|
|
||||||
16: 0,
|
|
||||||
17: 0,
|
|
||||||
18: 40,
|
|
||||||
19: 20
|
|
||||||
}
|
|
||||||
penalidade_erro = OID_ERROS_PENALIDADES.get(cod_erro, 0)
|
|
||||||
if penalidade_erro > 0:
|
|
||||||
condicoes_operacionais.append({
|
|
||||||
"valor": cod_erro,
|
|
||||||
"severidade": penalidade_erro,
|
|
||||||
"descricao": f"erro ativo: código {cod_erro} (penalidade {penalidade_erro}%)"
|
|
||||||
})
|
|
||||||
|
|
||||||
erro_percentual_rpm = abs(rpm - rpm_sp) / max(abs(rpm_sp), 1)
|
motivos.extend(motivos_freq)
|
||||||
if abs(rpm_sp) > LIMITE_ERRO_RPM and erro_percentual_rpm > (LIMITE_ERRO_RPM / 100.0):
|
motivos.extend(motivos_valores)
|
||||||
penalidade = min(int(erro_percentual_rpm * 100), LIMITE_ERRO_RPM)
|
condicoes_operacionais.extend(cond_valores)
|
||||||
condicoes_operacionais.append({
|
|
||||||
"valor": rpm,
|
|
||||||
"severidade": penalidade,
|
|
||||||
"descricao": f"RPM divergente (SP: {rpm_sp:.0f}, atual: {rpm:.0f}, erro: {erro_percentual_rpm*100:.1f}%, penalidade {penalidade}%)"
|
|
||||||
})
|
|
||||||
|
|
||||||
if freado and abs(rpm_sp) == 0 and erro_percentual_rpm > (LIMITE_ERRO_RPM / 100.0):
|
detalhes["frequencias"] = detalhes_freq
|
||||||
penalidade = min(int(erro_percentual_rpm * 100), LIMITE_ERRO_RPM)
|
detalhes.update(detalhes_valores)
|
||||||
condicoes_operacionais.append({
|
|
||||||
"valor": 1,
|
|
||||||
"severidade": penalidade,
|
|
||||||
"descricao": f"motor em movimento mesmo com freio (RPM SP: {rpm_sp}, atual: {rpm}, erro {erro_percentual_rpm*100:.1f}%, penalidade {penalidade}%)"
|
|
||||||
})
|
|
||||||
|
|
||||||
# 🔋 Tensão fora do padrão
|
|
||||||
if not padroes.padrao_tensao.esta_dentro_do_padrao(tensao):
|
|
||||||
grau = padroes.padrao_tensao.calcular_quao_anormal(tensao)
|
|
||||||
condicoes_operacionais.append({
|
|
||||||
"valor": tensao,
|
|
||||||
"severidade": grau,
|
|
||||||
"descricao": f"tensão fora do padrão: {tensao:.1f} V"
|
|
||||||
})
|
|
||||||
|
|
||||||
# ⚡ Corrente do motor elevada
|
if not alguma_freq_viva:
|
||||||
if not padroes.padrao_corrente_motor.esta_dentro_do_padrao(corrente_motor):
|
saude = 0.0
|
||||||
grau = padroes.padrao_corrente_motor.calcular_quao_anormal(corrente_motor)
|
motivos.append("Sem resposta dos parâmetros de movimentação (freq = 0 Hz).")
|
||||||
condicoes_operacionais.append({
|
else:
|
||||||
"valor": corrente_motor,
|
# Comunicação/frequência é o principal para health.
|
||||||
"severidade": grau,
|
# Valores operacionais entram forte, mas sem transformar
|
||||||
"descricao": f"corrente do motor fora do padrão: {corrente_motor:.1f} A"
|
# uma frequência levemente baixa em falha falsa.
|
||||||
})
|
saude = (0.65 * score_freq) + (0.35 * valor_score)
|
||||||
|
|
||||||
# ⚡ Corrente do barramento elevada
|
if idade is not None and idade > self.timeout:
|
||||||
if not padroes.padrao_corrente_barramento.esta_dentro_do_padrao(corrente_barramento):
|
penalidade_idade = min(40.0, (idade - self.timeout) * 8.0)
|
||||||
grau = padroes.padrao_corrente_barramento.calcular_quao_anormal(corrente_barramento)
|
saude -= penalidade_idade
|
||||||
condicoes_operacionais.append({
|
motivos.append(
|
||||||
"valor": corrente_barramento,
|
f"Telemetria MOV desatualizada ({idade:.1f}s sem atualização)."
|
||||||
"severidade": grau,
|
)
|
||||||
"descricao": f"corrente no barramento fora do padrão: {corrente_barramento:.1f} A"
|
condicoes_operacionais.append({
|
||||||
})
|
"label": "Telemetria MOV",
|
||||||
|
"valor": round(idade, 2),
|
||||||
|
"severidade": int(penalidade_idade),
|
||||||
|
"descricao": "Dados de movimentação desatualizados no Redis.",
|
||||||
|
"acoes": [
|
||||||
|
"Verificar rotina C# que publica dados MOV no Redis.",
|
||||||
|
"Verificar comunicação CAN dos drivers OID.",
|
||||||
|
"Conferir carga do Redis/health worker."
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
saude = max(0.0, min(100.0, round(saude, 1)))
|
||||||
|
|
||||||
|
status_individual = (
|
||||||
|
StatusModulo.DESCONECTADO
|
||||||
|
if not conectado
|
||||||
|
else self._status_por_score(saude)
|
||||||
|
)
|
||||||
|
|
||||||
# 🌡️ Temperatura alta (motor ou driver)
|
|
||||||
if not padroes.padrao_temperatura_driver.esta_dentro_do_padrao(temperatura_driver):
|
|
||||||
grau = padroes.padrao_temperatura_driver.calcular_quao_anormal(temperatura_driver)
|
|
||||||
condicoes_operacionais.append({
|
|
||||||
"valor": temperatura_driver,
|
|
||||||
"severidade": grau,
|
|
||||||
"descricao": f"temperatura elevada: motor {temperatura_motor:.1f}°C, driver {temperatura_driver:.1f}°C"
|
|
||||||
})
|
|
||||||
saude = max(saude, 0)
|
|
||||||
saude_mod = {
|
saude_mod = {
|
||||||
"id": endereco,
|
"id": endereco,
|
||||||
"label": mod_id,
|
"label": mod_id,
|
||||||
"status": (StatusModulo.DESCONECTADO if not conectado else StatusModulo.OPERANTE if saude >= SAUDE_MIN_ALERTA else StatusModulo.ALERTA if saude > 0 else StatusModulo.FALHA).value,
|
"status": status_individual.value,
|
||||||
"saude": saude,
|
"saude": saude,
|
||||||
"motivos": motivos,
|
"motivos": motivos,
|
||||||
"condicoes_operacionais": condicoes_operacionais,
|
"condicoes_operacionais": condicoes_operacionais,
|
||||||
"em_uso": comandar
|
"em_uso": comandar,
|
||||||
|
"detalhes": detalhes,
|
||||||
}
|
}
|
||||||
|
|
||||||
saude_individual.append(saude_mod)
|
saude_individual.append(saude_mod)
|
||||||
|
|
||||||
if comandar:
|
if comandar:
|
||||||
saude_total += saude
|
saude_total += saude
|
||||||
total_drivers_em_uso += 1
|
total_drivers_em_uso += 1
|
||||||
motivos_dos_ativos.extend([f"Driver {endereco}: {m}" for m in motivos])
|
motivos_dos_ativos.extend(
|
||||||
|
[f"Driver {endereco}: {m}" for m in motivos]
|
||||||
|
)
|
||||||
|
|
||||||
modulo["saude"] = saude_mod
|
modulo["saude"] = saude_mod
|
||||||
|
|
||||||
if conectado:
|
if conectado:
|
||||||
mod_conectado = True
|
mod_conectado = True
|
||||||
|
|
||||||
saude_individual.sort(key=lambda x: x["id"])
|
saude_individual.sort(key=lambda x: str(x["id"]))
|
||||||
|
|
||||||
saude_final = (saude_total // total_drivers_em_uso) if total_drivers_em_uso > 0 else 0
|
if total_drivers_em_uso > 0:
|
||||||
|
saude_final = round(saude_total / total_drivers_em_uso, 1)
|
||||||
|
else:
|
||||||
|
saude_final = 0.0
|
||||||
|
|
||||||
status = StatusModulo.OPERANTE
|
status = StatusModulo.OPERANTE
|
||||||
|
|
||||||
if not mod_conectado:
|
if not mod_conectado:
|
||||||
status = StatusModulo.DESCONECTADO
|
status = StatusModulo.DESCONECTADO
|
||||||
elif saude_final <= 0:
|
elif saude_final <= 0:
|
||||||
status = StatusModulo.FALHA
|
status = StatusModulo.FALHA
|
||||||
elif saude_final < SAUDE_MIN_ALERTA or any(saude["saude"] < SAUDE_MIN_ALERTA for saude in saude_individual):
|
elif (
|
||||||
|
saude_final < SAUDE_MIN_ALERTA or
|
||||||
|
any(item["saude"] < SAUDE_MIN_ALERTA and item.get("em_uso", True)
|
||||||
|
for item in saude_individual)
|
||||||
|
):
|
||||||
status = StatusModulo.ALERTA
|
status = StatusModulo.ALERTA
|
||||||
|
|
||||||
saude_geral = {
|
saude_geral = {
|
||||||
"conectado": mod_conectado,
|
"conectado": mod_conectado,
|
||||||
"status": status.value,
|
"status": status.value,
|
||||||
"saude": saude_final,
|
"saude": saude_final,
|
||||||
"motivos": motivos_dos_ativos,
|
"motivos": motivos_dos_ativos,
|
||||||
"saude_individual": saude_individual
|
"saude_individual": saude_individual,
|
||||||
|
"detalhes": {
|
||||||
|
"drivers_ativos": ativos,
|
||||||
|
"drivers_em_uso": total_drivers_em_uso,
|
||||||
|
"modelo_frequencia": "por_parametro",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#print(saude_geral)
|
|
||||||
|
|
||||||
ContextoGlobalRedis.atualizar_ctx_dict(
|
ContextoGlobalRedis.atualizar_ctx_dict(
|
||||||
ContextoGlobalRedis.ModKey(self.t_code),
|
ContextoGlobalRedis.ModKey(self.t_code),
|
||||||
saude=saude_geral
|
saude=saude_geral
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Erro ao atualizar saude do modulo {self.t_code.name}: {e}")
|
print(f"Erro ao atualizar saude do modulo {self.t_code.name}: {e}")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue