iniciado migracao para uso do Redis
|
|
@ -136,6 +136,9 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>.\Microsoft.DirectX.DirectInput.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.6.0.0\lib\net461\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Kinect, Version=1.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
|
||||
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.3240.44, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.3240.44\lib\net462\Microsoft.Web.WebView2.Core.dll</HintPath>
|
||||
|
|
@ -168,12 +171,18 @@
|
|||
<Reference Include="OpenTK.GLControl, Version=1.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\OpenTK.GLControl.1.1.2225.0\lib\net20\OpenTK.GLControl.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Pipelines.Sockets.Unofficial, Version=1.0.0.0, Culture=neutral, PublicKeyToken=42ea0a778e13fbe2, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Pipelines.Sockets.Unofficial.2.2.8\lib\net472\Pipelines.Sockets.Unofficial.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpDX.DirectInput, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpDX.DirectInput.4.2.0\lib\net45\SharpDX.DirectInput.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="StackExchange.Redis, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c219ff1ca8c2ce46, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\StackExchange.Redis.2.8.41\lib\net472\StackExchange.Redis.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
|
|
@ -196,6 +205,9 @@
|
|||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Pipelines, Version=5.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Pipelines.5.0.1\lib\net461\System.IO.Pipelines.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||
|
|
@ -223,6 +235,9 @@
|
|||
<Reference Include="System.Text.Json, Version=8.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Json.8.0.1\lib\net462\System.Text.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Channels, Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Channels.5.0.0\lib\net461\System.Threading.Channels.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
|
|
@ -571,6 +586,7 @@
|
|||
<Compile Include="Services\Operadores\VisualWorkerService.cs" />
|
||||
<Compile Include="Services\PythonService.cs" />
|
||||
<Compile Include="Services\PZEMService.cs" />
|
||||
<Compile Include="Services\RedisService.cs" />
|
||||
<Compile Include="Services\SerialService.cs" />
|
||||
<Compile Include="Services\SonarService.cs" />
|
||||
<Compile Include="Services\SyncDataService.cs" />
|
||||
|
|
@ -997,8 +1013,10 @@
|
|||
<Error Condition="!Exists('..\packages\OpenCvSharp4.runtime.win.4.10.0.20240616\build\netstandard\OpenCvSharp4.runtime.win.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenCvSharp4.runtime.win.4.10.0.20240616\build\netstandard\OpenCvSharp4.runtime.win.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Emgu.CV.runtime.windows.4.4.0.4099\build\Emgu.CV.runtime.windows.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Emgu.CV.runtime.windows.4.4.0.4099\build\Emgu.CV.runtime.windows.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.3240.44\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.3240.44\build\Microsoft.Web.WebView2.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Extensions.Logging.Abstractions.6.0.0\build\Microsoft.Extensions.Logging.Abstractions.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Extensions.Logging.Abstractions.6.0.0\build\Microsoft.Extensions.Logging.Abstractions.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\AssimpNet.4.1.0\build\AssimpNet.targets" Condition="Exists('..\packages\AssimpNet.4.1.0\build\AssimpNet.targets')" />
|
||||
<Import Project="..\packages\Emgu.CV.runtime.windows.4.4.0.4099\build\Emgu.CV.runtime.windows.targets" Condition="Exists('..\packages\Emgu.CV.runtime.windows.4.4.0.4099\build\Emgu.CV.runtime.windows.targets')" />
|
||||
<Import Project="..\packages\Microsoft.Web.WebView2.1.0.3240.44\build\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.3240.44\build\Microsoft.Web.WebView2.targets')" />
|
||||
<Import Project="..\packages\Microsoft.Extensions.Logging.Abstractions.6.0.0\build\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('..\packages\Microsoft.Extensions.Logging.Abstractions.6.0.0\build\Microsoft.Extensions.Logging.Abstractions.targets')" />
|
||||
</Project>
|
||||
|
|
@ -21,6 +21,14 @@
|
|||
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ namespace AgroBase.Forms
|
|||
|
||||
PythonService.EncerrarProcessos();
|
||||
|
||||
RedisService.Iniciar();
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await VariaveisOperacao.Operadores.IniciarProcessamento(false);
|
||||
|
|
|
|||
|
|
@ -1606,8 +1606,34 @@ namespace AgroBase.Models
|
|||
public OperacaoControleModel Controle { get; set; }
|
||||
public VisualWorkerModel OperadorVisual { get; set; }
|
||||
|
||||
private void AtualizarDadosOperacaoRedis()
|
||||
{
|
||||
var operacao = RedisService.Get(CtxKey.DadosOperacao);
|
||||
var parametros = JsonConvert.DeserializeObject<Dictionary<string, object>>(operacao);
|
||||
bool configurado = Convert.ToBoolean(parametros["configurado"]);
|
||||
long tempoAguardando = (long)(parametros["tempo_aguardando"]);
|
||||
int op_status = Convert.ToInt32(parametros["status"]);
|
||||
StatusOperacao statusOperacao = (StatusOperacao)op_status;
|
||||
bool liberado = Convert.ToBoolean(parametros["liberado"]);
|
||||
List<ManagerWorkerMessageResponseModulosPendentesModel> status_modulos = JsonConvert.DeserializeObject<ManagerWorkerMessageResponseModulosPendentesModel[]>(parametros["status_modulos"].ToString()).ToList();
|
||||
|
||||
Variaveis.OperacaoEmAndamento.TempoAguardando = DateTimeOffset.FromUnixTimeSeconds(tempoAguardando).UtcDateTime.AddSeconds(tempoAguardando % 1).ToLocalTime();
|
||||
|
||||
Variaveis.OperacaoEmAndamento.StatusAtual = statusOperacao;
|
||||
Variaveis.OperacaoEmAndamento.OperacaoLiberada = liberado;
|
||||
|
||||
VariaveisOperacao.Operadores.ModulosSaude = new List<ManagerWorkerMessageResponseModulosPendentesModel>(status_modulos);
|
||||
|
||||
var mandatorios = Variaveis.OperacaoEmAndamento.ModulosMandatorios.Select(x => x.Dispositivo).ToList();
|
||||
var mods_com_falha = status_modulos.Where(x => mandatorios.Contains(x.modulo) && x.status == Enums.StatusModulo.Falha);
|
||||
var motivos_por_modulo = mods_com_falha.Select(x => $"{x.modulo}: {string.Join("; ", x.motivos)}");
|
||||
Variaveis.OperacaoEmAndamento.ErroOperacaoLiberada = string.Join(Environment.NewLine + Environment.NewLine, motivos_por_modulo);
|
||||
}
|
||||
|
||||
public void AtualizarDados()
|
||||
{
|
||||
AtualizarDadosOperacaoRedis();
|
||||
|
||||
var _Trajetoria = Variaveis.OperacaoEmAndamento.Trajetoria;
|
||||
var _DispMvd = Variaveis.OperacaoEmAndamento.DispMvd;
|
||||
var _DispAtu = Variaveis.OperacaoEmAndamento.DispAtu;
|
||||
|
|
@ -1736,6 +1762,7 @@ namespace AgroBase.Models
|
|||
Variaveis.OperacaoEmAndamento.Sensoriamento = dadosAtualizados;
|
||||
Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.AtualizarConsumo();
|
||||
VariaveisOperacao.Operadores.HealthWorker?.EnviarDadosContexto();
|
||||
VariaveisOperacao.Operadores.HealthWorker?.EnviarDadosModulos();
|
||||
}
|
||||
|
||||
public OperacaoSensoriamentoLogModel Clone(bool comSonar = false)
|
||||
|
|
|
|||
|
|
@ -85,6 +85,11 @@ namespace AgroBase.Models.Operadores
|
|||
public string modelo { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public enum HealthWorkerCommandType
|
||||
{
|
||||
SetDadosModulo = 1,
|
||||
SetDadosContexto = 2,
|
||||
SetDadosOperacao = 3,
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,4 +80,10 @@ namespace AgroBase.Models.Operadores
|
|||
public string descricao { get; set; }
|
||||
}
|
||||
|
||||
public enum ManagerWorkerCommandType
|
||||
{
|
||||
IniciarMPC = 1,
|
||||
EnviarDadosControle = 2,
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -535,7 +535,10 @@ namespace AgroBase.Models.Operadores
|
|||
|
||||
public enum VisualWorkerCommandType
|
||||
{
|
||||
SalvarFrames = 0
|
||||
SalvarFrames = 1,
|
||||
IniciarCameraManager = 2,
|
||||
AtualizarSaudeCamera = 3,
|
||||
GetCameraFrame = 4,
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ namespace AgroBase.Services.Operadores
|
|||
topicoRx = await Variaveis.MqttService.AdicionarNovoTopico(TopicoMQTT_Rx, true, 2, MqttCallback);
|
||||
topicoTx = await Variaveis.MqttService.AdicionarNovoTopico(TopicoMQTT_Tx);
|
||||
|
||||
RedisService.Subscribe(CmdKey.HealthWorkerTx, RedisCallback);
|
||||
|
||||
mapaRespostas = new Dictionary<TipoComando, Func<bool>>
|
||||
{
|
||||
{ TipoComando.GetListaCameras, () => DadosLeitura.Leitura.obj?.cameras?.newData ?? false },
|
||||
|
|
@ -138,6 +140,11 @@ namespace AgroBase.Services.Operadores
|
|||
return true;
|
||||
}
|
||||
|
||||
private void RedisCallback(string mensagem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void AtualizarDadosLeitura(WorkerMessageModel<HealthWorkerMessageResponseModel> msg)
|
||||
{
|
||||
if (DadosLeitura.Leitura.obj == null)
|
||||
|
|
@ -174,149 +181,43 @@ namespace AgroBase.Services.Operadores
|
|||
|
||||
public void EnviarDadosContexto()
|
||||
{
|
||||
if (Variaveis.OperacaoEmAndamento.DispMvd == null) return;
|
||||
|
||||
double limiteValorPadrao = -9999;
|
||||
var a = Variaveis.OperacaoEmAndamento.Trajetoria;
|
||||
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
|
||||
if (_Sensoriamento.Trajetoria == null) return;
|
||||
|
||||
var dados = new
|
||||
{
|
||||
comando = (int)TipoComando.SetDadosContexto,
|
||||
dispositivo = (int)T_Code.Mod,
|
||||
payload = new
|
||||
Trajetoria = new
|
||||
{
|
||||
Operacao = new
|
||||
status = (int)_Sensoriamento.Trajetoria.StatusCarro,
|
||||
manobrando = _Sensoriamento.Trajetoria.ManobrandoEntreRuas,
|
||||
erro_angular = _Sensoriamento.Trajetoria.ErroOrientacaoAngularCombinado,
|
||||
idx_proximo_ponto = _Sensoriamento.Trajetoria.ProximoPonto.idxPonto,
|
||||
CorredorAtual = new
|
||||
{
|
||||
debug_mode = Variaveis.DebugMode,
|
||||
iniciado = Variaveis.OperacaoEmAndamento.Iniciado,
|
||||
finalizando = Variaveis.OperacaoEmAndamento.Finalizando,
|
||||
emergencia = Variaveis.OperacaoEmAndamento.Emergencia,
|
||||
concluido = _Sensoriamento.Trajetoria.CorredorAtual.Concluido,
|
||||
dentro = _Sensoriamento.Trajetoria.CorredorAtual.Dentro,
|
||||
ultimo = _Sensoriamento.Trajetoria.CorredorAtual.Ultimo,
|
||||
largura = _Sensoriamento.Trajetoria.CorredorAtual.Largura,
|
||||
progresso = _Sensoriamento.Trajetoria.CorredorAtual.Progresso,
|
||||
dist_esq = _Sensoriamento.Trajetoria.DistanciaEsquerda,
|
||||
dist_dir = _Sensoriamento.Trajetoria.DistanciaDireita,
|
||||
angulo = _Sensoriamento.Trajetoria.AnguloCaminho,
|
||||
},
|
||||
Trajetoria = new
|
||||
{
|
||||
status = (int)_Sensoriamento.Trajetoria.StatusCarro,
|
||||
manobrando = _Sensoriamento.Trajetoria.ManobrandoEntreRuas,
|
||||
erro_angular = _Sensoriamento.Trajetoria.ErroOrientacaoAngularCombinado,
|
||||
idx_proximo_ponto = _Sensoriamento.Trajetoria.ProximoPonto.idxPonto,
|
||||
CorredorAtual = new
|
||||
{
|
||||
concluido = _Sensoriamento.Trajetoria.CorredorAtual.Concluido,
|
||||
dentro = _Sensoriamento.Trajetoria.CorredorAtual.Dentro,
|
||||
ultimo = _Sensoriamento.Trajetoria.CorredorAtual.Ultimo,
|
||||
largura = _Sensoriamento.Trajetoria.CorredorAtual.Largura,
|
||||
progresso = _Sensoriamento.Trajetoria.CorredorAtual.Progresso,
|
||||
dist_esq = _Sensoriamento.Trajetoria.DistanciaEsquerda,
|
||||
dist_dir = _Sensoriamento.Trajetoria.DistanciaDireita,
|
||||
angulo = _Sensoriamento.Trajetoria.AnguloCaminho,
|
||||
},
|
||||
},
|
||||
Gerais = new
|
||||
{
|
||||
velocidade_ms = _Sensoriamento.Movimentacao.VelocidadeMedia,
|
||||
ervas_no_radar = _Sensoriamento.Atuador.ErvasNoRadar,
|
||||
},
|
||||
Gps = new
|
||||
{
|
||||
conectado = GPSService.Iniciado,
|
||||
freq_base = GPSService.TaxaAmostragemHz,
|
||||
lat = _Sensoriamento.Gps.Latitude,
|
||||
lon = _Sensoriamento.Gps.Longitude,
|
||||
theta = _Sensoriamento.Gps.AnguloCarroDefinido,
|
||||
fix = (int)_Sensoriamento.Gps.QualidadeFix,
|
||||
rtk = GPSService.UltimoEnvioCorrecaoRTK.AddSeconds(5) > DateTime.Now,
|
||||
hAcc = _Sensoriamento.Gps.PrecisaoCm,
|
||||
nSatelites = _Sensoriamento.Gps.NumeroSatelites.valor,
|
||||
freq = _Sensoriamento.Gps.NumeroSatelites.frequencia,
|
||||
},
|
||||
Dir = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Select(x => new
|
||||
{
|
||||
conectado = x.DirMotor.Inicializado,
|
||||
freq_base = Variaveis.OperacaoEmAndamento.DispMvd.Dados.tmrRegistradorDIR.IntervalHz,
|
||||
endereco = x.DirMotor._EnderecoCAN_Tx,
|
||||
mod_id = x.Modulo_ID,
|
||||
angulo = x.DirMotor.Angulo,
|
||||
angulo_sp = x.DirMotor.Angulo_SP,
|
||||
comandar = x.DirMotor.Comandar,
|
||||
in1_atuado = x.DirMotor.IN1_Atuado,
|
||||
sentido = x.DirMotor.Sentido,
|
||||
sentido_sp = x.DirMotor.Sentido_SP,
|
||||
sentido_real = x.DirMotor.SentidoReal,
|
||||
freq = new {
|
||||
io = x.DirMotor.Leitura?.NumeroPulsos?.frequencia ?? 0,
|
||||
pulsos = x.DirMotor.Leitura?.EntradaIN1?.frequencia ?? 0,
|
||||
}
|
||||
}).ToArray(),
|
||||
Mov = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Select(x => new
|
||||
{
|
||||
conectado = x.MovMotor.Inicializado,
|
||||
freq_base = Variaveis.OperacaoEmAndamento.DispMvd.Dados.tmrRegistradorMOV.IntervalHz,
|
||||
endereco = x.MovMotor._EnderecoCAN_Tx,
|
||||
mod_id = x.Modulo_ID,
|
||||
cod_erro = x.MovMotor.CodigoAlarme,
|
||||
rpm = x.MovMotor.RPM_Roda,
|
||||
rpm_sp = x.MovMotor.RPM_SP_Leitura,
|
||||
tensao = x.MovMotor.Tensao,
|
||||
corrente_motor = x.MovMotor.Corrente_Motor,
|
||||
corrente_barramento = x.MovMotor.Corrente_Barramento,
|
||||
temperatura_driver = x.MovMotor.TemperaturaDriver,
|
||||
temperatura_motor = x.MovMotor.Temperatura,
|
||||
freado = x.MovMotor.Leitura?.Freado ?? false,
|
||||
freq = new
|
||||
{
|
||||
erro = x.MovMotor.Leitura?.CodigoAlarme?.frequencia ?? 0,
|
||||
rpm = x.MovMotor.Leitura?.ERPM?.frequencia ?? 0,
|
||||
tensao = x.MovMotor.Leitura?.Tensao?.frequencia ?? 0,
|
||||
corrente_motor = x.MovMotor.Leitura?.CorrenteMotor?.frequencia ?? 0,
|
||||
corrente_barramento = x.MovMotor.Leitura?.CorrenteBarramento?.frequencia ?? 0,
|
||||
temperatura = x.MovMotor.Leitura?.Temperatura?.frequencia ?? 0,
|
||||
}
|
||||
}).ToArray(),
|
||||
Sen = new
|
||||
{
|
||||
conectado = Variaveis.OperacaoEmAndamento.DispSen.Dados.Conectado,
|
||||
freq_base = Variaveis.OperacaoEmAndamento.DispSen.Dados.tmrRegistrador.IntervalHz,
|
||||
sensores = Variaveis.OperacaoEmAndamento.DispSen.Dados.Sensores.Select(x => new
|
||||
{
|
||||
conectado = x.Inicializado,
|
||||
id = x.ID_Num,
|
||||
label = x.ID,
|
||||
tipo = (int)x.Componente,
|
||||
aferir = x.Aferir,
|
||||
mandatorio = x.Mandatorio,
|
||||
dados = x.ValoresLeituras.Where(y => y.analise_health).Select(y => new
|
||||
{
|
||||
label = y.funcao.ToString(),
|
||||
nominal = y.nominal,
|
||||
maximo = y.maximo,
|
||||
minimo = y.minimo,
|
||||
atual = y.atual.valor,
|
||||
freq = y.atual.frequencia
|
||||
}),
|
||||
}).ToArray(),
|
||||
servos = Variaveis.OperacaoEmAndamento.DispSen.Dados.Servos.Select(x => new
|
||||
{
|
||||
conectado = x.Inicializado,
|
||||
id = x.ID_Num,
|
||||
label = x.ID,
|
||||
controlar = x.Controlar,
|
||||
mandatorio = x.Mandatorio,
|
||||
angulo_sp = x._AnguloControle,
|
||||
dados = x.ValoresLeituras.Where(y => y.analise_health).Select(y => new
|
||||
{
|
||||
label = y.funcao.ToString(),
|
||||
atual = y.atual.valor,
|
||||
freq = y.atual.frequencia
|
||||
}),
|
||||
}).ToArray(),
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
Gerais = new
|
||||
{
|
||||
velocidade_ms = _Sensoriamento.Movimentacao.VelocidadeMedia,
|
||||
ervas_no_radar = _Sensoriamento.Atuador.ErvasNoRadar,
|
||||
},
|
||||
};
|
||||
Task.Run(async () =>
|
||||
|
||||
var comando = new
|
||||
{
|
||||
await Variaveis.MqttService.PublishAsync(topicoTx, JsonConvert.SerializeObject(dados));
|
||||
});
|
||||
cmd = (int)HealthWorkerCommandType.SetDadosContexto,
|
||||
@params = dados
|
||||
};
|
||||
|
||||
RedisService.Publish(CmdKey.HealthWorkerRx, JsonConvert.SerializeObject(comando));
|
||||
}
|
||||
|
||||
public void EnviarDadosOperacao()
|
||||
|
|
@ -327,27 +228,28 @@ namespace AgroBase.Services.Operadores
|
|||
|
||||
var dados = new
|
||||
{
|
||||
comando = (int)TipoComando.SetDadosOperacao,
|
||||
dispositivo = (int)T_Code.Mod,
|
||||
payload = new
|
||||
modo = (int)Variaveis.OperacaoEmAndamento.Modo,
|
||||
debug_mode = Variaveis.DebugMode,
|
||||
iniciado = Variaveis.OperacaoEmAndamento.Iniciado,
|
||||
finalizando = Variaveis.OperacaoEmAndamento.Finalizando,
|
||||
emergencia = Variaveis.OperacaoEmAndamento.Emergencia,
|
||||
tempo_aguardar_inicio_operacao = Variaveis.OperacaoEmAndamento.TempoIniciarOperacao,
|
||||
sonar_ativado = _Controle.SonarAtivado,
|
||||
modulos_mandatorios = Variaveis.OperacaoEmAndamento.ModulosMandatorios.Select(x => (int)x.Dispositivo).ToArray(),
|
||||
parametros_mandatorios = Variaveis.OperacaoEmAndamento.ParametrosMandatorios.Select(x => (int)x.Parametro).ToArray(),
|
||||
Mov = new
|
||||
{
|
||||
modo = (int)Variaveis.OperacaoEmAndamento.Modo,
|
||||
sonar_ativado = _Controle.SonarAtivado,
|
||||
modulos_mandatorios = Variaveis.OperacaoEmAndamento.ModulosMandatorios.Select(x => (int)x.Dispositivo).ToArray(),
|
||||
parametros_mandatorios = Variaveis.OperacaoEmAndamento.ParametrosMandatorios.Select(x => (int)x.Parametro).ToArray(),
|
||||
Mov = new
|
||||
percent_vel_max = _Controle.PercentualVelocidadeMax,
|
||||
percent_vel_min = _Controle.PercentualVelocidadeMin,
|
||||
},
|
||||
Dir = new
|
||||
{
|
||||
angulo_max = _Controle.Angulo_Max,
|
||||
vel_movimento = _Controle.VelocidadeMP,
|
||||
tipo_controle = (int)_Controle.TipoControleDirecional,
|
||||
mpc = new
|
||||
{
|
||||
percent_vel_max = _Controle.PercentualVelocidadeMax,
|
||||
percent_vel_min = _Controle.PercentualVelocidadeMin,
|
||||
},
|
||||
Dir = new
|
||||
{
|
||||
angulo_max = _Controle.Angulo_Max,
|
||||
vel_movimento = _Controle.VelocidadeMP,
|
||||
tipo_controle = (int)_Controle.TipoControleDirecional,
|
||||
mpc = new
|
||||
{
|
||||
pontos = Variaveis.OperacaoEmAndamento.Trajetoria?._TrajetoriaFixa?
|
||||
pontos = Variaveis.OperacaoEmAndamento.Trajetoria?._TrajetoriaFixa?
|
||||
.Select(p => new
|
||||
{
|
||||
lat = p.Posicao.Latitude,
|
||||
|
|
@ -356,32 +258,148 @@ namespace AgroBase.Services.Operadores
|
|||
distanciaMargem = p.LarguraCorredor * 0.8
|
||||
})
|
||||
.ToList(),
|
||||
horizonte = 2.5,
|
||||
angulo_max_graus = _Controle.Angulo_Max,
|
||||
distancia_entre_eixos = (VariaveisEquipamento.DistanciaEntreEixos / 100.0),
|
||||
largura_equipamento = (VariaveisEquipamento.LarguraEquipamentoMm / 1000.0),
|
||||
velocidade_min = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMin),
|
||||
velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMax)
|
||||
}
|
||||
},
|
||||
Atu = new
|
||||
{
|
||||
percent_vertical_deteccao = _Controle.PercentualInicioPulverizacao,
|
||||
capacidade_reservatorio = Variaveis.OperacaoEmAndamento.CapacidadeReservatorio,
|
||||
pressao_linha = _Controle.PressaoLinha,
|
||||
},
|
||||
Snr = new
|
||||
{
|
||||
mx_id = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.Id
|
||||
horizonte = 2.5,
|
||||
angulo_max_graus = _Controle.Angulo_Max,
|
||||
distancia_entre_eixos = (VariaveisEquipamento.DistanciaEntreEixos / 100.0),
|
||||
largura_equipamento = (VariaveisEquipamento.LarguraEquipamentoMm / 1000.0),
|
||||
velocidade_min = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMin),
|
||||
velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMax)
|
||||
}
|
||||
},
|
||||
Atu = new
|
||||
{
|
||||
percent_vertical_deteccao = _Controle.PercentualInicioPulverizacao,
|
||||
capacidade_reservatorio = Variaveis.OperacaoEmAndamento.CapacidadeReservatorio,
|
||||
pressao_linha = _Controle.PressaoLinha,
|
||||
},
|
||||
Snr = new
|
||||
{
|
||||
mx_id = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.Id
|
||||
}
|
||||
};
|
||||
Task.Run(async () =>
|
||||
|
||||
var comando = new
|
||||
{
|
||||
await Variaveis.MqttService.PublishAsync(topicoTx, JsonConvert.SerializeObject(dados));
|
||||
});
|
||||
cmd = (int)HealthWorkerCommandType.SetDadosOperacao,
|
||||
@params = dados
|
||||
};
|
||||
|
||||
RedisService.Publish(CmdKey.HealthWorkerRx, JsonConvert.SerializeObject(comando));
|
||||
}
|
||||
|
||||
public void EnviarDadosModulos()
|
||||
{
|
||||
if (Variaveis.OperacaoEmAndamento.DispMvd == null) return;
|
||||
|
||||
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
|
||||
|
||||
var dados = new
|
||||
{
|
||||
Gps = new
|
||||
{
|
||||
conectado = GPSService.Iniciado,
|
||||
freq_base = GPSService.TaxaAmostragemHz,
|
||||
lat = _Sensoriamento.Gps.Latitude,
|
||||
lon = _Sensoriamento.Gps.Longitude,
|
||||
theta = _Sensoriamento.Gps.AnguloCarroDefinido,
|
||||
fix = (int)_Sensoriamento.Gps.QualidadeFix,
|
||||
rtk = GPSService.UltimoEnvioCorrecaoRTK.AddSeconds(5) > DateTime.Now,
|
||||
hAcc = _Sensoriamento.Gps.PrecisaoCm,
|
||||
nSatelites = _Sensoriamento.Gps.NumeroSatelites.valor,
|
||||
freq = _Sensoriamento.Gps.NumeroSatelites.frequencia,
|
||||
},
|
||||
Dir = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Select(x => new
|
||||
{
|
||||
conectado = x.DirMotor.Inicializado,
|
||||
freq_base = Variaveis.OperacaoEmAndamento.DispMvd.Dados.tmrRegistradorDIR.IntervalHz,
|
||||
endereco = x.DirMotor._EnderecoCAN_Tx,
|
||||
mod_id = x.Modulo_ID,
|
||||
angulo = x.DirMotor.Angulo,
|
||||
angulo_sp = x.DirMotor.Angulo_SP,
|
||||
comandar = x.DirMotor.Comandar,
|
||||
in1_atuado = x.DirMotor.IN1_Atuado,
|
||||
sentido = x.DirMotor.Sentido,
|
||||
sentido_sp = x.DirMotor.Sentido_SP,
|
||||
sentido_real = x.DirMotor.SentidoReal,
|
||||
freq = new
|
||||
{
|
||||
io = x.DirMotor.Leitura?.NumeroPulsos?.frequencia ?? 0,
|
||||
pulsos = x.DirMotor.Leitura?.EntradaIN1?.frequencia ?? 0,
|
||||
}
|
||||
}).ToArray(),
|
||||
Mov = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Select(x => new
|
||||
{
|
||||
conectado = x.MovMotor.Inicializado,
|
||||
freq_base = Variaveis.OperacaoEmAndamento.DispMvd.Dados.tmrRegistradorMOV.IntervalHz,
|
||||
endereco = x.MovMotor._EnderecoCAN_Tx,
|
||||
mod_id = x.Modulo_ID,
|
||||
cod_erro = x.MovMotor.CodigoAlarme,
|
||||
rpm = x.MovMotor.RPM_Roda,
|
||||
rpm_sp = x.MovMotor.RPM_SP_Leitura,
|
||||
tensao = x.MovMotor.Tensao,
|
||||
corrente_motor = x.MovMotor.Corrente_Motor,
|
||||
corrente_barramento = x.MovMotor.Corrente_Barramento,
|
||||
temperatura_driver = x.MovMotor.TemperaturaDriver,
|
||||
temperatura_motor = x.MovMotor.Temperatura,
|
||||
freado = x.MovMotor.Leitura?.Freado ?? false,
|
||||
freq = new
|
||||
{
|
||||
erro = x.MovMotor.Leitura?.CodigoAlarme?.frequencia ?? 0,
|
||||
rpm = x.MovMotor.Leitura?.ERPM?.frequencia ?? 0,
|
||||
tensao = x.MovMotor.Leitura?.Tensao?.frequencia ?? 0,
|
||||
corrente_motor = x.MovMotor.Leitura?.CorrenteMotor?.frequencia ?? 0,
|
||||
corrente_barramento = x.MovMotor.Leitura?.CorrenteBarramento?.frequencia ?? 0,
|
||||
temperatura = x.MovMotor.Leitura?.Temperatura?.frequencia ?? 0,
|
||||
}
|
||||
}).ToArray(),
|
||||
Sen = new
|
||||
{
|
||||
conectado = Variaveis.OperacaoEmAndamento.DispSen.Dados.Conectado,
|
||||
freq_base = Variaveis.OperacaoEmAndamento.DispSen.Dados.tmrRegistrador.IntervalHz,
|
||||
sensores = Variaveis.OperacaoEmAndamento.DispSen.Dados.Sensores.Select(x => new
|
||||
{
|
||||
conectado = x.Inicializado,
|
||||
id = x.ID_Num,
|
||||
label = x.ID,
|
||||
tipo = (int)x.Componente,
|
||||
aferir = x.Aferir,
|
||||
mandatorio = x.Mandatorio,
|
||||
dados = x.ValoresLeituras.Where(y => y.analise_health).Select(y => new
|
||||
{
|
||||
label = y.funcao.ToString(),
|
||||
nominal = y.nominal,
|
||||
maximo = y.maximo,
|
||||
minimo = y.minimo,
|
||||
atual = y.atual.valor,
|
||||
freq = y.atual.frequencia
|
||||
}),
|
||||
}).ToArray(),
|
||||
servos = Variaveis.OperacaoEmAndamento.DispSen.Dados.Servos.Select(x => new
|
||||
{
|
||||
conectado = x.Inicializado,
|
||||
id = x.ID_Num,
|
||||
label = x.ID,
|
||||
controlar = x.Controlar,
|
||||
mandatorio = x.Mandatorio,
|
||||
angulo_sp = x._AnguloControle,
|
||||
dados = x.ValoresLeituras.Where(y => y.analise_health).Select(y => new
|
||||
{
|
||||
label = y.funcao.ToString(),
|
||||
atual = y.atual.valor,
|
||||
freq = y.atual.frequencia
|
||||
}),
|
||||
}).ToArray(),
|
||||
},
|
||||
};
|
||||
|
||||
var comando = new
|
||||
{
|
||||
cmd = (int)HealthWorkerCommandType.SetDadosModulo,
|
||||
@params = dados
|
||||
};
|
||||
|
||||
RedisService.Publish(CmdKey.HealthWorkerRx, JsonConvert.SerializeObject(comando));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using AgroBase.Models.Operadores;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static AgroBase.Models.Operadores.OperadoresModels;
|
||||
|
|
@ -32,6 +33,8 @@ namespace AgroBase.Services.Operadores
|
|||
topicoRx = await Variaveis.MqttService.AdicionarNovoTopico(TopicoMQTT_Rx, true, 2, MqttCallback);
|
||||
topicoTx = await Variaveis.MqttService.AdicionarNovoTopico(TopicoMQTT_Tx);
|
||||
|
||||
RedisService.Subscribe(CmdKey.ManagerWorkerTx, RedisCallback);
|
||||
|
||||
DadosLeitura.IniciadoEm = DateTime.Now;
|
||||
DadosLeitura.Iniciado = true;
|
||||
|
||||
|
|
@ -73,6 +76,59 @@ namespace AgroBase.Services.Operadores
|
|||
return true;
|
||||
}
|
||||
|
||||
private void RedisCallback(string mensagem)
|
||||
{
|
||||
try
|
||||
{
|
||||
var comando = JsonConvert.DeserializeObject<ComandoRedis>(mensagem);
|
||||
|
||||
var cmd = (ManagerWorkerCommandType)comando.cmd;
|
||||
|
||||
MostrarLog($"📥 Comando recebido: cmd = {cmd.ToString()}");
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case ManagerWorkerCommandType.EnviarDadosControle:
|
||||
if (Variaveis.OperacaoEmAndamento.Modo == Enums.ModoOperacao.MapaGPS)
|
||||
{
|
||||
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
|
||||
var novoComando = new ManagerWorkerMessageResponseComandoModel()
|
||||
{
|
||||
angulo = Convert.ToDouble(comando.@params["angulo"]),
|
||||
percentual_velocidade = Convert.ToDouble(comando.@params["percentual_velocidade"]),
|
||||
tipo_movimento = (Enums.TipoMovimentoDirecional)Convert.ToInt32(comando.@params["tipo_movimento"]),
|
||||
simulacao = JsonConvert.DeserializeObject<List<double[]>>(comando.@params["simulacao"].ToString())
|
||||
};
|
||||
if (novoComando != null)
|
||||
{
|
||||
_Controle.Angulo = novoComando.angulo;
|
||||
_Controle.TipoMovimento = novoComando.tipo_movimento;
|
||||
_Controle.PercentualVelocidadeSP = novoComando.percentual_velocidade;
|
||||
_Controle.SimulacaoMPC = novoComando.simulacao.Select(x => new MPCSimulacaoModel() { latitude = x[0], longitude = x[1] }).ToList();
|
||||
Variaveis.OperacaoEmAndamento.AtualizaInformacoesControleOperacao();
|
||||
}
|
||||
|
||||
if (Variaveis.OperacaoEmAndamento.StatusAtual == Enums.StatusOperacao.Concluido && Variaveis.OperacaoEmAndamento.Iniciado)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Variaveis.OperacaoEmAndamento.FinalizarOperacao();
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MostrarLog($"⚠️ Comando não reconhecido: {comando.cmd}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MostrarLog($"❌ Erro ao deserializar resposta: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void AtualizarDadosLeitura(WorkerMessageModel<ManagerWorkerMessageResponseModel> msg)
|
||||
{
|
||||
Variaveis.OperacaoEmAndamento.TempoAguardando = DateTimeOffset.FromUnixTimeSeconds(msg.obj.tempo_aguardando).UtcDateTime.AddSeconds(msg.obj.tempo_aguardando % 1).ToLocalTime();
|
||||
|
|
@ -90,12 +146,14 @@ namespace AgroBase.Services.Operadores
|
|||
if (Variaveis.OperacaoEmAndamento.Modo == Enums.ModoOperacao.MapaGPS)
|
||||
{
|
||||
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
|
||||
_Controle.Angulo = msg.obj.comando.angulo;
|
||||
_Controle.TipoMovimento = msg.obj.comando.tipo_movimento;
|
||||
_Controle.PercentualVelocidadeSP = msg.obj.comando.percentual_velocidade;
|
||||
_Controle.SimulacaoMPC = msg.obj.comando.simulacao.Select(x => new MPCSimulacaoModel() { latitude = x[0], longitude = x[1] }).ToList();
|
||||
|
||||
Variaveis.OperacaoEmAndamento.AtualizaInformacoesControleOperacao();
|
||||
if (msg.obj.comando != null)
|
||||
{
|
||||
_Controle.Angulo = msg.obj.comando.angulo;
|
||||
_Controle.TipoMovimento = msg.obj.comando.tipo_movimento;
|
||||
_Controle.PercentualVelocidadeSP = msg.obj.comando.percentual_velocidade;
|
||||
_Controle.SimulacaoMPC = msg.obj.comando.simulacao.Select(x => new MPCSimulacaoModel() { latitude = x[0], longitude = x[1] }).ToList();
|
||||
Variaveis.OperacaoEmAndamento.AtualizaInformacoesControleOperacao();
|
||||
}
|
||||
|
||||
if (Variaveis.OperacaoEmAndamento.StatusAtual == Enums.StatusOperacao.Concluido && Variaveis.OperacaoEmAndamento.Iniciado)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ namespace AgroBase.Services.Operadores
|
|||
topicoRx = await Variaveis.MqttService.AdicionarNovoTopico(TopicoMQTT_Rx, true, 2, MqttCallback);
|
||||
topicoTx = await Variaveis.MqttService.AdicionarNovoTopico(TopicoMQTT_Tx);
|
||||
|
||||
RedisService.Subscribe(CmdKey.VisualWorkerTx, RedisCallback);
|
||||
|
||||
mapaRespostas = new Dictionary<VisualWorkerCommandType, Func<bool>>
|
||||
{
|
||||
{ VisualWorkerCommandType.SalvarFrames, () => DadosLeitura.Leitura.obj?.save_frames?.newData ?? false },
|
||||
|
|
@ -137,6 +139,33 @@ namespace AgroBase.Services.Operadores
|
|||
return true;
|
||||
}
|
||||
|
||||
private void RedisCallback(string mensagem)
|
||||
{
|
||||
try
|
||||
{
|
||||
var comando = JsonConvert.DeserializeObject<ComandoRedis>(mensagem);
|
||||
|
||||
var cmd = (VisualWorkerCommandType)comando.cmd;
|
||||
|
||||
MostrarLog($"📥 Comando recebido: cmd = {cmd.ToString()}");
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case VisualWorkerCommandType.GetCameraFrame:
|
||||
var frameModel = JsonConvert.DeserializeObject<OAKCameraFrameModel>(comando.@params.ToString());
|
||||
break;
|
||||
|
||||
default:
|
||||
MostrarLog($"⚠️ Comando não reconhecido: {comando.cmd}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MostrarLog($"❌ Erro ao deserializar resposta: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void AtualizarDadosLeitura(WorkerMessageModel<VisualWorkerMessageResponseModel> msg)
|
||||
{
|
||||
if (DadosLeitura.Leitura.obj == null)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AgroBase.Services
|
||||
{
|
||||
public class RedisService
|
||||
{
|
||||
private static ConnectionMultiplexer _redis;
|
||||
private static IDatabase _db;
|
||||
|
||||
public static void Iniciar(string conexao = "localhost")
|
||||
{
|
||||
_redis = ConnectionMultiplexer.Connect(conexao);
|
||||
_db = _redis.GetDatabase();
|
||||
}
|
||||
|
||||
public static string Get(string chave)
|
||||
{
|
||||
return _db.StringGet(chave);
|
||||
}
|
||||
|
||||
public static void Set(string chave, string valor)
|
||||
{
|
||||
_db.StringSet(chave, valor);
|
||||
}
|
||||
|
||||
public static void Publish(string canal, string mensagem)
|
||||
{
|
||||
var pub = _redis.GetSubscriber();
|
||||
pub.Publish(canal, mensagem);
|
||||
}
|
||||
|
||||
public static void Subscribe(string canal, Action<string> callback)
|
||||
{
|
||||
var sub = _redis.GetSubscriber();
|
||||
sub.Subscribe(canal, (ch, msg) => {
|
||||
callback(msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ComandoRedis
|
||||
{
|
||||
public int cmd { get; set; }
|
||||
public Dictionary<string, object> @params { get; set; }
|
||||
}
|
||||
|
||||
public static class CtxKey
|
||||
{
|
||||
public const string DadosCameras = "ctx:dados_cameras";
|
||||
public const string DadosModulo = "ctx:dados_modulo_";
|
||||
public const string DadosOperacao = "ctx:dados_operacao";
|
||||
public const string DadosContexto = "ctx:dados_contexto";
|
||||
public const string DadosControle = "ctx:dados_controle";
|
||||
public const string DadosVisualWorker = "ctx:dados_visual_worker";
|
||||
}
|
||||
|
||||
public static class CmdKey
|
||||
{
|
||||
public const string VisualWorkerRx = "cmd_rx:visual_worker";
|
||||
public const string VisualWorkerTx = "cmd_tx:visual_worker";
|
||||
public const string HealthWorkerRx = "cmd_rx:health_worker";
|
||||
public const string HealthWorkerTx = "cmd_tx:health_worker";
|
||||
public const string CameraWorkerRx = "cmd_rx:camera_worker";
|
||||
public const string CameraWorkerTx = "cmd_tx:camera_worker";
|
||||
public const string ManagerWorkerRx = "cmd_rx:manager_worker";
|
||||
public const string ManagerWorkerTx = "cmd_tx:manager_worker";
|
||||
}
|
||||
}
|
||||
|
|
@ -22,5 +22,5 @@
|
|||
"top_topics_and_observing_domains": [ ]
|
||||
} ],
|
||||
"hex_encoded_hmac_key": "40F346D3248C3AFDF2BEE1FE496DBD32F7CED6E5AE98B881ABC421AA7E7B5642",
|
||||
"next_scheduled_calculation_time": "13395777469290834"
|
||||
"next_scheduled_calculation_time": "13395777469290985"
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
|
@ -1,3 +1,3 @@
|
|||
2025/06/26-10:44:24.216 8088 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/MANIFEST-000001
|
||||
2025/06/26-10:44:24.223 8088 Recovering log #3
|
||||
2025/06/26-10:44:24.226 8088 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/000003.log
|
||||
2025/06/27-20:56:49.222 2104 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/MANIFEST-000001
|
||||
2025/06/27-20:56:49.231 2104 Recovering log #3
|
||||
2025/06/27-20:56:49.234 2104 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/000003.log
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
2025/06/26-10:22:26.943 6078 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/MANIFEST-000001
|
||||
2025/06/26-10:22:26.952 6078 Recovering log #3
|
||||
2025/06/26-10:22:26.956 6078 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/000003.log
|
||||
2025/06/27-07:21:30.670 746c Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/MANIFEST-000001
|
||||
2025/06/27-07:21:30.676 746c Recovering log #3
|
||||
2025/06/27-07:21:30.679 746c Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/000003.log
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"net":{"http_server_properties":{"servers":[{"alternative_service":[{"advertised_alpns":["h3"],"expiration":"13395505488076776","port":443,"protocol_str":"quic"}],"anonymization":["DAAAAAcAAABmaWxlOi8vAA==",false,0],"network_stats":{"srtt":7496},"server":"https://tile.openstreetmap.org","supports_spdy":true}],"supports_quic":{"address":"2804:d78:6d4:dc00:395e:1fef:8c2d:dcbe","used_quic":true},"version":5},"network_qualities":{"CAASABiAgICA+P////8B":"4G","CAESABiAgICA+P////8B":"4G","CAISABiAgICA+P////8B":"4G","CAYSABiAgICA+P////8B":"Offline"}}}
|
||||
{"net":{"http_server_properties":{"servers":[{"alternative_service":[{"advertised_alpns":["h3"],"expiration":"13395628615843983","port":443,"protocol_str":"quic"}],"anonymization":["DAAAAAcAAABmaWxlOi8vAA==",false,0],"network_stats":{"srtt":7016},"server":"https://tile.openstreetmap.org","supports_spdy":true}],"supports_quic":{"address":"2804:d78:6d4:dc00:ad47:84dd:a027:10ff","used_quic":true},"version":5},"network_qualities":{"CAASABiAgICA+P////8B":"4G","CAESABiAgICA+P////8B":"4G","CAISABiAgICA+P////8B":"4G","CAYSABiAgICA+P////8B":"Offline"}}}
|
||||
|
|
@ -1 +1 @@
|
|||
{"sts":[{"expiry":1782481467.393117,"host":"bWGAftl61rqoc0YzqPncsLvQQh/iC2Bdp3ejUeGC83w=","mode":"force-https","sts_include_subdomains":true,"sts_observed":1750945467.393127}],"version":2}
|
||||
{"sts":[{"expiry":1782604614.73,"host":"bWGAftl61rqoc0YzqPncsLvQQh/iC2Bdp3ejUeGC83w=","mode":"force-https","sts_include_subdomains":true,"sts_observed":1751068614.730003}],"version":2}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
2025/06/26-15:18:11.205 8088 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/MANIFEST-000001
|
||||
2025/06/26-15:18:11.207 8088 Recovering log #3
|
||||
2025/06/26-15:18:11.210 8088 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/000003.log
|
||||
2025/06/27-20:57:03.060 2104 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/MANIFEST-000001
|
||||
2025/06/27-20:57:03.061 2104 Recovering log #3
|
||||
2025/06/27-20:57:03.064 2104 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/000003.log
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
2025/06/26-10:44:15.822 6078 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/MANIFEST-000001
|
||||
2025/06/26-10:44:15.823 6078 Recovering log #3
|
||||
2025/06/26-10:44:15.829 6078 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/000003.log
|
||||
2025/06/27-07:56:02.137 746c Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/MANIFEST-000001
|
||||
2025/06/27-07:56:02.138 746c Recovering log #3
|
||||
2025/06/27-07:56:02.141 746c Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/000003.log
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
2025/06/26-10:44:24.143 1508 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/MANIFEST-000001
|
||||
2025/06/26-10:44:24.145 1508 Recovering log #3
|
||||
2025/06/26-10:44:24.146 1508 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/000003.log
|
||||
2025/06/27-20:56:49.144 3264 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/MANIFEST-000001
|
||||
2025/06/27-20:56:49.146 3264 Recovering log #3
|
||||
2025/06/27-20:56:49.146 3264 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/000003.log
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
2025/06/26-10:22:26.868 205c Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/MANIFEST-000001
|
||||
2025/06/26-10:22:26.870 205c Recovering log #3
|
||||
2025/06/26-10:22:26.870 205c Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/000003.log
|
||||
2025/06/27-07:21:30.596 aec Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/MANIFEST-000001
|
||||
2025/06/27-07:21:30.597 aec Recovering log #3
|
||||
2025/06/27-07:21:30.598 aec Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/000003.log
|
||||
|
|
|
|||
|
|
@ -21,6 +21,14 @@
|
|||
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
|
|
|||
BIN
AgroBase/AgroBase/bin/x64/Debug/Microsoft.Extensions.Logging.Abstractions.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/AgroBase/bin/x64/Debug/Pipelines.Sockets.Unofficial.dll (Stored with Git LFS)
Normal file
|
|
@ -17,7 +17,7 @@
|
|||
<meta name="viewport" content="width=device-width,
|
||||
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<style>
|
||||
#map_8cbbfc19e2a4c0a6eea90701b0e88f16 {
|
||||
#map_ff161c1ccb57bb1593d13e6005bc17f7 {
|
||||
position: relative;
|
||||
width: 100.0%;
|
||||
height: 100.0%;
|
||||
|
|
@ -54,14 +54,14 @@
|
|||
<body>
|
||||
|
||||
|
||||
<div class="folium-map" id="map_8cbbfc19e2a4c0a6eea90701b0e88f16" ></div>
|
||||
<div class="folium-map" id="map_ff161c1ccb57bb1593d13e6005bc17f7" ></div>
|
||||
|
||||
</body>
|
||||
<script>
|
||||
|
||||
|
||||
var map_8cbbfc19e2a4c0a6eea90701b0e88f16 = L.map(
|
||||
"map_8cbbfc19e2a4c0a6eea90701b0e88f16",
|
||||
var map_ff161c1ccb57bb1593d13e6005bc17f7 = L.map(
|
||||
"map_ff161c1ccb57bb1593d13e6005bc17f7",
|
||||
{
|
||||
center: [-22.172636164916668, -47.395186322185666],
|
||||
crs: L.CRS.EPSG3857,
|
||||
|
|
@ -78,7 +78,7 @@
|
|||
|
||||
|
||||
|
||||
var tile_layer_9013db21f6eca3782c27866d5a1afa86 = L.tileLayer(
|
||||
var tile_layer_fb8295ca92bb6af06fdd24fd2b872328 = L.tileLayer(
|
||||
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
{
|
||||
"minZoom": 0,
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
);
|
||||
|
||||
|
||||
tile_layer_9013db21f6eca3782c27866d5a1afa86.addTo(map_8cbbfc19e2a4c0a6eea90701b0e88f16);
|
||||
tile_layer_fb8295ca92bb6af06fdd24fd2b872328.addTo(map_ff161c1ccb57bb1593d13e6005bc17f7);
|
||||
|
||||
|
||||
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
}*/
|
||||
});
|
||||
}
|
||||
function geo_json_9504ddffaf9242962edc59fd8f534970_onEachFeature(feature, layer) {
|
||||
function geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb_onEachFeature(feature, layer) {
|
||||
|
||||
layer.on({
|
||||
|
||||
|
|
@ -148,23 +148,23 @@
|
|||
}*/
|
||||
});
|
||||
};
|
||||
var geo_json_9504ddffaf9242962edc59fd8f534970 = L.geoJson(null, {
|
||||
onEachFeature: geo_json_9504ddffaf9242962edc59fd8f534970_onEachFeature,
|
||||
var geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb = L.geoJson(null, {
|
||||
onEachFeature: geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb_onEachFeature,
|
||||
|
||||
...{
|
||||
}
|
||||
});
|
||||
|
||||
function geo_json_9504ddffaf9242962edc59fd8f534970_add (data) {
|
||||
geo_json_9504ddffaf9242962edc59fd8f534970
|
||||
function geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb_add (data) {
|
||||
geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb
|
||||
.addData(data);
|
||||
}
|
||||
geo_json_9504ddffaf9242962edc59fd8f534970_add({"features": [{"geometry": {"coordinates": [[-47.395205344, -22.172559531333334], [-47.395212610166666, -22.172614638833334], [-47.395219157, -22.172656417833334], [-47.395223544833335, -22.1726892105], [-47.39522414098443, -22.17269369161165], [-47.395225326538004, -22.172702654611555]], "id": null, "type": "LineString"}, "id": 0, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "1", "Length": 14.558011415731592, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.39521090233333, -22.172708800833334], [-47.395206943666665, -22.172679811], [-47.395202420666664, -22.1726491015], [-47.395198865666664, -22.172615782833333], [-47.395193255833334, -22.172577132833332], [-47.395192610024395, -22.17257265769541], [-47.395191325698136, -22.172563706509337]], "id": null, "type": "LineString"}, "id": 1, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "2", "Length": 14.771318274761821, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.3951762925, -22.172561603], [-47.395180824166665, -22.172591686166665], [-47.395185745333336, -22.172623080166666], [-47.395190433, -22.172656367166667], [-47.395195199, -22.172693641833334], [-47.39519576904436, -22.172698125891035], [-47.39519690267159, -22.172707094716973]], "id": null, "type": "LineString"}, "id": 2, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "3", "Length": 14.827915524386164, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.39518293216667, -22.1727127985], [-47.39517819266667, -22.172680514833335], [-47.3951732595, -22.172646752833334], [-47.39516880516667, -22.1726149155], [-47.39516381233334, -22.172581167166665], [-47.39516315429932, -22.172576693573966], [-47.39516184565584, -22.172567745443878]], "id": null, "type": "LineString"}, "id": 3, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "4", "Length": 14.785159385903514, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.395147317833334, -22.172566031], [-47.395151503166666, -22.172595452333333], [-47.3951561855, -22.172628011166665], [-47.39516159866667, -22.172663757333332], [-47.39516672716667, -22.172697770833334], [-47.395167397572706, -22.172702242832194], [-47.39516873082615, -22.17271118781009]], "id": null, "type": "LineString"}, "id": 4, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "5", "Length": 14.80117692191233, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}], "type": "FeatureCollection"});
|
||||
geo_json_9504ddffaf9242962edc59fd8f534970.setStyle(function(feature) {return feature.properties.style;});
|
||||
geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb_add({"features": [{"geometry": {"coordinates": [[-47.395205344, -22.172559531333334], [-47.395212610166666, -22.172614638833334], [-47.395219157, -22.172656417833334], [-47.395223544833335, -22.1726892105], [-47.39522414098443, -22.17269369161165], [-47.395225326538004, -22.172702654611555]], "id": null, "type": "LineString"}, "id": 0, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "1", "Length": 14.558011415731592, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.39521090233333, -22.172708800833334], [-47.395206943666665, -22.172679811], [-47.395202420666664, -22.1726491015], [-47.395198865666664, -22.172615782833333], [-47.395193255833334, -22.172577132833332], [-47.395192610024395, -22.17257265769541], [-47.395191325698136, -22.172563706509337]], "id": null, "type": "LineString"}, "id": 1, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "2", "Length": 14.771318274761821, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.3951762925, -22.172561603], [-47.395180824166665, -22.172591686166665], [-47.395185745333336, -22.172623080166666], [-47.395190433, -22.172656367166667], [-47.395195199, -22.172693641833334], [-47.39519576904436, -22.172698125891035], [-47.39519690267159, -22.172707094716973]], "id": null, "type": "LineString"}, "id": 2, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "3", "Length": 14.827915524386164, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.39518293216667, -22.1727127985], [-47.39517819266667, -22.172680514833335], [-47.3951732595, -22.172646752833334], [-47.39516880516667, -22.1726149155], [-47.39516381233334, -22.172581167166665], [-47.39516315429932, -22.172576693573966], [-47.39516184565584, -22.172567745443878]], "id": null, "type": "LineString"}, "id": 3, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "4", "Length": 14.785159385903514, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.395147317833334, -22.172566031], [-47.395151503166666, -22.172595452333333], [-47.3951561855, -22.172628011166665], [-47.39516159866667, -22.172663757333332], [-47.39516672716667, -22.172697770833334], [-47.395167397572706, -22.172702242832194], [-47.39516873082615, -22.17271118781009]], "id": null, "type": "LineString"}, "id": 4, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "5", "Length": 14.80117692191233, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}], "type": "FeatureCollection"});
|
||||
geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb.setStyle(function(feature) {return feature.properties.style;});
|
||||
|
||||
|
||||
|
||||
geo_json_9504ddffaf9242962edc59fd8f534970.addTo(map_8cbbfc19e2a4c0a6eea90701b0e88f16);
|
||||
geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb.addTo(map_ff161c1ccb57bb1593d13e6005bc17f7);
|
||||
|
||||
</script>
|
||||
|
||||
|
|
@ -185,7 +185,7 @@
|
|||
}
|
||||
trajeto_json_add({"features": []});
|
||||
|
||||
trajeto_json.addTo(map_8cbbfc19e2a4c0a6eea90701b0e88f16);
|
||||
trajeto_json.addTo(map_ff161c1ccb57bb1593d13e6005bc17f7);
|
||||
|
||||
function adicionarGeometria(novaGeometria) {
|
||||
trajeto_json.addData(novaGeometria);
|
||||
|
|
@ -243,7 +243,7 @@
|
|||
}
|
||||
trajeto_dinamico_json_add({"features": []});
|
||||
|
||||
trajeto_dinamico_json.addTo(map_8cbbfc19e2a4c0a6eea90701b0e88f16);
|
||||
trajeto_dinamico_json.addTo(map_ff161c1ccb57bb1593d13e6005bc17f7);
|
||||
|
||||
function adicionarGeometriaDinamica(novaGeometria) {
|
||||
trajeto_dinamico_json.addData(novaGeometria);
|
||||
|
|
@ -296,9 +296,9 @@
|
|||
|
||||
var marcadorEquipamento = L.marker([0, 0], {
|
||||
icon: customIcon
|
||||
}).addTo(map_8cbbfc19e2a4c0a6eea90701b0e88f16);
|
||||
}).addTo(map_ff161c1ccb57bb1593d13e6005bc17f7);
|
||||
|
||||
var marcadorBase = L.marker([0, 0], {}).addTo(map_8cbbfc19e2a4c0a6eea90701b0e88f16);
|
||||
var marcadorBase = L.marker([0, 0], {}).addTo(map_ff161c1ccb57bb1593d13e6005bc17f7);
|
||||
var icon = L.AwesomeMarkers.icon(
|
||||
{"extraClasses": "fa-rotate-0", "icon": "info-sign", "iconColor": "white", "markerColor": "red", "prefix": "glyphicon"}
|
||||
);
|
||||
|
|
@ -380,7 +380,7 @@
|
|||
}
|
||||
|
||||
if (foco) {
|
||||
map_8cbbfc19e2a4c0a6eea90701b0e88f16.setView(novaPosicao, map_8cbbfc19e2a4c0a6eea90701b0e88f16.getZoom());
|
||||
map_ff161c1ccb57bb1593d13e6005bc17f7.setView(novaPosicao, map_ff161c1ccb57bb1593d13e6005bc17f7.getZoom());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -397,7 +397,7 @@
|
|||
function atualizarSelecaoRuas(selecionadas) {
|
||||
selecionadas = JSON.parse(selecionadas);
|
||||
RuasSelecionadas = Array.isArray(selecionadas) ? [...selecionadas] : [];
|
||||
geo_json_9504ddffaf9242962edc59fd8f534970.eachLayer(function (layer) {
|
||||
geo_json_58ce871dcea3f9f4438ef7bdd99f0dcb.eachLayer(function (layer) {
|
||||
if (RuasSelecionadas.includes(parseInt(layer.feature.id))) {
|
||||
layer.setStyle({ color: 'blue' });
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import time
|
|||
|
||||
from health_worker.modulos.imu import IMUCamera
|
||||
from shared.enums import StatusModulo, T_Code
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
|
||||
|
||||
class CameraOak:
|
||||
def __init__(self, mostrar_log, dev_info):
|
||||
|
|
@ -11,7 +12,7 @@ class CameraOak:
|
|||
self.dev_info = dev_info
|
||||
self.mx_id = dev_info.getMxId()
|
||||
self.versao = dev_info.name
|
||||
self.dispositivo = T_Code.Vzo
|
||||
self.dispositivo = T_Code.Vzo.value
|
||||
self.modelo = "Desconhecido"
|
||||
self.ultima_saude = None
|
||||
self.timestamp_ultimo_frame_rgb = None
|
||||
|
|
@ -19,55 +20,80 @@ class CameraOak:
|
|||
self.tem_depth = False
|
||||
self.tem_imu = False
|
||||
self.rodando = False
|
||||
self.iniciado = False
|
||||
|
||||
_cameras = ContextoGlobalRedis.get(CtxKey.DadosCameras, {})
|
||||
_camera = _cameras.get(self.mx_id, {})
|
||||
_camera["versao"] = self.versao
|
||||
_camera["iniciando"] = True
|
||||
_camera["iniciado"] = False
|
||||
_camera["rodando"] = False
|
||||
_camera["parametros"] = {}
|
||||
|
||||
# Fase 1: detectar sensores sem pipeline
|
||||
try:
|
||||
device_tmp = dai.Device(dev_info)
|
||||
self.tem_imu = "imu" in device_tmp.getOutputQueueNames()
|
||||
sensores = device_tmp.getConnectedCameras()
|
||||
device_tmp.close()
|
||||
|
||||
if dai.CameraBoardSocket.LEFT in sensores and dai.CameraBoardSocket.RIGHT in sensores:
|
||||
self.modelo = "OAK-D Lite"
|
||||
self.dispositivo = T_Code.Snr
|
||||
self.dispositivo = T_Code.Snr.value
|
||||
self.tem_depth = True
|
||||
elif dai.CameraBoardSocket.CAM_A in sensores:
|
||||
self.modelo = "OAK-1 Lite W"
|
||||
self.dispositivo = T_Code.Cam
|
||||
self.dispositivo = T_Code.Cam.value
|
||||
self.tem_depth = False
|
||||
else:
|
||||
self.mostrar_log(f"[WARN] Sensores desconhecidos: {sensores}")
|
||||
except Exception as e:
|
||||
self.mostrar_log(f"[ERRO] Falha ao detectar sensores: {e}")
|
||||
pass
|
||||
#self.mostrar_log(f"[ERRO] Falha ao detectar sensores: {e}")
|
||||
|
||||
_camera["modelo"] = self.modelo
|
||||
_camera["dispositivo"] = self.dispositivo
|
||||
_camera["tem_depht"] = self.tem_depth
|
||||
_camera["tem_imu"] = self.tem_imu
|
||||
|
||||
# Fase 2: criar pipeline e instanciar normalmente
|
||||
self.pipeline = self._criar_pipeline()
|
||||
self.device = dai.Device(self.pipeline, self.dev_info)
|
||||
self.q_video = self.device.getOutputQueue(name="video", maxSize=1, blocking=False)
|
||||
try:
|
||||
self.pipeline = self._criar_pipeline()
|
||||
self.device = dai.Device(self.pipeline, self.dev_info)
|
||||
self.q_video = self.device.getOutputQueue(name="video", maxSize=1, blocking=False)
|
||||
|
||||
if self.tem_depth:
|
||||
self.q_depth = self.device.getOutputQueue(name="depth", maxSize=1, blocking=False)
|
||||
self.parametros = {
|
||||
"rgb_width": 1920,
|
||||
"rgb_height": 1080,
|
||||
"depth_width": 640,
|
||||
"depth_height": 400,
|
||||
"fx": 440.0,
|
||||
"fy": 440.0,
|
||||
"baseline": 0.075,
|
||||
"fov_h": 1,
|
||||
"fov_v": 1,
|
||||
"qtd_setores_solo": 25,
|
||||
"distancia_maxima": 3000,
|
||||
"percentual_altura_solo": 30,
|
||||
}
|
||||
self._set_calib()
|
||||
if self.tem_depth:
|
||||
self.q_depth = self.device.getOutputQueue(name="depth", maxSize=1, blocking=False)
|
||||
self.parametros = {
|
||||
"rgb_width": 1920,
|
||||
"rgb_height": 1080,
|
||||
"depth_width": 640,
|
||||
"depth_height": 400,
|
||||
"fx": 440.0,
|
||||
"fy": 440.0,
|
||||
"baseline": 0.075,
|
||||
"fov_h": 1,
|
||||
"fov_v": 1,
|
||||
"qtd_setores_solo": 25,
|
||||
"distancia_maxima": 3000,
|
||||
"percentual_altura_solo": 30,
|
||||
}
|
||||
self._set_calib(_camera)
|
||||
_camera["parametros"] = self.parametros
|
||||
|
||||
if "imu" in self.device.getOutputQueueNames():
|
||||
self.q_imu = self.device.getOutputQueue(name="imu", maxSize=50, blocking=False)
|
||||
self.imu = IMUCamera(self.q_imu)
|
||||
self.tem_imu = True
|
||||
else:
|
||||
self.tem_imu = False
|
||||
if self.tem_imu:
|
||||
self.q_imu = self.device.getOutputQueue(name="imu", maxSize=50, blocking=False)
|
||||
self.imu = IMUCamera(self.q_imu)
|
||||
|
||||
self.iniciado = True
|
||||
_camera["iniciado"] = True
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
_camera["iniciando"] = False
|
||||
|
||||
ContextoGlobalRedis.set(CtxKey.DadosCameras, _cameras)
|
||||
|
||||
def _criar_pipeline(self):
|
||||
pipeline = dai.Pipeline()
|
||||
|
|
@ -83,7 +109,7 @@ class CameraOak:
|
|||
self.mostrar_log(f"Pipeline rgb criado")
|
||||
|
||||
# DEPTH (somente se sensores presentes)
|
||||
if getattr(self, "tem_depth", False):
|
||||
if self.tem_depth:
|
||||
try:
|
||||
mono_left = pipeline.create(dai.node.MonoCamera)
|
||||
mono_right = pipeline.create(dai.node.MonoCamera)
|
||||
|
|
@ -108,7 +134,7 @@ class CameraOak:
|
|||
self.mostrar_log(f"[WARN] Falha ao montar pipeline depth: {e}")
|
||||
|
||||
# IMU (somente se presente)
|
||||
if getattr(self, "tem_depth", False):
|
||||
if self.tem_imu:
|
||||
try:
|
||||
imu = pipeline.create(dai.node.IMU)
|
||||
imu.enableIMUSensor(dai.IMUSensor.ACCELEROMETER_RAW, 60)
|
||||
|
|
@ -181,19 +207,22 @@ class CameraOak:
|
|||
"frame_valido": False
|
||||
}
|
||||
|
||||
def requisitar_imu_status(self):
|
||||
if getattr(self, "tem_imu", False):
|
||||
return self.imu.get_imu_status()
|
||||
else:
|
||||
return None
|
||||
|
||||
def atualizar_saude(self):
|
||||
#print("Atualizando saude")
|
||||
|
||||
_cameras = ContextoGlobalRedis.get(CtxKey.DadosCameras, {})
|
||||
_camera = _cameras.get(self.mx_id)
|
||||
|
||||
conectado = _camera is not None
|
||||
|
||||
frame, resultado = self.requisitar_frame_rgb()
|
||||
|
||||
saude = 50
|
||||
motivos = []
|
||||
|
||||
if not conectado:
|
||||
saude = -100
|
||||
|
||||
if resultado["erro"]:
|
||||
motivos.append(resultado["erro"])
|
||||
saude = 0
|
||||
|
|
@ -206,17 +235,21 @@ class CameraOak:
|
|||
saude -= 20
|
||||
motivos.append(f"Tempo elevado para captura: {resultado['duracao']:.2f}s")
|
||||
|
||||
status = StatusModulo.OPERANTE
|
||||
if saude <= 0:
|
||||
status = StatusModulo.FALHA
|
||||
elif saude < 80:
|
||||
status = StatusModulo.ALERTA
|
||||
saude = min(max(saude, 0), 100)
|
||||
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
ContextoGlobal.set_item_dado(self.dispositivo, "saude", "status", status)
|
||||
ContextoGlobal.set_item_dado(self.dispositivo, "saude", "saude", saude)
|
||||
ContextoGlobal.set_item_dado(self.dispositivo, "saude", "motivos", motivos)
|
||||
ContextoGlobal.set_item_dado(self.dispositivo, "saude", "saude_individual", [])
|
||||
status = StatusModulo.OPERANTE.value
|
||||
if saude <= 0:
|
||||
status = StatusModulo.FALHA.value
|
||||
elif saude < 80:
|
||||
status = StatusModulo.ALERTA.value
|
||||
|
||||
saude_geral = {
|
||||
"conectado": conectado,
|
||||
"status": status.value,
|
||||
"saude": saude,
|
||||
"motivos": motivos,
|
||||
"saude_idividual": []
|
||||
}
|
||||
|
||||
agora = time.time()
|
||||
timeout = 2.0
|
||||
|
|
@ -228,13 +261,17 @@ class CameraOak:
|
|||
(agora - ts_depth) <= timeout
|
||||
or (agora - ts_rgb) <= timeout
|
||||
)
|
||||
|
||||
if conectado:
|
||||
_camera["saude"] = saude_geral
|
||||
_camera["rodando"] = self.rodando
|
||||
disp = _camera.get("dispositivo", T_Code.Vzo.value)
|
||||
if disp != T_Code.Vzo.value:
|
||||
modulo = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(disp), {})
|
||||
modulo["saude"] = saude_geral
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(disp), modulo)
|
||||
ContextoGlobalRedis.set(CtxKey.DadosCameras, _cameras)
|
||||
|
||||
self.ultima_saude = {
|
||||
"status": status,
|
||||
"saude": max(0, min(100, saude)),
|
||||
"motivos": motivos,
|
||||
"saude_individual": []
|
||||
}
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -3,15 +3,16 @@ import os
|
|||
import time
|
||||
import json
|
||||
|
||||
def main():
|
||||
|
||||
def main(multi_process):
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
print("🔎 Caminho sys.path:", os.path.abspath(os.path.join(os.path.dirname(__file__), "..")), "CameraWorker")
|
||||
|
||||
from shared.mqtt_handler import iniciar_mqtt, registrar_callback, enviar_mensagem_mqtt, enviar_mensagem_script_carregado
|
||||
from shared.mensagem_worker import WorkerFilaMensagens
|
||||
from shared.enums import T_Code, TipoComando
|
||||
from shared.enums import T_Code, CameraWorkerCommandType
|
||||
from camera_worker.config import mostrar_log, module_id, topico_tx, topico_rx, get_camera_manager
|
||||
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CmdKey, CtxKey
|
||||
|
||||
# 🔹 Callback que o MQTT chama
|
||||
def ao_receber_comando(topico, payload):
|
||||
|
|
@ -23,7 +24,7 @@ def main():
|
|||
# Aqui você decodifica o comando e processa normalmente
|
||||
mensagem = json.loads(message.decode())
|
||||
dispositivo = T_Code(mensagem.get("dispositivo"))
|
||||
tipo_comando = TipoComando(mensagem.get("comando"))
|
||||
tipo_comando = CameraWorkerCommandType(mensagem.get("comando"))
|
||||
payload = mensagem.get("payload", {})
|
||||
|
||||
#mostrar_log(f"📨 Mensagem recebida no tópico {topico}. Comando: {tipo_comando.name}, dispositivo {dispositivo.name}, payload: {payload}")
|
||||
|
|
@ -52,16 +53,26 @@ def main():
|
|||
mostrar_log("🛑 Encerrando Camera Worker...")
|
||||
break
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro no loop do Manager: {e}")
|
||||
mostrar_log(f"❌ Erro no loop do Camera: {e}")
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
def redis_callback(dados):
|
||||
acao = CameraWorkerCommandType(dados.get("cmd", 0))
|
||||
|
||||
if False:
|
||||
pass
|
||||
else:
|
||||
mostrar_log(f"⚠️ Comando desconhecido: {acao.name}")
|
||||
|
||||
|
||||
# 🔹 Execução principal
|
||||
def inicializar():
|
||||
iniciar_mqtt(module_id)
|
||||
|
||||
if multi_process:
|
||||
iniciar_mqtt(module_id)
|
||||
mostrar_log("🚀 Iniciando Camera Worker...")
|
||||
registrar_callback(topico=topico_rx, callback=ao_receber_comando)
|
||||
ContextoGlobalRedis.ouvir_comandos(CmdKey.CameraWorkerRx, redis_callback)
|
||||
enviar_mensagem_script_carregado(topico_tx)
|
||||
loop_ativo()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import time
|
||||
import depthai as dai
|
||||
from .camera_oak import CameraOak
|
||||
from multiprocessing import Process, Queue
|
||||
from shared.enums import HealthWorkerCommandType, T_Code, VisualWorkerCommandType
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey, CmdKey
|
||||
|
||||
class CameraManager:
|
||||
def __init__(self, mostrar_log):
|
||||
self.cameras = []
|
||||
self.mostrar_log = mostrar_log
|
||||
self._ultimo_scan = 0
|
||||
|
||||
|
|
@ -16,68 +15,38 @@ class CameraManager:
|
|||
|
||||
try:
|
||||
dispositivos = dai.Device.getAllAvailableDevices()
|
||||
dispositivos_mapeados = [d.getMxId() for d in dispositivos]
|
||||
dispositivos_serializados = [d.getMxId() for d in dispositivos]
|
||||
except Exception as e:
|
||||
dispositivos_mapeados = []
|
||||
dispositivos_serializados = []
|
||||
|
||||
if len(dispositivos_mapeados) == 0:
|
||||
self.mostrar_log("⚠️ Nenhum dispositivo retornado.")
|
||||
dispositivos_serializados = []
|
||||
else:
|
||||
dispositivos_serializados = dispositivos_mapeados
|
||||
|
||||
novas_cameras = []
|
||||
cameras_mapeadas = ContextoGlobalRedis.get(CtxKey.DadosCameras, {})
|
||||
|
||||
for mx_id in dispositivos_serializados:
|
||||
existente = next((c for c in self.cameras if c.mx_id == mx_id), None)
|
||||
|
||||
if existente:
|
||||
existente.atualizar_saude()
|
||||
novas_cameras.append(existente)
|
||||
cam_existente = cameras_mapeadas.get(mx_id)
|
||||
if not cam_existente:
|
||||
cameras_mapeadas[mx_id] = {
|
||||
"timestamp": self._ultimo_scan,
|
||||
"mx_id": mx_id,
|
||||
"iniciado": False,
|
||||
"dispositivo": T_Code.Vzo.value
|
||||
}
|
||||
else:
|
||||
if not self._is_camera_em_uso(mx_id):
|
||||
print("em uso: False")
|
||||
try:
|
||||
dev_info = dai.DeviceInfo(mx_id)
|
||||
nova = CameraOak(self.mostrar_log, dev_info)
|
||||
nova.atualizar_saude()
|
||||
novas_cameras.append(nova)
|
||||
except Exception as e:
|
||||
self.mostrar_log(f"[ERRO] Falha ao iniciar camera {dev_info}: {e}")
|
||||
else:
|
||||
print("em uso: True")
|
||||
cam_existente["timestamp"] = self._ultimo_scan
|
||||
|
||||
mxids_ativos = set(dispositivos_serializados)
|
||||
mxids_mapeados = set(cameras_mapeadas.keys())
|
||||
mxids_removidos = mxids_mapeados - mxids_ativos
|
||||
|
||||
if len(novas_cameras) > 0:
|
||||
self.cameras = novas_cameras
|
||||
for mx_id in mxids_removidos:
|
||||
self.mostrar_log(f"🟥 Camera desconectada: {mx_id}")
|
||||
cameras_mapeadas.pop(mx_id, None)
|
||||
|
||||
for cam in self.cameras:
|
||||
cam.atualizar_saude()
|
||||
ContextoGlobalRedis.set(CtxKey.DadosCameras, cameras_mapeadas)
|
||||
|
||||
if len(self.cameras) > 0:
|
||||
a = 1
|
||||
# enviar mensagem mqtt para tentar atualizar o camera manager agora que existe alguma camera mapeada
|
||||
|
||||
def _is_camera_em_uso(self, mx_id):
|
||||
for c in self.cameras:
|
||||
if c.mx_id == mx_id and c.rodando:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_cameras(self, mx_id = None):
|
||||
if mx_id == None:
|
||||
return self.cameras
|
||||
else:
|
||||
camera = next((c for c in self.cameras if c.mx_id == mx_id), None)
|
||||
return camera
|
||||
|
||||
def get_cameras_dict(self):
|
||||
return [cam.to_dict() for cam in self.cameras]
|
||||
|
||||
def get_camera_frame(self, mx_id):
|
||||
cam = next((c for c in self.cameras if c.mx_id == mx_id), None)
|
||||
if cam != None:
|
||||
frame, res = cam.requisitar_frame_rgb()
|
||||
|
||||
return frame, cam.timestamp_ultimo_frame_rgb, res
|
||||
else:
|
||||
return None, None, {}
|
||||
for cam in cameras_mapeadas:
|
||||
if cam.get("dispositivo", T_Code.Vzo.value) == T_Code.Snr.value:
|
||||
ContextoGlobalRedis.publicar_comando(CmdKey.VisualWorkerRx, { "cmd": VisualWorkerCommandType.AtualizarSaudeCamera.value } )
|
||||
|
||||
visual_worker_camera_id = ContextoGlobalRedis.get_operacao().get(T_Code.Snr.name, {}).get("mx_id")
|
||||
if visual_worker_camera_id is not None and visual_worker_camera_id in dispositivos_serializados:
|
||||
ContextoGlobalRedis.publicar_comando(CmdKey.VisualWorkerRx, { "cmd": VisualWorkerCommandType.IniciarCameraManager.value, "params": visual_worker_camera_id } )
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import time
|
||||
|
||||
from health_worker.modulos.camera_manager import CameraManager
|
||||
#from health_worker.modulos.camera_manager import CameraManager
|
||||
|
||||
module_id = "health"
|
||||
topico_tx = f"operador/{module_id}/tx"
|
||||
|
|
@ -11,7 +11,7 @@ def mostrar_log(mensagem):
|
|||
if debug:
|
||||
print(f"{time.time()} - [{module_id}] {mensagem}")
|
||||
|
||||
manager = CameraManager(mostrar_log)
|
||||
#manager = CameraManager(mostrar_log)
|
||||
|
||||
def get_camera_manager():
|
||||
return manager
|
||||
#def get_camera_manager():
|
||||
# return manager
|
||||
|
|
|
|||
|
|
@ -3,21 +3,19 @@ import os
|
|||
import time
|
||||
import json
|
||||
|
||||
def main():
|
||||
def main(multi_process):
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
print("🔎 Caminho sys.path:", os.path.abspath(os.path.join(os.path.dirname(__file__), "..")), "HealthWorker")
|
||||
|
||||
from shared.mqtt_handler import iniciar_mqtt, registrar_callback, enviar_mensagem_mqtt, enviar_mensagem_script_carregado
|
||||
from shared.mensagem_worker import WorkerFilaMensagens
|
||||
from shared.enums import T_Code, TipoComando
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from shared.enums import T_Code, HealthWorkerCommandType
|
||||
from health_worker.modulos.gps import ModuloGPS
|
||||
from health_worker.modulos.direcional import ModuloDirecional
|
||||
from health_worker.modulos.movimentacao import ModuloMovimentacao
|
||||
from health_worker.modulos.sensoriamento import ModuloSensoriamento
|
||||
from health_worker.config import mostrar_log, module_id, topico_tx, topico_rx, get_camera_manager
|
||||
|
||||
|
||||
from health_worker.config import mostrar_log, module_id, topico_tx, topico_rx
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CmdKey, CtxKey
|
||||
|
||||
modulos = {
|
||||
T_Code.Gps: ModuloGPS(),
|
||||
|
|
@ -36,7 +34,7 @@ def main():
|
|||
# Aqui você decodifica o comando e processa normalmente
|
||||
mensagem = json.loads(message.decode())
|
||||
dispositivo = T_Code(mensagem.get("dispositivo"))
|
||||
tipo_comando = TipoComando(mensagem.get("comando"))
|
||||
tipo_comando = HealthWorkerCommandType(mensagem.get("comando"))
|
||||
payload = mensagem.get("payload", {})
|
||||
|
||||
#mostrar_log(f"📨 Mensagem recebida no tópico {topico}. Comando: {tipo_comando.name}, dispositivo {dispositivo.name}, payload: {payload}")
|
||||
|
|
@ -44,56 +42,6 @@ def main():
|
|||
|
||||
resposta = {}
|
||||
|
||||
if tipo_comando in (TipoComando.GetDadosModulo, TipoComando.SetDadosModulo):
|
||||
if dispositivo in modulos:
|
||||
modulo = modulos[dispositivo]
|
||||
if tipo_comando == TipoComando.SetDadosModulo:
|
||||
modulo.atualizar_status(payload)
|
||||
elif tipo_comando == TipoComando.GetDadosModulo:
|
||||
resposta = modulo.verificar_status()
|
||||
elif tipo_comando == TipoComando.SetDadosContexto:
|
||||
ContextoGlobal.atualizar_contexto(payload)
|
||||
#mostrar_log("Dados de Contexto atualizados com sucesso!")
|
||||
for chave, dados_modulo in payload.items():
|
||||
if chave not in T_Code.__members__:
|
||||
#mostrar_log(f"🔎 Ignorando chave '{chave}' (não é módulo do T_Code)")
|
||||
continue
|
||||
try:
|
||||
t_code = T_Code[chave]
|
||||
if t_code in modulos:
|
||||
modulos[t_code].atualizar_status(dados_modulo)
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro ao atualizar módulo {chave}: {e}")
|
||||
elif tipo_comando == TipoComando.GetDadosContexto:
|
||||
resposta = ContextoGlobal.get_tudo()
|
||||
elif tipo_comando == TipoComando.SetDadosOperacao:
|
||||
ContextoGlobal.atualizar_operacao(payload)
|
||||
mostrar_log("Dados da Operacao atualizados com sucesso!")
|
||||
elif tipo_comando == TipoComando.GetListaCameras:
|
||||
manager = get_camera_manager()
|
||||
cameras = manager.get_cameras_dict()
|
||||
resposta = {
|
||||
"cameras": {
|
||||
"timestamp": time.time(),
|
||||
"itens": cameras
|
||||
}
|
||||
}
|
||||
elif tipo_comando == TipoComando.GetCameraFrame:
|
||||
camera_id = payload.get("dados", {}).get("mx_id", "")
|
||||
manager = get_camera_manager()
|
||||
frame, timestamp, res = manager.get_camera_frame(camera_id)
|
||||
base64_img = None
|
||||
if frame is not None:
|
||||
from shared.utils import encode_image_base64
|
||||
base64_img = encode_image_base64(frame)
|
||||
resposta = {
|
||||
"frame": {
|
||||
"timestamp": timestamp,
|
||||
"frame": base64_img
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (resposta != {}):
|
||||
resposta["cmd"] = tipo_comando
|
||||
enviar_mensagem_mqtt(topico=topico_tx, dispositivo=dispositivo,objeto=resposta)
|
||||
|
|
@ -106,10 +54,11 @@ def main():
|
|||
|
||||
# 🔹 Loop principal do Manager
|
||||
def loop_ativo():
|
||||
manager = get_camera_manager()
|
||||
#manager = get_camera_manager()
|
||||
while True:
|
||||
try:
|
||||
manager.atualizar_cameras()
|
||||
pass
|
||||
#manager.atualizar_cameras()
|
||||
#cameras = manager.get_cameras()
|
||||
#mostrar_log([f"Camera: {cam.modelo}, ID: {cam.mx_id}, Saude: {cam.ultima_saude}" for cam in cameras])
|
||||
|
||||
|
|
@ -121,11 +70,42 @@ def main():
|
|||
|
||||
time.sleep(5)
|
||||
|
||||
def redis_callback(dados):
|
||||
acao = HealthWorkerCommandType(dados.get("cmd", 0))
|
||||
|
||||
if acao == HealthWorkerCommandType.SetDadosModulo:
|
||||
_modulos = dados.get("params")
|
||||
if _modulos:
|
||||
for chave, dados_modulo in _modulos.items():
|
||||
if chave not in T_Code.__members__:
|
||||
#mostrar_log(f"🔎 Ignorando chave '{chave}' (não é módulo do T_Code)")
|
||||
continue
|
||||
try:
|
||||
t_code = T_Code[chave]
|
||||
if t_code in modulos:
|
||||
modulos[t_code].atualizar_status(dados_modulo)
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro ao atualizar módulo {chave}: {e}")
|
||||
elif acao == HealthWorkerCommandType.SetDadosContexto:
|
||||
_contexto = dados.get("params")
|
||||
if _contexto:
|
||||
ContextoGlobalRedis.set(CtxKey.DadosContexto, _contexto)
|
||||
ContextoGlobalRedis.atualizar_dados_operacao()
|
||||
elif acao == HealthWorkerCommandType.SetDadosOperacao:
|
||||
_operacao = dados.get("params")
|
||||
if _operacao:
|
||||
ContextoGlobalRedis.set(CtxKey.DadosOperacao, _operacao)
|
||||
ContextoGlobalRedis.atualizar_dados_operacao()
|
||||
mostrar_log("Dados da Operacao atualizados com sucesso!")
|
||||
|
||||
|
||||
# 🔹 Execução principal
|
||||
def inicializar():
|
||||
iniciar_mqtt(module_id)
|
||||
if multi_process:
|
||||
iniciar_mqtt(module_id)
|
||||
mostrar_log("🚀 Iniciando Health Worker...")
|
||||
registrar_callback(topico=topico_rx, callback=ao_receber_comando)
|
||||
ContextoGlobalRedis.ouvir_comandos(CmdKey.HealthWorkerRx, redis_callback)
|
||||
enviar_mensagem_script_carregado(topico_tx)
|
||||
loop_ativo()
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class CameraManager:
|
|||
|
||||
if len(self.cameras) > 0:
|
||||
from shared.mqtt_handler import enviar_mensagem_visual_worker
|
||||
enviar_mensagem_visual_worker(VisualWorkerCommandType.ATUALIZAR_CAMERA_MANAGER.value, {})
|
||||
enviar_mensagem_visual_worker(VisualWorkerCommandType.AtualizarCameraManager)
|
||||
|
||||
def _is_camera_em_uso(self, mx_id):
|
||||
for c in self.cameras:
|
||||
|
|
|
|||
|
|
@ -1,42 +1,31 @@
|
|||
import time
|
||||
from shared.enums import T_Code, Sentido, StatusModulo
|
||||
from shared.utils import penalizar_frequencia
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from health_worker.modulos.base import ModuloDiagnosticoBase, resposta
|
||||
|
||||
class StatusDirecional:
|
||||
def __init__(self):
|
||||
self.timestamp = 0
|
||||
self.freq_io = 0
|
||||
self.freq_pulsos = 0
|
||||
self.freq_rpm = 0
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis
|
||||
from health_worker.modulos.base import ModuloDiagnosticoBase
|
||||
|
||||
class ModuloDirecional(ModuloDiagnosticoBase):
|
||||
def __init__(self):
|
||||
self.t_code = T_Code.Dir
|
||||
self.nome = "Direcional"
|
||||
self.status_por_driver = {}
|
||||
self.timeout = 3 # segundos
|
||||
|
||||
def atualizar_status(self, dados):
|
||||
agora = time.time()
|
||||
|
||||
# Esperamos uma lista de dicionários (um por motor direcional)
|
||||
dados_dir = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(self.t_code), {})
|
||||
status_modulos = {
|
||||
"saude": dados_dir.get("saude", {}),
|
||||
"timestamp": agora
|
||||
}
|
||||
for item in dados:
|
||||
endereco = item.get("endereco")
|
||||
if endereco is None:
|
||||
continue
|
||||
|
||||
s = self.status_por_driver.get(endereco, StatusDirecional())
|
||||
s.timestamp = agora
|
||||
|
||||
freq_info = item.get("freq", {})
|
||||
s.freq_io = freq_info.get("io", 0.0)
|
||||
s.freq_pulsos = freq_info.get("pulsos", 0.0)
|
||||
s.freq_rpm = freq_info.get("rpm", 0.0)
|
||||
|
||||
self.status_por_driver[endereco] = s
|
||||
|
||||
driver = dict(item)
|
||||
driver["saude"] = dados_dir.get(endereco, {}).get("saude", {})
|
||||
driver["timestamp"] = agora
|
||||
status_modulos[endereco] = driver
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(self.t_code), status_modulos)
|
||||
self.verificar_status()
|
||||
|
||||
def verificar_status(self):
|
||||
|
|
@ -50,19 +39,21 @@ class ModuloDirecional(ModuloDiagnosticoBase):
|
|||
ENDERECOS_DRIVERS = {1, 2, 3, 4}
|
||||
mod_conectado = False
|
||||
|
||||
for endereco, driver in self.status_por_driver.items():
|
||||
mod_id = ContextoGlobal.get_item(T_Code.Dir, "dados", "mod_id", endereco)
|
||||
FREQ_BASE = ContextoGlobal.get_item(T_Code.Dir, "dados", "freq_base", endereco) or 1
|
||||
dados_dir = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(self.t_code), {})
|
||||
|
||||
for endereco, modulo in dados_dir.items():
|
||||
if not isinstance(endereco, int):
|
||||
continue
|
||||
mod_id = modulo.get("mod_id")
|
||||
FREQ_BASE = modulo.get("freq_base", 1)
|
||||
FREQ_MIN = FREQ_BASE * 0.5
|
||||
saude = 100
|
||||
motivos = []
|
||||
condicoes_operacionais = []
|
||||
conectado = ContextoGlobal.get_item(T_Code.Dir, "dados", "conectado", endereco) or False
|
||||
comandar = ContextoGlobal.get_item(T_Code.Dir, "dados", "comandar", endereco) or True
|
||||
freqs = ContextoGlobal.get_item(T_Code.Dir, "dados", "freq", endereco) or {}
|
||||
|
||||
maior_freq = max(freqs.values())
|
||||
|
||||
conectado = modulo.get("conectado", False)
|
||||
comandar = modulo.get("comandar", True)
|
||||
freqs = modulo.get("freq", {})
|
||||
maior_freq = max(freqs.values() if freqs != {} else [0])
|
||||
if not conectado:
|
||||
saude = 0
|
||||
elif maior_freq == 0:
|
||||
|
|
@ -74,20 +65,17 @@ class ModuloDirecional(ModuloDiagnosticoBase):
|
|||
saude -= pen
|
||||
if freq < FREQ_MIN:
|
||||
motivos.append(f"Frequencia {label} baixa ({freq:.2f}/{FREQ_BASE} Hz, penalidade {pen}%)")
|
||||
|
||||
referenciado = ContextoGlobal.get_item(T_Code.Dir, "dados", "referenciado", endereco)
|
||||
angulo = ContextoGlobal.get_item(T_Code.Dir, "dados", "angulo", endereco)
|
||||
angulo_sp = ContextoGlobal.get_item(T_Code.Dir, "dados", "angulo_sp", endereco)
|
||||
sentido = ContextoGlobal.get_item(T_Code.Dir, "dados", "sentido", endereco)
|
||||
sentido_real = ContextoGlobal.get_item(T_Code.Dir, "dados", "sentido_real", endereco)
|
||||
|
||||
referenciado = modulo.get("referenciado", False)
|
||||
angulo = modulo.get("angulo", 0.0)
|
||||
angulo_sp = modulo.get("angulo_sp", 0.0)
|
||||
sentido = modulo.get("sentido", Sentido.PARADO.value)
|
||||
sentido_real = modulo.get("sentido_real", Sentido.PARADO.value)
|
||||
if referenciado is False:
|
||||
condicoes_operacionais.append({
|
||||
"valor": 0,
|
||||
"severidade": 50,
|
||||
"descricao": "Driver nunca foi referenciado"
|
||||
})
|
||||
|
||||
if angulo_sp != angulo:
|
||||
erro_angulo = abs(angulo - angulo_sp)
|
||||
condicoes_operacionais.append({
|
||||
|
|
@ -95,37 +83,34 @@ class ModuloDirecional(ModuloDiagnosticoBase):
|
|||
"severidade": erro_angulo,
|
||||
"descricao": f"Angulo incoerente (Atual: {angulo}°, SP: {angulo_sp}°)"
|
||||
})
|
||||
|
||||
if sentido != Sentido.PARADO and sentido != sentido_real:
|
||||
if sentido != Sentido.PARADO.value and sentido != sentido_real:
|
||||
condicoes_operacionais.append({
|
||||
"valor": angulo,
|
||||
"severidade": (10 + angulo),
|
||||
"descricao": f"Direção incoerente (real: {Sentido(sentido_real).name}, esperada: {Sentido(sentido).name}, ângulo: {angulo:.2f}°)"
|
||||
})
|
||||
|
||||
saude = max(saude, 0)
|
||||
saude_individual.append({
|
||||
saude_mod = {
|
||||
"id": endereco,
|
||||
"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,
|
||||
"status": (StatusModulo.DESCONECTADO if not conectado else StatusModulo.OPERANTE if saude >= SAUDE_MIN_ALERTA else StatusModulo.ALERTA if saude > 0 else StatusModulo.FALHA).value,
|
||||
"saude": saude,
|
||||
"motivos": motivos,
|
||||
"condicoes_operacionais": condicoes_operacionais,
|
||||
"em_uso": comandar
|
||||
})
|
||||
|
||||
}
|
||||
saude_individual.append(saude_mod)
|
||||
# Se o driver está sendo usado, entra na média geral
|
||||
if comandar is True:
|
||||
saude_total += saude
|
||||
total_drivers_em_uso += 1
|
||||
motivos_dos_ativos.extend([f"Driver {endereco}: {m}" for m in motivos])
|
||||
|
||||
ContextoGlobal.set_item_dado(T_Code.Dir, "dados", "saude", saude, endereco)
|
||||
modulo["saude"] = saude_mod
|
||||
if conectado:
|
||||
mod_conectado = True
|
||||
|
||||
# Verifica se algum driver esperado está ausente
|
||||
drivers_respondendo = set(self.status_por_driver.keys())
|
||||
drivers_respondendo = set(k for k in dados_dir.keys() if isinstance(k, int))
|
||||
drivers_esperados = ENDERECOS_DRIVERS
|
||||
drivers_ausentes = drivers_esperados - drivers_respondendo
|
||||
|
||||
|
|
@ -133,7 +118,7 @@ class ModuloDirecional(ModuloDiagnosticoBase):
|
|||
saude_individual.append({
|
||||
"id": endereco,
|
||||
"label": "",
|
||||
"status": StatusModulo.DESCONECTADO,
|
||||
"status": StatusModulo.DESCONECTADO.value,
|
||||
"saude": 0,
|
||||
"motivos": ["Nenhuma resposta recebida"],
|
||||
"condicoes_operacionais": [{
|
||||
|
|
@ -149,18 +134,25 @@ class ModuloDirecional(ModuloDiagnosticoBase):
|
|||
|
||||
saude_final = (saude_total // total_drivers_em_uso) if total_drivers_em_uso > 0 else 0
|
||||
|
||||
status = StatusModulo.OPERANTE
|
||||
status = StatusModulo.OPERANTE.value
|
||||
if not mod_conectado:
|
||||
status = StatusModulo.DESCONECTADO
|
||||
status = StatusModulo.DESCONECTADO.value
|
||||
elif saude_final <= 0 or len(drivers_ausentes) > 0:
|
||||
status = StatusModulo.FALHA
|
||||
status = StatusModulo.FALHA.value
|
||||
elif saude_final < SAUDE_MIN_ALERTA or any(saude["saude"] < SAUDE_MIN_ALERTA for saude in saude_individual):
|
||||
status = StatusModulo.ALERTA
|
||||
status = StatusModulo.ALERTA.value
|
||||
|
||||
ContextoGlobal.set_item_dado(T_Code.Dir, "saude", "conectado", mod_conectado)
|
||||
ContextoGlobal.set_item_dado(T_Code.Dir, "saude", "status", status)
|
||||
ContextoGlobal.set_item_dado(T_Code.Dir, "saude", "saude", saude_final)
|
||||
ContextoGlobal.set_item_dado(T_Code.Dir, "saude", "motivos", motivos_dos_ativos)
|
||||
ContextoGlobal.set_item_dado(T_Code.Dir, "saude", "saude_individual", saude_individual)
|
||||
saude_geral = {
|
||||
"conectado": mod_conectado,
|
||||
"status": status,
|
||||
"saude": saude_final,
|
||||
"motivos": motivos_dos_ativos,
|
||||
"saude_individual": saude_individual
|
||||
}
|
||||
|
||||
return resposta(status, saude_final, motivos_dos_ativos, saude_individual)
|
||||
dados_dir["saude"] = saude_geral
|
||||
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(self.t_code), dados_dir)
|
||||
#ContextoGlobalRedis.atualizar_ctx_dict(ContextoGlobalRedis.ModKey(self.t_code), saude=saude_geral)
|
||||
|
||||
return saude_geral
|
||||
|
|
|
|||
|
|
@ -1,86 +1,87 @@
|
|||
import time
|
||||
from shared.enums import T_Code, StatusModulo
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
|
||||
from health_worker.modulos.base import ModuloDiagnosticoBase
|
||||
|
||||
class GPSStatus:
|
||||
def __init__(self, dados=None):
|
||||
dados = dados or {}
|
||||
self.conectado = dados.get("conectado", False)
|
||||
self.fix = dados.get("fix", 0)
|
||||
self.rtk = dados.get("rtk", False)
|
||||
self.hAcc = dados.get("hAcc", dados.get("precisao_cm", 999.0) / 100.0)
|
||||
self.freq_hz = dados.get("freq", 0.0)
|
||||
|
||||
class ModuloGPS(ModuloDiagnosticoBase):
|
||||
def __init__(self):
|
||||
self.t_code = T_Code.Gps
|
||||
self.nome = "UM982"
|
||||
self.status = GPSStatus()
|
||||
self.timeout = 5
|
||||
|
||||
def atualizar_status(self, dados):
|
||||
agora = time.time()
|
||||
self.timestamp = agora
|
||||
self.status = GPSStatus(dados)
|
||||
|
||||
modulo = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(self.t_code), {})
|
||||
dados["saude"] = modulo.get("saude", {})
|
||||
dados["timestamp"] = agora
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(self.t_code), dados)
|
||||
self.verificar_status()
|
||||
|
||||
def verificar_status(self):
|
||||
s = self.status
|
||||
|
||||
FREQ_BASE = ContextoGlobal.get_item(T_Code.Gps, "dados", "freq_base") or 1
|
||||
modulo = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(self.t_code), {})
|
||||
FREQ_BASE = modulo.get("freq_base", 1)
|
||||
FREQ_MIN = FREQ_BASE * 0.2
|
||||
SAUDE_MIN_ALERTA = 80
|
||||
|
||||
if not s.conectado:
|
||||
return self._resposta(StatusModulo.DESCONECTADO, 0, ["GPS desconectado"])
|
||||
|
||||
if s.freq_hz <= FREQ_MIN:
|
||||
return self._resposta(StatusModulo.FALHA, 0, ["Sem resposta do GPS"])
|
||||
conectado = modulo.get("conectado", False)
|
||||
freq_hz = modulo.get("freq", 0.0)
|
||||
fix = modulo.get("fix", 0)
|
||||
rtk = modulo.get("rtk", False)
|
||||
hAcc = modulo.get("hAcc", 0)
|
||||
|
||||
saude = 100
|
||||
motivos = []
|
||||
|
||||
f = min(s.freq_hz, FREQ_BASE)
|
||||
erro = (FREQ_BASE - f) / FREQ_BASE
|
||||
p = min(int(erro * 100), 40)
|
||||
saude -= abs(p)
|
||||
if abs(p) > 0:
|
||||
motivos.append(f"Frequência baixa: {f:.2f} Hz (penalidade {p}%)")
|
||||
|
||||
# 🔹 Fix
|
||||
penalidades_fix = { 0: 90, 1: 70, 2: 40, 3: 30, 4: 5, 5: 0 }
|
||||
p = penalidades_fix.get(s.fix, 100)
|
||||
saude -= p
|
||||
if s.fix < 4:
|
||||
motivos.append(f"Fix inadequado: {s.fix} (penalidade {p}%)")
|
||||
|
||||
# 🔹 RTK
|
||||
if not s.rtk:
|
||||
saude -= 20
|
||||
motivos.append("RTK inativo")
|
||||
|
||||
# 🔹 hAcc
|
||||
p = self._penalidade_hacc(s.hAcc)
|
||||
if p > 0:
|
||||
if not conectado:
|
||||
motivos.append("GPS desconectado")
|
||||
saude = 0
|
||||
elif freq_hz <= FREQ_MIN:
|
||||
motivos.append("Sem resposta do GPS")
|
||||
saude = 0
|
||||
else:
|
||||
f = min(freq_hz, FREQ_BASE)
|
||||
erro = (FREQ_BASE - f) / FREQ_BASE
|
||||
p = min(int(erro * 100), 40)
|
||||
saude -= abs(p)
|
||||
if abs(p) > 0:
|
||||
motivos.append(f"Frequência baixa: {f:.2f} Hz (penalidade {p}%)")
|
||||
# 🔹 Fix
|
||||
penalidades_fix = { 0: 90, 1: 70, 2: 40, 3: 30, 4: 5, 5: 0 }
|
||||
p = penalidades_fix.get(fix, 100)
|
||||
saude -= p
|
||||
motivos.append(f"hAcc {'nao definido' if s.hAcc == 0 else 'alto'}: {s.hAcc:.2f} cm (penalidade {p}%)")
|
||||
if fix < 4:
|
||||
motivos.append(f"Fix inadequado: {fix} (penalidade {p}%)")
|
||||
# 🔹 RTK
|
||||
if not rtk:
|
||||
saude -= 20
|
||||
motivos.append("RTK inativo")
|
||||
# 🔹 hAcc
|
||||
p = self._penalidade_hacc(hAcc)
|
||||
if p > 0:
|
||||
saude -= p
|
||||
motivos.append(f"hAcc {'nao definido' if hAcc == 0 else 'alto'}: {hAcc:.2f} cm (penalidade {p}%)")
|
||||
|
||||
saude = max(saude, 0)
|
||||
|
||||
status = StatusModulo.OPERANTE
|
||||
status = StatusModulo.OPERANTE.value
|
||||
if saude <= 0:
|
||||
status = StatusModulo.FALHA
|
||||
status = StatusModulo.FALHA.value
|
||||
elif saude < SAUDE_MIN_ALERTA:
|
||||
status = StatusModulo.ALERTA
|
||||
status = StatusModulo.ALERTA.value
|
||||
|
||||
ContextoGlobal.set_item_dado(T_Code.Gps, "saude", "status", status)
|
||||
ContextoGlobal.set_item_dado(T_Code.Gps, "saude", "saude", saude)
|
||||
ContextoGlobal.set_item_dado(T_Code.Gps, "saude", "motivos", motivos)
|
||||
ContextoGlobal.set_item_dado(T_Code.Gps, "saude", "saude_individual", [])
|
||||
saude_geral = {
|
||||
"conectado": conectado,
|
||||
"status": status,
|
||||
"saude": saude,
|
||||
"motivos": motivos,
|
||||
"saude_idividual": []
|
||||
}
|
||||
|
||||
modulo["saude"] = saude_geral
|
||||
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(self.t_code), modulo)
|
||||
|
||||
return self._resposta(status, saude, motivos)
|
||||
return saude_geral
|
||||
|
||||
def _penalidade_hacc(self, h):
|
||||
if h < 40: return 0
|
||||
|
|
@ -89,10 +90,3 @@ class ModuloGPS(ModuloDiagnosticoBase):
|
|||
if h < 200: return 20
|
||||
if h == 0: return 30
|
||||
return 30
|
||||
|
||||
def _resposta(self, status, saude, motivos):
|
||||
return {
|
||||
"status": status,
|
||||
"saude": min(100, saude),
|
||||
"motivos": motivos
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,16 @@ import time
|
|||
import threading
|
||||
from ahrs.filters import Madgwick
|
||||
from scipy.spatial.transform import Rotation as R
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
|
||||
from shared.enums import T_Code
|
||||
|
||||
class IMUCamera:
|
||||
def __init__(self, queue):
|
||||
def __init__(self, queue, freq=10):
|
||||
self.freq = freq
|
||||
self.imu_queue = queue
|
||||
self.filtro_imu = Madgwick()
|
||||
self.q = np.array([1.0, 0.0, 0.0, 0.0])
|
||||
|
||||
self.imu_data_lock = threading.Lock()
|
||||
self.imu_status = {
|
||||
"roll": 0.0,
|
||||
"pitch": 0.0,
|
||||
"yaw": 0.0,
|
||||
"timestamp": 0.0
|
||||
}
|
||||
|
||||
self.imu_thread = threading.Thread(target=self.imu_task_loop, daemon=True)
|
||||
self.imu_thread.start()
|
||||
|
||||
|
|
@ -48,16 +43,12 @@ class IMUCamera:
|
|||
r = R.from_quat([q[1], q[2], q[3], q[0]])
|
||||
roll, pitch, yaw = r.as_euler('xyz', degrees=True)
|
||||
|
||||
with self.imu_data_lock:
|
||||
self.imu_status = {
|
||||
"roll": round(roll, 2),
|
||||
"pitch": round(pitch, 2),
|
||||
"yaw": round(yaw, 2),
|
||||
"timestamp": imuData.getTimestamp().total_seconds()
|
||||
}
|
||||
_imu = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(T_Code.Imu), {})
|
||||
_imu["roll"] = round(roll, 2)
|
||||
_imu["pitch"] = round(pitch, 2)
|
||||
_imu["yaw"] = round(yaw, 2)
|
||||
_imu["timestamp"] = imuData.getTimestamp().total_seconds()
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(T_Code.Imu), _imu)
|
||||
|
||||
time.sleep(0.01) # → Ajuste aqui a frequência (~100Hz → 10ms de intervalo)
|
||||
time.sleep(1.0 / self.freq)
|
||||
|
||||
def get_imu_status(self):
|
||||
with self.imu_data_lock:
|
||||
return self.imu_status.copy()
|
||||
|
|
|
|||
|
|
@ -1,20 +1,12 @@
|
|||
import time
|
||||
from shared.enums import T_Code, StatusModulo
|
||||
from shared.utils import penalizar_frequencia
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from health_worker.modulos.base import ModuloDiagnosticoBase, resposta
|
||||
from health_worker.modulos.base import ModuloDiagnosticoBase
|
||||
from health_worker.aprendizado.padrao_dinamico import PadraoDinamico
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis
|
||||
|
||||
class StatusMovimentacao:
|
||||
class ModuloMovimentacaoPadroes():
|
||||
def __init__(self):
|
||||
self.timestamp = 0
|
||||
self.freq_erro = 0
|
||||
self.freq_rpm = 0
|
||||
self.freq_tensao = 0
|
||||
self.freq_corrente_motor = 0
|
||||
self.freq_corrente_barramento = 0
|
||||
self.freq_temperatura = 0
|
||||
|
||||
self.padrao_tensao = PadraoDinamico("tensao", faixa_inicial=(38, 42))
|
||||
self.padrao_corrente_motor = PadraoDinamico("corrente_motor", faixa_inicial=(0, 45))
|
||||
self.padrao_corrente_barramento = PadraoDinamico("corrente_barramento", faixa_inicial=(0, 15))
|
||||
|
|
@ -25,28 +17,24 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
def __init__(self):
|
||||
self.t_code = T_Code.Mov
|
||||
self.nome = "Movimentacao"
|
||||
self.status_por_driver = {}
|
||||
self.timeout = 3 # segundos
|
||||
self.padroes = {}
|
||||
|
||||
def atualizar_status(self, dados):
|
||||
agora = time.time()
|
||||
|
||||
dados_mov = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(self.t_code), {})
|
||||
status_modulos = {
|
||||
"saude": dados_mov.get("saude", {}),
|
||||
"timestamp": agora
|
||||
}
|
||||
for item in dados:
|
||||
endereco = item.get("endereco")
|
||||
if endereco is None:
|
||||
continue
|
||||
|
||||
s = self.status_por_driver.get(endereco, StatusMovimentacao())
|
||||
s.timestamp = agora
|
||||
|
||||
freq = item.get("freq", {})
|
||||
|
||||
s.freq_erro = freq.get("erro", 0.0)
|
||||
s.freq_rpm = freq.get("rpm", 0.0)
|
||||
s.freq_tensao = freq.get("tensao", 0.0)
|
||||
s.freq_corrente_motor = freq.get("corrente_motor", 0.0)
|
||||
s.freq_corrente_barramento = freq.get("corrente_barramento", 0.0)
|
||||
s.freq_temperatura = freq.get("temperatura", 0.0)
|
||||
driver = dict(item)
|
||||
driver["saude"] = dados_mov.get(endereco, {}).get("saude", {})
|
||||
driver["timestamp"] = agora
|
||||
status_modulos[endereco] = driver
|
||||
|
||||
# Atualiza os padrões dinâmicos com os valores principais
|
||||
tensao = item.get("tensao", 0.0)
|
||||
|
|
@ -55,14 +43,14 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
#temperatura_motor = item.get("temperatura_motor", 0.0)
|
||||
temperatura_driver = item.get("temperatura_driver", 0.0)
|
||||
|
||||
s.padrao_tensao.adicionar_valor(tensao)
|
||||
s.padrao_corrente_motor.adicionar_valor(corrente_motor)
|
||||
s.padrao_corrente_barramento.adicionar_valor(corrente_barramento)
|
||||
#s.padrao_temperatura_motor.adicionar_valor(temperatura_motor)
|
||||
s.padrao_temperatura_driver.adicionar_valor(temperatura_driver)
|
||||
|
||||
self.status_por_driver[endereco] = s
|
||||
padroes = self.padroes.setdefault(endereco, ModuloMovimentacaoPadroes())
|
||||
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_motor.adicionar_valor(temperatura_motor)
|
||||
padroes.padrao_temperatura_driver.adicionar_valor(temperatura_driver)
|
||||
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(self.t_code), status_modulos)
|
||||
self.verificar_status()
|
||||
|
||||
def verificar_status(self):
|
||||
|
|
@ -77,19 +65,21 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
LIMITE_ERRO_RPM = 30
|
||||
mod_conectado = False
|
||||
|
||||
for endereco, driver in self.status_por_driver.items():
|
||||
mod_id = ContextoGlobal.get_item(T_Code.Mov, "dados", "mod_id", endereco)
|
||||
FREQ_BASE = ContextoGlobal.get_item(T_Code.Mov, "dados", "freq_base", endereco) or 1
|
||||
dados_mov = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(self.t_code), {})
|
||||
|
||||
for endereco, modulo in dados_mov.items():
|
||||
if not isinstance(endereco, int):
|
||||
continue
|
||||
mod_id = modulo.get("mod_id")
|
||||
FREQ_BASE = modulo.get("freq_base", 1)
|
||||
FREQ_MIN = FREQ_BASE * 0.5
|
||||
saude = 100
|
||||
motivos = []
|
||||
condicoes_operacionais = []
|
||||
conectado = ContextoGlobal.get_item(T_Code.Mov, "dados", "conectado", endereco) or False
|
||||
comandar = ContextoGlobal.get_item(T_Code.Mov, "dados", "comandar", endereco) or True
|
||||
freqs = ContextoGlobal.get_item(T_Code.Mov, "dados", "freq", endereco) or {}
|
||||
|
||||
maior_freq = max(freqs.values())
|
||||
|
||||
conectado = modulo.get("conectado", False)
|
||||
comandar = modulo.get("comandar", True)
|
||||
freqs = modulo.get("freq", {})
|
||||
maior_freq = max(freqs.values() if freqs != {} else [0])
|
||||
if not conectado:
|
||||
saude = 0
|
||||
elif maior_freq == 0:
|
||||
|
|
@ -101,17 +91,16 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
saude -= pen
|
||||
if (freq <= FREQ_MIN):
|
||||
motivos.append(f"Frequencia {label} baixa ({freq:.2f}/{FREQ_BASE} Hz, penalidade {pen}%)")
|
||||
|
||||
# Verificações de contexto
|
||||
rpm = ContextoGlobal.get_item(T_Code.Mov, "dados", "rpm", endereco) or 0
|
||||
rpm_sp = ContextoGlobal.get_item(T_Code.Mov, "dados", "rpm_sp", endereco) or 0
|
||||
cod_erro = ContextoGlobal.get_item(T_Code.Mov, "dados", "cod_erro", endereco) or 0
|
||||
tensao = ContextoGlobal.get_item(T_Code.Mov, "dados", "tensao", endereco) or 0
|
||||
corrente_motor = ContextoGlobal.get_item(T_Code.Mov, "dados", "corrente_motor", endereco) or 0
|
||||
corrente_barramento = ContextoGlobal.get_item(T_Code.Mov, "dados", "corrente_barramento", endereco) or 0
|
||||
temperatura_motor = ContextoGlobal.get_item(T_Code.Mov, "dados", "temperatura_motor", endereco) or 0
|
||||
temperatura_driver = ContextoGlobal.get_item(T_Code.Mov, "dados", "temperatura_driver", endereco) or 0
|
||||
freado = ContextoGlobal.get_item(T_Code.Mov, "dados", "freado", endereco) or False
|
||||
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)
|
||||
|
||||
OID_ERROS_PENALIDADES = {
|
||||
0: 0,
|
||||
|
|
@ -160,9 +149,11 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
"descricao": f"motor em movimento mesmo com freio (RPM SP: {rpm_sp}, atual: {rpm}, erro {erro_percentual_rpm*100:.1f}%, penalidade {penalidade}%)"
|
||||
})
|
||||
|
||||
padroes = self.padroes.setdefault(endereco, ModuloMovimentacaoPadroes())
|
||||
|
||||
# 🔋 Tensão fora do padrão
|
||||
if not driver.padrao_tensao.esta_dentro_do_padrao(tensao):
|
||||
grau = driver.padrao_tensao.calcular_quao_anormal(tensao)
|
||||
if not modulo.padrao_tensao.esta_dentro_do_padrao(tensao):
|
||||
grau = padroes.padrao_tensao.calcular_quao_anormal(tensao)
|
||||
condicoes_operacionais.append({
|
||||
"valor": tensao,
|
||||
"severidade": grau,
|
||||
|
|
@ -170,8 +161,8 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
})
|
||||
|
||||
# ⚡ Corrente do motor elevada
|
||||
if not driver.padrao_corrente_motor.esta_dentro_do_padrao(corrente_motor):
|
||||
grau = driver.padrao_corrente_motor.calcular_quao_anormal(corrente_motor)
|
||||
if not padroes.padrao_corrente_motor.esta_dentro_do_padrao(corrente_motor):
|
||||
grau = padroes.padrao_corrente_motor.calcular_quao_anormal(corrente_motor)
|
||||
condicoes_operacionais.append({
|
||||
"valor": corrente_motor,
|
||||
"severidade": grau,
|
||||
|
|
@ -179,8 +170,8 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
})
|
||||
|
||||
# ⚡ Corrente do barramento elevada
|
||||
if not driver.padrao_corrente_barramento.esta_dentro_do_padrao(corrente_barramento):
|
||||
grau = driver.padrao_corrente_barramento.calcular_quao_anormal(corrente_barramento)
|
||||
if not padroes.padrao_corrente_barramento.esta_dentro_do_padrao(corrente_barramento):
|
||||
grau = padroes.padrao_corrente_barramento.calcular_quao_anormal(corrente_barramento)
|
||||
condicoes_operacionais.append({
|
||||
"valor": corrente_barramento,
|
||||
"severidade": grau,
|
||||
|
|
@ -188,16 +179,15 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
})
|
||||
|
||||
# 🌡️ Temperatura alta (motor ou driver)
|
||||
if not driver.padrao_temperatura_driver.esta_dentro_do_padrao(temperatura_driver):
|
||||
grau = driver.padrao_temperatura_driver.calcular_quao_anormal(temperatura_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_individual.append({
|
||||
saude_mod = {
|
||||
"id": endereco,
|
||||
"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,
|
||||
|
|
@ -205,19 +195,18 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
"motivos": motivos,
|
||||
"condicoes_operacionais": condicoes_operacionais,
|
||||
"em_uso": comandar
|
||||
})
|
||||
|
||||
}
|
||||
saude_individual.append(saude_mod)
|
||||
if comandar:
|
||||
saude_total += saude
|
||||
total_drivers_em_uso += 1
|
||||
motivos_dos_ativos.extend([f"Driver {endereco}: {m}" for m in motivos])
|
||||
|
||||
ContextoGlobal.set_item_dado(T_Code.Mov, "dados", "saude", saude, endereco)
|
||||
modulo["saude"] = saude_mod
|
||||
if conectado:
|
||||
mod_conectado = True
|
||||
|
||||
# Verificação de ausência de drivers esperados
|
||||
drivers_respondendo = set(self.status_por_driver.keys())
|
||||
drivers_respondendo = set(k for k in dados_mov.keys() if isinstance(k, int))
|
||||
drivers_esperados = ENDERECOS_DRIVERS
|
||||
drivers_ausentes = drivers_esperados - drivers_respondendo
|
||||
|
||||
|
|
@ -225,7 +214,7 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
saude_individual.append({
|
||||
"id": endereco,
|
||||
"label": "",
|
||||
"status": StatusModulo.DESCONECTADO,
|
||||
"status": StatusModulo.DESCONECTADO.value,
|
||||
"saude": 0,
|
||||
"motivos": ["Nenhuma resposta recebida"],
|
||||
"condicoes_operacionais": [{
|
||||
|
|
@ -241,18 +230,25 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
|||
|
||||
saude_final = (saude_total // total_drivers_em_uso) if total_drivers_em_uso > 0 else 0
|
||||
|
||||
status = StatusModulo.OPERANTE
|
||||
status = StatusModulo.OPERANTE.value
|
||||
if not mod_conectado:
|
||||
status = StatusModulo.DESCONECTADO
|
||||
status = StatusModulo.DESCONECTADO.value
|
||||
elif saude_final <= 0 or len(drivers_ausentes) > 0:
|
||||
status = StatusModulo.FALHA
|
||||
status = StatusModulo.FALHA.value
|
||||
elif saude_final < SAUDE_MIN_ALERTA or any(saude["saude"] < SAUDE_MIN_ALERTA for saude in saude_individual):
|
||||
status = StatusModulo.ALERTA
|
||||
status = StatusModulo.ALERTA.value
|
||||
|
||||
ContextoGlobal.set_item_dado(T_Code.Mov, "saude", "conectado", mod_conectado)
|
||||
ContextoGlobal.set_item_dado(T_Code.Mov, "saude", "status", status)
|
||||
ContextoGlobal.set_item_dado(T_Code.Mov, "saude", "saude", saude_final)
|
||||
ContextoGlobal.set_item_dado(T_Code.Mov, "saude", "motivos", motivos_dos_ativos)
|
||||
ContextoGlobal.set_item_dado(T_Code.Mov, "saude", "saude_individual", saude_individual)
|
||||
saude_geral = {
|
||||
"conectado": mod_conectado,
|
||||
"status": status,
|
||||
"saude": saude_final,
|
||||
"motivos": motivos_dos_ativos,
|
||||
"saude_individual": saude_individual
|
||||
}
|
||||
|
||||
return resposta(status, saude_final, motivos_dos_ativos, saude_individual)
|
||||
dados_mov["saude"] = saude_geral
|
||||
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(self.t_code), dados_mov)
|
||||
#ContextoGlobalRedis.atualizar_ctx_dict(ContextoGlobalRedis.ModKey(self.t_code), saude=saude_geral)
|
||||
|
||||
return saude_geral
|
||||
|
|
|
|||
|
|
@ -1,30 +1,9 @@
|
|||
import time
|
||||
from shared.enums import T_Code, S_Code, StatusModulo
|
||||
from shared.utils import penalizar_frequencia
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from health_worker.modulos.base import ModuloDiagnosticoBase, resposta
|
||||
from health_worker.modulos.base import ModuloDiagnosticoBase
|
||||
from health_worker.aprendizado.padrao_dinamico import PadraoDinamico
|
||||
|
||||
class StatusSensor:
|
||||
def __init__(self):
|
||||
self.timestamp = 0
|
||||
self.conectado = False
|
||||
self.aferir = False
|
||||
self.mandatorio = False
|
||||
self.id = 0
|
||||
self.label = ""
|
||||
self.dados = {} # chave = label, valor = StatusCampoSensor
|
||||
|
||||
class StatusCampoSensor:
|
||||
def __init__(self, id=0, label=0, atual=0, freq=0, nominal=None, minimo=None, maximo=None):
|
||||
self.id = id
|
||||
self.label = label
|
||||
self.atual = atual
|
||||
self.freq = freq
|
||||
self.nominal = nominal
|
||||
self.minimo = minimo
|
||||
self.maximo = maximo
|
||||
self.padrao = PadraoDinamico(nome="") # opcional, preenche depois
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis
|
||||
|
||||
class StatusServo:
|
||||
def __init__(self):
|
||||
|
|
@ -44,106 +23,72 @@ class ModuloSensoriamento(ModuloDiagnosticoBase):
|
|||
super().__init__() # ✅ garante que a classe base é corretamente iniciada
|
||||
self.t_code = T_Code.Sen
|
||||
self.nome = "Sensoriamento"
|
||||
self.status_sensor = {} # Ex: sTMP → {id1: StatusSensor, id2: StatusSensor}
|
||||
self.status_servo = {} # chave: ID do servo (ex: freio_dianteiro)
|
||||
self.padroes_sensores = {}
|
||||
self.padroes_servos = {}
|
||||
self.timeout = 3 # pode ser usado para validar timestamp
|
||||
|
||||
def atualizar_status(self, dados):
|
||||
agora = time.time()
|
||||
|
||||
sensores = dados.get("sensores", [])
|
||||
for sensor in sensores:
|
||||
tipo_int = sensor.get("tipo")
|
||||
sensor_id = sensor.get("id")
|
||||
dados_sen = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(self.t_code), {})
|
||||
modulo = dict(dados)
|
||||
sensores = modulo.get("sensores", [])
|
||||
_sensores_save = dados_sen.get("sensores", {})
|
||||
for item in sensores:
|
||||
tipo_int = item.get("tipo")
|
||||
sensor_id = item.get("id")
|
||||
if tipo_int is None or sensor_id is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
tipo_enum = S_Code(tipo_int)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if tipo_enum not in self.status_sensor:
|
||||
self.status_sensor[tipo_enum] = {}
|
||||
|
||||
if sensor_id not in self.status_sensor[tipo_enum]:
|
||||
self.status_sensor[tipo_enum][sensor_id] = StatusSensor()
|
||||
|
||||
status = self.status_sensor[tipo_enum][sensor_id]
|
||||
status.timestamp = agora
|
||||
status.conectado = sensor.get("conectado", False)
|
||||
status.id = sensor_id
|
||||
status.label = sensor.get("label", sensor_id)
|
||||
status.aferir = sensor.get("aferir", False)
|
||||
status.mandatorio = sensor.get("mandatorio", False)
|
||||
status.dados.clear()
|
||||
|
||||
for item in sensor.get("dados", []):
|
||||
label = item.get("label")
|
||||
if tipo_enum not in _sensores_save:
|
||||
_sensores_save[tipo_enum] = {}
|
||||
self.padroes_sensores[tipo_enum] = {}
|
||||
if sensor_id not in _sensores_save[tipo_enum]:
|
||||
_sensores_save[tipo_enum][sensor_id] = {}
|
||||
self.padroes_sensores[tipo_enum][sensor_id] = {}
|
||||
sensor = dict(item)
|
||||
sensor["saude"] = _sensores_save[tipo_enum][sensor_id].get("saude", {})
|
||||
sensor["timestamp"] = agora
|
||||
padroes = self.padroes_sensores.get(tipo_enum, {}).get(sensor_id, {})
|
||||
for dado in sensor.get("dados", []):
|
||||
label = dado.get("label")
|
||||
if label is None:
|
||||
continue
|
||||
atual = dado.get("atual")
|
||||
nominal = dado.get("nominal")
|
||||
minimo = dado.get("minimo")
|
||||
maximo = dado.get("maximo")
|
||||
freq = dado.get("freq", 0.0)
|
||||
padrao = padroes.get(label)
|
||||
if not padrao:
|
||||
padrao = PadraoDinamico(
|
||||
nome=f"{tipo_enum.name}_{sensor_id}_{label}",
|
||||
faixa_inicial=(minimo or 0, maximo or 100),
|
||||
valor_esperado=nominal or ((minimo + maximo) / 2 if minimo is not None and maximo is not None else None)
|
||||
)
|
||||
padroes[label] = padrao
|
||||
padrao.adicionar_valor(atual)
|
||||
padrao.frequencia = freq
|
||||
_sensores_save[tipo_enum][sensor_id] = sensor
|
||||
|
||||
atual = item.get("atual")
|
||||
nominal = item.get("nominal")
|
||||
minimo = item.get("minimo")
|
||||
maximo = item.get("maximo")
|
||||
freq = item.get("freq", 0.0)
|
||||
|
||||
status.dados[label] = atual # Valor atual por label
|
||||
|
||||
status.dados[label] = StatusCampoSensor(
|
||||
id=sensor_id,
|
||||
label=status.label,
|
||||
atual=atual,
|
||||
freq=freq,
|
||||
nominal=nominal,
|
||||
minimo=minimo,
|
||||
maximo=maximo,
|
||||
)
|
||||
|
||||
status.dados[label].padrao = PadraoDinamico(
|
||||
nome=f"{tipo_enum.name}_{sensor_id}_{label}",
|
||||
faixa_inicial=(minimo or 0, maximo or 100),
|
||||
valor_esperado=nominal or ((minimo + maximo) / 2 if minimo is not None and maximo is not None else None)
|
||||
)
|
||||
|
||||
status.dados[label].padrao.adicionar_valor(atual)
|
||||
status.dados[label].padrao.frequencia = freq
|
||||
|
||||
servos = dados.get("servos", [])
|
||||
servos = modulo.get("servos", [])
|
||||
_servos_save = dados_sen.get("servos", {})
|
||||
for item in servos:
|
||||
servo_id = item.get("id")
|
||||
if servo_id is None:
|
||||
continue
|
||||
servo = dict(item)
|
||||
servo["saude"] = _servos_save.get(servo_id, {}).get("saude", {})
|
||||
servo["timestamp"] = agora
|
||||
_servos_save[servo_id] = servo
|
||||
|
||||
status = self.status_servo.get(servo_id, StatusServo())
|
||||
status.timestamp = agora
|
||||
status.conectado = item.get("conectado", False)
|
||||
status.id = servo_id
|
||||
status.label = item.get("label", servo_id)
|
||||
status.controlar = item.get("controlar", False)
|
||||
status.mandatorio = item.get("mandatorio", False)
|
||||
status.angulo_sp = item.get("angulo_sp", 0.0)
|
||||
modulo["sensores"] = _sensores_save
|
||||
modulo["servos"] = _servos_save
|
||||
modulo["timestamp"] = agora
|
||||
|
||||
# Reinicializa os dados
|
||||
status.dados = {}
|
||||
status.freqs = {}
|
||||
|
||||
for dado in item.get("dados", []):
|
||||
label = dado.get("label")
|
||||
if label is None:
|
||||
continue
|
||||
|
||||
atual = dado.get("atual", 0.0)
|
||||
freq = dado.get("freq", 0.0)
|
||||
|
||||
status.dados[label] = atual
|
||||
status.freqs[label] = freq
|
||||
|
||||
if label == "angulo":
|
||||
status.angulo = atual # Referência direta para facilitar diagnósticos
|
||||
|
||||
self.status_servo[servo_id] = status
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(self.t_code), modulo)
|
||||
|
||||
self.verificar_status()
|
||||
|
||||
|
|
@ -154,22 +99,27 @@ class ModuloSensoriamento(ModuloDiagnosticoBase):
|
|||
total_ativos = 0
|
||||
saude_individual = []
|
||||
|
||||
mod_conectado = ContextoGlobal.get_item(T_Code.Sen, "dados", "conectado") or False
|
||||
FREQ_BASE = ContextoGlobal.get_item(T_Code.Sen, "dados", "freq_base") or 1
|
||||
dados_sen = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(self.t_code), {})
|
||||
|
||||
mod_conectado = dados_sen.get("conectado", False)
|
||||
FREQ_BASE = dados_sen.get("freq_base", 1)
|
||||
FREQ_MIN = FREQ_BASE * 0.5
|
||||
SAUDE_MIN_ALERTA = 80
|
||||
|
||||
for tipo, sensores in self.status_sensor.items():
|
||||
for tipo, sensores in dados_sen.get("sensores", {}).items():
|
||||
for sensor_id, dados_sensor in sensores.items():
|
||||
saude = 100
|
||||
motivos = []
|
||||
condicoes_operacionais = []
|
||||
aferir = dados_sensor.aferir
|
||||
|
||||
for label, campo in dados_sensor.dados.items():
|
||||
conectado = dados_sensor.conectado
|
||||
freq = getattr(campo, "freq", 0.0)
|
||||
|
||||
aferir = dados_sensor.get("aferir", False)
|
||||
padroes = self.padroes_sensores.get(tipo, {}).get(sensor_id, {})
|
||||
conectado = dados_sensor.get("conectado", False)
|
||||
mandatorio = dados_sensor.get("mandatorio", False)
|
||||
for campo in dados_sensor.get("dados", []):
|
||||
label = campo.get("label")
|
||||
if label is None:
|
||||
continue
|
||||
freq = campo.get("freq", 0.0)
|
||||
if not conectado:
|
||||
saude = 0
|
||||
elif freq == 0:
|
||||
|
|
@ -181,43 +131,47 @@ class ModuloSensoriamento(ModuloDiagnosticoBase):
|
|||
if (freq <= FREQ_MIN):
|
||||
motivos.append(f"{label} frequência baixa ({freq:.2f}/{FREQ_BASE} Hz, penalidade {penalidade}%)")
|
||||
|
||||
padrao = campo.padrao if campo else None
|
||||
atual = campo.get("atual")
|
||||
padrao = padroes.get(label) if atual else None
|
||||
if padrao is not None:
|
||||
# Avaliação de condição operacional (sem penalizar saúde)
|
||||
if not padrao.esta_dentro_do_padrao(campo.atual):
|
||||
grau = padrao.calcular_quao_anormal(campo.atual)
|
||||
if not padrao.esta_dentro_do_padrao(atual):
|
||||
grau = padrao.calcular_quao_anormal(atual)
|
||||
condicoes_operacionais.append({
|
||||
"valor": campo.atual,
|
||||
"valor": atual,
|
||||
"severidade": grau,
|
||||
"descricao": f"{label} fora do padrão"
|
||||
})
|
||||
|
||||
saude = max(0, saude)
|
||||
chave = f"{tipo.name}_{sensor_id}"
|
||||
saude_individual.append({
|
||||
chave = f"{S_Code(int(tipo)).name}_{sensor_id}"
|
||||
saude_mod = {
|
||||
"id": sensor_id,
|
||||
"label": campo.label,
|
||||
"status": StatusModulo.DESCONECTADO if not conectado else StatusModulo.OPERANTE if saude >= SAUDE_MIN_ALERTA else StatusModulo.ALERTA if saude > 0 else StatusModulo.FALHA,
|
||||
"label": dados_sensor.get("label"),
|
||||
"status": (StatusModulo.DESCONECTADO if not conectado else StatusModulo.OPERANTE if saude >= SAUDE_MIN_ALERTA else StatusModulo.ALERTA if saude > 0 else StatusModulo.FALHA).value,
|
||||
"saude": saude,
|
||||
"motivos": motivos,
|
||||
"condicoes_operacionais": condicoes_operacionais,
|
||||
"em_uso": aferir
|
||||
})
|
||||
|
||||
if dados_sensor.mandatorio:
|
||||
}
|
||||
saude_individual.append(saude_mod)
|
||||
if mandatorio:
|
||||
total_ativos += 1
|
||||
saude_total += saude
|
||||
motivos_gerais.extend([f"{chave}: {m}" for m in motivos])
|
||||
dados_sensor["saude"] = saude_mod
|
||||
|
||||
for servo_id, dados_servo in self.status_servo.items():
|
||||
for servo_id, dados_servo in dados_sen.get("servos", {}).items():
|
||||
saude = 100
|
||||
motivos = []
|
||||
condicoes_operacionais = []
|
||||
controlar = dados_servo.controlar
|
||||
|
||||
for label, atual in dados_servo.dados.items():
|
||||
conectado = dados_servo.conectado
|
||||
freq = dados_servo.freqs.get(label, 0.0)
|
||||
controlar = dados_servo.get("controlar", False)
|
||||
conectado = dados_servo.get("conectado", False)
|
||||
mandatorio = dados_servo.get("mandatorio", False)
|
||||
for dado in dados_servo.get("dados", {}):
|
||||
label = dado.get("label")
|
||||
if label is None:
|
||||
continue
|
||||
freq = dado.get("freq", 0.0)
|
||||
if not conectado:
|
||||
saude = 0
|
||||
elif freq == 0:
|
||||
|
|
@ -229,46 +183,56 @@ class ModuloSensoriamento(ModuloDiagnosticoBase):
|
|||
if freq <= FREQ_MIN:
|
||||
motivos.append(f"{label} frequência baixa ({freq:.2f}/{FREQ_BASE} Hz, penalidade {penalidade}%)")
|
||||
|
||||
if label == "angulo":
|
||||
erro = abs(dados_servo.angulo - dados_servo.angulo_sp)
|
||||
if label == "ServoAnguloLeitura":
|
||||
angulo = dado.get("atual", 0.0)
|
||||
angulo_sp = dados_servo.get("angulo_sp", 0.0)
|
||||
erro = abs(angulo - angulo_sp)
|
||||
if erro > 0:
|
||||
condicoes_operacionais.append({
|
||||
"valor": dados_servo.angulo,
|
||||
"valor": angulo,
|
||||
"severidade": erro,
|
||||
"descricao": f"{label} fora do padrão"
|
||||
})
|
||||
|
||||
saude = max(0, saude)
|
||||
chave = f"servo_{servo_id}"
|
||||
saude_individual.append({
|
||||
saude_mod = {
|
||||
"id": servo_id,
|
||||
"label": dados_servo.label,
|
||||
"status": StatusModulo.DESCONECTADO if not conectado else StatusModulo.OPERANTE if saude >= SAUDE_MIN_ALERTA else StatusModulo.ALERTA if saude > 0 else StatusModulo.FALHA,
|
||||
"label": dados_servo.get("label"),
|
||||
"status": (StatusModulo.DESCONECTADO if not conectado else StatusModulo.OPERANTE if saude >= SAUDE_MIN_ALERTA else StatusModulo.ALERTA if saude > 0 else StatusModulo.FALHA).value,
|
||||
"saude": saude,
|
||||
"motivos": motivos,
|
||||
"condicoes_operacionais": condicoes_operacionais,
|
||||
"em_uso": controlar
|
||||
})
|
||||
|
||||
if dados_servo.mandatorio:
|
||||
}
|
||||
saude_individual.append(saude_mod)
|
||||
if mandatorio:
|
||||
total_ativos += 1
|
||||
saude_total += saude
|
||||
motivos_gerais.extend([f"{chave}: {m}" for m in motivos])
|
||||
dados_servo["saude"] = saude_mod
|
||||
|
||||
saude_final = (saude_total // total_ativos) if total_ativos > 0 else 100
|
||||
|
||||
status = StatusModulo.OPERANTE
|
||||
status = StatusModulo.OPERANTE.value
|
||||
if not mod_conectado:
|
||||
status = StatusModulo.DESCONECTADO
|
||||
status = StatusModulo.DESCONECTADO.value
|
||||
elif saude_final <= 0:
|
||||
status = StatusModulo.FALHA
|
||||
status = StatusModulo.FALHA.value
|
||||
elif saude_final < SAUDE_MIN_ALERTA or any(s["em_uso"] is True and s["saude"] < SAUDE_MIN_ALERTA for s in saude_individual):
|
||||
status = StatusModulo.ALERTA
|
||||
status = StatusModulo.ALERTA.value
|
||||
|
||||
ContextoGlobal.set_item_dado(T_Code.Sen, "saude", "conectado", mod_conectado)
|
||||
ContextoGlobal.set_item_dado(T_Code.Sen, "saude", "status", status)
|
||||
ContextoGlobal.set_item_dado(T_Code.Sen, "saude", "saude", saude_final)
|
||||
ContextoGlobal.set_item_dado(T_Code.Sen, "saude", "motivos", motivos_gerais)
|
||||
ContextoGlobal.set_item_dado(T_Code.Sen, "saude", "saude_individual", saude_individual)
|
||||
saude_geral = {
|
||||
"conectado": mod_conectado,
|
||||
"status": status,
|
||||
"saude": saude_final,
|
||||
"motivos": motivos_gerais,
|
||||
"saude_individual": saude_individual
|
||||
}
|
||||
|
||||
return resposta(status, saude_final, motivos_gerais, saude_individual)
|
||||
dados_sen["saude"] = saude_geral
|
||||
|
||||
ContextoGlobalRedis.set(ContextoGlobalRedis.ModKey(self.t_code), dados_sen)
|
||||
|
||||
#ContextoGlobalRedis.atualizar_ctx_dict(ContextoGlobalRedis.ModKey(self.t_code), saude=saude_geral)
|
||||
|
||||
return saude_geral
|
||||
|
|
|
|||
|
|
@ -4,12 +4,18 @@ from shared.mqtt_handler import iniciar_mqtt
|
|||
from manager_worker.main import main as iniciar_manager_worker
|
||||
from health_worker.main import main as iniciar_health_worker
|
||||
from visual_worker.main import main as iniciar_visual_worker
|
||||
from camera_worker.main import main as iniciar_camera_worker
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
|
||||
def main():
|
||||
iniciar_mqtt("ia_central")
|
||||
threading.Thread(target=iniciar_manager_worker, daemon=True).start()
|
||||
threading.Thread(target=iniciar_health_worker, daemon=True).start()
|
||||
threading.Thread(target=iniciar_visual_worker, daemon=True).start()
|
||||
|
||||
ContextoGlobal.iniciar_contexto_base()
|
||||
|
||||
threading.Thread(target=iniciar_manager_worker, args=(False,), daemon=True).start()
|
||||
threading.Thread(target=iniciar_health_worker, args=(False,), daemon=True).start()
|
||||
threading.Thread(target=iniciar_visual_worker, args=(False,), daemon=True).start()
|
||||
threading.Thread(target=iniciar_camera_worker, args=(False,), daemon=True).start()
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
|
|
|||
|
|
@ -4,13 +4,16 @@ from manager_worker.main import main as iniciar_manager_worker
|
|||
from health_worker.main import main as iniciar_health_worker
|
||||
from visual_worker.main import main as iniciar_visual_worker
|
||||
from camera_worker.main import main as iniciar_camera_worker
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
|
||||
def main():
|
||||
ContextoGlobal.iniciar_contexto_base()
|
||||
|
||||
processos = [
|
||||
#Process(target=iniciar_manager_worker, name="ManagerWorker"),
|
||||
Process(target=iniciar_health_worker, name="HealthWorker"),
|
||||
Process(target=iniciar_visual_worker, name="VisualWorker"),
|
||||
#Process(target=iniciar_camera_worker, name="CameraWorker"),
|
||||
Process(target=iniciar_manager_worker, args=(True,), name="ManagerWorker"),
|
||||
Process(target=iniciar_health_worker, args=(True,), name="HealthWorker"),
|
||||
Process(target=iniciar_visual_worker, args=(True,), name="VisualWorker"),
|
||||
Process(target=iniciar_camera_worker, args=(True,), name="CameraWorker"),
|
||||
]
|
||||
|
||||
for p in processos:
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import time
|
||||
from shared.mqtt_handler import enviar_mensagem_mqtt
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from shared.enums import StatusOperacao, T_Code
|
||||
from shared.contexto_global_redis import CmdKey, ContextoGlobalRedis
|
||||
from shared.enums import ManagerWorkerCommandType, StatusOperacao, T_Code
|
||||
from manager_worker.config import mostrar_log, topico_tx
|
||||
from manager_worker.processadores.padroes import log_status_operacao
|
||||
from manager_worker.processadores.parado import ProcessadorParado
|
||||
from manager_worker.processadores.aguardando import ProcessadorAguardando
|
||||
from manager_worker.processadores.em_andamento import ProcessadorEmAndamento
|
||||
|
|
@ -26,37 +25,33 @@ class ManagerWorker:
|
|||
if self.processador:
|
||||
comando = self.processador.processar()
|
||||
#mostrar_log(f"Comando: {comando}")
|
||||
|
||||
resposta = {
|
||||
"configurado": ContextoGlobal.get_operacao("configurado"),
|
||||
"tempo_aguardando": ContextoGlobal.get_operacao("tempo_aguardando"),
|
||||
"status_operacao": ContextoGlobal.get_operacao("status"),
|
||||
"operacao_liberada": ContextoGlobal.get_operacao("liberado"),
|
||||
"status_modulos": ContextoGlobal.get_operacao("status_modulos") or [],
|
||||
"comando": comando,
|
||||
"cmd": ManagerWorkerCommandType.EnviarDadosControle.value,
|
||||
"params": comando,
|
||||
}
|
||||
ContextoGlobalRedis.publicar_comando(CmdKey.ManagerWorkerTx, resposta)
|
||||
else:
|
||||
mostrar_log("Processador nao definido")
|
||||
|
||||
if resposta != {}:
|
||||
self.enviar_comando(resposta)
|
||||
|
||||
t1 = time.time()
|
||||
latencia = t1 - t0
|
||||
return latencia
|
||||
|
||||
def definir_processador(self):
|
||||
status = ContextoGlobal.get_operacao("status")
|
||||
if status == StatusOperacao.NaoIniciado:
|
||||
_operacao = ContextoGlobalRedis.get_operacao()
|
||||
status = _operacao.get("status")
|
||||
if status == StatusOperacao.NaoIniciado.value:
|
||||
self.processador = ProcessadorNaoIniciado()
|
||||
elif status == StatusOperacao.Parado:
|
||||
elif status == StatusOperacao.Parado.value:
|
||||
self.processador = ProcessadorParado()
|
||||
elif status == StatusOperacao.Parametrizando:
|
||||
elif status == StatusOperacao.Parametrizando.value:
|
||||
self.processador = ProcessadorParametrizando()
|
||||
elif status == StatusOperacao.Aguardando:
|
||||
elif status == StatusOperacao.Aguardando.value:
|
||||
self.processador = ProcessadorAguardando()
|
||||
elif status == StatusOperacao.EmAndamento:
|
||||
elif status == StatusOperacao.EmAndamento.value:
|
||||
self.processador = ProcessadorEmAndamento()
|
||||
elif status == StatusOperacao.Concluido:
|
||||
elif status == StatusOperacao.Concluido.value:
|
||||
self.processador = ProcessadorConcluido()
|
||||
else:
|
||||
self.processador = None
|
||||
|
|
|
|||
|
|
@ -3,16 +3,18 @@ import os
|
|||
import time
|
||||
import json
|
||||
|
||||
def main():
|
||||
def main(multi_process):
|
||||
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
print("🔎 Caminho sys.path:", os.path.abspath(os.path.join(os.path.dirname(__file__), "..")), "ManagerWorker")
|
||||
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from shared.mqtt_handler import iniciar_mqtt, registrar_callback, enviar_mensagem_script_carregado
|
||||
from shared.mqtt_handler import iniciar_mqtt, registrar_callback, enviar_mensagem_script_carregado, enviar_mensagem_mqtt
|
||||
from shared.mensagem_worker import WorkerFilaMensagens
|
||||
from manager_worker.gerenciador import ManagerWorker
|
||||
from manager_worker.config import mostrar_log, module_id, topico_tx, topico_rx
|
||||
from shared.enums import ManagerWorkerCommandType, T_Code
|
||||
from manager_worker.modulos.mpc import inicializar as iniciar_mpc
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CmdKey
|
||||
|
||||
manager = ManagerWorker()
|
||||
|
||||
|
|
@ -26,8 +28,21 @@ def main():
|
|||
def processar_comando(topico, message):
|
||||
try:
|
||||
mensagem = json.loads(message.decode())
|
||||
# Você pode tratar mensagens diretas aqui, mas o manager geralmente só envia
|
||||
mostrar_log(f"Mensagem recebida: {mensagem}")
|
||||
codigo = ManagerWorkerCommandType(mensagem.get("comando"))
|
||||
payload = mensagem.get("payload", {})
|
||||
|
||||
#mostrar_log(f"📨 Mensagem recebida no tópico {topico}. Comando recebido: {dispositivo}, payload: {payload}")
|
||||
#mostrar_log(f"Comando recebido: {dispositivo}")
|
||||
|
||||
resposta = {}
|
||||
|
||||
if codigo == ManagerWorkerCommandType.IniciarMPC:
|
||||
iniciar_mpc(payload)
|
||||
|
||||
if (resposta != {}):
|
||||
resposta["cmd"] = codigo
|
||||
enviar_mensagem_mqtt(topico=topico_tx, dispositivo=T_Code.Mod,objeto=resposta)
|
||||
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro ao processar comando: {e}")
|
||||
|
||||
|
|
@ -50,12 +65,25 @@ def main():
|
|||
|
||||
time.sleep(delay_corrigido)
|
||||
|
||||
def redis_callback(dados):
|
||||
acao = ManagerWorkerCommandType(dados.get("cmd", 0))
|
||||
|
||||
if acao == ManagerWorkerCommandType.IniciarMPC:
|
||||
parametros = dados.get("params", {}).get("parametros")
|
||||
mapa = dados.get("params", {}).get("mapa")
|
||||
if parametros is not None:
|
||||
iniciar_mpc(parametros, mapa)
|
||||
else:
|
||||
mostrar_log(f"⚠️ Comando desconhecido: {acao.name}")
|
||||
|
||||
|
||||
def inicializar():
|
||||
#iniciar_mqtt(module_id)
|
||||
if multi_process:
|
||||
iniciar_mqtt(module_id)
|
||||
mostrar_log("🚀 Iniciando Manager Worker...")
|
||||
registrar_callback(topico=topico_rx, callback=ao_receber_comando)
|
||||
ContextoGlobalRedis.ouvir_comandos(CmdKey.ManagerWorkerRx, redis_callback)
|
||||
enviar_mensagem_script_carregado(topico_tx)
|
||||
ContextoGlobal.iniciar_contexto_base()
|
||||
loop_ativo()
|
||||
|
||||
inicializar()
|
||||
|
|
|
|||
|
|
@ -1,42 +1,43 @@
|
|||
import time
|
||||
|
||||
from shared.enums import StatusCarroMapa, StatusModulo, StatusOperacao, T_Code, TipoMovimentoDirecional
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
|
||||
from manager_worker.config import mostrar_log
|
||||
from visual_worker.config import get_camera_manager
|
||||
from .mpc import get_mpc, comando_parado
|
||||
from manager_worker.modulos.mpc import get_mpc, comando_parado
|
||||
|
||||
def definir_comando():
|
||||
"""
|
||||
Define o comando de direção com base em regras mockadas + MPC
|
||||
"""
|
||||
try:
|
||||
gps = ContextoGlobal.get_item(T_Code.Gps, "dados") or {}
|
||||
visual_worker_operante = (ContextoGlobal.get_item(T_Code.Snr, "saude", "status") or StatusModulo.DESCONECTADO) == StatusModulo.OPERANTE
|
||||
_contexto = ContextoGlobalRedis.get(CtxKey.DadosContexto, {})
|
||||
_operacao = ContextoGlobalRedis.get(CtxKey.DadosOperacao, {})
|
||||
_gps = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(T_Code.Gps.name), {})
|
||||
_snr = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(T_Code.Snr.name), {})
|
||||
_trajetoria = _contexto.get(T_Code.Trajetoria.name, {})
|
||||
visual_worker_operante = (_snr.get("saude", {}).get("status", StatusModulo.DESCONECTADO.value)) == StatusModulo.OPERANTE.value
|
||||
contexto = {
|
||||
"Operacao": {
|
||||
"Status": ContextoGlobal.get_operacao("status"),
|
||||
"Finalizando": ContextoGlobal.get_operacao("finalizando")
|
||||
"Status": _operacao.get("status"),
|
||||
"Finalizando": _operacao.get("finalizando")
|
||||
},
|
||||
"GPS": {
|
||||
"Latitude": gps.get("lat", 0),
|
||||
"Longitude": gps.get("lon", 0),
|
||||
"AnguloCarro": gps.get("theta", 0),
|
||||
"Latitude": _gps.get("lat", 0),
|
||||
"Longitude": _gps.get("lon", 0),
|
||||
"AnguloCarro": _gps.get("theta", 0),
|
||||
},
|
||||
"Carro": {
|
||||
"Velocidade": ContextoGlobal.get_item(T_Code.Gerais, "dados", "velocidade_ms") or 0.0,
|
||||
"Status": ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "status") or StatusCarroMapa.Parado.value,
|
||||
"ManobrandoEntreRuas": ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "manobrando") or False,
|
||||
"DentroCorredor": (ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "CorredorAtual") or {}).get("dentro", False),
|
||||
"DistanciaEsquerda": (ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "CorredorAtual") or {}).get("dist_esq", 0.0),
|
||||
"DistanciaDireita": (ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "CorredorAtual") or {}).get("dist_dir", 0.0),
|
||||
"IdxProximoPonto": (ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "idx_proximo_ponto") or 0),
|
||||
"AnguloCaminho": (ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "angulo") or 0),
|
||||
"Velocidade": _contexto.get(T_Code.Gerais.name, {}).get("velocidade_ms", 0.0),
|
||||
"Status": _trajetoria.get("status", StatusCarroMapa.Parado.value),
|
||||
"ManobrandoEntreRuas": _trajetoria.get("manobrando", False),
|
||||
"DentroCorredor": _trajetoria.get("CorredorAtual", {}).get("dentro", False),
|
||||
"DistanciaEsquerda": _trajetoria.get("CorredorAtual", {}).get("dist_esq", 0.0),
|
||||
"DistanciaDireita": _trajetoria.get("CorredorAtual", {}).get("dist_dir", 0.0),
|
||||
"IdxProximoPonto": _trajetoria.get("idx_proximo_ponto", 0),
|
||||
"AnguloCaminho": _trajetoria.get("angulo", 0.0),
|
||||
},
|
||||
"VisualWorker": {
|
||||
"Operante": visual_worker_operante,
|
||||
"Camera": {
|
||||
"FovH": get_camera_manager().camera.parametros["fov_h"] or 0.7 if get_camera_manager().camera is not None else 0.7,
|
||||
"FovH": ContextoGlobalRedis.get(CtxKey.DadosVisualWorker, {}).get("parametros", {}).get("fov_h", 0.7),
|
||||
},
|
||||
"MatrizCusto": [[]],
|
||||
},
|
||||
|
|
@ -69,21 +70,18 @@ def comando_direcional_parado(analise={}):
|
|||
|
||||
def regras_taticas(contexto):
|
||||
try:
|
||||
if contexto["Operacao"]["Status"] != StatusOperacao.EmAndamento or contexto["Operacao"]["Finalizando"]:
|
||||
if contexto["Operacao"]["Status"] != StatusOperacao.EmAndamento.value or contexto["Operacao"]["Finalizando"]:
|
||||
mostrar_log("🟥 Direcional parado: operação não está em andamento ou está finalizando.")
|
||||
return True, comando_direcional_parado()
|
||||
|
||||
if not contexto.get("VisualWorker", {}).get("Operante", False):
|
||||
vw_operante = contexto.get("VisualWorker", {}).get("Operante", False)
|
||||
|
||||
if not vw_operante:
|
||||
#mostrar_log("⚠️ Sensores principais inativos. Rodando MPC no modo básico.")
|
||||
return False, comando_direcional_parado()
|
||||
|
||||
camera_manager = get_camera_manager()
|
||||
|
||||
if camera_manager.camera is None:
|
||||
return False, comando_direcional_parado()
|
||||
|
||||
imu = camera_manager.get_imu_data()
|
||||
if imu is not None and False:
|
||||
imu = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(T_Code.Imu))
|
||||
if imu is not None:
|
||||
if abs(imu.get("pitch", 0)) > 15 or abs(imu.get("roll", 0)) > 10:
|
||||
mostrar_log("🟥 Inclinação perigosa detectada. Parando movimentação.")
|
||||
return True, comando_direcional_parado()
|
||||
|
|
@ -93,11 +91,13 @@ def regras_taticas(contexto):
|
|||
mostrar_log("⚠️ Possível travamento detectado (velocidade quase zero).")
|
||||
# Pode evoluir para uma lógica de recuperação no futuro
|
||||
|
||||
_visual_worker = ContextoGlobalRedis.get(CtxKey.DadosVisualWorker, {})
|
||||
|
||||
# 🔸 Pega os dados do contexto
|
||||
analise = {}
|
||||
if contexto.get("RegrasAtivas", {}).get("matriz_custo", False):
|
||||
analise = camera_manager.get_analise_mais_recente()
|
||||
obstaculos = analise.get("anomalias", {}).get("deteccoes", [])
|
||||
analise = _visual_worker.get("anomalias", {})
|
||||
obstaculos = analise.get("deteccoes", [])
|
||||
if obstaculos:
|
||||
for obst in obstaculos:
|
||||
if obst.get("distancia_m", 99) < 0.4:
|
||||
|
|
@ -116,30 +116,31 @@ def definir_comando_mpc(contexto):
|
|||
mostrar_log("⚠️ MPC ainda não inicializado.")
|
||||
return
|
||||
|
||||
_controle = ContextoGlobalRedis.get(CtxKey.DadosControle, {})
|
||||
|
||||
comando_anterior = {
|
||||
"angulo": ContextoGlobal.get_controle("angulo_sp") or 0.0,
|
||||
"tipo": ContextoGlobal.get_controle("tipo_movimento_direcional") or TipoMovimentoDirecional.RodasDianteiras
|
||||
"angulo": _controle.get("angulo_sp", 0.0),
|
||||
"tipo": _controle.get("tipo_movimento_direcional", TipoMovimentoDirecional.RodasDianteiras.value),
|
||||
"velocidade": _controle.get("velocidade_sp", 0.0)
|
||||
}
|
||||
|
||||
# 🔸 Requisição ao controlador MPC
|
||||
t0 = time.time()
|
||||
comando = mpc.compute_receding(contexto, comando_anterior)
|
||||
#comando = mpc.compute_horizonte(contexto, comando_anterior)
|
||||
t1 = time.time()
|
||||
EPSILON = 1e-3 # 1 milissegundo, pra evitar divisão por zero
|
||||
if (comando != None):
|
||||
# 🔸 Extrai os dados de controle
|
||||
angulo_sp = comando.get("angulo", 0.0)
|
||||
tipo_movimento = comando.get("tipo", TipoMovimentoDirecional.RodasDianteiras)
|
||||
ContextoGlobal.set_controle_dado("angulo_sp", angulo_sp)
|
||||
ContextoGlobal.set_controle_dado("tipo_movimento_direcional", tipo_movimento)
|
||||
mostrar_log(f"🧭 Direcional MPC | Ângulo: {angulo_sp:.2f}° | Movimento: {tipo_movimento.name} | {(t1 - t0):.3f}s ({1 / max(t1 - t0, EPSILON):.3f} Hz)")
|
||||
ContextoGlobalRedis.atualizar_ctx_dict(CtxKey.DadosControle,
|
||||
angulo_sp=comando.get("angulo", 0.0),
|
||||
tipo_movimento_direcional=comando.get("tipo", TipoMovimentoDirecional.RodasDianteiras.value)
|
||||
)
|
||||
_controle = ContextoGlobalRedis.get(CtxKey.DadosControle, {})
|
||||
else:
|
||||
mostrar_log(f"🧭 Direcional MPC | Erro ao definir comando")
|
||||
|
||||
#input("⏸️ Pressione Enter para continuar...")
|
||||
|
||||
return ContextoGlobal.get_controle("angulo_sp"), ContextoGlobal.get_controle("tipo_movimento_direcional"), comando.get("simulacao", [])
|
||||
return _controle.get("angulo_sp"), _controle.get("tipo_movimento_direcional"), comando.get("simulacao", [])
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro ao definir comando MPC: {e}")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,64 +1,69 @@
|
|||
from shared.enums import StatusOperacao, StatusCarroMapa, T_Code
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
|
||||
from manager_worker.config import mostrar_log
|
||||
from manager_worker.filtros import FiltroVelocidade
|
||||
|
||||
def definir_comando():
|
||||
status_operacao = ContextoGlobal.get_operacao("status")
|
||||
finalizando = ContextoGlobal.get_operacao("finalizando")
|
||||
try:
|
||||
_operacao = ContextoGlobalRedis.get(CtxKey.DadosOperacao, {})
|
||||
status_operacao = _operacao.get("status")
|
||||
finalizando = _operacao("finalizando")
|
||||
|
||||
if (status_operacao != StatusOperacao.EmAndamento) or finalizando:
|
||||
mostrar_log("🟥 Movimento parado: operação não está em andamento.")
|
||||
return 0 # percentual velocidade = 0
|
||||
|
||||
status_carro = ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "status")
|
||||
ervas_no_radar = ContextoGlobal.get_item(T_Code.Gerais, "dados", "ervas_no_radar")
|
||||
controle_mov = ContextoGlobal.get_operacao(T_Code.Mov.name) or {}
|
||||
vel_min = controle_mov.get("percent_vel_min", 0)
|
||||
vel_max = controle_mov.get("percent_vel_max", 100)
|
||||
if (status_operacao != StatusOperacao.EmAndamento.value) or finalizando:
|
||||
mostrar_log("🟥 Movimento parado: operação não está em andamento.")
|
||||
return 0 # percentual velocidade = 0
|
||||
|
||||
_contexto = ContextoGlobalRedis.get(CtxKey.DadosContexto, {})
|
||||
_trajetoria = _contexto.get(T_Code.Trajetoria.name, {})
|
||||
status_carro = _trajetoria.get("status")
|
||||
ervas_no_radar = _contexto.get(T_Code.Gerais.name, {}).get("ervas_no_radar")
|
||||
controle_mov = _operacao.get(T_Code.Mov.name, {})
|
||||
vel_min = controle_mov.get("percent_vel_min", 0)
|
||||
vel_max = controle_mov.get("percent_vel_max", 100)
|
||||
erro = _trajetoria.get("erro_angular", 0)
|
||||
|
||||
velocidade_sp = vel_min
|
||||
|
||||
if status_carro == StatusCarroMapa.Parado:
|
||||
velocidade_sp = 0
|
||||
|
||||
elif status_carro == StatusCarroMapa.Direcionando:
|
||||
manobrando = ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "manobrando")
|
||||
desvio_necessario = ContextoGlobal.get_sonar("desvio_necessario") or False
|
||||
|
||||
if manobrando or desvio_necessario:
|
||||
velocidade_sp = vel_min
|
||||
else:
|
||||
velocidade_sp = calcular_velocidade_relativa(vel_min, vel_max)
|
||||
|
||||
elif status_carro in [StatusCarroMapa.EntrandoRua, StatusCarroMapa.SaindoRua, StatusCarroMapa.Manobrando]:
|
||||
velocidade_sp = vel_min
|
||||
|
||||
elif status_carro == StatusCarroMapa.CaminhandoRua:
|
||||
if ervas_no_radar > 0:
|
||||
if status_carro == StatusCarroMapa.Parado.value:
|
||||
velocidade_sp = 0
|
||||
|
||||
elif status_carro == StatusCarroMapa.Direcionando.value:
|
||||
manobrando = _trajetoria.get("manobrando", False)
|
||||
|
||||
if manobrando:
|
||||
velocidade_sp = vel_min
|
||||
else:
|
||||
velocidade_sp = calcular_velocidade_relativa(vel_min, vel_max, erro)
|
||||
|
||||
elif status_carro in [StatusCarroMapa.EntrandoRua.value, StatusCarroMapa.SaindoRua.value, StatusCarroMapa.Manobrando.value]:
|
||||
velocidade_sp = vel_min
|
||||
|
||||
elif status_carro == StatusCarroMapa.CaminhandoRua.value:
|
||||
if ervas_no_radar > 0:
|
||||
velocidade_sp = vel_min
|
||||
else:
|
||||
velocidade_sp = calcular_velocidade_relativa(vel_min, vel_max, erro)
|
||||
|
||||
# Aplica limites
|
||||
velocidade_sp = max(vel_min, min(vel_max, velocidade_sp))
|
||||
|
||||
filtro_vel = FiltroVelocidade()
|
||||
|
||||
if velocidade_sp <= vel_min:
|
||||
filtro_vel.reset(velocidade_sp)
|
||||
else:
|
||||
velocidade_sp = calcular_velocidade_relativa(vel_min, vel_max)
|
||||
velocidade_sp = filtro_vel.filtrar(velocidade_sp)
|
||||
|
||||
# Aplica limites
|
||||
velocidade_sp = max(vel_min, min(vel_max, velocidade_sp))
|
||||
ContextoGlobalRedis.atualizar_ctx_dict(CtxKey.DadosControle, velocidade_sp=velocidade_sp)
|
||||
|
||||
filtro_vel = FiltroVelocidade()
|
||||
#mostrar_log(f"🚗 Velocidade definida: {velocidade_sp:.1f}%")
|
||||
|
||||
if velocidade_sp <= vel_min:
|
||||
filtro_vel.reset(velocidade_sp)
|
||||
else:
|
||||
velocidade_sp = filtro_vel.filtrar(velocidade_sp)
|
||||
return velocidade_sp
|
||||
except Exception as e:
|
||||
mostrar_log("Erro ao definir o comando de movimentacao")
|
||||
|
||||
ContextoGlobal.set_controle_dado("velocidade_sp", velocidade_sp)
|
||||
|
||||
#mostrar_log(f"🚗 Velocidade definida: {velocidade_sp:.1f}%")
|
||||
|
||||
return velocidade_sp
|
||||
|
||||
def calcular_velocidade_relativa(vel_min, vel_max):
|
||||
erro = ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "erro_angular") or 0.0
|
||||
severidade = min(abs(erro) / 30.0, 1.0)
|
||||
def calcular_velocidade_relativa(vel_min, vel_max, erro_orientacao):
|
||||
severidade = min(abs(erro_orientacao) / 30.0, 1.0)
|
||||
penalidade = severidade * 0.85
|
||||
faixa = vel_max - vel_min
|
||||
velocidade = vel_max - (faixa * penalidade)
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@ from shared.utils import analisar_linhas_por_profundidade
|
|||
|
||||
_mpc = None
|
||||
|
||||
def inicializar(parametros):
|
||||
def inicializar(parametros, mapa):
|
||||
global _mpc
|
||||
_mpc = ControladorMPC(parametros_mpc=parametros)
|
||||
_mpc = ControladorMPC(parametros_mpc=parametros, pontos_mapa=mapa)
|
||||
mostrar_log(f"MPC iniciado! Trajetoria com {len(_mpc.pontos_info)} pontos")
|
||||
|
||||
def get_mpc():
|
||||
return _mpc
|
||||
|
||||
class ControladorMPC:
|
||||
def __init__(self, parametros_mpc):
|
||||
def __init__(self, parametros_mpc, pontos_mapa):
|
||||
self.raio_terra = 6371000
|
||||
self.lat0 = None
|
||||
self.lon0 = None
|
||||
|
|
@ -37,17 +37,9 @@ class ControladorMPC:
|
|||
self.pontos_info = []
|
||||
self.visitados_execucao = []
|
||||
|
||||
pontos = parametros_mpc.get("pontos", [])
|
||||
if pontos:
|
||||
self.lat0, self.lon0 = pontos[0]["lat"], pontos[0]["lon"]
|
||||
for p in pontos:
|
||||
x, y = self._latlon_to_xy(p["lat"], p["lon"], self.lat0, self.lon0)
|
||||
ponto = {
|
||||
"xy": (x, y),
|
||||
"tipo": p.get("tipo", 3),
|
||||
"distanciaMargem": p.get("distanciaMargem", 0.7)
|
||||
}
|
||||
self.pontos_info.append(ponto)
|
||||
self.pontos_info = pontos_mapa
|
||||
|
||||
if pontos_mapa:
|
||||
self.visitados_execucao = [False] * len(self.pontos_info)
|
||||
|
||||
|
||||
|
|
@ -1062,7 +1054,7 @@ class ControladorMPC:
|
|||
comando = self._processar_mpc_receding(contexto, comando_anterior)
|
||||
|
||||
t_exec = max((time.time() - self.ultima_atualizacao), 1e-3)
|
||||
mostrar_log(f"Estatisticas MPC. dt: {self.dt:.2f} s, freq = {(1.0 / self.dt):.2f} Hz, t_exec: {t_exec:.2} s, f_exec: {(1.0 / t_exec):.2f} Hz")
|
||||
mostrar_log(f"🧭 Direcional MPC | Ângulo: {float(comando['angulo']):.2f}° | Movimento: {comando['tipo'].name} | dt: {self.dt:.2f} s | freq = {(1.0 / self.dt):.2f} Hz | t_exec: {t_exec:.2} s | f_exec: {(1.0 / t_exec):.2f} Hz")
|
||||
return comando
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -1077,7 +1069,7 @@ class ControladorMPC:
|
|||
pos_lon = GPS.get("Longitude", 0)
|
||||
theta = np.radians(GPS.get("AnguloCarro", 0))
|
||||
velocidade = contexto.get("Carro", {}).get("Velocidade", 0)
|
||||
|
||||
|
||||
x, y = self._latlon_to_xy(pos_lat, pos_lon, self.lat0, self.lon0)
|
||||
|
||||
distancia_m = velocidade * self.dt
|
||||
|
|
@ -1149,7 +1141,7 @@ class ControladorMPC:
|
|||
|
||||
return {
|
||||
"angulo": np.degrees(angulo_final),
|
||||
"tipo": tipo_final,
|
||||
"tipo": tipo_final.value,
|
||||
"simulacao": simulacao_latlon
|
||||
}
|
||||
|
||||
|
|
@ -1233,7 +1225,7 @@ class ControladorMPC:
|
|||
matriz_custo = contexto.get("VisualWorker", {}).get("MatrizCusto", [[]])
|
||||
com_matriz_custo = contexto.get("VisualWorker", {}).get("Operante", False)
|
||||
|
||||
if not com_matriz_custo:
|
||||
if not com_matriz_custo or len(matriz_custo[0]) == 0:
|
||||
custos_candidatos = {}
|
||||
for tipo in tipos:
|
||||
for ang in angulos_rad:
|
||||
|
|
@ -1265,7 +1257,7 @@ class ControladorMPC:
|
|||
custos_candidatos[(tipo, ang)] = custo + custo_ideal
|
||||
|
||||
t01 = time.time()
|
||||
#print(f"Candidatos filtrados em {t01 - t00} segundos, de {len(angulos_deg)} para {len(angulos_validos)}")
|
||||
print(f"Candidatos filtrados em {t01 - t00} segundos, de {len(angulos_deg)} para {len(angulos_validos)}")
|
||||
return tipos_validos, angulos_validos, custos_candidatos
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro ao filtrar candidatos por matriz: {e}")
|
||||
|
|
@ -1371,7 +1363,7 @@ class ControladorMPC:
|
|||
indices = np.linspace(0, len(restantes) - 1, qtd_restantes).astype(int)
|
||||
selecionados = [restantes[i] for i in indices]
|
||||
|
||||
#print(f"Candidatos uniformizados de {len(angulos_validos)} para {len(extremos + selecionados)}")
|
||||
print(f"Candidatos uniformizados de {len(angulos_validos)} para {len(extremos + selecionados)}")
|
||||
|
||||
return sorted(set(extremos + selecionados))
|
||||
|
||||
|
|
@ -1477,4 +1469,4 @@ class ControladorMPC:
|
|||
|
||||
|
||||
def comando_parado():
|
||||
return 0.0, TipoMovimentoDirecional.RodasDianteiras
|
||||
return 0.0, TipoMovimentoDirecional.RodasDianteiras.value
|
||||
|
|
|
|||
|
|
@ -3,4 +3,7 @@ from manager_worker.processadores.padroes import comando_parado
|
|||
|
||||
class ProcessadorAguardando(ProcessadorBase):
|
||||
def processar(self):
|
||||
return comando_parado()
|
||||
try:
|
||||
return comando_parado()
|
||||
except Exception as e:
|
||||
print(f"Erro no processador Aguardando: {e}")
|
||||
|
|
|
|||
|
|
@ -3,4 +3,7 @@ from manager_worker.processadores.padroes import comando_parado
|
|||
|
||||
class ProcessadorConcluido(ProcessadorBase):
|
||||
def processar(self):
|
||||
return comando_parado()
|
||||
try:
|
||||
return comando_parado()
|
||||
except Exception as e:
|
||||
print(f"Erro no processador Concluido: {e}")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from shared.contexto_global import ContextoGlobal
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
|
||||
from shared.enums import ModoOperacao
|
||||
from .base import ProcessadorBase
|
||||
from manager_worker.processadores.padroes import comando_controle
|
||||
|
|
@ -7,9 +7,12 @@ from manager_worker.modulos.movimentacao import definir_comando as definir_coman
|
|||
|
||||
class ProcessadorEmAndamento(ProcessadorBase):
|
||||
def processar(self):
|
||||
modo = ContextoGlobal.get_operacao("modo")
|
||||
if modo == ModoOperacao.MapaGPS:
|
||||
angulo_sp, tipo_dir, simulacao = definir_comando_dir()
|
||||
velocidade_sp = definir_comando_mov()
|
||||
return comando_controle(percentual_velocidade=velocidade_sp, angulo=angulo_sp, tipo_movimento=tipo_dir, simulacao=simulacao)
|
||||
return None
|
||||
try:
|
||||
modo = ContextoGlobalRedis.get(CtxKey.DadosOperacao, {}).get("modo")
|
||||
if modo == ModoOperacao.MapaGPS.value:
|
||||
angulo_sp, tipo_dir, simulacao = definir_comando_dir()
|
||||
velocidade_sp = definir_comando_mov()
|
||||
return comando_controle(percentual_velocidade=velocidade_sp, angulo=angulo_sp, tipo_movimento=tipo_dir, simulacao=simulacao)
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Erro no processador EmAndamento: {e}")
|
||||
|
|
|
|||
|
|
@ -3,4 +3,7 @@ from manager_worker.processadores.padroes import comando_parado
|
|||
|
||||
class ProcessadorNaoIniciado(ProcessadorBase):
|
||||
def processar(self):
|
||||
return comando_parado()
|
||||
try:
|
||||
return comando_parado()
|
||||
except Exception as e:
|
||||
print(f"Erro no processador NaoIniciado: {e}")
|
||||
|
|
|
|||
|
|
@ -3,4 +3,7 @@ from manager_worker.processadores.padroes import comando_parado
|
|||
|
||||
class ProcessadorParado(ProcessadorBase):
|
||||
def processar(self):
|
||||
return comando_parado()
|
||||
try:
|
||||
return comando_parado()
|
||||
except Exception as e:
|
||||
print(f"Erro no processador Parado: {e}")
|
||||
|
|
|
|||
|
|
@ -4,5 +4,7 @@ from shared.contexto_global import ContextoGlobal
|
|||
|
||||
class ProcessadorParametrizando(ProcessadorBase):
|
||||
def processar(self):
|
||||
|
||||
return comando_parado()
|
||||
try:
|
||||
return comando_parado()
|
||||
except Exception as e:
|
||||
print(f"Erro no processador Parametrizando: {e}")
|
||||
|
|
|
|||
|
|
@ -1,11 +1,24 @@
|
|||
import time
|
||||
|
||||
from shared.enums import T_Code, ModoOperacao, StatusOperacao, StatusModulo, TiposControladorDirecional, VisualWorkerCommandType
|
||||
from manager_worker.modulos.mpc import inicializar as iniciar_mpc
|
||||
from shared.enums import ManagerWorkerCommandType, T_Code, ModoOperacao, StatusOperacao, StatusModulo, TiposControladorDirecional, VisualWorkerCommandType
|
||||
|
||||
def mostrar_log(mensagem):
|
||||
print(f"{time.time()} - [CONTEXTO_GLOBAL] {mensagem}")
|
||||
|
||||
class ContextoGlobal:
|
||||
|
||||
_tempo_inicio_operacao = 5
|
||||
_dados = {}
|
||||
_operacao = {}
|
||||
_sonar = {}
|
||||
_controle = {}
|
||||
|
||||
|
||||
@classmethod
|
||||
def carregar_dicionarios(cls, dados, operacao, sonar, controle):
|
||||
cls._dados = dados
|
||||
cls._operacao = operacao
|
||||
cls._sonar = sonar
|
||||
cls._controle = controle
|
||||
|
||||
@classmethod
|
||||
def iniciar_contexto_base(cls):
|
||||
|
|
@ -16,6 +29,40 @@ class ContextoGlobal:
|
|||
cls.set_operacao_dado("tempo_aguardando", time.time())
|
||||
cls.set_operacao_dado("status_modulos", [])
|
||||
cls.set_operacao_dado("modulos_mandatorios_pendentes", [])
|
||||
cls.set_operacao_dado("parametros_mandatorios", [])
|
||||
|
||||
@classmethod
|
||||
def iniciar_dicionarios_compartilhados(cls, manager):
|
||||
for cod in T_Code:
|
||||
cls._dados[cod.name] = manager.dict()
|
||||
if cod == T_Code.Dir or cod == T_Code.Mov:
|
||||
for addr in range(1, 10, 1):
|
||||
cls._dados[cod.name][addr] = manager.dict()
|
||||
cls._dados[cod.name][addr]["dados"] = manager.dict()
|
||||
cls._dados[cod.name][addr]["saude"] = manager.dict()
|
||||
else:
|
||||
cls._dados[cod.name]["dados"] = manager.dict()
|
||||
cls._dados[cod.name]["saude"] = manager.dict()
|
||||
|
||||
cls._operacao[cod.name] = manager.dict()
|
||||
if cod == T_Code.Dir:
|
||||
cls._operacao[cod.name]["mpc"] = manager.dict()
|
||||
cls._operacao[cod.name]["mpc"]["pontos"] = manager.list()
|
||||
|
||||
cls._operacao["parametros_mandatorios"] = manager.list()
|
||||
cls._operacao["status_modulos"] = manager.list()
|
||||
cls._operacao["modulos_mandatorios_pendentes"] = manager.list()
|
||||
cls._operacao["pontos_mapa"] = manager.list()
|
||||
cls._operacao["ponto_mapa_ref"] = manager.dict()
|
||||
|
||||
cls._sonar["imu"] = manager.dict()
|
||||
cls._sonar["anomalias"] = manager.dict()
|
||||
cls._sonar["solo"] = manager.dict()
|
||||
cls._sonar["radar_2d"] = manager.dict()
|
||||
cls._sonar["segmentacao"] = manager.dict()
|
||||
cls._sonar["matriz_confianca"] = manager.list()
|
||||
cls._sonar["matriz_custo"] = manager.list()
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_timestamp(cls, modulo, endereco=None):
|
||||
|
|
@ -36,7 +83,7 @@ class ContextoGlobal:
|
|||
}
|
||||
|
||||
|
||||
_dados = {}
|
||||
|
||||
|
||||
@classmethod
|
||||
def atualizar_contexto(cls, dados_contexto: dict):
|
||||
|
|
@ -64,7 +111,7 @@ class ContextoGlobal:
|
|||
|
||||
cls._atualizar_dados_operacao()
|
||||
except Exception as e:
|
||||
print(f"{time.time()} - [CONTEXTO_GLOBAL] ❌ Erro ao atualizar contexto: {e}")
|
||||
mostrar_log(f"❌ Erro ao atualizar contexto: {e}")
|
||||
|
||||
|
||||
@classmethod
|
||||
|
|
@ -100,11 +147,12 @@ class ContextoGlobal:
|
|||
|
||||
|
||||
|
||||
_operacao = {}
|
||||
|
||||
|
||||
@classmethod
|
||||
def atualizar_operacao(cls, dados_operacao: dict):
|
||||
cls._operacao = dados_operacao
|
||||
for k, v in dados_operacao.items():
|
||||
cls._operacao[k] = v
|
||||
cls._atualizar_dados_operacao()
|
||||
cls.set_operacao_dado("configurado", True)
|
||||
|
||||
|
|
@ -248,14 +296,25 @@ class ContextoGlobal:
|
|||
|
||||
@classmethod
|
||||
def get_operacao(cls, dado=None):
|
||||
if (dado == None):
|
||||
return cls._operacao
|
||||
else:
|
||||
return cls._operacao.get(dado)
|
||||
try:
|
||||
if (dado is None):
|
||||
return cls._operacao
|
||||
else:
|
||||
return cls._operacao.get(dado)
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro ao consultar operacao: {e}")
|
||||
|
||||
@classmethod
|
||||
def set_operacao_dado(cls, dado, valor):
|
||||
cls._operacao[dado] = valor
|
||||
try:
|
||||
atual = cls._operacao.get(dado)
|
||||
if isinstance(atual, list) and hasattr(atual, 'append'):
|
||||
atual.clear()
|
||||
atual.extend(valor)
|
||||
else:
|
||||
cls._operacao[dado] = valor
|
||||
except Exception as e:
|
||||
cls._operacao[dado] = valor
|
||||
|
||||
@classmethod
|
||||
def _iniciar_operacao(cls):
|
||||
|
|
@ -271,14 +330,15 @@ class ContextoGlobal:
|
|||
if (dados_dir.get("tipo_controle", TiposControladorDirecional.Manual) == TiposControladorDirecional.MPC):
|
||||
dados_mpc = dados_dir.get("mpc") or {}
|
||||
if (len(dados_mpc.get("pontos", []))) > 0:
|
||||
iniciar_mpc(dados_mpc)
|
||||
from shared.mqtt_handler import enviar_mensagem_manager_worker
|
||||
enviar_mensagem_manager_worker(ManagerWorkerCommandType.IniciarMPC, dados_mpc)
|
||||
|
||||
@classmethod
|
||||
def _atualizar_visual_worker(cls):
|
||||
mx_id = (cls.get_operacao(T_Code.Snr.name) or {}).get("mx_id")
|
||||
if mx_id is not None:
|
||||
from shared.mqtt_handler import enviar_mensagem_visual_worker
|
||||
enviar_mensagem_visual_worker(VisualWorkerCommandType.INICIAR_CAMERA_MANAGER.value, {"mx_id": mx_id})
|
||||
enviar_mensagem_visual_worker(VisualWorkerCommandType.IniciarCameraManager, {"mx_id": mx_id})
|
||||
|
||||
@classmethod
|
||||
def _atualizar_pontos_mapa(cls):
|
||||
|
|
@ -304,11 +364,12 @@ class ContextoGlobal:
|
|||
cls.set_operacao_dado("ponto_mapa_ref", p_ref)
|
||||
|
||||
|
||||
_sonar = {}
|
||||
|
||||
|
||||
@classmethod
|
||||
def atualizar_sonar(cls, dados_sonar: dict):
|
||||
cls._sonar = dados_sonar
|
||||
for k, v in dados_sonar.items():
|
||||
cls._sonar[k] = v
|
||||
|
||||
@classmethod
|
||||
def get_sonar(cls, dado=None):
|
||||
|
|
@ -319,7 +380,7 @@ class ContextoGlobal:
|
|||
|
||||
|
||||
|
||||
_controle = {}
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_controle(cls, dado=None):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,343 @@
|
|||
# contexto_global.py
|
||||
import threading
|
||||
import time
|
||||
import redis
|
||||
import json
|
||||
from enum import Enum
|
||||
|
||||
from shared.enums import ManagerWorkerCommandType, ModoOperacao, StatusModulo, StatusOperacao, T_Code, TiposControladorDirecional, VisualWorkerCommandType
|
||||
|
||||
class CtxKey(str, Enum):
|
||||
DadosCameras = "ctx:dados_cameras"
|
||||
DadosModulo = "ctx:dados_modulo_"
|
||||
DadosOperacao = "ctx:dados_operacao"
|
||||
DadosContexto = "ctx:dados_contexto"
|
||||
DadosControle = "ctx:dados_controle"
|
||||
DadosVisualWorker = "ctx:dados_visual_worker"
|
||||
|
||||
|
||||
class CmdKey(str, Enum):
|
||||
VisualWorkerTx = "cmd_tx:visual_worker"
|
||||
VisualWorkerRx = "cmd_rx:visual_worker"
|
||||
HealthWorkerTx = "cmd_tx:health_worker"
|
||||
HealthWorkerRx = "cmd_rx:health_worker"
|
||||
CameraWorkerTx = "cmd_tx:camera_worker"
|
||||
CameraWorkerRx = "cmd_rx:camera_worker"
|
||||
ManagerWorkerTx = "cmd_tx:manager_worker"
|
||||
ManagerWorkerRx = "cmd_rx:manager_worker"
|
||||
|
||||
|
||||
def mostrar_log(mensagem):
|
||||
print(f"{time.time()} - [Redis] {mensagem}")
|
||||
|
||||
class ContextoGlobalRedis:
|
||||
_redis = redis.Redis(host="localhost", port=6379, decode_responses=True)
|
||||
|
||||
@classmethod
|
||||
def set(cls, chave: CtxKey, valor):
|
||||
"""Salva qualquer estrutura como JSON"""
|
||||
try:
|
||||
chave_str = chave.value if hasattr(chave, "value") else str(chave)
|
||||
cls._redis.set(chave_str, json.dumps(valor))
|
||||
except Exception as e:
|
||||
mostrar_log(f"Erro no set: {e}")
|
||||
|
||||
@classmethod
|
||||
def get(cls, chave: CtxKey, default=None):
|
||||
"""Lê a estrutura e decodifica de volta para objeto"""
|
||||
try:
|
||||
chave_str = chave.value if hasattr(chave, "value") else str(chave)
|
||||
valor = cls._redis.get(chave_str)
|
||||
if valor is None:
|
||||
return default
|
||||
try:
|
||||
return json.loads(valor)
|
||||
except json.JSONDecodeError:
|
||||
return valor
|
||||
except Exception as e:
|
||||
mostrar_log(f"Erro no get, chave: {chave}: {e}")
|
||||
|
||||
@classmethod
|
||||
def hset(cls, chave, campo, valor):
|
||||
"""Salva um campo dentro de uma hash"""
|
||||
try:
|
||||
cls._redis.hset(chave, campo, json.dumps(valor))
|
||||
except Exception as e:
|
||||
mostrar_log(f"Erro no hset: {e}")
|
||||
|
||||
@classmethod
|
||||
def hget(cls, chave, campo, default=None):
|
||||
"""Lê um campo de uma hash"""
|
||||
try:
|
||||
valor = cls._redis.hget(chave, campo)
|
||||
if valor is None:
|
||||
return default
|
||||
try:
|
||||
return json.loads(valor)
|
||||
except json.JSONDecodeError:
|
||||
return valor
|
||||
except Exception as e:
|
||||
mostrar_log(f"Erro no hget: {e}")
|
||||
|
||||
@classmethod
|
||||
def atualizar_ctx_dict(cls, chave: CtxKey, **novos_campos):
|
||||
dados = cls.get(chave.value, {})
|
||||
dados.update(novos_campos)
|
||||
cls.set(chave, dados)
|
||||
|
||||
@classmethod
|
||||
def publicar_comando(cls, canal: CmdKey, dados):
|
||||
"""Publica um comando JSON em um canal Redis"""
|
||||
try:
|
||||
cls._redis.publish(canal.value, json.dumps(dados))
|
||||
except Exception as e:
|
||||
mostrar_log(f"Erro ao publicar comando: {e}")
|
||||
|
||||
@classmethod
|
||||
def ouvir_comandos(cls, canal: CmdKey, funcao_callback):
|
||||
"""Assina um canal Redis e chama a função para cada comando recebido"""
|
||||
def _ouvinte():
|
||||
pubsub = cls._redis.pubsub()
|
||||
pubsub.subscribe(canal.value)
|
||||
mostrar_log(f"Escutando canal: {canal.value}")
|
||||
for mensagem in pubsub.listen():
|
||||
if mensagem["type"] == "message":
|
||||
try:
|
||||
dados = json.loads(mensagem["data"])
|
||||
funcao_callback(dados)
|
||||
except Exception as e:
|
||||
mostrar_log(f"Erro ao processar comando recebido: {e}")
|
||||
|
||||
# Roda o ouvinte em uma thread separada (não bloqueia)
|
||||
threading.Thread(target=_ouvinte, daemon=True).start()
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_operacao(cls):
|
||||
return cls.get(CtxKey.DadosOperacao, {})
|
||||
|
||||
@classmethod
|
||||
def get_contexto(cls):
|
||||
return cls.get(CtxKey.DadosContexto, {})
|
||||
|
||||
@classmethod
|
||||
def get_controle(cls):
|
||||
return cls.get(CtxKey.DadosControle, {})
|
||||
|
||||
@classmethod
|
||||
def ModKey(cls, mod: T_Code):
|
||||
"""Lê a estrutura e decodifica de volta para objeto"""
|
||||
return CtxKey.DadosModulo.value + mod.name
|
||||
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def atualizar_dados_operacao(cls):
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, configurado=True)
|
||||
cls._atualizar_operacao_liberada()
|
||||
cls._atualiza_status_operacao()
|
||||
cls._atualizar_visual_worker()
|
||||
cls._atualizar_pontos_mapa()
|
||||
|
||||
@classmethod
|
||||
def _atualizar_operacao_liberada(cls):
|
||||
_operacao = cls.get_operacao()
|
||||
|
||||
# 🔹 Check se todos os módulos mandatórios estão disponíveis
|
||||
modulos_mandatorios = set(_operacao.get("modulos_mandatorios", []))
|
||||
modulos_presentes = set()
|
||||
status_modulos = []
|
||||
|
||||
for t_code in T_Code:
|
||||
if t_code.value < 100:
|
||||
continue
|
||||
|
||||
try:
|
||||
_mod_data = cls.get(cls.ModKey(t_code), {})
|
||||
_saude = _mod_data.get("saude", {})
|
||||
conectado = _saude.get("conectado", False)
|
||||
status = _saude.get("status", (StatusModulo.FALHA.value if conectado else StatusModulo.DESCONECTADO.value))
|
||||
saude = _saude.get("saude", 0.0)
|
||||
motivos = _saude.get("motivos", ["Modulo desconectado"])
|
||||
saude_individual = _saude.get("saude_individual", [])
|
||||
if status == StatusModulo.OPERANTE.value:
|
||||
modulos_presentes.add(t_code.value)
|
||||
status_modulos.append({
|
||||
"modulo": t_code.value,
|
||||
"status": status,
|
||||
"saude": saude,
|
||||
"motivos": motivos,
|
||||
"saude_individual": saude_individual
|
||||
})
|
||||
except Exception as e:
|
||||
status_modulos.append({
|
||||
"modulo": t_code.value,
|
||||
"status": StatusModulo.FALHA.value,
|
||||
"saude": 0.0,
|
||||
"motivos": [f"Erro ao verificar {t_code.name}: {e}"],
|
||||
"saude_individual": saude_individual
|
||||
})
|
||||
|
||||
todos_presentes = modulos_mandatorios.issubset(modulos_presentes)
|
||||
modulos_pendentes = modulos_mandatorios - modulos_presentes
|
||||
|
||||
cls.atualizar_ctx_dict(
|
||||
CtxKey.DadosOperacao,
|
||||
status_modulos=status_modulos,
|
||||
modulos_mandatorios_pendentes=list(modulos_pendentes)
|
||||
)
|
||||
|
||||
# 🔹 Parâmetros mandatórios
|
||||
parametros = _operacao.get("parametros_mandatorios", [])
|
||||
parametros_ok = True
|
||||
|
||||
# 🔹 Define status da operação
|
||||
debug_mode = _operacao.get("debug_mode", False)
|
||||
|
||||
# 🔹 Atualiza status de liberação
|
||||
liberou = (todos_presentes and parametros_ok) or debug_mode
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, liberado=liberou)
|
||||
|
||||
@classmethod
|
||||
def _atualiza_status_operacao(cls):
|
||||
agora = time.time()
|
||||
|
||||
#_contexto = cls.get_contexto()
|
||||
_operacao = cls.get_operacao()
|
||||
|
||||
iniciado = _operacao.get("iniciado", False)
|
||||
finalizando = _operacao.get("finalizando", False)
|
||||
op_liberada = _operacao.get("liberado", False)
|
||||
status_anterior_parado = _operacao.get("status_anterior_parado", StatusOperacao.Parado.value)
|
||||
status_iniciado_anterior = _operacao.get("status_iniciado_anterior", False)
|
||||
modo = _operacao.get("modo")
|
||||
status_atual = _operacao.get("status")
|
||||
|
||||
try:
|
||||
# Iniciando operacao
|
||||
if (iniciado and not status_iniciado_anterior):
|
||||
cls._iniciar_operacao()
|
||||
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status_iniciado_anterior=iniciado)
|
||||
|
||||
if not iniciado:
|
||||
if status_atual != StatusOperacao.Concluido:
|
||||
cls.atualizar_ctx_dict(
|
||||
CtxKey.DadosOperacao,
|
||||
tempo_aguardando=0,
|
||||
status=StatusOperacao.Parametrizando.value
|
||||
)
|
||||
return # Não avança se não iniciou
|
||||
|
||||
# 🔸 Modo MANUAL
|
||||
if modo == ModoOperacao.Manual:
|
||||
if op_liberada:
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status=StatusOperacao.EmAndamento.value)
|
||||
else:
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status=StatusOperacao.Parado.value)
|
||||
return
|
||||
|
||||
# 🔸 Modo MAPA GPS ou IA
|
||||
if modo in (ModoOperacao.MapaGPS, ModoOperacao.TreinamentoIA):
|
||||
# Verifica se ainda está aguardando tempo inicial
|
||||
tempo_aguardando = _operacao.get("tempo_aguardando", 0)
|
||||
if tempo_aguardando == 0:
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, tempo_aguardando=agora)
|
||||
tempo_aguardando = _operacao.get("tempo_aguardando", 0)
|
||||
if (tempo_aguardando + _operacao.get("tempo_aguardar_inicio_operacao", 25)) > agora:
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status=StatusOperacao.Aguardando.value)
|
||||
return
|
||||
|
||||
_corredor = cls.get_contexto().get(T_Code.Trajetoria.name, {}).get("CorredorAtual", {})
|
||||
#print(f"Corredor Atual: {_corredor}")
|
||||
if _corredor.get("ultimo", False) and _corredor.get("concluido", False):
|
||||
if iniciado and not finalizando:
|
||||
cls._finalizar_operacao()
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status=StatusOperacao.Concluido.value)
|
||||
return
|
||||
|
||||
# Não está liberado: para operação
|
||||
if not op_liberada:
|
||||
if status_atual != StatusOperacao.Parado:
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status_anterior_parado=status_atual)
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status=StatusOperacao.Parado.value)
|
||||
return
|
||||
|
||||
# Estava parado e liberou: volta para aguardando
|
||||
if status_atual == StatusOperacao.Parado:
|
||||
cls.atualizar_ctx_dict(
|
||||
CtxKey.DadosOperacao,
|
||||
tempo_aguardando=agora,
|
||||
status=StatusOperacao.Aguardando.value
|
||||
)
|
||||
return
|
||||
|
||||
# Restaura status anterior à parada
|
||||
if status_anterior_parado != StatusOperacao.Parado:
|
||||
cls.atualizar_ctx_dict(
|
||||
CtxKey.DadosOperacao,
|
||||
status=status_anterior_parado,
|
||||
status_anterior_parado=StatusOperacao.Parado.value
|
||||
)
|
||||
else:
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, status=StatusOperacao.EmAndamento.value)
|
||||
|
||||
finally:
|
||||
pass
|
||||
#_operacao = cls.get_operacao()
|
||||
#status = _operacao.get("status")
|
||||
#liberado = _operacao.get("liberado")
|
||||
#print(f"Status Atual: {status.name}, Liberado: {liberado}")
|
||||
|
||||
@classmethod
|
||||
def _iniciar_operacao(cls):
|
||||
cls._atualizar_mpc()
|
||||
|
||||
@classmethod
|
||||
def _finalizar_operacao(cls):
|
||||
cls.atualizar_ctx_dict(CtxKey.DadosOperacao, iniciado=False)
|
||||
|
||||
@classmethod
|
||||
def _atualizar_mpc(cls):
|
||||
dados_dir = cls.get_operacao().get(T_Code.Dir.name, {})
|
||||
if (dados_dir.get("tipo_controle", TiposControladorDirecional.Manual.value) == TiposControladorDirecional.MPC.value):
|
||||
dados_mpc = dados_dir.get("mpc", {})
|
||||
mapa = cls.get_operacao().get("pontos_mapa", [])
|
||||
cls.publicar_comando(CmdKey.ManagerWorkerRx, { "cmd": ManagerWorkerCommandType.IniciarMPC.value, "params": { "parametros": dados_mpc, "mapa": mapa } })
|
||||
|
||||
@classmethod
|
||||
def _atualizar_visual_worker(cls):
|
||||
mx_id = cls.get_operacao().get(T_Code.Snr.name, {}).get("mx_id")
|
||||
if mx_id is not None:
|
||||
cls.publicar_comando(CmdKey.VisualWorkerRx, { "cmd": VisualWorkerCommandType.IniciarCameraManager, "params": mx_id })
|
||||
|
||||
@classmethod
|
||||
def _atualizar_pontos_mapa(cls):
|
||||
pontos_info = []
|
||||
p_ref = (0, 0)
|
||||
_operacao = cls.get_operacao()
|
||||
dados_dir = _operacao.get(T_Code.Dir.name, {})
|
||||
if (dados_dir.get("tipo_controle", TiposControladorDirecional.Manual.value) == TiposControladorDirecional.MPC.value):
|
||||
dados_mpc = dados_dir.get("mpc", {})
|
||||
pontos = dados_mpc.get("pontos", [])
|
||||
if pontos is not None and len(pontos) > 0:
|
||||
p_ref = pontos[0]["lat"], pontos[0]["lon"]
|
||||
from shared.gps_handler import GPSHandler
|
||||
handler = GPSHandler(p_ref[0], p_ref[1])
|
||||
for p in pontos:
|
||||
x, y = handler.converter_latlon_para_xz(p["lat"], p["lon"])
|
||||
ponto = {
|
||||
"xy": (x, y),
|
||||
"tipo": p.get("tipo", 3),
|
||||
"distanciaMargem": p.get("distanciaMargem", 0.7)
|
||||
}
|
||||
pontos_info.append(ponto)
|
||||
cls.atualizar_ctx_dict(
|
||||
CtxKey.DadosOperacao,
|
||||
pontos_mapa=pontos_info,
|
||||
ponto_mapa_ref=p_ref
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,14 +1,22 @@
|
|||
from enum import IntEnum
|
||||
|
||||
class TipoComando(IntEnum):
|
||||
class VisualWorkerCommandType(IntEnum):
|
||||
SalvarFrames = 1
|
||||
IniciarCameraManager = 2
|
||||
AtualizarSaudeCamera = 3
|
||||
GetCameraFrame = 4
|
||||
|
||||
class HealthWorkerCommandType(IntEnum):
|
||||
SetDadosModulo = 1
|
||||
GetDadosModulo = 2
|
||||
SetDadosContexto = 3
|
||||
GetDadosContexto = 4
|
||||
SetDadosOperacao = 5
|
||||
GetDadosOperacao = 6
|
||||
GetListaCameras = 7
|
||||
GetCameraFrame = 8
|
||||
SetDadosContexto = 2
|
||||
SetDadosOperacao = 3
|
||||
|
||||
class CameraWorkerCommandType(IntEnum):
|
||||
GetListaCameras = 1
|
||||
|
||||
class ManagerWorkerCommandType(IntEnum):
|
||||
IniciarMPC = 1
|
||||
EnviarDadosControle = 2
|
||||
|
||||
class ModoOperacao(IntEnum):
|
||||
NaoDefinido = 0
|
||||
|
|
@ -37,6 +45,7 @@ class T_Code(IntEnum):
|
|||
Operacao = 50
|
||||
Trajetoria = 51
|
||||
Gerais = 52
|
||||
Imu = 53
|
||||
Mov = 100
|
||||
Dir = 101
|
||||
Sen = 102
|
||||
|
|
@ -135,11 +144,7 @@ class TipoPontoRua(IntEnum):
|
|||
Desvio = 7
|
||||
|
||||
# Visual Worker
|
||||
class VisualWorkerCommandType(IntEnum):
|
||||
SALVAR_FRAMES = 0
|
||||
ATUALIZAR_CAMERA_MANAGER = 1
|
||||
INICIAR_CAMERA_MANAGER = 2
|
||||
GET_ULTIMA_ANALISE = 3
|
||||
|
||||
|
||||
class VisualWorkerTipoDeteccao(IntEnum):
|
||||
SEGURO = 1
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import paho.mqtt.client as mqtt
|
|||
import json
|
||||
import time
|
||||
|
||||
from shared.enums import T_Code, VisualWorkerCommandType
|
||||
from shared.enums import CameraWorkerCommandType, HealthWorkerCommandType, ManagerWorkerCommandType, T_Code, VisualWorkerCommandType
|
||||
|
||||
mqtt_client = None
|
||||
debug = True
|
||||
|
|
@ -68,17 +68,47 @@ def enviar_mensagem_mqtt_entre_modulos(topico: str, dispositivo: T_Code, comando
|
|||
}
|
||||
mqtt_client.publish(topico, json.dumps(mensagem))
|
||||
|
||||
def enviar_mensagem_visual_worker(comando: VisualWorkerCommandType, payload):
|
||||
def enviar_mensagem_visual_worker(comando: VisualWorkerCommandType, payload = {}):
|
||||
#mostrar_log(f"Enviando dados MQTT para o dispositivo {dispositivo}...")
|
||||
mensagem = {
|
||||
"momento": time.time(),
|
||||
"dispositivo": T_Code.Snr,
|
||||
"comando": comando,
|
||||
"comando": comando.value,
|
||||
"payload": payload
|
||||
}
|
||||
from visual_worker.config import topico_rx
|
||||
mqtt_client.publish(topico_rx, json.dumps(mensagem))
|
||||
|
||||
def enviar_mensagem_manager_worker(comando: ManagerWorkerCommandType, payload = {}):
|
||||
#mostrar_log(f"Enviando dados MQTT para o dispositivo {dispositivo}...")
|
||||
mensagem = {
|
||||
"momento": time.time(),
|
||||
"comando": comando.value,
|
||||
"payload": payload
|
||||
}
|
||||
from manager_worker.config import topico_rx
|
||||
mqtt_client.publish(topico_rx, json.dumps(mensagem))
|
||||
|
||||
def enviar_mensagem_health_worker(comando: HealthWorkerCommandType, payload = {}):
|
||||
#mostrar_log(f"Enviando dados MQTT para o dispositivo {dispositivo}...")
|
||||
mensagem = {
|
||||
"momento": time.time(),
|
||||
"dispositivo": T_Code.Mod,
|
||||
"comando": comando.value,
|
||||
"payload": payload
|
||||
}
|
||||
from health_worker.config import topico_rx
|
||||
mqtt_client.publish(topico_rx, json.dumps(mensagem))
|
||||
|
||||
def enviar_mensagem_camera_worker(comando: CameraWorkerCommandType, payload = {}):
|
||||
#mostrar_log(f"Enviando dados MQTT para o dispositivo {dispositivo}...")
|
||||
mensagem = {
|
||||
"momento": time.time(),
|
||||
"comando": comando.value,
|
||||
"payload": payload
|
||||
}
|
||||
from camera_worker.config import topico_rx
|
||||
mqtt_client.publish(topico_rx, json.dumps(mensagem))
|
||||
|
||||
def registrar_callback(topico, callback):
|
||||
_inscritos[topico] = callback
|
||||
if mqtt_client:
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ import time
|
|||
import cv2
|
||||
import cupy as cp
|
||||
import numpy as np
|
||||
from health_worker.config import get_camera_manager
|
||||
from visual_worker.utils import calcular_threshold_anomalias, calcular_referencia, obter_regiao_solo, calcular_profundidades_setores, gerar_heatmap
|
||||
from visual_worker.utils import calcular_threshold_anomalias, calcular_referencia, gerar_heatmap
|
||||
from visual_worker.processamento.analise_solo import AnaliseSoloManager
|
||||
from visual_worker.processamento.analise_anomalias import AnaliseAnomaliasManager
|
||||
from visual_worker.processamento.radar_top_down import Radar2DManager
|
||||
|
|
@ -15,30 +14,45 @@ from visual_worker.processamento.segmentacao_semantica import ClassesSegmentacao
|
|||
from shared.enums import T_Code, VisualWorkerTipoAnalise
|
||||
from shared.utils import analisar_linhas_por_profundidade, decode_image_base64
|
||||
from shared.gps_handler import GPSHandler
|
||||
from camera_worker.camera_oak import CameraOak
|
||||
import depthai as dai
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
|
||||
|
||||
class CameraManager:
|
||||
_iniciando = False # variável de classe (compartilhada por instâncias)
|
||||
|
||||
def __init__(self, mostrar_log, mx_id=None):
|
||||
if CameraManager._iniciando:
|
||||
return
|
||||
|
||||
CameraManager._iniciando = True
|
||||
def __init__(self, mostrar_log):
|
||||
self.mostrar_log = mostrar_log
|
||||
self.mx_id = None
|
||||
self.camera = None
|
||||
self.operante = False
|
||||
self.iniciando = False
|
||||
|
||||
def inicializar(self, mx_id):
|
||||
if self.iniciando:
|
||||
return
|
||||
|
||||
_camera_conectada = ContextoGlobalRedis.get(CtxKey.DadosCameras, {}).get(mx_id) is not None
|
||||
if not _camera_conectada:
|
||||
return
|
||||
|
||||
self.iniciando = True
|
||||
if mx_id == None:
|
||||
self.iniciando = False
|
||||
#self.mostrar_log(f"❌ Camera não definida.")
|
||||
CameraManager._iniciando = False
|
||||
return
|
||||
|
||||
self.mx_id = mx_id
|
||||
self.camera = get_camera_manager().get_cameras(mx_id)
|
||||
|
||||
try:
|
||||
dev_info = dai.DeviceInfo(mx_id)
|
||||
nova = CameraOak(self.mostrar_log, dev_info)
|
||||
if nova.iniciado:
|
||||
self.camera = nova
|
||||
except Exception as e:
|
||||
self.mostrar_log(f"⚠️ Camera com ID {mx_id} não conectada.")
|
||||
self.iniciando = False
|
||||
return
|
||||
if self.camera is None:
|
||||
self.mostrar_log(f"❌ Camera com ID {mx_id} não encontrada no manager.")
|
||||
CameraManager._iniciando = False
|
||||
self.mostrar_log(f"❌ Camera com ID {mx_id} não iniciada.")
|
||||
else:
|
||||
self.mostrar_log(f"📷 Camera visual selecionada: {self.camera.modelo} - {self.camera.mx_id}")
|
||||
self.grid_ref = None
|
||||
|
|
@ -53,8 +67,13 @@ class CameraManager:
|
|||
self.operante = True
|
||||
self._ultima_analise = None
|
||||
self._timestamp_analise = None
|
||||
self.iniciar_loop_analise_continua(4.0)
|
||||
CameraManager._iniciando = False
|
||||
self._iniciar_loop_analise_continua(4.0)
|
||||
self.iniciando = False
|
||||
self.atualizar_saude_camera()
|
||||
|
||||
def atualizar_saude_camera(self):
|
||||
if self.camera is not None:
|
||||
self.camera.atualizar_saude()
|
||||
|
||||
def get_rgb_frame(self):
|
||||
if self.camera is None:
|
||||
|
|
@ -88,16 +107,11 @@ class CameraManager:
|
|||
return gerar_heatmap(frame, self.camera.parametros["distancia_maxima"]), timestamp, res
|
||||
return None, None, None
|
||||
|
||||
def get_imu_data(self):
|
||||
if self.camera is not None:
|
||||
return self.camera.requisitar_imu_status()
|
||||
return None
|
||||
|
||||
def iniciar_loop_analise_continua(self, freq):
|
||||
def _iniciar_loop_analise_continua(self, freq):
|
||||
def loop():
|
||||
while self.operante:
|
||||
t_ini = time.time()
|
||||
resultado = self.realizar_analise(
|
||||
resultado = self._realizar_analise(
|
||||
tipos_analise=[
|
||||
VisualWorkerTipoAnalise.MATRIZ_CONFIANCA,
|
||||
VisualWorkerTipoAnalise.ANOMALIA,
|
||||
|
|
@ -105,19 +119,24 @@ class CameraManager:
|
|||
VisualWorkerTipoAnalise.RADAR_2D
|
||||
]
|
||||
)
|
||||
self._ultima_analise = resultado
|
||||
self._timestamp_analise = time.time()
|
||||
self._ultima_analise = resultado
|
||||
dados_visual_worker = {
|
||||
"timestamp": self._timestamp_analise,
|
||||
"matriz_confianca": resultado.get("matriz_confianca", [[]]),
|
||||
"matriz_custo": resultado.get("matriz_custo", [[]]),
|
||||
"segmentacao_perfil_corredor": resultado.get("segmentacao", {}).get("corredor_perfil", []),
|
||||
"anomalias": resultado.get("anomalias", {}).get("deteccoes", []),
|
||||
"solo_perfol": resultado.get("solo", {}).get("perfil", []),
|
||||
"solo_inclinacao": resultado.get("solo", {}).get("inclinacao", 0),
|
||||
"profundidade_perfil_corredor": resultado.get("radar_2d", {}).get("analise", {}).get("corredor_perfil", []),
|
||||
"sombras": resultado.get("radar_2d", {}).get("analise", {}).get("bboxes_sombra", []),
|
||||
}
|
||||
ContextoGlobalRedis.set(CtxKey.DadosVisualWorker, dados_visual_worker)
|
||||
|
||||
time.sleep(max(0, (1.0 / freq) - (self._timestamp_analise - t_ini)))
|
||||
threading.Thread(target=loop, daemon=True).start()
|
||||
|
||||
def get_analise_mais_recente(self, max_idade_segundos=1.0):
|
||||
if self._ultima_analise is None:
|
||||
return {}
|
||||
t = time.time() - self._timestamp_analise
|
||||
if t > max_idade_segundos:
|
||||
self.mostrar_log(f"⚠️ Análise visual desatualizada a {t} segundos. Limite de {max_idade_segundos} segundos.")
|
||||
return self._ultima_analise
|
||||
|
||||
def _calibrar(self, n_frames=50):
|
||||
self.calibrado = False
|
||||
|
||||
|
|
@ -142,23 +161,12 @@ class CameraManager:
|
|||
return False
|
||||
|
||||
self.depth_referencia = calcular_referencia(lista_frames, metodo="mediana")
|
||||
self.setores_referencia = self._salvar_grade_referencia()
|
||||
self.grid_ref = self._gerar_grid_referencia(self.depth_referencia)
|
||||
|
||||
self.calibrado = True
|
||||
self.mostrar_log(f"✅ Calibração concluída com sucesso! Definido {len(self.setores_referencia)} setores no solo")
|
||||
self.mostrar_log(f"✅ Calibração concluída com sucesso! Matriz {self.grid_ref_shape}")
|
||||
return True
|
||||
|
||||
def _salvar_grade_referencia(self):
|
||||
n_setores = self.camera.parametros["qtd_setores_solo"]
|
||||
distancia_max = self.camera.parametros["distancia_maxima"]
|
||||
percent_altura = self.camera.parametros["percentual_altura_solo"]
|
||||
# 🔸 Extrai a região do solo
|
||||
depth_solo, y_inicio, linhas_solo, altura, largura = obter_regiao_solo(self.depth_referencia, percent_altura)
|
||||
# 🔸 Calcula as profundidades médias dos setores
|
||||
setores_referencia, largura_setor = calcular_profundidades_setores(depth_solo, n_setores, largura, distancia_max)
|
||||
return setores_referencia
|
||||
|
||||
def _gerar_grid_referencia(self, depth_frame_medio: np.ndarray):
|
||||
altura, largura = depth_frame_medio.shape
|
||||
grid_h, grid_w = self.grid_ref_shape
|
||||
|
|
@ -185,7 +193,7 @@ class CameraManager:
|
|||
|
||||
return grid_referencia
|
||||
|
||||
def realizar_analise(self, tipos_analise: list, largura_min: float = 0.15, altura_min: float = 0.15):
|
||||
def _realizar_analise(self, tipos_analise: list, largura_min: float = 0.15, altura_min: float = 0.15):
|
||||
t0 = time.time()
|
||||
resultado = {
|
||||
"timestamp": t0,
|
||||
|
|
@ -193,7 +201,8 @@ class CameraManager:
|
|||
"solo": {},
|
||||
"radar_2d": {},
|
||||
"segmentacao": {},
|
||||
"matriz_confianca": []
|
||||
"matriz_confianca": [],
|
||||
"matriz_custo": []
|
||||
}
|
||||
|
||||
if not self.calibrado:
|
||||
|
|
@ -350,7 +359,7 @@ class CameraManager:
|
|||
cv2.imwrite(caminho_heatmap, heatmap_frame)
|
||||
frames_salvos.append(caminho_heatmap)
|
||||
|
||||
analise = self.get_analise_mais_recente()
|
||||
analise = self._ultima_analise
|
||||
|
||||
for res in analise.keys():
|
||||
if (res == "timestamp"):
|
||||
|
|
@ -1013,21 +1022,20 @@ class CameraManager:
|
|||
matriz_custo.append(linha_custo)
|
||||
|
||||
# 🔵 Após montar, adiciona bonificação do caminho do mapa (se houver)
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
pontos_xy = ContextoGlobal.get_operacao("pontos_mapa") or []
|
||||
pontos_xy = ContextoGlobalRedis.get_operacao().get("pontos_mapa", [])
|
||||
#print(f"Pontos do mapa: {len(pontos_xy)}")
|
||||
if pontos_xy:
|
||||
gps = ContextoGlobal.get_item(T_Code.Gps, "dados") or {}
|
||||
lat_atual = gps.get("lat", 0)
|
||||
lon_atual = gps.get("lon", 0)
|
||||
theta_robo = np.radians(gps.get("theta", 0.0))
|
||||
if len(pontos_xy) > 0:
|
||||
_gps = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(T_Code.Gps), {})
|
||||
lat_atual = _gps.get("lat", 0)
|
||||
lon_atual = _gps.get("lon", 0)
|
||||
theta_robo = np.radians(_gps.get("theta", 0.0))
|
||||
|
||||
# Converte usando mesmo ponto de referência do mapa
|
||||
p_ref = ContextoGlobal.get_operacao("ponto_mapa_ref") or (0, 0)
|
||||
p_ref = ContextoGlobalRedis.get_operacao().get("ponto_mapa_ref", (0, 0))
|
||||
gps_handler = GPSHandler(p_ref[0], p_ref[1])
|
||||
x_robo, z_robo = gps_handler.converter_latlon_para_xz(lat_atual, lon_atual)
|
||||
|
||||
idx_proximo = ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "idx_proximo_ponto") or 0
|
||||
idx_proximo = ContextoGlobalRedis.get_contexto().get(T_Code.Trajetoria.name, {}).get("idx_proximo_ponto", 0)
|
||||
pontos_plotar = []
|
||||
distancia_max = 3.0 # linhas_info[0]["distancia"]
|
||||
|
||||
|
|
@ -1132,19 +1140,18 @@ class CameraManager:
|
|||
|
||||
# Se tiver ponto do caminho, desenha seta direcional
|
||||
try:
|
||||
from shared.contexto_global import ContextoGlobal
|
||||
pontos_xy = ContextoGlobal.get_operacao("pontos_mapa") or []
|
||||
gps = ContextoGlobal.get_item(T_Code.Gps, "dados") or {}
|
||||
if pontos_xy and gps:
|
||||
lat, lon = gps.get("lat", 0), gps.get("lon", 0)
|
||||
theta_robo = np.radians(gps.get("theta", 0.0))
|
||||
pontos_xy = ContextoGlobalRedis.get_operacao().get("pontos_mapa", [])
|
||||
_gps = ContextoGlobalRedis.get(ContextoGlobalRedis.ModKey(T_Code.Gps))
|
||||
if len(pontos_xy) > 0 and _gps:
|
||||
lat, lon = _gps.get("lat", 0), _gps.get("lon", 0)
|
||||
theta_robo = np.radians(_gps.get("theta", 0.0))
|
||||
from shared.gps_handler import GPSHandler
|
||||
p_ref = ContextoGlobal.get_operacao("ponto_mapa_ref") or (0, 0)
|
||||
p_ref = ContextoGlobalRedis.get_operacao().get("ponto_mapa_ref", (0, 0))
|
||||
handler = GPSHandler(p_ref[0], p_ref[1])
|
||||
x_robo, z_robo = handler.converter_latlon_para_xz(lat, lon)
|
||||
|
||||
# Pega o próximo ponto (idx já considerado pelo seu sistema)
|
||||
idx_proximo = ContextoGlobal.get_item(T_Code.Trajetoria, "dados", "idx_proximo_ponto") or 0
|
||||
idx_proximo = ContextoGlobalRedis.get_contexto().get(T_Code.Trajetoria.name, {}).get("idx_proximo_ponto", 0)
|
||||
#idx_proximo -= 1
|
||||
if idx_proximo < len(pontos_xy):
|
||||
p = pontos_xy[idx_proximo]["xy"]
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ def iniciar_camera_manager(mx_id):
|
|||
if mx_id is None:
|
||||
return
|
||||
agora = time.time()
|
||||
if ((agora - ultima_atualizacao) > 5 and (manager is None or manager.camera is None or manager.mx_id != mx_id)):
|
||||
if (not manager.iniciando and (agora - ultima_atualizacao) > 5 and (manager.camera is None or manager.mx_id != mx_id)):
|
||||
ultima_atualizacao = agora
|
||||
mostrar_log("Iniciando Camera Manager...")
|
||||
manager = CameraManager(mostrar_log=mostrar_log, mx_id=mx_id)
|
||||
if manager.camera is not None:
|
||||
manager.inicializar(mx_id=mx_id)
|
||||
if manager.camera is not None and manager.operante:
|
||||
mostrar_log(f"Camera manager iniciado, com MX_ID: {mx_id}")
|
||||
|
||||
def atualizar_camera_manager():
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ import os
|
|||
import time
|
||||
import json
|
||||
|
||||
def main():
|
||||
|
||||
def main(multi_process):
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
print("🔎 Caminho sys.path:", os.path.abspath(os.path.join(os.path.dirname(__file__), "..")), "VisualWorker")
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ def main():
|
|||
from shared.mensagem_worker import WorkerFilaMensagens
|
||||
from shared.enums import T_Code, VisualWorkerCommandType
|
||||
from visual_worker.config import mostrar_log, module_id, topico_tx, topico_rx, get_camera_manager, iniciar_camera_manager, atualizar_camera_manager
|
||||
from shared.contexto_global_redis import ContextoGlobalRedis, CmdKey, CtxKey
|
||||
|
||||
# 🔹 Callback que o MQTT chama
|
||||
def ao_receber_comando(topico, payload):
|
||||
|
|
@ -21,8 +23,7 @@ def main():
|
|||
try:
|
||||
# Aqui você decodifica o comando e processa normalmente
|
||||
mensagem = json.loads(message.decode())
|
||||
dispositivo = T_Code(mensagem.get("dispositivo"))
|
||||
codigo = int(mensagem.get("comando"))
|
||||
codigo = VisualWorkerCommandType(mensagem.get("comando"))
|
||||
payload = mensagem.get("payload", {})
|
||||
|
||||
#mostrar_log(f"📨 Mensagem recebida no tópico {topico}. Comando recebido: {dispositivo}, payload: {payload}")
|
||||
|
|
@ -30,7 +31,7 @@ def main():
|
|||
|
||||
resposta = {}
|
||||
|
||||
if codigo == VisualWorkerCommandType.SALVAR_FRAMES:
|
||||
if codigo == VisualWorkerCommandType.SalvarFrames:
|
||||
manager = get_camera_manager()
|
||||
frames = manager.salvar_frames()
|
||||
resposta = {
|
||||
|
|
@ -39,23 +40,20 @@ def main():
|
|||
"frames": frames
|
||||
}
|
||||
}
|
||||
elif codigo == VisualWorkerCommandType.ATUALIZAR_CAMERA_MANAGER:
|
||||
elif codigo == VisualWorkerCommandType.AtualizarCameraManager:
|
||||
atualizar_camera_manager()
|
||||
elif codigo == VisualWorkerCommandType.INICIAR_CAMERA_MANAGER:
|
||||
elif codigo == VisualWorkerCommandType.IniciarCameraManager:
|
||||
mx_id = payload.get("mx_id")
|
||||
iniciar_camera_manager(mx_id)
|
||||
elif codigo == VisualWorkerCommandType.GET_ULTIMA_ANALISE:
|
||||
manager = get_camera_manager()
|
||||
resposta = manager.get_analise_mais_recente()
|
||||
|
||||
if (resposta != {}):
|
||||
resposta["cmd"] = codigo
|
||||
enviar_mensagem_mqtt(topico=topico_tx, dispositivo=codigo, objeto=resposta)
|
||||
enviar_mensagem_mqtt(topico=topico_tx, dispositivo=T_Code.Snr, objeto=resposta)
|
||||
|
||||
except Exception as e:
|
||||
print("❌ Erro ao processar comando MQTT:", e)
|
||||
|
||||
mostrar_log(f"❌ Erro ao processar comando MQTT: {e}")
|
||||
|
||||
|
||||
# 🔹 Inicia a fila e os workers
|
||||
fila_mensagens = WorkerFilaMensagens(id=module_id, processador_callback=processar_comando)
|
||||
|
||||
|
|
@ -64,21 +62,49 @@ def main():
|
|||
def loop_ativo():
|
||||
while True:
|
||||
try:
|
||||
a = 1
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
mostrar_log("🛑 Encerrando Visual Worker...")
|
||||
break
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro no loop do Visual: {e}")
|
||||
|
||||
time.sleep(1)
|
||||
time.sleep(5)
|
||||
|
||||
def redis_callback(dados):
|
||||
acao = VisualWorkerCommandType(dados.get("cmd", 0))
|
||||
|
||||
if acao == VisualWorkerCommandType.IniciarCameraManager:
|
||||
mx_id = dados.get("params")
|
||||
if mx_id is not None:
|
||||
iniciar_camera_manager(mx_id)
|
||||
elif acao == VisualWorkerCommandType.AtualizarSaudeCamera:
|
||||
get_camera_manager().atualizar_saude_camera()
|
||||
elif acao == VisualWorkerCommandType.GetCameraFrame:
|
||||
frame, timestamp, res = get_camera_manager().get_rgb_frame()
|
||||
base64_img = None
|
||||
if frame is not None:
|
||||
from shared.utils import encode_image_base64
|
||||
base64_img = encode_image_base64(frame)
|
||||
resposta = {
|
||||
"cmd": acao.value,
|
||||
"params": {
|
||||
"timestamp": timestamp,
|
||||
"frame": base64_img
|
||||
}
|
||||
}
|
||||
ContextoGlobalRedis.publicar_comando(CmdKey.VisualWorkerTx, resposta)
|
||||
else:
|
||||
mostrar_log(f"⚠️ Comando desconhecido: {acao.name}")
|
||||
|
||||
|
||||
# 🔹 Execução principal
|
||||
def inicializar():
|
||||
iniciar_mqtt(module_id)
|
||||
if multi_process:
|
||||
iniciar_mqtt(module_id)
|
||||
mostrar_log("🚀 Iniciando Visual Worker...")
|
||||
registrar_callback(topico=topico_rx, callback=ao_receber_comando)
|
||||
ContextoGlobalRedis.ouvir_comandos(CmdKey.VisualWorkerRx, redis_callback)
|
||||
enviar_mensagem_script_carregado(topico_tx)
|
||||
loop_ativo()
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import cv2
|
|||
|
||||
from visual_worker.processamento.gestor_deteccoes import GestorDeteccoes
|
||||
from visual_worker.filtros import aplicar_filtros_mapa_anomalias, filtrar_deteccoes
|
||||
from visual_worker.processamento.segmentacao_semantica import ClassesSegmentacao
|
||||
|
||||
class AnaliseAnomaliasManager:
|
||||
def __init__(self):
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
pip
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
Metadata-Version: 2.4
|
||||
Name: redis
|
||||
Version: 6.2.0
|
||||
Summary: Python client for Redis database and key-value store
|
||||
Project-URL: Changes, https://github.com/redis/redis-py/releases
|
||||
Project-URL: Code, https://github.com/redis/redis-py
|
||||
Project-URL: Documentation, https://redis.readthedocs.io/en/latest/
|
||||
Project-URL: Homepage, https://github.com/redis/redis-py
|
||||
Project-URL: Issue tracker, https://github.com/redis/redis-py/issues
|
||||
Author-email: "Redis Inc." <oss@redis.com>
|
||||
License-Expression: MIT
|
||||
License-File: LICENSE
|
||||
Keywords: Redis,database,key-value-store
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Requires-Python: >=3.9
|
||||
Requires-Dist: async-timeout>=4.0.3; python_full_version < '3.11.3'
|
||||
Provides-Extra: hiredis
|
||||
Requires-Dist: hiredis>=3.2.0; extra == 'hiredis'
|
||||
Provides-Extra: jwt
|
||||
Requires-Dist: pyjwt>=2.9.0; extra == 'jwt'
|
||||
Provides-Extra: ocsp
|
||||
Requires-Dist: cryptography>=36.0.1; extra == 'ocsp'
|
||||
Requires-Dist: pyopenssl>=20.0.1; extra == 'ocsp'
|
||||
Requires-Dist: requests>=2.31.0; extra == 'ocsp'
|
||||
Description-Content-Type: text/markdown
|
||||
|
||||
# redis-py
|
||||
|
||||
The Python interface to the Redis key-value store.
|
||||
|
||||
[](https://github.com/redis/redis-py/actions?query=workflow%3ACI+branch%3Amaster)
|
||||
[](https://redis-py.readthedocs.io/en/stable/)
|
||||
[](./LICENSE)
|
||||
[](https://pypi.org/project/redis/)
|
||||
[](https://github.com/redis/redis-py/releases)
|
||||
[](https://codecov.io/gh/redis/redis-py)
|
||||
|
||||
[Installation](#installation) | [Usage](#usage) | [Advanced Topics](#advanced-topics) | [Contributing](https://github.com/redis/redis-py/blob/master/CONTRIBUTING.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
**Note:** redis-py 5.0 will be the last version of redis-py to support Python 3.7, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 5.1 will support Python 3.8+.
|
||||
**Note:** redis-py 6.1.0 will be the last version of redis-py to support Python 3.8, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 6.2.0 will support Python 3.9+.
|
||||
---------------------------------------------
|
||||
|
||||
## How do I Redis?
|
||||
|
||||
[Learn for free at Redis University](https://redis.io/learn/university)
|
||||
|
||||
[Try the Redis Cloud](https://redis.io/try-free/)
|
||||
|
||||
[Dive in developer tutorials](https://redis.io/learn)
|
||||
|
||||
[Join the Redis community](https://redis.io/community/)
|
||||
|
||||
[Work at Redis](https://redis.io/careers/)
|
||||
|
||||
## Installation
|
||||
|
||||
Start a redis via docker (for Redis versions >= 8.0):
|
||||
|
||||
``` bash
|
||||
docker run -p 6379:6379 -it redis:latest
|
||||
```
|
||||
|
||||
Start a redis via docker (for Redis versions < 8.0):
|
||||
|
||||
``` bash
|
||||
docker run -p 6379:6379 -it redis/redis-stack:latest
|
||||
|
||||
To install redis-py, simply:
|
||||
|
||||
``` bash
|
||||
$ pip install redis
|
||||
```
|
||||
|
||||
For faster performance, install redis with hiredis support, this provides a compiled response parser, and *for most cases* requires zero code changes.
|
||||
By default, if hiredis >= 1.0 is available, redis-py will attempt to use it for response parsing.
|
||||
|
||||
``` bash
|
||||
$ pip install "redis[hiredis]"
|
||||
```
|
||||
|
||||
Looking for a high-level library to handle object mapping? See [redis-om-python](https://github.com/redis/redis-om-python)!
|
||||
|
||||
## Supported Redis Versions
|
||||
|
||||
The most recent version of this library supports Redis version [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES), [7.4](https://github.com/redis/redis/blob/7.4/00-RELEASENOTES) and [8.0](https://github.com/redis/redis/blob/8.0/00-RELEASENOTES).
|
||||
|
||||
The table below highlights version compatibility of the most-recent library versions and redis versions.
|
||||
|
||||
| Library version | Supported redis versions |
|
||||
|-----------------|-------------------|
|
||||
| 3.5.3 | <= 6.2 Family of releases |
|
||||
| >= 4.5.0 | Version 5.0 to 7.0 |
|
||||
| >= 5.0.0 | Version 5.0 to 7.4 |
|
||||
| >= 6.0.0 | Version 7.2 to current |
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Example
|
||||
|
||||
``` python
|
||||
>>> import redis
|
||||
>>> r = redis.Redis(host='localhost', port=6379, db=0)
|
||||
>>> r.set('foo', 'bar')
|
||||
True
|
||||
>>> r.get('foo')
|
||||
b'bar'
|
||||
```
|
||||
|
||||
The above code connects to localhost on port 6379, sets a value in Redis, and retrieves it. All responses are returned as bytes in Python, to receive decoded strings, set *decode_responses=True*. For this, and more connection options, see [these examples](https://redis.readthedocs.io/en/stable/examples.html).
|
||||
|
||||
|
||||
#### RESP3 Support
|
||||
To enable support for RESP3, ensure you have at least version 5.0 of the client, and change your connection object to include *protocol=3*
|
||||
|
||||
``` python
|
||||
>>> import redis
|
||||
>>> r = redis.Redis(host='localhost', port=6379, db=0, protocol=3)
|
||||
```
|
||||
|
||||
### Connection Pools
|
||||
|
||||
By default, redis-py uses a connection pool to manage connections. Each instance of a Redis class receives its own connection pool. You can however define your own [redis.ConnectionPool](https://redis.readthedocs.io/en/stable/connections.html#connection-pools).
|
||||
|
||||
``` python
|
||||
>>> pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
|
||||
>>> r = redis.Redis(connection_pool=pool)
|
||||
```
|
||||
|
||||
Alternatively, you might want to look at [Async connections](https://redis.readthedocs.io/en/stable/examples/asyncio_examples.html), or [Cluster connections](https://redis.readthedocs.io/en/stable/connections.html#cluster-client), or even [Async Cluster connections](https://redis.readthedocs.io/en/stable/connections.html#async-cluster-client).
|
||||
|
||||
### Redis Commands
|
||||
|
||||
There is built-in support for all of the [out-of-the-box Redis commands](https://redis.io/commands). They are exposed using the raw Redis command names (`HSET`, `HGETALL`, etc.) except where a word (i.e. del) is reserved by the language. The complete set of commands can be found [here](https://github.com/redis/redis-py/tree/master/redis/commands), or [the documentation](https://redis.readthedocs.io/en/stable/commands.html).
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
The [official Redis command documentation](https://redis.io/commands)
|
||||
does a great job of explaining each command in detail. redis-py attempts
|
||||
to adhere to the official command syntax. There are a few exceptions:
|
||||
|
||||
- **MULTI/EXEC**: These are implemented as part of the Pipeline class.
|
||||
The pipeline is wrapped with the MULTI and EXEC statements by
|
||||
default when it is executed, which can be disabled by specifying
|
||||
transaction=False. See more about Pipelines below.
|
||||
|
||||
- **SUBSCRIBE/LISTEN**: Similar to pipelines, PubSub is implemented as
|
||||
a separate class as it places the underlying connection in a state
|
||||
where it can\'t execute non-pubsub commands. Calling the pubsub
|
||||
method from the Redis client will return a PubSub instance where you
|
||||
can subscribe to channels and listen for messages. You can only call
|
||||
PUBLISH from the Redis client (see [this comment on issue
|
||||
#151](https://github.com/redis/redis-py/issues/151#issuecomment-1545015)
|
||||
for details).
|
||||
|
||||
For more details, please see the documentation on [advanced topics page](https://redis.readthedocs.io/en/stable/advanced_features.html).
|
||||
|
||||
### Pipelines
|
||||
|
||||
The following is a basic example of a [Redis pipeline](https://redis.io/docs/manual/pipelining/), a method to optimize round-trip calls, by batching Redis commands, and receiving their results as a list.
|
||||
|
||||
|
||||
``` python
|
||||
>>> pipe = r.pipeline()
|
||||
>>> pipe.set('foo', 5)
|
||||
>>> pipe.set('bar', 18.5)
|
||||
>>> pipe.set('blee', "hello world!")
|
||||
>>> pipe.execute()
|
||||
[True, True, True]
|
||||
```
|
||||
|
||||
### PubSub
|
||||
|
||||
The following example shows how to utilize [Redis Pub/Sub](https://redis.io/docs/manual/pubsub/) to subscribe to specific channels.
|
||||
|
||||
``` python
|
||||
>>> r = redis.Redis(...)
|
||||
>>> p = r.pubsub()
|
||||
>>> p.subscribe('my-first-channel', 'my-second-channel', ...)
|
||||
>>> p.get_message()
|
||||
{'pattern': None, 'type': 'subscribe', 'channel': b'my-second-channel', 'data': 1}
|
||||
```
|
||||
|
||||
### Redis’ search and query capabilities default dialect
|
||||
|
||||
Release 6.0.0 introduces a client-side default dialect for Redis’ search and query capabilities.
|
||||
By default, the client now overrides the server-side dialect with version 2, automatically appending *DIALECT 2* to commands like *FT.AGGREGATE* and *FT.SEARCH*.
|
||||
|
||||
**Important**: Be aware that the query dialect may impact the results returned. If needed, you can revert to a different dialect version by configuring the client accordingly.
|
||||
|
||||
``` python
|
||||
>>> from redis.commands.search.field import TextField
|
||||
>>> from redis.commands.search.query import Query
|
||||
>>> from redis.commands.search.index_definition import IndexDefinition
|
||||
>>> import redis
|
||||
|
||||
>>> r = redis.Redis(host='localhost', port=6379, db=0)
|
||||
>>> r.ft().create_index(
|
||||
>>> (TextField("name"), TextField("lastname")),
|
||||
>>> definition=IndexDefinition(prefix=["test:"]),
|
||||
>>> )
|
||||
|
||||
>>> r.hset("test:1", "name", "James")
|
||||
>>> r.hset("test:1", "lastname", "Brown")
|
||||
|
||||
>>> # Query with default DIALECT 2
|
||||
>>> query = "@name: James Brown"
|
||||
>>> q = Query(query)
|
||||
>>> res = r.ft().search(q)
|
||||
|
||||
>>> # Query with explicit DIALECT 1
|
||||
>>> query = "@name: James Brown"
|
||||
>>> q = Query(query).dialect(1)
|
||||
>>> res = r.ft().search(q)
|
||||
```
|
||||
|
||||
You can find further details in the [query dialect documentation](https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/dialects/).
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
### Author
|
||||
|
||||
redis-py is developed and maintained by [Redis Inc](https://redis.io). It can be found [here](
|
||||
https://github.com/redis/redis-py), or downloaded from [pypi](https://pypi.org/project/redis/).
|
||||
|
||||
Special thanks to:
|
||||
|
||||
- Andy McCurdy (<sedrik@gmail.com>) the original author of redis-py.
|
||||
- Ludovico Magnocavallo, author of the original Python Redis client,
|
||||
from which some of the socket code is still used.
|
||||
- Alexander Solovyov for ideas on the generic response callback
|
||||
system.
|
||||
- Paul Hubbard for initial packaging support.
|
||||
|
||||
[](https://redis.io)
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
redis-6.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
redis-6.2.0.dist-info/METADATA,sha256=nU7-kjJL_I8KHMRNFmLBeS9tWPwTPOw2_oQ8dEBfSPM,10783
|
||||
redis-6.2.0.dist-info/RECORD,,
|
||||
redis-6.2.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
redis-6.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
||||
redis-6.2.0.dist-info/licenses/LICENSE,sha256=pXslClvwPXr-VbdAYzE_Ktt7ANVGwKsUmok5gzP-PMg,1074
|
||||
redis/__init__.py,sha256=h5BepEwJtNeHNFaMJ0VdpbtFFTC8QcY5s9wqAnYG8TE,2060
|
||||
redis/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/__pycache__/backoff.cpython-311.pyc,,
|
||||
redis/__pycache__/cache.cpython-311.pyc,,
|
||||
redis/__pycache__/client.cpython-311.pyc,,
|
||||
redis/__pycache__/cluster.cpython-311.pyc,,
|
||||
redis/__pycache__/connection.cpython-311.pyc,,
|
||||
redis/__pycache__/crc.cpython-311.pyc,,
|
||||
redis/__pycache__/credentials.cpython-311.pyc,,
|
||||
redis/__pycache__/event.cpython-311.pyc,,
|
||||
redis/__pycache__/exceptions.cpython-311.pyc,,
|
||||
redis/__pycache__/lock.cpython-311.pyc,,
|
||||
redis/__pycache__/ocsp.cpython-311.pyc,,
|
||||
redis/__pycache__/retry.cpython-311.pyc,,
|
||||
redis/__pycache__/sentinel.cpython-311.pyc,,
|
||||
redis/__pycache__/typing.cpython-311.pyc,,
|
||||
redis/__pycache__/utils.cpython-311.pyc,,
|
||||
redis/_parsers/__init__.py,sha256=gyf5dp918NuJAkWFl8sX1Z-qAvbX_40-_7YCTM6Rvjc,693
|
||||
redis/_parsers/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/_parsers/__pycache__/base.cpython-311.pyc,,
|
||||
redis/_parsers/__pycache__/commands.cpython-311.pyc,,
|
||||
redis/_parsers/__pycache__/encoders.cpython-311.pyc,,
|
||||
redis/_parsers/__pycache__/helpers.cpython-311.pyc,,
|
||||
redis/_parsers/__pycache__/hiredis.cpython-311.pyc,,
|
||||
redis/_parsers/__pycache__/resp2.cpython-311.pyc,,
|
||||
redis/_parsers/__pycache__/resp3.cpython-311.pyc,,
|
||||
redis/_parsers/__pycache__/socket.cpython-311.pyc,,
|
||||
redis/_parsers/base.py,sha256=k6n7-oTmmzAUiiZpaB6Vfjzlj_torwBsaPBEYdOTDak,9908
|
||||
redis/_parsers/commands.py,sha256=pmR4hl4u93UvCmeDgePHFc6pWDr4slrKEvCsdMmtj_M,11052
|
||||
redis/_parsers/encoders.py,sha256=X0jvTp-E4TZUlZxV5LJJ88TuVrF1vly5tuC0xjxGaSc,1734
|
||||
redis/_parsers/helpers.py,sha256=X5wkGDtuzseeCz23_t3FJpzy1ltIvh7zO1uD3cypiOs,29184
|
||||
redis/_parsers/hiredis.py,sha256=iUjLT5OEgD4zqF_tg3Szmg1c_73RozXyjjAFsVYKCWM,10893
|
||||
redis/_parsers/resp2.py,sha256=f22kH-_ZP2iNtOn6xOe65MSy_fJpu8OEn1u_hgeeojI,4813
|
||||
redis/_parsers/resp3.py,sha256=tiZRbyJAnObqll2LQJ57Br-3jxwQcMocV4GQE_LpC6g,9883
|
||||
redis/_parsers/socket.py,sha256=CKD8QW_wFSNlIZzxlbNduaGpiv0I8wBcsGuAIojDfJg,5403
|
||||
redis/asyncio/__init__.py,sha256=uoDD8XYVi0Kj6mcufYwLDUTQXmBRx7a0bhKF9stZr7I,1489
|
||||
redis/asyncio/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/asyncio/__pycache__/client.cpython-311.pyc,,
|
||||
redis/asyncio/__pycache__/cluster.cpython-311.pyc,,
|
||||
redis/asyncio/__pycache__/connection.cpython-311.pyc,,
|
||||
redis/asyncio/__pycache__/lock.cpython-311.pyc,,
|
||||
redis/asyncio/__pycache__/retry.cpython-311.pyc,,
|
||||
redis/asyncio/__pycache__/sentinel.cpython-311.pyc,,
|
||||
redis/asyncio/__pycache__/utils.cpython-311.pyc,,
|
||||
redis/asyncio/client.py,sha256=6a5-txYcRMtObkb7Bfi08MKQQY01oy5NKpHAlfhIFNM,61905
|
||||
redis/asyncio/cluster.py,sha256=LNEXjBJKr9M13jGnN52BQgYX6PbojCcxT_Jix9W2k0Y,90121
|
||||
redis/asyncio/connection.py,sha256=32MXfAoa5bOj2rNw-8YKJad6kpDmcOBNz2qsZd4Ty6Q,48828
|
||||
redis/asyncio/lock.py,sha256=GxgV6EsyKpMjh74KtaOPxh4fNPuwApz6Th46qhvrAws,12801
|
||||
redis/asyncio/retry.py,sha256=8carxJLme2f0frB9Z0wU3mHqKzwqzGAGb2TMEtaaMvo,2482
|
||||
redis/asyncio/sentinel.py,sha256=H7N_hvdATojwY06aH1AawFV-05AImqtOSAq0xKElbbk,14636
|
||||
redis/asyncio/utils.py,sha256=31xFzXczDgSRyf6hSjiwue1eDQ_XlP_OJdp5dKxW_aE,718
|
||||
redis/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
redis/auth/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/auth/__pycache__/err.cpython-311.pyc,,
|
||||
redis/auth/__pycache__/idp.cpython-311.pyc,,
|
||||
redis/auth/__pycache__/token.cpython-311.pyc,,
|
||||
redis/auth/__pycache__/token_manager.cpython-311.pyc,,
|
||||
redis/auth/err.py,sha256=WYkbuDIzwp1S-eAvsya6QMlO6g9QIXbzMITOsTWX0xk,694
|
||||
redis/auth/idp.py,sha256=IMDIIb9q72vbIwtFN8vPdaAKZVTdh0HuC5uj5ufqmw4,631
|
||||
redis/auth/token.py,sha256=qYwAgxFW3S93QDUqp1BTsj7Pj9ZohnixGeOX0s7AsjY,3317
|
||||
redis/auth/token_manager.py,sha256=ShBsYXiBZBJBOMB_Y-pXfLwEOAmc9s1okaCECinNZ7g,12018
|
||||
redis/backoff.py,sha256=2zR-ik5enJDsC2n2AWmE3ALSONgDLtyO4k096ZT6Txo,5275
|
||||
redis/cache.py,sha256=68rJDNogvNwgdgBel6zSX9QziL11qsKIMhmvQvHvznM,9549
|
||||
redis/client.py,sha256=BrYjhRBWw7Sw3LKPNbdW0UzaQsd-y-wPR70SMgDTeEc,62758
|
||||
redis/cluster.py,sha256=_Pi_u8U9meq-WcTHV0j4u0lgOQVqmALj37wU1qekWcE,123762
|
||||
redis/commands/__init__.py,sha256=cTUH-MGvaLYS0WuoytyqtN1wniw2A1KbkUXcpvOSY3I,576
|
||||
redis/commands/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/commands/__pycache__/cluster.cpython-311.pyc,,
|
||||
redis/commands/__pycache__/core.cpython-311.pyc,,
|
||||
redis/commands/__pycache__/helpers.cpython-311.pyc,,
|
||||
redis/commands/__pycache__/redismodules.cpython-311.pyc,,
|
||||
redis/commands/__pycache__/sentinel.cpython-311.pyc,,
|
||||
redis/commands/bf/__init__.py,sha256=qk4DA9KsMiP4WYqYeP1T5ScBwctsVtlLyMhrYIyq1Zc,8019
|
||||
redis/commands/bf/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/commands/bf/__pycache__/commands.cpython-311.pyc,,
|
||||
redis/commands/bf/__pycache__/info.cpython-311.pyc,,
|
||||
redis/commands/bf/commands.py,sha256=xeKt8E7G8HB-l922J0DLg07CEIZTVNGx_2Lfyw1gIck,21283
|
||||
redis/commands/bf/info.py,sha256=_OB2v_hAPI9mdVNiBx8jUtH2MhMoct9ZRm-e8In6wQo,3355
|
||||
redis/commands/cluster.py,sha256=vdWdpl4mP51oqfYBZHg5CUXt6jPaNp7aCLHyTieDrt8,31248
|
||||
redis/commands/core.py,sha256=lIi3DUP2kPdBC_RXrSTcUpjI_ORL9nKck9YayWIF_Pc,238242
|
||||
redis/commands/helpers.py,sha256=VCoPdBMCr4wxdWBw1EB9R7ZBbQM0exAG1kws4XwsCII,3318
|
||||
redis/commands/json/__init__.py,sha256=bznXhLYR652rfLfLp8cz0ZN0Yr8IRx4FgON_tq9_2Io,4845
|
||||
redis/commands/json/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/commands/json/__pycache__/_util.cpython-311.pyc,,
|
||||
redis/commands/json/__pycache__/commands.cpython-311.pyc,,
|
||||
redis/commands/json/__pycache__/decoders.cpython-311.pyc,,
|
||||
redis/commands/json/__pycache__/path.cpython-311.pyc,,
|
||||
redis/commands/json/_util.py,sha256=b_VQTh10FyLl8BtREfJfDagOJCyd6wTQQs8g63pi5GI,116
|
||||
redis/commands/json/commands.py,sha256=ih8upnxeOpjPZXNfqeFBYxiCN2Cmyv8UGu3AlQnT6JQ,15723
|
||||
redis/commands/json/decoders.py,sha256=a_IoMV_wgeJyUifD4P6HTcM9s6FhricwmzQcZRmc-Gw,1411
|
||||
redis/commands/json/path.py,sha256=0zaO6_q_FVMk1Bkhkb7Wcr8AF2Tfr69VhkKy1IBVhpA,393
|
||||
redis/commands/redismodules.py,sha256=-kLM4RBklDhNh-MXCra81ZTSstIQ-ulRab6v0dYUTdA,2573
|
||||
redis/commands/search/__init__.py,sha256=happQFVF0j7P87p7LQsUK5AK0kuem9cA-xvVRdQWpos,5744
|
||||
redis/commands/search/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/_util.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/aggregation.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/commands.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/dialect.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/document.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/field.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/index_definition.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/profile_information.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/query.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/querystring.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/reducers.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/result.cpython-311.pyc,,
|
||||
redis/commands/search/__pycache__/suggestion.cpython-311.pyc,,
|
||||
redis/commands/search/_util.py,sha256=9Mp72OO5Ib5UbfN7uXb-iB7hQCm1jQLV90ms2P9XSGU,219
|
||||
redis/commands/search/aggregation.py,sha256=CcZSZyquLWLrcSblwgt-bSyMvm-TQS9B7N8QI_ahCBU,11582
|
||||
redis/commands/search/commands.py,sha256=ozyF6YgCiMArhb6ScXLPy49hnJwm4CGK4vrJRwSeB-I,38413
|
||||
redis/commands/search/dialect.py,sha256=-7M6kkr33x0FkMtKmUsbeRAE6qxLUbqdJCqIo0UKIXo,105
|
||||
redis/commands/search/document.py,sha256=g2R-PRgq-jN33_GLXzavvse4cpIHBMfjPfPK7tnE9Gc,413
|
||||
redis/commands/search/field.py,sha256=ZWHYTtrLi-zZojohqXoidfllxP0SiadBW6hnGkBw7mM,5891
|
||||
redis/commands/search/index_definition.py,sha256=VL2CMzjxN0HEIaTn88evnHX1fCEmytbik4vAmiiYSC8,2489
|
||||
redis/commands/search/profile_information.py,sha256=w9SbMiHbcZ1TpsZMe8cMIyO1hGkm5GhnZ_Gqg1feLtc,249
|
||||
redis/commands/search/query.py,sha256=MbSs-cY7hG1OEkO-i6LJ_Ui1D3d2VyDTXPrmb-rty7w,12199
|
||||
redis/commands/search/querystring.py,sha256=dE577kOqkCErNgO-IXI4xFVHI8kQE-JiH5ZRI_CKjHE,7597
|
||||
redis/commands/search/reducers.py,sha256=Scceylx8BjyqS-TJOdhNW63n6tecL9ojt4U5Sqho5UY,4220
|
||||
redis/commands/search/result.py,sha256=iuqmwOeCNo_7N4a_YxxDzVdOTpbwfF1T2uuq5sTqzMo,2624
|
||||
redis/commands/search/suggestion.py,sha256=V_re6suDCoNc0ETn_P1t51FeK4pCamPwxZRxCY8jscE,1612
|
||||
redis/commands/sentinel.py,sha256=hRcIQ9x9nEkdcCsJzo6Ves6vk-3tsfQqfJTT_v3oLY0,4110
|
||||
redis/commands/timeseries/__init__.py,sha256=k492_xE_lBD0cVSX82TWBiNxOWuDDrrVZUjINi3LZSc,3450
|
||||
redis/commands/timeseries/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/commands/timeseries/__pycache__/commands.cpython-311.pyc,,
|
||||
redis/commands/timeseries/__pycache__/info.cpython-311.pyc,,
|
||||
redis/commands/timeseries/__pycache__/utils.cpython-311.pyc,,
|
||||
redis/commands/timeseries/commands.py,sha256=8Z2BEyP23qTYCJR_e9zdG11yWmIDwGBMO2PJNLtK2BA,47147
|
||||
redis/commands/timeseries/info.py,sha256=meZYdu7IV9KaUWMKZs9qW4vo3Q9MwhdY-EBtKQzls5o,3223
|
||||
redis/commands/timeseries/utils.py,sha256=NLwSOS5Dz9N8dYQSzEyBIvrItOWwfQ0xgDj8un6x3dU,1319
|
||||
redis/commands/vectorset/__init__.py,sha256=_fM0UdYjuzs8YWIUjQGH9QX5FwI0So8_D-5ALWWrWFc,1322
|
||||
redis/commands/vectorset/__pycache__/__init__.cpython-311.pyc,,
|
||||
redis/commands/vectorset/__pycache__/commands.cpython-311.pyc,,
|
||||
redis/commands/vectorset/__pycache__/utils.cpython-311.pyc,,
|
||||
redis/commands/vectorset/commands.py,sha256=7CvQNFvkXuG3XPhHJ82y_oBYJwewRFz84aEi3OCH4Rw,12495
|
||||
redis/commands/vectorset/utils.py,sha256=N-x0URyg76XC39CNfBym6FkFCVgm5NthzWKBnc2H0Xc,2981
|
||||
redis/connection.py,sha256=z1m1-maULRuw4KeiuKXmzL_DtFxcXiqMbKFJm_3V7ao,66905
|
||||
redis/crc.py,sha256=Z3kXFtkY2LdgefnQMud1xr4vG5UYvA9LCMqNMX1ywu4,729
|
||||
redis/credentials.py,sha256=GOnO3-LSW34efHaIrUbS742Mw8l70mRzF6UrKiKZsMY,1828
|
||||
redis/event.py,sha256=urOK241IdgmCQ3fq7GqXRstZ2vcXRV14bBBMdN3latk,12129
|
||||
redis/exceptions.py,sha256=46H-asqIaZ65Gc-voGzP7S39JtxdICGdHzdsT6LSMJE,5617
|
||||
redis/lock.py,sha256=GrvPSxaOqKo7iAL2oi5ZUEPsOkxAXHVE_Tp1ejgO2fY,12760
|
||||
redis/ocsp.py,sha256=teYSmKnCtk6B3jJLdNYbZN4OE0mxgspt2zUPbkIQzio,11452
|
||||
redis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
redis/retry.py,sha256=qJPRTARm3TYQPRNnzyjUUjGohbwtMz5KoDphCtHJ44Y,2902
|
||||
redis/sentinel.py,sha256=DBphu6uNp6ZCSaVDSVC8nFhSxG93a12DnzgGWpyeh64,14757
|
||||
redis/typing.py,sha256=z5JQjGkNzejEzb2y7TXct7tS5yzAfLQod9o37Mh1_Ug,1953
|
||||
redis/utils.py,sha256=q7tQJs6Tj5M91QypOwZtGnFXs2Bcji3eTt9VEwLYOeA,8386
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: hatchling 1.27.0
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022-2023, Redis, inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
from redis import asyncio # noqa
|
||||
from redis.backoff import default_backoff
|
||||
from redis.client import Redis, StrictRedis
|
||||
from redis.cluster import RedisCluster
|
||||
from redis.connection import (
|
||||
BlockingConnectionPool,
|
||||
Connection,
|
||||
ConnectionPool,
|
||||
SSLConnection,
|
||||
UnixDomainSocketConnection,
|
||||
)
|
||||
from redis.credentials import CredentialProvider, UsernamePasswordCredentialProvider
|
||||
from redis.exceptions import (
|
||||
AuthenticationError,
|
||||
AuthenticationWrongNumberOfArgsError,
|
||||
BusyLoadingError,
|
||||
ChildDeadlockedError,
|
||||
ConnectionError,
|
||||
CrossSlotTransactionError,
|
||||
DataError,
|
||||
InvalidPipelineStack,
|
||||
InvalidResponse,
|
||||
OutOfMemoryError,
|
||||
PubSubError,
|
||||
ReadOnlyError,
|
||||
RedisClusterException,
|
||||
RedisError,
|
||||
ResponseError,
|
||||
TimeoutError,
|
||||
WatchError,
|
||||
)
|
||||
from redis.sentinel import (
|
||||
Sentinel,
|
||||
SentinelConnectionPool,
|
||||
SentinelManagedConnection,
|
||||
SentinelManagedSSLConnection,
|
||||
)
|
||||
from redis.utils import from_url
|
||||
|
||||
|
||||
def int_or_str(value):
|
||||
try:
|
||||
return int(value)
|
||||
except ValueError:
|
||||
return value
|
||||
|
||||
|
||||
# This version is used when building the package for publishing
|
||||
__version__ = "6.2.0"
|
||||
VERSION = tuple(map(int_or_str, __version__.split(".")))
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AuthenticationError",
|
||||
"AuthenticationWrongNumberOfArgsError",
|
||||
"BlockingConnectionPool",
|
||||
"BusyLoadingError",
|
||||
"ChildDeadlockedError",
|
||||
"Connection",
|
||||
"ConnectionError",
|
||||
"ConnectionPool",
|
||||
"CredentialProvider",
|
||||
"CrossSlotTransactionError",
|
||||
"DataError",
|
||||
"from_url",
|
||||
"default_backoff",
|
||||
"InvalidPipelineStack",
|
||||
"InvalidResponse",
|
||||
"OutOfMemoryError",
|
||||
"PubSubError",
|
||||
"ReadOnlyError",
|
||||
"Redis",
|
||||
"RedisCluster",
|
||||
"RedisClusterException",
|
||||
"RedisError",
|
||||
"ResponseError",
|
||||
"Sentinel",
|
||||
"SentinelConnectionPool",
|
||||
"SentinelManagedConnection",
|
||||
"SentinelManagedSSLConnection",
|
||||
"SSLConnection",
|
||||
"UsernamePasswordCredentialProvider",
|
||||
"StrictRedis",
|
||||
"TimeoutError",
|
||||
"UnixDomainSocketConnection",
|
||||
"WatchError",
|
||||
]
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
from .base import (
|
||||
AsyncPushNotificationsParser,
|
||||
BaseParser,
|
||||
PushNotificationsParser,
|
||||
_AsyncRESPBase,
|
||||
)
|
||||
from .commands import AsyncCommandsParser, CommandsParser
|
||||
from .encoders import Encoder
|
||||
from .hiredis import _AsyncHiredisParser, _HiredisParser
|
||||
from .resp2 import _AsyncRESP2Parser, _RESP2Parser
|
||||
from .resp3 import _AsyncRESP3Parser, _RESP3Parser
|
||||
|
||||
__all__ = [
|
||||
"AsyncCommandsParser",
|
||||
"_AsyncHiredisParser",
|
||||
"_AsyncRESPBase",
|
||||
"_AsyncRESP2Parser",
|
||||
"_AsyncRESP3Parser",
|
||||
"AsyncPushNotificationsParser",
|
||||
"CommandsParser",
|
||||
"Encoder",
|
||||
"BaseParser",
|
||||
"_HiredisParser",
|
||||
"_RESP2Parser",
|
||||
"_RESP3Parser",
|
||||
"PushNotificationsParser",
|
||||
]
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
import sys
|
||||
from abc import ABC
|
||||
from asyncio import IncompleteReadError, StreamReader, TimeoutError
|
||||
from typing import Callable, List, Optional, Protocol, Union
|
||||
|
||||
if sys.version_info.major >= 3 and sys.version_info.minor >= 11:
|
||||
from asyncio import timeout as async_timeout
|
||||
else:
|
||||
from async_timeout import timeout as async_timeout
|
||||
|
||||
from ..exceptions import (
|
||||
AskError,
|
||||
AuthenticationError,
|
||||
AuthenticationWrongNumberOfArgsError,
|
||||
BusyLoadingError,
|
||||
ClusterCrossSlotError,
|
||||
ClusterDownError,
|
||||
ConnectionError,
|
||||
ExecAbortError,
|
||||
MasterDownError,
|
||||
ModuleError,
|
||||
MovedError,
|
||||
NoPermissionError,
|
||||
NoScriptError,
|
||||
OutOfMemoryError,
|
||||
ReadOnlyError,
|
||||
RedisError,
|
||||
ResponseError,
|
||||
TryAgainError,
|
||||
)
|
||||
from ..typing import EncodableT
|
||||
from .encoders import Encoder
|
||||
from .socket import SERVER_CLOSED_CONNECTION_ERROR, SocketBuffer
|
||||
|
||||
MODULE_LOAD_ERROR = "Error loading the extension. Please check the server logs."
|
||||
NO_SUCH_MODULE_ERROR = "Error unloading module: no such module with that name"
|
||||
MODULE_UNLOAD_NOT_POSSIBLE_ERROR = "Error unloading module: operation not possible."
|
||||
MODULE_EXPORTS_DATA_TYPES_ERROR = (
|
||||
"Error unloading module: the module "
|
||||
"exports one or more module-side data "
|
||||
"types, can't unload"
|
||||
)
|
||||
# user send an AUTH cmd to a server without authorization configured
|
||||
NO_AUTH_SET_ERROR = {
|
||||
# Redis >= 6.0
|
||||
"AUTH <password> called without any password "
|
||||
"configured for the default user. Are you sure "
|
||||
"your configuration is correct?": AuthenticationError,
|
||||
# Redis < 6.0
|
||||
"Client sent AUTH, but no password is set": AuthenticationError,
|
||||
}
|
||||
|
||||
|
||||
class BaseParser(ABC):
|
||||
EXCEPTION_CLASSES = {
|
||||
"ERR": {
|
||||
"max number of clients reached": ConnectionError,
|
||||
"invalid password": AuthenticationError,
|
||||
# some Redis server versions report invalid command syntax
|
||||
# in lowercase
|
||||
"wrong number of arguments "
|
||||
"for 'auth' command": AuthenticationWrongNumberOfArgsError,
|
||||
# some Redis server versions report invalid command syntax
|
||||
# in uppercase
|
||||
"wrong number of arguments "
|
||||
"for 'AUTH' command": AuthenticationWrongNumberOfArgsError,
|
||||
MODULE_LOAD_ERROR: ModuleError,
|
||||
MODULE_EXPORTS_DATA_TYPES_ERROR: ModuleError,
|
||||
NO_SUCH_MODULE_ERROR: ModuleError,
|
||||
MODULE_UNLOAD_NOT_POSSIBLE_ERROR: ModuleError,
|
||||
**NO_AUTH_SET_ERROR,
|
||||
},
|
||||
"OOM": OutOfMemoryError,
|
||||
"WRONGPASS": AuthenticationError,
|
||||
"EXECABORT": ExecAbortError,
|
||||
"LOADING": BusyLoadingError,
|
||||
"NOSCRIPT": NoScriptError,
|
||||
"READONLY": ReadOnlyError,
|
||||
"NOAUTH": AuthenticationError,
|
||||
"NOPERM": NoPermissionError,
|
||||
"ASK": AskError,
|
||||
"TRYAGAIN": TryAgainError,
|
||||
"MOVED": MovedError,
|
||||
"CLUSTERDOWN": ClusterDownError,
|
||||
"CROSSSLOT": ClusterCrossSlotError,
|
||||
"MASTERDOWN": MasterDownError,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def parse_error(cls, response):
|
||||
"Parse an error response"
|
||||
error_code = response.split(" ")[0]
|
||||
if error_code in cls.EXCEPTION_CLASSES:
|
||||
response = response[len(error_code) + 1 :]
|
||||
exception_class = cls.EXCEPTION_CLASSES[error_code]
|
||||
if isinstance(exception_class, dict):
|
||||
exception_class = exception_class.get(response, ResponseError)
|
||||
return exception_class(response)
|
||||
return ResponseError(response)
|
||||
|
||||
def on_disconnect(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def on_connect(self, connection):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class _RESPBase(BaseParser):
|
||||
"""Base class for sync-based resp parsing"""
|
||||
|
||||
def __init__(self, socket_read_size):
|
||||
self.socket_read_size = socket_read_size
|
||||
self.encoder = None
|
||||
self._sock = None
|
||||
self._buffer = None
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
self.on_disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def on_connect(self, connection):
|
||||
"Called when the socket connects"
|
||||
self._sock = connection._sock
|
||||
self._buffer = SocketBuffer(
|
||||
self._sock, self.socket_read_size, connection.socket_timeout
|
||||
)
|
||||
self.encoder = connection.encoder
|
||||
|
||||
def on_disconnect(self):
|
||||
"Called when the socket disconnects"
|
||||
self._sock = None
|
||||
if self._buffer is not None:
|
||||
self._buffer.close()
|
||||
self._buffer = None
|
||||
self.encoder = None
|
||||
|
||||
def can_read(self, timeout):
|
||||
return self._buffer and self._buffer.can_read(timeout)
|
||||
|
||||
|
||||
class AsyncBaseParser(BaseParser):
|
||||
"""Base parsing class for the python-backed async parser"""
|
||||
|
||||
__slots__ = "_stream", "_read_size"
|
||||
|
||||
def __init__(self, socket_read_size: int):
|
||||
self._stream: Optional[StreamReader] = None
|
||||
self._read_size = socket_read_size
|
||||
|
||||
async def can_read_destructive(self) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
async def read_response(
|
||||
self, disable_decoding: bool = False
|
||||
) -> Union[EncodableT, ResponseError, None, List[EncodableT]]:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
_INVALIDATION_MESSAGE = [b"invalidate", "invalidate"]
|
||||
|
||||
|
||||
class PushNotificationsParser(Protocol):
|
||||
"""Protocol defining RESP3-specific parsing functionality"""
|
||||
|
||||
pubsub_push_handler_func: Callable
|
||||
invalidation_push_handler_func: Optional[Callable] = None
|
||||
|
||||
def handle_pubsub_push_response(self, response):
|
||||
"""Handle pubsub push responses"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def handle_push_response(self, response, **kwargs):
|
||||
if response[0] not in _INVALIDATION_MESSAGE:
|
||||
return self.pubsub_push_handler_func(response)
|
||||
if self.invalidation_push_handler_func:
|
||||
return self.invalidation_push_handler_func(response)
|
||||
|
||||
def set_pubsub_push_handler(self, pubsub_push_handler_func):
|
||||
self.pubsub_push_handler_func = pubsub_push_handler_func
|
||||
|
||||
def set_invalidation_push_handler(self, invalidation_push_handler_func):
|
||||
self.invalidation_push_handler_func = invalidation_push_handler_func
|
||||
|
||||
|
||||
class AsyncPushNotificationsParser(Protocol):
|
||||
"""Protocol defining async RESP3-specific parsing functionality"""
|
||||
|
||||
pubsub_push_handler_func: Callable
|
||||
invalidation_push_handler_func: Optional[Callable] = None
|
||||
|
||||
async def handle_pubsub_push_response(self, response):
|
||||
"""Handle pubsub push responses asynchronously"""
|
||||
raise NotImplementedError()
|
||||
|
||||
async def handle_push_response(self, response, **kwargs):
|
||||
"""Handle push responses asynchronously"""
|
||||
if response[0] not in _INVALIDATION_MESSAGE:
|
||||
return await self.pubsub_push_handler_func(response)
|
||||
if self.invalidation_push_handler_func:
|
||||
return await self.invalidation_push_handler_func(response)
|
||||
|
||||
def set_pubsub_push_handler(self, pubsub_push_handler_func):
|
||||
"""Set the pubsub push handler function"""
|
||||
self.pubsub_push_handler_func = pubsub_push_handler_func
|
||||
|
||||
def set_invalidation_push_handler(self, invalidation_push_handler_func):
|
||||
"""Set the invalidation push handler function"""
|
||||
self.invalidation_push_handler_func = invalidation_push_handler_func
|
||||
|
||||
|
||||
class _AsyncRESPBase(AsyncBaseParser):
|
||||
"""Base class for async resp parsing"""
|
||||
|
||||
__slots__ = AsyncBaseParser.__slots__ + ("encoder", "_buffer", "_pos", "_chunks")
|
||||
|
||||
def __init__(self, socket_read_size: int):
|
||||
super().__init__(socket_read_size)
|
||||
self.encoder: Optional[Encoder] = None
|
||||
self._buffer = b""
|
||||
self._chunks = []
|
||||
self._pos = 0
|
||||
|
||||
def _clear(self):
|
||||
self._buffer = b""
|
||||
self._chunks.clear()
|
||||
|
||||
def on_connect(self, connection):
|
||||
"""Called when the stream connects"""
|
||||
self._stream = connection._reader
|
||||
if self._stream is None:
|
||||
raise RedisError("Buffer is closed.")
|
||||
self.encoder = connection.encoder
|
||||
self._clear()
|
||||
self._connected = True
|
||||
|
||||
def on_disconnect(self):
|
||||
"""Called when the stream disconnects"""
|
||||
self._connected = False
|
||||
|
||||
async def can_read_destructive(self) -> bool:
|
||||
if not self._connected:
|
||||
raise RedisError("Buffer is closed.")
|
||||
if self._buffer:
|
||||
return True
|
||||
try:
|
||||
async with async_timeout(0):
|
||||
return self._stream.at_eof()
|
||||
except TimeoutError:
|
||||
return False
|
||||
|
||||
async def _read(self, length: int) -> bytes:
|
||||
"""
|
||||
Read `length` bytes of data. These are assumed to be followed
|
||||
by a '\r\n' terminator which is subsequently discarded.
|
||||
"""
|
||||
want = length + 2
|
||||
end = self._pos + want
|
||||
if len(self._buffer) >= end:
|
||||
result = self._buffer[self._pos : end - 2]
|
||||
else:
|
||||
tail = self._buffer[self._pos :]
|
||||
try:
|
||||
data = await self._stream.readexactly(want - len(tail))
|
||||
except IncompleteReadError as error:
|
||||
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR) from error
|
||||
result = (tail + data)[:-2]
|
||||
self._chunks.append(data)
|
||||
self._pos += want
|
||||
return result
|
||||
|
||||
async def _readline(self) -> bytes:
|
||||
"""
|
||||
read an unknown number of bytes up to the next '\r\n'
|
||||
line separator, which is discarded.
|
||||
"""
|
||||
found = self._buffer.find(b"\r\n", self._pos)
|
||||
if found >= 0:
|
||||
result = self._buffer[self._pos : found]
|
||||
else:
|
||||
tail = self._buffer[self._pos :]
|
||||
data = await self._stream.readline()
|
||||
if not data.endswith(b"\r\n"):
|
||||
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
|
||||
result = (tail + data)[:-2]
|
||||
self._chunks.append(data)
|
||||
self._pos += len(result) + 2
|
||||
return result
|
||||