Lux sensor finished

Another project is almost finished; my JeeLabs Lux Plug moved inside an enclosure.

JeeNode Lux Plug

JeeNode Lux Plug

The Lux Plug is inside the enclosure with the rest: battery holder, JeeNode and XBee module. In my opinion there was no need to put the sensor in it’s own small enclosure like i did with the motion sensor; there are enough places where i can place this enclosure in such a way that the sensor can measure the light intensity and still be relatively invisible. So this Plug is fitted directly into one of the 4 JeeNode ports and a hole in the enclosure is enough for this sensor to work well.

dsc_3396c_resize2

Another fun project! I saw a Z-Wave sensor a few days ago, costing >100 Euros. Ok, it has a LCD and a beep tone ofcourse (who can live without that!), but basically, it does the same thing: measuring lux! In my opinion, i got more value for money… but hey, who am i 🙂

With a bit of soldering, some code and a lot of fun you can create your own!

#include <Ports.h>
#include <RF12.h>
#include <avr/sleep.h>
#include <NewSoftSerial.h>

#define DEBUG 0

NewSoftSerial XBSerial = NewSoftSerial(2, 3);
PortI2C myBus (1);
LuxPlug sensor (myBus, 0x39);

int pinCTS=6;                         // to monitor CTS
int pinXBee=5;                        // to Control XBee on/off

static int SampleInterval = 30000;
static int HeartBeatInterval = 90000;
static int CTS=0;                     // value of XBee CTS pin

static void lowPower (byte mode) {
    // prepare to go into power down mode
    set_sleep_mode(mode);
    // disable the ADC
    byte prrSave = PRR, adcsraSave = ADCSRA;
    ADCSRA &= ~ bit(ADEN);
    PRR &= ~ bit(PRADC);
    // zzzzz...
    sleep_mode();
    // re-enable the ADC
    PRR = prrSave;
    ADCSRA = adcsraSave;
}

EMPTY_INTERRUPT(WDT_vect); // just wakes us up to resume

static void watchdogInterrupts (uint8_t mode) {
    MCUSR &= ~(1<<WDRF); // only generate interrupts, no reset
    cli();
    WDTCSR |= (1<<WDCE) | (1<<WDE); // start timed sequence
    WDTCSR = bit(WDIE) | mode; // mode is a slightly quirky bit-pattern
    sei();
}

static byte loseSomeTime (word msecs) {
    // only slow down for periods longer than twice the watchdog granularity
    if (msecs >= 32) {
        for (word ticks = msecs / 16; ticks > 0; --ticks) {
            lowPower(SLEEP_MODE_PWR_DOWN); // now completely power down
            // adjust the milli ticks, since we will have missed several
            extern volatile unsigned long timer0_millis;
            timer0_millis += 16L;
        }
        return 1;
    }
    return 0;
}

static MilliTimer SampleTimer;     // Interval for reading a sample from the BMP085
static MilliTimer HeartBeatTimer;  // forced maximum interval (Heartbeat)
word payload;

static byte periodicSleep (word msecs) {
    // switch to idle mode while waiting for the next event
    lowPower(SLEEP_MODE_IDLE);
  // see
  if (loseSomeTime(SampleTimer.remaining()))
    SampleTimer.set(1); // really did a power down, trigger right now

  // return true if the time has come to do something meaningful
  return SampleTimer.poll(msecs);
}

static unsigned long tBusy0;
static unsigned long tBusy1;
static unsigned long tBusyPrev;

static void Send() {

  unsigned long tXB1;    // time XBee was woken up
  unsigned long tXB0;    // time XBee was put to sleep

  HeartBeatTimer.set(0);  // disable heartbeat

  CTS = HIGH;
  tXB0=millis();
  // wake up Xbee
  digitalWrite(pinXBee,LOW);

  // wait for CTS to become LOW
  do
  {
    CTS=digitalRead(pinCTS);
  } while (CTS != LOW);
  tXB1=millis();
  // wait 2 msec otherwise data will be received all messed up
  delay(3);

#if DEBUG
  Serial.print(millis());
  Serial.print(" Send ");
  Serial.print(tXB1-tXB0);
  Serial.print(" ");
  Serial.println(payload);
#endif

  // send dummy data
  XBSerial.print(tBusyPrev);
  XBSerial.print(" ");
  XBSerial.print(tXB1-tXB0);
  XBSerial.print(" ");
  XBSerial.println(payload);

  // wait for XBee to finish transmission
  delay(4);

  // switch off XBee
  digitalWrite(pinXBee,HIGH);

  HeartBeatTimer.set(HeartBeatInterval);
}

int ReadSensor() {

#if DEBUG
  Serial.print(millis());
  Serial.println(" Readsensor");
#endif

    sensor.begin();
    sensor.getData();
    payload = sensor.calcLux();

    return 1;        // always report for now.
}

void setup() {

  // setup XBee
  pinMode(pinXBee,OUTPUT);
  digitalWrite(pinXBee,LOW);
  pinMode(pinCTS,INPUT);
  digitalWrite(pinCTS,LOW);
  delay(10);

  XBSerial.begin(9600);
#if DEBUG
  Serial.begin(9600);
#endif
  // give XBee some time to join PAN
  delay(5000);

  // let the world know we're here
  XBSerial.println("[Lux002]");
#if DEBUG
  Serial.println("[Lux002]");
#endif
 delay(5);

 watchdogInterrupts(0); // 16ms
}

void loop() {
    if (periodicSleep(SampleInterval)) {
      // sensor values changed or heartbeat interval elapsed?
      tBusy0 = millis();
      if (ReadSensor() || (HeartBeatTimer.poll(HeartBeatInterval)))
      {
         Send();
         tBusy1 = millis();
         tBusyPrev = tBusy1-tBusy0;
       }
    }
}

XBee Supply Voltage monitoring (3)

This is what you get when a battery powered XBee is struggling to stay alive cause the batteries aren’t supplying enough ‘juice’ anymore:

FF FF FF FF FF FD 7A 1F 33 40 00 A2 13 00 01 FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 1D 00
01 53 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF 00
00 73 A0 73 B6 70 E0 73 CC 73 E2 06 40 75 5C 76 F0 76 3C 76 B4 76 3C
76 3C 73 F8 74 0E 74 22 75 1C 75 EC 75 60 74 2C 46 50 E6 00 01 02 00
00 00 00 E8 00 01 02 00 00 00 00 F3 E0 58 A0 FF FE 00 EC 30 BC 75 CA
A8 D8 B6 D5 9F FD 5A 7B FF FE 00 00 FF FE 00 00 FF FE 00 00 FF FE 00
00 FF FE 00 00 FF FE 00 00 FF FE FF FF 79 BE 01 4A 01 B0 01 62 01 4E
01 66 01 AC 01 60 01 82 01 9C 01 68 01 B2 01 94 08 1C 08 29 08 34 02
etc. etc. ...

For those not really experienced in recognizing XBee API frames from a byte stream: there’s not a single valid frame to be found inside all those bytes. But this is what my Coordinator received today.

But that’s OK; i intentionally left the XBee running on low batteries; I wanted to see what would happen. My code that should recognize valid XBee API packets just got it’s ultimate real life test. Cause normally, the byte stream coming from the Zigbee Coordinator is so clean you can hardly test it without writing a special tool that creates a mix of garbage, valid and invalid frames. Now i know for sure my code works! 🙂

Another good thing i saw, is that this ‘dying’ XBee didn’t create that much traffic resulting in other XBee’s not being able to get their messages to the Coordinator anymore.

This is really important actually; imagine you’re on holiday and a sensor runs out of battery power; do you really want to monitor your Home Automation system for that kind of trouble while you’re at the other side of the world? Become a slave of your own system? And have to call your neighbor that feeds the cat to remove the batteries or worse ? (“I don’t care how you do it, just do it.. Cut some red wires if you have to!”) Just to keep the system running? Not me!

In the meantime, this really nice weather only makes you want to play outside; sitting behind a computer with an airco blowing cold air in your neck is not my favorite right now:

RC Cars

Batteries are being charged! 🙂

XBee Supply Voltage monitoring (2)

Here are the results of the test i started 3 days ago. After 3 days of monitoring the XBee supply voltage the alkaline batteries were empty and with a bit of tweaking i got the data out of the logs and into an Excel sheet so i could create a chart:

XBee Supply Voltage

XBee Supply Voltage

OK, this looks good and it’s easy to do; all you need are some changed settings on the XBee, a Domotica system that can fire the ‘IS’ remote AT Command to your XBee and your done. Well, almost 🙂

The JeeNode has been running a small sketch that transmits a dummy string every 5 seconds; without any sleeping and also keeping the XBee on all the time:

#include <NewSoftSerial.h>

#define SERDBG 1
NewSoftSerial XBSerial = NewSoftSerial(2, 3);

int CTSpin = 7;
int XBpin  = 6;

static void Send () {
  // send a dummy string
  XBSerial.print(millis());
  XBSerial.print(" ");
  XBSerial.println("XBeeaaaaaa");
#if SERDBG
  Serial.print(millis());
  Serial.print(" ");
  Serial.println("XBeeaaaaaa");
#endif
}

void setup() {
  // setup XBee
  pinMode(CTSpin,INPUT);
  pinMode(XBpin,OUTPUT);
  digitalWrite(XBpin,LOW);
  digitalWrite(CTSpin,LOW);
  delay(10);

  XBSerial.begin(9600);
#if SERDBG
  Serial.begin(9600);
#endif
  // give XBee some time to join PAN
  delay(5000);

  // let the world know we're here
  XBSerial.println("[XBeeVoltage]");
#if SERDBG
  Serial.println("[XBeeVoltage]");
#endif
}

void loop() {
  delay(5000);
  Send();
}

The JeeNode stopped working at around 2/3 of the horizontal axis, so after 48 hours or so where the voltage had already dropped to 2,64 V. The XBee is still working as i write this, with a voltage of 2,3 V. I wonder how long it takes for the XBee to give up too…

Conclusion: this can definitely be used as a way to remotely monitor my battery powered sensors; Yippee!

XBee Supply Voltage monitoring

One thing i would really like, is being able to monitor the voltage the JeeNode and XBee are running on. Now the XBee has a %V command, specially for reading the voltage on the Vcc pin. So let’s see of i can use this.

The first thing i noticed was that the XBee i configured with the AT End Device firmware, didn’t respond to the %V command. Hmm, correct; the manual was very clear about it: the %V command is only supported by a Router  and not by a Coordinator or an End Device. And it’s those End Devices  (which will run on batteries) that i want to monitor…

OK.. next command to have a look at was the ‘IS‘ command, which stands for Force Sample; this command forces a read of all enabled digital and analog input lines and a small comment told me it could also return the supply voltage: “Analog samples are ordered sequentially from AD0/DIO0 to AD3/DIO3, to the supply voltage.”  So lets try this one, shouldn’t be to hard i guess?

So i added support for this command to my API and started sending frames to the XBee:

Sending frame:7E 00 0F 17 01 00 13 A2 00 40 33 1F 7A A2 ED 00 49 53 FB

I won’t go into detail of every byte in the frame above, but the 2 bytes marked in red are the ASCII codes for ‘I’ and ‘S’: yes, ‘IS’, the command we want to be executed on the remote XBee. The response that came back from the XBee was encouraging, however, no supply voltage was present, only the values of some random Analog input lines i enabled:

Rcvd Frame:97 01 00 13 A2 00 40 33 1F 7A A2 ED 49 53 00 01 00 00 02 02 09
FrameID=1, Command=IS, Status=0, Command Data size = 6 (01 00 00 02 02 09)

With the help of an example i found out the meaning of the Command data:

IS response example

IS response example

OK… the frames that were being received looked nice, but it’s not what i want… where’s the supply voltage? The example above doesn’t show it either.. but it must be possible, right?

After searching for more than an hour, i suddenly bumped upon a setting in the X-CTU tool (in the I/O Sampling section), that had the following description:

Configure the supply voltage high threshold.  If the supply voltage measurement equals or drops below this threshold, the supply voltage will be included in an IO sample transmission.  RANGE:0-0XFFFF

Aahh, that must be it… this setting has a default of 0, causing the supply voltage to never be included in an IO sample! I set the value to FFFF, disabled all other I/O lines on the XBee et voila:

Rcvd Frame:97 01 00 13 A2 00 40 33 1F 7A A2 ED 49 53 00 01 00 00 80 0A BC
FrameID=1, Command=IS, Status=0, Command Data size = 6 (01 00 00 80 0A BC)

This means there is 1 sample set, containing the supply voltage, and the value is: 0ABC.

Multiply this with 1200/1024 and you get the supply voltage in mV:

($0ABC =) 2748 * 1200/1024 = 3220 mV. Great!

Tomorrow i’ll add some code to my HA system to periodically send an IS command to this XBee and store the results. And then just wait and see what happens when i let a JeeNode and XBee running on alkaline batteries 24/7…

New motion sensor in use

After my problems with the MS13 sensors yesterday, i managed to find some spare time (even though, or maybe because it was father’s day) to write a sketch for the new motion sensor i created during the last couple of weeks. Always taking one step at a time, i located the first prototype of this sensor at a place where i can see the enclosure LED from the living room: i want to know how it performs…

New motion sensor

New motion sensor

Now powered by 3 rechargable NiCd batteries and with all hardware nicely put away in the enclosure. In due time the enclosure will be moved out of sight so only the PIR will be visible. I’ve decided to use 3.5 mm jack plugs to be able to disconnect the enclosure from the sensor, so i can easily take the enclosure back to my office, because i don’t think the JeeNode is already running the final version of the ‘PIR’ sketch… 🙂

A new class, 2 database records and 1 line of code were enough to get the sensor working in my Domotica system:

procedure TAMN31112.ProcessInterfaceData;
begin
  Pin(1).AsBoolean:= (O.Data[1]='1');
end;

The new PIR can be viewed from my website (it’s called BP PIR):

Battery powered PIR

Battery powered PIR

The sketch is still under development; for instance, how much difference would it make if i change the DigitalRead() into a bitRead()? I’ll have to read more about that on JeeLabs … Other questions are: should i increase the heartbeat interval (currently 45 seconds) or the Motion report interval? Can i create some sort of battery power monitoring with the XBee? But that will all be investigated when i’ve finished building my second motion sensor based on JeeNode and XBee..

Motion sensor in next stage

This weekend i spent some time to make the experimental PIR sensor setup i made some time ago, a bit more permanent. Ingredients:

Enclosure modified with hobby knifeThe enclosure i used this time is a bit different from the enclosure i used on a previous occasion. This one lacks the inner ribs and opening and closing is a bit harder: for opening the enclosure you need to put a screwdriver between the 2 halves and twist it to get the enclosure open.  The first thing i did was making my life easier by removing the ribs that keep the 2 halves together on one side of the enclosure. Some more modifications here and there now make it possible to open the enclosure without any additional tools, but still will not open by accident.

PIR enclosurePIR enclosure

I drilled a 10 mm hole into the PIR enclosure so that the PIR fitted nicely through the top plate; a drop of super glue on the inside did the rest. There was plenty of room for the 100k pull-down resistor inside the PIR enclosure so i soldered it to the PIR there. An extra hole of 4 mm and a cable tie for the wire completed the PIR box.

JeeNode, XBee

JeeNode, XBee

This being my first motion sensor built this way, i added a LED to be able to see what the XBee radio is doing; is it still transmitting or not, when, how often, etc. ? Maybe this is overkill, but when this sensor is placed somewhere in the house with no computer screen nearby, it can be very handy to see if the sensor is still functioning instead of running to and from the nearest screen…
If the flickering of the LED is to visible or annoying in the future, i can always disable it or make it invisible by a piece of tape over it; but for now, this LED seemed like a good idea to have. The LED lights up when the XBee is on and from the duration that the LED stays on i can see what’s happening; whether it’s transmitting (very short durations) or having PAN trouble (long).

