Cómo controlar arduino desde Internet

10/02/2019
Enviado por pepem el Vie, 20/07/2018 - 17:17

En esta entrada vamos a ver como programar nuestro arduino para realizar peticiones periódicas sobre un servidor en Internet con Node.js, y que nuestro arduino sea capaz de intepretar un dato recibido desde el servidor y que realice acciones en consecuencia.

En este ejemplo, controlaremos el encendido y apagado de un led, según un valor que almacenaremos en un registro en unas tablas de MySql, y servido con Node.js.

Arduino y Node

¿Que necesitamos?

Para esto nos harán falta los siguientes materiales:

- Placa arduino uno.
- Placa Ethernet Shield W5100.
- Resistencia 220 ohms.
- Diodo led.
- Cables y puentes varios.
- Host en Internet con node.js.

Preparando el servidor Node.js

Explicar como se instala node en un servidor se escapa del alcance de este post, así que daré por hecho que dispones de una máquina ya configurada y lista para correr el script.

Lo que se hace en el script es crear una ruta /getmessages y tomando un parámetro que debe enviar la placa arduino (iotid), se realiza una consulta a la tabla para que devuelva el campo message_value del registro más reciente, y filtrado por el parámetro iotid. En una amplación de este código, debería marcarse este registro en la tabla con el campo viewed a 1 (leido), para que arduino obtenga siempre el registro más reciente en cada petición. Y así para enviar una orden nueva a arduino, tan sólo tenemos que agregar nuevos registros a la tabla con los correspondientes datos.

Recuerda modificar el fichero models/bd.js y index.js con tus datos de servidor mysql.

Tabla usada para el ejemplo

CREATE TABLE `messages` (
  `messageid` int(11) NOT NULL,
  `iotid` int(11) DEFAULT NULL,
  `message_header` text,
  `message_value` text,
  `time` datetime DEFAULT NULL,
  `viewed` tinyint(4) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Volcado de datos para la tabla `messages`
--

INSERT INTO `messages` (`messageid`, `iotid`, `message_header`, `message_value`, `time`, `viewed`) VALUES
(1, 1, 'turn-led', '1', '2018-06-25 23:35:01', 0);

--
-- Índices para tablas volcadas
--

--
-- Indices de la tabla `messages`
--
ALTER TABLE `messages`
  ADD PRIMARY KEY (`messageid`),
  ADD UNIQUE KEY `iotid` (`iotid`);

--
-- AUTO_INCREMENT de las tablas volcadas
--

--
-- AUTO_INCREMENT de la tabla `messages`
--
ALTER TABLE `messages`
  MODIFY `messageid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
COMMIT;

/models/bd.js

var mysql = require('mysql');

var connection = mysql.createConnection({
    host: 'host',
    user: 'user',
    password: 'pass',
    database: 'database',
    port: 3306
});

connection.connect(function(error){
    if(error){
      throw error;
    }else{
      console.log('Conexion servidor BD correcta.');
    }
});

module.exports = connection;

index.js

var express = require('express');
var basedato = require("./models/bd.js");
var app = express();

var port        = process.env.PORT || 8080;

var allowMethods = function ( req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
}

// GET
app.get("/getmessages", function(req, res, next) {     
  console.log('Iotid ' + req.query.iotid); 
  basedato.query('SELECT * FROM messages WHERE iotid = ? AND viewed = 0 ORDER BY TIME desc LIMIT 1', req.query.iotid, function(error, result){           
    if(error){
      console.log('Se produjo un error');

    }else{
       if(result.length > 0){
              res.send('~' + result[0].message_value + '~');                    	
       }else{
          // usuario no existe, registra y devuelve token                
          console.log('Registro no encontrado');          
          res.send({error:true, message:'auth-ko'}); 
       }
    }
   }
  );   
});

app.use(allowMethods);

app.listen(port, function() {
	console.log('Esperando peticiones');
});

 

Descargar código

Preparando Arduino

Para el prototipo he usado una tarjeta Arduino Uno del fabricante Elegoo, y la ethernet shield w5100 de keyestudio. Hay que ensamblarlas con un poco de cuidado para no doblar las patas. No es necesario configuración adicional, como en el caso de muchas tarjetas wifi. Para ensamblarlas correctamente, toma como referencia las patillas ICSP de la shield deben coincidir con las ICSP de la placa Arduino. La Shield también es compatible con el Arduino Mega.

 

Arduino Ethernet

El esquema eléctrico como podemos ver, es muy sencillo:

Ethernet Led Arduino

La vista no corresponde al modelo en concreto con el que he realizado las pruebas, pero los pines son los mismos, donde he usado el pin 3 para alimentar el led que vamos a controlar.

El código se trata de un cliente web que realiza peticiones a un servidor de forma continua. Entre peticiones, hay un lapso de tiempo determinado por postingInterval, en milisegundos, que posiblemente tengas que configurar para que funcione adecuadamente.

En función de la respuesta obtenida del servidor (un 0 o un 1, apagará o endenderá un led. En las peticiones al servidor uso el parametro iotid, esto es para diferenciar diversos dispositivos o placas arduino.

Recuerda modificar la dirección ip y la dirección de tu servidor Node.js

/*
  Repeating Web client

 This sketch connects to a a web server and makes a request
 using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or
 the Adafruit Ethernet shield, either one will work, as long as it's got
 a Wiznet Ethernet module on board.

 This example uses DNS, by assigning the Ethernet client with a MAC address,
 IP address, and DNS address.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13

 created 19 Apr 2012
 by Tom Igoe
 modified 21 Jan 2014
 by Federico Vanzati

 http://www.arduino.cc/en/Tutorial/WebClientRepeating
 This code is in the public domain.

 */

#include <SPI.h>
#include <Ethernet.h>

// assign a MAC address for the ethernet controller.
// fill in your address here:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
// fill in an available IP address on your network here,
// for manual configuration:
IPAddress ip(192, 168, 0, 177);

// fill in your Domain Name Server address here:
IPAddress myDns(1, 1, 1, 1);

// initialize the library instance:
EthernetClient client;

char server[] = "tuservidor.com";

byte ledPin = 3;

unsigned long lastConnectionTime = 0;             // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 3000L; // delay between updates, in milliseconds
// the "L" is needed to use long type numbers

// this method makes a HTTP connection to the server:
void getMessages() {
  // close any connection before send a new request.
  // This will free the socket on the WiFi shield
  client.stop();

  // if there's a successful connection:
  if (client.connect(server, 8080)) {
    Serial.println("connecting... to get messages");
    // send the HTTP GET request:
    client.println("GET /getmessages?iotid=1 HTTP/1.1");
    client.println("Host: tuservidor.com");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

    // note the time that the connection was made:
    lastConnectionTime = millis();
  } else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
  }
}

void setup() {
  // start serial port:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // give the ethernet module time to boot up:
  delay(1000);
  // start the Ethernet connection using a fixed IP address and DNS server:
  Ethernet.begin(mac, ip, myDns);
  // print the Ethernet board/shield's IP address:
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());

  pinMode(ledPin, OUTPUT);
}

void loop() {
  
  char command[100] = "";
  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  if (client.available())
     {
        char c = client.read();
        int i = 0;
        
        if (c == '~')
        {
           while (client.available())
           {
              c = client.read();
              if (c == '~')
              {
                 client.stop();
                 client.flush();
                 break;
              } else {
                command[i]=c;
                i=i+1;
                
              }
           }
           
        }
     }

     if (command != "") {
      Serial.print(command);
     }

    if ((String) command == "1") {
      Serial.print("turn on");
      digitalWrite(ledPin, HIGH);  
    } else if ((String) command == "0") {
      Serial.print("turn off");
      digitalWrite(ledPin, LOW);
    } 


   // if three seconds have passed since your last connection,
  // then connect again and get data:
  if (millis() - lastConnectionTime > postingInterval) {    
    getMessages(); 
  }


}

 

Descargar código