Skip to content

Commit dcec565

Browse files
committed
Added desktop notifications and improved LightBurn upload
1 parent 5397842 commit dcec565

3 files changed

Lines changed: 59 additions & 25 deletions

File tree

main/app.js

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { app, BrowserWindow, ipcMain } = require('electron/main');
1+
const { app, BrowserWindow, ipcMain, Notification } = require('electron/main');
22
const path = require('node:path');
33
const fs = require('node:fs');
44
const discovery = require('./discovery.js');
@@ -12,6 +12,7 @@ let appSettings = {
1212
moveDistance: 10,
1313
laserSpotIntensity: 3,
1414
grblBridgeEnabled: true,
15+
desktopNotifications: true,
1516
}
1617
const confDir = (process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share"))+'/xTool-Connect';
1718
if(!fs.existsSync(confDir)) {
@@ -21,11 +22,22 @@ const confFile = confDir+'/config.json';
2122
if(!fs.existsSync(confFile)) {
2223
fs.writeFileSync(confFile, '{}');
2324
} else {
24-
appSettings = {...appSettings, ...JSON.parse(fs.readFileSync(confFile))};
25+
Object.assign(appSettings, JSON.parse(fs.readFileSync(confFile)));
2526
}
2627
function saveSettings() {
2728
fs.writeFileSync(confFile, JSON.stringify(appSettings));
2829
}
30+
31+
function desktopNotification(msg) {
32+
if(!appSettings.desktopNotifications) return;
33+
const template = {
34+
title: 'xTool Connect',
35+
icon: path.join(__dirname, '../icon.png'),
36+
};
37+
Object.assign(template, msg);
38+
new Notification(template).show();
39+
}
40+
2941
function createWindow() {
3042
const window = new BrowserWindow({
3143
width: 500,
@@ -81,10 +93,30 @@ app.whenReady().then(() => {
8193
ipcMain.handle('deviceMenu:connect', async () => {
8294
firstConnect = false;
8395
const result = await deviceController.connect(appSettings.deviceAddress, data => {
84-
if(data == 'err:TIMEOUT') {
85-
window.loadFile('../renderer/index.html', {
86-
query: {message: 'timeout'}
87-
});
96+
switch(data) {
97+
case 'err:TIMEOUT':
98+
desktopNotification({body: 'Connection to device lost. Please check your internet connection and reconnect.'});
99+
window.loadFile('../renderer/index.html', {
100+
query: {message: 'timeout'}
101+
});
102+
grblBridge.stop();
103+
break;
104+
case 'err:tiltCheck':
105+
case 'err:movingCheck':
106+
desktopNotification({body: 'Movement detected!\nThe current job was aborted because the device was moved during operation.', urgency: 'critical'});
107+
break;
108+
case 'err:flameCheck':
109+
desktopNotification({body: 'Flame detected!\nThe current job was aborted because a flame was detected. Please check the state of the device immediately.', urgency: 'critical'});
110+
break;
111+
case 'err:limitCheck':
112+
desktopNotification({body: 'Limit reached!\nThe current job was aborted because a limit switch was activated.', urgency: 'critical'});
113+
break;
114+
case 'grbl:complete':
115+
desktopNotification({body: 'LightBurn upload complete!\nou can now start the job by pressing the start button on the device.'});
116+
break;
117+
case 'grbl:timeout':
118+
desktopNotification({body: 'LightBurn upload failed!\nFile could not be sent to the device.'});
119+
break;
88120
}
89121
window.webContents.send('websocket:message', data);
90122
});

main/device-controller.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,9 @@ module.exports.connect = async (address, callback) => {
6767
websocket.ping();
6868
if(lastHeartbeat + 4100 < Date.now()) {
6969
wsCallback('err:TIMEOUT');
70-
clearInterval(heartbeatTimer);
70+
console.log('Connection to device timed out.');
7171
websocket.terminate();
72-
connected = false;
73-
console.log('Connection to current device timed out.');
72+
this.disconnect();
7473
}
7574
}, 2000);
7675
console.log('Successfully connected to device '+deviceAddress);

renderer/assets/js/control.js

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const currentStatus = document.getElementById('currentStatus');
1111
const currentProgress = document.getElementById('currentProgress');
1212
const currentProgressNum = document.getElementById('currentProgressNum');
1313

14-
let progressUpdateTimer, laserSpotActive;
14+
let progressUpdateTimer, laserSpotActive, uploadNotification;
1515

1616
disconnectBtn.addEventListener('click', () => {
1717
window.electronAPI.disconnectDevice();
@@ -81,20 +81,21 @@ stopBtn.addEventListener('click', () => {
8181
laserSpotIntensity.value = settings.laserSpotIntensity;
8282

8383
window.electronAPI.onWebsocketMessage(data => {
84-
if(data.startsWith('ok:WORKING_')) {
85-
gcodeDropzone.classList.add('disabled');
86-
disableMoveButtons(true);
87-
pauseBtn.disabled = false;
88-
stopBtn.disabled = false;
89-
currentStatus.innerText = 'Working';
90-
pauseBtn.innerText = 'Pause';
91-
pauseBtn.value = 'pause';
92-
if(!progressUpdateTimer) {
93-
updateProgress();
94-
progressUpdateTimer = setInterval(updateProgress, 5000);
95-
}
96-
}
9784
switch(data) {
85+
case 'ok:WORKING_OFFLINE':
86+
case 'ok:WORKING_FRAMING':
87+
gcodeDropzone.classList.add('disabled');
88+
disableMoveButtons(true);
89+
pauseBtn.disabled = false;
90+
stopBtn.disabled = false;
91+
currentStatus.innerText = 'Working';
92+
pauseBtn.innerText = 'Pause';
93+
pauseBtn.value = 'pause';
94+
if(!progressUpdateTimer) {
95+
updateProgress();
96+
progressUpdateTimer = setInterval(updateProgress, 5000);
97+
}
98+
break;
9899
case 'ok:IDLE':
99100
gcodeDropzone.classList.remove('disabled');
100101
disableMoveButtons(false);
@@ -132,12 +133,14 @@ stopBtn.addEventListener('click', () => {
132133
toastr.error('The current job was aborted because a limit switch was activated.', 'Limit reached!', {timeOut: 8000});
133134
break;
134135
case 'grbl:started':
135-
toastr.success('Please wait until the file is received and the upload is complete.', 'Receiving data from LightBurn...');
136+
uploadNotification = toastr.success('Please wait until the file is received and the upload is complete.', 'Receiving data from LightBurn...', {timeOut: 0});
136137
break;
137-
case 'grbl:complete':
138+
case 'grbl:complete':
139+
uploadNotification.remove();
138140
toastr.success('You can now start the job by pressing the start button on the device.', 'LightBurn upload complete');
139141
break;
140142
case 'grbl:timeout':
143+
uploadNotification.remove();
141144
toastr.success('File could not be sent to the device.', 'LightBurn upload failed');
142145
break;
143146
}

0 commit comments

Comments
 (0)