Menghubungkan aplikasi web ke IoT AWS

8

Saya menggunakan Raspberry Pi sebagai server web web ini untuk mengontrol mesin CNC seperti yang Anda lihat pada gambar berikut.

UI pengontrol CNC

(Saya mengambilnya dari git hub)

Saya dapat memasukkan kode g secara manual atau saya dapat mengunggah file kode g tetapi sekarang saya ingin menghubungkan halaman web ini ke Amazon Web Services IoT untuk mengirim kode g secara otomatis ke halaman saya, setelah pencarian yang lama saya menemukan tautan ini menunjukkan cara untuk sambungkan aplikasi web ke AWS IOT, tetapi saya rasa saya masih perlu bantuan dengan hal-hal itu karena saya tidak begitu mengerti bagaimana cara menerapkannya. Ini adalah file server.js:

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');
        }

    });

});
Balsam Qassem
sumber
Apakah Anda ingin mengirim nilai g ke atau dari aws?
mico
tidak, saya ingin mengirim kode g ke halaman web (ketika objek datang ke mesin cnc sensor akan merasakan objek itu sehingga ia harus mengirim kode g ke halaman web saya
Balsam Qassem
Apa tantangan khusus Anda? Solusi keseluruhan atau bagian tertentu yang perlu diklarifikasi?
mico
1
Setelah pencarian yang panjang saya menemukan tautan ini menunjukkan bagaimana menghubungkan aplikasi web ke AWS IOT, tetapi saya pikir saya masih membutuhkan bantuan dengan hal-hal itu karena saya tidak benar-benar mengerti bagaimana cara menerapkannya.
Balsam Qassem

Jawaban:

6

Apa yang Anda tautkan terlalu rumit dan dalam tingkat abstraksi yang terlalu rendah sehingga sulit bagi seorang profesional untuk membaca dan mengikutinya.

aws-mqtt-client hingga npm adalah solusi termudah yang bisa saya temukan. Anda hanya perlu menginstal npm dan membuat layanan aws dan kode klien cukup mudah:

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'
});

Anda mengisi nilai yang benar di sana dan menerbitkan data dari mesin Anda seperti ini:

mqttClient.publish(MQTT_TOPIC, message);

Dan di situs yang membutuhkan data Anda mendapatkannya:

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

Info lebih lanjut:

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

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

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

mico
sumber
OK, dan bagaimana jika saya ingin mempublikasikan ke perangkat lunak pengirim g cod universal pada laptop saya di mana mesin cnc terhubung, apakah saya menggunakan npm mqtt juga @mico terima kasih banyak atas bantuan Anda
Balsam Qassem
Mungkin Anda harus memposting pertanyaan baru tentang hal itu dengan lebih detail. Saya menganggap REST sebagai opsi juga, jika data tidak berubah pada waktunya. Dengan spesifikasi tersebut saya tidak bisa mengatakan yang mana masalahnya.
mico
saya pikir saya akan menggunakan linuxcnc karena saya menemukan youtube.com/watch?v=jmKUV3aNLjk&t=215s ini , apa yang Anda pikirkan @mico
Balsam Qassem
Dalam simpul video merah digunakan untuk mendapatkan data dari linuxcnc. Ini adalah alat grafis untuk menghubungkan bagian-bagian IoT, jadi silakan menggunakannya, itu harus mudah digunakan setelah Anda menginstalnya.
mico