Add malyan controls

not styled yet
This commit is contained in:
casperlamboo 2018-01-24 16:03:44 +01:00
parent 6628b9cf13
commit de2acfe6be
4 changed files with 94 additions and 123 deletions

View File

@ -0,0 +1,61 @@
import React from 'react';
import PropTypes from 'proptypes';
import muiThemeable from 'material-ui/styles/muiThemeable';
import injectSheet from 'react-jss';
import FlatButton from 'material-ui/FlatButton';
import { sleep, getMalyanStatus } from './utils.js';
const styles = {
};
class MalyanControl extends React.Component {
static propTypes = {
ip: PropTypes.string.isRequired
};
state = {
status: null,
mounted: true
};
componentDidMount = async () => {
const { ip } = this.props;
while (this.state.mounted) {
const status = await getMalyanStatus(ip).catch(() => null);
this.setState({ status });
await sleep(1000);
}
};
home = () => {
const { ip } = this.props;
fetch(`http://${ip}/set?code=G28`, { method: 'GET' });
};
stop = () => {
const { ip } = this.props;
fetch(`http://${ip}/set?cmd={P:X}`, { method: 'GET' });
};
componentWillUnmount() {
this.setState({ mounted: false });
}
render() {
const { status } = this.state;
return (
<div>
{status && <span>
<p>Nozzle temperature: {status.nozzleTemperature}/{status.nozzleTargetTemperature}</p>
<p>Bed temperature: {status.bedTemperature}/{status.bedTargetTemperature}</p>
{status.state === 'printing' && <p>Progress: {status.progress}%</p>}
</span>}
<FlatButton label="Stop" onTouchTap={this.stop} />
<FlatButton label="Home" onTouchTap={this.home} />
</div>
);
}
}
export default muiThemeable()(injectSheet(styles)(MalyanControl));

View File

