Adding Sense Control

While i was quite happy yesterday with the new way i’m going to handle things on the JeeNode regarding the motion sensor (PIR), i already knew i wasn’t finished yet; this was nice, but only a first step.

Cause what i had created was an IRQ being fired when the input becomes low. Well, the PIR output becomes high when there’s motion detected, so this is unusable, actually. For a brief moment i considered using a transistor as a NOT gate to invert the PIR output, but there had to be an easier way. Why would you only be able to activate an External Interrupt when a pin becomes low?? I read some topics on various forums, but those were very contradictory; some said i could, some said otherwise. OK, in that case, i’ll sort it out myself .. cause i really need interrupts based on a rise or a change!

Page 71 of the ATmega datasheet learned me that INT0 and INT1 indeed have Interrupt Sense Control and it’s only a matter of setting the right bits in the External Interrupt Control Register A, aka EICRA:

Bit 3 and 2 of EICRA

So it can be done, only thing is to figure out how…

The Arduino attachInterrupt() function has a 2nd parameter with which you can control what triggers an interrupt; the values are the constants LOW, CHANGE, RISING and FALLING (found in wiring.h). So why didn’t that nice Sleep library i found earlier have this feature? All i can do is call this function:

void SleepClass::powerDownAndWakeupExternalEvent(uint8_t interruptNumber)
{
 attachInterrupt(interruptNumber, SleepClass::external_event_handler, LOW);
 set_sleep_mode_and_sleep(SLEEP_MODE_PWR_DOWN);
 detachInterrupt(interruptNumber);
}

OK; changing things in the library depending on the kind of Sense Control i need for a specific sensor type is not an option of course, so i added a 2nd parameter to that function:

void SleepClass::powerDownAnd...Event(uint8_t interruptNumber, int mode)
{
 attachInterrupt(interruptNumber, SleepClass::external_event_handler, mode);
 set_sleep_mode_and_sleep(SLEEP_MODE_PWR_DOWN);
 detachInterrupt(interruptNumber);

}

That’s better; now i can choose whatever Sense Control I want; I’ve checked all of them right away:

Sleep.powerDownAndWakeupExternalEvent(0, RISING);

What a surprise, its working, all of them! RISING is just what i need right now for the PIR; CHANGE is what i would need for a door sensor.

Now i’m already modifying libraries and I can even understand what

EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);

does… i wonder where or when (if ever) this will end…

But I’m still not finished! Cause with all this powering down going on, it has become increasingly hard to keep a notion of time; millis() has become useless cause how can i determine the time that has passed since the last power down? On the other hand, do i really need to know that? Time will tell ๐Ÿ™‚

Really powering down this time

Having a first set of batteries empty wasn’tย  funny.. they lasted only 7 weeks! Way to short. And i kept on thinking that it might not have been caused by a bad battery.. what could i do next? Wait another 7 weeks to find out that I’m wrong? Neh.. that didn’t feel the right thing to do; Power down as much as possible and use an external interrupt would possibly give the best results anyway, so why not start with that right now!

I started with attaching a push-button to an Arduino, using a pull-up resistor to keep the input high when the button isn’t pressed:

Arduino with push-button

After that i started reading about interrupts. Here’s a table that shows the Wake-up sources that are available in the various sleep modes:

ATmega48PA/88PA/168PA/328P Wake-up sources

Both things i need are available: INT0 and/or INT1 and the Watchdog Timer, so it was time to start sketching ๐Ÿ™‚

After 5 different sketches with all the same miserable results (freezing Arduino), i finally found a sleep library that did exactly what i wanted. I combined this library with code i had found earlier regarding setting up and using the Watchdog Timer, and what i have now, is just what i need. Below a sample of the Serial Monitor output and here is the sketch that produced it.

39171 I'm awake, caused by the WDT
39205 Sleeping...
39327 I'm awake, caused by the WDT
39362 Sleeping...
39484 I'm awake, caused by the WDT
39519 Sleeping...
39640 I'm awake, caused by the WDT
39674 Sleeping...
39796 I'm awake, caused by INT0
Doing some work...finished!
40257 Sleeping...
40377 I'm awake, caused by INT0
Doing some work...finished!
40839 Sleeping...
40960 I'm awake, caused by INT0
Doing some work...finished!
41421 Sleeping...
41542 I'm awake, caused by the WDT
41577 Sleeping...
41698 I'm awake, caused by INT0
Doing some work...finished!
42160 Sleeping...
42280 I'm awake, caused by the WDT
42315 Sleeping...
42437 I'm awake, caused by the WDT
42472 Sleeping...
42593 I'm awake, caused by the WDT
42628 Sleeping...

etc. etc.

Cool stuff! ๐Ÿ™‚ Let’s see how we can change the motion sensor to make use of this!

Dropping fast…

XBee Supply Voltage dropping fast!

Oops… the Supply Voltage on my motion sensor is already down to 3060 millivolts. Suddenly it’s dropping very fast; this sensor has been operational for more then 7 weeks now, with IIRC 2 new and 1 older rechargeable battery of a brand with which i’ve had bad experiences before. I hope that’s what is causing this, cause if not, i have some work to do ๐Ÿ™

The other 2 battery powered sensors are still doing fine, BTW:

Supply Voltages (click to view the realtime values)

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!

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.

New sensor shipment

It took a while before the package arrived, but here they are:

10 1-Wire DS18B20 sensors

10 1-Wire DS18B20 sensors

These sensors are going to be used to monitor the floor heating. This floor heating is made of 5 groups which can be controlled separately (manually, however ๐Ÿ™ ).

In the coming fall i want to be able to monitor the temperature decrease in each group and see what happens when i turn the knobs.. I’m not sure if this will be another job for a JeeNode with XBee or that i’ll use the EDS HA7Net this time because it’s in the neighborhood monitoring the central heating and hot water usage and it still has plenty of capacity for 10 more sensors, so we’ll see.

I don’t know where i got the idea from, probably because i went through a lot of RC hardware lately but those who don’t like soldering wires to these small DS18B20 sensor should consider this:

DS18B20 in a RC servo connector

DS18B20 in a RC servo connector

A DS18B20 fits perfectly in a RC servo connector; they come with 3 wires and you can buy these connectors in any RC hobby shop; this picture only shows the connector without the wire, cause i cut it off years ago for whatever reason. The male connector on the other end of the wire will fit (with a little bit of help) in a 0.1″ raster, like a breadboard..ย  good for building a test setup without any soldering!

Small sensor enclosures

Enclosures can be found in any size you can imagine; but the smaller they get, the less choice there is.

But i found this one:

Small enclosure compared to a MS-13 This reduces the visible size of a motion sensor with more than a half and there’s no more antenna, yippee !

I never liked those MS13 motion sensors because of their size, but they worked ok so i just had to live with them… until now! ๐Ÿ™‚

I placed the new sensor on the door frame next to an existing MS13. What a difference! The enclosure only contains the sensor; all the rest (batteries, JeeNode and XBee module) are located elsewhere; nearby, but out of sight. A wire running from the sensor to the other hardware can be hidden very easily, so all that remains to be seen is this enclosure, measuring 44 x 30 x 15 mm…

Soldering a new JeeNode, connecting the battery holder and the XBee and putting it in an enclosure is all that’s left to do now; so more results can be expected later this week. Exciting!