В наше время обычная вещь, подключённая к интернету, начинает становиться обыденностью. Даже появилось понятие — «интернет вещей» (Internet of Things, IoT). Но как подступиться к этому своеобразному интернету новичку — не всегда понятно, потому что хотя статей по данной теме много, но каждому хочется, чтобы статья была простой для воспроизведения и чтобы в ней разбиралось что-то очень близкое и приятное для читателя.
Поэтому попробуем подключить к интернету самое простое — светодиод, взятый из сломанной оптической мыши. Будем через страницу в интернете включать и выключать светодиод, управлять частотой его мерцаний.
Схема подключения светодиода к интернету будет следующая:
Итак, соберём все детали на столе и спаяем нашу простую схемку. Из мышки достаём светодиод и резистор в 220 Ом. Резистор нужен для ограничения тока, он мелкий и его еле можно разглядеть на конце провода. Для соединения проводов с GPIO использую коннекторы, которые выпросил в сервисе, ремонтирующем компьютеры.
Подготавливаем софт
На сервере и «малинке» должен стоять node.js и npm (node package manager). Устанавливаем по данной инструкции.
Для того, чтобы node.js смог работать с GPIO, требуется установить модуль rpi-gpio. А для соединения с сервером RPi потребуется socket.io-client. Устанавливаются пакеты командой sudo npm install rpi-gpio и sudo npm install socket.io-client.
Скрипт для node.js на Raspberry Pi:
var socket = require('socket.io-client')('vpssite.domain:3141');
var gpio = require('rpi-gpio');
var fs = require('fs');
// hack due to error
fs.exists = require('path').exists;
var async = require('async');
// pin GPIO4
var pin = 7;
// current fps
var piFps = 0;
var currentValue = false;
var timemanager;
var set0 = function(err, results) {
if (err)
console.log(err);
console.log('Pin ' + pin + ' closed');
directWrite(pin, false, function() {
clearTimeout(timemanager);
});
};
var blinkexec = function() {
delayedWrite(7, true, function() {
delayedWrite(7, false, blinkexec)
});
};
var blink = function(err, results) {
if (err)
console.log(err);
console.log('Pin ' + pin + ' blinking');
blinkexec();
};
function directWrite(pin, value, callback) {
return gpio.write(pin, value, callback);
}
function delayedWrite(pin, value, callback) {
var delay = Math.round(1000 / piFps / 2);
clearTimeout(timemanager);
timemanager = setTimeout(function() {
directWrite(pin, value, callback);
}, delay);
}
var release = function() {
console.log('Writes complete, pause then unexport pins');
setTimeout(function() {
gpio.destroy(function() {
console.log('Closed pins, now exit');
return process.exit(0);
});
}, 500);
};
socket.on('connect', function() {
console.log('connected');
socket.on('setfps', function(data) {
console.log(data);
if (data.fps > 0) {
piFps = data.fps;
gpio.setup(pin, gpio.DIR_OUT, blink);
} else {
gpio.setup(pin, gpio.DIR_OUT, set0);
}
});
socket.on('disconnect', function() {
console.log('disconnect');
release();
});
});
Следующий код на сервере создаёт сервер на порту 3141 и принимает команду setfps и рассылает её дальше всем браузерам и Raspberry Pi.
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var allClients = [];
var count = 0;
var fpsPi = 0;
server.listen(3141);
server.on('error', function(e) {
if (e.code == 'EADDRINUSE') {
console.log('Address in use, exit...');
process.exit();
}
});
app.get('/', function (req, res) {
res.send('Fps is ' + fpsPi);
console.log('requested / - show ' + fpsPi);
});
function getDate() {
var datas = new Date();
return datas.getHours() + ':' + datas.getMinutes() + ':' + datas.getSeconds() + '.' + datas.getMilliseconds()
}
function consolelog(msg) {
console.log(getDate() + ' ' + msg);
}
io.on('connection', function (socket) {
io.emit('setfps', {fps: fpsPi});
// browser subscribes to listen to the station
socket.on('subscribe', function(data) {
socket.json.emit('subscribed', {fps: fpsPi});
io.emit('setfps', {fps: fpsPi});
});
// disconnect on error. Browser will reconnect
socket.on('error', function() {
socket.disconnect();
});
// client disconnects
socket.on('disconnect', function() {
consolelog('Client disconnected.');
});
// save to RPi and browsers new fps
socket.on('setfps', function(fps){
fpsPi = fps;
consolelog('setfps ' + fpsPi);
io.emit('setfps', {fps: fpsPi});
});
});
Запуск работы
Запускаем скрипты следующим образом. На RaspberryPi — с правами рута: sudo nodejs led.js, а на сервере — просто добавляем в кронтаб * * * * * cd /var/www/apps; node server.js >> cron_rpi.log, это не так красиво, зато всегда сервер будет запущен и можем о нём забыть.
На странице своего сайта включаем код для слайдера jquery-ui и socket.io с нашего сервера. При получении сигнала от node.js-сервера слайдер выставляет текущее значение fps и наоборот — при передвижении слайдера мы на сервер отсылаем новое значение fps, которое сервер затем рассылает всем клиентам в браузеры и на Raspberry Pi.
Вот, собственно, и всё, светодиод подключен к интернету. Теперь с любого устройства с интернетом мы можем управлять его мерцанием. Простор для дальнейшего творчества большой. Можно к выводам подключить модуль-реле и кнопкой на своём сайте включать и выключать любое оборудование. Модулей для Raspberry Pi продаётся очень много, поэтому полёт фантазии почти не ограничен, особенно если в наличии восторженный восьмилетний почитатель электроники.