Something old and something new

While I’m logging data and waiting for it to become substantial enough to test another project with, I thought it would be nice to kill the time and start building some new sensors: motion, temperature and light.

My goal is to monitor the complete second floor. For the 3 bedrooms I want to monitor motion, temperature and light. The passage will only require motion and light, while measuring the humidity in the bathroom would be nice too.

So, for that I need the following:

  • 5 * motion;
  • 4 * temperature;
  • 5 * light;
  • 1 * humidity.

I already have the motion sensors (PIR), the temperature sensors (1-Wire DS18B20), light sensors (LDR), enough JeeNodes, so all I need is a new humidity sensor.

OK; the amount of sensors I want to use is a bit too much for a single JeeNode I guess. Maybe 2 JeeNodes will suffice? I didn’t do any math on this yet, but I don’t think a single JeeNode can do the job all on its own. 2 JeeNodes maybe, cause the temperature sensors can be on a single 1-Wire bus, so those sensors won’t use up much ports on the JeeNode; and maybe I can use an Analog Plug to measure the LDRs? We’ll see. But for now, I assume I’ll need more than 1 JeeNode. However, I don’t like to spend an XBee module on each of those JeeNodes, cause I want to keep it relatively low cost. Yeah I know, there are cheaper alternatives for XBee..

But wait, I’ve still got an Arduino Fio; I’ve bought it sometime in January, not for a specific purpose but just to have a look at it, and I never found a good use for it yet. This Fio is also based on the ATmega328P and runs at 3.3V and 8 MHz. And it also has an XBee socket and USB connector. And it’s getting old, gathering dust on the shelf…

Now why don’t I use this Fio as a ‘hub’, or ‘central node’? It shouldn’t be too hard to make the (1,2,..) JeeNodes talk to this Arduino Fio over a few wires and use the Fio to transmit all the sensor values to the Zigbee coordinator; now that would be nice! I could power this Fio with a small USB power adapter and run a few wires (for power and serial connection) to the JeeNodes. Maybe I could just as easily use 1 JeeNode per room; this leaves enough ports available for future expansion… well, let’s think this one over for some time!

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..