Step 5: Publish telemetry
Create device/main/sensor_task.cpp with the read loop:
#include "sensor_task.h"
#include "app_shared.h"
#include "ina219.h"
#include <cmath>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
static const char *TAG = "sensor-task";
static i2c_master_dev_handle_t s_ina219 = nullptr;
static void sensor_task(void *) {
// I2C + INA219 init elided — see reference repo
xEventGroupWaitBits(g_state_events, DEVICE_READY_BIT,
pdFALSE, pdTRUE, portMAX_DELAY);
while (true) {
ina219_readings r;
if (ina219_read(s_ina219, &r) == ESP_OK) {
ESP_LOGI(TAG, "V=%.3fV I=%.2fmA P=%.2fmW",
r.bus_voltage_v, std::fabs(r.current_ma), r.power_mw);
g_device->telemetry.publish_number(TELEMETRY_POWER, r.power_mw);
g_device->telemetry.publish_number(TELEMETRY_CURRENT,
std::fabs(r.current_ma));
g_device->telemetry.publish_number(TELEMETRY_VOLT,
r.bus_voltage_v);
}
uint32_t rate_ms = g_sample_rate_ms.load();
vTaskDelay(pdMS_TO_TICKS(rate_ms));
}
}
void sensor_task_start() {
xTaskCreate(sensor_task, "sensor_task", 4096, nullptr, 4, nullptr);
}
The task waits on DEVICE_READY_BIT before it publishes anything. After that, the SDK buffers publishes across reconnects, so no reconnect logic is required. The sample rate comes from g_sample_rate_ms, which Step 7 updates at runtime.
The three metric names (power, current, volt) must match what you registered on the RelayX console for the device schema.
Start the task from main.cpp, right after device_task_start():
device_task_start();
sensor_task_start();
Test it
Reflash and watch the serial log. You should see a reading every 10 seconds:
I (12422) sensor-task: V=0.012V I=0.00mA P=0.00mW
I (22430) sensor-task: V=0.014V I=0.00mA P=0.00mW
Values are near zero because the relay is open. The dashboard will close the loop in the dashboard track.