I know you like uPlot but have you considered using pivottable library at GitHub - nicolaskruchten/pivottable: Open-source Javascript Pivot Table (aka Pivot Grid, Pivot Chart, Cross-Tab) implementation with drag'n'drop. ?
In my opinion it is more suitable for monitoring sensor data from network of devices with very little coding.It include tables and graphs in same package. And unlike other graphing software it is easy to render table or graph with drag and drop selectors. It could be standard widget for FlexDash so user do not need any other separate widget for graphor table. I use following code for my purpose:
<script type="text/javascript">
// This example loads sensor data from a ESP32 gateway which collect data from remote sensor devices and store it in a CSV file.
$(function(){
var renderers = $.extend(
$.pivotUtilities.renderers,
$.pivotUtilities.plotly_renderers,
$.pivotUtilities.d3_renderers,
$.pivotUtilities.export_renderers
);
Papa.parse("http://192.168.0.3/sensors.csv", {
download: true,
skipEmptyLines: true,
complete: function(parsed){
for (let i = 0; i < parsed.data.length; i ++) {
var d = new Date(parsed.data[i][0]*1000);
parsed.data[i][0] = (("00" + d.getFullYear()).slice(-2) + ("00" + (d.getMonth() + 1)).slice(-2) + ("00" +
d.getDate()).slice(-2) + ("00" + d.getHours()).slice(-2) + ("00" + d.getSeconds()).slice(-2));
parsed.data[0][0] = "Timestamp";
if (parsed.data[i][1] == 6) {
parsed.data[i][1] = "Livingroom";
} else if (parsed.data[i][1] == 16) {
parsed.data[i][1] = "Kitchen";
} else if (parsed.data[i][1] == 26) {
parsed.data[i][1] = "Bedroom1";
} else if (parsed.data[i][1] == 36) {
parsed.data[i][1] = "Bedroom2";
} else if (parsed.data[i][1] == 46) {
parsed.data[i][1] = "Bedroom3";
} else if (parsed.data[i][1] == 56) {
parsed.data[i][1] = "Bedroom4";
} else if (parsed.data[i][1] == 66) {
parsed.data[i][1] = "Bathroom1";
} else if (parsed.data[i][1] == 76) {
parsed.data[i][1] = "Bathroom2";
} else if (parsed.data[i][1] == 86) {
parsed.data[i][1] = "Bathroom3";
} else if (parsed.data[i][1] == 96) {
parsed.data[i][1] = "Bathroom4";
} else if (parsed.data[i][1] == 106) {
parsed.data[i][1] = "Laundry";
} else if (parsed.data[i][1] == 116) {
parsed.data[i][1] = "Boiler Room";
} else if (parsed.data[i][1] == 126) {
parsed.data[i][1] = "Workshop";
} else if (parsed.data[i][1] == 136) {
parsed.data[i][1] = "Garage";
} else if (parsed.data[i][1] == 146) {
parsed.data[i][1] = "Office";
} else if (parsed.data[i][1] == 156) {
parsed.data[i][1] = "Tank";
} else if (parsed.data[i][1] == 166) {
parsed.data[i][1] = "Solar";
} else {
parsed.data[i][1] = "Unknown";
parsed.data[0][1] = "Location";
}
//console.log(parsed.data[i][1]); // (13)arrays of values by sensor type
}
$("#output").pivotUI(parsed.data, {
rows: ["Location"], cols: ["Timestamp"],
aggregatorName: "List Unique Values",
vals: ["Temperature"],
rendererName: "Line Chart",
});
}
});
var dragging = function(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.originalEvent.dataTransfer.dropEffect = 'copy';
$("body").removeClass("whiteborder").addClass("greyborder");
};
var endDrag = function(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.originalEvent.dataTransfer.dropEffect = 'copy';
$("body").removeClass("greyborder").addClass("whiteborder");
};
var dropped = function(evt) {
evt.stopPropagation();
evt.preventDefault();
$("body").removeClass("greyborder").addClass("whiteborder");
parseAndPivot(evt.originalEvent.dataTransfer.files[0]);
};
$("html")
.on("dragover", dragging)
.on("dragend", endDrag)
.on("dragexit", endDrag)
.on("dragleave", endDrag)
.on("drop", dropped);
});
</script>
Content of sensors.csv file is as follows:
Timestamp,Location,Voltage,RSSI,Temperature,Humidity,Pressure,Light,Open/Close,Level,Presence,Motion,Custom
1621906615,26,6,-37,51,78,232,86,0,0,0,0,0
1621906647,6,6,-37,49,44,225,55,0,0,0,0,0
1621906678,6,146,-37,46,45,228,72,0,0,0,0,0
1621906691,26,6,-36,46,45,228,72,0,0,0,0,0
1621906723,6,146,-39,54,88,250,66,0,0,0,0,0
Dependencies are as follows:
Thanks.