Ajustes de conectividade mqtt
This commit is contained in:
parent
ca86e1b1e2
commit
8ee9368c8b
|
|
@ -172,7 +172,7 @@ namespace AgroBase
|
|||
|
||||
tkbVelocidade.Minimum = 0;
|
||||
tkbVelocidade.Maximum = 100;
|
||||
FuncoesGlobais.PreencheValorTrackBar(tkbVelocidade, Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento);
|
||||
FuncoesGlobais.PreencheValorTrackBar(tkbVelocidade, Variaveis.OperacaoEmAndamento.Parametros.Controle?.DirVelocidadeMovimento ?? 0);
|
||||
|
||||
tkbAngulo.Minimum = 0;
|
||||
tkbAngulo.Maximum = 90;
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ namespace AgroBase
|
|||
_Controle.Angulo = solto ? 0 : pControle.DirAnguloMaximo * percent;
|
||||
break;
|
||||
case T_Code.Mov:
|
||||
_Controle.PercentualVelocidadeSP = solto ? 0 : pControle.MovVelocidadeSErvasPercent * percent;
|
||||
_Controle.PercentualVelocidadeSP = solto ? 0 : Math.Max(pControle.MovVelocidadeCErvasPercent, pControle.MovVelocidadeSErvasPercent * percent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,10 +338,12 @@ namespace AgroBase.Models
|
|||
OperacaoParametrosModel p = new OperacaoParametrosModel()
|
||||
{
|
||||
Modo = Modo,
|
||||
Descricao = $"{Modo} - Padrão",
|
||||
QtdCamerasSolo = VariaveisEquipamento.QuantidadeCamerasSolo,
|
||||
QtdBicos = VariaveisEquipamento.QuantidadeBicosPulverizadores,
|
||||
CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio,
|
||||
RoverId = VariaveisEquipamento.Parametros.serial_number,
|
||||
IP = VariaveisEquipamento.Parametros.rover_ip,
|
||||
RuasPercorrer = null,
|
||||
Mapa = null,
|
||||
DadosLeitura = new OperacaoParametrosDadosModel(),
|
||||
|
|
@ -382,7 +384,7 @@ namespace AgroBase.Models
|
|||
MpcMatrizCusto = false,
|
||||
MpcHorizonte = 4.0,
|
||||
|
||||
MovVelocidadeSErvasPercent = 100,
|
||||
MovVelocidadeSErvasPercent = 50,
|
||||
MovVelocidadeCErvasPercent = 15,
|
||||
DirAnguloMaximo = 25,
|
||||
DirVelocidadeMovimento = 40,
|
||||
|
|
@ -832,6 +834,7 @@ namespace AgroBase.Models
|
|||
if (isagrobase)
|
||||
{
|
||||
Variaveis.OperacaoEmAndamento.Parametros = p;
|
||||
Variaveis.OperacaoEmAndamento.DefinirComponentesEmUso();
|
||||
Variaveis.OperacaoEmAndamento.Trajetoria = new TrajetoriaMapaOperacaoModel(new List<List<GPSModel>>());
|
||||
Variaveis.OperacaoEmAndamento.Sensoriamento = new OperacaoSensoriamentoLogModel();
|
||||
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
|
||||
|
|
@ -891,36 +894,38 @@ namespace AgroBase.Models
|
|||
case T_Code.Mov:
|
||||
foreach (var c in m.ComponentesEmUso)
|
||||
{
|
||||
var d = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.MovMotor.Mod_ID == c.Key).MovMotor;
|
||||
d.Comandar = c.Value.Item2;
|
||||
var d = Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.FirstOrDefault(x => x?.MovMotor?.Mod_ID == c.Key)?.MovMotor;
|
||||
if (d != null)
|
||||
d.Comandar = c.Value.Item2;
|
||||
}
|
||||
break;
|
||||
case T_Code.Dir:
|
||||
foreach (var c in m.ComponentesEmUso)
|
||||
{
|
||||
var d = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.DirMotor.Mod_ID == c.Key).DirMotor;
|
||||
d.Comandar = c.Value.Item2;
|
||||
var d = Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.FirstOrDefault(x => x?.DirMotor?.Mod_ID == c.Key)?.DirMotor;
|
||||
if (d != null)
|
||||
d.Comandar = c.Value.Item2;
|
||||
}
|
||||
break;
|
||||
case T_Code.Atu:
|
||||
var da = Variaveis.OperacaoEmAndamento.DispAtu.Dados;
|
||||
var da = Variaveis.OperacaoEmAndamento.DispAtu?.Dados;
|
||||
foreach (var c in m.ComponentesEmUso)
|
||||
{
|
||||
var s = da.Sensores.FirstOrDefault(x => x.ID == c.Key);
|
||||
var s = da?.Sensores?.FirstOrDefault(x => x.ID == c.Key);
|
||||
if (s != null)
|
||||
{
|
||||
s.Mandatorio = c.Value.Item1;
|
||||
s.Aferir = c.Value.Item2;
|
||||
continue;
|
||||
}
|
||||
var bc = da.BicosPulverizadores.FirstOrDefault(x => x.ID == c.Key);
|
||||
var bc = da?.BicosPulverizadores?.FirstOrDefault(x => x.ID == c.Key);
|
||||
if (bc != null)
|
||||
{
|
||||
bc.Mandatorio = c.Value.Item1;
|
||||
bc.Comandar = c.Value.Item2;
|
||||
continue;
|
||||
}
|
||||
var bo = da.BombasPressurizadoras.FirstOrDefault(x => x.ID == c.Key);
|
||||
var bo = da?.BombasPressurizadoras?.FirstOrDefault(x => x.ID == c.Key);
|
||||
if (bo != null)
|
||||
{
|
||||
bo.Mandatorio = c.Value.Item1;
|
||||
|
|
@ -930,31 +935,31 @@ namespace AgroBase.Models
|
|||
}
|
||||
break;
|
||||
case T_Code.Sen:
|
||||
var ds = Variaveis.OperacaoEmAndamento.DispSen.Dados;
|
||||
var ds = Variaveis.OperacaoEmAndamento.DispSen?.Dados;
|
||||
foreach (var c in m.ComponentesEmUso)
|
||||
{
|
||||
var s = ds.Sensores.FirstOrDefault(x => x.ID == c.Key);
|
||||
var s = ds?.Sensores?.FirstOrDefault(x => x.ID == c.Key);
|
||||
if (s != null)
|
||||
{
|
||||
s.Mandatorio = c.Value.Item1;
|
||||
s.Aferir = c.Value.Item2;
|
||||
continue;
|
||||
}
|
||||
var sv = ds.Servos.FirstOrDefault(x => x.ID == c.Key);
|
||||
var sv = ds?.Servos?.FirstOrDefault(x => x.ID == c.Key);
|
||||
if (sv != null)
|
||||
{
|
||||
sv.Mandatorio = c.Value.Item1;
|
||||
sv.Controlar = c.Value.Item2;
|
||||
continue;
|
||||
}
|
||||
var rl = ds.Reles.FirstOrDefault(x => x.ID == c.Key);
|
||||
var rl = ds?.Reles?.FirstOrDefault(x => x.ID == c.Key);
|
||||
if (rl != null)
|
||||
{
|
||||
rl.Mandatorio = c.Value.Item1;
|
||||
rl.Controlar = c.Value.Item2;
|
||||
continue;
|
||||
}
|
||||
var ld = ds.Sinaleiros.FirstOrDefault(x => x.ID == c.Key);
|
||||
var ld = ds?.Sinaleiros?.FirstOrDefault(x => x.ID == c.Key);
|
||||
if (ld != null)
|
||||
{
|
||||
ld.Mandatorio = c.Value.Item1;
|
||||
|
|
@ -973,15 +978,17 @@ namespace AgroBase.Models
|
|||
|
||||
CarregarParametrosOperacaoPadrao((ModoOperacao)Parametros.Modo, true);
|
||||
|
||||
Variaveis.OperacaoEmAndamento.Parametros = Parametros;
|
||||
Variaveis.OperacaoEmAndamento.Parametros.RoverId = VariaveisEquipamento.Parametros.serial_number;
|
||||
Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura = new OperacaoParametrosDadosModel();
|
||||
Variaveis.OperacaoEmAndamento.Sensoriamento.AtualizarDados();
|
||||
Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.ForEach(m => m.ComponentesEmUso = Variaveis.OperacaoEmAndamento.PreencherComponentesEmUso(m.Dispositivo));
|
||||
Variaveis.OperacaoEmAndamento.DefinirComponentesEmUso();
|
||||
|
||||
Variaveis.OperacaoEmAndamento.Descricao = Parametros.Descricao;
|
||||
Variaveis.OperacaoEmAndamento.OprPath = $"Base ({VariaveisEquipamento.Parametros.base_ip})";
|
||||
var p = Variaveis.OperacaoEmAndamento.Parametros;
|
||||
p.Descricao = Parametros.Descricao;
|
||||
p.CapacidadeReservatorio = Parametros.CapacidadeReservatorio;
|
||||
p.Controle = Parametros.Controle;
|
||||
p.QtdBicos = Parametros.QtdBicos;
|
||||
p.QtdCamerasSolo = Parametros.QtdCamerasSolo;
|
||||
p.RuasPercorrer = Parametros.RuasPercorrer;
|
||||
p.ModulosMandatorios = Parametros.ModulosMandatorios;
|
||||
p.ParametrosMandatorios = Parametros.ParametrosMandatorios;
|
||||
|
||||
List<string> ruasSelecionadas = Parametros.RuasPercorrer ?? new List<string>();
|
||||
if (Parametros.Mapa != null)
|
||||
|
|
@ -1491,7 +1498,8 @@ namespace AgroBase.Models
|
|||
{
|
||||
case BotoesJoystick.Share: // Requisitar parametros da operacao
|
||||
var topico = Variaveis.MqttServiceBase.Topicos.FirstOrDefault(x => x.Topico == VariaveisEquipamento.TopicoMqttParametros.Replace("<id>", VariaveisEquipamento.Parametros.serial_number));
|
||||
string msg = JsonConvert.SerializeObject(Variaveis.OperacaoEmAndamento.Parametros);
|
||||
var p = Variaveis.OperacaoEmAndamento.Parametros;
|
||||
string msg = JsonConvert.SerializeObject(p);
|
||||
Task.Run(async () => await Variaveis.MqttServiceBase.PublishAsync(topico, msg));
|
||||
break;
|
||||
case BotoesJoystick.Options: // Operacao nao iniciada, carrega todos os parametros compeltos
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace AgroBase.Models.Operadores
|
|||
public void AtualizarStatusBloqueio(bool consideraEmMovimento)
|
||||
{
|
||||
var Sonar = Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual;
|
||||
ObstaculoDetectado = (Sonar.Analises?.matriz_confianca?.block?.decision?.parar ?? false);
|
||||
ObstaculoDetectado = (Sonar?.Analises?.matriz_confianca?.block?.decision?.parar ?? false);
|
||||
StatusCarro = Sonar?.Analises?.segmentacao?.status_corredor ?? StatusCarroMapa.Indefinido;
|
||||
ErroLateral = Sonar?.Analises?.segmentacao?.erro_angular ?? 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,17 +49,24 @@ class ModuloIPBribge(ModuloDiagnosticoBase):
|
|||
self.last_heartbeat_ts = time.time()
|
||||
|
||||
self.rover_id = None
|
||||
self.sub = False
|
||||
|
||||
self._mqtt = None
|
||||
self._mqtt_conectado = False
|
||||
self._mqtt_executor = ThreadPoolExecutor(max_workers=1)
|
||||
self._mqtt_future = None
|
||||
self._mqtt_lock = threading.Lock()
|
||||
self._mqtt_last_attempt_ts = 0.0
|
||||
self._mqtt_backoff_s = 1.0 # começa rápido
|
||||
self._mqtt_backoff_max_s = 15.0 # limite
|
||||
self._mqtt_conectado = False
|
||||
self._mqtt_connecting = False
|
||||
self._heartbeat_ok = False
|
||||
self._mqtt_last_attempt_ts = 0.0
|
||||
self._mqtt_backoff_s = 1.0
|
||||
self._mqtt_backoff_max_s = 30.0
|
||||
self._mqtt_connected_ts = 0.0
|
||||
self.last_heartbeat_ts = 0.0
|
||||
self._heartbeat_timeout_s = 10.0
|
||||
self._heartbeat_grace_after_connect_s = 15.0
|
||||
self.sub = False
|
||||
self._mqtt_future = None
|
||||
self._mqtt_executor = ThreadPoolExecutor(max_workers=1)
|
||||
self._mqtt_client_seq = 0
|
||||
self._mqtt_debug = False
|
||||
|
||||
self._ping_executor = ThreadPoolExecutor(max_workers=1)
|
||||
self._ping_future = None
|
||||
|
|
@ -152,129 +159,209 @@ class ModuloIPBribge(ModuloDiagnosticoBase):
|
|||
finally:
|
||||
self._running = False
|
||||
|
||||
def _start_mqtt_heartbeat(self):
|
||||
try:
|
||||
if self._mqtt_conectado:
|
||||
|
||||
# MQTT HEARTBEAT
|
||||
def _mqtt_mostra_log(self, msg):
|
||||
if self._mqtt_debug:
|
||||
print(f"[HEARTBEAT] {msg}")
|
||||
|
||||
def _check_mqtt_heartbeat(self):
|
||||
now = time.time()
|
||||
client_to_close = None
|
||||
|
||||
with self._mqtt_lock:
|
||||
if not 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")
|
||||
|
||||
connected_ts = self._mqtt_connected_ts
|
||||
last_hb = self.last_heartbeat_ts
|
||||
|
||||
# janela de graça após reconnect
|
||||
if (now - connected_ts) < self._heartbeat_grace_after_connect_s:
|
||||
return
|
||||
|
||||
atraso_s = now - last_hb
|
||||
|
||||
if atraso_s >= self._heartbeat_timeout_s:
|
||||
self._mqtt_mostra_log(f"atraso de {atraso_s:.1f}s detectado")
|
||||
|
||||
with self._mqtt_lock:
|
||||
self._heartbeat_ok = False
|
||||
client_to_close = self._mqtt_detach_client_locked("heartbeat atrasado")
|
||||
|
||||
self._mqtt_close_client(client_to_close)
|
||||
|
||||
def _is_active_client_locked(self, client):
|
||||
return self._mqtt is client
|
||||
|
||||
def _mqtt_detach_client_locked(self, reason=""):
|
||||
client = self._mqtt
|
||||
self._mqtt = None
|
||||
self._mqtt_conectado = False
|
||||
self._mqtt_connecting = False
|
||||
self._heartbeat_ok = False
|
||||
self.sub = False
|
||||
self._mqtt_last_attempt_ts = time.time()
|
||||
self._mqtt_backoff_s = max(self._mqtt_backoff_s, 5.0)
|
||||
|
||||
if reason:
|
||||
self._mqtt_mostra_log(f"Resetando client MQTT: {reason}")
|
||||
|
||||
return client
|
||||
|
||||
def _mqtt_close_client(self, client):
|
||||
if client is not None:
|
||||
cid = getattr(client, "_agro_client_local_id", "?")
|
||||
self._mqtt_mostra_log(f"[client={cid}] fechando client antigo")
|
||||
|
||||
try:
|
||||
client.loop_stop()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
client.disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _start_mqtt_heartbeat_async(self):
|
||||
"""Dispara tentativa de conexão MQTT sem bloquear o loop."""
|
||||
now = time.time()
|
||||
|
||||
with self._mqtt_lock:
|
||||
if self._mqtt_conectado:
|
||||
return
|
||||
|
||||
if self._mqtt_connecting:
|
||||
return
|
||||
|
||||
# respeita backoff
|
||||
if self._mqtt_future is not None and not self._mqtt_future.done():
|
||||
return
|
||||
|
||||
if (now - self._mqtt_last_attempt_ts) < self._mqtt_backoff_s:
|
||||
return
|
||||
|
||||
base_ip = self.get_base_ip()
|
||||
if not base_ip:
|
||||
self._mqtt_mostra_log("mqtt heartbeat sem ip base definido")
|
||||
return
|
||||
|
||||
self._mqtt_last_attempt_ts = now
|
||||
self._mqtt_connecting = True
|
||||
|
||||
base_ip = self.get_base_ip()
|
||||
if base_ip is None:
|
||||
with self._mqtt_lock:
|
||||
self._mqtt_connecting = False
|
||||
return
|
||||
|
||||
# se já tem uma future rodando, não dispara outra
|
||||
if self._mqtt_future is not None and not self._mqtt_future.done():
|
||||
return
|
||||
|
||||
self._mqtt_mostra_log("tentando conectar mqtt heartbeat")
|
||||
self._mqtt_future = self._mqtt_executor.submit(self._mqtt_connect_worker, base_ip)
|
||||
|
||||
def _mqtt_connect_worker(self, base_ip: str):
|
||||
"""Roda em background. Pode bloquear aqui sem travar o health."""
|
||||
client = None
|
||||
try:
|
||||
client = mqtt.Client()
|
||||
with self._mqtt_lock:
|
||||
self._mqtt_client_seq += 1
|
||||
cid = self._mqtt_client_seq
|
||||
|
||||
client._agro_client_local_id = cid
|
||||
client.on_connect = self._on_connect
|
||||
client.on_message = self._on_message
|
||||
client.on_disconnect = self._on_disconnect
|
||||
|
||||
# dica V1: keepalive menor ajuda a detectar quedas mais rápido
|
||||
keepalive = 15
|
||||
|
||||
# conecta (bloqueante)
|
||||
client.connect(base_ip, 1883, keepalive)
|
||||
|
||||
# se chegou aqui, iniciou. loop_start é não-bloqueante
|
||||
client.connect(base_ip, 1883, 15)
|
||||
client.loop_start()
|
||||
|
||||
# troca o client com lock (evita race)
|
||||
with self._mqtt_lock:
|
||||
# se tinha um client antigo, tenta parar
|
||||
if self._mqtt is not None:
|
||||
try:
|
||||
self._mqtt.loop_stop()
|
||||
self._mqtt.disconnect()
|
||||
except:
|
||||
pass
|
||||
|
||||
# só assume como ativo depois de iniciar sem exception
|
||||
old = self._mqtt
|
||||
self._mqtt = client
|
||||
# on_connect vai setar _mqtt_conectado quando confirmar
|
||||
|
||||
except Exception:
|
||||
# falhou: libera pra tentar de novo com backoff maior
|
||||
if old is not None and old is not client:
|
||||
try:
|
||||
old.loop_stop()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
old.disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self._mqtt_mostra_log(f"mqtt heartbeat conectado [client={cid}]")
|
||||
|
||||
except Exception as e:
|
||||
with self._mqtt_lock:
|
||||
self._mqtt_conectado = False
|
||||
self._mqtt_connecting = False
|
||||
self._mqtt_backoff_s = min(self._mqtt_backoff_s * 2.0, self._mqtt_backoff_max_s)
|
||||
|
||||
self._mqtt_conectado = False
|
||||
self._heartbeat_ok = False
|
||||
self.sub = False
|
||||
self._mqtt_last_attempt_ts = time.time()
|
||||
self._mqtt_backoff_s = min(max(self._mqtt_backoff_s * 2.0, 5.0), self._mqtt_backoff_max_s)
|
||||
|
||||
self._mqtt_mostra_log(f"mqtt heartbeat erro ao conectar [client={getattr(client, '_agro_client_local_id', '?')}]: {e}")
|
||||
|
||||
def _on_connect(self, client, userdata, flags, rc):
|
||||
cid = getattr(client, "_agro_client_local_id", "?")
|
||||
|
||||
self._mqtt_mostra_log(f"[client={cid}] on_connect rc={rc} | t={time.time():.3f}")
|
||||
|
||||
with self._mqtt_lock:
|
||||
self._mqtt_conectado = (rc == 0)
|
||||
if not self._is_active_client_locked(client):
|
||||
self._mqtt_mostra_log(f"[client={cid}] on_connect IGNORADO (client antigo)")
|
||||
return
|
||||
|
||||
self._mqtt_connecting = False
|
||||
# reset backoff quando conecta
|
||||
if self._mqtt_conectado:
|
||||
|
||||
if rc == 0:
|
||||
self._mqtt_conectado = True
|
||||
self._heartbeat_ok = False
|
||||
self._mqtt_backoff_s = 1.0
|
||||
self._reset_janelas()
|
||||
self._mqtt_connected_ts = time.time()
|
||||
self.last_heartbeat_ts = self._mqtt_connected_ts
|
||||
|
||||
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
|
||||
topic = f"agrobot/v1/rover/{self.rover_id}/heartbeat"
|
||||
|
||||
result, mid = client.subscribe(topic)
|
||||
self.sub = (result == 0)
|
||||
self._mqtt_mostra_log(f"[client={cid}] Subscribado em: {topic} | result={result} mid={mid}")
|
||||
else:
|
||||
print("Erro ao conectar MQTT:", rc)
|
||||
self._mqtt_conectado = False
|
||||
self._heartbeat_ok = False
|
||||
self.sub = False
|
||||
self._mqtt_mostra_log(f"[client={cid}] Erro ao conectar MQTT: rc={rc}")
|
||||
|
||||
def _on_disconnect(self, client, userdata, rc):
|
||||
cid = getattr(client, "_agro_client_local_id", "?")
|
||||
|
||||
with self._mqtt_lock:
|
||||
if not self._is_active_client_locked(client):
|
||||
self._mqtt_mostra_log(f"[client={cid}] on_disconnect IGNORADO (client antigo) rc={rc}")
|
||||
return
|
||||
|
||||
self._mqtt_conectado = False
|
||||
self._mqtt_connecting = False
|
||||
self._heartbeat_ok = False
|
||||
self.sub = False
|
||||
print("[HEARTBEAT] MQTT desconectado!", rc)
|
||||
self._mqtt = None
|
||||
|
||||
# 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
|
||||
# adiciona isso:
|
||||
self._mqtt_last_attempt_ts = time.time()
|
||||
self._mqtt_backoff_s = max(self._mqtt_backoff_s, 5.0)
|
||||
|
||||
self._mqtt_mostra_log(f"[client={cid}] MQTT desconectado! rc={rc} | t={time.time():.3f}")
|
||||
|
||||
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")
|
||||
cid = getattr(client, "_agro_client_local_id", "?")
|
||||
|
||||
with self._mqtt_lock:
|
||||
if not self._is_active_client_locked(client):
|
||||
self._mqtt_mostra_log(f"[client={cid}] on_message IGNORADO (client antigo)")
|
||||
return
|
||||
|
||||
if msg.topic == f"agrobot/v1/rover/{self.rover_id}/heartbeat":
|
||||
now = time.time()
|
||||
with self._mqtt_lock:
|
||||
self.last_heartbeat_ts = now
|
||||
self._heartbeat_ok = True
|
||||
|
||||
self._mqtt_mostra_log(f"[client={cid}] heartbeat recebido | t={now:.3f}")
|
||||
|
||||
|
||||
def _reset_janelas(self):
|
||||
for d in (
|
||||
self.rtts_f, self.timeouts_f, self.loses_f,
|
||||
|
|
@ -654,6 +741,7 @@ class ModuloIPBribge(ModuloDiagnosticoBase):
|
|||
distancia_base = m.get("distancia_base", -1)
|
||||
self._ajustar_limites_banda_por_distancia(distancia_m=distancia_base)
|
||||
|
||||
self._check_mqtt_heartbeat()
|
||||
self._start_mqtt_heartbeat_async()
|
||||
|
||||
SAUDE_MIN_ALERTA = 80
|
||||
|
|
|
|||
|
|
@ -865,10 +865,10 @@ namespace OperationControl.Controls
|
|||
return dict.TryGetValue(fieldName, out var v) ? v : null;
|
||||
}
|
||||
|
||||
public AgroBase.Models.MapaFeatureCollectionModel CriarDadosMapa()
|
||||
public AgroBase.Models.MapaFeatureCollectionModel CriarDadosMapa(bool selecionadas = false)
|
||||
{
|
||||
AgroBase.Models.MapaFeatureCollectionModel _mapa = new AgroBase.Models.MapaFeatureCollectionModel() { type = "FeatureCollection", features = new List<AgroBase.Models.MapaFeatureModel>() };
|
||||
foreach (var x in RuasMapaCarregado.Where(x => x.Selected))
|
||||
foreach (var x in RuasMapaCarregado.Where(x => selecionadas ? x.Selected : true))
|
||||
{
|
||||
string id = ((dynamic)x.Feature).Id.ToString();
|
||||
string type = ((dynamic)x.Feature).Geometry.GeometryType;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ namespace OperationControl.Models
|
|||
|
||||
public static readonly string BaseMarkerID = "BASE";
|
||||
private static readonly object _RoversLock = new object();
|
||||
private static double TempoRoverVivo = 5.0;
|
||||
public static double TempoRoverVivo = 5.0;
|
||||
private static bool AdicionandoNovoRover = false;
|
||||
private static bool AtualizandoListaRovers = false;
|
||||
public static AgroBase.Models.Enums.StatusModulo StatusBase
|
||||
|
|
@ -153,7 +153,7 @@ namespace OperationControl.Models
|
|||
OperacaoParametrosModel rover;
|
||||
lock (_RoversLock)
|
||||
{
|
||||
rover = RoversNaRede.FirstOrDefault(x => x.RoverId == device_id);
|
||||
rover = RoversNaRede?.FirstOrDefault(x => x.RoverId == device_id);
|
||||
if (rover != null)
|
||||
{
|
||||
obj.Momento = DateTime.Now;
|
||||
|
|
@ -189,10 +189,8 @@ namespace OperationControl.Models
|
|||
var rover = RoversNaRede.FirstOrDefault(x => x.RoverId == device_id);
|
||||
if (rover != null)
|
||||
{
|
||||
obj.UltimoContato = DateTime.Now;
|
||||
obj.IP = rover.IP;
|
||||
RoversNaRede.Remove(rover);
|
||||
RoversNaRede.Add(obj);
|
||||
rover = obj;
|
||||
rover.UltimoContato = DateTime.Now;
|
||||
}
|
||||
}
|
||||
((App)Application.Current).Shell.Main?.AtualizarDadosTela_ParametrosOperacao(obj.Controle);
|
||||
|
|
@ -253,6 +251,7 @@ namespace OperationControl.Models
|
|||
((App)Application.Current).Shell.Main?.RemoverAlerta(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb);
|
||||
((App)Application.Current).Shell.RemoverAlertaDock(rover.RoverId, AgroBase.Models.Enums.T_Code.Ipb);
|
||||
}
|
||||
((App)Application.Current).Shell.Dock?._vm?.AtualizarBarraSuperior(rover);
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
|
|
|
|||
|
|
@ -746,12 +746,12 @@ namespace OperationControl.ViewModels.Views.Operacao.Monitoramento.Diagnostico
|
|||
|
||||
case T_Code.Ipb:
|
||||
var conexao = rover.ModulosSaude?.FirstOrDefault(x => x.modulo == T_Code.Ipb);
|
||||
AddOrAppendSerie("Latência", "ms", conexao?.detalhes?["avg_rtt"]?.Value<double>());
|
||||
AddOrAppendSerie("Jitter", "ms", conexao?.detalhes?["jitter"]?.Value<double>());
|
||||
AddOrAppendSerie("Timeout", "%", conexao?.detalhes?["tmout_pct"]?.Value<double>());
|
||||
AddOrAppendSerie("Perda", "%", conexao?.detalhes?["loss_pct"]?.Value<double>());
|
||||
AddOrAppendSerie("Banda", "Mbps", conexao?.detalhes?["bw_total_mbps"]?.Value<double>());
|
||||
AddOrAppendSerie("Banda %", "%", conexao?.detalhes?["bw_util_pct"]?.Value<double>());
|
||||
AddOrAppendSerie("Latência", "ms", conexao?.detalhes?["avg_rtt"]?.Value<double?>());
|
||||
AddOrAppendSerie("Jitter", "ms", conexao?.detalhes?["jitter"]?.Value<double?>());
|
||||
AddOrAppendSerie("Timeout", "%", conexao?.detalhes?["tmout_pct"]?.Value<double?>());
|
||||
AddOrAppendSerie("Perda", "%", conexao?.detalhes?["loss_pct"]?.Value<double?>());
|
||||
AddOrAppendSerie("Banda", "Mbps", conexao?.detalhes?["bw_total_mbps"]?.Value<double?>());
|
||||
AddOrAppendSerie("Banda %", "%", conexao?.detalhes?["bw_util_pct"]?.Value<double?>());
|
||||
break;
|
||||
|
||||
case T_Code.Gps:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using AgroBase.Models;
|
||||
using AgroBase.Models.Operacoes;
|
||||
using OperationControl.Controls;
|
||||
using OperationControl.Helpers;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Input;
|
||||
|
|
@ -51,6 +52,11 @@ namespace OperationControl.ViewModels.Views.Operacao.Monitoramento
|
|||
Parametros = origem;
|
||||
}
|
||||
|
||||
public void ProcessarStreetMapClicked(MapViewControl.StreetMapClickedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
private void OnPropertyChanged(string nome)
|
||||
|
|
|
|||
|
|
@ -366,8 +366,26 @@ namespace OperationControl.ViewModels
|
|||
if (rover == null || obj == null)
|
||||
return;
|
||||
|
||||
if (rover.RoverId != VariaveisControleOperacao.SelectedRoverId)
|
||||
return;
|
||||
|
||||
var eventos = new List<MotivoTopBarModel>();
|
||||
|
||||
double tempoSemResposta = (DateTime.Now - rover.UltimoContato).TotalSeconds;
|
||||
bool semComunicacao = tempoSemResposta >= VariaveisControleOperacao.TempoRoverVivo;
|
||||
|
||||
if (semComunicacao)
|
||||
{
|
||||
eventos.Add(new MotivoTopBarModel
|
||||
{
|
||||
Prioridade = 2000,
|
||||
Fonte = "Comunicacao",
|
||||
Titulo = "PERDA DE COMUNICAÇÃO COM O ROVER",
|
||||
Descricao = $"Sem resposta do rover há {tempoSemResposta:F1} s. Tentando reconectar automaticamente.",
|
||||
StatusVisual = StatusModulo.Desconectado
|
||||
});
|
||||
}
|
||||
|
||||
if (obj.ModulosSaude?.All(x => (x?.status ?? StatusModulo.Desconectado) == StatusModulo.Desconectado) ?? false)
|
||||
{
|
||||
// ============================
|
||||
|
|
@ -535,6 +553,7 @@ namespace OperationControl.ViewModels
|
|||
// Badge curto
|
||||
badge = principal.Fonte switch
|
||||
{
|
||||
"Comunicacao" => "DESCONECTADO",
|
||||
"Emergencia" => "EMERGÊNCIA",
|
||||
"Pausa" => "PAUSADO",
|
||||
"Trajetoria" => "TRAJETÓRIA",
|
||||
|
|
@ -546,6 +565,7 @@ namespace OperationControl.ViewModels
|
|||
// Resumo curto
|
||||
resumo = principal.Fonte switch
|
||||
{
|
||||
"Comunicacao" => "Sem telemetria",
|
||||
"Emergencia" => "Parada imediata",
|
||||
"Pausa" => "Aguardando retomada",
|
||||
"Trajetoria" => "Operação bloqueada",
|
||||
|
|
@ -968,6 +988,15 @@ namespace OperationControl.ViewModels
|
|||
}
|
||||
private void OnSalvarParametrosSolicitado(OperacaoParametrosModel parametros)
|
||||
{
|
||||
var dadosMapa = _viewOperacaoCenter?.Mapa?.CriarDadosMapa();
|
||||
var ruasPercorrer = _viewOperacaoCenter?.Mapa?.RuasMapaCarregado?.Where(x => x.Selected)?.Select(x => x.Id)?.ToList() ?? new List<string>();
|
||||
|
||||
if ((dadosMapa?.features?.Count ?? 0) == 0 || !ruasPercorrer.Any())
|
||||
{
|
||||
System.Windows.MessageBox.Show("Selecione as ruas no mapa onde o equipamento irá operar", "Ruas não selecionadas", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (VariaveisControleOperacao.RoverEmFoco == null)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ namespace OperationControl.Views.Operacao
|
|||
private void MAP_StreetMapClicked(object? sender, MapViewControl.StreetMapClickedEventArgs e)
|
||||
{
|
||||
_vm.ProcessarStreetMapClicked(e);
|
||||
((App)System.Windows.Application.Current).Shell.Dock?._vm?._viewOperacaoRight?.areaParametrizacao?._vm?.ProcessarStreetMapClicked(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue