> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hyperwisor.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ESP-IDF — Examples

> A real-world ESP-IDF integration — command handlers, responses, and pushing sensor values to widgets.

These patterns come from a **production ESP-IDF project** — a Waveshare
ESP32-S3 touch HMI with cloud control, Modbus, HVAC, and a BMP280 sensor. They
show the Hyperwisor component used the way you'd use it in a real product.

<Card title="Reference project" icon="github" href="https://github.com/nikolaindustry/hmi_waveshare_7">
  hmi\_waveshare\_7 — the full source these examples are drawn from.
</Card>

## The shape of an integration

1. **Register command handlers** for the commands your dashboard sends.
2. **Push sensor values** to dashboard widgets by their widget ID.
3. **Respond** to commands so the UI can confirm.

```c theme={null}
#include "hyperwisor.h"   /* umbrella: core + ws + cmd + widget + nvs */

void app_main(void)
{
    hyperwisor_set_port(&board_port_s3);     /* optional board port */
    hyperwisor_init();

    hyperwisor_register_cmd_handler("relay_control", handle_relay_control);
    hyperwisor_register_cmd_handler("hvac_control",  handle_hvac_control);
    hyperwisor_register_cmd_handler("get_status",    handle_get_status);
    hyperwisor_register_cmd_handler("rgb_control",   handle_rgb_control);

    hyperwisor_start();
}
```

## Handling a command and responding

```c theme={null}
static void handle_relay_control(const char *from, cJSON *payload)
{
    /* navigate payload → command → action → params, then act */
    bool on = /* read from params */;
    gpio_set_level(RELAY_GPIO, on);

    cJSON *resp = cJSON_CreateObject();
    cJSON_AddStringToObject(resp, "status", "ok");
    hyperwisor_emit(from, "relay_control", "response", resp);   /* confirm to the UI */
    cJSON_Delete(resp);
}
```

## Pushing sensor values to widgets

Push readings to the widget IDs your dashboard uses (here a Gauge `w_temp` and a
Label `w_hpa`):

```c theme={null}
void app_push_bmp280(const char *target_id, float temp_c, float pressure_hpa)
{
    if (!hyperwisor_ws_is_connected()) return;
    hyperwisor_update_widget_float(target_id, "w_temp", temp_c);
    hyperwisor_update_widget_float(target_id, "w_hpa",  pressure_hpa);
}
```

Call it from your sensor task on a timer — the gauges move live.

## Reading a color-picker command

The dashboard [Color Picker](/dashboard/widgets/color-picker) auto-injects
`rgb:{ r, g, b }` (and `hex`, `hsl`, …). Pull the channels out of the params:

```c theme={null}
static void handle_rgb_control(const char *from, cJSON *payload)
{
    cJSON *params = /* … → params */;
    cJSON *rgb = cJSON_GetObjectItem(params, "rgb");
    int r = cJSON_GetObjectItem(rgb, "r")->valueint;
    int g = cJSON_GetObjectItem(rgb, "g")->valueint;
    int b = cJSON_GetObjectItem(rgb, "b")->valueint;
    led_set_rgb(r, g, b);
}
```

## Configurable widget bindings

A common pattern from the reference project: don't hardcode widget IDs — let the
dashboard send them via a `config` command and store them in NVS. Then your
`update_widget_*` calls use the stored IDs, so the same firmware works with any
dashboard layout.

<Note>
  This mirrors the Arduino library's model — see the
  [Arduino examples](/firmware/arduino/examples) for the same patterns in C++.
</Note>

<CardGroup cols={2}>
  <Card title="API reference" icon="book" href="/firmware/esp-idf/api-reference">
    Every function these examples use.
  </Card>

  <Card title="Configuration" icon="sliders" href="/firmware/esp-idf/configuration">
    Kconfig toggles and the board port.
  </Card>
</CardGroup>
