Pular para conteúdo

Adicionar uma periférica

Quando usar

Se o dispositivo precisa controlar hardware em um comando da nuvem ou LAN — relé, aquecedor, fita LED, motor — use esta receita.

Código pronto para usar

// main.cpp
#include <iDryer.h>
#include <runtime/idryer_runtime.h>

static const iDryer::Config CFG = {
    .deviceType      = iDryer::DeviceType::StorageLink,
    .unitsCount      = 1,
    .hardwareVersion = "1.0",
    .firmwareVersion = "1.0.0",
};

static iDryer::Link s_link(CFG);

static void handleCommand(const char* cmd, JsonObjectConst data) {
    if (!cmd) return;

    if (strcmp(cmd, "invoke") == 0) {
        const char* action = data["action"] | "";

        if (strcmp(action, "fan.on") == 0) {
            myFan.on();
            s_link.publishStatusNow();  // refletir novo estado imediatamente
            return;
        }
        if (strcmp(action, "fan.off") == 0) {
            myFan.off();
            s_link.publishStatusNow();
            return;
        }
    }

    if (strcmp(cmd, "drying") == 0) {
        float targetTempC  = data["targetTempC"]  | 45.0f;
        uint32_t durationS = data["durationS"]    | 0;
        myHeater.start(targetTempC, durationS);
        s_link.status.mode[0]        = iDryer::UnitMode::Drying;
        s_link.status.targetTempC[0] = targetTempC;
        s_link.status.durationS[0]   = durationS;
        s_link.publishStatusNow();
        return;
    }

    if (strcmp(cmd, "stop") == 0) {
        myHeater.stop();
        s_link.status.mode[0] = iDryer::UnitMode::Idle;
        s_link.publishStatusNow();
        return;
    }
}

void setup() {
    myFan.begin();
    myHeater.begin();
    s_link.begin();
    // IMPORTANTE: setCommandHandler — estritamente APÓS begin().
    // begin() instala seu próprio dispatcher; nosso handleCommand deve sobrescrevê-lo.
    s_link.runtime()->setCommandHandler(handleCommand);
}

void loop() {
    s_link.loop();
    myFan.tick();
    myHeater.tick();
}

Explicação

s_link.runtime()->setCommandHandler(handleCommand) é o único ponto de conexão para o manipulador de comandos. Após essa chamada, todos os comandos MQTT recebidos (invoke, set, drying, stop, ping, get_config, etc.) chegam diretamente a handleCommand.

s_link.publishStatusNow() — chame após cada mudança em s_link.status.*. Isso envia imediatamente o novo estado para o portal e clientes LAN sem esperar pelo temporizador statusPeriodMs.

Nunca chame delay() dentro de handleCommand — a chamada é síncrona de um callback MQTT; bloqueá-lo quebra a sessão. Coloque temporizadores no loop() do objeto do produto.

Alternativa: link.onCommand()

Se não precisar analisar todo o fluxo de comandos, pendure um tratador num nome de comando — um para cada:

s_link.onCommand("drying", [](JsonObjectConst data) {
    myHeater.start(data["targetTempC"] | 0, data["durationS"] | 0);
});
s_link.onCommand("stop", [](JsonObjectConst) {
    myHeater.stop();
});

O nome é arbitrário, no máximo doze comandos. link_integration, bambu_apply e ping são tratados pela própria biblioteca — o seu tratador com o mesmo nome roda depois.

Não funciona junto com setCommandHandler: o dispatcher completo intercepta tudo e os tratadores de onCommand() não são chamados pela via MQTT. Mais detalhes em 03-public-api/01-link-api-reference.md.

Exemplo completo no repositório

Implementação de referência: handleCommand tratando drying / stop em iHeater-link/src/main.cpp.