Přeskočit obsah

Veřejné API: iDryer::Link

iDryer::Link je jediný vstupní bod pro vývojáře zabudovaných systémů. Fasáda skrývá celý SDK stack: WiFi/Improv, cloud stavový stroj, HTTP claim, MQTT, lokální WebSocket, NVS. Produkt stačí vyplnit pole telemetry/status, zaregistrovat zpětná volání a zavolat begin()/loop().


Životní cyklus

Typický skelet main.cpp:

#include <iDryer.h>
#include <runtime/idryer_runtime.h>  // vyžadováno pouze při použití setCommandHandler

static const iDryer::Config CFG = {
    .deviceType        = iDryer::DeviceType::StorageLink,
    .unitsCount        = 1,
    .hasAirTemp        = true,
    .hasAirHumidity    = true,
    .hasHeaterTemp     = false,
    .hasHeaterPower    = false,
    .hasFanStatus      = false,
    .hasScales         = false,
    .hasRfid           = false,
    .allowHa           = false,
    .allowBambu        = false,
    .allowMoonraker    = false,
    .telemetryPeriodMs = 10000,
    .statusPeriodMs    = 0,
    .hardwareVersion   = "1.0",
    .firmwareVersion   = "1.0.0",
};

static iDryer::Link link(CFG);

void setup() {
    link.begin();
    // setCommandHandler — striktně PO begin(): begin() instaluje vlastní dispatcher
    link.runtime()->setCommandHandler(handleCommand);
}

void loop() {
    link.loop();
    link.telemetry.airTempC[0]       = sensor.readTemp();
    link.telemetry.airHumidityPct[0] = sensor.readHumidity();
}

Konfigurace: iDryer::Config

Vyplňuje se jednou v main.cpp, předává se konstruktoru Link. Všechna pole používají agregovanou inicializaci (C++ designované inicializátory).

Pole Typ Účel Poznámka
deviceType DeviceType Typ zařízení povinné
unitsCount uint8_t Počet jednotek (komor), 1..MAX_UNITS (4) povinné
hasAirTemp bool Je přítomen senzor teploty vzduchu false = pole je vynecháno z JSON
hasAirHumidity bool Je přítomen senzor vlhkosti false = pole je vynecháno z JSON
hasHeaterTemp bool Je přítomen senzor teploty topidla —
hasHeaterPower bool Je přítomen senzor výkonu topidla —
hasFanStatus bool Je přítomen stav ventilátoru —
hasScales bool Jsou přítomny váhy —
hasRfid bool Je přítomen čtečka RFID —
allowHa bool Povolovat integraci Home Assistant false = SDK nevytváří klienta
allowBambu bool Povolovat integraci Bambu Lab LAN —
allowMoonraker bool Povolovat integraci Moonraker/Klipper —
telemetryPeriodMs uint32_t Období automatického publikování Telemetry (ms) 0 = nepublikovat
statusPeriodMs uint32_t Období automatického publikování Status (ms) 0 = nepublikovat
hardwareVersion const char* Řetězec verze hardwaru povinné
firmwareVersion const char* Řetězec verze firmware povinné

Konstruktor

explicit Link(const Config& cfg);

Bere konfiguraci podle konstantní reference. CFG musí existovat po dobu celé životnosti objektu (typicky static const).

Metody

begin()

bool begin();

Zapne celý SDK stack: WiFi/Improv, cloud stavový stroj, HTTP claim, MQTT, lokální WebSocket, NVS persistence.

Zavolá se jednou v setup(). Vrací true při úspěšné inicializaci.

void setup() {
    link.begin();
}

loop()

void loop();

Jedina povinná metoda. Obsluhuje WiFi/MQTT/LocalAccess a automaticky publikuje telemetrii a stav na jejich časovačích.

Volá se při každé iteraci loop(). Bez tohoto volání není připojení udržováno.

void loop() {
    link.loop();  // první v loop(), před logikou produktu
}

Zdroj: iDryer-Storage/src/main.cpp:253, iHeater-link/src/main.cpp:381.

publishTelemetryNow()

void publishTelemetryNow();

Okamžitě publikuje aktuální stav link.telemetry, bez ohledu na časovač telemetryPeriodMs.

publishStatusNow()

void publishStatusNow();

Okamžitě publikuje aktuální stav link.status. Používá se po zpracování příkazu, když má být nový stav bez prodlevy odrážen na portálu.

// iHeater-link/src/main.cpp:238
device().publishStatusNow();

raiseEvent()

