Knowing that a command actually reached and was applied by the device — not just that it was sent.
Say a user taps a light switch on a dashboard. Here's exactly what happens, step by step:
Two outcomes: either the device answers in time and everything — automations, both dashboards, and any third-party app — updates together; or it doesn't, and nothing changes anywhere. Never a half-applied, out-of-sync state.
| Without confirmation | With confirmation | |
|---|---|---|
| Database & widgets | updated immediately | updated when the device answers |
| Rules / scripts / HTTP triggers | run immediately | run when the device answers |
| If the device never answers | value stored anyway | nothing stored — you're alerted |
Console → Devices → open the device → Edit → set Command confirmation to Enabled, choose a timeout (default 5s).
Replay the same message on every incoming message.
In the dashboard's settings, tick "Alert me if a command is not confirmed" to get an email/push, not just a log entry.
Two fields shown below (relay1, relay2) to make the point that
every command field needs its own echo — there's no per-field switch anymore, so a
field you forget here will simply always time out.
digitalRead() only works for a simple on/off relay. For a slider or any numeric field,
echo the value you actually parsed from the command — a pin reading will never match it.
// ── Topics ────────────────────────────────────────────── // Bare topics — no account key needed. Each one is used for // BOTH subscribe (receive command) and publish (echo back); // the broker keeps the two directions separate automatically. String deviceName = "esp32"; String topicRelay1 = deviceName + "/relay1"; String topicRelay2 = deviceName + "/relay2"; void onMessage(char* topic, byte* payload, unsigned int len) { String msg = ""; for (unsigned int i = 0; i < len; i++) msg += (char)payload[i]; if (String(topic) == topicRelay1) { digitalWrite(RELAY1_PIN, msg == "1" ? HIGH : LOW); mqtt.publish(topicRelay1.c_str(), msg.c_str()); // echo — confirms relay1 } if (String(topic) == topicRelay2) { digitalWrite(RELAY2_PIN, msg == "1" ? HIGH : LOW); mqtt.publish(topicRelay2.c_str(), msg.c_str()); // echo — confirms relay2 } } void setup() { // ... WiFi.begin(...), mqtt.setServer(...), mqtt.setCallback(onMessage) ... mqtt.subscribe(topicRelay1.c_str()); mqtt.subscribe(topicRelay2.c_str()); }