Ethernet Doorbell

Yep, today the old Doorbell has been removed and my new Ethernet Doorbell is in use! As you can see the white LED was on when I took the picture on the left, which means that it was dark outside at that time. By polling my Domotica system, the doorbell ‘knows’ whether it’s dark outside or not. Of course it’s not the doorbell itself, but the hardware behind it that does the ‘knowing’: a JeeNode with Ethercard.

All I had to do today was some soldering, finishing the doorbell sketch and pulling the UTP cable through the hole in the wooden door frame. Those last 2 items made it all take a total of 9 hours before I could actually say that the job was completely finished…

Using XMLRPC to communicate to my Domotica system was a bit too much for the 2 kilobytes of RAM on the ATMega. Strings like

<?xml version="1.0"?><methodCall><methodName>GetDevice</methodName><params>
<param><value>DUSKDAWN1.DAYLIGHT</value></param></params></methodCall>

just to get the current value of a dusk/dawn sensor made the amount of free RAM disappear very quickly, so I decided to use another approach I already used some years ago. It hasn’t been used for some time, but it was still available and ready to use. Now all I have to send to my Domotica system is a

GET DUSKDAWN1.DAYLIGHT

and a Indy IdCmdTCPServer takes care of supplying the response. This saves a lot of RAM! Free RAM went up to 900 bytes again, where the XMLRPC method made RAM drop below 200 bytes. And an additional bonus: no need for XML parsing of the response 😉

 

The picture below shows the hardware that’s making it all possible: a JeeNode, an EtherCard and a modified Utility Plug. The cable at the bottom goes to the doorbell, the yellow cable on the right goes to an Ethernet switch and the top right cable is the power supply.

 

And below the sketch that’s currently running on the JeeNode:

 

