16#if DETWS_ENABLE_DASHBOARD
28 const DetwsWidget *widgets =
nullptr;
31 DetwsControlCb control_cb =
nullptr;
33static DashboardCtx s_dash;
35static const char *widget_type_name(DetwsWidgetType t)
39 case DetwsWidgetType::DETWS_WIDGET_GAUGE:
41 case DetwsWidgetType::DETWS_WIDGET_BAR:
43 case DetwsWidgetType::DETWS_WIDGET_SPARKLINE:
45 case DetwsWidgetType::DETWS_WIDGET_CHART:
47 case DetwsWidgetType::DETWS_WIDGET_BUTTON:
49 case DetwsWidgetType::DETWS_WIDGET_TOGGLE:
51 case DetwsWidgetType::DETWS_WIDGET_SLIDER:
60static int json_append(
char *out,
size_t cap,
size_t *pos,
const char *fmt, ...)
66 int w = vsnprintf(out + *pos, cap - *pos, fmt, ap);
68 if (w < 0 || (
size_t)w >= cap - *pos)
74void detws_dashboard_configure(
const DetwsWidget *widgets, uint8_t count)
76 s_dash.widgets = widgets;
79 s_dash.values[i] = 0.0f;
82bool detws_dashboard_set(
const char *key,
float value)
84 if (!key || !s_dash.widgets)
86 for (uint8_t i = 0; i < s_dash.count; i++)
88 if (s_dash.widgets[i].key && strcmp(s_dash.widgets[i].key, key) == 0)
90 s_dash.values[i] = value;
97int detws_dashboard_layout_json(
char *out,
size_t cap)
105 if (json_append(out, cap, &pos,
"[") != 0)
107 for (uint8_t i = 0; i < s_dash.count; i++)
109 const DetwsWidget *w = &s_dash.widgets[i];
110 if (json_append(out, cap, &pos,
111 "%s{\"type\":\"%s\",\"label\":\"%s\",\"key\":\"%s\",\"min\":%g,\"max\":%g,\"unit\":\"%s\"}",
112 i ?
"," :
"", widget_type_name(w->type), w->label ? w->label :
"", w->key ? w->key :
"",
113 (double)w->min, (double)w->max, w->unit ? w->unit :
"") != 0)
116 if (json_append(out, cap, &pos,
"]") != 0)
121int detws_dashboard_values_json(
char *out,
size_t cap)
123 if (!out || cap == 0)
129 if (json_append(out, cap, &pos,
"{") != 0)
131 for (uint8_t i = 0; i < s_dash.count; i++)
133 if (json_append(out, cap, &pos,
"%s\"%s\":%g", i ?
"," :
"", s_dash.widgets[i].key ? s_dash.widgets[i].key :
"",
134 (double)s_dash.values[i]) != 0)
137 if (json_append(out, cap, &pos,
"}") != 0)
146void detws_dashboard_on_control(DetwsControlCb cb)
148 s_dash.control_cb = cb;
154static const char *control_value_ptr(
const char *s,
const char *key)
157 snprintf(pat,
sizeof(pat),
"\"%s\"", key);
158 const char *p = strstr(s, pat);
161 p += strnlen(pat,
sizeof(pat));
162 while (*p ==
' ' || *p ==
'\t')
167 while (*p ==
' ' || *p ==
'\t')
172bool detws_dashboard_parse_control(
const char *msg,
char *key_out,
size_t key_cap,
float *value_out)
174 if (!msg || !key_out || key_cap == 0 || !value_out)
177 const char *kp = control_value_ptr(msg,
"k");
178 const char *vp = control_value_ptr(msg,
"v");
179 if (!kp || !vp || *kp !=
'"')
183 while (*kp && *kp !=
'"' && i + 1 < key_cap)
184 key_out[i++] = *kp++;
191 const char *end =
nullptr;
199bool detws_dashboard_dispatch_control(
const char *msg)
203 if (!detws_dashboard_parse_control(msg, key,
sizeof(key), &value))
205 if (s_dash.control_cb)
206 s_dash.control_cb(key, value);
207 return s_dash.control_cb !=
nullptr;
#define DETWS_DASHBOARD_MAX_WIDGETS
Maximum widgets in the dashboard table (BSS value array).
Real-time SVG telemetry dashboard (DETWS_ENABLE_DASHBOARD).
Tiny no-stdlib base-10 number parsers (strtol/strtoul/strtof replacements).
float det_strtof(const char *s, const char **end)
Parse a float (integer[.frac][e[+/-]exp]); sets end (or to s if none).