Implemented server updates to printer controls.

This commit is contained in:
Tom Butcher 2025-12-03 15:46:52 +00:00
parent 6f46587f5e
commit d0911c1166
6 changed files with 412 additions and 223 deletions

View File

@ -19,7 +19,7 @@ import PrinterIcon from '../../../Icons/PrinterIcon.jsx'
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel.jsx' import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel.jsx'
import PrinterPositionPanel from '../../common/PrinterPositionPanel.jsx' import PrinterPositionPanel from '../../common/PrinterPositionPanel.jsx'
import PrinterMovementPanel from '../../common/PrinterMovementPanel.jsx' import PrinterMovementPanel from '../../common/PrinterMovementPanel.jsx'
import PrinterMiscPanel from '../../common/PrinterMiscPanel.jsx'
import JobIcon from '../../../Icons/JobIcon.jsx' import JobIcon from '../../../Icons/JobIcon.jsx'
import SubJobIcon from '../../../Icons/SubJobIcon.jsx' import SubJobIcon from '../../../Icons/SubJobIcon.jsx'
import FilamentStockIcon from '../../../Icons/FilamentStockIcon.jsx' import FilamentStockIcon from '../../../Icons/FilamentStockIcon.jsx'
@ -50,7 +50,8 @@ const ControlPrinter = () => {
filamentStock: true, filamentStock: true,
temperature: true, temperature: true,
position: true, position: true,
movement: true movement: true,
misc: true
} }
) )
@ -58,7 +59,8 @@ const ControlPrinter = () => {
const [sideBarVisible, setSideBarVisible] = useState( const [sideBarVisible, setSideBarVisible] = useState(
collapseState.temperature || collapseState.temperature ||
collapseState.position || collapseState.position ||
collapseState.movement collapseState.movement ||
collapseState.misc
) )
const [loadFilamentStockOpen, setLoadFilamentStockOpen] = useState(false) const [loadFilamentStockOpen, setLoadFilamentStockOpen] = useState(false)
@ -68,7 +70,8 @@ const ControlPrinter = () => {
setSideBarVisible( setSideBarVisible(
collapseState.temperature || collapseState.temperature ||
collapseState.position || collapseState.position ||
collapseState.movement collapseState.movement ||
collapseState.misc
) )
}, [collapseState]) }, [collapseState])
@ -168,18 +171,23 @@ const ControlPrinter = () => {
const sideBarItems = ( const sideBarItems = (
<Flex gap={isMobile ? 'large' : 'middle'} vertical> <Flex gap={isMobile ? 'large' : 'middle'} vertical>
{collapseState.temperature && ( {collapseState.temperature && (
<Card style={{ width: '100%' }}> <Card style={{ width: '100%' }} title='Temperature' size='small'>
<PrinterTemperaturePanel id={printerId} /> <PrinterTemperaturePanel id={printerId} />
</Card> </Card>
)} )}
{collapseState.position && ( {collapseState.position && (
<Card style={{ width: '100%' }}> <Card style={{ width: '100%' }} title='Position' size='small'>
<PrinterPositionPanel /> <PrinterPositionPanel id={printerId} />
</Card> </Card>
)} )}
{collapseState.movement && ( {collapseState.movement && (
<Card style={{ width: '100%' }}> <Card style={{ width: '100%' }} title='Movement' size='small'>
<PrinterMovementPanel /> <PrinterMovementPanel id={printerId} />
</Card>
)}
{collapseState.misc && (
<Card style={{ width: '100%' }} title='Misc' size='small'>
<PrinterMiscPanel id={printerId} />
</Card> </Card>
)} )}
</Flex> </Flex>
@ -236,6 +244,10 @@ const ControlPrinter = () => {
key: 'movement', key: 'movement',
label: 'Movement' label: 'Movement'
}, },
{
key: 'misc',
label: 'Misc'
},
{ key: 'notes', label: 'Notes' } { key: 'notes', label: 'Notes' }
]} ]}
visibleState={collapseState} visibleState={collapseState}

View File

