Field Schema
Define what data your device sends and how the platform displays it. Fields control chart grouping, map rendering, and alert evaluation.
Field structure
Section titled “Field structure”Each field has a name, label, unit, and two optional properties:
| Property | Required | Description |
|---|---|---|
name | Yes | Lowercase letters, numbers, underscores (1-50 chars). The JSON key the device sends. |
label | Yes | Display name shown in charts and tables (max 100 chars). |
unit | No | Measurement unit (e.g., °C, %, g, m/km). Controls Y-axis labels and dual-axis grouping. |
role | No | Semantic hint: location, boolean, timestamp, or status. Controls display behavior. |
children | No | Array of child fields for nested JSON data. Max 10 children, 1 level deep. |
Flat fields
Section titled “Flat fields”The simplest configuration. Each field maps to a top-level JSON key.
Field config:
[ { "name": "temperature", "label": "Temperature", "unit": "°C" }, { "name": "humidity", "label": "Humidity", "unit": "%" }, { "name": "battery", "label": "Battery", "unit": "%" }]Device sends:
{ "temperature": 25.5, "humidity": 60, "battery": 87 }Nested fields with children
Section titled “Nested fields with children”Group related values by sending nested JSON objects. The parent field defines a group, and children are the individual values within it.
Field config:
[ { "name": "iri", "label": "Road Roughness", "unit": "m/km" }, { "name": "acc", "label": "Accelerometer", "unit": "g", "children": [ { "name": "x", "label": "X" }, { "name": "y", "label": "Y" }, { "name": "z", "label": "Z" } ]}, { "name": "gps", "label": "GPS", "role": "location", "children": [ { "name": "lat", "label": "Latitude" }, { "name": "lon", "label": "Longitude" } ]}]Device sends:
{ "iri": 3.45, "acc": { "x": 1.23, "y": 0.95, "z": 2.11 }, "gps": { "lat": -1.2867, "lon": 36.8172 }}What happens automatically:
- “Accelerometer” chart tab: X, Y, Z plotted together with a shared g-force Y-axis
- “Road Roughness” chart tab: IRI plotted on its own
- Map: GPS trail rendered from gps.lat/gps.lon
- GPS is excluded from line charts because of
role: "location"
Children inherit the parent’s unit unless they define their own.
Roles tell the platform how to display a field:
| Role | Chart behavior | Display |
|---|---|---|
| (none) | Line chart (default) | Numeric value |
location | Excluded from charts | Map with trail |
boolean | Excluded from charts | On/off badge |
timestamp | Excluded from charts | Formatted date/time |
status | Excluded from charts | Status badge |
Location role
Section titled “Location role”Fields with role: "location" and children containing lat/lon (or latitude/longitude) are automatically detected and displayed on the map:
{ "name": "gps", "label": "GPS", "role": "location", "children": [ { "name": "lat", "label": "Latitude" }, { "name": "lon", "label": "Longitude" }, { "name": "alt", "label": "Altitude", "unit": "m" }]}Altitude (and any other children) will be charted normally. Only the lat/lon pair goes to the map.
Boolean role
Section titled “Boolean role”Fields with role: "boolean" display as on/off badges in the latest reading panel instead of numeric values:
{ "name": "online", "label": "Online", "role": "boolean" }Complex example: environmental station
Section titled “Complex example: environmental station”[ { "name": "env", "label": "Environment", "children": [ { "name": "temp", "label": "Temperature", "unit": "°C" }, { "name": "humidity", "label": "Humidity", "unit": "%" }, { "name": "pressure", "label": "Pressure", "unit": "hPa" } ]}, { "name": "power", "label": "Power", "children": [ { "name": "voltage", "label": "Voltage", "unit": "V" }, { "name": "current", "label": "Current", "unit": "A" } ]}, { "name": "gps", "label": "Location", "role": "location", "children": [ { "name": "lat", "label": "Latitude" }, { "name": "lon", "label": "Longitude" } ]}, { "name": "battery", "label": "Battery", "unit": "%" }, { "name": "online", "label": "Online", "role": "boolean" }]Auto-generated chart tabs:
- Environment: temp, humidity, pressure (dual Y-axis by unit)
- Power: voltage, current
- Other: battery
- Map section: GPS trail
- Latest reading: battery as number, online as on/off badge
Alerts on nested fields
Section titled “Alerts on nested fields”When creating alerts or automation rules, nested fields appear as dot-notation paths. For example, to alert when accelerometer X exceeds 2.5g:
- Field:
acc.x - Operator: greater than
- Value:
2.5
Commands (subscribe side)
Section titled “Commands (subscribe side)”Commands define what the platform can send to your device. The device subscribes to d/{device_id}/c via MQTT to receive them.
Command types:
| Type | Description | Example |
|---|---|---|
toggle | On/off switch | LED control |
button | One-shot action | Reboot device |
slider | Numeric range | Fan speed (0-100) |
json | Arbitrary JSON payload | Configuration update |
Commands are configured separately from telemetry fields in the device settings.
What happens with unexpected data
Section titled “What happens with unexpected data”The platform handles various edge cases gracefully:
| Scenario | What happens |
|---|---|
| Extra top-level field | Silently dropped. Only defined fields are stored. |
| Extra child field | Silently dropped. e.g., sending acc.w when only acc.x/y/z are defined. |
| Missing fields | Accepted. Missing fields show as gaps in charts, not errors. |
| Missing child fields | Accepted. e.g., sending only acc.x when x/y/z are defined. |
| Wrong type (number where object expected) | Stored as-is. e.g., sending "acc": 2.5 instead of "acc": {"x": 1.2}. |
| Completely different payload | All fields dropped (none match). Empty data stored. |
You can safely send partial data: only the fields you include are stored. This is useful for devices that don’t always have every sensor reading available.
Location on the map
Section titled “Location on the map”Fields with role: "location" and lat/lon children automatically render as an interactive map with a trail of points. The map:
- Auto-fits to show all points when data loads or the time range changes
- Shows a marker at the latest position with coordinates and timestamp
- Supports fullscreen mode (press Esc to exit)
- Updates in real-time when new data arrives
Configuring fields
Section titled “Configuring fields”Auto-detect from first data
Section titled “Auto-detect from first data”If your device has no fields configured and sends its first data point, the platform automatically infers the schema:
- Nested objects become parent fields with children
- Boolean values get
role: "boolean" - Lat/lon children in an object get
role: "location" - Labels and units are guessed from field names (e.g.,
tempgets°C) - The inferred schema is saved to your device settings
If the payload has more fields than your plan allows, the request is rejected with a clear message explaining the limit.
After auto-detection, review the inferred schema in your device settings and adjust labels, units, or roles as needed.
Configuring fields
Section titled “Configuring fields”You can configure fields in several ways:
Device settings UI
Section titled “Device settings UI”The field editor in your device’s settings tab provides these tools:
| Tool | Description |
|---|---|
| Add | Add a new field row |
| Add Children (sitemap icon) | Add child fields for nested data |
| Role dropdown | Set field role (location, boolean, timestamp, status) |
| JSON Import | Paste or upload a JSON field configuration |
| Copy | Copy current fields as JSON to clipboard |
| Export | Download current fields as a JSON file |
| Clear | Remove all fields |
| Browse file | Upload a JSON file with field definitions |
| Validate | Check your JSON for errors before importing |
JSON import
Section titled “JSON import”Click the JSON import button and paste your field configuration array. The importer validates names, labels, roles, and children before applying. It also supports uploading a .json file.
Set settings.fields when creating or updating a device via the API.
Payload limits
Section titled “Payload limits”| Limit | Value |
|---|---|
| Maximum payload size | 10 KB |
| Maximum nesting depth | 2 levels |
| Maximum top-level fields | 50 |
| Maximum children per parent | 10 |
| Total fields (including children) | Per plan limit |
Data interval and rate limiting
Section titled “Data interval and rate limiting”Each device has a configurable data interval (default: 10 seconds). The platform enforces this as a rate limit: if your device sends data faster than its configured interval, the extra requests are rejected with a 429 (Rate Limit Exceeded) response.
Set the interval when creating the device. If you need to change it later, go to your device’s Settings tab and edit the Data Interval in the Configuration section.
For testing, use a short interval (e.g., 10 seconds). For production, match your sensor’s actual sampling rate.