Created
May 4, 2022 04:27
-
-
Save garethky/8e7edd0c744da81e77facfa6528fe6a5 to your computer and use it in GitHub Desktop.
Temporary load cell data capture and display Tool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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