Skip to main content
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.

Reference project

hmi_waveshare_7 — the full source these examples are drawn from.

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.
#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

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):
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 auto-injects rgb:{ r, g, b } (and hex, hsl, …). Pull the channels out of the params:
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.
This mirrors the Arduino library’s model — see the Arduino examples for the same patterns in C++.

API reference

Every function these examples use.

Configuration

Kconfig toggles and the board port.