Vlastní telemetrie (zátěž specifická pro produkt)¶
Kdy použít¶
Standardní telemetrie idryer-core publikuje pouze pole definovaná v běžné smlouvě (units[].temperature, humidity, heaterPower, atd.). Pokud tvůj produkt potřebuje přidat pole na nejvyšší úrovni JSON (např. outputMode, targetTempC, active) nebo zahrnout data, která nejsou v struktuře Telemetry, použij tento návod.
Typický případ: iHeater Link publikuje outputMode a targetTempC vedle standardního units[], aby backend mohl přeposlat heaterIntent do frontendu přes telemetry:update WebSocket event.
Krok 1 — Zakázání automatické publikace¶
Nastav telemetryPeriodMs = 0 v Config. To zabrání idryer-core publikování zjednodušené zátěže samo:
static const iDryer::Config CFG = {
// ...
.telemetryPeriodMs = 0, // publikuj ručně
.statusPeriodMs = 5000,
};
Krok 2 — Napsání funkce publikace¶
Používej device().mqttClient()->publishTelemetry(doc). Zahrň všechna pole, která backend očekává: jak specifickou pro produkt (nejvyšší úroveň), tak standardní blok units[].
#include <integrations/common/link_integrations_types.h> // activeIntegrationToString()
static void publishCustomTelemetry() {
auto* mqtt = device().mqttClient();
if (!mqtt) return;
// Aktuální záměr výstupu hardwaru
const auto cmd = s_output.getLastCommand();
const bool heating = (cmd.mode == ControllerOutputMode::TargetTemperature);
// Aktivní integrace ('bambu' / 'moonraker' / 'ha' / 'none')
using AI = idryer::cloud::ActiveIntegration;
const AI active = device().integrationsManager()->getActive();
StaticJsonDocument<384> doc;
// Pole na nejvyšší úrovni specifická pro produkt
doc["deviceType"] = "iheater_link";
doc["active"] = idryer::cloud::activeIntegrationToString(active);
doc["outputMode"] = heating ? 1 : 0;
doc["targetTempC"]= cmd.targetTempC;
// Standardní blok units[] — backend ukládá historii z tohoto
// temperature/humidity = 0 pokud zařízení nemá senzory
JsonArray units = doc.createNestedArray("units");
JsonObject u = units.createNestedObject();
u["unitId"] = "U1";
u["temperature"]= 0;
u["humidity"] = 0;
u["heaterPower"]= heating ? 100 : 0;
u["fanStatus"] = false;
mqtt->publishTelemetry(doc); // časové razítko se přidá automaticky
}
Krok 3 — Volání z loop()¶
void loop() {
device().loop();
static uint32_t s_lastTelMs = 0;
if ((uint32_t)(millis() - s_lastTelMs) >= 5000u) {
s_lastTelMs = millis();
publishCustomTelemetry();
}
// ...
}
Co nedělat¶
- Nepublikuj obojí automatickou telemetrii idryer-core (nenulové
telemetryPeriodMs) a vlastní telemetrii současně. Backend dostane dvě zprávy na stejném tématu a zpracuje obě — data se duplikují. - Nevoláj
device().publishTelemetryNow()kdyžtelemetryPeriodMs = 0— publikuje standardní zjednodušenou zátěž bez tvých polí specifických pro produkt.
Proč to knihovna nedělá sama¶
idryer-core už publikuje heaterPower: 1 uvnitř units[] — formálně dost aby bylo vidět, že se topí. Problém není v knihovně ale v backendu (telemetry.handler.ts): vypadá konkrétně po poli outputMode na nejvyšší úrovni a neodvozuje heaterIntent ze standardního heaterPower. To je technický dluh na straně backendu.
Aktuální návod je dočasné řešení. Pokud bude backend opraven aby odvodil heaterIntent z units[0].heaterPower, můžeš se vrátit k telemetryPeriodMs = 5000 a odstranit publishCustomTelemetry() — standardní telemetrie knihovny bude fungovat bez jakýchkoli změn.
Sleduj aktualizace telemetry.handler.ts: jakmile bude tam přidáno fallback na heaterPower, tento návod bude nadbytečný.