The software part of this sensor will be the most time consuming of it all i guess. Since i want it to be battery powered, i’ll have to consider what is relevant information for my Domotica system, and when it is. In fact, the only thing that really matters is one single thing: fast motion detection! All the rest is less important.
Cause what do we Domoticans use this motion detection for? To turn things ON… not OFF; at least, i don’t.

Further more, a quick look in my events history tells me that from 01-04-2010 till today i missed (my 433 MHz RFXCOM receivers, i mean) a total 869 ‘OFF’ transmissions (meaning “no motion”) from my 10 MS13 motion detectors. That’s way to much to be called reliable! So my system already has the capability to deal with this situation of missing ‘OFF’ transmissions; when a MS13 hasn’t reported neither an ‘ON’ nor an ‘OFF’ for a specific time interval, i set the motion sensor back to ‘OFF’ in software.

So.. i could as well do without this ‘OFF’ completely; i don’t use it as a trigger, so why send this non-information anyway?

What i do want to have is a heartbeat, every 90 seconds or so. And i would like to have an ‘ON’ being sent with a specific interval when motion is detected continuously. That’s what I’ll be working on in the coming week.

To be continued.

JeeNode/ZigBee pressure sensor closed

Now that my Zigbee/Jeenode equipped pressure sensor is working for 3 months without any problems, it was time to leave the breadboard stage and move on to something more permanent. While ordering new Jeenodes at Jean-Claude Wipplers shop, i stumbled upon a post (i should read his daily weblog more often!) that showed me just what i needed: an enclosure that looked just right for this job. I ordered the Jeenodes, 2 enclosures (1 extra for when i mess up the first one and don’t want to wait for a second delivery..) and some other handy stuff.

First i sawed off the part of the PCB that i didn’t need, to decrease it’s size.

JeeNode PCB without RF part

JeeNode PCB size reduction

Guess what? Now the length of the PCB equals the internal width of the enclosure! Nice… I still had some battery holders laying around that also fitted quite well:

Enclose, batt holder and JeeNode

Enclosure, batt holder and JeeNode

I didn’t want to leave off the FTDI headers, so i used 6 straight headers and removed the plastic strip from the headers after the headers were soldered onto the PCB. With the plastic headers left on, the completed PCB was just a bit to wide for the enclosure, which caused tension and the enclosure wouldn’t close well anymore.

Next item that had to be prepared, was the XBee Breakout Board. Normally the top of this Breakout Board contains the 2mm XBee headers and the 0.1″ spaced headers are at the opposite side. I removed the bottom headers i soldered in when i used this board for other purposes and soldered 6 wires on it from the top, only for those pins i really needed:

XBee Breakout Board

XBee Breakout Board

Pin 1 (labeled Vcc) for Power, Pin 3  (labeled DIN) for transmission, Pin 9 (DTR) for controlling Sleep mode, Pin 10 (GND), Pin 11(CTS) and Pin 12 (ON) for the LED. This makes the Breakout board a lot thinner and the wires are coming out between the board and the XBee module.

After soldering the wires coming from the XBee board to the JeeNode, drilling a hole for the LED (which blinks when a pressure sample is being sent), soldering the wires and gluing the battery holder into the enclosure, it looked like this:

Almost done!

Almost done!

The FTDI headers are very handy now, for uploading the sketch with the JeeNode already inside the enclosure; cause all you have to do is open the enclosure, gently lift up the left side of the JeeNode and connect the cable. So whenever i need to upgrade the JeeNode, i don’t have to worry about connecting issues.

FTDI cable connected to the JeeNode

FTDI cable connected to the JeeNode

Now all there was left to do was moving the XBee module and the Pressure Plug from the Breadboard to their new ‘home’, add 4 batteries, click on the other half of the enclosure and.. my first WAF certified sensor was born!

Zigbee Pressure sensor

First DIY Zigbee sensor operational

On my desk i have a JeeNode, equipped with a Pressure sensor. This JeeNode is also controlling a XBee Series 2 module which is configured as Zigbee End Device. All this is battery powered. Calculations on power usage of the JeeNode+Sensor+XBee are good enough to expect an acceptible battery life. A Sparkfun XBee RS232 holds another XBee module, configured as Zigbee coordinator. This setup has been operating for more than a week now. It all looks stable enough to go ahead and connect the Zigbee network (ok, it’s only 2 nodes right now 🙂 ) to my Domotica system and  actually do something with it; something different from logging the incoming pressure data to a text file and reviewing this file periodically to see if everything is still up and running; so i added another (the 16th) interface to my Domotica system: Zigbee! 🙂

