Compare commits

..

2 Commits

Author SHA1 Message Date
Diego Freitas 777993dfbb ajustado asincronia ao atualizar saude do IPB 2025-12-15 10:42:45 -03:00
Diego Freitas db72144faa Correcao carregamento parametros atuador 2025-12-15 10:41:05 -03:00
7 changed files with 654 additions and 22 deletions

View File

@ -56,9 +56,9 @@ namespace AgroBase.Models.Modules
};
//public int QuantidadeBicos { get; set; } = 4;
public double DensidadeHerbicida { get; set; } = 1.0;
public List<AtuadorBicoModel> BicosPulverizadores { get; set; } = new List<AtuadorBicoModel>();
public List<AtuadorBombaModel> BombasPressurizadoras { get; set; } = new List<AtuadorBombaModel>();
public List<SensorModel> Sensores { get; set; } = new List<SensorModel>();
public List<AtuadorBicoModel> BicosPulverizadores { get; set; }
public List<AtuadorBombaModel> BombasPressurizadoras { get; set; }
public List<SensorModel> Sensores { get; set; }
public string ScriptDeteccaoErvas { get; set; } = PythonService.ScriptWeedDetector;
public AsyncTaskTimerModel tmrRegistrador;
@ -67,7 +67,7 @@ namespace AgroBase.Models.Modules
public AtuadorMensagemJsonModel DadosLeitura { get; set; } = new AtuadorMensagemJsonModel();
public AtuHandler _AtuHandler = new AtuHandler();
public SensorModel SensorAnguloBarraEsquerda
private SensorModel SensorAnguloBarraEsquerda
{
get
{
@ -75,7 +75,7 @@ namespace AgroBase.Models.Modules
return sMAG;
}
}
public SensorModel SensorAnguloBarraDireita
private SensorModel SensorAnguloBarraDireita
{
get
{
@ -83,7 +83,7 @@ namespace AgroBase.Models.Modules
return sMAG;
}
}
public SensorModel SensorAnguloBarraAltura
private SensorModel SensorAnguloBarraAltura
{
get
{
@ -1161,7 +1161,7 @@ namespace AgroBase.Models.Modules
return ValoresLeituras.OrderByDescending(x => x.atual.lidoEm).FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
}
}
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; } = new List<SensorValoresLeituraModel>();
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
@ -1268,7 +1268,7 @@ namespace AgroBase.Models.Modules
return !Mandatorio || (Comandar && Inicializado);
}
}
public List<FuncoesPinout> Funcoes { get; set; } = new List<FuncoesPinout>();
public List<FuncoesPinout> Funcoes { get; set; }
public bool Inicializado { get; set; }
public DateTime UltimaLeitura
{
@ -1277,7 +1277,7 @@ namespace AgroBase.Models.Modules
return ValoresLeituras.OrderByDescending(x => x.atual.lidoEm).FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
}
}
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; } = new List<SensorValoresLeituraModel>();
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }

View File

@ -2462,8 +2462,8 @@ namespace AgroBase.Models.Modules
}
}
public List<FuncoesPinout> Funcoes { get; set; }
public List<SensorParametroModel> Parametros { get; set;} = new List<SensorParametroModel>();
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; } = new List<SensorValoresLeituraModel>();
public List<SensorParametroModel> Parametros { get; set; }
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel Pinout, bool conectar, T_Code Dispositivo)
{
@ -2513,7 +2513,7 @@ namespace AgroBase.Models.Modules
return ValoresLeituras.OrderByDescending(x => x.atual.lidoEm).FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
}
}
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; } = new List<SensorValoresLeituraModel>();
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
{
@ -2571,7 +2571,7 @@ namespace AgroBase.Models.Modules
return ValoresLeituras.OrderByDescending(x => x.atual.lidoEm).FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
}
}
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; } = new List<SensorValoresLeituraModel>();
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
{
@ -2630,7 +2630,7 @@ namespace AgroBase.Models.Modules
return ValoresLeituras.OrderByDescending(x => x.atual.lidoEm).FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
}
}
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; } = new List<SensorValoresLeituraModel>();
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
{

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,624 @@
import time
import threading
import statistics
import socket
import psutil
import subprocess
from collections import deque
import paho.mqtt.client as mqtt
from shared.contexto_global_redis import ContextoGlobalRedis
from shared.enums import StatusModulo, T_Code
from health_worker.modulos.base import ModuloDiagnosticoBase
class ModuloIPBribge(ModuloDiagnosticoBase):
def __init__(self, window_size: int = 5):
self.t_code = T_Code.Ipb
self.nome = "IP_Brigde"
self.timeout = 5
self._thread_saude = None
self._running = False
self.nic_name = None
self.window_size = window_size
self.rtts = deque(maxlen=window_size) # ping válidos (ms)
self.timeouts = deque(maxlen=window_size) # True/False por tentativa
self.loses = deque(maxlen=window_size) # True/False por tentativa
self.last_nic_counters = None
self.nic_error_rates = deque(maxlen=window_size)
self.last_bw_counters = None
self.last_bw_ts = None
self.bw_rx_mbps = deque(maxlen=window_size)
self.bw_tx_mbps = deque(maxlen=window_size)
self.last_heartbeat_ts = time.time() # atualize isso de fora
self.rover_id = None
self._mqtt_conectado = False
self.sub = False
self._start_mqtt_heartbeat()
def atualizar_saude(self):
if self._running:
return
self._running = True
self._thread_saude = threading.Thread(target=self._job_saude, daemon=True)
self._thread_saude.start()
def _job_saude(self):
try:
self.atualizar_saude_interno()
except Exception as e:
print(f"Erro ao atualizar saude: {e}")
finally:
self._running = False
def _start_mqtt_heartbeat(self):
try:
if self._mqtt_conectado:
return
base_ip = self.get_base_ip()
if base_ip is None:
self._mqtt_conectado = False
return
self._mqtt = mqtt.Client()
self._mqtt.on_connect = self._on_connect
self._mqtt.on_message = self._on_message
self._mqtt.on_disconnect = self._on_disconnect
self._mqtt.connect(base_ip, 1883, 60)
self._mqtt.loop_start()
except:
pass
#print("Erro ao se conectar no broker mqtt")
def _on_connect(self, client, userdata, flags, rc):
if rc == 0:
print("[HEARTBEAT] MQTT conectado")
self._mqtt_conectado = True
self._reset_janelas()
self.rover_id = ContextoGlobalRedis.get_equipamento().get("serial_number")
if self.sub == False:
topic = f"agrobot/v1/rover/{self.rover_id}/heartbeat"
client.subscribe(topic)
print("[HEARTBEAT] Subscribado em:", topic)
self.sub = True
else:
print("Erro ao conectar MQTT:", rc)
def _on_disconnect(self, client, userdata, rc):
print("[HEARTBEAT] MQTT desconectado!", rc)
self._mqtt_conectado = False
self.sub = False
# se rc != 0 significa desconexão inesperada
if rc != 0:
print("[HEARTBEAT] Desconexão inesperada — pode ter perdido o link 900 MHz")
# Marca como "sem heartbeat" instantâneo (opcional)
# Aqui podemos forçar atraso grande
self.last_heartbeat_ts = 0
def _on_message(self, client, userdata, msg):
topic = msg.topic
if topic == f"agrobot/v1/rover/{self.rover_id}/heartbeat":
self.last_heartbeat_ts = time.time()
#print("[HEARTBEAT] recebido")
def _reset_janelas(self):
self.rtts.clear()
self.timeouts.clear()
self.loses.clear()
self.nic_error_rates.clear()
self.bw_rx_mbps.clear()
self.bw_tx_mbps.clear()
self.last_nic_counters = None
self.last_bw_counters = None
self.last_bw_ts = None
def _status_por_score(self, score: float) -> StatusModulo:
if score >= 80:
return StatusModulo.OPERANTE
elif score >= 50:
return StatusModulo.ALERTA
else:
return StatusModulo.FALHA
def get_base_ip(self):
return ContextoGlobalRedis.get_equipamento().get("base_ip")
def descobrir_nic_para_base(self) -> str | None:
try:
base_ip = self.get_base_ip()
if base_ip is None:
return None
# Abre socket UDP só para descobrir o IP local usado na rota
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((base_ip, 80)) # porta não importa
local_ip = s.getsockname()[0]
s.close()
except Exception as e:
print("[Ponte IP] Erro ao descobrir IP local da rota:", e)
return None
# Agora, com o local_ip, encontrar qual NIC possui esse IP
addrs = psutil.net_if_addrs()
for nic_name, addr_list in addrs.items():
for addr in addr_list:
if addr.family == socket.AF_INET and addr.address == local_ip:
return nic_name
return None
def _update_nic_bandwidth(self):
if self.nic_name is None:
self.nic_name = self.descobrir_nic_para_base()
if self.nic_name is None:
return
counters = psutil.net_io_counters(pernic=True).get(self.nic_name)
if not counters:
return
now = time.time()
if self.last_bw_counters is not None and self.last_bw_ts is not None:
dt = now - self.last_bw_ts
if dt > 0:
delta_rx = counters.bytes_recv - self.last_bw_counters.bytes_recv
delta_tx = counters.bytes_sent - self.last_bw_counters.bytes_sent
# bytes → bits → Mbit/s
rx_mbps = (delta_rx * 8.0) / (dt * 1_000_000.0)
tx_mbps = (delta_tx * 8.0) / (dt * 1_000_000.0)
self.bw_rx_mbps.append(rx_mbps)
self.bw_tx_mbps.append(tx_mbps)
self.last_bw_counters = counters
self.last_bw_ts = now
def _ping_once(self):
"""
Retorna RTT em ms se ok, ou None se timeout.
Aqui exemplo pra Windows usando 'ping -n 1'.
Ajuste pro teu ambiente se precisar.
"""
try:
base_ip = self.get_base_ip()
if base_ip is None:
return None, None
# timeout de 1000 ms
proc = subprocess.run(
["ping", "-n", "5", "-w", "500", base_ip],
capture_output=True, text=True
)
if proc.returncode != 0:
#print("timeout")
return None, 100
#print(proc.stdout)
perda = None
media_tempo = None
for line in proc.stdout.splitlines():
line = line.lower()
if ("%" in line and perda is None):
perda = line.split('(')[1].split('%')[0]
perda = float(perda) if perda.isdigit() else None
elif (" = " in line and "ms" in line and media_tempo is None):
media_tempo = line.split(' = ')[3].split('ms')[0]
media_tempo = float(media_tempo) if media_tempo.isdigit() else None
if perda is not None and media_tempo is not None:
break
return media_tempo, perda
except Exception:
print("erro timeout")
return None, 100
def _update_nic_errors(self):
if self.nic_name is None:
self.nic_name = self.descobrir_nic_para_base()
if self.nic_name is None:
return
counters = psutil.net_io_counters(pernic=True).get(self.nic_name)
if not counters:
return
if self.last_nic_counters is not None:
delta_err = (counters.errin - self.last_nic_counters.errin) + \
(counters.errout - self.last_nic_counters.errout)
delta_pkts = (counters.packets_sent - self.last_nic_counters.packets_sent) + \
(counters.packets_recv - self.last_nic_counters.packets_recv)
if delta_pkts > 0:
# erros por mil pacotes
rate = (delta_err / delta_pkts) * 1000.0
self.nic_error_rates.append(rate)
self.last_nic_counters = counters
def _metric_scores(self):
# valores brutos (default)
avg_rtt = None
loss_pct = 100.0
jitter = 0.0
err_rate = 0.0
atraso = time.time() - self.last_heartbeat_ts
# LATÊNCIA
if self.rtts:
avg_rtt = statistics.mean(self.rtts)
if avg_rtt <= 30:
latency_score = 100
elif avg_rtt <= 50:
latency_score = 80
elif avg_rtt <= 100:
latency_score = 50
elif avg_rtt <= 200:
latency_score = 20
else:
latency_score = 0
else:
latency_score = 0
# TIMEOUT
if self.timeouts:
timeout_pct = (sum(self.timeouts) / len(self.timeouts)) * 100.0
else:
timeout_pct = 100.0
if timeout_pct <= 5:
timeout_score = 100
elif timeout_pct <= 10:
timeout_score = 80
elif timeout_pct <= 15:
timeout_score = 50
elif timeout_pct <= 30:
timeout_score = 20
else:
timeout_score = 0
# LOSS
if self.loses:
loss_pct = (sum(self.loses) / len(self.loses))
else:
loss_pct = 100.0
if loss_pct <= 2:
loss_score = 100
elif loss_pct <= 5:
loss_score = 80
elif loss_pct <= 8:
loss_score = 50
elif loss_pct <= 15:
loss_score = 20
else:
loss_score = 0
# JITTER
if len(self.rtts) > 1:
jitter = statistics.pstdev(self.rtts)
if jitter <= 10:
jitter_score = 100
elif jitter <= 20:
jitter_score = 70
elif jitter <= 40:
jitter_score = 30
else:
jitter_score = 0
else:
jitter = 0.0
# Sem dados suficientes, melhor considerar "desconhecido" => score neutro/baixo
jitter_score = 0
# NIC ERRORS
if self.nic_error_rates:
err_rate = statistics.mean(self.nic_error_rates)
else:
err_rate = 0.0
if err_rate <= 0.1:
nic_score = 100
elif err_rate <= 1:
nic_score = 70
elif err_rate <= 5:
nic_score = 40
else:
nic_score = 0
# HEARTBEAT (score usando "atraso")
if atraso <= 1.5:
hb_score = 100
elif atraso <= 2:
hb_score = 80
elif atraso <= 5:
hb_score = 30
else:
hb_score = 0
# retorna scores + brutos
return (
latency_score, timeout_score, loss_score, jitter_score, nic_score, hb_score,
avg_rtt, timeout_pct, loss_pct, jitter, err_rate, atraso
)
def atualizar_saude_interno(self):
try:
self._start_mqtt_heartbeat()
SAUDE_MIN_ALERTA = 80
motivos = []
condicoes = []
saude_individual = []
conectado = self.get_base_ip() is not None and self.nic_name is not None and self._mqtt_conectado
(rtt, loss) = self._ping_once()
#print(f"rtt: {rtt}, loss: {loss}")
self.timeouts.append(loss == 100)
if rtt is not None:
self.rtts.append(rtt)
if loss is not None:
self.loses.append(loss)
self._update_nic_errors()
self._update_nic_bandwidth()
(ls, tmout, los, js, ns, hbs, avg_rtt, tmout_pct, loss_pct, jitter, err_rate, atraso) = self._metric_scores()
health = (
0.25 * ls +
0.10 * tmout +
0.30 * los +
0.15 * js +
0.10 * ns +
0.10 * hbs
)
saude = round(health, 1)
# -------- SAÚDE INDIVIDUAL / CONDIÇÕES / MOTIVOS --------
# 1) Latência
cond_lat = []
if ls < SAUDE_MIN_ALERTA:
severidade = int(max(0, 100 - ls))
c = {
"label": "Latência ICMP",
"valor": avg_rtt if avg_rtt is not None else -1,
"severidade": severidade,
"descricao": "Latência alta na comunicação com a base",
"acoes": [
"Reduzir taxa de envio de telemetria",
"Verificar alinhamento das antenas 900 MHz",
"Verificar interferência ou obstáculos entre base e rover"
]
}
condicoes.append(c)
cond_lat.append(c)
motivos.append(
f"Latência ICMP elevada "
f"({avg_rtt:.0f} ms, score {ls:.0f})."
if avg_rtt is not None else
f"Latência ICMP comprometida (score {ls:.0f})."
)
saude_individual.append({
"id": "ip_latency",
"label": "Latência ICMP",
"status": self._status_por_score(ls).value,
"saude": round(ls, 1),
"motivos": [m for m in motivos if "Latência" in m],
"condicoes_operacionais": cond_lat,
"em_uso": True,
})
# 2) Timeouts
cond_timeout = []
if tmout < SAUDE_MIN_ALERTA:
severidade = int(max(0, 100 - tmout))
c = {
"label": "Timeout",
"valor": round(tmout_pct, 2),
"severidade": severidade,
"descricao": "Timeout na comunicação ICMP",
"acoes": [
"Checar conectores e cabo da ponte 900 MHz",
"Verificar nível de ruído / interferência no enlace",
"Reduzir banda utilizada (streaming de vídeo, logs, etc.)"
]
}
condicoes.append(c)
cond_timeout.append(c)
motivos.append(
f"Timeout elevado ({tmout_pct:.1f}%, score {tmout:.0f})."
)
saude_individual.append({
"id": "ip_timeout",
"label": "Timeout",
"status": self._status_por_score(tmout).value,
"saude": round(tmout, 1),
"motivos": [m for m in motivos if "Timeout" in m],
"condicoes_operacionais": cond_timeout,
"em_uso": True,
})
# 2) Perda de pacotes
cond_loss = []
if los < SAUDE_MIN_ALERTA:
severidade = int(max(0, 100 - los))
c = {
"label": "Perda de Pacotes",
"valor": round(loss_pct, 2),
"severidade": severidade,
"descricao": "Perda de pacotes na comunicação ICMP",
"acoes": [
"Checar conectores e cabo da ponte 900 MHz",
"Verificar nível de ruído / interferência no enlace",
"Reduzir banda utilizada (streaming de vídeo, logs, etc.)"
]
}
condicoes.append(c)
cond_loss.append(c)
motivos.append(
f"Perda de pacotes elevada ({loss_pct:.1f}%, score {los:.0f})."
)
saude_individual.append({
"id": "ip_loss",
"label": "Perda de pacotes",
"status": self._status_por_score(los).value,
"saude": round(los, 1),
"motivos": [m for m in motivos if "Perda de pacotes" in m],
"condicoes_operacionais": cond_loss,
"em_uso": True,
})
# 3) Jitter
cond_jit = []
if js < SAUDE_MIN_ALERTA:
severidade = int(max(0, 100 - js))
c = {
"label": "Jitter (variação de latência)",
"valor": round(jitter, 2),
"severidade": severidade,
"descricao": "Variação de latência acima do ideal",
"acoes": [
"Evitar tráfego pesado na mesma rede da ponte",
"Reduzir taxa de envio de mensagens de controle",
"Verificar qualidade do enlace 900 MHz"
]
}
condicoes.append(c)
cond_jit.append(c)
motivos.append(
f"Jitter elevado ({jitter:.1f} ms, score {js:.0f})."
)
saude_individual.append({
"id": "ip_jitter",
"label": "Jitter da conexão",
"status": self._status_por_score(js).value,
"saude": round(js, 1),
"motivos": [m for m in motivos if "Jitter" in m],
"condicoes_operacionais": cond_jit,
"em_uso": True,
})
# 4) Erros na NIC
cond_nic = []
if ns < SAUDE_MIN_ALERTA:
severidade = int(max(0, 100 - ns))
c = {
"label": "Erros na interface de rede",
"valor": round(err_rate, 3),
"severidade": severidade,
"descricao": "Erros na placa de rede ligada à ponte 900 MHz",
"acoes": [
"Verificar cabo de rede e conectores",
"Checar se há colisões ou problemas físicos no link",
"Substituir cabo ou porta de switch se necessário"
]
}
condicoes.append(c)
cond_nic.append(c)
motivos.append(
f"Erros na NIC acima do normal ({err_rate:.3f} erros/mil pacotes, score {ns:.0f})."
)
saude_individual.append({
"id": "ip_nic_errors",
"label": "Erros da interface de rede",
"status": self._status_por_score(ns).value,
"saude": round(ns, 1),
"motivos": [m for m in motivos if "NIC" in m or "interface de rede" in m],
"condicoes_operacionais": cond_nic,
"em_uso": True,
})
# 5) Heartbeat
cond_hb = []
if hbs < SAUDE_MIN_ALERTA:
severidade = int(max(0, 100 - hbs))
c = {
"label": "Atraso de heartbeat",
"valor": round(atraso, 2),
"severidade": severidade,
"descricao": "Atraso na recepção de heartbeat do rover",
"acoes": [
"Verificar estado do serviço de telemetria no rover",
"Checar fila de mensagens MQTT/Redis",
"Garantir prioridade para mensagens de controle"
]
}
condicoes.append(c)
cond_hb.append(c)
motivos.append(
f"Heartbeat atrasado ({atraso:.1f} s sem atualização, score {hbs:.0f})."
)
saude_individual.append({
"id": "ip_heartbeat",
"label": "Heartbeat do rover",
"status": self._status_por_score(hbs).value,
"saude": round(hbs, 1),
"motivos": [m for m in motivos if "Heartbeat" in m],
"condicoes_operacionais": cond_hb,
"em_uso": True,
})
rx_mbps = statistics.mean(self.bw_rx_mbps) if self.bw_rx_mbps else 0.0
tx_mbps = statistics.mean(self.bw_tx_mbps) if self.bw_tx_mbps else 0.0
bw_total = rx_mbps + tx_mbps
# -------- STATUS GERAL DO MÓDULO --------
status = StatusModulo.OPERANTE
if not conectado:
status = StatusModulo.DESCONECTADO
elif saude <= 0:
status = StatusModulo.FALHA
elif saude < SAUDE_MIN_ALERTA:
status = StatusModulo.ALERTA
payload = {
"conectado": conectado,
"status": status.value,
"saude": saude,
"motivos": motivos,
"saude_individual": saude_individual,
"condicoes_operacionais": condicoes,
"detalhes": {
"ls": ls,
"tmout": tmout,
"los": los,
"js": js,
"ns": ns,
"hbs": hbs,
"avg_rtt": avg_rtt,
"tmout_pct": tmout_pct,
"loss_pct": loss_pct,
"jitter": jitter,
"err_rate": err_rate,
"atraso_hb": atraso,
"rx_mbps": rx_mbps,
"tx_mbps": tx_mbps,
"bw_total_mbps": bw_total
}
}
ContextoGlobalRedis.atualizar_ctx_dict(
ContextoGlobalRedis.ModKey(self.t_code),
saude=payload
)
except Exception as e:
print(f"Erro ao atualizar saude do modulo {self.t_code.name}: {e}")

View File

@ -199,8 +199,14 @@ class ContextoGlobalRedis:
@classmethod
def atualizar_dados_operacao(cls):
cls._atualizar_operacao_liberada()
cls._atualiza_status_operacao()
try:
cls._atualizar_operacao_liberada()
except Exception as e:
print(f"Erro ao atualizar operacao liberada: {e}")
try:
cls._atualiza_status_operacao()
except Exception as e:
print(f"Erro ao atualizar status da operacao: {e}")
@classmethod
def _atualizar_operacao_liberada(cls):
@ -212,7 +218,8 @@ class ContextoGlobalRedis:
modulos_opcionais = set(_operacao.get("modulos_opcionais", []))
emergencia = _operacao.get("emergencia", False)
pausa = _operacao.get("pausa", False)
trajetoria_liberada = _contexto.get("Trajetoria", {}).get("CorredorAtual", {}).get("liberado", False)
_t = _contexto.get("Trajetoria", {})
trajetoria_liberada = True if _t is None or _t == "" else _t.get("CorredorAtual", {}).get("liberado", False)
modulos_presentes = set()
status_modulos = []
@ -518,13 +525,14 @@ class ContextoGlobalRedis:
if status_atual != StatusOperacao.EmAndamento:
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status=StatusOperacao.EmAndamento.value)
except Exception as e:
print(f"Erro ao atualizar status da operacao: {e}")
finally:
pass
#_operacao = cls.get_operacao()
#status = _operacao.get("status")
#liberado = _operacao.get("liberado")
#print(f"Status Atual: {status.name}, Liberado: {liberado}")
#print(f"Status Atual: {StatusOperacao(status).name}, Liberado: {liberado}")
@classmethod
def _iniciar_operacao(cls):