@ -14,6 +14,7 @@ import Menu from 'material-ui/Menu';
import MenuItem from 'material-ui/MenuItem';
import { Tabs, Tab } from 'material-ui/Tabs';
import Settings from './Settings.js';
import MalyanControl from './MalyanControl.js';
import ReactResizeDetector from 'react-resize-detector';
import JSONToSketchData from 'doodle3d-core/shape/JSONToSketchData';
import createSceneData from 'doodle3d-core/d3/createSceneData.js';
@ -334,6 +335,7 @@ class Interface extends React.Component {
{isSlicing && <p>{progress.action}</p>}
{isSlicing && <LinearProgress mode="determinate" value={progress.percentage * 100.0} />}
</div>
{settings && settings.printer === 'doodle3d_printer' && <MalyanControl ip={settings.ip} />}
<div className={classes.sliceButtons}>
{onCancel && <RaisedButton
label="Cancel"

View File

@ -115,6 +115,32 @@ export function fetchProgress(url, data = {}, onProgress) {
});
}
export function getMalyanStatus(ip) {
return fetch(`http://${ip}/inquiry`, { method: 'GET' })
.then(response => response.text())
.then(statusText => {
const [nozzleTemperature, nozzleTargetTemperature, bedTemperature, bedTargetTemperature, progress] = statusText.match(/\d+/g);
const status = { nozzleTemperature, nozzleTargetTemperature, bedTemperature, bedTargetTemperature, progress };
switch (statusText.charAt(statusText.length - 1)) {
case 'I':
status.state = 'idle';
break;
case 'P':
status.state = 'printing';
break;
default:
status.state = 'unknown';
break;
}
return status;
})
}
export function sleep(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
const GCODE_SERVER_URL = 'https://gcodeserver.doodle3d.com';
const CONNECT_URL = 'http://connect.doodle3d.com/';
@ -127,6 +153,10 @@ export async function slice(target, name, mesh, settings, updateProgress) {
break;
case 'WIFI':
case 'DOODLE3D-WIFI-BOX':
if (settings.printer === 'doodle3d_printer') {
const { state } = await getMalyanStatus(settings.ip);
if (state !== 'idle') throw { message: 'printer must be idle before starting a print', code: 1 };
}
steps = 2;
break;
default:
@ -161,7 +191,7 @@ export async function slice(target, name, mesh, settings, updateProgress) {
const file = new File([gcode], 'doodle.gcode', { type: 'plain/text' });
body.append('file', file);
await fetchProgress(`http://${settings.ip}/set?code=M563 S4`, { method: 'GET' });
// await fetchProgress(`http://${settings.ip}/set?code=M563 S4`, { method: 'GET' });
await fetchProgress(`http://${settings.ip}/upload`, { method: 'POST', body }, (progress) => {
updateProgress({
action: 'Uploading',

122
test.js
View File

@ -1,122 +0,0 @@
import 'babel-polyfill'
import React from 'react';
import { render } from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';
// import './fetch.js';
injectTapEventPlugin();
const IP = 'http://10.0.0.109';
const DEFAULT_GCODE = `; Generated with Doodle3D Slicer V0.0.18
G28
G1 X30 Y30
G1 X90 Y30
G1 X30 Y30
G1 X90 Y30
G1 X30 Y30
G1 X90 Y30
G1 X30 Y30
G1 X90 Y30
G1 X30 Y30
G1 X90 Y30
G1 X30 Y30
G1 X90 Y30
; test
`;
const CIRCLE = `; Generated with Doodle3D Slicer V0.0.18
G28
G1 X50 Y70
G1 X56.180339887498945 Y69.02113032590307
G1 X61.75570504584947 Y66.18033988749895
G1 X66.18033988749895 Y61.75570504584947
G1 X69.02113032590307 Y56.180339887498945
G1 X70 Y50
G1 X69.02113032590307 Y43.819660112501055
G1 X66.18033988749895 Y38.24429495415054
G1 X61.75570504584947 Y33.819660112501055
G1 X56.18033988749895 Y30.97886967409693
G1 X50 Y30
G1 X43.819660112501055 Y30.978869674096927
G1 X38.24429495415054 Y33.819660112501055
G1 X33.819660112501055 Y38.24429495415053
G1 X30.97886967409693 Y43.81966011250105
G1 X30 Y49.99999999999999
G1 X30.978869674096927 Y56.180339887498945
G1 X33.81966011250105 Y61.75570504584946
G1 X38.24429495415053 Y66.18033988749895
G1 X43.81966011250105 Y69.02113032590307
; test
`;
// export function fetch(url, data = {}, onProgress) {
// return new Promise((resolve, reject) => {
// const request = new Request(url, data);
// const xhr = new XMLHttpRequest();
//
// xhr.onload = () => {
// const { status, statusText, responseURL: url } = xhr;
// resolve(new Response(xhr.response, { status, statusText, url }));
// }
// xhr.onerror = () => reject(new TypeError('Network request failed'));
// xhr.ontimeout = () => reject(new TypeError('Network request failed'));
//
// xhr.open(request.method, url);
//
// if (request.credentials === 'include') {
// xhr.withCredentials = true
// } else if (request.credentials === 'omit') {
// xhr.withCredentials = false
// }
// if (xhr.upload && onProgress) xhr.upload.onprogress = onProgress;
// if (xhr.responseType) xhr.responseType = 'blob';
//
// request.headers.forEach((value, name) => {
// xhr.setRequestHeader(name, value)
// });
//
// xhr.send(data.body);
// });
// }
class Print extends React.Component {
home = () => fetch(`${IP}/set?code=G28`, { method: 'GET', mode: 'no-cors' });
status = () => fetch(`${IP}/inquiry`, { method: 'GET', mode: 'no-cors' })
.then(response => response.text())
.then(result => console.log('result: ', result));
start = () => fetch(`${IP}/set?code=M565`, { method: 'GET', mode: 'no-cors' });
stop = () => fetch(`${IP}/set?cmd={P:X}`, { method: 'GET', mode: 'no-cors' });
upload = async () => {
const gcode = this.refs.gcode.value;
const headers = new Headers();
headers.append('Content-Disposition', 'form-data; name="file"; filename="doodle.gcode"');
headers.append('Content-Type', 'application/octet-stream');
headers.append('Accept', 'application/json');
const body = new FormData();
const file = new File([gcode], 'doodle.gcode', { type: 'application/octet-stream' });
body.append('file', file);
const result = await fetch(`${IP}/upload`, { method: 'POST', mode: 'no-cors', headers, body });
};
render() {
return (
<span>
<button onTouchTap={this.home} type="button">Home</button>
<button onTouchTap={this.status} type="button">Status</button>
<button onTouchTap={this.start} type="button">Start</button>
<button onTouchTap={this.stop} type="button">Stop</button>
<div>
<textarea ref="gcode" cols="80" rows="20" defaultValue={CIRCLE} />
<button onTouchTap={this.upload} type="button">Upload</button>
</div>
</span>
);
}
}
render((
<Print />
), document.getElementById('app'));