@ -1,22 +1,21 @@
import { useContext, useState, useEffect } from 'react' import { useContext, useState, useEffect } from 'react'
import { Typography, Spin, Flex, Space, Slider, Descriptions, Tag } from 'antd' import { Typography, Spin, Flex, Space, Slider, Descriptions, Tag } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import { PrintServerContext } from '../context/PrintServerContext' import { ApiServerContext } from '../context/ApiServerContext'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import merge from 'lodash/merge'
const { Text } = Typography const { Text } = Typography
const PrinterMiscPanel = ({ const PrinterMiscPanel = ({ id, showControls = true }) => {
printerId, const { subscribeToObjectEvent, connected, sendObjectAction } =
showControls = true, useContext(ApiServerContext)
shouldUnsubscribe = true
}) => {
const [miscData, setMiscData] = useState({ const [miscData, setMiscData] = useState({
fan: { fan: {
speed: 0, speed: 0,
target: 0 target: 0
}, },
ledBacklight: { lcdBacklight: {
// eslint-disable-line camelcase // eslint-disable-line camelcase
brightness: 0 brightness: 0
}, },
@ -27,112 +26,81 @@ const PrinterMiscPanel = ({
enabled: false, enabled: false,
filamentDetected: false filamentDetected: false
}, },
heaterFan: { coolingFan: {
speed: 0 speed: 0
} }
}) })
const [initialized, setInitialized] = useState(false)
const { printServer } = useContext(PrintServerContext)
const [fanSpeed, setFanSpeed] = useState(0) const [fanSpeed, setFanSpeed] = useState(0)
const [ledBrightness, setLedBrightness] = useState(0) const [lcdBrightness, setLcdBrightness] = useState(0)
const [beeperValue, setBeeperValue] = useState(0) const [beeperValue, setBeeperValue] = useState(0)
useEffect(() => { useEffect(() => {
const params = { if (id && connected == true) {
printerId, console.log('subscribing to misc event')
objects: { const miscEventUnsubscribe = subscribeToObjectEvent(
fan: null, id,
'filament_switch_sensor fsensor': null, 'printer',
'output_pin BEEPER_pin': null, 'misc',
'output_pin LCD_backlight_pin': null, (event) => {
'heater_fan nozzle_cooling_fan': null console.log('misc event', event)
} setMiscData((prev) => {
} const merged = merge({}, prev, event.data)
return merged
const notifyMiscStatusUpdate = (statusUpdate) => {
if (statusUpdate?.fan) {
setMiscData((prevData) => ({
...prevData,
fan: statusUpdate.fan
}))
setFanSpeed(statusUpdate.fan.speed)
}
if (statusUpdate?.['heater_fan nozzle_cooling_fan']) {
setMiscData((prevData) => ({
...prevData,
heaterFan: statusUpdate['heater_fan nozzle_cooling_fan']
}))
}
if (statusUpdate?.['output_pin LCD_backlight_pin']) {
setMiscData((prevData) => ({
...prevData,
ledBacklight: statusUpdate['output_pin LCD_backlight_pin'].value
}))
setLedBrightness(statusUpdate['output_pin LCD_backlight_pin'].value)
}
if (statusUpdate?.['output_pin BEEPER_pin']) {
setMiscData((prevData) => ({
...prevData,
beeper: statusUpdate['output_pin BEEPER_pin']
}))
setBeeperValue(statusUpdate['output_pin BEEPER_pin'].value)
}
if (statusUpdate?.['filament_switch_sensor fsensor']) {
setMiscData((prevData) => ({
...prevData,
filamentSensor: {
enabled: statusUpdate['filament_switch_sensor fsensor'].enabled,
filamentDetected:
statusUpdate['filament_switch_sensor fsensor'].filament_detected
}
}))
}
}
if (!initialized && printServer.connected) {
setInitialized(true)
printServer.on('connect', () => {
printServer.emit('printer.objects.subscribe', params)
printServer.emit('printer.objects.query', params)
}) })
printServer.emit('printer.objects.subscribe', params)
printServer.emit('printer.objects.query', params)
printServer.on('notify_status_update', notifyMiscStatusUpdate)
} }
)
return () => { return () => {
if (printServer.connected && initialized && shouldUnsubscribe) { if (miscEventUnsubscribe) miscEventUnsubscribe()
printServer.off('notify_status_update', notifyMiscStatusUpdate)
printServer.emit('printer.objects.unsubscribe', params)
} }
} }
}, [printServer, initialized, printerId, shouldUnsubscribe]) }, [id, connected, subscribeToObjectEvent])
useEffect(() => {
if (miscData.fan?.speed !== undefined) {
setFanSpeed(miscData.fan.speed)
}
if (miscData.lcdBacklight?.brightness !== undefined) {
setLcdBrightness(miscData.lcdBacklight.brightness)
}
if (miscData.beeper?.value !== undefined) {
setBeeperValue(miscData.beeper.value)
}
}, [
miscData.fan?.speed,
miscData.lcdBacklight?.brightness,
miscData.beeper?.value
])
const handleSetFanSpeed = (value) => { const handleSetFanSpeed = (value) => {
if (printServer) { if (id && connected == true) {
printServer.emit('printer.gcode.script', { sendObjectAction(id, 'printer', {
printerId, type: 'gcodeScript',
data: {
script: `M106 S${Math.round(value * 255)}` script: `M106 S${Math.round(value * 255)}`
}
}) })
} }
} }
const handleSetLedBrightness = (value) => { const handleSetLcdBrightness = (value) => {
if (printServer) { if (id && connected == true) {
printServer.emit('printer.gcode.script', { sendObjectAction(id, 'printer', {
printerId, type: 'gcodeScript',
script: `SET_LED LED=led_backlight BRIGHTNESS=${value}` data: {
script: `SET_LCD LCD=lcd_backlight BRIGHTNESS=${value}`
}
}) })
} }
} }
const handleSetBeeperValue = (value) => { const handleSetBeeperValue = (value) => {
if (printServer) { if (id && connected == true) {
printServer.emit('printer.gcode.script', { sendObjectAction(id, 'printer', {
printerId, type: 'gcodeScript',
data: {
script: `M300 S440 P200 V${Math.round(value * 100)}` script: `M300 S440 P200 V${Math.round(value * 100)}`
}
}) })
} }
} }
@ -156,14 +124,14 @@ const PrinterMiscPanel = ({
tooltip={{ open: false }} tooltip={{ open: false }}
/> />
<Text>LED Backlight: {Math.round(ledBrightness * 100)}%</Text> <Text>LCD Backlight: {Math.round(lcdBrightness * 100)}%</Text>
<Slider <Slider
value={ledBrightness} value={lcdBrightness}
min={0} min={0}
max={1} max={1}
step={0.01} step={0.01}
onChange={setLedBrightness} onChange={setLcdBrightness}
onAfterChange={handleSetLedBrightness} onAfterChange={handleSetLcdBrightness}
tooltip={{ open: false }} tooltip={{ open: false }}
/> />
@ -201,9 +169,9 @@ const PrinterMiscPanel = ({
)} )}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Nozzle Cooling Fan'> <Descriptions.Item label='Nozzle Cooling Fan'>
{miscData.heaterFan.speed > 0 ? ( {miscData.coolingFan.speed > 0 ? (
<Text> <Text>
Running ({Math.round(miscData.heaterFan.speed * 100)}%) Running ({Math.round(miscData.coolingFan.speed * 100)}%)
</Text> </Text>
) : ( ) : (
<Text>Off</Text> <Text>Off</Text>
@ -222,9 +190,8 @@ const PrinterMiscPanel = ({
} }
PrinterMiscPanel.propTypes = { PrinterMiscPanel.propTypes = {
printerId: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
showControls: PropTypes.bool, showControls: PropTypes.bool
shouldUnsubscribe: PropTypes.bool
} }
export default PrinterMiscPanel export default PrinterMiscPanel

View File

@ -10,7 +10,6 @@ import {
Card, Card,
message // eslint-disable-line message // eslint-disable-line
} from 'antd' } from 'antd'
import { PrintServerContext } from '../context/PrintServerContext'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import LevelBedIcon from '../../Icons/LevelBedIcon' import LevelBedIcon from '../../Icons/LevelBedIcon'
import ArrowLeftIcon from '../../Icons/ArrowLeftIcon' import ArrowLeftIcon from '../../Icons/ArrowLeftIcon'
@ -18,14 +17,12 @@ import ArrowRightIcon from '../../Icons/ArrowRightIcon'
import ArrowUpIcon from '../../Icons/ArrowUpIcon' import ArrowUpIcon from '../../Icons/ArrowUpIcon'
import ArrowDownIcon from '../../Icons/ArrowDownIcon' import ArrowDownIcon from '../../Icons/ArrowDownIcon'
import HomeIcon from '../../Icons/HomeIcon' import HomeIcon from '../../Icons/HomeIcon'
import { ApiServerContext } from '../context/ApiServerContext'
const PrinterMovementPanel = ({ printerId }) => { const PrinterMovementPanel = ({ id }) => {
const { connected, sendObjectAction } = useContext(ApiServerContext)
const [posValue, setPosValue] = useState(10) const [posValue, setPosValue] = useState(10)
const [rateValue, setRateValue] = useState(1000) const [rateValue, setRateValue] = useState(1000)
const { printServer } = useContext(PrintServerContext)
//const messageApi = message.useMessage()
const handlePosRadioChange = (e) => { const handlePosRadioChange = (e) => {
const value = e.target.value const value = e.target.value
setPosValue(value) // Update posValue state when radio button changes setPosValue(value) // Update posValue state when radio button changes
@ -40,20 +37,26 @@ const PrinterMovementPanel = ({ printerId }) => {
} }
const handleHomeAxisClick = (axis) => { const handleHomeAxisClick = (axis) => {
if (printServer) { if (id && connected == true) {
printServer.emit('printer.gcode.script', { sendObjectAction(id, 'printer', {
printerId, type: 'homeAxis',
script: `G28 ${axis}` data: {
axis: axis
}
}) })
} }
} }
const handleMoveAxisClick = (axis, minus) => { const handleMoveAxisClick = (axis, minus) => {
const distanceValue = !minus ? posValue * -1 : posValue const distanceValue = !minus ? posValue * -1 : posValue
if (printServer) { if (id && connected == true) {
printServer.emit('printer.gcode.script', { sendObjectAction(id, 'printer', {
printerId, type: 'moveAxis',
script: `_CLIENT_LINEAR_MOVE ${axis}=${distanceValue} F=${rateValue}` data: {
axis: axis,
distance: distanceValue,
rate: rateValue
}
}) })
} }
//sendCommand('moveAxis', { axis, pos, rate }) //sendCommand('moveAxis', { axis, pos, rate })
@ -93,7 +96,7 @@ const PrinterMovementPanel = ({ printerId }) => {
return ( return (
<div style={{ minWidth: 190 }}> <div style={{ minWidth: 190 }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'} align='center'>
<Flex horizontal='true' gap='small'> <Flex horizontal='true' gap='small'>
<Card size='small' title='XY'> <Card size='small' title='XY'>
<Flex <Flex
@ -211,23 +214,21 @@ const PrinterMovementPanel = ({ printerId }) => {
min={0.1} min={0.1}
max={100} max={100}
value={posValue} value={posValue}
formatter={(value) => `${value} mm`} suffix='mm'
parser={(value) => value?.replace(' mm', '')}
onChange={handlePosInputChange} onChange={handlePosInputChange}
placeholder='10 mm' placeholder='10 mm'
name='posInput' name='posInput'
style={{ flexGrow: 1 }} style={{ flexGrow: 1, minWidth: '125px' }}
/> />
<InputNumber <InputNumber
min={1} min={1}
max={5000} max={5000}
value={rateValue} value={rateValue}
formatter={(value) => `${value} mm/s`} suffix='mm/s'
parser={(value) => value?.replace(' mm/s', '')}
onChange={handleRateInputChange} onChange={handleRateInputChange}
placeholder='100 mm/s' placeholder='100 mm/s'
name='rateInput' name='rateInput'
style={{ flexGrow: 1 }} style={{ flexGrow: 1, minWidth: '125px' }}
/> />
</Flex> </Flex>
</Flex> </Flex>
@ -237,7 +238,7 @@ const PrinterMovementPanel = ({ printerId }) => {
} }
PrinterMovementPanel.propTypes = { PrinterMovementPanel.propTypes = {
printerId: PropTypes.string.isRequired id: PropTypes.string.isRequired
} }
export default PrinterMovementPanel export default PrinterMovementPanel

View File

@ -7,14 +7,16 @@ import {
Collapse, Collapse,
InputNumber, InputNumber,
Descriptions, Descriptions,
Button Button,
Divider
} from 'antd' } from 'antd'
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons' import { LoadingOutlined, CaretRightOutlined } from '@ant-design/icons'
import { PrintServerContext } from '../context/PrintServerContext' import { ApiServerContext } from '../context/ApiServerContext'
import styled from 'styled-components' import styled from 'styled-components'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import BoolDisplay from './BoolDisplay' import BoolDisplay from './BoolDisplay'
import merge from 'lodash/merge'
import { round } from '../utils/Utils'
const { Text } = Typography const { Text } = Typography
const CustomCollapse = styled(Collapse)` const CustomCollapse = styled(Collapse)`
@ -29,91 +31,151 @@ const CustomCollapse = styled(Collapse)`
` `
const PrinterPositionPanel = ({ const PrinterPositionPanel = ({
printerId, id,
showControls = true, showControls = true,
showMoreInfo = true, showMoreInfo = true
shouldUnsubscribe = true
}) => { }) => {
const { subscribeToObjectEvent, connected, sendObjectAction } =
useContext(ApiServerContext)
const [positionData, setPositionData] = useState({ const [positionData, setPositionData] = useState({
speed_factor: 1.0, // eslint-disable-line speedFactor: 1.0, // eslint-disable-line
speed: 100, speed: 100,
extrude_factor: 1.0, // eslint-disable-line extrudeFactor: 1.0, // eslint-disable-line
absolute_foordinates: true, // eslint-disable-line absoluteCoordinates: true, // eslint-disable-line
absolute_extrude: false, // eslint-disable-line absoluteExtrude: false, // eslint-disable-line
homing_origin: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line homingOrigin: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line
position: [0.0, 0.0, 0.0, 0.0], toolheadPosition: [0.0, 0.0, 0.0, 0.0],
gcode_position: [0.0, 0.0, 0.0, 0.0] // eslint-disable-line gcodePosition: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line
livePosition: [0.0, 0.0, 0.0, 0.0],
maxVelocity: 1000,
maxAcceleration: 1000,
squareCornerVelocity: 100,
minCruiseRatio: 0
}) })
const [initialized, setInitialized] = useState(false) useEffect(() => {
const { printServer } = useContext(PrintServerContext) if (id && connected == true) {
const [speedFactor, setSpeedFactor] = useState(positionData.speed_factor) console.log('subscribing to motion event')
const [extrudeFactor, setExtrudeFactor] = useState( const motionEventUnsubscribe = subscribeToObjectEvent(
positionData.extrude_factor id,
'printer',
'motion',
(event) => {
console.log('motion event', event)
setPositionData((prev) => {
const merged = merge({}, prev, event.data)
return merged
})
}
)
return () => {
if (motionEventUnsubscribe) motionEventUnsubscribe()
}
}
}, [id, connected])
const [speedFactor, setSpeedFactor] = useState(positionData.speedFactor)
const [extrudeFactor, setExtrudeFactor] = useState(positionData.extrudeFactor)
const [maxVelocity, setMaxVelocity] = useState(positionData.maxVelocity)
const [maxAcceleration, setMaxAcceleration] = useState(
positionData.maxAcceleration
)
const [squareCornerVelocity, setSquareCornerVelocity] = useState(
positionData.squareCornerVelocity
)
const [minCruiseRatio, setMinCruiseRatio] = useState(
positionData.minCruiseRatio
) )
useEffect(() => { useEffect(() => {
const params = { if (positionData.speedFactor !== undefined) {
printerId, setSpeedFactor(positionData.speedFactor)
objects: {
toolhead: null,
gcode_move: null // eslint-disable-line
} }
if (positionData.extrudeFactor !== undefined) {
setExtrudeFactor(positionData.extrudeFactor)
} }
if (positionData.maxVelocity !== undefined) {
const notifyPositionStatusUpdate = (statusUpdate) => { setMaxVelocity(positionData.maxVelocity)
if (statusUpdate?.toolhead) {
setPositionData((prevData) => ({
...prevData,
...statusUpdate.toolhead
}))
} }
if (statusUpdate?.gcode_move) { if (positionData.maxAcceleration !== undefined) {
setPositionData((prevData) => ({ setMaxAcceleration(positionData.maxAcceleration)
...prevData,
...statusUpdate.gcode_move
}))
} }
if (positionData.squareCornerVelocity !== undefined) {
setSquareCornerVelocity(positionData.squareCornerVelocity)
} }
if (positionData.minCruiseRatio !== undefined) {
if (!initialized && printServer?.connected) { setMinCruiseRatio(positionData.minCruiseRatio)
setInitialized(true)
printServer.on('connect', () => {
printServer.emit('printer.objects.subscribe', params)
printServer.emit('printer.objects.query', params)
})
printServer.emit('printer.objects.subscribe', params)
printServer.emit('printer.objects.query', params)
printServer.on('notify_status_update', notifyPositionStatusUpdate)
} }
}, [
setSpeedFactor(positionData.speed_factor) positionData.speedFactor,
setExtrudeFactor(positionData.extrude_factor) positionData.extrudeFactor,
positionData.maxVelocity,
return () => { positionData.maxAcceleration,
if (printServer?.connected && initialized && shouldUnsubscribe) { positionData.squareCornerVelocity,
printServer.off('notify_status_update', notifyPositionStatusUpdate) positionData.minCruiseRatio
printServer.emit('printer.objects.unsubscribe', params) ])
}
}
}, [printServer, initialized, printerId, shouldUnsubscribe])
const handleSetSpeedFactor = () => { const handleSetSpeedFactor = () => {
if (printServer) { if (id && connected == true) {
printServer.emit('printer.gcode.script', { sendObjectAction(id, 'printer', {
printerId, type: 'setSpeedFactor',
script: `M220 S${speedFactor * 100}` data: {
speedFactor: speedFactor * 100
}
}) })
} }
} }
const handleSetExtrudeFactor = () => { const handleSetExtrudeFactor = () => {
if (printServer) { if (id && connected == true) {
printServer.emit('printer.gcode.script', { sendObjectAction(id, 'printer', {
printerId, type: 'setExtrudeFactor',
script: `M221 S${extrudeFactor * 100}` data: {
extrudeFactor: extrudeFactor * 100
}
})
}
}
const handleSetMaxVelocity = () => {
if (id && connected == true) {
sendObjectAction(id, 'printer', {
type: 'setMaxVelocity',
data: {
maxVelocity: maxVelocity
}
})
}
}
const handleSetMaxAcceleration = () => {
if (id && connected == true) {
sendObjectAction(id, 'printer', {
type: 'setMaxAcceleration',
data: {
maxAcceleration: maxAcceleration
}
})
}
}
const handleSetSquareCornerVelocity = () => {
if (id && connected == true) {
sendObjectAction(id, 'printer', {
type: 'setSquareCornerVelocity',
data: {
squareCornerVelocity: squareCornerVelocity
}
})
}
}
const handleSetMinCruiseRatio = () => {
if (id && connected == true) {
sendObjectAction(id, 'printer', {
type: 'setMinCruiseRatio',
data: {
minCruiseRatio: minCruiseRatio
}
}) })
} }
} }
@ -124,22 +186,132 @@ const PrinterPositionPanel = ({
label: 'More Position Data', label: 'More Position Data',
children: ( children: (
<> <>
<Divider style={{ margin: '0 0 12px 0' }} />
<Flex vertical gap={'middle'}> <Flex vertical gap={'middle'}>
<Text>GCode Position:</Text> <Text>GCode Position:</Text>
<Descriptions column={1} size='small' bordered> <Descriptions column={1} size='small' bordered>
<Descriptions.Item label='X'> <Descriptions.Item label='X'>
{positionData.gcode_position[0].toFixed(2)}mm {' '}
{round(positionData.gcodePosition[0], 2)}mm
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Y'> <Descriptions.Item label='Y'>
{positionData.gcode_position[1].toFixed(2)}mm {round(positionData.gcodePosition[1], 2)}mm
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Z'> <Descriptions.Item label='Z'>
{positionData.gcode_position[2].toFixed(2)}mm {round(positionData.gcodePosition[2], 2)}mm
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='E'> <Descriptions.Item label='E'>
{positionData.gcode_position[3].toFixed(2)}mm {round(positionData.gcodePosition[3], 2)}mm
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
{showControls && (
<>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Max Velocity:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(maxVelocity, 2)}
min={1}
max={10000}
step={5}
style={{ width: '125px' }}
suffix='mm/s'
onChange={(value) => setMaxVelocity(value)}
onPressEnter={handleSetMaxVelocity}
size='small'
/>
<Button
type='default'
style={{ width: 40 }}
onClick={handleSetMaxVelocity}
>
Set
</Button>
</Space.Compact>
</Space>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Max Acceleration:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(maxAcceleration, 2)}
min={1}
max={10000}
step={5}
style={{ width: '125px' }}
suffix='mm/s²'
onChange={(value) => setMaxAcceleration(value)}
onPressEnter={handleSetMaxAcceleration}
size='small'
/>
<Button
type='default'
style={{ width: 40 }}
onClick={handleSetMaxAcceleration}
>
Set
</Button>
</Space.Compact>
</Space>
</Space>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Sqr Corner Vel:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(squareCornerVelocity, 2) || 0}
min={0.1}
max={1000}
step={0.1}
suffix='mm/s'
style={{ width: '125px' }}
onChange={(value) => setSquareCornerVelocity(value)}
onPressEnter={handleSetSquareCornerVelocity}
size='small'
/>
<Button
type='default'
style={{ width: 40 }}
onClick={handleSetSquareCornerVelocity}
>
Set
</Button>
</Space.Compact>
</Space>
</Space>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Min Cruise Ratio:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(minCruiseRatio * 100, 2) || 0}
min={0}
max={100}
step={1}
suffix='%'
style={{ width: '125px' }}
onChange={(value) => setMinCruiseRatio(value / 100)}
onPressEnter={handleSetMinCruiseRatio}
size='small'
/>
<Button
type='default'
style={{ width: 40 }}
onClick={handleSetMinCruiseRatio}
>
Set
</Button>
</Space.Compact>
</Space>
</Space>
</Space>
</>
)}
<Text>Homing Origin:</Text> <Text>Homing Origin:</Text>
<Descriptions <Descriptions
column={1} column={1}
@ -148,16 +320,16 @@ const PrinterPositionPanel = ({
style={{ flexGrow: 1 }} style={{ flexGrow: 1 }}
> >
<Descriptions.Item label='X' span={1}> <Descriptions.Item label='X' span={1}>
{positionData.homing_origin[0].toFixed(2)}mm {round(positionData.homingOrigin[0], 2)}mm
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Y' span={1}> <Descriptions.Item label='Y' span={1}>
{positionData.homing_origin[1].toFixed(2)}mm {round(positionData.homingOrigin[1], 2)}mm
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Z' span={1}> <Descriptions.Item label='Z' span={1}>
{positionData.homing_origin[2].toFixed(2)}mm {round(positionData.homingOrigin[2], 2)}mm
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='E'> <Descriptions.Item label='E'>
{positionData.homing_origin[3].toFixed(2)}mm {round(positionData.homingOrigin[3], 2)}mm
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
</Flex> </Flex>
@ -173,16 +345,36 @@ const PrinterPositionPanel = ({
<Flex vertical gap={'middle'}> <Flex vertical gap={'middle'}>
<Descriptions column={1} size='small' bordered> <Descriptions column={1} size='small' bordered>
<Descriptions.Item label='X'> <Descriptions.Item label='X'>
{positionData.position[0].toFixed(2)}mm <Space>
<Text>{round(positionData.livePosition[0], 2)}mm</Text>
<Text type='secondary'>
{round(positionData.toolheadPosition[0], 2)}mm
</Text>
</Space>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Y'> <Descriptions.Item label='Y'>
{positionData.position[1].toFixed(2)}mm <Space>
<Text>{round(positionData.livePosition[1], 2)}mm</Text>
<Text type='secondary'>
{round(positionData.toolheadPosition[1], 2)}mm
</Text>
</Space>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Z'> <Descriptions.Item label='Z'>
{positionData.position[2].toFixed(2)}mm <Space>
<Text>{round(positionData.livePosition[2], 2)}mm</Text>
<Text type='secondary'>
{round(positionData.toolheadPosition[2], 2)}mm
</Text>
</Space>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='E'> <Descriptions.Item label='E'>
{positionData.position[3].toFixed(2)}mm <Space>
<Text>{round(positionData.livePosition[3], 2)}mm</Text>
<Text type='secondary'>
{round(positionData.toolheadPosition[3], 2)}mm
</Text>
</Space>
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
{showControls && ( {showControls && (
@ -192,11 +384,12 @@ const PrinterPositionPanel = ({
<Text>Speed Factor:</Text> <Text>Speed Factor:</Text>
<Space.Compact block size='small'> <Space.Compact block size='small'>
<InputNumber <InputNumber
value={speedFactor.toFixed(2)} value={round(speedFactor, 2)}
min={0.1} min={0.1}
max={2} max={2}
step={0.1} step={0.1}
style={{ width: '100px' }} style={{ width: '125px' }}
suffix='%'
onChange={(value) => setSpeedFactor(value)} onChange={(value) => setSpeedFactor(value)}
onPressEnter={handleSetSpeedFactor} onPressEnter={handleSetSpeedFactor}
size='small' size='small'
@ -215,11 +408,12 @@ const PrinterPositionPanel = ({
<Text>Extrude Factor:</Text> <Text>Extrude Factor:</Text>
<Space.Compact block size='small'> <Space.Compact block size='small'>
<InputNumber <InputNumber
value={extrudeFactor.toFixed(2)} value={round(extrudeFactor, 2)}
min={0.1} min={0.1}
max={2} max={2}
step={0.1} step={0.1}
style={{ width: '100px' }} style={{ width: '125px' }}
suffix='%'
onChange={(value) => setExtrudeFactor(value)} onChange={(value) => setExtrudeFactor(value)}
onPressEnter={handleSetExtrudeFactor} onPressEnter={handleSetExtrudeFactor}
size='small' size='small'
@ -237,13 +431,23 @@ const PrinterPositionPanel = ({
</> </>
)} )}
<Descriptions column={1} size='small' bordered> <Descriptions column={1} size='small' bordered>
<Descriptions.Item label='Current Speed'> <Descriptions.Item label='Speed'>
{positionData.speed.toFixed(2)}mm/s {round(positionData.speed, 2)}mm/s
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Absolute Coordinates'> <Descriptions.Item label='Abs Coor'>
{positionData ? ( {positionData ? (
<BoolDisplay <BoolDisplay
value={positionData.absolute_coordinates} value={positionData.absoluteCoordinates}
yesNo={true}
/>
) : (
<Text>n/a</Text>
)}
</Descriptions.Item>
<Descriptions.Item label='Abs Extrude'>
{positionData ? (
<BoolDisplay
value={positionData.absoluteExtrude}
yesNo={true} yesNo={true}
/> />
) : ( ) : (
@ -259,7 +463,7 @@ const PrinterPositionPanel = ({
size='small' size='small'
items={moreInfoItems} items={moreInfoItems}
expandIcon={({ isActive }) => ( expandIcon={({ isActive }) => (
<CaretLeftOutlined rotate={isActive ? 90 : 0} /> <CaretRightOutlined rotate={isActive ? 90 : 0} />
)} )}
/> />
)} )}
@ -274,10 +478,9 @@ const PrinterPositionPanel = ({
} }
PrinterPositionPanel.propTypes = { PrinterPositionPanel.propTypes = {
printerId: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
showControls: PropTypes.bool, showControls: PropTypes.bool,
showMoreInfo: PropTypes.bool, showMoreInfo: PropTypes.bool
shouldUnsubscribe: PropTypes.bool
} }
export default PrinterPositionPanel export default PrinterPositionPanel

View File

@ -8,7 +8,8 @@ import {
Space, Space,
Collapse, Collapse,
InputNumber, InputNumber,
Button Button,
Divider
} from 'antd' } from 'antd'
import { LoadingOutlined, CaretRightOutlined } from '@ant-design/icons' import { LoadingOutlined, CaretRightOutlined } from '@ant-design/icons'
import styled from 'styled-components' import styled from 'styled-components'
@ -113,6 +114,7 @@ const PrinterTemperaturePanel = ({
label: 'More Temperature Data', label: 'More Temperature Data',
children: ( children: (
<> <>
<Divider style={{ margin: '0 0 12px 0' }} />
<Flex vertical gap={0}> <Flex vertical gap={0}>
<Text> <Text>
Hot End Power:{' '} Hot End Power:{' '}

View File

@ -30,5 +30,9 @@ export function timeStringToMinutes(timeString) {
return Math.floor(totalMinutes) return Math.floor(totalMinutes)
} }
export function round(num, decimals) {
return Math.round(num * 10 ** decimals) / 10 ** decimals
}
// Re-export the functions for backward compatibility // Re-export the functions for backward compatibility
export {} export {}