void raiseEvent(EventKind   severity,
                const char* event,
                const char* message,
                uint8_t     unitId = 0xFF);

Publikuje událost do tématu idryer/{serial}/events. Odesláno okamžitě.

Parameter Typ Účel
severity EventKind Info / Warning / Error
event const char* Kód události, např. "OVERHEAT", "SESSION_COMPLETE"
message const char* Libovolný ladící text
unitId uint8_t Index jednotky (0..unitsCount-1) nebo 0xFF pro zařízení
link.raiseEvent(iDryer::EventKind::Error, "OVERHEAT", "U1 too hot", 0);

onRequest()

void onRequest(RequestCallback cb);

Registruje zpětné volání pro obchodní příkazy (Start, Stop, Storage, Find, ClearErrors) přicházející přes MQTT nebo Local WS. Zdroj příkazu je transparentní.

RequestCallback = std::function<void(const iDryer::Request&)>

link.onRequest([](const iDryer::Request& r) {
    switch (r.kind) {
        case iDryer::RequestKind::Start: myStart(r.unitId, r.targetTempC); break;
        case iDryer::RequestKind::Stop:  myStop(r.unitId);                 break;
        default: break;
    }
});

Důležité: pokud je nastaven runtime()->setCommandHandler(...), toto zpětné volání není voláno — plný dispatcher zachycuje všechny příkazy.

onProfile()

void onProfile(ProfileCallback cb);

Registruje zpětné volání pro commands/profile — víceúrovňový plán sušení.

ProfileCallback = std::function<void(const iDryer::ProfileSchedule&)>

onIntegrationStatus()

void onIntegrationStatus(IntegrationStatusCallback cb);

Volá se, když se změní stav připojení integrace (HA, Bambu, Moonraker). Volitelné zpětné volání.

IntegrationStatusCallback = std::function<void(const iDryer::IntegrationStatus&)>

onClaimPin()

void onClaimPin(ClaimPinCallback cb);

Volá se, když cloud claim flow vrátí PIN pro zadání na portálu.

ClaimPinCallback = std::function<void(const char* pin, uint32_t expiresInSeconds)>

// iHeater-link/src/main.cpp:367
device().onClaimPin([](const char* pin, uint32_t expiresInSeconds) {
    Serial.printf("CLAIM_PIN:%s:%u\n", pin, expiresInSeconds);
});

isOnline()

bool isOnline() const;

Vrací true, pokud je zařízení zaregistrováno a relace MQTT je aktivní.

// iHeater-link/src/main.cpp:281
if (device().isOnline()) { ... }

serial()

const char* serial() const;

Sériové číslo zařízení (řetězec z NVS, přiřazeno během claim). Prázdný řetězec před dokončením claim.

seedWifiCredentialsIfEmpty()

void seedWifiCredentialsIfEmpty(const char* ssid, const char* password);

Zapíše přihlašovací údaje WiFi do NVS pouze pokud ještě nejsou nastaveny. Zavolá se před begin(). Používá se ve vývojových prostředích s pevnými přihlašovacími údaji.

setWifiCredentials()

void setWifiCredentials(const char* ssid, const char* password);

Vždy přepíše přihlašovací údaje WiFi v NVS. Vývojářský pomocník a vynucené přeúčtování.

// iHeater-link/src/main.cpp:313
device().setWifiCredentials(ssid.c_str(), pass.c_str());

requestClaim()

bool requestClaim();

Ručně spustí cloud claim flow (provision → register → check-claim). Při úspěchu volá registrované zpětné volání onClaimPin. Vrací true, pokud byl požadavek přijat.

// iHeater-link/src/main.cpp:284
bool ok = device().requestClaim();

eraseClaimAndRestart()

void eraseClaimAndRestart();

Odebere token zařízení z NVS a restartuje čip. Po restartu je zařízení neregistrované — automaticky se spustí flow autom. claim. Tato funkce se nevrací.

// iHeater-link/src/main.cpp:293
device().eraseClaimAndRestart();

integrationsManager()

idryer::cloud::LinkIntegrationsManager* integrationsManager();

Výstup na správce integrací — pro zapojení na straně produktu (Moonraker chamber target callbacks, Bambu printer status, atd.).

Vyžaduje #include <integrations/common/link_integrations_manager.h>.

// iHeater-link/src/main.cpp:337
device().integrationsManager()->setVirtualChamberCallback(onVirtualChamberUpdate);

mqttClient()

idryer::MqttClient* mqttClient();

