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;
       }
    }
}
Tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *