RisalDash RisalDash

Документация

Documentation

Quick start

Arduino IDE: Library Manager → RisalDash. PlatformIO:

; platformio.ini
lib_deps =
    RisalDash
    ESP Async WebServer
    AsyncTCP            ; ESP32

A minimal sketch — five widgets, an access point, live over WebSocket:

#include <RisalUI.h>

RisalUI dash("Greenhouse");
float temp, volts; bool pump = false;

void setup() {
  dash.gauge ("Voltage", &volts, 0, 14, "V");
  dash.chart ("Temp", &temp, "°C").history(30);
  dash.toggle("Pump", &pump, [](bool on){ digitalWrite(PUMP_PIN, on); });
  dash.beginAP("Greenhouse", "12345678");   // access point
}

void loop() {
  temp = readTemp(); volts = readVolts();
  dash.update();   // pushes changes over WebSocket
}

Open http://192.168.4.1/ after joining the AP. No front-end code, no HTML files.

Core concepts

Zero-Waste UI

The linker (--gc-sections) strips the code of widgets you never instantiate. CSS/JS for a widget reaches flash only if its class is used. Empty core is < 8 KB flash / < 2 KB RAM; a new widget costs ~200–400 bytes.

Offline-first

Everything is served from the device — system fonts, zero external requests. The dashboard renders with no internet, which is the normal state on first boot.

WebSocket protocol

The device pushes only changed values as compact JSON ({ "Temp": 24.3 }); the client sends commands in the same shape. dash.update() diffs and pushes.

Widgets & sensors

30+ chainable widgets across display, control and layout — see the full catalog. A widget binds to a variable by pointer and configures via chaining:

dash.metric("CPU", &cpu, "%").zone(70, 90);

Sensors are a composition of quantities — presets expand to the right widgets automatically:

// One line drops the right widgets, units, ranges and icon:
dash.sensor("bme280", &t, &h, &p);   // gauge + metric + chart

// Tune the template: a trend chart per quantity, or bigger readouts.
dash.sensor("ina219", &v, &i, &w).chart();
dash.sensor("ld2410", &pr, &d, &m).size(RSIZE_L);

First boot & Wi-Fi

On first power-up the client has no internet. beginAP() raises a SoftAP with a captive portal (catch-all DNS + OS probes) that auto-opens the dashboard. A provisioning page scans networks, takes credentials, stores them in NVS, then switches to station mode — falling back to AP if the connection fails.

Languages & RTL

EN / RU / UZ / AR ship in the library. The device serves all four at runtime; users switch live in the appbar Settings (the choice sticks per browser). Your own widget titles follow via dash.translate():

dash.lang("ru");   // default UI language: en · ru · uz · ar (ar → RTL)
// users switch live in the appbar Settings; the choice sticks per browser.

// translate the strings YOU write — widget titles, page names, options:
dash.translate([](const char *s, const char *l) {
  if (!strcmp(l, "ru") && !strcmp(s, "Temperature")) return "Температура";
  return s;   // fall back to the original for anything unmapped
});

Arabic gets full RTL via logical CSS properties. On a mono LCD panel the stock font is Latin-only, so the screen shows en / uz natively and falls back to English for ru / ar — while the web dashboard serves all four.

AI control (MCP)

Each widget automatically becomes an MCP tool, so Claude/Cursor can read sensors and flip relays by voice — same actions as the browser buttons, just driven by AI.

dash.enableMCP("risal_pat_xxx");
// metric/gauge -> get_*  (read) ; toggle/slider -> set_*  (write)

A real exchange — read a value, decide, act, all through the same tools:

You
Is the greenhouse too warm? If so, turn on the fan.
Claude
Air temp reads 28.4 °C — above your 24 °C target, so I've switched the Fan on. It'll pull the temperature back down.
get_AirTemp → 28.4 · set_Fan(true)