Control de Relays por Ethernet con Arduino Nano

Este es un proyecto que tenia en la carpeta de pendientes hace mucho tiempo; queria armar algo que me permite apagar y prender el router wifi sin necesidad de ir hasta el lugar; es un equipo viejo que ya no se actualiza el firmware por lo cual me dio la excusa perfecta para trabajar con este proyecto.

La idea es conectarnos a un dispositivo en la red mediante cable (nada de red inalambrica) y poder apagar o encender un dispositivo; en este caso a 12V, aunque es muy facil de adaptarlo para trabajar con 220V.

Para ello utilizamos un Arduino Nano para manejar la lógica; el modulo ethernet ENC28J60, una fuente DC-DC que convierte los 12V a 5V para alimentar la electrónica y por ultimo un modulo relay.

El circuito es el siguiente:

Algunas consideraciones respecto al gráfico anterior
1. El modulo Ethernet si bien soporta 5V, lo recomendable es que opere con 3.3V; utilice un regulador lineal para obtener los 3.3V, puesto que la salida de 3.3V del arduino nano no era suficiente.
2. El modulo de rele que utilice es doble; en el gráfico arme con uno simple; en los módulos simples que tengo la señal es el pin del medio.

El cuadro de conexiones sobre el Arduino Nano seria el siguiente:

ArduinoModulo EthernetRelay
D2Signal
D10SS(CS)
D11MOSI(SI)
D12MISO(SO)
D13SCK

El código del programa es bastante sencillo:

#include <EtherCard.h>

static byte mymac[] = {0xDD,0xDD,0xDD,0x00,0x01,0x05};
static byte myip[] = {192,168,2,5};
byte Ethernet::buffer[700];

const int ledPin1 = 2;
const int ledPin2 = 3;

char* EstadoLed1="OFF";
char* EstadoLed2="OFF";

Se importa la libreria EtherCard, luego se define la mac del dispositivo y la dirección IP; en este caso no vamos a utilizar DHCP para que tome una IP sino definimos una estatica. Luego se establecen cuales serán los GPIO del Arduino que usaremos para el relay, en este caso el D2.

Por ultimo se definen dos variables que mantendrán el estado de los relay.

void setup () {
 
  Serial.begin(9600);
 
  if (!ether.begin(sizeof Ethernet::buffer, mymac, 10))
    Serial.println( "No se ha podido acceder a la controlador Ethernet");
 else
   Serial.println("Controlador Ethernet inicializado");
 
  if (!ether.staticSetup(myip))
    Serial.println("No se pudo establecer la dirección IP");

  Serial.println();
  
  pinMode(ledPin1, OUTPUT);
  digitalWrite(ledPin1, HIGH);

  pinMode(ledPin2, OUTPUT);
  digitalWrite(ledPin2, HIGH);
  
}

En el método setup() inicializamos la comunicación serie, sirve para el momento de depurar el programa luego no es necesaria; luego inicializamos la conexion Ethernet y por ultimo establecemos la forma de operación de los GPIO, en este caso ambos como salida.

void loop() {
 
  word len = ether.packetReceive();
  word pos = ether.packetLoop(len);
  
  if(pos) {
    // http://192.168.2.5/?status1=ON
    if(strstr((char *)Ethernet::buffer + pos, "GET /?status1=ON") != 0) {
      Serial.println("Comando ON recibido");
      digitalWrite(ledPin1, LOW);
      EstadoLed1 = "ON";
    }

    if(strstr((char *)Ethernet::buffer + pos, "GET /?status1=OFF") != 0) {
      Serial.println("Comando OFF recibido");
      digitalWrite(ledPin1, HIGH);
       EstadoLed1= "OFF";
    }  

    if(strstr((char *)Ethernet::buffer + pos, "GET /?status2=ON") != 0) {
      Serial.println("Comando ON recibido");
      digitalWrite(ledPin2, LOW);
      EstadoLed2 = "ON";
    }

    if(strstr((char *)Ethernet::buffer + pos, "GET /?status2=OFF") != 0) {
      Serial.println("Comando OFF recibido");
      digitalWrite(ledPin2, HIGH);
       EstadoLed2= "OFF";
    }
          
    ether.httpServerReply(homePage()); // se envia página Web
  }
}

Dentro de la función loop(), lo primero que realiza es recibir los paquetes. Si los paquetes finalizan en GET /?status1=ON indica que el relay1 debe encenderse, si en cambio finaliza en GET /?status1=OFF debe apagarse, mismo caso para el relay2.

Luego de realizar el cambio de estado, asigna el nuevo estado a la variable EstadoLed1 o EstadoLed2 segun corresponda y por ultimo devuelve el resultado de la funcion homePage().

static word homePage() {
  
 BufferFiller bfill = ether.tcpOffset();
 
 bfill.emit_p(PSTR("HTTP/1.0 200 OK\r\n"
      "Content-Type: text/htmlrnPragma: no-cachernRefresh: 5\r\n\r\n"
      "{\"uptime\":\"$L\",\"s1\":\"$S\",\"s2\":\"$S\"}"      
      ),millis()/1000,EstadoLed1,EstadoLed2);
     
  return bfill.position();
}

La funcion homePage() devuelve un word conteniendo un JSON, donde se informa el tiempo de uptime del dispositivo y el estado de cada relay.

Luego de cargado el programa simplemente accediendo a la direccion IP del dispositivo mas /?status1=ON podes activar el rele y con/?status1=OFF lo apagamos.

En thingiverse pueden encontrar los archivos STL para descargar la caja e imprimirla si lo desean.

En la imagen anterior pueden ver como quedo armada la caja con la electrónica interna.

El repositorio donde pueden encontrar el código completo es el siguiente:
https://github.com/gsampallo/ArduinoLanSwitch

A continuación pueden encontrar el video completo de como se armo:

Nano Game

Hace un tiempo estuve trabajando en un pequeño shield para programar juegos sencillos que se ejecuten en un Arduino Nano

La idea es programar juegos que pudieron ejecutarse sobre esta «plataforma», para demostrar algunos conceptos de programación, uso de sprites y demás.

Hice un video mostrando su uso, con el sencillo juego que se había programado hace un tiempo: