Kết nối ứng dụng web với IoT AWS


8

Tôi đang sử dụng Raspberry Pi làm máy chủ web, web này là để điều khiển máy CNC như bạn có thể thấy trong hình sau.

Giao diện điều khiển CNC

(Tôi lấy nó từ trung tâm git)

Tôi có thể nhập mã g theo cách thủ công hoặc tôi có thể tải lên tệp mã g nhưng bây giờ tôi muốn kết nối trang web này với Amazon Web Services IoT để tự động gửi mã g đến trang của mình, sau khi tìm kiếm lâu tôi thấy liên kết này hiển thị cách kết nối một ứng dụng web với AWS IOT, nhưng tôi nghĩ tôi vẫn cần trợ giúp với những điều đó vì tôi không thực sự hiểu cách áp dụng nó. Đây là tệp 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');
        }

    });

});

Bạn có muốn gửi giá trị g đến hoặc từ aws không?
mico

không, tôi muốn gửi mã g đến trang web (khi đối tượng đến máy cnc, cảm biến sẽ cảm nhận được đối tượng đó nên giả sử gửi mã g đến trang web của tôi
Balsam Qassem

Thách thức cụ thể của bạn về nó là gì? Giải pháp tổng thể hoặc một số phần được xác định rõ cần làm rõ?
mico


1
Sau một hồi tìm kiếm, tôi thấy liên kết này cho thấy cách kết nối một ứng dụng web với AWS IOT, nhưng tôi nghĩ tôi vẫn cần trợ giúp với những điều đó vì tôi không thực sự hiểu cách áp dụng nó.
Balsam Qassem

Câu trả lời:


6

Những gì bạn liên kết là quá phức tạp và ở mức độ trừu tượng quá thấp mà nó dành cho một chuyên gia thậm chí khó đọc và làm theo nó.

aws-mqtt-client qua npm là giải pháp đơn giản nhất tôi có thể tìm thấy. Bạn chỉ cần cài đặt npm và làm cho dịch vụ aws và mã máy khách khá đơn giản:

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

Bạn điền các giá trị chính xác vào đó và xuất bản dữ liệu từ máy của bạn như thế này:

mqttClient.publish(MQTT_TOPIC, message);

Và trên trang web cần dữ liệu bạn nhận được:

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

Thêm thông tin:

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

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

https://aws.amazon.com/iot-pl platform / gett-start /


OK, và nếu tôi muốn xuất bản lên phần mềm người gửi mã g phổ biến trên máy tính xách tay của tôi nơi máy cnc kết nối, tôi có sử dụng npm mqtt không @mico cảm ơn rất nhiều vì sự giúp đỡ của bạn
Balsam Qassem

Có lẽ bạn nên đăng một câu hỏi mới về nó với nhiều chi tiết hơn. Tôi nghĩ rằng REST cũng là một tùy chọn, nếu dữ liệu không thay đổi theo thời gian. Với thông số kỹ thuật nói tôi không thể nói đó là trường hợp.
mico

Tôi nghĩ rằng tôi sẽ sử dụng linuxcnc vì tôi đã tìm thấy youtube.com/watch?v=jmKUV3aNLjk&t=215s này , bạn nghĩ gì @mico
Balsam Qassem

Trong nút video màu đỏ được sử dụng để lấy dữ liệu từ linuxcnc. Nó là công cụ đồ họa để kết nối các bộ phận IoT, vì vậy hãy thoải mái sử dụng nó, nó sẽ dễ sử dụng một khi bạn đã cài đặt nó.
mico
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.