Pular para conteúdo

Fluxo de dados

Descrição de como os dados se movem dentro de um dispositivo em execução. O objetivo é mostrar que idryer-core não usa um barramento de eventos nem um localizador de serviço: os participantes são conectados por ponteiros explícitos na raiz de composição, e cada direção de dados é um caminho separado e legível.

Padrões detalhados para "como rotear dados entre minhas partes" estão em 04-patterns/99-data-flow.md.

Direções principais

                Backend / app
                     │ MQTT commands/*
        ┌──────────────────────────────┐
        │  MqttClient                  │
        │  analisa topic + payload     │
        └──────────────┬───────────────┘
                       │ CommandCallback
        ┌──────────────────────────────┐
        │  IdryerRuntime               │
        │  ping → settimeofday + info  │
        │  outros → CommandHandler     │
        └──────────────┬───────────────┘
                       │ commandHandler_(cmd, data)
        ┌──────────────────────────────┐
        │  Produto handleCommand()     │
        │  invoke / set / get_config / │
        │  comandos específicos produto│
        └──────┬───────────────┬───────┘
               │               │
               ▼               ▼
   ActionDispatcher        IProfile
   handleInvoke / Set      getConfig
                           applyConfig
                           buildInfoJson
       Sensor (produto)        Perfil / executor
            │                           │
            │ tick() / leia             │ atualiza estado
            ▼                           ▼
       ┌───────────────────────────────────────┐
       │  Editor de produto                    │
       │  (StorageTelemetryPublisher, …)       │
       │  constrói JsonDocument                │
       └────────────────┬──────────────────────┘
                        │ pub.publishX(doc)
       ┌───────────────────────────────────────┐
       │  DevicePublisher (opcional)           │
       │  ajudante duplo publicar: MQTT + WS   │
       └─────────┬─────────────────────┬───────┘
                 │                     │
                 ▼                     ▼
            MqttClient            LocalAccess (WS)
            broker                cliente LAN

Comandos recebidos

  1. MQTT entrega uma mensagem no tópico idryer/{serial}/commands/{cmd}.
  2. MqttClient::handleMessage analisa a carga como JSON e chama CommandCallback.
  3. CommandCallback é registrado por IdryerRuntime em begin() — aceita (command, data), onde command é o sufixo após commands/.
  4. IdryerRuntime::onMqttCommand:
  5. Se command == "ping" — sincroniza tempo e publica informações. Não passado adiante.
  6. Se um commandHandler_ é registrado — passa tudo o mais para o produto.
  7. Caso contrário — caminho integrado de fallback: invokeActionDispatcher, setActionDispatcher, device.getConfigIProfile::getConfig.

  8. WS local (se usado) aceita {"type":"command","command":"...","data":{...}}, desembrulha o envelope e chama o mesmo CommandSink registrado para o caminho MQTT. Um manipulador — dois transportes.

Dados de saída

A biblioteca não publica nada a menos que seja solicitada. Todas as mensagens de saída são iniciadas pelo produto:

O quê Iniciado por Via qual API
info IdryerRuntime (uma vez quando Online e no ping) MqttClient::publishInfoJson
telemetry editor do produto MqttClient::publishTelemetry ou DevicePublisher::publishTelemetry
status código do produto na mudança de estado MqttClient::publishStatus ou DevicePublisher::publishStatus
config handleCommand em device.getConfig ou get_config MqttClient::publishConfig
events código do produto em um evento MqttClient::publishEvent
integrations/status LinkIntegrationsManager MqttClient::publishIntegrationsStatus
offline broker automaticamente (LWT) dispositivo nunca publica isto

Conexões de objetos na raiz de composição

Referências entre participantes são passadas explicitamente através de construtores e setters. Sem registros globais.

ArduinoWifiManager     ─┐
ArduinoCredentialStore ─┤
HttpApi (← Http)       ─┼──→ CloudStateMachine ──→ IdryerRuntime ──→ MqttClient
MqttClient             ─┘                              ▲
                                ActionDispatcher ──────┤
                                IProfile         ──────┘

                LocalAccess  ──── (setCommandSink) ────→ mesmo handleCommand
                DevicePublisher (&MqttClient, &LocalAccess)

                Sensor  ──→ Editor  ──→ DevicePublisher  ──→ MqttClient + LocalAccess
                Executor ←── ActionDispatcher (invoke)  ←── handleCommand

Cada conexão é uma linha em main.cpp. Esta é a "raiz de composição explícita".

Por quê este design

  • Sem magia: para entender como os dados viajam de um sensor para a nuvem, o leitor vê a cadeia de ponteiros em main.cpp. Nenhum fluxo de dados fica escondido atrás de uma fachada.
  • Flexibilidade: o produto escolhe se usar DevicePublisher (MQTT + WS), publicar apenas para MQTT ou usar seu próprio editor com lógica adicional.
  • Testabilidade: cada nó é uma classe separada com dependências explícitas. Os nós podem ser substituídos por mocks sem alterar o resto da pilha.

O que está intencionalmente ausente

  • Nenhum barramento de eventos global ou intermediário de mensagens dentro do dispositivo.
  • Nenhuma detecção automática de "tenho um sensor, publicarei seus dados por conta própria".
  • Nenhum registro de tipo de "dispositivo conhece todos os seus provedores de telemetria".

Se o produto precisa de tais conexões — o produto as adiciona em seu próprio código. A biblioteca não as impõe.