Skip to content

Instantly share code, notes, and snippets.

@garethky
Created May 4, 2022 04:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save garethky/8e7edd0c744da81e77facfa6528fe6a5 to your computer and use it in GitHub Desktop.
Save garethky/8e7edd0c744da81e77facfa6528fe6a5 to your computer and use it in GitHub Desktop.
Temporary load cell data capture and display Tool
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Graph Load Cell Data</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.2/dist/echarts.min.js"></script>
</head>
<body>
<h2>Moonraker Server:
<form id="serverForm">
<fieldset id="serverFormFields">
<input id="serverInput" type="text" placeholder="raspberrypi.local"/>
<input type="submit" value="Connect"/>
</fieldset>
</form>
</h2>
<h4>MCU Awake:<span id="mcuAwakeDisplay">--</span></h4>
<h4>MCU Load:<span id="mcuLoadDisplay">--</span></h4>
<div id="main-chart" style="height: 500px; width: 100%; margin: auto;"></div>
<p>Tip: press the space bar to pause data capture.</p>
<script>
const loadCellTopic = "load_cell/dump";
var chartDom = document.getElementById('main-chart');
var myChart = echarts.init(chartDom);
var pauseGraph = false;
var loadCellSamples = [];
var sampleAverageData = [];
var trendAverageData = [];
var trendDeadbanMin = [];
var trendDeadbanMax = [];
var dates = [];
let series = [
{
data: loadCellSamples,
name: 'Load Cell Raw Value',
type: 'line',
step: 'start',
showSymbol: false,
sampling: 'lttb',
zlevel: 1,
lineStyle: {
opacity: 0.75,
width: 1
},
},
{
name: 'Deadband Min',
type: 'line',
data: trendDeadbanMin,
lineStyle: {
opacity: 0
},
zlevel: 2,
stack: 'confidence-band',
symbol: 'none'
},
{
name: 'Deadband Max',
type: 'line',
data: trendDeadbanMax,
lineStyle: {
opacity: 0
},
areaStyle: {
color: '#ccc'
},
zlevel: 2,
stack: 'confidence-band',
symbol: 'none'
},
{
data: sampleAverageData,
name: 'Smoothed Sample Value',
type: 'line',
showSymbol: false,
sampling: 'lttb',
zlevel: 3,
lineStyle: {
width: 3
},
},
];
let xAxis = {
type: 'category',
data: dates
}
var option = {
xAxis: xAxis,
series: series,
yAxis: {
type: 'value',
},
animation: false,
dataZoom: [
{
type: 'slider',
show: true,
xAxisIndex: [0],
start: 80,
end: 100
},
]
};
option && myChart.setOption(option);
// Add event listener to pause data collection on spacebar
document.addEventListener('keydown', (event) => {
if (event.keyCode == 32) {
pauseGraph = !pauseGraph;
// Consume the event so it doesn't get handled twice
event.preventDefault();
}
}, false);
const mcuAwakeDisplay = document.getElementById("mcuAwakeDisplay");
const mcuLoadDisplay = document.getElementById("mcuLoadDisplay");
const serverInput = document.getElementById('serverInput');
const serverFormFields = document.getElementById('serverFormFields');
const serverForm = document.getElementById('serverForm');
async function oneshotToken(server) {
let token = fetch("http://" + server + "/access/oneshot_token");
return (await (await token).json()).result;
}
let id = Date.now();
function nextId() {
id += 1;
return id;
}
function subscribeObject(socket) {
const id = nextId();
let message = JSON.stringify({
"jsonrpc": "2.0",
"method": "printer.objects.subscribe",
"params": {
"objects": {
"load_cell_status": ["dump"],
"mcu": null
}
},
"id": id
}
);
return [id, socket.send(message)];
};
function addLoadCellData(data) {
if (pauseGraph) {
return;
}
let sampleGroups = data.dump;
sampleGroups.forEach(sample => {
let samples = sample.samples;
samples.forEach(sample => {
dates.push(new Date(sample[0]));
loadCellSamples.push(sample[1]);
sampleAverageData.push(sample[2]);
trendAverageData.push(sample[3]);
trendDeadbanMin.push(sample[3] - 500000)
trendDeadbanMax.push(500000 * 2)
});
});
while (dates.length > 28000) {
dates.shift();
loadCellSamples.shift();
sampleAverageData.shift();
trendAverageData.shift();
trendDeadbanMin.shift();
trendDeadbanMax.shift();
}
myChart.setOption({
xAxis: xAxis,
series: series
});
}
function updateMcuLoad(data) {
const STATS_INTERVAL = 5.0;
const TASK_MAX = 0.0025;
// this is awake ticks/frequency, so its a % of available clock cycles
let mcuAwake = ((data.last_stats.mcu_awake / STATS_INTERVAL) * 100.0).toFixed(2);
let mcuLoad = data.last_stats.mcu_task_avg + (3 * data.last_stats.mcu_task_stddev);
mcuLoad = (100.0 * mcuLoad / TASK_MAX).toFixed(2);
mcuAwakeDisplay.textContent = "" + (mcuAwake) + "%";
mcuLoadDisplay.textContent = "" + (mcuLoad) + "%";
}
function handleMessage(messageEvent) {
payload = JSON.parse(messageEvent.data);
if (payload && payload.method === "notify_proc_stat_update" && payload.params) {
} else if (payload.method === "notify_status_update") {
payload.params.forEach(param => {
if (param['mcu']) {
updateMcuLoad(param.mcu);
} else if (param['load_cell_status']) {
addLoadCellData(param.load_cell_status);
}
});
}
}
async function openSocket(server) {
let token = await oneshotToken(server)
if (!token) {
throw("oneshotToken error");
}
const socket_url = "ws://" + server + "/websocket?token=" + token;
const socket = new WebSocket(socket_url);
let opened, open = new Promise((resolve) => (opened = resolve));
// Callback of even listener used to resolve promise.
socket.addEventListener("open", (open) => {
opened();
});
await open;
return socket;
}
async function connect(event) {
event.preventDefault();
serverFormFields.disabled = true;
const server = serverInput.value;
let socket = await openSocket(server);
socket.addEventListener('message', event => handleMessage(event));
subscribeObject(socket);
}
serverForm.addEventListener('submit', connect);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment