forked from w-A-L-L-e/printerface
-
Notifications
You must be signed in to change notification settings - Fork 0
/
printerface.js
369 lines (316 loc) · 13.1 KB
/
printerface.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
// ============================= Printerface ===================================
// Author : Walter Schreppers
// Description : Web interface to upload gcode files that are then transferred
// to usb-serial connected sanguinulolu. For 3D printing or cnc.
// Kicked out the direct serial connect and interface with pronsole/printrun instead
// Make sure you have it installed in /home/pi/printrun/pronsole.py
// That fixed an issue, sometimes on restart
// Lot's of todo's like progress, temperatature monitoring etc.
// adding jquery mobile theme etc....
var port = 8080; //make this anything you want (mind that you need to sudo if you want port 80)
var formidable = require('formidable'); //file uploads + forms are easy with formidable
var http = require('http'); //the http server
//var sys = require("sys"); //for system calls
var util = require('util'); //replaces sys
var fs = require('fs'); //moving files
var menu_items = ['home', 'printer', 'files', 'about'];
var command_output = ''; //this will contain output of commands that we're run with runCommand fuction...
var files = []; //array of files uploaded
//we need to just to interface with pronsole.py that works perfectly !
var spawn = require('child_process').spawn;
///home/pi/printrun/pronsole.py
//var pronsole = spawn('python', ['/home/pi/printrun/test2.py','']);
var pronsole = spawn('python', ['/home/pi/printrun/pronsole.py','']);
//in future we might use the serialport directly here...
//var repl = require("repl"); //for having interactive shell
//var serialport = require("serialport"); //connecto to our arduino or sanguinulolu based 3d printer here !
//var SerialPort = serialport.SerialPort; // localize object constructor for serial interface
function menu_item( response, item ){
response.write( '<td align="center"><b><a href="/'+item+'">'+item+'</a></b></td>');
}
function menu( response ){
response.write('<tr>');
for( i=0;i<menu_items.length;i++){
menu_item( response, menu_items[i] );
}
response.write('</tr>');
response.write('<tr><td colspan="'+menu_items.length.toString()+'" height="400" valign="top" padding="10px">');
}
function header( response ){
response.writeHead(200, {'content-type': 'text/html'});
response.write('<html><body bgcolor="#888888" color="#224422" link="#224422" vlink="#228822" style="background-image:url(images/background.jpg)">'); //background does not work, again we don't care much about styling now (we will use express js in future ...).
response.write('<center><table class="layout" border="1" width="800" bgcolor="#EEEEEE">');
response.write('<tr><td colspan="'+menu_items.length.toString()+'"><h1>Printerface for Raspberry Pi</h1></td></tr>');
menu( response );
}
function footer( response ){
response.write( '</td></tr>');
response.write('<tr> <td colspan="2"> Server port = '+ port.toString() +' </td> <td colspan="'+(menu_items.length-2).toString()+'"> Author: Walter Schreppers</td></tr>')
response.write('</table></center></body></html>' );
response.end();
}
function showAboutPage( response ){
header( response );
response.write('Written on a sunday by Walter Schreppers<br/>Why? Because : YES we can! <br/> Ow and yeah because it\'s cool: <br/>1. Print anywhere in the world to your reprap at home! <br/> 2. Stop messing with swapping SD cards just upload and print. <br/>3. Build farms of bots all controllable from a single server etc...');
}
function showUploadForm( res ){
// show a file upload form
header( res );
res.write('Upload a file for printing');
res.write(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
}
//is only used for showing after upload... todo change this mess ;)
function showPrintPage( response ){
//header( res );
showUploadForm( response );
response.write('todo connect to serial here...');
}
//actual page to control our printer with pronsole ;)
function showPrinterPage( res ){
//start pronsole
//reset printer
//show some links here
header( res );
res.write( '<center>' );
res.write( '<table width="780px">');
res.write( '<tr> <td> <a href="connect">Connect</a> </td><td> </td> <td> </td> <td> </td>'+
'<td> <a href="disconnect">Disconnect</a></td> </tr>' );
res.write( '<tr> <td> </td></tr>' );
res.write( '<tr> <td> </td> <td> <a href="moveforward">^ forward</a> </td></tr>' );
res.write( '<tr> <td> </td><td> </td><td> </td> <td> <a href="moveup">Move up ^</a> </td></tr>' );
res.write( '<tr> <td> <a href="moveleft"><- left</a> </td> <td> </td> <td> <a href="moveright">right -></a> </td> </tr>' );
res.write( '<tr> <td> </td><td> </td><td> </td> <td> <a href="movedown">Move down ^</a> </td></tr>' );
res.write( '<tr> <td> </td><td><a href="moveback">v backward</a> </td></tr>' );
res.write( '<tr> <td> </td></tr>' );
res.write( '<tr> <td> <a href="homex">Home X axis </a> </td></tr>' );
res.write( '<tr> <td> <a href="homey">Home Y axis </a> </td></tr>' );
res.write( '<tr> <td> <a href="homez">Home Z axis </a> </td></tr>' );
res.write( '<tr> <td> </td></tr>' );
res.write( '<tr><td> <a href="heaton">Heat Extruder to 190 degrees</a> </td><td> <a href="/heatoff">Extr Heat OFF</a> </td></tr>'+
'<tr><td> <a href="heatbed">Heat Bed to 55 degrees</a> </td><td> <a href="/bedoff">Bed Heat OFF</a> </td></tr>'+
'<tr><td> <a href="extrude">Extrude 5mm</a> </td><td> <a href="retract">Retract 5mm</a> </td></tr>'+
'<tr><td><a href="/printfile">PRINT G-CODE!</a> </td></tr>' );
res.write('</table>');
res.write('</center>');
//todo show snapshot of printer here or status or stuff...
footer(res);
}
//todo add some checks in future here, for now it does the job ;)
function moveFile( source_file, target_file ){
var is = fs.createReadStream(source_file)
var os = fs.createWriteStream(target_file);
util.pump(is, os, function() {
fs.unlinkSync( source_file );
//we update the directory after the move...
runCommand( 'ls', '-tr1', '/home/pi/printerface/gcode_uploads' );
});
//the fs.rename does not work for me, i want to move from /tmp to a different dir in /home
//move temp file into gcode_uploads dir with original filename
//fs.rename( tempfile, targetfile, function(error){
// if( error ){
// res.write('Oops could not move uploaded file');
// return;
// }
// res.write('thanks, all done!');
//} );
}
//needs both request and response vars (request to get file data, response to show results...)
function parseFileUpload( req, res ){
// parse a file upload
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
//res.writeHead(200, {'content-type': 'text/plain'});
showPrintPage( res );
//header( res );
res.write('<pre>\n');
//res.write(util.inspect({fields: fields, files: files})); //handy snippet to show the fields submitted
var tempfile = files['upload']['path'];
var targetfile = '/home/pi/printerface/gcode_uploads/'+files['upload']['name'];
moveFile( tempfile, targetfile );
res.write('Thanks for the upload. saved file to:'+targetfile);
res.write('</pre>\n');
//res.end('');
//now move the file into gcode_uploads
footer( res );
});
}
function runCommand( command, args, dir ){
//var spawn = require('child_process').spawn;
var command = spawn(command, [args, dir]);
command_output = '';
command.stdout.on('data', function (data) {
console.log('stdout: ' + data);
command_output = command_output+ data;
});
command.stderr.on('data', function (data) {
//console.log('stderr: ' + data);
command_output = command_output + data;
});
command.on('exit', function (code) {
//console.log('child process exited with code ' + code);
files = command_output.toString().split('\n');
files.splice(files.length-1,1); //removes last empty entry here...
});
}
//everything is async, this kinda sucks here, we need to call this thing even before we go to the page... test it now here use a global var here...
function showFilesPage( response ){
header( response );
response.write('<pre>');
response.write( command_output );
response.write('</pre>');
footer( response );
}
var printserver = http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
parseFileUpload( req, res );
return; //making it trickle down does not seem to work here???
}
else if( req.url == '/about' ){
showAboutPage( res );
}
else if( req.url == '/print' ){
showPrintPage( res );
}
else if( req.url == '/printer' ){
showPrinterPage( res );
}
else if( req.url == '/connect' ){
console.log('-- connect --');
pronsole.stdin.write('connect\n');
showPrinterPage( res );
}
else if( req.url == '/disconnect' ){
console.log('-- disconnect --');
pronsole.stdin.write('disconnect\n');
showPrinterPage( res );
}
else if( req.url == '/moveleft' ){
console.log('-- move left --');
pronsole.stdin.write('move x -10\n');
showPrinterPage( res );
}
else if( req.url == '/moveright' ){
console.log('-- move right --');
pronsole.stdin.write('move x 10\n');
showPrinterPage( res );
}
else if( req.url == '/moveup' ){
console.log('-- move up --');
pronsole.stdin.write('move z 10\n');
showPrinterPage( res );
}
else if( req.url == '/movedown' ){
console.log('-- move down --');
pronsole.stdin.write('move z -10\n');
showPrinterPage( res );
}
else if( req.url == '/moveback' ){
console.log('-- move backward --');
pronsole.stdin.write('move y -10\n');
showPrinterPage( res );
}
else if( req.url == '/moveforward' ){
console.log('-- move forward ==');
pronsole.stdin.write('move y 10\n');
showPrinterPage( res );
}
else if( req.url == '/homex' ){
console.log('home x');
pronsole.stdin.write('home x\n');
showPrinterPage( res );
}
else if( req.url == '/homey' ){
console.log('home y');
pronsole.stdin.write('home y\n');
showPrinterPage( res );
}
else if( req.url == '/homez' ){
console.log('home z');
pronsole.stdin.write('home z\n');
showPrinterPage( res );
}
else if( req.url == '/heaton' ){
console.log('setting heat to 190 degrees');
pronsole.stdin.write('settemp 190\n');
showPrinterPage( res );
}
else if( req.url == '/heatbed' ){
console.log('setting bedtemp to 55 degrees');
pronsole.stdin.write('bedtemp 55\n');
showPrinterPage( res );
}
else if( req.url == '/extrude' ){
console.log('extrude 5mm filament');
pronsole.stdin.write('extrude 5\n');
showPrinterPage( res );
}
else if( req.url == '/retract' ){
console.log('retract 5mm filament');
pronsole.stdin.write('extrude -5\n');
showPrinterPage( res );
}
else if( req.url == '/printfile' ){
var lastfile = files[files.length-1].toString();
console.log('last file='+lastfile +"\n");
pronsole.stdin.write( 'load /home/pi/printerface/gcode_uploads/'+lastfile+"\n" );
pronsole.stdin.write( 'print\n' );
showPrinterPage( res );
}
else if( req.url == '/heatoff' ){
console.log('setting extruder temp off!');
pronsole.stdin.write( 'settemp 0\n' );
showPrinterPage( res );
}
else if( req.url == '/bedoff' ){
console.log('setting bed temp off!');
pronsole.stdin.write( 'bedtemp 0\n' );
showPrinterPage( res );
}
else if( req.url == '/files' ){
showFilesPage( res );
}
else{ //the home is show upload form for uploading gcode file to print ;)
showUploadForm( res );
}
footer( res );
});
//todo make it somehow different here...
//this makes the list of uploaded files available
runCommand( 'ls', '-tr1', '/home/pi/printerface/gcode_uploads' );
console.log('pronsole.py is spawned, waiting 3 seconds and sending connect...');
setTimeout( function(){
//calling connect without params here (todo add ttyUSB etc, but hey the defaults work just fine now ;)
pronsole.stdin.write('connect\n');
}, 3000 );
console.log('starting pronsole monitor...');
setTimeout( function(){
//calling connect without params here (todo add ttyUSB etc, but hey the defaults work just fine now ;)
pronsole.stdin.write('monitor\n'); //cool this just works like we want -> need some ajax though to feed it back to the browser...
}, 3000 );
pronsole.stdout.on('data', function (data) {
console.log( 'pronsole: '+data ); //todo use some ajax to feed it to our browser here...
});
pronsole.stderr.on('data', function (data) {
console.log('pronsole err: ' + data);
});
pronsole.stdout.on('end', function(data) {
pronsole.stdout.end();
} );
pronsole.on('exit', function (code) {
if (code !== 0) {
console.log('pronsole process exited with code ' + code);
}
console.log('pronsole exited!');
pronsole.stdin.end();
//todo just respawn pronsole here!!!
});
//Start webserver on port specified here.
printserver.listen(port);
//Start an interactive shell (remove on production, uhu not for this sunday most likely ;))
//repl.start("=>");