Event
Publish discrete events from your device. Events represent moments that happen — a door opening, a device booting up, a threshold being crossed, a user pressing a button. The App SDK can subscribe to these events in real time.
Telemetry vs Events
Telemetry and events are both fire-and-forget, but they serve different purposes:
| Telemetry | Events | |
|---|---|---|
| What it captures | Continuous measurements (temperature, humidity, pressure) | Discrete moments (door opened, error detected, boot complete) |
| Frequency | Regular intervals (e.g., every 5 seconds) | Whenever something happens |
| Schema | Validated against device schema | No schema — you define the event name and payload |
| Timestamps | Auto-added by the SDK via NTP | Auto-added by the SDK via NTP |
Rule of thumb: if you're measuring something continuously, use telemetry. If something just happened, use an event.
Overview
Events are user-defined — the name and payload are entirely up to you and your use case. When you send an event, it's delivered to any App SDK instance subscribed to that event name. Events are buffered offline and flushed on reconnect.
API
send()
Publish a named event with a payload to RelayX.
- JavaScript
- Python
- C++
await device.event.send(name, data)| Parameter | Type | Description |
|---|---|---|
name | string | The event name |
data | any | The event payload (any serializable value) |
Returns true if sent, false if buffered (offline)
await device.event.send(name, data)| Parameter | Type | Description |
|---|---|---|
name | string | The event name |
data | any | The event payload (any serializable value) |
Returns true if sent, false if buffered (offline)
device->event.send_number(name, value) → relay_err_tdevice->event.send_string(name, value) → relay_err_tdevice->event.send_bool(name, value) → relay_err_tdevice->event.send_json(name, json_value) → relay_err_t| Parameter | Type | Description |
|---|---|---|
name | const char* | The event name |
value | double, const char*, bool | The value to send (type must match the method) |
json_value | const cJSON* | A cJSON object tree (for send_json) — caller owns and must free |
Returns RELAY_OK if sent, RELAY_ERR_BUFFERED if offline, RELAY_ERR_VALIDATION if the name contains invalid characters
Names can only contain letters, numbers, hyphens, and underscores (A-Z, a-z, 0-9, -, _).
Send an Event
- JavaScript
- Python
- C++
await device.event.send("door_opened", {
door: "front",
method: "keycard",
});
await device.event.send("boot_complete", {
firmware: "1.2.0",
bootTime: 3200,
});
await device.event.send("door_opened", {
"door": "front",
"method": "keycard",
})
await device.event.send("boot_complete", {
"firmware": "1.2.0",
"bootTime": 3200,
})
cJSON* door_event = cJSON_CreateObject();
cJSON_AddStringToObject(door_event, "door", "front");
cJSON_AddStringToObject(door_event, "method", "keycard");
device->event.send_json("door_opened", door_event);
cJSON_Delete(door_event);
cJSON* boot_event = cJSON_CreateObject();
cJSON_AddStringToObject(boot_event, "firmware", "1.2.0");
cJSON_AddNumberToObject(boot_event, "bootTime", 3200);
device->event.send_json("boot_complete", boot_event);
cJSON_Delete(boot_event);
Example Use Cases
Events are flexible — here are some common patterns:
- JavaScript
- Python
- C++
// geofence
if (crossedBoundary(lat, lng)) {
await device.event.send("geofence_entered", {
zone: "warehouse-A",
lat,
lng,
});
}
// user interaction
button.on("press", async () => {
await device.event.send("button_pressed", { button: "power" });
});
// error reporting
try {
await riskyOperation();
} catch (err) {
await device.event.send("error_detected", {
operation: "riskyOperation",
message: err.message,
});
}
# geofence
if crossed_boundary(lat, lng):
await device.event.send("geofence_entered", {
"zone": "warehouse-A",
"lat": lat,
"lng": lng,
})
# state change
if new_state != previous_state:
await device.event.send("state_changed", {
"from": previous_state,
"to": new_state,
})
# error reporting
try:
await risky_operation()
except Exception as err:
await device.event.send("error_detected", {
"operation": "risky_operation",
"message": str(err),
})
// geofence
if (crossed_boundary(lat, lng)) {
cJSON* ev = cJSON_CreateObject();
cJSON_AddStringToObject(ev, "zone", "warehouse-A");
cJSON_AddNumberToObject(ev, "lat", lat);
cJSON_AddNumberToObject(ev, "lng", lng);
device->event.send_json("geofence_entered", ev);
cJSON_Delete(ev);
}
// button press
device->event.send_string("button_pressed", "power");
// error reporting
device->event.send_string("error_detected", "sensor read failed");
Offline Buffering
When the device is disconnected, events are buffered in memory. Once the connection is restored, all buffered events are flushed in order.
- JavaScript
- Python
- C++
const sent = await device.event.send("door_opened", { door: "front" });
if (!sent) {
console.log("Device is offline — event buffered");
}
sent = await device.event.send("door_opened", {"door": "front"})
if not sent:
print("Device is offline — event buffered")
relay_err_t err = device->event.send_string("door_opened", "front");
if (err == RELAY_ERR_BUFFERED) {
ESP_LOGW("app", "Device is offline — event buffered");
}
Buffered events are stored in memory only. If the device process restarts while offline, buffered events are lost.