In fact all the hard work had already been done in an earlier stage where i created an API-mode interface for Zigbee; in essence, the only thing left to do was making this interface ‘talk’ to the rest of the Home Automation system, add some records in the database for this new sensor type and write a routine that would convert the incoming packets to the measured values of temperature and pressure.

Zigbee interface

Wow! It’s great to see my first Zigbee based sensor really working! The pressure data is being stored in the database, so in a few hours i can start creating an additional web page to show a pressure chart… and here it is!

BMP085 Pressure sensor data

BMP085 Pressure sensor data

Next on the list: finding a suitable, small housing, making a light sensor, a motion sensor, humidity sensor, … the list is to long! 🙂

Battery powered sensors

Now that i have 2 JeeNodes up and running for more than a week and everything’s working fine, it’s time to do some calculations on power usage of the sensors. First thing i wanted to know was how much power a combination of a sensorless Jeenode and XBee module was using, so i created a sketch that would give me some ‘inside’ information about what was going on inside the Jeenode. The sketch i made informs me about a couple of things, like:

– the timespan the JeeNode is awake to power up the XBee, send a packet to the XBee and wait for it to finish transmission;

– the timespan the XBee is powered to send that packet of 10 bytes.

Battery powered JeeNode

With these numbers i should be able to roughly calculate the power usage of this sensor. The power that is used by the JeeNode while it’s awake is about 35 mA, while the XBee uses around 40 mA while transmitting. When both the JeeNode and XBee are in deep sleep, the combination of both uses only 60 μA.

The time measurements i did to find out the timespans mentioned above gave me the following figures: the total time the JeeNode is awake to read a sample from the Pressure sensor, wake the XBee, transmit the data and go back to sleep is 40 ms. The time that the XBee is awake is around 25 ms. With a sample interval of 30 seconds, and a 2000 mAh battery, i have calculated a battery life of more than a year; increase the interval to 60 seconds (still good enough for this type of information) and batteries should survive more than 2 years… i think.

Just ask me in a year or so ..

But good enough to go ahead with the expedition! 🙂

Wireless Pressure Sensor – small fix

The fact that in the setup i made yesterday, the XBee module sometimes had trouble setting up the connection was troubling me, so i tried to figure out what was going on. My guess was that the CTS line was not monitored, so i built a counter into the loop that waits for CTS to get high; and made this counter part of the packet payload so that i could monitor what was going on; this counter  was always 1, meaning CTS was high at the time the first CTS check was done!

Hmm, seeing that, the error was found very quickly: CTS was attached to the wrong digital input, so CTS wasn’t monitored at all… fixed the wiring and now everything’s OK.

Second thing i changed was for the sake of convenience: the new sketch does the temperature and pressure calculations “on board”, so now the payload immediately shows value that are easily interpreted. I also took the time to create a small Delphi program that uses my XBee API to log all the packets that are received in a more readable style:

31-1-2010 20:43:30:Packet payload=[2 215 100159]
31-1-2010 20:43:41:Packet payload=[7 215 100150]
31-1-2010 20:43:52:Packet payload=[0 215 100153]
31-1-2010 20:44:03:Packet payload=[0 215 100156]
31-1-2010 20:44:14:Packet payload=[0 215 100166]
31-1-2010 20:44:25:Packet payload=[5 215 100156]
31-1-2010 20:44:36:Packet payload=[10 215 100159]
31-1-2010 20:44:47:Packet payload=[0 215 100150]
31-1-2010 20:44:59:Packet payload=[0 215 100156]
31-1-2010 20:45:10:Packet payload=[0 214 100153]

The first value is the time in milliseconds that it takes for the CTS to become high, the second value is the temperature in 1/10th of a degree and the last value is the pressure in mbar.  Neat 🙂