Command Confirmation

Knowing that a command actually reached and was applied by the device — not just that it was sent.

MQTT QoS is not confirmation. QoS only confirms the message reached the broker — never that the device received it or applied it. Confirmation is a separate feature, and it's off by default.

1What confirmation does

Say a user taps a light switch on a dashboard. Here's exactly what happens, step by step:

User taps the switch on the dashboard Dashboard sends home/light1 = 1 and WAITS nothing else runs yet — the switch shows a spinner Device replies home/light1 = 1 within 5 seconds No reply within 5 seconds Platform receives it → runs rules & scripts → updates Web + Virtuino Cloud app Nothing happens not stored, no automations run (logged — optional alert) Also publishes home/light1/state (retained) Third-party MQTT app must subscribe to home/light1/state (not home/light1) to get the right value

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 confirmationWith confirmation
Database & widgetsupdated immediatelyupdated when the device answers
Rules / scripts / HTTP triggersrun immediatelyrun when the device answers
If the device never answersvalue stored anywaynothing stored — you're alerted
It's a per-device setting. Turning it on applies to every field on that device — there's no way to confirm one field and not another. This matches how firmware is actually written: echoing back everything is simpler and more reliable than picking and choosing.

2Steps to enable it

1

What you have to do in the platform?

Console → Devices → open the device → Edit → set Command confirmation to Enabled, choose a timeout (default 5s).

2

What you have to do on device code

Replay the same message on every incoming message.

3

Optional

In the dashboard's settings, tick "Alert me if a command is not confirmed" to get an email/push, not just a log entry.

3Device code

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.

Echo the received value, not a pin reading. 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());
}
Full ready-to-flash sketch with Wi-Fi, Last Will and heartbeat included: see the MQTT code examples. For device availability / online-offline detection specifically, see Device Availability.