Close

The brain of the thingy

A project log for Open Z3zzvw3

An over engineered way to unlock a door

GlitchmakerGlitchmaker 01/01/2015 at 14:540 Comments

This was the time to give a brain to the thingy, in other words how to control the thing. My first approach was to create a web browser, running in the arduino based on the example of the enc28j60 library. I wanted to press a button on a webpage, set the relay, delay for a few seconds and return to the original condition. I produced the following code:

// This is a demo of the RBBB running as webserver with the Ether Card
// 2010-05-28  http://opensource.org/licenses/mit-license.php

#include <EtherCard.h>
#define RELAY 10
#define LED 2
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
static byte myip[] = { 192,168,1,203 };

byte Ethernet::buffer[1000];
BufferFiller bfill;

char * color = "green";
char * state = "fechada";
int changed_state= 0;

void setup () {
  Serial.begin(9600);
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
    Serial.println(F("Failed to access Ethernet controller"));
  ether.staticSetup(myip);
}
const char http_OK[] PROGMEM =
    "HTTP/1.0 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Pragma: no-cache\r\n\r\n";
 
const char http_Found[] PROGMEM =
    "HTTP/1.0 302 Found\r\n"
    "Location: /\r\n\r\n";
 
const char http_Unauthorized[] PROGMEM =
    "HTTP/1.0 401 Unauthorized\r\n"
    "Content-Type: text/html\r\n\r\n"
    "<h1>401 Unauthorized</h1>";

static word homePage() {
  bfill = ether.tcpOffset();
  if(changed_state == 0){
  bfill.emit_p(PSTR(
    "HTTP/1.0 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Pragma: no-cache\r\n"
    "\r\n"
    "<meta http-equiv='refresh' content='1' />"
    "<title>OPEN ZEZZAWEE</title>"
   "<body bgcolor='green'>" 
    "<h1>Porta esta fechada</h1>"
    "<INPUT Type='BUTTON' VALUE='porta' ONCLICK='window.location.href=\"/?cmd=porta\"'>"));
  return bfill.position();
  }
  else{
    bfill.emit_p(PSTR(
    "HTTP/1.0 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Pragma: no-cache\r\n"
    "\r\n"
    //"<meta http-equiv='refresh' content='1' />"
    "<title>OPEN ZEZZAWEE</title>"
   "<body bgcolor='red'>" 
    "<h1>Porta esta aberta</h1>"
    "<INPUT Type='BUTTON' VALUE='porta' ONCLICK='window.location.href=\"/?cmd=porta\"'>"));
      return bfill.position();
}
}
void loop () {
  word len = ether.packetReceive();
  word pos = ether.packetLoop(len);
  
  if (pos)  {
    bfill = ether.tcpOffset();
    char *data = (char *) Ethernet::buffer + pos;
    
    if (strncmp("GET /", data, 5) !=0){
      bfill.emit_p(http_Unauthorized);
    }
    else {
      data +=5;
      if (data[0] == ' '){
      homePage();
      }
    else if ((strncmp("?cmd=porta", data,10) ==0) && changed_state ==0){
      Serial.println("Im here");
        digitalWrite(RELAY,HIGH);
        Serial.println("Open...");
        delay(5000);
        changed_state=1;
        bfill.emit_p(http_Found);
    }
    else if ((strncmp("?cmd=porta", data,10) ==0) && changed_state ==1){
        digitalWrite(RELAY,LOW);
        Serial.println("Closed...");
        changed_state=0;
        bfill.emit_p(http_Found);
    }
    }
    ether.httpServerReply(bfill.position()); // send web page dat
  }
}

The trouble with this code is that it behaved like a flip-flop, it just changed the state based on the current state, so if the door was locked, it was unlocked and stayed that way until a new button press.

After some thinking I realized I didn't need to use TCP on this application, i just needed some way to receive a UDP package, check its validity and if valid open the door for the specified amount of time. Again based on a example of the ehternet library this was what i got:

//Open Zezzvw3 - Door unlocking mechanism
// 2014-11-29 glitchmaker <glitchmakers at gmail dot com>
// based on the UDP example from
// 2013-4-7 Brian Lee <cybexsoft at hotmail dot com>

#include <EtherCard.h>
#include <IPAddress.h>

#define STATIC 1  // set to 1 to disable DHCP (adjust myip/gwip values below)

#define RELAY 10
#define LED 2

#if STATIC
// ethernet interface ip address
static byte myip[] = { 10,1,21,250 };
// gateway ip address
static byte gwip[] = { 10,1,21,254 };
#endif

// ethernet mac address - must be unique on your network
static byte mymac[] = { 0x70,0x69,0x69,0x2D,0x30,0x31 };

void blink_OK(void){
  digitalWrite(LED,HIGH);
  delay(300);
  digitalWrite(LED,LOW);
  delay(300);
}

void open_door(void){
  Serial.print("Opening door for 5 seconds");
  digitalWrite(RELAY,HIGH);
  digitalWrite(LED,HIGH);
  delay(5000);
  digitalWrite(RELAY,LOW);
  digitalWrite(LED,LOW);
  Serial.print("It's Closed Again!");
}

byte Ethernet::buffer[500]; // tcp/ip send and receive buffer

//callback that prints received packets to the serial port
void udpSerialPrint(word port, byte ip[4], const char *data, word len) {
  Serial.println(data);
  if (strncmp("OPEND0123",data,9)==0){
    open_door();
  }
  else{
    blink_OK();
    Serial.println("Do I know YOU?");
  }
}

void setup(){
  Serial.begin(57600);
  Serial.println(F("\n[backSoon]"));
  int count=0;

  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
    Serial.println(F("Failed to access Ethernet controller"));
#if STATIC
  ether.staticSetup(myip, gwip);
#else
  if (!ether.dhcpSetup())
    Serial.println(F("DHCP failed"));
#endif

  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);
  ether.printIp("DNS: ", ether.dnsip);

  //register udpSerialPrint() to port 1337
 ether.udpServerListenOnPort(&udpSerialPrint, 1337);

  //register udpSerialPrint() to port 42.
  ether.udpServerListenOnPort(&udpSerialPrint, 42);
  
  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);
  pinMode(RELAY,OUTPUT);
  digitalWrite(RELAY,LOW);
  for(count=0;count <=3;count++){
    blink_OK();
  }
}
  
  
  void loop(){
  //this must be called for ethercard functions to work.
  ether.packetLoop(ether.packetReceive());
}
At first it all seem to run, but then I notice that after a few uses the thingy became unresponsive and I needed to reset it. The solution was simple: add a watchdog timer and let it auto reset every time it became unresponsive. All I needed was to add the following lines:
#include <avr/wdt.h>

void setup(){
.
.
.
.
wdt_enable(WDTO_1S);//This start the watchdog timer with a 1 second timeout.
}

void loop(){
wdt_reset();//This resets the timer
.


}

I know what I've done. Since the delay is of five seconds, the watchdog timer timeouts every time the door is unlocked. This way I am sure that the device is always ready.


        

Discussions