NOTES¶
Overview¶
The online sensing module provides continuous sensor data acquisition and transmission functionality. It enables real-time monitoring of sensor data with configurable sampling frequency and multiple output channels (MQTT, serial, and optionally LCD).
Features¶
- ✅ Configurable sampling frequency (default: 1.0 Hz, range: 0.1 - 300 Hz, practical limit: ~200 Hz)
- ✅ MQTT transmission (enabled/disabled)
- ✅ Serial output (enabled/disabled)
- ✅ Optional LCD display (when
TINY_MEASUREMENT_ENABLE_LCDis defined) - ✅ Fixed-rate data acquisition using ESP timer
- ✅ Automatic data formatting
- ✅ Thread-safe operation
- ✅ Runtime configuration updates
Architecture¶
Timer-Based Sampling¶
The module uses ESP timer for precise periodic sampling:
- Timer Creation: Creates a periodic timer with period = 1 / sampling_frequency
- Timer Callback: Executes at each timer tick to read sensor data
- Data Output: Formats and outputs data to configured channels (MQTT, serial, LCD)
Data Flow¶
ESP Timer → Timer Callback → Sensor Read → Data Formatting → Output Channels
├─ MQTT
├─ Serial
└─ LCD (optional)
Implementation Principles¶
Architecture Overview¶
The online sensing module implements a timer-driven, event-based architecture using ESP-IDF's high-precision timer system. The design prioritizes real-time data streaming with minimal latency.
Core Components¶
-
ESP Timer (esp_timer)
- High-precision hardware timer with microsecond accuracy
- Periodic timer mode: triggers callback at fixed intervals
- Timer period:
period_us = 1,000,000 / sampling_frequency_hz - Timer callback executes in timer context (high priority, interrupt-like)
-
Timer Callback Function
- Executes synchronously at each timer tick
- Performs sensor read operations (non-blocking SPI)
- Formats data immediately (string formatting)
- Publishes to output channels (MQTT, serial, LCD)
- Minimal processing time to avoid missing timer ticks
-
Output Channels
- MQTT: Non-blocking publish via
esp_mqtt_client_publish()(QoS 0) - Serial: Blocking
printf()with immediatefflush() - LCD: Synchronous display update (may affect timing at high frequencies)
- MQTT: Non-blocking publish via
Programming Tools & APIs¶
-
ESP-IDF Timer API:
esp_timer_create(),esp_timer_start_periodic() -
ESP-IDF MQTT Client:
esp_mqtt_client_publish()for network transmission -
Standard C I/O:
printf(),snprintf()for data formatting -
FreeRTOS: State management and thread safety (no explicit tasks needed)
Execution Flow¶
- Initialization: Create periodic timer with calculated period
- Start: Execute immediate first sample, then start periodic timer
- Runtime: Timer callback fires at fixed intervals
- Read sensor (SPI communication)
- Format data (string conversion)
- Output to enabled channels (non-blocking where possible)
- Stop: Delete timer, cleanup resources
Key Design Decisions¶
- Immediate First Sample: Ensures data collection starts at t=0
- Non-blocking MQTT: Prevents timer callback from blocking on network operations
- Minimal Callback Processing: Keeps callback execution time short to maintain timing accuracy
- State Flag Protection: Uses
s_is_runningflag to prevent callback execution after stop
Configuration¶
Default Configuration¶
Default values are defined in tiny_measurement_config.h:
#define TINY_MEASUREMENT_ONLINE_SENSING_DEFAULT_FREQ_HZ 1.0f
#define TINY_MEASUREMENT_ONLINE_SENSING_DEFAULT_ENABLE_MQTT true
#define TINY_MEASUREMENT_ONLINE_SENSING_DEFAULT_ENABLE_SERIAL true
Configuration Structure¶
typedef struct
{
float sampling_frequency_hz; // Sampling frequency in Hz
bool enable_mqtt; // Enable MQTT transmission
bool enable_serial; // Enable serial output
bool enable_lcd; // Enable LCD display (optional)
const char *mqtt_topic; // MQTT topic (NULL for default)
} online_sensing_config_t;
Data Format¶
MQTT Format¶
Compact format with 6 decimal places for full 20-bit precision:
Example:
Serial Format¶
Same format as MQTT, with newline:
LCD Format¶
One axis per line:
-
Line 1:
X:0.012345 -
Line 2:
Y:-0.045678 -
Line 3:
Z:0.987654 -
Line 4:
T:25.50C
Usage Workflow¶
- Initialize Sensor: Initialize ADXL355 sensor
- Set Sensor Handle: Call
online_sensing_set_sensor_handle() - Initialize Module: Call
online_sensing_init()with configuration (or NULL for defaults) - Start Sensing: Call
online_sensing_start() - Runtime Updates: Optionally update frequency or enable/disable channels
- Stop Sensing: Call
online_sensing_stop()when done - Deinitialize: Call
online_sensing_deinit()to clean up
Performance Considerations¶
Sampling Frequency Limits¶
- Minimum: 0.1 Hz (10 second period)
- Maximum: 300 Hz (3333 microsecond period) - Code-level limit
- Practical Maximum: ~200 Hz - Measured upper limit in actual hardware testing
- Recommended: 1 - 200 Hz for most applications
Practical Limitation
While the code accepts frequencies up to 300 Hz, actual hardware testing shows that stable operation is limited to approximately 200 Hz. This limitation is primarily due to MQTT transmission constraints. At higher frequencies, MQTT publishing cannot keep up with the data generation rate, leading to buffer overflows, message queue saturation, and potential data loss. For reliable operation, especially when MQTT transmission is enabled, keep sampling frequency at or below 200 Hz.
Resource Usage¶
- CPU: Timer callback executes at sampling frequency
- Memory: Minimal stack usage in callback
- Network: MQTT bandwidth depends on frequency and payload size. MQTT transmission is the primary bottleneck limiting the practical maximum sampling rate to ~200 Hz. At higher frequencies, MQTT publish operations cannot complete fast enough, causing message queue buildup and potential data loss.
- Serial: High frequencies may cause serial buffer overflow
Improving Sampling Frequency
To achieve higher sampling frequencies, consider disabling unnecessary output channels:
- Disable Serial Output: Serial printing (
printf()) is blocking and can significantly slow down the timer callback, especially at high frequencies (>100 Hz) - Disable LCD Display: LCD updates are synchronous and relatively slow, making them unsuitable for frequencies above 10 Hz
- Keep Only MQTT: If network transmission is required, keep only MQTT enabled and disable serial/LCD outputs
By disabling serial and LCD outputs, you can reduce the timer callback execution time and potentially achieve higher stable sampling rates.
Optimization Tips¶
- Disable Serial Output: For high frequencies (>100 Hz), disable serial output
- MQTT QoS: Use QoS 0 for high-frequency data (default)
- LCD Update: LCD updates are relatively slow, use only for low frequencies (<10 Hz)
- Stay Within Practical Limits: Keep sampling frequency at or below 200 Hz for stable operation, especially when MQTT is enabled. The 200 Hz limit is primarily due to MQTT transmission bandwidth constraints.
- Code-Level Limit: The code enforces a maximum of 300 Hz, but practical testing shows ~200 Hz is the reliable limit
Error Handling¶
Common Errors¶
ESP_ERR_INVALID_ARG: Invalid frequency (out of range: 0.1 - 300 Hz)ESP_ERR_INVALID_STATE: Already running or not initializedESP_FAIL: Timer creation or start failed
Error Recovery¶
- Check sensor handle is set before starting
- Validate frequency range before initialization
- Stop before restarting with new configuration
Thread Safety¶
- Timer callback is executed in timer context (high priority)
- Configuration changes require stopping and restarting
- State checks prevent concurrent operations
Integration Notes¶
MQTT Integration¶
- Requires MQTT client to be connected
- Checks
s_is_mqtt_connectedbefore publishing - Uses default topic if
mqtt_topicis NULL
Sensor Integration¶
- Requires ADXL355 sensor handle
- Must be initialized before setting handle
- Sensor read operations are non-blocking
LCD Integration¶
- Only available when
TINY_MEASUREMENT_ENABLE_LCDis defined - LCD screen is cleared when starting
- Updates are synchronous (may affect timing at high frequencies)