|
|
@@ -6,6 +6,10 @@
|
|
|
//const socket = io(); // declared in main.js
|
|
|
let workpiece_color = "";
|
|
|
|
|
|
+// CHARTS
|
|
|
+const stations = ['dsi', 'dso', 'vgr', 'hbw', 'mpo', 'sld'];
|
|
|
+const charts = {};
|
|
|
+
|
|
|
// MQTT message filter
|
|
|
const excludedTopics = ['i/cam', 'o/broadcast'];
|
|
|
let allTopics = new Set(); // Tracks all seen topics
|
|
|
@@ -16,6 +20,57 @@ const selectAllBtn = document.getElementById('selectAll');
|
|
|
const deselectAllBtn = document.getElementById('selectNone');
|
|
|
const messageList = document.getElementById('mqtt-messages');
|
|
|
|
|
|
+// Draw initial charts
|
|
|
+stations.forEach(station => {
|
|
|
+ if (document.getElementById(`chart-${station}`) === null) return; // Skip if canvas not found
|
|
|
+ const ctx = document.getElementById(`chart-${station}`).getContext('2d');
|
|
|
+
|
|
|
+ charts[station] = new Chart(ctx, {
|
|
|
+ type: 'line',
|
|
|
+ data: {
|
|
|
+ datasets: [
|
|
|
+ {
|
|
|
+ label: 'Real',
|
|
|
+ data: [],
|
|
|
+ borderColor: '#0266ff',
|
|
|
+ stepped: true,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: 'Sim',
|
|
|
+ data: [],
|
|
|
+ borderColor: '#fa33d7',
|
|
|
+ stepped: true,
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ options: {
|
|
|
+ responsive: true,
|
|
|
+ scales: {
|
|
|
+ x: {
|
|
|
+ type: 'time',
|
|
|
+ time: {
|
|
|
+ tooltipFormat: 'HH:mm:ss.SSS', // hover format
|
|
|
+ displayFormats: { second: 'HH:mm:ss' } // tick labels
|
|
|
+ },
|
|
|
+ ticks: {autoSkip: true}
|
|
|
+ },
|
|
|
+ y: {
|
|
|
+ min: 0,
|
|
|
+ max: 1.1,
|
|
|
+ ticks: {
|
|
|
+ stepSize: 0.1,
|
|
|
+ callback: function(value, index, ticks){
|
|
|
+ if (value === 0) return 'Inactive';
|
|
|
+ if (value === 1) return 'Active';
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
// Format timestamp as hh:mm:ss.mmm
|
|
|
function formatTimestamp() {
|
|
|
const now = new Date();
|
|
|
@@ -56,17 +111,21 @@ function updateMessageVisibility() {
|
|
|
}
|
|
|
|
|
|
// Button handlers
|
|
|
-selectAllBtn.addEventListener('click', () => {
|
|
|
- allowedTopics = new Set(allTopics);
|
|
|
- renderFilters();
|
|
|
- updateMessageVisibility();
|
|
|
-});
|
|
|
+if (selectAllBtn !== null) {
|
|
|
+ selectAllBtn.addEventListener('click', () => {
|
|
|
+ allowedTopics = new Set(allTopics);
|
|
|
+ renderFilters();
|
|
|
+ updateMessageVisibility();
|
|
|
+ });
|
|
|
+}
|
|
|
+if (deselectAllBtn !== null) {
|
|
|
+ deselectAllBtn.addEventListener('click', () => {
|
|
|
+ allowedTopics.clear();
|
|
|
+ renderFilters();
|
|
|
+ updateMessageVisibility();
|
|
|
+ });
|
|
|
+}
|
|
|
|
|
|
-deselectAllBtn.addEventListener('click', () => {
|
|
|
- allowedTopics.clear();
|
|
|
- renderFilters();
|
|
|
- updateMessageVisibility();
|
|
|
-});
|
|
|
|
|
|
// Handle incoming MQTT messages
|
|
|
socket.on('mqtt_message', function (data) {
|
|
|
@@ -173,10 +232,26 @@ socket.on('sensor_update', function (data) {
|
|
|
|
|
|
// Update the state of a station
|
|
|
socket.on('station_update', function (data) {
|
|
|
- // Only show messages from origin that matches our view
|
|
|
- if (data.origin !== dashboardMode) return;
|
|
|
-
|
|
|
const state = JSON.parse(data.message);
|
|
|
+
|
|
|
+ // ---------- STATION ACTIVITY CHARTS ----------
|
|
|
+ if (Object.keys(charts).length > 0) {
|
|
|
+ const chart = charts[state.station];
|
|
|
+
|
|
|
+ const seriesIndex = data.origin === 'real' ? 0 : 1;
|
|
|
+ chart.data.datasets[seriesIndex].data.push({
|
|
|
+ x: new Date(), // or parse data.ts
|
|
|
+ y: state.active ? 1 : 0
|
|
|
+ });
|
|
|
+
|
|
|
+ // Limit to last 30 points
|
|
|
+ chart.data.datasets[seriesIndex].data = chart.data.datasets[seriesIndex].data.slice(-30);
|
|
|
+ chart.update();
|
|
|
+ };
|
|
|
+
|
|
|
+ // ---------- STATION ICONS ----------
|
|
|
+ // Only show messages from origin that matches our view
|
|
|
+ if (data.origin !== dashboardMode) return;
|
|
|
|
|
|
// Change colour depending on the code
|
|
|
let colorClass = "text-warning"; // default -> not active
|