All examples communicate with the Virtuino Cloud HTTP REST API using the VirtuinoCloud Arduino library — a lightweight, open-source wrapper that handles HTTPS, JSON serialization and multi-board support so your sketches stay short and readable.
Each example sends or receives data over HTTPS to https://api.virtuino.com/api/data. If you prefer to call the API directly without a library, see the HTTP API Guide.
Supports ESP32, ESP8266, Uno WiFi Rev2, MKR WiFi 1010, Nano 33 IoT and Nano RP2040 Connect. The correct HTTP backend is selected automatically at compile time — no configuration needed.
iliaslamprou/VirtuinoCloud on GitHubhttps://arduino.esp8266.com/stable/package_esp8266com_index.json
DEVICE string in your sketch must match the device name in the Console exactly.
| Board | WiFi chip | WiFi include | Extra library |
|---|---|---|---|
| ESP32 (all variants) | built-in | #include <WiFi.h> | none |
| ESP8266 — NodeMCU, Wemos D1 Mini, etc. | built-in | #include <ESP8266WiFi.h> | none |
| Uno WiFi Rev2 | NINA-W102 | #include <WiFiNINA.h> | ArduinoHttpClient |
| MKR WiFi 1010 | NINA-W102 | #include <WiFiNINA.h> | ArduinoHttpClient |
| Nano 33 IoT | NINA-W102 | #include <WiFiNINA.h> | ArduinoHttpClient |
| Nano RP2040 Connect | NINA-W102 | #include <WiFiNINA.h> | ArduinoHttpClient |
Every sketch that includes VirtuinoCloud.h has access to all of the following methods.
r.ok before using the result.bool — false on network error, wrong API key, or field not found.float or int. e.g. 23.4 / 23String. e.g. "23.4"char[] — ISO 8601 UTC timestamp. e.g. "2024-06-15T14:30:00Z"String: {"value":"23.4","time":"2024-06-15T14:30:00Z"}count records. Returns "[]" on error.count ≤ 50 on ESP8266. Server max: 5000.true on HTTP 200.publish=true also pushes to the MQTT broker — live dashboard widgets update instantly (Essential+ plan).true = publish to MQTT. Max 16 fields per block.beginWrite can be called next loop.The simplest upload: reads a sensor value and posts it to one field every 30 seconds. Use publish:true to also push to the MQTT broker so dashboard widgets update live.
temperature.
#include <WiFi.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY"; // Console → API & Connections
const char* DEVICE = "YOUR_DEVICE_ID"; // must match device name in Console exactly
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
float temperature = 23.4; // replace with a real sensor read
// Basic upload — server records the time of arrival as timestamp
bool ok = cloud.write(DEVICE, "temperature", temperature);
// publish=true pushes the value to the MQTT broker immediately,
// so live dashboard widgets (gauges, charts) update in real time
// bool ok = cloud.write(DEVICE, "temperature", temperature, true);
// With an explicit ISO 8601 UTC timestamp (for batch / offline uploads)
// bool ok = cloud.write(DEVICE, "temperature", temperature, true, "2024-06-15T14:30:00Z");
Serial.println(ok ? "Uploaded" : "Upload failed — check WiFi and API key");
delay(30000); // upload every 30 seconds (max rate: 600 writes/min)
}#include <ESP8266WiFi.h> // ESP8266 — use this instead of <WiFi.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
float temperature = 23.4;
bool ok = cloud.write(DEVICE, "temperature", temperature);
Serial.println(ok ? "Uploaded" : "Failed");
delay(30000);
}#include <WiFiNINA.h> // WiFiNINA boards — use this instead of <WiFi.h>
#include <VirtuinoCloud.h> // also install ArduinoHttpClient from Library Manager
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
float temperature = 23.4;
bool ok = cloud.write(DEVICE, "temperature", temperature);
Serial.println(ok ? "Uploaded" : "Failed");
delay(30000);
}Uploads three sensor values (temperature, humidity, pressure) in a single HTTP POST using beginWrite / add / send. Without block write, three fields would require three separate requests and three times the network latency.
temperature, humidity, pressure to your device.#include <WiFi.h>
#include <DHT.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
#define DHT_PIN 4
DHT dht(DHT_PIN, DHT22);
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
float pressure = 1013.0; // replace with a real barometer read
if (isnan(temperature) || isnan(humidity)) {
Serial.println("DHT22 read failed"); delay(5000); return;
}
// beginWrite() starts a new block — does NOT send yet
cloud.beginWrite(DEVICE);
// add() queues a field value
// publish=true → also push to MQTT broker for live dashboard widgets
cloud.add("temperature", temperature, true);
cloud.add("humidity", humidity, true);
cloud.add("pressure", pressure); // no publish for this one
// Optional: set a shared timestamp for all fields in this block
// cloud.add("time", "2024-06-15T14:30:00Z");
// send() transmits all queued fields in ONE HTTP POST, then resets the queue
bool ok = cloud.send();
if (ok) Serial.printf("Uploaded — T:%.1f H:%.1f P:%.1f\n", temperature, humidity, pressure);
else Serial.println("Upload failed");
delay(30000);
}#include <ESP8266WiFi.h>
#include <DHT.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
#define DHT_PIN D4 // GPIO2 on NodeMCU / Wemos D1 Mini
DHT dht(DHT_PIN, DHT22);
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) { delay(5000); return; }
cloud.beginWrite(DEVICE);
cloud.add("temperature", temperature, true);
cloud.add("humidity", humidity, true);
bool ok = cloud.send();
Serial.println(ok ? "Uploaded" : "Failed");
delay(30000);
}#include <WiFiNINA.h>
#include <DHT.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
#define DHT_PIN 2
DHT dht(DHT_PIN, DHT22);
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) { delay(5000); return; }
cloud.beginWrite(DEVICE);
cloud.add("temperature", temperature, true);
cloud.add("humidity", humidity, true);
bool ok = cloud.send();
Serial.println(ok ? "Uploaded" : "Failed");
delay(30000);
}Reads the state of two relay fields from the cloud every 5 seconds and switches the corresponding GPIO pins. A Toggle widget on the dashboard writes 1 (ON) or 0 (OFF) to each field.
relay1 and relay2.#include <WiFi.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int RELAY1 = 26; // GPIO connected to relay module 1 (HIGH = ON)
const int RELAY2 = 27; // GPIO connected to relay module 2
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
// Read relay 1 state set by the dashboard toggle widget
VirtuinoResult r1 = cloud.read(DEVICE, "relay1");
if (r1.ok) {
digitalWrite(RELAY1, r1.asInt() ? HIGH : LOW);
Serial.print("relay1="); Serial.print(r1.asString());
Serial.print(" at "); Serial.println(r1.time); // ISO 8601 timestamp
// r1.asJson() → {"value":"1","time":"2024-06-15T14:30:00Z"}
}
VirtuinoResult r2 = cloud.read(DEVICE, "relay2");
if (r2.ok) digitalWrite(RELAY2, r2.asInt() ? HIGH : LOW);
if (!r1.ok && !r2.ok) Serial.println("Read failed — check WiFi and API key");
delay(5000); // poll every 5 seconds
}#include <ESP8266WiFi.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int RELAY1 = D1; // GPIO5 on NodeMCU / Wemos D1 Mini
const int RELAY2 = D2; // GPIO4
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
VirtuinoResult r1 = cloud.read(DEVICE, "relay1");
if (r1.ok) digitalWrite(RELAY1, r1.asInt() ? HIGH : LOW);
VirtuinoResult r2 = cloud.read(DEVICE, "relay2");
if (r2.ok) digitalWrite(RELAY2, r2.asInt() ? HIGH : LOW);
delay(5000);
}#include <WiFiNINA.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int RELAY1 = 2;
const int RELAY2 = 3;
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
VirtuinoResult r1 = cloud.read(DEVICE, "relay1");
if (r1.ok) digitalWrite(RELAY1, r1.asInt() ? HIGH : LOW);
VirtuinoResult r2 = cloud.read(DEVICE, "relay2");
if (r2.ok) digitalWrite(RELAY2, r2.asInt() ? HIGH : LOW);
delay(5000);
}Reads a speed setpoint (0–255) and a direction flag from the cloud every 2 seconds. Sets PWM on a motor driver (e.g. L298N) and a direction GPIO. A Slider widget on the dashboard controls the speed; a Toggle widget controls the direction.
speed (slider 0–255) and direction (toggle 0/1).#include <WiFi.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int PWM_PIN = 18; // ENA pin on L298N (speed via LEDC PWM)
const int DIR_PIN = 19; // IN1 pin on L298N (direction)
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
ledcSetup(0, 1000, 8); // channel 0, 1 kHz, 8-bit resolution (0–255)
ledcAttachPin(PWM_PIN, 0);
pinMode(DIR_PIN, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
// Read speed value (0–255) set by slider widget on dashboard
VirtuinoResult spd = cloud.read(DEVICE, "speed");
if (spd.ok) {
int pwm = constrain(spd.asInt(), 0, 255);
ledcWrite(0, pwm);
Serial.print("Speed: "); Serial.println(pwm);
}
// Read direction: 0 = forward, 1 = reverse
VirtuinoResult dir = cloud.read(DEVICE, "direction");
if (dir.ok) {
digitalWrite(DIR_PIN, dir.asInt() ? HIGH : LOW);
Serial.println(dir.asInt() ? "Direction: REVERSE" : "Direction: FORWARD");
}
delay(2000); // check every 2 seconds
}#include <ESP8266WiFi.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int PWM_PIN = D5; // speed (analogWrite range 0–1023 on ESP8266)
const int DIR_PIN = D6; // direction
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
pinMode(DIR_PIN, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
VirtuinoResult spd = cloud.read(DEVICE, "speed");
if (spd.ok) {
// Dashboard uses 0–255; ESP8266 analogWrite uses 0–1023 — scale it
int pwm = map(constrain(spd.asInt(), 0, 255), 0, 255, 0, 1023);
analogWrite(PWM_PIN, pwm);
}
VirtuinoResult dir = cloud.read(DEVICE, "direction");
if (dir.ok) digitalWrite(DIR_PIN, dir.asInt() ? HIGH : LOW);
delay(2000);
}#include <WiFiNINA.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int PWM_PIN = 9;
const int DIR_PIN = 8;
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
pinMode(DIR_PIN, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
VirtuinoResult spd = cloud.read(DEVICE, "speed");
if (spd.ok) analogWrite(PWM_PIN, constrain(spd.asInt(), 0, 255));
VirtuinoResult dir = cloud.read(DEVICE, "direction");
if (dir.ok) digitalWrite(DIR_PIN, dir.asInt() ? HIGH : LOW);
delay(2000);
}Syncs time from an NTP server and attaches an explicit ISO 8601 UTC timestamp to each block upload. Useful when you want precise control over the timestamp shown in charts, or when you are uploading historical data collected offline.
2024-06-15T14:30:00Z. If omitted, the server records the time of arrival.#include <WiFi.h>
#include <time.h> // for configTime() and strftime()
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
VirtuinoCloud cloud(API_KEY);
// Fills buf with the current UTC time in ISO 8601 format: "2024-06-15T14:30:00Z"
void getTimestamp(char* buf, size_t len) {
time_t now = time(nullptr);
strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
}
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
// Sync time from NTP — waits until a valid epoch is received
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
Serial.print("Syncing NTP");
while (time(nullptr) < 1000000000UL) { delay(500); Serial.print("."); }
Serial.println(" done");
}
void loop() {
float temperature = 23.4; // replace with sensor read
float humidity = 61.0;
char ts[25];
getTimestamp(ts, sizeof(ts)); // e.g. "2024-06-15T14:30:00Z"
// All fields in this block share the same explicit timestamp
cloud.beginWrite(DEVICE);
cloud.add("temperature", temperature, true);
cloud.add("humidity", humidity, true);
cloud.add("time", ts); // attach the NTP timestamp
bool ok = cloud.send();
Serial.printf("%s at %s\n", ok ? "Uploaded" : "FAILED", ts);
delay(60000); // upload every minute
}#include <ESP8266WiFi.h>
#include <time.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
VirtuinoCloud cloud(API_KEY);
void getTimestamp(char* buf, size_t len) {
time_t now = time(nullptr);
strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
}
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
configTime(0, 0, "pool.ntp.org");
while (time(nullptr) < 1000000000UL) { delay(500); }
Serial.println("NTP synced");
}
void loop() {
char ts[25];
getTimestamp(ts, sizeof(ts));
cloud.beginWrite(DEVICE);
cloud.add("temperature", 23.4f, true);
cloud.add("humidity", 61.0f, true);
cloud.add("time", ts);
Serial.println(cloud.send() ? "Uploaded" : "Failed");
delay(60000);
}#include <WiFiNINA.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
VirtuinoCloud cloud(API_KEY);
// WiFiNINA provides getTime() which returns Unix epoch seconds
// For production use consider an RTC module for a proper formatted timestamp
void getTimestamp(char* buf, size_t len) {
unsigned long ep = WiFi.getTime();
snprintf(buf, len, "epoch-%lu", ep); // simple form; convert to ISO 8601 if needed
}
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
char ts[32];
getTimestamp(ts, sizeof(ts));
cloud.beginWrite(DEVICE);
cloud.add("temperature", 23.4f, true);
cloud.add("time", ts);
Serial.println(cloud.send() ? "Uploaded" : "Failed");
delay(60000);
}Fetches the last 50 records of a field as a JSON array String, parses each entry with ArduinoJson and computes the average, minimum and maximum values. The same technique can be used to find anomalies, draw local charts, or make decisions based on trend data.
count ≤ 50 on ESP8266. ESP32 handles 500+ records comfortably.#include <WiFi.h>
#include <ArduinoJson.h> // needed to parse the returned JSON array
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
VirtuinoCloud cloud(API_KEY);
bool fetched = false;
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected — fetching history...");
}
void loop() {
if (!fetched) {
// Returns: [{"time":"...","value":"23.4","source":"HTTP"}, ...]
// Returns "[]" on error or if the field has no data yet
String history = cloud.readHistory(DEVICE, "temperature", 50);
// Parse with ArduinoJson — allocate ~120 bytes × number of records
DynamicJsonDocument doc(8192);
DeserializationError err = deserializeJson(doc, history);
if (err) {
Serial.print("JSON parse error: "); Serial.println(err.c_str());
} else {
JsonArray arr = doc.as<JsonArray>();
float sum = 0, minVal = 1e9, maxVal = -1e9;
int n = 0;
for (JsonObject rec : arr) {
float v = atof(rec["value"] | "0");
sum += v;
minVal = min(minVal, v);
maxVal = max(maxVal, v);
Serial.printf("[%2d] %s → %.2f\n", n, (const char*)rec["time"], v);
n++;
}
if (n > 0) {
Serial.println("────────────────────────────────");
Serial.printf("Count: %d Avg: %.2f Min: %.2f Max: %.2f\n",
n, sum/n, minVal, maxVal);
} else {
Serial.println("No records — upload some data first (Example 1 or 2)");
}
}
fetched = true;
}
delay(1000);
}#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
VirtuinoCloud cloud(API_KEY);
bool fetched = false;
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nConnected — fetching...");
}
void loop() {
if (!fetched) {
// Keep count ≤ 50 on ESP8266 to avoid running out of heap
String history = cloud.readHistory(DEVICE, "temperature", 50);
DynamicJsonDocument doc(4096);
if (!deserializeJson(doc, history)) {
JsonArray arr = doc.as<JsonArray>();
float sum = 0; int n = 0;
for (JsonObject rec : arr) { sum += atof(rec["value"] | "0"); n++; }
if (n > 0) Serial.printf("Avg: %.2f over %d records\n", sum/n, n);
}
fetched = true;
}
delay(1000);
}#include <WiFiNINA.h>
#include <ArduinoJson.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
VirtuinoCloud cloud(API_KEY);
bool fetched = false;
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nConnected");
}
void loop() {
if (!fetched) {
String history = cloud.readHistory(DEVICE, "temperature", 50);
DynamicJsonDocument doc(4096);
if (!deserializeJson(doc, history)) {
JsonArray arr = doc.as<JsonArray>();
float sum = 0; int n = 0;
for (JsonObject rec : arr) { sum += atof(rec["value"] | "0"); n++; }
if (n > 0) Serial.printf("Avg: %.2f over %d records\n", sum/n, n);
}
fetched = true;
}
delay(1000);
}A complete closed-loop control example: reads a temperature setpoint from the dashboard, measures actual temperature with a DHT22, controls a heater relay using bang-bang logic with hysteresis, and uploads all measurements in one request. Demonstrates read() and beginWrite/add/send working together.
setpoint, temperature, heater_state.setpoint | Gauge → temperature | LED → heater_state
#include <WiFi.h>
#include <DHT.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int DHT_PIN = 4;
const int HEATER = 26; // relay controlling the heater (HIGH = ON)
DHT dht(DHT_PIN, DHT22);
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(HEATER, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
// Step 1 — Read desired setpoint from dashboard (default 22°C if read fails)
VirtuinoResult sp = cloud.read(DEVICE, "setpoint");
float setpoint = sp.ok ? sp.asFloat() : 22.0f;
// Step 2 — Measure actual temperature
float actual = dht.readTemperature();
if (isnan(actual)) { Serial.println("DHT22 read failed"); delay(5000); return; }
// Step 3 — Bang-bang control with 0.5°C hysteresis
// Heater turns ON below (setpoint - 0.5) and OFF above (setpoint + 0.5)
// No change inside the 1°C deadband — prevents rapid switching
bool heaterOn = digitalRead(HEATER);
if (actual < setpoint - 0.5f) heaterOn = true;
if (actual > setpoint + 0.5f) heaterOn = false;
digitalWrite(HEATER, heaterOn ? HIGH : LOW);
// Step 4 — Upload measurements and heater state in ONE request
// publish=true → live dashboard widgets update immediately
cloud.beginWrite(DEVICE);
cloud.add("temperature", actual, true);
cloud.add("heater_state", heaterOn ? 1.0f : 0.0f, true);
bool ok = cloud.send();
Serial.printf("%s SP:%.1f Actual:%.1f Heater:%s\n",
ok ? "OK " : "FAIL", setpoint, actual, heaterOn ? "ON" : "OFF");
delay(10000); // control loop runs every 10 seconds
}#include <ESP8266WiFi.h>
#include <DHT.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int DHT_PIN = D4;
const int HEATER = D1;
DHT dht(DHT_PIN, DHT22);
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(HEATER, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
VirtuinoResult sp = cloud.read(DEVICE, "setpoint");
float setpoint = sp.ok ? sp.asFloat() : 22.0f;
float actual = dht.readTemperature();
if (isnan(actual)) { delay(5000); return; }
bool heaterOn = digitalRead(HEATER);
if (actual < setpoint - 0.5f) heaterOn = true;
if (actual > setpoint + 0.5f) heaterOn = false;
digitalWrite(HEATER, heaterOn ? HIGH : LOW);
cloud.beginWrite(DEVICE);
cloud.add("temperature", actual, true);
cloud.add("heater_state", heaterOn ? 1.0f : 0.0f, true);
cloud.send();
delay(10000);
}#include <WiFiNINA.h>
#include <DHT.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int DHT_PIN = 2;
const int HEATER = 4;
DHT dht(DHT_PIN, DHT22);
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(HEATER, OUTPUT);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
VirtuinoResult sp = cloud.read(DEVICE, "setpoint");
float setpoint = sp.ok ? sp.asFloat() : 22.0f;
float actual = dht.readTemperature();
if (isnan(actual)) { delay(5000); return; }
bool heaterOn = digitalRead(HEATER);
if (actual < setpoint - 0.5f) heaterOn = true;
if (actual > setpoint + 0.5f) heaterOn = false;
digitalWrite(HEATER, heaterOn ? HIGH : LOW);
cloud.beginWrite(DEVICE);
cloud.add("temperature", actual, true);
cloud.add("heater_state", heaterOn ? 1.0f : 0.0f, true);
cloud.send();
delay(10000);
}A complete weather station sketch that combines multiple sensors: a DHT22 for temperature and humidity, a BMP280 for barometric pressure and altitude, and a photoresistor for light level. All six values are sent in one block write every minute. Also reads an alarm threshold from the dashboard and activates a buzzer if the temperature exceeds it.
temperature, humidity, pressure, altitude, light, alarm_threshold.#include <WiFi.h>
#include <DHT.h>
#include <Adafruit_BMP280.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int DHT_PIN = 4;
const int LIGHT_PIN = 34; // ADC pin for photoresistor (0–4095)
const int BUZZER = 25; // alarm buzzer
DHT dht(DHT_PIN, DHT22);
Adafruit_BMP280 bmp; // I2C: SDA=21, SCL=22 on ESP32
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(BUZZER, OUTPUT);
if (!bmp.begin(0x76)) { // try 0x77 if 0x76 doesn't work
Serial.println("BMP280 not found — check wiring");
}
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
// ── Read all sensors ─────────────────────────────────────────────────────
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
float pressure = bmp.readPressure() / 100.0f; // Pa → hPa
float altitude = bmp.readAltitude(1013.25f); // sea-level pressure hPa
float light = analogRead(LIGHT_PIN) / 40.95f; // map 0–4095 → 0–100%
if (isnan(temperature) || isnan(humidity)) {
Serial.println("DHT22 read failed"); delay(5000); return;
}
// ── Check alarm threshold from dashboard ──────────────────────────────────
VirtuinoResult threshold = cloud.read(DEVICE, "alarm_threshold");
if (threshold.ok && temperature > threshold.asFloat()) {
tone(BUZZER, 1000, 500); // beep for 500 ms
Serial.printf("ALARM! Temp %.1f°C exceeds threshold %.1f°C\n",
temperature, threshold.asFloat());
}
// ── Upload all 5 sensor values in one HTTP request ────────────────────────
cloud.beginWrite(DEVICE);
cloud.add("temperature", temperature, true);
cloud.add("humidity", humidity, true);
cloud.add("pressure", pressure, true);
cloud.add("altitude", altitude);
cloud.add("light", light, true);
bool ok = cloud.send();
Serial.printf("%s T:%.1f H:%.1f P:%.1f Alt:%.0f Light:%.0f%%\n",
ok ? "OK" : "FAIL",
temperature, humidity, pressure, altitude, light);
delay(60000); // upload every minute
}#include <ESP8266WiFi.h>
#include <DHT.h>
#include <Adafruit_BMP280.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int DHT_PIN = D4;
const int BUZZER = D3;
DHT dht(DHT_PIN, DHT22);
Adafruit_BMP280 bmp; // I2C: SDA=D2, SCL=D1 on NodeMCU / Wemos D1 Mini
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(BUZZER, OUTPUT);
if (!bmp.begin(0x76)) Serial.println("BMP280 not found");
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
float pressure = bmp.readPressure() / 100.0f;
float altitude = bmp.readAltitude(1013.25f);
// ESP8266 has one ADC (A0, 0-1V, 0–1023)
float light = analogRead(A0) / 10.23f; // 0–100%
if (isnan(temperature) || isnan(humidity)) { delay(5000); return; }
VirtuinoResult threshold = cloud.read(DEVICE, "alarm_threshold");
if (threshold.ok && temperature > threshold.asFloat())
digitalWrite(BUZZER, HIGH);
else
digitalWrite(BUZZER, LOW);
cloud.beginWrite(DEVICE);
cloud.add("temperature", temperature, true);
cloud.add("humidity", humidity, true);
cloud.add("pressure", pressure, true);
cloud.add("altitude", altitude);
cloud.add("light", light, true);
Serial.println(cloud.send() ? "Uploaded" : "Failed");
delay(60000);
}#include <WiFiNINA.h>
#include <DHT.h>
#include <Adafruit_BMP280.h>
#include <VirtuinoCloud.h>
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
const char* API_KEY = "YOUR_API_KEY";
const char* DEVICE = "YOUR_DEVICE_ID";
const int DHT_PIN = 2;
const int BUZZER = 5;
DHT dht(DHT_PIN, DHT22);
Adafruit_BMP280 bmp;
VirtuinoCloud cloud(API_KEY);
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(BUZZER, OUTPUT);
if (!bmp.begin(0x76)) Serial.println("BMP280 not found");
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi connected");
}
void loop() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
float pressure = bmp.readPressure() / 100.0f;
float altitude = bmp.readAltitude(1013.25f);
float light = analogRead(A0) / 10.23f;
if (isnan(temperature) || isnan(humidity)) { delay(5000); return; }
VirtuinoResult threshold = cloud.read(DEVICE, "alarm_threshold");
if (threshold.ok && temperature > threshold.asFloat())
digitalWrite(BUZZER, HIGH);
else
digitalWrite(BUZZER, LOW);
cloud.beginWrite(DEVICE);
cloud.add("temperature", temperature, true);
cloud.add("humidity", humidity, true);
cloud.add("pressure", pressure, true);
cloud.add("altitude", altitude);
cloud.add("light", light, true);
Serial.println(cloud.send() ? "Uploaded" : "Failed");
delay(60000);
}