//
// Doorbell
//
#include <EtherCard.h>
#include <Ports.h>
#include <RF12.h> // needed to avoid a linker error :(
// ethernet interface mac address, must be unique on the LAN
//char website[] PROGMEM = "virtualxp.hekkers.lan";
char website[] PROGMEM = "domoticaserver.hekkers.lan";
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
static byte myip[] = { 192,168,10,75 };
static byte gwip[] = {192,168,10,60 };
static byte dnsip[] = {192,168,10,10 };
static byte hisip[] = {192,168,10,40 };
Stash stash;
MilliTimer DuskDawn;
MilliTimer HeartBeat;
byte Ethernet::buffer[600];
byte HP3=0;
byte VP3=0;
byte night = 0;
byte vnight = 0;
#define DDINTERVAL 60000  // 10 minutes = 600 seconds
#define HBINTERVAL 9000   // 1.5 minutes = 90 seconds
//
// LED & button related stuff
//
Port BlueLed (1);
Port Button (3);
Port WhiteLed (4);
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
void(* resetFunc) (void) = 0; //declare reset function @ address 0
void setup () {
Serial.begin(57600);
Serial.println("[Doorbell_01]");
Serial.println(freeRam());
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println("Failed to access Ethernet controller");
if (!ether.staticSetup(myip, gwip, dnsip))
Serial.print("IP address setup failed");
ether.printIp("IP:  ", ether.myip);
ether.printIp("GW:  ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
if (!ether.dnsLookup(website))
Serial.print("DNS failed");
ether.printIp("SRV: ", ether.hisip);
ether.hisport = 8000;
// port 3 = doorbell button
Button.mode(INPUT);
Button.digiWrite(HIGH);   // pull-up DIO
// BlueLed = push LED
BlueLed.mode(OUTPUT);
BlueLed.digiWrite(0);
// WhiteLed = night LED
WhiteLed.mode(OUTPUT);
WhiteLed.digiWrite(0);
DuskDawn.set(1);
}
static void send_callback (byte status, word off, word len) {
Serial.println("<P<rn");
Ethernet::buffer[off+600] = 0;
Serial.print((const char*) Ethernet::buffer + off);
Serial.println("...");
}
static void poll_callback (byte status, word off, word len) {
const char* res = (const char*) Ethernet::buffer + off;
Serial.println("<G<rn");
Ethernet::buffer[off+600] = 0;
Serial.println(res);
if((res[0]=='R')&&((res[1]=='='))) {
night = (res[2]=='1')?0:1;
Serial.print("n=");
Serial.println(night, DEC);
}
if(res[0]=='E') {
resetFunc();
}
Serial.println("...");
if (night!=vnight)
{
WhiteLed.digiWrite(night);
vnight = night;
}
}
void PollDuskDawn(){
//return;
Serial.println("?");
byte sd = stash.create();
stash.println("DUSKDAWN1.DAYLIGHT");
stash.save();
// generate the header with payload - note that the stash size is used,
// and that a "stash descriptor" is passed in as argument using "$H"
Stash::prepare(PSTR("GET $H"), sd);
// send the packet - this also releases all stash buffers once done
ether.tcpSend(poll_callback);
Serial.println(".");
}
void SendStatus() {
Serial.print("P");
byte sd = stash.create();
stash.print("DB2=");
stash.println(HP3, DEC);
stash.save();
// generate the header with payload - note that the stash size is used,
// and that a "stash descriptor" is passed in as argument using "$H"
Stash::prepare(PSTR("PUT $H"), sd);
// send the packet - this also releases all stash buffers once done
ether.tcpSend(send_callback);
Serial.println(".");
}
void loop(){
ether.packetLoop(ether.packetReceive());
if (ether.clientWaitingGw()) return;
if (DuskDawn.poll(DDINTERVAL)) {
PollDuskDawn();
}
if (HeartBeat.poll(HBINTERVAL)) {
SendStatus();
}
HP3 = !Button.digiRead();
if (HP3 != VP3)
{
if (HP3) {
Serial.println("Button Pressed!");
BlueLed.digiWrite(HIGH);
WhiteLed.digiWrite(LOW);
SendStatus();
HeartBeat.set(HBINTERVAL);
}
else
{
Serial.print("Button Releasedrn");
BlueLed.digiWrite(LOW);
WhiteLed.digiWrite(night);
}
}
VP3=HP3;
}

That’s it! On to the next adventure 😉

 

Doorbell software

Today I continued working on the Doorbell controller hardware & software. First I had to solder a Utility Plug, but I did it somewhat different than usual, I guess:

Utility Plug

(sorry JC, I seem to have some sort of “destructive” way of using your creations 😉

The way I’m going to use this Utility Plug is not standard; the only reason I want to use this Utility Plug is to have a good-fitting RJ12 plug sticking out of the enclosure in a way that it keeps the whole construction as strong as possible. I could just as easily have glued a RJ12 Plug into the enclosure, but with the headers plugged into the carrier board I think I have a stronger construction than without the use of this Plug.

Since I will need to use more than 1 JeeNode Port (a button and 2 LEDs), I made sure that the Utility Plug headers were isolated from the Plug but were still usable construction-wise, so I cut all connections between the headers and the PCB, as can be seen in the picture above. Instead of using the headers, I soldered an Extension cable to the Utility Plug; this way I can do whatever I want with those 6 wires! After checking the header isolation with a multimeter and connecting the Extension cable wires to the JeeNode ports, I was ready to start writing some code. But first, let’s specify how this Ethernet enabled doorbell should behave. It should:

  • Periodically query my system and ask whether it’s dark outside or not and turn on the “night LED” inside the doorbell based on that. If the query fails, it should always turn on the night LED;
  • Switch on the blue “signalling LED” when the button is pressed; if the white night LED is on at that moment, it should switch that one off;
  • Switch off the blue “signalling LED” when the button is released; if it’s dark outside, it should switch the white night LED on;
  • Periodically send a heartbeat to my system;
  • Only send a “Doorbell pressed” message to my system once in a specific time-frame (1 second or so, to eliminate jitter).

I’m almost there! Most of these items are already working, but there are still some small issues to be resolved.  As always, the details take most of the time..

Building the doorbell controller

2 days ago the hardware for the doorbell controller arrived; a JeeNode v6, a Carrier Board, an Ether Card and a Utility Plug. After building the first 3 items on the day they arrived, I was ready to do some tests yesterday. I installed the latest Arduino IDE, the latest RF12, Ports and Ether Card library and hooked up the JeeNode to a USB BUB. I saw the RF12demo sketch appearing in the Serial Monitor; so far so good.

Let’s see if there’s an example sketch in the JeeLabs Ether Card Libary I can quickly modify for testing; yep, the getStaticIP sketch looks OK; I changed some IP addresses, the page to request on my web server and the request interval. I pushed a patch cable into the RJ45 plug, uploaded the sketch and bingo!

Ready! Hmm, no, not really. It all seemed to work perfectly, but after a while I saw strange replies in the Serial Monitor window and I could tell they didn’t belong there. These replies came at times where there hadn’t been a request for several seconds, so where was this reply coming from? I searched the code but couldn’t find out what the status code 3 meant that was returned with these strange replies. Hmm, I don’t like this. Just ignoring those strange replies was easy to do but it just didn’t feel right. There had to be something wrong; I mean, have you ever heard of a garbage filter on a NIC? Me neither.

I decided to dig a little bit deeper. The next morning, while on my way to the office, it hit me: the HTTP 1.1 protocol, doesn’t it use persistent connections by default? And does the connection get closed by either side after the reply has arrived? I checked RFC 2616 and I was right, so the first thing I did when I came home was checking my IIS logs and found the evidence for open connections being closed by IIS after a certain idle period:

192.168.10.203 3031 192.168.10.13 80 - - - - - Timer_ConnectionIdle

That could very well be the cause of those garbage replies I saw on the JeeNode!

Looking at the sketch I saw that the request didn’t contain a Connection:close header line. So my server did not close the connection.. after changing the request to HTTP 1.0, the behavior of the server changed and it closed the connection after sending the reply. This was also visible by the extra header line the server added to the reply: Connection:close. And guess what: the garbage replies no longer appeared and everything’s fine now. Now that traffic between server and JeeNode was clean, I could start working on the enclosure.

I disconnected the USB BUB, grabbed an enclosure and started cutting out holes for the DC jack and the RJ45 plug:

Doorbell controller in enclosureDoorbell controller in enclosure

 

 

 

 

 

 

With the enclosure almost finished I connected a 5V power adapter to the DC jack, put the patch cable back in and I saw the requests arriving at my server again. Perfect!

Doorbell controllerDoorbell controller: case closed

Finishing the Doorbell

 

Today I finished modifying the doorbell with which I started yesterday. I drilled a 4.5 mm hole through the back of the doorbell and led a solid core CAT5 cable through that hole. This cable will be used to connect the doorbell switch and the 2 LEDs (a white and blue one) to the Jeenode that will be placed in the fuse box which is only 2 meters away. The legs of the LED were bent sideways right there where they come out of the LED housing and these legs were temporarily glued to the doorbell housing to secure the position of the LED for easy soldering. You can still see some residue of the glue (the white blur on the housing surface) where the legs of the right LED touch the doorbell housing.

Finishing the hardwareFinishing the hardware

 

 

 

 

 

 

To get a good insulation from the outside world, I pushed the cable through the hole, put hot glue on it and pulled the cable back  a few millimeters; this should suffice for proper insulation. After the wires were cut to the right length and soldered to the legs of the LEDs, it was time to check if everything was working. So I put the 2 halves of the doorbell housing on each other, pressed them firmly, and put the other side of the wire on a breadboard. With a 5V power supply, two 330 Ω resistors and a multimeter I convinced myself that everything was OK.

BTW, it’s a good thing I didn’t choose red as one of the colors for the LEDs; otherwise, a visitor might think he’s being held at gunpoint by a sniper with laser sight 🙂 In other words, the LEDs are a bit too bright, so I think I’ll use a higher resistor value in the final version – that’s why I left the resistors out of the housing in the first place, cause I was anticipating “tuning” issues like this.

Well, now that I have verified that the doorbell is working OK, I can move on to the next step: the JeeNode, some more hardware and the software that goes with it!

 

A new doorbell

One of the things I never liked, was our doorbell. You’ve probably seen or used them, those mostly black plastic boxes with some pieces of copper strips inside; the mechanism relies on those 2 copper spring-like strips to make contact when the button is pressed and return to their old position when the button is released. However, more than once it has happened that if someone pushes the button too hard, the button doesn’t work that well anymore because the strips are bent. Time to do something about this annoying issue and solve this once and for all.

So here’s the most important requirement: the new doorbell should always work. Besides that, I wanted the doorbell to have a distinctive ‘click’ as physical feedback and if possible, also a visible feedback for the person standing in front of our door pushing that doorbell button. Last but not least, the visitor should be able to find the doorbell while standing in front of the door while it’s dark outside. A white LEDs should be able to do just that.

I bought a wireless doorbell once, thinking I could remove the wireless part and just use it as a simple switch . But I was wrong; the button and wireless part were too much integrated for me to do something useful with the PCB that was inside. This wireless doorbell cost me about 30 euro, the looks were OK and I didn’t want it to end up on the shelf with all the rest of the things I’ve bought but never used. Sounds like a good opportunity for some DIY 😉

I removed the PCB from the doorbell, glued a piece of experimenting board into the doorbell and soldered a PCB switch on top of the board:

New Doorbell

Fits perfectly. With this switch you get instant feedback on whether the switch sensed your push because of the audible and tactile click, you can both hear and feel it very well. As visible feedback for pressing the button I decided to use a blue 3mm LED. This LED should cooperate with the white one, which should take care of night visibility: resulting in a blue indicator above the button when it’s pushed, and a white indicator while it’s dark outside.

While working on the new interior of the doorbell, I decided to use a JeeNode with EtherCard to control it all, thereby creating my own Ethernet-enabled doorbell. Why? Because I can! 🙂

To be continued.