Výstup na SDK MQTT klienta — pro komponenty, které publikují vlastní témata nebo se integrují do směrování příkazů (např. MenuBridge).

Vyžaduje #include <mqtt/mqtt_client.h>.

devicePublisher()

idryer::DevicePublisher* devicePublisher();

Výstup na duální publikační pomocníka — odesílá jednu zátěž na MQTT i Local WS současně. Používá se pro odpovědi produktu, které se musí dostat na LAN klienta stejným způsobem jako automaticky publikovaná telemetrie.

// iDryer-Storage/src/main.cpp:175
link.devicePublisher()->publishConfigRaw(buf, len);

runtime()

idryer::IdryerRuntime* runtime();

Výstup na SDK runtime — používá se k nastavení plného obsluhy příkazů místo fasádního dispatcheru. Po setCommandHandler(...) nejsou fasádní onRequest/onProfile volány přes MQTT cestu.

Důležité: volej striktně po begin() — begin() instaluje vlastní dispatcher, který musí být přepsán.

// iDryer-Storage/src/main.cpp:249
link.runtime()->setCommandHandler(handleCommand);

// Podpis obsluhy:
// void handleCommand(const char* cmd, JsonObjectConst data);

Vyžaduje #include <runtime/idryer_runtime.h>.


Telemetrická pole

Vyplňuje produkt v loop(). SDK je čte na časovači telemetryPeriodMs a publikuje do MQTT a Local WS.

Pole Typ Příznak konfigurace Účel
telemetry.airTempC[unitId] float hasAirTemp Teplota vzduchu, °C
telemetry.airHumidityPct[unitId] float hasAirHumidity Vlhkost, %
telemetry.heaterTempC[unitId] float hasHeaterTemp Teplota topidla, °C
telemetry.heaterPower01[unitId] float hasHeaterPower Výkon topidla, 0.0..1.0
telemetry.fanOn[unitId] bool hasFanStatus Stav ventilátoru
telemetry.weightG[unitId] uint16_t hasScales Váha, gramy
// iDryer-Storage/src/main.cpp:267
link.telemetry.airTempC[0]       = r.temperature;
link.telemetry.airHumidityPct[0] = r.humidity;

unitId = 0 pro první (nebo jedinou) jednotku. Index musí být < Config.unitsCount.

Pole Status — stejná struktura, ale pro operační stav:

Pole Typ Účel
status.mode[unitId] UnitMode Aktuální režim jednotky
status.targetTempC[unitId] float Cílová teplota
status.durationS[unitId] uint32_t Požadovaná doba trvání, s (0 = neurčitá)
status.elapsedS[unitId] uint32_t Čas uplynulý od začátku relace, s
// iHeater-link/src/main.cpp:229
device().status.mode[0]        = iDryer::UnitMode::Drying;
device().status.targetTempC[0] = cmd.targetTempC;
device().publishStatusNow();

Registrace zpětného volání přes runtime

Pokud je potřeba plná kontrola nad příchozími příkazy (např. produkt zpracovává get_config, set, nestandardní invoke):

// Podpis — z idryer_runtime.h
void handleCommand(const char* cmd, JsonObjectConst data);

// Registrace — striktně po link.begin()
link.runtime()->setCommandHandler(handleCommand);

cmd — řetězec příkazu ("set", "invoke", "ping", "get_config"). data — ArduinoJson JsonObjectConst s zátěží.

S tímto přístupem nejsou onRequest() a onProfile() volány z MQTT cesty — produkt zpracovává příkazy přímo.


Výčty

iDryer::DeviceType

Hodnota Číselně Účel
Unknown 0 Žádný / nedefinovaný
Dryer 1 Sušička (iDryer LINK)
Heater 2 Topidlo
StorageLink 4 Storage Link (ESP32-C3 + LED)
IHeaterLink 5 iHeater Link

iDryer::UnitMode

Idle, Drying, Storage, Profile, Fault, Unknown

iDryer::EventKind

Info, Warning, Error

iDryer::RequestKind

Start, Stop, Storage, Find, ClearErrors

iDryer::IntegrationKind

Ha, Bambu, Moonraker

iDryer::IntegrationState

Disabled, Idle, Connecting, Online, ConfigMissing, Error


Kdy jít hlouběji

Fasáda je dostatečná pro většinu úkolů. Pokud potřebuješ pracovat pod úrovní fasády — s idryer::IdryerRuntime, idryer::MqttClient, idryer::cloud::LinkIntegrationsManager — podívej se do sekce Architektura.