Seven steps, no sensor and no wiring. Your board publishes a value to the cloud every 3 seconds, and a switch on your dashboard turns the board's built-in LED on and off the moment you tap it.
The whole journey in 3 minutes — from empty account to a dashboard that turns your board's LED on and off.
Any ESP32 or ESP8266 board works. Nothing to wire — the sketch uses the LED that is already on the board.
Use the Sign In button at the top of this page, or create a free account if you don't have one yet.
In the console open Keys & Sub Users. You need the username (your account key) and the MQTT password. The broker address and ports are shown there too.
The complete sketch. It publishes a made-up value to demo_field_1 every
3 seconds and listens on demo_field_2 to switch the built-in LED.
#if defined(ESP32)
#include <WiFi.h>
#include <WiFiClientSecure.h>
WiFiClientSecure net;
#else
#include <ESP8266WiFi.h>
#include <WiFiClientSecureBearSSL.h>
BearSSL::WiFiClientSecure net;
#endif
#include <PubSubClient.h> // install "PubSubClient" by Nick O'Leary
#ifndef LED_BUILTIN
#define LED_BUILTIN 2 // some ESP32 boards don't define it
#endif
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* ACCOUNT = "YOUR_ACCOUNT_KEY"; // MQTT username - Console → Keys & Sub Users
const char* MQTT_PASS = "YOUR_MQTT_PASSWORD";
String pubTopic = String(ACCOUNT) + "/in/device/demo_device/demo_field_1"; // device → cloud
String subTopic = String(ACCOUNT) + "/out/device/demo_device/demo_field_2"; // cloud → device
PubSubClient mqtt(net);
void onMessage(char* topic, byte* payload, unsigned int len) {
String msg;
for (unsigned int i = 0; i < len; i++) msg += (char)payload[i];
bool on = msg.toFloat() > 0.5;
#if defined(ESP8266)
digitalWrite(LED_BUILTIN, on ? LOW : HIGH); // ESP8266 LED is inverted
#else
digitalWrite(LED_BUILTIN, on ? HIGH : LOW);
#endif
Serial.println("demo_field_2 = " + msg);
}
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
net.setInsecure(); // skip certificate check
mqtt.setServer("cloud.virtuino.com", 8883); // TLS
mqtt.setCallback(onMessage);
}
void loop() {
if (!mqtt.connected()) {
String clientId = String(ACCOUNT) + "-" + String(random(0xffff), HEX);
if (mqtt.connect(clientId.c_str(), ACCOUNT, MQTT_PASS)) mqtt.subscribe(subTopic.c_str());
else { Serial.println("MQTT failed, retrying..."); delay(2000); return; }
}
mqtt.loop();
static unsigned long last = 0;
if (millis() - last > 3000) {
last = millis();
float sensor_value = 25 + random(-5,+5);
mqtt.publish(pubTopic.c_str(), String(sensor_value).c_str());
}
}
Replace the four placeholders at the top of the sketch with your own values.
const char* SSID = "YOUR_WIFI_SSID"; const char* PASSWORD = "YOUR_WIFI_PASSWORD"; const char* ACCOUNT = "YOUR_ACCOUNT_KEY"; const char* MQTT_PASS = "YOUR_MQTT_PASSWORD";
In the Arduino IDE open Sketch → Include Library → Manage Libraries, search for PubSubClient by Nick O'Leary and install it. Then choose your ESP32 or ESP8266 board and the correct serial port, and press Upload.
Open the Serial Monitor at 115200 baud. Once WiFi and MQTT connect, the board starts publishing silently every 3 seconds.
Create a dashboard and add two widgets: a value or level widget bound to
demo_field_1, and a switch bound to
demo_field_2. The value updates every 3 seconds, and the switch turns the
board's LED on and off instantly.
The same walkthrough on video, from an empty account to a working dashboard.
Everything beyond this first connection — topics, security, and knowing whether a command actually reached the device.
Topic structure, QoS, retained messages, TLS and the reserved LWT topic for device availability.
Have the device echo back what it applied, so the dashboard shows whether a command really executed.
Every widget, how to size and style it, and how to bind it to your fields.
Simpler, and better for battery devices that just report a reading every few minutes.