Publishing Data
How to send data from your device to the OhioIoT platform — and what happens when it arrives.
Topic prefixing with ~/ and ~/~/
Every topic on the broker must begin with your MQTT username, and most device-scoped topics also include your device ID as the second segment. Typing those out on every publish call is noisy, so the SDK gives you two shortcuts: ~/ and ~/~/. The SDK rewrites them at publish time — they never leave the device.
// ~/~/ expands to username/deviceID/
mqtt.publish("~/~/numb/temperature/temp", 72.5);
// actual topic on the broker:
// larry/a8f3k2m1/numb/temperature/temp → 72.5
// ~/ expands to username/ (device ID is skipped)
mqtt.publish("~/outdoor/humidity", 45.2);
// actual topic on the broker:
// larry/outdoor/humidity → 45.2
// no prefix — topic is sent verbatim
mqtt.publish("larry/fleet/alert", "rollover");
// actual topic on the broker:
// larry/fleet/alert → rolloverThe username comes from your MQTT_USER credential, and the device ID comes from device_id.get_or_set() at boot.
~/ or ~/~/ is rewritten. A ~ anywhere else in the topic is treated as a literal character and sent through unchanged.Which prefix to use
~/~/ for device-scoped topics — the default choice. Any data that belongs to a specific device: sensor readings, status, config echoes, per-device commands. This is what the OhioIoT dashboard expects for graphs and device cards.
~/ for account-wide topics — when a message belongs to your account but not to one specific device. Group broadcasts, fleet-wide commands, or shared topics that multiple devices publish to or subscribe to.
No prefix — when you want full control over the topic string, or when you're copying topics from another source. You are responsible for making sure the topic starts with your username; the broker will reject it otherwise.
Data types
The third segment of your topic tells the platform what kind of data you're sending. Each type is handled differently:
For numb and bool, the topic has five segments: username / device / type / graph name / series name. Multiple series on the same graph share the graph name.
For status and config, the topic has four segments: username / device / type / key name. The payload is the value.
Publish overloads
The mqtt.publish() function accepts several payload types. The topic is always a const char *.
// string payload
mqtt.publish("~/~/status/firmware", "v1.2.0");
// float payload — converted to string with 2 decimal places
mqtt.publish("~/~/numb/temperature/temp", 72.53);
// integer payload — converted to string
mqtt.publish("~/~/numb/counters/boot_count", 14);
// empty payload — publishes with an empty string
mqtt.publish("~/~/numb/heartbeat/ping");"72.5" as a string to a numb topic, it's parsed as a number. If you publish "true", "yes", "on", or "1" to a bool topic, it's parsed as true. You don't need to worry about types on the device side.Multiple series on one graph
To plot multiple values on the same graph, use the same graph name with different series names:
// both go on the "temperature" graph
mqtt.publish("~/~/numb/temperature/indoor", 72.5);
mqtt.publish("~/~/numb/temperature/outdoor", 58.3);
// both go on the "climate" graph
mqtt.publish("~/~/bool/climate/heating", "true");
mqtt.publish("~/~/bool/climate/cooling", "false");Each unique series name becomes a separate line on the graph. The graph is created automatically the first time the platform sees the graph name — you don't need to configure anything.
Status and config
status and config values appear on the device card in the Devices screen. Use status for read-only values the device reports about itself:
mqtt.publish("~/~/status/firmware", "v1.2.0");
mqtt.publish("~/~/status/uptime", millis() / 1000);
mqtt.publish("~/~/status/ip", WiFi.localIP().toString().c_str());Use config when the device echoes back a setting it received from the dashboard — this confirms to the user that the setting took effect:
// device receives a new setpoint from the dashboard,
// applies it, and echoes back confirmation:
mqtt.publish("~/~/config/setpoint", 72);