Sobre o projeto

## Visão Geral plexus-python é um SDK Python leve para a plataforma Plexus. O Plexus oferece armazenamento de séries temporais e dashboards para equipes de hardware: transmita dados de drones, robôs e dispositivos IoT para o Plexus Time Series, ou conecte-se a um banco de dados existente, obtendo dashboards e alertas em tempo real. Este pacote apenas envia dados para o gateway Plexus; armazenamento, dashboards, alertas e gerenciamento de frota ficam na plataforma. ## Início Rápido ```bash pip install plexus-python ``` ```python from plexus import Plexus px = Plexus(api_key="plx_xxx", source_id="device-001") px.send("temperature", 72.5) ``` A chave de API pode ser obtida em app.plexus.company/api, ou execute `plexus init` para autorizar esta máquina no navegador. ## Identificação do Dispositivo Cada dispositivo precisa de um `source_id` único. Recomenda-se usar o script de configuração, que primeiro solicita o nome do dispositivo: ```bash curl -sL https://app.plexus.company/setup | bash -s -- \ --key plx_xxx --name drone-01 ``` O nome é convertido no `source_id` do dispositivo, devendo corresponder a `^[a-z0-9][a-z0-9._-]*$` (máx. 256 caracteres). Se não houver `--name` nem `source_id=...` no código, o SDK gera um id aleatório na primeira execução (ex.: `source-1a2b3c4d`) e o salva em `~/.plexus/config.json`. Não use o hostname: imagens de cartão SD clonadas iniciam como `raspberrypi`, e a telemetria seria mesclada na mesma fonte. Nomes não são deduplicados automaticamente; o gateway ecoa o `source_id` declarado, e dois dispositivos declarando o mesmo nome escrevem na mesma fonte. ## Métodos Principais ### send(metric, value) O método mais usado; chame-o a cada nova leitura. `metric` é uma string de namespace pontilhado (ex.: `"motor.rpm"`), `value` aceita qualquer tipo serializável em JSON: float/int (leituras de sensores, contadores), str (máquinas de estado, códigos de erro), bool (flags binárias), dict (vetores, leituras estruturadas), list (formas de onda, ângulos de juntas). Parâmetro opcional `tags={"motor_id": "A1"}` para filtros no dashboard, `timestamp=t` para timestamp Unix em segundos. ### send_batch(points) Envia várias leituras de uma vez, compartilhando o timestamp e consolidando em uma única chamada de rede. `points` é uma lista de tuplas `(metric, value)`, ou tuplas `(metric, value, timestamp)` quando timestamps por ponto são necessários. ### batch() Use quando houver mais de alguns leituras por segundo. Cada `send()` é uma mensagem WebSocket; o gateway limita o número de mensagens, não de pontos (2.000/s por conexão). 25 canais a 100 Hz enviados individualmente são 2.500 mensagens/s, e o excesso é descartado antes do armazenamento. ```python with px.batch(interval_ms=50) as b: while running: b.send("att.pos_x", att.x) ``` Uma thread em segundo plano descarrega a fila a cada `interval_ms`; ao sair do bloco, os dados restantes são descarregados, e as leituras mantêm o timestamp da coleta. Se o gateway descartar quadros, reporta `RATE_LIMITED`; o SDK conta em `px.rate_limited_frames` e lança `RateLimitedError` no próximo envio. ### run(name) Um run é uma janela de tempo nomeada em uma fonte; pode ser revisada em `/runs`, alinhada para comparação em T+0, e verificada contra critérios de aprovação no fechamento. Sair do bloco marca o run como `completed`; uma exceção o marca como `aborted` e é relançada. Também é possível usar `px.start_run()` / `px.end_run()` separadamente; `end_run()` retorna o run com `test_result`. ### event(name, data) Para registrar "o que aconteceu" em vez de "o que está sendo medido continuamente": falhas, mudanças de estado, ações do operador, entradas de log. A plataforma exibe eventos como marcadores no gráfico de telemetria, não como séries temporais. Limites por evento: valores string 256 bytes, valores dict/list 4.096 bytes JSON, máx. 16 tags. ### Logs Este pacote não tem upload de arquivos de log nem `logging.Handler`. Para enviar linhas de log importantes ao Plexus, use eventos: `px.event("log", {"level": "error", "msg": "..."})`. Encaminhe apenas linhas que você quer na linha do tempo (erros, avisos, mudanças de estado), não cada log de debug. ## Streaming de Vídeo Vídeo requer plano pago: quadros vão via WebSocket, e o gateway rejeita no plano gratuito. Os quadros são encaminhados em tempo real aos espectadores e armazenados apenas quando Record é pressionado no app; gravação única de até 4 horas. - `send_video_frame(frame, camera_id)`: use quando você controla o loop de captura (callback picamera2, loop OpenCV VideoCapture, pipeline FFmpeg próprio). Aceita ndarray numpy (requer opencv-python), bytes JPEG (passados adiante), outros bytes de imagem (decodificados via Pillow e re-encodados como JPEG; requer `pip install plexus-python[video]`). - `stream_camera(url, camera_id)`: use quando há um stream RTSP ou arquivo de vídeo e você não quer gerenciar o loop de captura; o SDK executa FFmpeg internamente (requer FFmpeg no `$PATH`). Retorna um `threading.Event`; chame `.set()` para parar; roda em thread em segundo plano. ## Traga Seu Próprio Protocolo Este pacote não tem adaptadores, autodetecção ou daemons; é apenas um cliente. Use as bibliotecas que você já usaria para alimentar `px.send()`; o README traz exemplos para MAVLink (pymavlink), CAN (python-can), MQTT (paho-mqtt) e sensores I2C (Adafruit CircuitPython), com versões executáveis em `examples/`. ## Confiabilidade Cada envio é primeiro bufferizado localmente antes de ir para a rede, com retry com backoff exponencial, preservando dados em quedas de conexão. O buffer é em disco por padrão (SQLite), sobrevivendo a reinicializações e quedas de energia; `persistent_buffer=False` usa apenas memória. Use `px.buffer_size()` e `px.flush_buffer()` para ver o número de pontos e descarregar. ## Timestamps e Correção de Relógio Por padrão, o SDK escolhe o tempo. Via WebSocket, o relógio é sincronizado com o gateway a cada conexão, mesmo que o relógio do dispositivo esteja errado (primeira inicialização sem NTP, RTC expirado, imagem de sistema nova), os dados caem na posição correta na linha do tempo. Com fonte de tempo externa confiável (GPS, RTC confiável, NTP do host) ou ao reproduzir dados históricos com timestamps conhecidos, passe `timestamp` explicitamente. Limitações conhecidas: a sincronização de relógio é atualizada na reconexão WebSocket; dispositivos com RTC com deriva em conexões longas acumulam deriva não corrigida entre reconexões; o fallback HTTP não recebe sincronização de relógio; `send_batch()` compartilha um timestamp por padrão. ## Transporte Por padrão, conecta-se ao gateway via WebSocket em `/ws/device`, obtendo streaming de telemetria de menor latência e um canal para ações acionadas pelo dashboard. Quando o socket não está disponível, faz fallback transparente para `POST /ingest`, sem perda de dados. Não há seletor de transporte; o SDK sempre prioriza WebSocket. No plano gratuito, o gateway rejeita WebSocket de dispositivo (`streaming_requires_plan`), e o SDK faz fallback para HTTP; `send()`, `send_batch()`, `batch()` e `event()` continuam funcionando; streaming em tempo real e vídeo exigem plano pago; o plano gratuito limita a 3 dispositivos e 7 dias de histórico. ## Comandos Você pode declarar quais comandos seu código aceita; declare antes do primeiro `send()` (a declaração vai no quadro de autenticação). Decore handlers com `@px.command(...)`; parâmetros suportam string (maxLength, enum), integer/number (minimum, maximum, unit), boolean, além de title, description, default, required; máx. 16 e planos, sem aninhamento. `danger` é normal/dangerous/critical; `idempotent` verdadeiro só reentrega após queda; `expires_in` é 5–3600 segundos; `concurrency` opcional accept/reject. Handlers são chamados como `handler(run, **params)`, com parâmetros validados e convertidos; o valor de retorno vira o resultado do run; exceções tornam o run `failed`. Requer chave de API com permissão Receive commands. O SDK confirma cada run, não executa o mesmo run id duas vezes, usa relógio monotônico para expiração e reproduz estado não confirmado após reconexão. `px.on_command()` está obsoleto, mas ainda funciona com a assinatura antiga. ## Variáveis de Ambiente `PLEXUS_API_KEY` (obrigatória), `PLEXUS_GATEWAY_URL` (padrão `https://gateway.plexus.company`), `PLEXUS_GATEWAY_WS_URL` (padrão `wss://gateway.plexus.company`). ## Habilidades para Agentes O pacote inclui três skills que ensinam agentes de codificação a usar a API Plexus (endpoints, streaming em tempo real, erros comuns que causam 400 silenciosos). `plexus skills install` instala em `~/.claude/skills`; com `--project`, instala em `./.claude/skills` junto ao repositório. Markdown puro, sem instalação ou credenciais necessárias. ## Arquitetura ``` Seu código ── px.send() ── WebSocket /ws/device (ou HTTP POST /ingest) ──> plexus-gateway ──> ClickHouse + Dashboard ``` Um caminho leve, sem agentes, daemons ou adaptadores. A plataforma HardwareOps completa (dashboards, alertas, RCA, visão de frota) está na UI web em app.plexus.company. ## Licença Apache 2.0.