diff --git a/DOCKER.md b/DOCKER.md index 3cc94a44..9ff986af 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -21,7 +21,7 @@ docker run -it --device=/dev/ttyUSB0 --rm -p 8000:8000 laserweb4:dev ## Release You can run the current lw.comm-server version of the app in Docker using the commands below. -**Warning:** This will bundle the current (head) [lw.comm-server head](https://github.com/LaserWeb/lw.comm-server/) Git version + the LW app bundled with that, it *does not* build the latest LW app from this repo! Use the 'dev' target for that. +**Warning:** This will bundle the current (head) [lw.comm-server head](https://github.com/LaserWeb/lw.comm-server/) Git version + the LW app from this repo. - build release image: ``` diff --git a/Dockerfile b/Dockerfile index a2d394f6..b35502ab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,11 @@ # # ---- Base Node ---- -FROM node:16-bullseye AS base +FROM node:22-bookworm AS base # set working directory WORKDIR /usr/src/app # Set up Apt, install build tooling and udev RUN apt update -RUN apt install -y build-essential udev +RUN apt install -y build-essential udev libudev-dev libusb-1.0-0-dev # Upgrade npm and set node options RUN npm install -g npm RUN npm set progress=false @@ -19,12 +19,21 @@ FROM base AS comm-server # (Currently use --force to allow for broken deps, this should be removed once the dep tree is fixed RUN npm install -g nodemon && npm install --force lw.comm-server@git+https://github.com/LaserWeb/lw.comm-server.git -# ---- Release ---- -# This will use the git head version of lw.comm-server + the LW app version bundled with that. -# it DOES NOT build and serve the version of LaserWeb in this repo # +# ---- build Laserweb ---- +FROM base as build-prod +COPY package.json package-lock.json ./ +RUN npm ci --force +COPY . . +RUN npm run bundle-prod + +# ---- Release ---- +# This will use the git head version of lw.comm-server and Laserweb from the build stage FROM comm-server AS release WORKDIR /usr/src/app +# Replace the bundled app with the freshly built Laserweb +RUN rm -rf node_modules/lw.comm-server/app/ +COPY --from=build-prod /usr/src/app/dist /usr/src/app/node_modules/lw.comm-server/app/ # define CMD CMD [ "node", "node_modules/lw.comm-server/server.js"] diff --git a/src/components/com.js b/src/components/com.js index a56c0641..a0fbfd74 100644 --- a/src/components/com.js +++ b/src/components/com.js @@ -4,12 +4,14 @@ import { connect } from 'react-redux'; import { PanelGroup, Panel, Tooltip, OverlayTrigger, FormControl, InputGroup, ControlLabel, FormGroup, ButtonGroup, Label, Collapse, Badge, ButtonToolbar, Button, Glyphicon } from 'react-bootstrap'; import { Input, TextField, NumberField, ToggleField, SelectField, Info } from './forms'; -import { runStatus } from './jog.js'; +import { runStatus, hasHomed } from './jog.js'; import { setSettingsAttrs } from '../actions/settings'; import { setComAttrs } from '../actions/com'; import { setWorkspaceAttrs } from '../actions/workspace'; // import { setGcode } from '../actions/gcode'; import CommandHistory from './command-history'; +import { strftime } from '../lib/strftime.js' +import { thumbnails } from './workspace.js' import { alert, prompt, confirm} from './laserweb'; @@ -17,20 +19,25 @@ import Icon from './font-awesome'; import io from 'socket.io-client'; var socket, connectVia, connectReset; +var messageId = 1 +var feedOverrideVal = 100 +var spindleOverrideVal = 100 var serverConnected = false; var machineConnected = false; var jobLines = 0; +var jobProgress = 0; var jobStartTime = -1; var accumulatedJobTime = 0; var playing = false; var paused = false; var m0 = false; var laserTestOn = false; +var laserTestOnCnt = 0; var firmware, fVersion, fDate; var xpos, ypos, zpos, apos; var xOffset, yOffset, zOffset, aOffset; -export { xOffset, yOffset } +export { xOffset, yOffset, serverConnected, socket } const formatPorts=(data)=>{ @@ -67,12 +74,16 @@ class Com extends React.Component { if (!serverConnected) { $('#connectS').removeClass('disabled'); $('#disconnectS').addClass('disabled'); + $('#restartKlippy').addClass('disabled'); + $('#restartFirmware').addClass('disabled'); if (!socket && !serverConnected) { this.handleConnectServer(); } } else { $('#connectS').addClass('disabled'); $('#disconnectS').removeClass('disabled'); + $('#restartKlippy').removeClass('disabled'); + $('#restartFirmware').removeClass('disabled'); if (!machineConnected) { $('#connect').removeClass('disabled'); $('#disconnect').addClass('disabled'); @@ -81,6 +92,9 @@ class Com extends React.Component { $('#disconnect').removeClass('disabled'); } } + if (serverConnected && socket && socket.moonraker) { + socket.emit('getServerConfig'); + } } handleConnectServer() { @@ -89,12 +103,433 @@ class Com extends React.Component { let server = settings.comServerIP; CommandHistory.write('Connecting to Server @ ' + server, CommandHistory.INFO); //console.log('Connecting to Server ' + server); - socket = io('ws://' + server); + let addr = server.replace(/^((http|ws)s?:\/\/|)/, (w) => `ws${(w || location.protocol).indexOf('s') > -1 ? 's' : ''}://`); + if (settings.connectServerVia === 'Moonraker') { + if (socket) { + socket.disconnect(); + } + addr = addr.replace(/^(wss?:\/\/[^\/]*)(.*)/, (_, ad, path) => `${ad}${ path || '/websocket'}`); + const moonraker = new WebSocket(addr); + const callbacks = new Map(); + let statusInterval + let klipperState + const handle = {} + function send(method, params, callback) { + const id = `${method}:${messageId++}`; + if (typeof params === 'function') { + callback = params; + params = undefined; + } + moonraker.send(JSON.stringify({ jsonrpc: "2.0", method, params, id })); + if (callback) { + callbacks.set(id, callback); + } + } + const recv = { + notify_proc_stat_update(data) { + // console.log('notify_proc_stat_update', data); + }, + notify_status_update(data) { + if (!data || !data[0]) { + return + } + const d = data[0] + // console.log('notify_status_update',d); + if (d.toolhead) { + const t = d.toolhead + if (t.homed_axes) { + hasHomed(t.homed_axes === 'xyz' || (t.homed_axes === 'xy' && !that.props.settings.machineZEnabled)) + } + if (t.axis_minimum && t.axis_maximum && that.props.settings.machineSizeFromMachine) { + const minX = t.axis_minimum[0] + const minY = t.axis_minimum[1] + const maxX = t.axis_maximum[0] + const maxY = t.axis_maximum[1] + + dispatch(setSettingsAttrs({ + machineWidth: maxX - minX, + machineHeight: maxY - minY, + machineBottomLeftX: minX, + machineBottomLeftY: minY, + })); + } + } + if (d.gcode_move) { + const g = d.gcode_move + if (g.speed_factor != null) { + feedOverrideVal = Math.round(g.speed_factor * 100) + handle.feedOverride(feedOverrideVal) + } + if (g.extrude_factor != null) { + spindleOverrideVal = Math.round(g.extrude_factor * 100) + handle.spindleOverride(spindleOverrideVal) + } + if (g.homing_origin) { + const [x, y, z, a] = g.homing_origin + handle.wOffset({ x, y, z, a }) + } + if (g.gcode_position) { + [xpos, ypos, zpos, apos] = g.gcode_position + const x = parseFloat(xpos).toFixed(5).replace(/0{1,3}$/, '') + const y = parseFloat(ypos).toFixed(5).replace(/0{1,3}$/, '') + const z = parseFloat(zpos).toFixed(5).replace(/0{1,3}$/, '') + const a = parseFloat(apos).toFixed(5).replace(/0{1,3}$/, '') + $('#mX').html(x); + $('#mY').html(y); + $('#mZ').html(z); + $('#mA').html(a); + } + } + if (d.motion_report) { + let [x, y, z] = d.motion_report.live_position + dispatch(setWorkspaceAttrs({ cursorPos: [x-xOffset, y-yOffset, z-zOffset] })); + } + if (d.print_stats) { + const p = d.print_stats + if (klipperState === 'ready') { + // standby The printer is standing by for a job to begin. + // printing A job is currently printing. + // paused The current print job is paused. + // complete The last print job successfully finished. + // error The last print job exited with an error. + // cancelled THe last print job was cancelled by the user. + const uStatus = p.state === 'standby' ? 'Idle' : + p.state === 'printing' ? 'Run' : + p.state === 'paused' ? 'Hold' : + p.state === 'complete' ? 'Idle' : + p.state === 'error' ? 'Alarm' : + p.state === 'cancelled' ? 'Idle' : + ''; + const rStatus = p.state === 'standby' ? 'stopped' : + p.state === 'printing' ? 'running' : + p.state === 'paused' ? 'm0' : + p.state === 'complete' ? 'finished' : + p.state === 'error' ? 'stopped' : // alert? + p.state === 'cancelled' ? 'stopped' : + ''; + updateStatus(`<${uStatus},`); + ({ playing, paused, m0 } = runStatus(rStatus, true)); + } + if (p.message) { + CommandHistory.write(p.message, CommandHistory.INFO); + } + } + if (d.virtual_sdcard) { + const sd = d.virtual_sdcard + if (sd.progress) { + jobProgress = Math.floor(sd.progress*100+0.01) + $('#queueCnt').html(`${jobProgress} %`); + } else if (sd.progress == 0){ + $('#queueCnt').html(''); + } + } + }, + notify_klippy_ready() { + console.log('notify_klippy_ready'); + emitter.getServerConfig(); + }, + notify_klippy_shutdown() { + console.log('notify_klippy_shutdown'); + handle.connectStatus('Connect: shutdown'); + klipperState = 'shutdown' + updateStatus(' { + klipperState = data.klippy_state + handle.serverConfig({ serverVersion: data.moonraker_version, apiVersion: data.api_version_string }); + send('printer.objects.subscribe', { + objects: { + gcode_move: ['gcode_position', 'homing_origin', 'speed_factor', 'extrude_factor'], + motion_report: ['live_position'], + print_stats: ['state', 'message'], + toolhead: ['homed_axes', 'axis_minimum', 'axis_maximum'], + virtual_sdcard: ['progress'] + } + }, (data) => { + recv.notify_status_update([data && data.status]) + }); + for (const msg of data.warnings) { + CommandHistory.write(msg.message, CommandHistory.WARN); + } + for (const msg of data.missing_klippy_requirements) { + CommandHistory.write(msg.message, CommandHistory.DANGER); + } + if (klipperState !== 'ready') { + updateStatus('= 10)) { + // valid range is 10..200, else ignore! + feedOverrideVal += data; + } + } + const script = `M220 S${feedOverrideVal}`; + send('printer.gcode.script', { script }); + }, + spindleOverride(data) { + if (data === 0) { + spindleOverrideVal = 100; + } else { + if ((spindleOverrideVal + data <= 200) && (spindleOverrideVal + data >= 10)) { + // valid range is 10..200, else ignore! + spindleOverrideVal += data; + } + } + const script = `M221 S${spindleOverrideVal}`; + send('printer.gcode.script', { script }); + }, + runJob(data) { + const thumbs = thumbnails(); + var form = new FormData(); + form.append('print', true) + const filename = strftime(that.props.settings.gcodeFilename) + that.props.settings.gcodeExtension + const blob = new Blob([data+thumbs], { type: 'text/plain' }) + form.append('file', blob, filename) + fetch(addr.replace('ws', 'http').replace(/\/websocket|$/, '/server/files/upload'), { method: 'POST', body: form }).then((response) => { + if (response.status > 201) { + console.log(response) + CommandHistory.error(`Job upload failed!`) + } + }, (error) => { + console.log(error) + CommandHistory.error(`Job upload failed!`) + }) + }, + clearJob() { + send('printer.gcode.script', { script: 'SDCARD_RESET_FILE' }); + }, + stop() { + send('printer.print.cancel', () => { + emitter.getServerConfig(); + }); + }, + pause() { + send('printer.print.pause', () => { + emitter.getServerConfig(); + }); + }, + resume() { + send('printer.print.resume', () => { + emitter.getServerConfig(); + }); + }, + clearAlarm(method) { + if (method === 1) { + send('printer.restart'); + } else if (method === 2) { + send('printer.firmware_restart'); + } + }, + resetMachine() { + socket.send('printer.emergency_stop') + }, + probe({ axis, offset }) { + if (axis.indexOf('z') > -1) { + send('printer.gcode.script', { script: 'PROBE' }); + } else { + CommandHistory.error(`Can only probe Z axis!`) + } + }, + laserTest(data) { + const [laserPower, duration, maxS] = data.split(',') + const s = that.props.settings + let laserOnS = s.gcodeLaserIntensity + (s.gcodeSMinValue + (s.gcodeSMaxValue - s.gcodeSMinValue) * laserPower / 100).toFixed(s.decimal || 4); + const toolOn = s.gcodeToolOn.split('$INTENSITY').join(laserOnS) || laserOnS + const laserOffS = s.gcodeLaserIntensity + 0 + const toolOff = s.gcodeToolOff || (s.gcodeToolOn.indexOf('$INTENSITY') > -1 ? s.gcodeToolOn.split('$INTENSITY').join(laserOffS) : laserOffS) + const script = `${toolOn}\nG4 P${duration}\n${toolOff}` + handle.laserTest(1) + laserTestOnCnt++ + send('printer.gcode.script', { script }, () => { setTimeout(() => { --laserTestOnCnt === 0 && handle.laserTest(0) }, 300); }); + }, + home(axis) { + send('printer.gcode.script', { script: `G28 ${axis.toUpperCase()}` }); + }, + setPosition(data) { + const { x, y, z} = data; + let pos = '' + if (isFinite(x)) { + pos += ` X=${x}` + } + if (isFinite(y)) { + pos += ` Y=${y}` + } + if (isFinite(z)) { + pos += ` Z=${z}` + } + let script = `SET_GCODE_OFFSET MOVE=0 ${pos}\n` + script += `SAVE_GCODE_STATE NAME=Laserweb\nG91\nG0 F10 X0.125\nG0 X-0.125\nG90\nRESTORE_GCODE_STATE NAME=Laserweb` // cause position update to apply offsets + send('printer.gcode.script', { script }); + }, + setZero(axis, reset) { + let pos = {} + if (axis === 'all') { + axis = 'xyz' + } + if (axis.indexOf('x') > -1) { + pos.x = reset ? 0 : xpos + xOffset + } + if (axis.indexOf('y') > -1) { + pos.y = reset ? 0 : ypos + yOffset + } + if (axis.indexOf('z') > -1) { + pos.z = reset ? 0 : zpos + zOffset + } + emitter.setPosition(pos); + }, + gotoZero(axis) { + let pos = '' + if (axis.indexOf('x') > -1) { + pos += ` X0` + } + if (axis.indexOf('y') > -1) { + pos += ` Y0` + } + if (axis.indexOf('z') > -1) { + pos += ` Z0` + } + const script = `SAVE_GCODE_STATE NAME=Laserweb\nG90\nG0 ${pos}\nRESTORE_GCODE_STATE NAME=Laserweb` + send('printer.gcode.script', { script }); + }, + } + socket = { + moonraker: true, + send, + on(name, fn) { + handle[name] = fn + }, + emit(name, ...args) { + if (emitter[name]) { + emitter[name](...args) + } else { + console.log('emitter missing', name, ...args); + } + }, + disconnect() { + moonraker.close(); + }, + } + moonraker.onopen = function() { + console.log('onopen'); + handle.connect() + clearInterval(statusInterval) + let printerState + let printerMsg + statusInterval = setInterval(function () { + if (!machineConnected || printerState !== 'ready') { + send('printer.info', (data, error) => { + // console.log('printer.info', data, error) + if (error) { + return; + } + if (printerState !== data.state) { + printerState = data.state; + if (printerState === 'ready') { + handle.firmware({ firmware: 'Klipper', version: data.software_version, date: '' }); + } + } + if (printerMsg !== data.state_message) { + printerMsg = data.state_message; + if (printerState === 'ready') { + CommandHistory.write(printerMsg || 'Machine connected', CommandHistory.SUCCESS); + } else { + CommandHistory.error(printerMsg || 'Machine disconnected: ' + klipperState); + } + } + }) + } + }, 1000); + } + moonraker.onclose = function() { + console.log('onclose'); + clearInterval(statusInterval) + handle.disconnect() + } + moonraker.onerror = function(err) { + console.log('onerror', err); + } + moonraker.onmessage = function(e) { + try { + const data = JSON.parse(e.data) + const cb = callbacks.get(data.id); + if (cb) { + cb(data.result, data.error); + callbacks.delete(data.id); + } else if (recv[data.method]) { + recv[data.method](data.params, data.error) + } else { + console.warn('onmessage', data.id || data.method, e.data); + } + } catch(err) { + console.error('invalid message', e.data, err); + } + } + } else { + socket = io(addr); + } socket.on('connect', function(data) { serverConnected = true; $('#connectS').addClass('disabled'); $('#disconnectS').removeClass('disabled'); + $('#restartKlippy').removeClass('disabled'); + $('#restartFirmware').removeClass('disabled'); //socket.emit('firstLoad'); socket.emit('getServerConfig'); CommandHistory.write('Server connected', CommandHistory.SUCCESS); @@ -108,7 +543,8 @@ class Com extends React.Component { $('#disconnectS').addClass('disabled'); machineConnected = false; $('#connect').removeClass('disabled'); - $('#disconnect').addClass('disabled'); + $('#restartKlippy').addClass('disabled'); + $('#restartFirmware').addClass('disabled'); firmware = ''; fVersion = ''; fDate = ''; @@ -286,27 +722,11 @@ class Com extends React.Component { socket.on('runStatus', function (status) { //CommandHistory.write('runStatus: ' + status); console.log('runStatus: ' + status); - if (status === 'running') { - playing = true; - paused = false; - } else if (status === 'paused') { - paused = true; - } else if (status === 'm0') { - paused = true; - m0 = true; - } else if (status === 'resumed') { - paused = false; - } else if (status === 'stopped') { - playing = false; - paused = false; - } else if (status === 'finished') { - playing = false; - paused = false; - } else if (status === 'alarm') { + if (status === 'alarm') { CommandHistory.error('ALARM!') //socket.emit('clearAlarm', 2); } - runStatus(status); + ({ playing, paused, m0 } = runStatus(status, true)); }); socket.on('data', function (data) { @@ -457,10 +877,8 @@ class Com extends React.Component { } $('#queueCnt').html(queueState); if (playing && data === 0) { - playing = false; - paused = false; jobLines = 0; - runStatus('stopped'); + ({ playing, paused, m0 } = runStatus('stopped')); $('#playicon').removeClass('fa-pause'); $('#playicon').addClass('fa-play'); @@ -580,10 +998,8 @@ class Com extends React.Component { CommandHistory.write('Disconnecting Machine', CommandHistory.INFO); console.log('Machine Disconnected by user'); socket.emit('closePort'); - playing = false; - paused = false; jobLines = 0; - runStatus('stopped'); + ({ playing, paused, m0 } = runStatus('stopped')); $("#machineStatus").removeClass('badge-ok'); $("#machineStatus").addClass('badge-notify'); $("#machineStatus").removeClass('badge-warn'); @@ -601,6 +1017,7 @@ class Com extends React.Component { + @@ -609,23 +1026,36 @@ class Com extends React.Component { - - +
- - + + + +
+ + +
+
+ +
+ +
+
+ + + + +
- +
- + + + +
- - - - -
@@ -750,9 +1180,7 @@ export function runJob(job) { if (job.length > 0) { jobLines = job.split(/\r\n|\r|\n/).length CommandHistory.write('Running Job; ' + jobLines + ' lines', CommandHistory.INFO); - playing = true; - jobLines = job.split(/\r\n|\r|\n/).length - runStatus('running'); + ({ playing, paused, m0 } = runStatus('running')); $('#playicon').removeClass('fa-play'); $('#playicon').addClass('fa-pause'); jobStartTime = new Date(Date.now()); @@ -775,8 +1203,7 @@ export function pauseJob() { console.log('pauseJob'); if (serverConnected) { if (machineConnected){ - paused = true; - runStatus('paused'); + ({ playing, paused, m0 } = runStatus('paused')); $('#playicon').removeClass('fa-pause'); $('#playicon').addClass('fa-play'); socket.emit('pause'); @@ -792,9 +1219,7 @@ export function resumeJob() { console.log('resumeJob'); if (serverConnected) { if (machineConnected){ - paused = false; - m0 = false; - runStatus('running'); + ({ playing, paused, m0 } = runStatus('running')); $('#playicon').removeClass('fa-play'); $('#playicon').addClass('fa-pause'); socket.emit('resume'); @@ -811,11 +1236,8 @@ export function abortJob() { if (serverConnected) { if (machineConnected){ CommandHistory.write('Aborting job', CommandHistory.INFO); - playing = false; - paused = false; - m0 = false; jobLines = 0; - runStatus('stopped'); + ({ playing, paused, m0 } = runStatus('stopped')); $('#playicon').removeClass('fa-pause'); $('#playicon').addClass('fa-play'); socket.emit('stop'); @@ -827,10 +1249,28 @@ export function abortJob() { } } +export function clearJob() { + console.log('clearJob'); + if (serverConnected) { + if (machineConnected){ + if (!jobProgress || jobProgress === 100) { + CommandHistory.write('Clearing Finished job', CommandHistory.INFO); + socket.emit('clearJob'); + } else { + CommandHistory.error('Job is still running!') + } + } else { + CommandHistory.error('Machine is not connected!') + } + } else { + CommandHistory.error('Server is not connected!') + } +} + export function clearAlarm(method) { console.log('clearAlarm'); if (serverConnected) { - if (machineConnected){ + if (machineConnected || (socket && socket.moonraker)){ CommandHistory.write('Resetting alarm', CommandHistory.INFO); socket.emit('clearAlarm', method); } else { @@ -841,11 +1281,11 @@ export function clearAlarm(method) { } } -export function setZero(axis) { +export function setZero(axis, reset) { if (serverConnected) { if (machineConnected){ CommandHistory.write('Set ' + axis + ' Axis zero', CommandHistory.INFO); - socket.emit('setZero', axis); + socket.emit('setZero', axis, reset); } else { CommandHistory.error('Machine is not connected!') } @@ -973,7 +1413,7 @@ export function spindleOverride(step) { export function resetMachine() { if (serverConnected) { - if (machineConnected){ + if (machineConnected || (socket && socket.moonraker)){ CommandHistory.error('Resetting Machine') socket.emit('resetMachine'); } else { @@ -995,8 +1435,7 @@ export function playpauseMachine() { laseroncmd = 0; } socket.emit('resume', laseroncmd); - paused = false; - runStatus('running'); + ({ playing, paused, m0 } = runStatus('running')); $('#playicon').removeClass('fa-play'); $('#playicon').addClass('fa-pause'); // end ifPaused @@ -1007,8 +1446,7 @@ export function playpauseMachine() { laseroffcmd = 0; } socket.emit('pause', laseroffcmd); - paused = true; - runStatus('paused'); + ({ playing, paused, m0 } = runStatus('paused')); $('#playicon').removeClass('fa-pause'); $('#playicon').addClass('fa-play'); } diff --git a/src/components/jog.js b/src/components/jog.js index 58605870..fc9a6e4f 100644 --- a/src/components/jog.js +++ b/src/components/jog.js @@ -14,7 +14,7 @@ import { xOffset, yOffset } from './com'; import CommandHistory from './command-history'; import { Input, TextField, NumberField, ToggleField, SelectField } from './forms'; -import { runCommand, runJob, pauseJob, resumeJob, abortJob, clearAlarm, setZero, gotoZero, setPosition, home, probe, checkSize, laserTest, jog, jogTo, feedOverride, spindleOverride, resetMachine } from './com.js'; +import { runCommand, runJob, pauseJob, resumeJob, abortJob, clearJob, clearAlarm, setZero, gotoZero, setPosition, home, probe, checkSize, laserTest, jog, jogTo, feedOverride, spindleOverride, resetMachine, serverConnected, socket } from './com.js'; import { MacrosBar } from './macros'; import '../styles/index.css' @@ -33,6 +33,7 @@ var ovLoop; var playing = false; var paused = false; var m0 = false; +var thatComponent; $('body').on('keydown', function (ev) { if (ev.keyCode === 17) { @@ -123,6 +124,7 @@ class Jog extends React.Component { componentDidMount() { + thatComponent = this; this.checkGcodeBounds(this.props.gcode); bindKeys(this.bindings); @@ -176,9 +178,13 @@ class Jog extends React.Component { } } + if (serverConnected && socket && socket.moonraker) { + socket.emit('getServerConfig'); + } } componentWillUnmount() { + thatComponent = undefined; liveJoggingState = this.state.liveJogging; // unbindKeys(this.bindings) @@ -244,14 +250,16 @@ class Jog extends React.Component { let cmd = this.props.gcode; //alert(cmd); console.log('runJob(' + cmd.length + ')'); - playing = true; + if (cmd.length > 0) { + playing = true; - this.setState({ - isPlaying: true, - liveJogging: { - ... this.state.liveJogging, disabled: true, hasHomed: false - } - }) + this.setState({ + isPlaying: true, + liveJogging: { + ... this.state.liveJogging, disabled: true, hasHomed: false + } + }) + } runJob(cmd); } else { @@ -296,6 +304,18 @@ class Jog extends React.Component { } } + clearJob() { + if (!socket || !socket.moonraker) { + return; + } + + if (playing) { + CommandHistory.log('clearJob ignored, because job is running'); + } else { + clearJob(); + } + } + homeAll() { console.log('homeAll'); let cmd = this.props.settings.gcodeHoming; @@ -313,20 +333,21 @@ class Jog extends React.Component { probe(axis) { console.log('probe'); + let offset if (axis.indexOf('z') === 0) { - let offset = this.props.settings.machineZProbeOffset; + offset = this.props.settings.machineZProbeOffset; } else { - let offset = this.props.settings.machineXYProbeOffset; + offset = this.props.settings.machineXYProbeOffset; } probe(axis, offset); } - setZero(axis) { + setZero(axis, event) { if (!this.state.isPlaying) this.setState({ liveJogging: { ... this.state.liveJogging, hasHomed: true, disabled: false } }) - console.log('setZero(' + axis + ')'); - setZero(axis); + console.log('setZero(' + axis + ', ' + event.altKey + ')'); + setZero(axis, event.altKey); } setPosition(pos) { @@ -346,7 +367,11 @@ class Jog extends React.Component { if (units == 'mm/s') mult = 60; feedrate = jQuery('#jogfeedxy').val() * mult; - let bounds=this.getGcodeBounds(this.props.gcode) + let bounds = this.getGcodeBounds(this.props.gcode); + if (!bounds) { + CommandHistory.error('no gcode to check size of'); + return; + } let power = this.props.settings.gcodeCheckSizePower / 100 * this.props.settings.gcodeSMaxValue; let moves = ` G90\n @@ -412,11 +437,9 @@ class Jog extends React.Component { } laserTest() { - console.log('laserTest'); let power = this.props.settings.gcodeToolTestPower; let duration = this.props.settings.gcodeToolTestDuration; let maxS = this.props.settings.gcodeSMaxValue; - console.log('laserTest(' + power + ',' + duration + ',' + maxS + ')'); laserTest(power, duration, maxS); } @@ -523,7 +546,7 @@ class Jog extends React.Component { return (
Not Connected - Queued: 0 + { this.clearJob() }} title="Job details, based on gcode lines completed and queued" id="queueCnt" style={{ marginRight: 5 }}>Queued: 0
X:
@@ -539,7 +562,7 @@ class Jog extends React.Component {
  • Work Coordinates
  • { this.home('x') }}>Home X Axis
  • -
  • { this.setZero('x') }}>Set X Axis Zero
  • +
  • { this.setZero('x', e) }}>Set X Axis Zero
  • Move
  • { this.gotoZero('x') }}>G0 to X0
  • @@ -562,7 +585,7 @@ class Jog extends React.Component {
  • Work Coordinates
  • { this.home('y') }}>Home Y Axis
  • -
  • { this.setZero('y') }}>Set Y Axis Zero
  • +
  • { this.setZero('y', e) }}>Set Y Axis Zero
  • Move
  • { this.gotoZero('y') }}>G0 to Y0
  • @@ -586,7 +609,7 @@ class Jog extends React.Component {
  • Work Coordinates
  • { this.home('z') }}>Home Z Axis
  • -
  • { this.setZero('z') }}>Set Z Axis Zero
  • +
  • { this.setZero('z', e) }}>Set Z Axis Zero
  • Move
  • { this.gotoZero('z') }}>G0 to Z0
  • @@ -613,7 +636,7 @@ class Jog extends React.Component {
  • Work Coordinates
  • { this.home('a') }}>Home A Axis
  • -
  • { this.setZero('a') }}>Set A Axis Zero
  • +
  • { this.setZero('a', e) }}>Set A Axis Zero
  • Move
  • { this.gotoZero('a') }}>G0 to A0
  • @@ -706,7 +729,7 @@ class Jog extends React.Component {
    -