9

I am using Raspberry Pi as a web server this web is to control CNC machine as you can see in the following picture.

CNC controller UI

(I took it from git hub)

I can enter the g code manually or I can upload the g code file but now I want to connect this web page to Amazon Web Services IoT to send g code automatically to my page,after a long search i found this link it shows how to connect a web app to AWS IOT , but i think i am still need help with those things because i don't really understand how to apply it . Here is server.js file:

var config = require('./config');
var serialport = require("serialport");
var SerialPort = serialport.SerialPort; // localize object constructor
var app = require('http').createServer(handler)
  , io = require('socket.io').listen(app)
  , fs = require('fs');
var static = require('node-static');
var EventEmitter = require('events').EventEmitter;
var url = require('url');
var qs = require('querystring');
var http = require('http');

// test for webcam
config.showWebCam = false;

http.get('http://127.0.0.1:8080', function(res) {
    // valid response, enable webcam
    console.log('enabling webcam');
    config.showWebCam = true;
}).on('socket', function(socket) {
    // 2 second timeout on this socket
    socket.setTimeout(2000);
    socket.on('timeout', function() {
        this.abort();
    });
}).on('error', function(e) {
    console.log('Got error: '+e.message+' not enabling webcam')
});

app.listen(config.webPort);
var fileServer = new static.Server('./i');

function handler (req, res) {

    //console.log(req.url);

    if (req.url.indexOf('/api/uploadGcode') == 0 && req.method == 'POST') {
        // this is a gcode upload, probably from jscut
        console.log('new data from jscut');
        var b = '';
        req.on('data', function (data) {
            b += data;
            if (b.length > 1e6) {
                req.connection.destroy();
            }
        });
        req.on('end', function() {
            var post = qs.parse(b);
            //console.log(post);
            io.sockets.emit('gcodeFromJscut', {'val':post.val});
            res.writeHead(200, {"Content-Type": "application/json"});
            res.end(JSON.stringify({'data':'ok'}));
        });
    } else {
        fileServer.serve(req, res, function (err, result) {
            if (err) console.log('fileServer error: ',err);
        });
    }
}

function ConvChar( str ) {
  c = {'<':'&lt;', '>':'&gt;', '&':'&amp;', '"':'&quot;', "'":'&#039;',
       '#':'&#035;' };
  return str.replace( /[<&>'"#]/g, function(s) { return c[s]; } );
}

var sp = [];
var allPorts = [];

serialport.list(function (err, ports) {

    // if on rPi - http://www.hobbytronics.co.uk/raspberry-pi-serial-port
    if (fs.existsSync('/dev/ttyAMA0') && config.usettyAMA0 == 1) {
        (ports = ports || []).push({comName:'/dev/ttyAMA0',manufacturer: undefined,pnpId: 'raspberryPi__GPIO'});
        console.log('adding /dev/ttyAMA0 because it is enabled in config.js, you may need to enable it in the os - http://www.hobbytronics.co.uk/raspberry-pi-serial-port');
    }

    allPorts = ports;

    for (var i=0; i<ports.length; i++) {
    !function outer(i){

        sp[i] = {};
        sp[i].port = ports[i].comName;
        sp[i].q = [];
        sp[i].qCurrentMax = 0;
        sp[i].lastSerialWrite = [];
        sp[i].lastSerialReadLine = '';
        // 1 means clear to send, 0 means waiting for response
        sp[i].handle = new SerialPort(ports[i].comName, {
            parser: serialport.parsers.readline("\n"),
            baudrate: config.serialBaudRate
        });
        sp[i].sockets = [];

        sp[i].handle.on("open", function() {

            console.log('connected to '+sp[i].port+' at '+config.serialBaudRate);

            // line from serial port
            sp[i].handle.on("data", function (data) {
                serialData(data, i);
            });

            // loop for status ?
            setInterval(function() {
                // console.log('writing ? to serial');
                sp[i].handle.write('?');
            }, 1000);

        });

    }(i)
    }

});

function emitToPortSockets(port, evt, obj) {
    for (var i=0; i<sp[port].sockets.length; i++) {
        sp[port].sockets[i].emit(evt, obj);
    }
}

function serialData(data, port) {

    // handle ?
    if (data.indexOf('<') == 0) {
        // https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.8#---current-status

        // remove first <
        var t = data.substr(1);

        // remove last >
        t = t.substr(0,t.length-2);

        // split on , and :
        t = t.split(/,|:/);

        emitToPortSockets(port, 'machineStatus', {'status':t[0], 'mpos':[t[2], t[3], t[4]], 'wpos':[t[6], t[7], t[8]]});

        return;
    }

    if (queuePause == 1) {
        // pause queue
        return;
    }

    data = ConvChar(data);

    if (data.indexOf('ok') == 0) {

        // ok is green
        emitToPortSockets(port, 'serialRead', {'line':'<span style="color: green;">RESP: '+data+'</span>'});

        // run another line from the q
        if (sp[port].q.length > 0) {
            // there are remaining lines in the q
            // write one
            sendFirstQ(port);
        }

        // remove first
        sp[port].lastSerialWrite.shift();

    } else if (data.indexOf('error') == 0) {

        // error is red
        emitToPortSockets(port, 'serialRead', {'line':'<span style="color: red;">RESP: '+data+'</span>'});

        // run another line from the q
        if (sp[port].q.length > 0) {
            // there are remaining lines in the q
            // write one
            sendFirstQ(port);
        }

        // remove first
        sp[port].lastSerialWrite.shift();

    } else {
        // other is grey
        emitToPortSockets(port, 'serialRead', {'line':'<span style="color: #888;">RESP: '+data+'</span>'});
    }

    if (sp[port].q.length == 0) {
        // reset max once queue is done
        sp[port].qCurrentMax = 0;
    }

    // update q status
    emitToPortSockets(port, 'qStatus', {'currentLength':sp[port].q.length, 'currentMax':sp[port].qCurrentMax});

    sp[port].lastSerialReadLine = data;

}

var currentSocketPort = {};

function sendFirstQ(port) {

    if (sp[port].q.length < 1) {
        // nothing to send
        return;
    }
    var t = sp[port].q.shift();

    // remove any comments after the command
    tt = t.split(';');
    t = tt[0];
    // trim it because we create the \n
    t = t.trim();
    if (t == '' || t.indexOf(';') == 0) {
        // this is a comment or blank line, go to next
        sendFirstQ(port);
        return;
    }
    //console.log('sending '+t+' ### '+sp[port].q.length+' current q length');

    // loop through all registered port clients
    for (var i=0; i<sp[port].sockets.length; i++) {
        sp[port].sockets[i].emit('serialRead', {'line':'<span style="color: black;">SEND: '+t+'</span>'+"\n"});
    }
    sp[port].handle.write(t+"\n")
    sp[port].lastSerialWrite.push(t);
}

var queuePause = 0;
io.sockets.on('connection', function (socket) {

    socket.emit('ports', allPorts);
    socket.emit('config', config);

    // do soft reset, this has it's own clear and direct function call
    socket.on('doReset', function (data) {
        // soft reset for grbl, send ctrl-x ascii \030
        sp[currentSocketPort[socket.id]].handle.write("\030");
        // reset vars
        sp[currentSocketPort[socket.id]].q = [];
        sp[currentSocketPort[socket.id]].qCurrentMax = 0;
        sp[currentSocketPort[socket.id]].lastSerialWrite = [];
        sp[currentSocketPort[socket.id]].lastSerialRealLine = '';
    });

    // lines from web ui
    socket.on('gcodeLine', function (data) {

        if (typeof currentSocketPort[socket.id] != 'undefined') {

            // valid serial port selected, safe to send
            // split newlines
            var nl = data.line.split("\n");
            // add to queue
            sp[currentSocketPort[socket.id]].q = sp[currentSocketPort[socket.id]].q.concat(nl);
            // add to qCurrentMax
            sp[currentSocketPort[socket.id]].qCurrentMax += nl.length;
            if (sp[currentSocketPort[socket.id]].q.length == nl.length) {
                // there was no previous q so write a line
                sendFirstQ(currentSocketPort[socket.id]);
            }

        } else {
            socket.emit('serverError', 'you must select a serial port');
        }

    });

    socket.on('clearQ', function(data) {
        // clear the command queue
        sp[currentSocketPort[socket.id]].q = [];
        // update the status
        emitToPortSockets(currentSocketPort[socket.id], 'qStatus', {'currentLength':0, 'currentMax':0});
    });

    socket.on('pause', function(data) {
        // pause queue
        if (data == 1) {
            console.log('pausing queue');
            queuePause = 1;
        } else {
            console.log('unpausing queue');
            queuePause = 0;
            sendFirstQ(currentSocketPort[socket.id]);
        }
    });

    socket.on('disconnect', function() {

        if (typeof currentSocketPort[socket.id] != 'undefined') {
            for (var c=0; c<sp[currentSocketPort[socket.id]].sockets.length; c++) {
                if (sp[currentSocketPort[socket.id]].sockets[c].id == socket.id) {
                    // remove old
                    sp[currentSocketPort[socket.id]].sockets.splice(c,1);
                }
            }
        }

    });

    socket.on('usePort', function (data) {

        console.log('user wants to use port '+data);
        console.log('switching from '+currentSocketPort[socket.id]);

        if (typeof currentSocketPort[socket.id] != 'undefined') {
            for (var c=0; c<sp[currentSocketPort[socket.id]].sockets.length; c++) {
                if (sp[currentSocketPort[socket.id]].sockets[c].id == socket.id) {
                    // remove old
                    sp[currentSocketPort[socket.id]].sockets.splice(c,1);
                }
            }
        }

        if (typeof sp[data] != 'undefined') {
            currentSocketPort[socket.id] = data;
            sp[data].sockets.push(socket);
        } else {
            socket.emit('serverError', 'that serial port does not exist');
        }

    });

});
9
  • Do you want to send g value to or from aws?
    – mico
    Aug 16, 2017 at 15:03
  • no, i want to send the g code to the web page (when object comes to cnc machine the sensor will sense that object so it suppose to send the g code to my web page Aug 16, 2017 at 15:11
  • What is your particular challenge on it? Overall solution or some well defined part that needs clarification?
    – mico
    Aug 16, 2017 at 15:19
  • 1
    Let us continue this discussion in chat.
    – mico
    Aug 16, 2017 at 16:18
  • 1
    After a long search i found this link it shows how to connect a web app to AWS IOT , but i think i am still need help with those things because i don't really understand how to apply it . Aug 18, 2017 at 10:41

1 Answer 1

6

What you linked is far too complicated and in too low level of abstraction that it is for an professional even hard to read and follow it.

aws-mqtt-client through npm is the easiest solution I could find. You just have to install npm and make the aws service and client code is quite straight forward:

const mqttClient = new AWSMqtt({
    accessKeyId: AWS_ACCESS_KEY,
    secretAccessKey: AWS_SECRET_ACCESS_KEY,
    sessionToken: AWS_SESSION_TOKEN,
    endpointAddress: AWS_IOT_ENDPOINT_HOST,
    region: 'us-east-1'
});

You fill correct values there and publish data from your machine like this:

mqttClient.publish(MQTT_TOPIC, message);

And on site that needs the data you get it:

mqttClient.on('connect', () => {
    mqttClient.subscribe('test-topic');
    console.log('connected to iot mqtt websocket');
});
mqttClient.on('message', (topic, message) => {
    console.log(message.toString());
});

More info:

https://www.npmjs.com/package/aws-mqtt-client

https://www.npmjs.com/get-npm

https://aws.amazon.com/iot-platform/getting-started/

4
  • OK, and what if i want to publish to universal g cod sender software on my laptop where cnc machine connect , do i use npm mqtt too @mico thanks so much for your help Aug 21, 2017 at 20:50
  • Maybe you should post a new question about it with more detail. I think of REST as an option too, if the data does not change upon time. With said specs I cannot say which is the case.
    – mico
    Aug 22, 2017 at 3:18
  • i think i will use linuxcnc because i found this youtube.com/watch?v=jmKUV3aNLjk&t=215s ,what u think @mico Aug 22, 2017 at 6:03
  • In the video node red is used to get data from linuxcnc. It is graphical tool to connect IoT parts, so feel free using it, it should be easy to use once you get it installed.
    – mico
    Aug 23, 2017 at 17:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.