В прошлый раз удалось наладить передачу данных от Arduino на веб сервер.
Теперь следующий шаг, буду записывать данные от датчиков в БД и результат смотреть через браузер.
Для примера сделал такой скетч для Arduino. Просто раз в секунду вычисляю квадратный корень следующего по счёту целого числа.
С Arduino разобрался. Далее - работа с веб сервером и СУБД.
После этого пришлось исправить doctype в файле views/layout.jade, для этого заменил первую строку
По ссылке http://localhost:3000/ открывается стартовая страничка. Отлично, можно отправить на неё данные с Arduino.
На клиенте данные буду строить с помощью D3.js, с помощью этой библиотеки данные легко визуализировать на клиенте, разгрузив сервер.
В качестве СУБД будет MongoDB, у неё дешёвая запись. Это может пригодиться, если понадобится часто логировать показания датчиков.
Теперь устанавливаю mongodb для nodejs.
Данные от Arduino буду записывать в коллекцию sqrt с атрибутами time (текущее время), value (значение).
Для этого делаю такого демона getdata.js, воспользовавшись этой удачной статьёй.
Чтобы он работал, устанавливаю ещё serialport и запускаю демона.
Вот какие манипуляции для этого совершаю.
Один. Прописываю маршрут для express. В файле app.js добавляю строки
Два. Забираю данные из БД (в routes/get-data.js.).
Три. Отображаю данные в браузере, по аналогии с этим примером (в javascripts/getdata.js).
В итоге получаю такую картинку:
Каждые 5 секунд она обновляется.
Всё. За качество кода не боролся, главная задача тут - отработать подход и убедиться, что нет серьёзных подводных камней. Код этого примера можно посмотреть на Гитхабе.
Теперь следующий шаг, буду записывать данные от датчиков в БД и результат смотреть через браузер.
Для примера сделал такой скетч для Arduino. Просто раз в секунду вычисляю квадратный корень следующего по счёту целого числа.
int i = 0; void setup() { Serial.begin(9600); } void loop() { i++; Serial.println(sqrt(i)); delay(1000); }
С Arduino разобрался. Далее - работа с веб сервером и СУБД.
Веб сервер
В качестве фреймворка для веб сервера взял express для node.js. Установил express так, как советуют тут.$ sudo npm install -g express $ express arduino-web $ cd arduino-web $ npm install $ node app
После этого пришлось исправить doctype в файле views/layout.jade, для этого заменил первую строку
doctype 5
на doctype
.По ссылке http://localhost:3000/ открывается стартовая страничка. Отлично, можно отправить на неё данные с Arduino.
На клиенте данные буду строить с помощью D3.js, с помощью этой библиотеки данные легко визуализировать на клиенте, разгрузив сервер.
В качестве СУБД будет MongoDB, у неё дешёвая запись. Это может пригодиться, если понадобится часто логировать показания датчиков.
Запись в базу
У меня Ubuntu, поэтому устанавливаю MongoDB, как описано тут.$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 $ echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list $ sudo apt-get install mongodb-10gen
Теперь устанавливаю mongodb для nodejs.
$ npm install mongodb
Данные от Arduino буду записывать в коллекцию sqrt с атрибутами time (текущее время), value (значение).
Для этого делаю такого демона getdata.js, воспользовавшись этой удачной статьёй.
/** * Сохранение в БД данных от Arduino */ console.log("Connect to database..."); var _getData = { database: { mongo: require('mongodb'), host: 'localhost', name: 'sqrt', port: null, db: null }, arduino: { port: "/dev/ttyACM0", baudrate: 9600 } }; _getData.database.port = _getData.database.mongo.Connection.DEFAULT_PORT; _getData.database.db = new _getData.database.mongo.Db(_getData.database.name, new _getData.database.mongo.Server( _getData.database.host, _getData.database.port, {}), {safe: false}); // Соединяемся с БД _getData.database.db.open(function(err, db) { console.log("Connected to database."); // Подключаемся к порту var serialport = require("serialport"); var SerialPort = serialport.SerialPort; var serialPort = new SerialPort(_getData.arduino.port, { baudrate: _getData.arduino.baudrate }); serialPort.on("open", function() { // Читаем данные из порта var readData = ""; var first = true; console.log("Waiting for data from Arduino..."); serialPort.on('data', function(data) { var dataStr = data.toString(); // Парсим данные (делим на строки) for (var i = 0, l = dataStr.length; i < l; i++) { if (dataStr.charAt(i) != "\n" && dataStr.charAt(i) != "\r") { readData += dataStr.charAt(i); } else if (readData) { // Пропускаем первое полученное значение if (!first) { db.collection('sqrt', function(err, collection) { var date = new Date(); // Сохраняем значение в базу collection.insert({ time: date, value: readData }); console.log(date + ': ' + readData + ';'); }); } else { first = false; } readData = ""; } } }); }); });
Чтобы он работал, устанавливаю ещё serialport и запускаю демона.
$ npm install serialport
$ node getdata.js
Отображение данных в браузере
Данные, которые присылает Arduino, сохраняются в БД. Теперь можно написать кусок кода, с помощью которого эти данные можно будет увидеть в браузере. Далее я буду каждые 5 секунд отправлять на сервер AJAX запрос для получения информации за последние 5 минут.Вот какие манипуляции для этого совершаю.
Один. Прописываю маршрут для express. В файле app.js добавляю строки
var data = require('./routes/get-data'); ... app.get('/get-data', data.get_data);
Два. Забираю данные из БД (в routes/get-data.js.).
/* * GET home page. */ exports.get_data = function(req, res){ // Читаем данные из БД var _getData = { database: { mongo: require('mongodb'), host: 'localhost', name: 'sqrt', port: null, db: null } }; _getData.database.port = _getData.database.mongo.Connection.DEFAULT_PORT; _getData.database.db = new _getData.database.mongo.Db(_getData.database.name, new _getData.database.mongo.Server( _getData.database.host, _getData.database.port, {}), {safe: false}); // Соединяемся с БД _getData.database.db.open(function(err, db) { db.collection('sqrt', function(err, collection) { // Выбераем из таблицы всё, что не старее 10 минут var dateFrom = new Date(Date.parse(new Date()) - 1000 * 60 * 10); collection.find({time: {'$gt': dateFrom}}).toArray(function(err, docs) { console.log(docs.length); res.send(JSON.stringify(docs)); db.close(); }); }); }); };
Три. Отображаю данные в браузере, по аналогии с этим примером (в javascripts/getdata.js).
var margin = {top: 20, right: 20, bottom: 30, left: 50}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var x = d3.time.scale() .range([0, width]); var y = d3.scale.linear() .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); var line = d3.svg.line() .x(function(d) { return x(d.time); }) .y(function(d) { return y(d.value); }); var svg = d3.select("#data").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); getData(); setInterval(function() { getData(); }, 1000*5); function getData() { d3.json("get-data", function(error, data) { data.forEach(function(d) { d.time = Date.parse(d.time); d.value = +d.value; }); x.domain(d3.extent(data, function(d) { return d.time; })); y.domain(d3.extent(data, function(d) { return d.value; })); svg.selectAll("g") .remove(); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Value"); svg.selectAll("path") .remove(); svg.append("path") .datum(data) .attr("class", "line") .attr("d", line); }); }
В итоге получаю такую картинку:
Каждые 5 секунд она обновляется.
Всё. За качество кода не боролся, главная задача тут - отработать подход и убедиться, что нет серьёзных подводных камней. Код этого примера можно посмотреть на Гитхабе.
Комментариев нет:
Отправить комментарий