This guide explains how data moves through Virtuino Cloud — from the moment a device sends a value, all the way to storage, real-time dashboards, automation rules, and scripts. Understanding this flow helps you design reliable automations, avoid common pitfalls, and get the most out of the platform's capabilities.
Every value that reaches Virtuino Cloud arrives through one of the following entry points. Each one identifies itself with a source tag that travels with the data throughout its entire journey inside the platform.
| Entry Point | Source Tag | Typical Use |
|---|---|---|
MQTT Device publishes to a bare topic, e.g. {name}/{field} |
MQTT |
Microcontrollers, sensors, ESP32, Arduino, any MQTT-capable device |
| HTTP Device sends an HTTP POST/GET request | HTTP |
Any device or service that can make web requests |
| WS User writes a value from a Dashboard widget | DASHBOARD |
Manual control, sliders, buttons in the UI |
| RULE An Automation Rule fires an action | AUTOMATION_RULE |
Conditional logic that writes to a field when a threshold is met |
| SCRIPT A Script writes an output value | SCRIPT |
JavaScript logic that computes and writes results |
| SCHEDULE A Scheduler writes a value on a timer | SCHEDULE |
Periodic writes, e.g. every hour or every day |
Figure 1 — Every entry point funnels through the platform hub, which then distributes the value to all downstream systems.
No matter where a value originates, it always passes through the platform's central processing function. This hub performs the same sequence of actions for every incoming value:
MQTT is a publish/subscribe messaging protocol. Devices publish values to "topics" — think of these as named channels. Every field has two such channels: one your devices publish sensor readings to, and a separate one the platform uses to send commands back. For exactly what topic string to use in your device code, see the MQTT topic guide — this section is only about the architecture underneath, not something you need to configure.
Virtuino Cloud keeps these two channels strictly separate under the hood. This is one of the most important architectural decisions in the platform, as it eliminates an entire class of potential infinite loops.
Used by your physical devices to send data to the platform. The platform only ever listens on this channel — it never sends anything out on it.
Used by the platform to send data back to devices, or for other apps to receive real-time updates. The platform never listens on this channel — only ever sends.
Figure 2 — The two channels are completely separate. The platform only listens on Channel 1, so values it sends out on Channel 2 never come back to it.
If your device does not have a specific device name, you can publish directly to a bare field topic without any device segment. The platform will assign the value to a generic device called unspecified:
// Bare topic, no device name — what your device actually writes:
{fieldName}
// Example:
temperature
Every time any value is processed by the platform hub — regardless of source — it is instantly broadcast to all open dashboards that are displaying that field. This happens through an internal real-time channel (WebSocket), so there is no need to refresh the page.
This means:
DASHBOARD and is processed exactly like any other incoming value — saved to the database, broadcast to all other dashboards, and eligible to trigger rules and scripts.
Automation Rules are condition-based triggers. You define a condition (e.g., "when field temperature is greater than 80") and an action (e.g., "write value 1 to field alarm"). When the condition is met, the action fires automatically.
AUTOMATION_RULE.| Setting | Description |
|---|---|
| Source field | The field whose incoming value will trigger the condition check |
| Source device | Optionally restrict the rule to a specific device |
| Operator | The comparison: >, <, ==, !=, >=, <= |
| Threshold | The value to compare against |
| Target field | The field that will receive the action value |
| Target value | The value to write to the target field when the condition is met |
| MQTT Publish | If enabled, the written value is also sent out via MQTT to devices |
| Email / Push notification | Alert notifications, controlled by a cooldown interval to avoid spam |
| Notify interval (seconds) | Minimum time between repeat notifications for the same rule |
Rules use an internal triggered flag. When a condition is first met, the rule fires and sets the flag to true. If the condition remains true on subsequent data arrivals, the action does not fire again (it already fired). The flag resets to false only when the condition is no longer met — this prevents the rule from repeatedly firing while the condition is continuously true.
Scripts allow you to write JavaScript logic that runs automatically when data arrives or on a timer. They can read multiple input fields, perform calculations, and write results to output fields.
The script runs immediately when one of its configured input fields receives a new value. Best for low-latency responses: alarms, control loops, value transformations.
The script runs on a fixed schedule (e.g., every 30 seconds, every hour). Best for periodic calculations: averages, aggregations, scheduled reports.
Scripts interact with platform data through a mapping table, not by directly naming database tables. Each row in the mapping table declares:
SCRIPT. It will be saved to the database, shown on dashboards, and is eligible to trigger rules — but will not trigger other scripts. See Section 9.
Each script runs in an isolated sandbox with a strict 50ms execution timeout. If the script takes longer than 50ms, it is terminated. This protects the platform from poorly written scripts consuming server resources. Additionally, script-to-script cascade chains are limited to a maximum depth of 5 levels.
Schedulers allow you to write a specific value to a specific field at a fixed time or on a repeating interval — without any condition or script logic. They are the simplest form of automation: "every day at 08:00, write value 1 to field morning_flag".
Values written by schedulers enter the hub with source SCHEDULE and are eligible to trigger both rules and scripts, exactly like values from external devices.
When any value arrives at the platform hub, the following sequence always takes place in this order:
Figure 3 — The fixed processing order for every incoming value. Steps 5 and 6 run in parallel and have conditions based on the value's source.
The most dangerous scenario in any automation platform is an infinite loop: a value triggers a rule, which writes a new value, which triggers a script, which writes another value, which triggers the rule again — endlessly. This would fill the database, consume all server resources, and crash the platform.
Virtuino Cloud prevents loops at three levels:
The platform only ever listens on the channel devices publish to, and only ever sends on the separate channel devices/apps listen to (see Section 3). Since it never listens to its own outbound channel, its own outbound MQTT messages can never come back to it. This makes MQTT-based loops architecturally impossible — not just prevented by code logic, but structurally impossible by design.
The platform tracks the source of every value and applies strict rules about what can trigger what:
Figure 4 — Source-based trigger filtering. The source tag determines what the value is allowed to trigger.
Scripts that are triggered by other scripts (through a chain of field writes) are limited to a maximum cascade depth of 5 levels. If a script's output triggers another script, and that script's output triggers another, and so on, the chain is cut at level 5 regardless of conditions.
Symptom: A rule seems to fire over and over, filling the automation log with repeated entries.
Cause: The triggered flag mechanism prevents repeat fires within the same condition state. However, if the source field is receiving many new values (e.g., every second), and the condition remains true, the rule evaluates every time but fires only on the first occurrence — this is normal. If you are seeing log entries on every value, check that the rule's notify interval is set appropriately.
Solution: Set the notify interval to a minimum cooldown period (e.g., 300 seconds) to silence repeat notifications while the condition remains true.
Symptom: Script A writes to a field. Script B is configured to trigger on that same field. Script B never runs.
Cause: This is intentional. Values produced by scripts are tagged with source SCRIPT, and the platform will not trigger other scripts from script-produced values. This prevents infinite script chains.
Solution: Combine the logic into a single script that reads all the input fields and writes all the outputs directly, instead of chaining scripts.
Symptom: A rule writes a value to a target field, but the dashboard widget for that field does not update.
Cause: The dashboard widget may be configured to show a different device's field, or the field mapping is incorrect.
Solution: Verify that the rule's target field matches exactly the field displayed by the dashboard widget, including the device name. Check the Data Monitor to confirm the value is actually being written.
Symptom: A device is publishing via MQTT but no data appears in the platform.
Cause: The device is publishing to a topic that doesn't match its intended field, or the Device/Field name in the topic doesn't exactly match what's registered in the Console.
Solution: Check the exact bare topic your device publishes to against the MQTT topic guide — the device and field names must match the Console exactly. Use the Data Monitor to observe incoming data in real time.
Symptom: A device subscribes to MQTT to receive commands or values from rules/scripts, but receives nothing.
Cause: The device is subscribed to a topic that doesn't match the field name being published, or "MQTT Publish" isn't enabled on that field.
Solution: Update the device to subscribe to the same bare field topic (e.g. {deviceName}/{fieldName}) — see the MQTT topic guide. Use # to subscribe to everything the platform sends you, for debugging.
Symptom: A script executes without errors in the test console, but the target field shows no new value.
Cause: Either the output mapping row has an incorrect field reference, or the script is writing to the output variable but the Is Ready / Is Active flags are not both enabled.
Solution: Confirm both Is Active and Is Ready are checked. Verify the OUT mapping row points to the correct device and field. Use the built-in test console to run the script and check the output values shown.
Symptom: A field configured as historical is storing every value, consuming large amounts of storage.
Cause: A device or script is writing to a historical field very frequently (e.g., every second).
Solution: Either reduce the write frequency on the device side, switch the field to live-only mode if history is not needed, or use a script to filter and write only when the value changes significantly (deadband filtering).
The source tag is attached to every value in the platform. It determines what that value is allowed to trigger and is visible in the Data Monitor and automation logs.
| Source Tag | Origin | Triggers Rules? | Triggers Scripts? | MQTT outbound? |
|---|---|---|---|---|
MQTT |
Device via MQTT | Yes | Yes | Forwarded to devices automatically |
HTTP |
Device via HTTP | Yes | Yes | Only if publish is enabled |
DASHBOARD |
Manual write from UI widget | Yes | Yes | Only if publish is enabled |
SCHEDULE |
Scheduler write | Yes | Yes | Only if publish is enabled |
SCRIPT |
Script output write | Yes | No | Only if publish is enabled for that output mapping |
AUTOMATION_RULE |
Rule action write | No | No | Only if MQTT publish is enabled on the rule |
Figure 5 — The complete automation execution graph. External sources can trigger both rules and scripts. Rule outputs and script outputs have restricted downstream triggering to prevent loops.
Virtuino Cloud Platform — Data Flow & Automation Architecture Guide