Time series data
Time series turns a parameter into a history: every value change is published as a timestamped data point, and the cloud stores and aggregates it so an app can draw a graph or answer "how much energy did this use last week".
There is no API to call. It is a property flag on the parameter.
Enabling it
/* A sensor reading — one value per sample */
esp_rmaker_param_t *temp = esp_rmaker_param_create("Temperature",
ESP_RMAKER_PARAM_TEMPERATURE,
esp_rmaker_float(25.0),
PROP_FLAG_READ | PROP_FLAG_TIME_SERIES);
/* An energy meter — monotonically increasing */
esp_rmaker_param_t *energy = esp_rmaker_param_create("Energy",
"acme.param.energy",
esp_rmaker_float(0.0),
PROP_FLAG_READ | PROP_FLAG_TS_CUMULATIVE);
From then on, every esp_rmaker_param_update() that actually changes the value queues a data point.
Simple vs cumulative
| Flag | Use for | Cloud treats it as |
|---|---|---|
PROP_FLAG_TIME_SERIES | Instantaneous readings — temperature, humidity, power draw | Independent samples; averages, min/max, and latest are meaningful |
PROP_FLAG_TS_CUMULATIVE | Monotonically increasing counters — energy consumed, run hours, litres dispensed | A running total; the cloud can difference consecutive points to get consumption per period |
Pick correctly. A cumulative counter reported as simple time series gives you a meaningless "average total", and an instantaneous reading reported as cumulative produces nonsense deltas whenever it goes down.
Set exactly one of the two flags on a given parameter.
What gets published
Each data point is a compact JSON object:
{
"k": "Light.Power",
"dt": "bool",
"v": true,
"t": 1769000000000,
"tz": "America/New_York",
"cumulative": false
}
| Field | Meaning |
|---|---|
k | Path: "<device_id>.<param_id>" |
dt | "int", "float", "bool", or "string" |
v | The value |
t | Unix timestamp in milliseconds, UTC, int64 |
tz | IANA timezone at the time of the sample |
cumulative | Present and true for PROP_FLAG_TS_CUMULATIVE |
The path separator is ., so device and parameter IDs must not contain a dot. A parameter called Temp.Out produces an unparseable path. This constraint is easy to violate and hard to notice.
Data points are queued and published at a throttled rate on the state-reporting flow, at QoS 1. Several points are batched into one MQTT message where possible.
Timestamps need a clock
The t field is the node's wall clock at the moment of the update. That means:
- Time sync is mandatory. Points generated before the first successful sync are deferred or dropped, depending on the startup flow. See Time and timezone.
- The timezone is captured per sample. If a user changes the timezone, existing points keep the timezone they were recorded with.
If your graphs are empty or start at 1970, check local-time on the serial console first.
Throughput and the queue
The queue is the thing to size, because when it is full new data points are silently dropped.
| Option | Default | Notes |
|---|---|---|
CONFIG_RMAKER_TIMESERIES_DATA_QUEUE_LENGTH | 100 | Data points held in the queue; ~24 bytes each |
CONFIG_RMAKER_TIMESERIES_PUBLISH_INITIAL_DELAY_MS | 100 | Minimum gap between publishes; range 10–1000 |
CONFIG_RMAKER_TIMESERIES_PUBLISH_MAX_DELAY_MS | 300000 | Ceiling for the exponential backoff after a failed publish |
Raise the queue length if either applies:
- You generate points faster than the publish delay drains them.
- Your network is unreliable, so backoff can stretch to five minutes and a lot of points accumulate.
100 points at the default 100 ms delay covers about ten seconds of continuous drain — comfortable for a sensor sampling every few seconds, tight for anything reporting at 10 Hz.
With CONFIG_ESP_RMAKER_MQTT_ENABLE_BUDGETING=y (the default), an exhausted budget drops timeseries publishes. A chatty timeseries parameter can starve your state reports, and vice versa. Budget is 100 by default, reviving 1 message every 5 seconds — so sustained reporting above roughly one message per five seconds will eventually hit the limit. See Configure and build.
Choosing what to record
Every timeseries parameter costs MQTT messages on the device and storage plus query cost in the cloud. Two habits keep that under control:
- Report on meaningful change, not on every sample. Apply a deadband in your driver — a temperature that wobbles by 0.05 °C does not need a data point.
esp_rmaker_param_update()already suppresses updates to the identical value, but it does not know your noise floor. - Don't flag control parameters.
PowerandBrightnessare already in the shadow with their current value; a history of them is rarely worth the traffic.
Reading it back
Firmware does not read time series. Queries — raw, latest, and aggregates by hour/day/week/month — are cloud-side APIs used by apps and dashboards. See Cloud specifications → Timeseries and the Platform API reference.
Related
- Firmware specifications → Timeseries Data Collection — topic, payload, and publishing behaviour
- Data model → Property flags
- Time and timezone
- Product overview → Time series