Mostriamo come utilizzare i pin GPIO del Raspberry Pi, con Node JS, creando un web server e gestendo gli entrypoint.

Prepariamo il Raspberry Pi

Dopo aver seguito la guida su come installare Node.js sul Rpi, installiamo la libreria che ci permette di interfacciarci ai pin GPIO del Raspberry.
Ne esistono svariate nella repository ufficiale di Node.js, quella che attualmente andremo ad usare si chiama ‘onoff’: https://www.npmjs.com/package/onoff, questa libreria è un pacchetto npm, per utilizzarla semplicemente definiamo ‘onoff’ nelle dipendenze su package.json oppue lanciamo il comando:
npm install onoff --save

Il modo più comodo e corretto per iniziare è forse quello di usare direttamente il node package manager (npm), quindi semplicemente andiamo a creare il package.json nella cartella di lavoro corrente, non manualmente, ma inizializzando il nuovo progetto con il comando: npm init.
Lanciato il comando ci chiederà il nome che vogliamo dare al progetto ed altre informazioni. Inseriamone un paio e completiamo la procedura.
Adesso possiamo si dare il comando npm install onoff --save che scaricherà il modulo specificato e lo aggiungerà come dipendenza nel file package.json creato con il comando npm init.

Ogniqualvolta andremo ad eseguire con node uno script che interagisce con i GPIO non dimentichiamo di far precedere la voce sudo per eseguire l’app con i permessi di root (Ex. sudo node app.js).

Un altra dipendenza necessaria è express, installiamo la libreria come visto per la precedente: npm install express --save.

Scriviamo lo script per Node.js

A seconda di come vogliamo strutturare l’app possiamo optare per differenti scelte organizzative.
L’app che segue è pensata per pilotare un singolo pin del RPi, restando in ascolto su una porta prefissata, il tutto è definito nel file config.json:

{"porta": 5000, "pin": 17}

Ricordo che il numero del pin segue quella che è la notazione GPIO mostrata in questa foto:

Raspberry-Pi-GPIO-Layout

Dunque per pilotare il pin 11, dovremo riferirci ad esso con il numero 17.
Questo file di configurazione viene letto da altre due pagine per implementare la logica dell’applicazione.

Gli altri due file che compongono l’applicativo sono:

app.js:

var express = require('express'); // Usiamo libreria express per facilitarci il routing // npm install express --save
var app = express();
 
var relay = require('./gpio-onoff.js');
 
var config = require('./config.json'); // file di configurazione
var porta = config.porta;
 
 
app.get('/toggle', function (req, res) { // processiamo richiesta get verso /toggle
 
  // risposta in JSON
  res.json(relay.toggle());
 
});
 
app.get('/on', function (req, res) { // processiamo richiesta get verso /toggle
 
  // risposta in JSON
  res.json(relay.on());
 
});
 
app.get('/off', function (req, res) { // processiamo richiesta get verso /toggle
 
  // risposta in JSON
  res.json(relay.off());
 
});
 
app.get('/get', function (req, res) { // processiamo richiesta get verso /toggle
 
  // risposta in JSON
  res.json(relay.get());
 
});
 
// Express route for any other unrecognised incoming requests
app.get('*', function(req, res) {
  res.status(404).send('Unrecognised API call');
});
 
var server = app.listen(porta, function () { // server in ascolto sulla porta
 
 
  var host = server.address().address;
  var port = server.address().port;
 
  console.log('App in ascolto su http://%s:%s', host, port);
 
});

gpio-onoff.js:

var Gpio = require("onoff").Gpio; // npm install onoff --save
 
var config = require('./config.json'); // file di configurazione
var pin = config.pin; // pin fisico 11, ma header 17, occhio alla differenza.
 
// FUNZIONI PER INTERAGIRE CON IL RELAY COLLEGATO AD UN GPIO pin
 
led = new Gpio(pin, 'out');
 
exports.get = function(pin){ // perchè questo file gpio-onoff.js è incluso esternamente
	var value = led.readSync();
	var stato = (value == 1) ? "on": "off";
 
	console.log("Get status: "+stato);
	return {response_code: 200, new_state: stato, path: "/get"};
 
};
 
 
exports.on = function(pin){
	led.writeSync(1);
	console.log("Pin ON");
	return {response_code: 200, new_state: "on", path: "/on"};
};
 
exports.off = function(pin){
	led.writeSync(0);
	console.log("Pin OFF");
	return {response_code: 200, new_state: "off", path: "/off"};
};
 
exports.toggle = function(pin){
 
var stato = 0;
 
/*
   led.read(function (err, value) { // Asynchronous read.
		if (err) throw err;
		led.write(value ^ 1, function (err) { // Asynchronous write.
		  if (err) throw err;
		  stato = value ^ 1;
		  console.log('Pin new value: '+stato);
		});
  });
*/
 
stato = led.readSync() ^ 1;
 
led.writeSync(stato);
console.log("Toggle: "+stato);
 
if (stato == 1)
	return {response_code: 200, new_state: "on", path: "/toggle"};
else
	return {response_code: 200, new_state: "off", path: "/toggle"};
 
};

Potete scaricare i sorgenti direttamente dalla repository ufficiale su github, la cartella è node_rele_server.
Nella root della repository c’è anche l’equivalente di quanto mostrato, però scritto in Python.

Lanciare l’app all’avvio del sistema

Qualora vorreste far in modo che il server venga eseguito all’avvio del Raspberry dovete inserire una voce nel file /etc/rc.local che avvii il server con permessi di root:
sudo node /home/pi/Desktop/node_rele_server/app.js &
(non dimenticate il percorso assoluto! – la & commerciale serve a eseguire il comando in un nuovo processo, così che un eventuale loop infinito all’interno del nostro programma non blocchi la fase di boot, l’esecuzione di comandi all’avvio del RPi è ben documentato sul sito ufficiale).