Skip to content
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. Development
  3. Battery powered PIR and temp/humid sensor
  • Getting Started
  • Controller
  • Build
  • Hardware
  • Download/API
  • Forum
  • Store

Battery powered PIR and temp/humid sensor

Scheduled Pinned Locked Moved Development
22 Posts 7 Posters 7.7k Views 8 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    tomkxy
    wrote on last edited by
    #1

    I have built a battery powered PIR temp/humidity and light sensor. I based the sketch on the Sensebender sketch which allows to control how long the sensor sleeps and how often to report measurements back. I changed the sketch now so that when the PIR is triggered an interrupt wakes up the sensor.

     gw.sleep(INTERRUPT,RISING, MEASURE_INTERVAL);
    

    This is all working well. However, now I lost total control over measurement intervals and send intervals. If I get it right retrieving millis will not work since they are not counted while the sensor sleeps.
    Any ideas how to solve that.

    1 Reply Last reply
    0
    • L Offline
      L Offline
      LastSamurai
      Hardware Contributor
      wrote on last edited by
      #2

      There is another sleep method which also takes a time in millis and wakes on both, intervall and interrupt. That might be a solution?!

      1 Reply Last reply
      0
      • T Offline
        T Offline
        tomkxy
        wrote on last edited by
        #3

        @LastSamurai: I am using that method. My problem is that due to the fact that motion will trigger the interrupt and hence the sleep time in between measurements vary depending on movements. So when there is a lot of motion the send and measurement frequency will be much shorter and thus draining the battery faster.

        1 Reply Last reply
        0
        • hekH Offline
          hekH Offline
          hek
          Admin
          wrote on last edited by
          #4

          The return value from gw.sleep tells you if it woke up on timer or pin.

          So just send motions status when pin triggered. If timer triggered wakeup send temp.

          1 Reply Last reply
          0
          • T Offline
            T Offline
            tomkxy
            wrote on last edited by
            #5

            @hek This will definitely help but it still means that there is no real means to control the time between temp/humid measurements. In the worst case the PIR triggers over a longer time always the interrupt and thus temp is never send. Even if I introduce some counter which when reached will trigger a temp measurement I have no glue what the interval length in between is. Or do I miss something?

            hekH 1 Reply Last reply
            0
            • T tomkxy

              @hek This will definitely help but it still means that there is no real means to control the time between temp/humid measurements. In the worst case the PIR triggers over a longer time always the interrupt and thus temp is never send. Even if I introduce some counter which when reached will trigger a temp measurement I have no glue what the interval length in between is. Or do I miss something?

              hekH Offline
              hekH Offline
              hek
              Admin
              wrote on last edited by
              #6

              @tomkxy

              I don't understand.. the timer option will wake your board at the specified time even if no motion was detected.

              1 Reply Last reply
              0
              • T Offline
                T Offline
                tomkxy
                wrote on last edited by
                #7

                @hek

                Sorry, I didn't express it well enough.
                Let's say my sketch would sleep between two measurements 60 sec and send every 30 measurements its value, which means every 30 minutes (which are the defaults of the sensebender sketch). I can increase or reduce the frequency by adjusting the sleep times and send intervals easily.

                By introducing the interrupt - which I think there is no way around -, the sleep time can be interrupted somewhere between 1 second and 60 seconds. And I don't know how long my sketch has slept. If I cannot determine the time how long my sketch was sleeping I cannot determine when I should take the next temp/humid measurement. Although I can still use the loop counter, I have no control over the elapsed time between two temp/humid measurements.

                1 Reply Last reply
                0
                • hekH Offline
                  hekH Offline
                  hek
                  Admin
                  wrote on last edited by
                  #8

                  True, if you wake up from pin change you haven't the exact knowledge of elapsed time (< MAX-SLEEP-TIME though).

                  But in most applications I doubt it would super exact temp-send-interval would matter much... It will only diff when pin change wake-up interfere.

                  1 Reply Last reply
                  0
                  • T Offline
                    T Offline
                    tomkxy
                    wrote on last edited by
                    #9

                    @hek

                    Thanks! That confirms my understanding.

                    1 Reply Last reply
                    0
                    • HaakonH Offline
                      HaakonH Offline
                      Haakon
                      wrote on last edited by
                      #10

                      @tomkxy: Have you gathered some experiences with this setup over time? And would you mind sharing the Arduino sketch you are using?

                      I am hoping to do more or less the same with Sensebenders and PIRs, and I am new to electronics of this sort.

                      1 Reply Last reply
                      0
                      • T Offline
                        T Offline
                        tomkxy
                        wrote on last edited by
                        #11

                        @Haakon I have one of these sensor in place since about half a year and it is working well. Last battery change is about 4 month ago.

                        Please find the sketch below which requires some cleanup.

                        /*
                        Multisensor Sketch
                        
                        Author: Thomas Krebs, thkrebs@gmx.de
                        
                        This sketch reads temperature, humidity, light and presence.
                        It is based on the various examples sketches from SparkFun and MySensors 
                        
                        It uses the following sensors:
                        Light           - TSL2561
                        Temp&Humidity   - HTU21D
                        Presence 
                        
                        HTU21D and TLS2561 need to connect the I2C pins (SCL and SDA) to your Arduino.
                        The pins are different on different Arduinos:
                        
                                            SDA    SCL
                        Any Arduino         "SDA"  "SCL"
                        Uno, Redboard, Pro  A4     A5
                        Mega2560, Due       20     21
                        Leonardo            2      3
                        
                        */
                        #define MY_DEBUG_VERBOSE_SIGNING //!< Enable signing related debug prints to serial monitor
                        
                        #define MY_SIGNING_FEATURE
                        #define MY_SIGNING_ATSHA204
                        #define MY_SIGNING_REQUEST_SIGNATURES
                        
                        #define MY_DEBUG
                        #define MY_NODE_ID              26
                        #define MY_RADIO_NRF24
                        #define BATT_SENSOR
                        
                        #include <MySensor.h>
                        #include <TSL2561.h>
                        #include <SparkFunHTU21D.h>
                        
                        #include <SPI.h>
                        #include <Wire.h>
                        #include <avr/power.h>
                        
                        #define VERSION           "1.4"
                        #define SKETCH_NAME       "Multisensor A"
                        
                        #define TEMP_CHILD_ID   1
                        #define HUM_CHILD_ID    2
                        #define LIGHT_CHILD_ID  3
                        #define MOTION_CHILD_ID 4
                        
                        // Uncomment the line below, to transmit battery voltage as a normal sensor value
                        #define BATT_SENSOR    199
                        #define MAX_VOLTAGE    1316
                        #define MIN_VOLTAGE    890     // it seems that about 0.89 V the sensor stops working
                        
                        // How many milli seconds between each measurement
                        #define MEASURE_INTERVAL 120000
                        
                        // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller
                        #define FORCE_TRANSMIT_INTERVAL 30 
                        
                        // When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes.
                        // Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement
                        
                        // HUMI_TRANSMIT_THRESHOLD tells how much the humidity should have changed since last time it was transmitted. Likewise with
                        // TEMP_TRANSMIT_THRESHOLD for temperature threshold.
                        #define HUMI_TRANSMIT_THRESHOLD   0.5
                        #define TEMP_TRANSMIT_THRESHOLD   0.5
                        #define LIGHT_TRANSMIT_THRESHOLD  0.3    // relative change
                        
                        
                        // Pin definitions
                        #define LED_PIN            13            // TODO: need to check that
                        #define BATTERY_SENSE_PIN  A0            // select the input pin for the battery sense point
                        #define MOTION_SENSOR      3             // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
                        #define INTERRUPT          1             // Usually the interrupt = pin -2 (on uno/nano anyway)
                        
                        // Global settings
                        int tempMeasureCount = 0;
                        int lightMeasureCount = 0;
                        
                        int sendBattery = 0;
                        boolean isMetric = true;
                        boolean highfreq = true;
                        boolean motionDetected = false;
                        int repeats = 2;
                        
                        // Storage of old measurements
                        float lastTemperature = -100;
                        float lastHumidity = -100;
                        long  lastBattery = -100;
                        long  lastLight = -5000;
                        int   lastTripped = -1; 
                        
                        int   motionTrips = 0;  // count the number of cont. motion trips
                        
                        HTU21D myHumidity;
                        TSL2561 myLight(TSL2561_ADDR_FLOAT); 
                        
                        // Sensor messages
                        MyMessage msgTemp(TEMP_CHILD_ID,V_TEMP);
                        MyMessage msgHum(HUM_CHILD_ID,V_HUM);
                        MyMessage msgLight(LIGHT_CHILD_ID,V_LEVEL);
                        MyMessage msg(MOTION_CHILD_ID, V_TRIPPED);
                        
                        
                        #ifdef BATT_SENSOR
                        MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE);
                        #endif
                        
                        
                        /****************************************************
                         *
                         * Setup code 
                         *
                         ****************************************************/
                        void setup()  
                        { 
                          pinMode(LED_PIN, OUTPUT);
                          Serial.print(F(SKETCH_NAME));
                          Serial.println(VERSION);
                          Serial.flush();
                          
                          
                        #ifdef MY_SIGNING_ATSHA204_PIN
                          // Make sure that ATSHA204 is not floating
                          pinMode(MY_SIGNING_ATSHA204_PIN, INPUT);
                          digitalWrite(MY_SIGNING_ATSHA204_PIN, HIGH);
                        #endif  
                          
                          // use the 1.1 V internal reference
                          analogReference(INTERNAL);
                        
                          // setup sensors
                          setup_htu21d();
                          
                          delay(100);
                          setup_tls2561(); 
                          delay(500);
                          
                          // setup motion sensor 
                          pinMode(MOTION_SENSOR, INPUT);    
                          Serial.println(F("Setup complete..."));
                        }
                        
                        
                        void presentation()  {
                          // Send the sketch version information to the gateway and Controller
                          sendSketchInfo(SKETCH_NAME, VERSION);
                        
                          // Present all sensors to controller
                          present(TEMP_CHILD_ID, S_TEMP);
                          present(HUM_CHILD_ID, S_HUM);
                        //  present(LIGHT_CHILD_ID,S_LIGHT_LEVEL);
                          present(MOTION_CHILD_ID, S_MOTION);
                        
                        
                        #ifdef BATT_SENSOR
                          present(BATT_SENSOR, S_POWER);
                        #endif
                        
                          isMetric = getConfig().isMetric;
                        #ifdef MY_DEBUG
                          Serial.print(F("isMetric: ")); Serial.println(isMetric);
                        #endif
                        
                          Serial.flush();
                          Serial.println(F(" - Online!"));
                        }
                        
                        
                        /***********************************************
                        /* Setup HTU21d
                         ***********************************************/
                        void setup_htu21d() {
                          myHumidity.begin();
                        #ifdef MY_DEBUG  
                          Serial.println("Setup temp/humid sensor completed");
                        #endif
                        }
                        
                        
                        /***********************************************
                        /* Setup TLS2561
                         ***********************************************/
                        void setup_tls2561() {
                         
                          if (myLight.begin()) {
                            Serial.println(F("Found light sensor"));
                          } else {
                            Serial.println(F("Light Sensor not found - cont. anyway"));
                          }
                          myLight.setGain(TSL2561_GAIN_0X);          // set 16x gain (for dim situations)
                          
                          // Changing the integration time gives you a longer time over which to sense light
                          // longer timelines are slower, but are good in very low light situtations!
                          //tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS);  // shortest integration time (bright light)
                          myLight.setTiming(TSL2561_INTEGRATIONTIME_101MS);  // medium integration time (medium light)
                          //tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS);  // longest integration time (dim light)
                          
                        }
                        
                        /***********************************************
                         *
                         *  Main loop function
                         *
                         ***********************************************/
                        void loop()     
                        { 
                          tempMeasureCount++;
                          lightMeasureCount++;
                          sendBattery++;
                          bool forceTransmit = false;
                        
                          if (motionDetected) {
                            sendMotion(false);  // do not force transmission unless motion status has changed
                            motionDetected = false;
                          }
                          
                          // do not enter into sensor data gathering on each motion tripped
                          if ((!motionDetected) || (motionTrips > 3)) {
                            motionTrips = 0; // avoid starvation of temp measure in case we have a lot of motion
                            
                            // I do the battery check at the beginning
                            if (sendBattery > 60) {
                               sendBattLevel(forceTransmit); // Not needed to send battery info that often
                               sendBattery = 0;
                            }
                            
                            if ((lightMeasureCount > FORCE_TRANSMIT_INTERVAL) || (tempMeasureCount > FORCE_TRANSMIT_INTERVAL) ) { // force a transmission
                              forceTransmit = true; 
                              tempMeasureCount = 0;
                              lightMeasureCount = 0;
                            }
                          
                            // Get & send sensor data
                            wait(200);
                            sendTempHumidityMeasurement(forceTransmit);
                            wait(200);
                            sendLightLevelMeasurement(forceTransmit);
                            wait(200);
                            sendMotion(forceTransmit);
                          } 
                          wait(100);  // I don't know whether that is really required; however I have the impression that shutting down the radio leads to
                                         // problems in the communication when using signatures
                          Serial.println("going to sleep");
                          if (sleep(INTERRUPT,RISING, MEASURE_INTERVAL)) {
                            motionDetected = true;
                            motionTrips++;
                          }
                          Serial.print("Motion detected="); Serial.println(motionDetected);
                        }
                        
                        /*********************************************
                         *
                         * Sends state of motion sensor
                         *
                         * Parameters
                         * - force : Forces transmission of a value (even if it's the same as previous measurement)
                         *
                         *********************************************/
                        void sendMotion(bool force) {
                         
                          bool tx = force;
                          
                          // Read digital motion value
                          bool tripped = digitalRead(MOTION_SENSOR) == HIGH; 
                          Serial.print(F("Tripped: ")); Serial.println(tripped);
                          
                          if (lastTripped != tripped) tx = true;
                          if (tx) {
                            resend(msg.set(tripped?"1":"0"),repeats);  // Send tripped value to gw 
                            lastTripped = tripped;
                          }
                        }
                        
                        /*********************************************
                         *
                         * Sends temperature and humidity from HTU21D sensor
                         *
                         * Parameters
                         * - force : Forces transmission of a value (even if it's the same as previous measurement)
                         *
                         *********************************************/
                        void sendTempHumidityMeasurement(bool force) 
                        {
                            bool tx = force;
                            
                            float hum = myHumidity.readHumidity();
                            float temp = myHumidity.readTemperature();
                            
                            Serial.print(F("lastTemperature: ")); Serial.println(lastTemperature);
                            Serial.print(F("lastHumidity: ")); Serial.println(lastHumidity);
                            
                            float diffTemp = abs(lastTemperature - temp);
                            float diffHum = abs(lastHumidity - hum);
                        
                        #ifdef MY_DEBUG
                            Serial.print(F("TempDiff :"));Serial.println(diffTemp);
                            Serial.print(F("HumDiff  :"));Serial.println(diffHum); 
                        #endif
                        
                            if (isnan(diffHum)) tx = true; 
                            if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true;
                            if (diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true;
                        
                            if (tx) {
                              tempMeasureCount = 0;
                              resend(msgTemp.setSensor(TEMP_CHILD_ID).set(temp,1),repeats); 
                              wait(20);
                              resend(msgHum.setSensor(HUM_CHILD_ID).set(hum,1),repeats); 
                              lastTemperature = temp;
                              lastHumidity = hum;   
                            }
                        }
                        
                        
                        /*********************************************
                         *
                         * Sends light level from TLS6512 sensor
                         *
                         * Parameters
                         * - force : Forces transmission of a value (even if it's the same as previous measurement)
                         *
                         *********************************************/
                        void sendLightLevelMeasurement(bool force) {
                          bool tx = force;
                          
                          uint32_t lum = myLight.getFullLuminosity();
                          uint16_t ir, full;
                          ir = lum >> 16;
                          full = lum & 0xFFFF;
                          
                          Serial.print(F("IR: ")); Serial.print(ir);   Serial.print(F("\t\t"));
                          Serial.print(F("Full: ")); Serial.print(full);   Serial.print(F("\t"));
                          Serial.print(F("Visible: ")); Serial.print(full - ir);   Serial.print(F("\t"));
                          
                          double lux = myLight.calculateLux(full, ir);
                          Serial.print(F("Lux: ")); Serial.println(lux);
                          float diffLux = abs(lastLight - lux);
                        #ifdef MY_DEBUG
                            Serial.print(F("Lux difference since last measurement: ")); Serial.println((float)diffLux/abs(lastLight));    
                        #endif
                            if (isnan(diffLux)) tx = true; 
                            if (diffLux/abs(lastLight)  >= LIGHT_TRANSMIT_THRESHOLD) tx = true;
                        
                            if (tx) {
                              lightMeasureCount = 0;
                              resend(msgLight.setSensor(LIGHT_CHILD_ID).set(lux,1),repeats);
                              lastLight = lux;
                            }
                        }
                        
                        
                        /*********************************************
                         * Prints error on I2C comm bus
                         *********************************************/
                        void printError(byte error)
                          // If there's an I2C error, this function will
                          // print out an explanation.
                        {
                          Serial.print(F("I2C error: "));
                          Serial.print(error,DEC);
                          Serial.print(F(", "));
                          
                          switch(error)
                          {
                            case 0:
                              Serial.println(F("success"));
                              break;
                            case 1:
                              Serial.println(F("data too long for transmit buffer"));
                              break;
                            case 2:
                              Serial.println(F("received NACK on address (disconnected?)"));
                              break;
                            case 3:
                              Serial.println(F("received NACK on data"));
                              break;
                            case 4:
                              Serial.println(F("other error"));
                              break;
                            default:
                              Serial.println(F("unknown error"));
                          }
                        }
                        
                        
                        /********************************************
                         *
                         * Sends battery information (battery percentage)
                         *
                         * Parameters
                         * - force : Forces transmission of a value
                         *
                         *******************************************/
                        void sendBattLevel(bool force)
                        {
                          if (force) lastBattery = -1;
                          long batteryV =  analogRead(BATTERY_SENSE_PIN);  
                          for (int i = 1; i<5; i++) {
                            long newSample = analogRead(BATTERY_SENSE_PIN); //readVcc();
                            batteryV -= batteryV / (i+1);
                            batteryV += newSample / (i+1);   
                          }
                           
                           // 10M, 2,86M divider across battery and using internal ADC ref of 1.1V
                           // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
                           // ((10+4,7)/4,7)*1.1 = 3.4404255
                           // 3.4404255/1023 = Volts per bit = 0.003630748
                        
                          long vcc  = batteryV * 3.3630748;
                          if (vcc != lastBattery) {
                            lastBattery = vcc;
                        
                        #ifdef BATT_SENSOR
                            resend(msgBatt.set(vcc),repeats);
                        #endif
                            // Calculate on the fully charged cell. Since I have a step-up in place I go as low as possible no offset for minimum
                           sendBatteryLevel(  ((vcc-MIN_VOLTAGE)*10.0)/((MAX_VOLTAGE-MIN_VOLTAGE)*10.0) *100.0);
                          }
                        }
                        
                        
                        /********************************************
                         *
                         * Send message, resend on error
                         *
                         * Parameters
                         * - msg : message to send
                         * - repeats: number of repetitions
                         *
                         *******************************************/
                        void resend(MyMessage &msg, int repeats)
                        {
                          int repeat = 0;
                          int repeatdelay = 0;
                          boolean sendOK = false;
                        
                          while ((sendOK == false) and (repeat < repeats)) {
                            if (send(msg)) {
                              sendOK = true;
                            } else {
                              sendOK = false;
                              Serial.print(F("Send ERROR "));
                              Serial.println(repeat);
                              repeatdelay += random(50,200);
                            } 
                            repeat++; 
                            delay(repeatdelay);
                          }
                        }
                        
                        
                        /*******************************************
                         *
                         * Internal battery ADC measuring 
                         *
                         *******************************************/
                        long readVcc() {
                          // Read 1.1V reference against AVcc
                          // set the reference to Vcc and the measurement to the internal 1.1V reference
                          #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
                            ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
                          #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
                            ADMUX = _BV(MUX5) | _BV(MUX0);
                          #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
                            ADcdMUX = _BV(MUX3) | _BV(MUX2);
                          #else
                            ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
                          #endif  
                         
                          delay(2); // Wait for Vref to settle
                          ADCSRA |= _BV(ADSC); // Start conversion
                          while (bit_is_set(ADCSRA,ADSC)); // measuring
                         
                          uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
                          uint8_t high = ADCH; // unlocks both
                         
                          long result = (high<<8) | low;
                         
                          result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
                          return result; // Vcc in millivolts
                        }
                        
                        HaakonH 1 Reply Last reply
                        0
                        • T tomkxy

                          @Haakon I have one of these sensor in place since about half a year and it is working well. Last battery change is about 4 month ago.

                          Please find the sketch below which requires some cleanup.

                          /*
                          Multisensor Sketch
                          
                          Author: Thomas Krebs, thkrebs@gmx.de
                          
                          This sketch reads temperature, humidity, light and presence.
                          It is based on the various examples sketches from SparkFun and MySensors 
                          
                          It uses the following sensors:
                          Light           - TSL2561
                          Temp&Humidity   - HTU21D
                          Presence 
                          
                          HTU21D and TLS2561 need to connect the I2C pins (SCL and SDA) to your Arduino.
                          The pins are different on different Arduinos:
                          
                                              SDA    SCL
                          Any Arduino         "SDA"  "SCL"
                          Uno, Redboard, Pro  A4     A5
                          Mega2560, Due       20     21
                          Leonardo            2      3
                          
                          */
                          #define MY_DEBUG_VERBOSE_SIGNING //!< Enable signing related debug prints to serial monitor
                          
                          #define MY_SIGNING_FEATURE
                          #define MY_SIGNING_ATSHA204
                          #define MY_SIGNING_REQUEST_SIGNATURES
                          
                          #define MY_DEBUG
                          #define MY_NODE_ID              26
                          #define MY_RADIO_NRF24
                          #define BATT_SENSOR
                          
                          #include <MySensor.h>
                          #include <TSL2561.h>
                          #include <SparkFunHTU21D.h>
                          
                          #include <SPI.h>
                          #include <Wire.h>
                          #include <avr/power.h>
                          
                          #define VERSION           "1.4"
                          #define SKETCH_NAME       "Multisensor A"
                          
                          #define TEMP_CHILD_ID   1
                          #define HUM_CHILD_ID    2
                          #define LIGHT_CHILD_ID  3
                          #define MOTION_CHILD_ID 4
                          
                          // Uncomment the line below, to transmit battery voltage as a normal sensor value
                          #define BATT_SENSOR    199
                          #define MAX_VOLTAGE    1316
                          #define MIN_VOLTAGE    890     // it seems that about 0.89 V the sensor stops working
                          
                          // How many milli seconds between each measurement
                          #define MEASURE_INTERVAL 120000
                          
                          // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller
                          #define FORCE_TRANSMIT_INTERVAL 30 
                          
                          // When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes.
                          // Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement
                          
                          // HUMI_TRANSMIT_THRESHOLD tells how much the humidity should have changed since last time it was transmitted. Likewise with
                          // TEMP_TRANSMIT_THRESHOLD for temperature threshold.
                          #define HUMI_TRANSMIT_THRESHOLD   0.5
                          #define TEMP_TRANSMIT_THRESHOLD   0.5
                          #define LIGHT_TRANSMIT_THRESHOLD  0.3    // relative change
                          
                          
                          // Pin definitions
                          #define LED_PIN            13            // TODO: need to check that
                          #define BATTERY_SENSE_PIN  A0            // select the input pin for the battery sense point
                          #define MOTION_SENSOR      3             // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
                          #define INTERRUPT          1             // Usually the interrupt = pin -2 (on uno/nano anyway)
                          
                          // Global settings
                          int tempMeasureCount = 0;
                          int lightMeasureCount = 0;
                          
                          int sendBattery = 0;
                          boolean isMetric = true;
                          boolean highfreq = true;
                          boolean motionDetected = false;
                          int repeats = 2;
                          
                          // Storage of old measurements
                          float lastTemperature = -100;
                          float lastHumidity = -100;
                          long  lastBattery = -100;
                          long  lastLight = -5000;
                          int   lastTripped = -1; 
                          
                          int   motionTrips = 0;  // count the number of cont. motion trips
                          
                          HTU21D myHumidity;
                          TSL2561 myLight(TSL2561_ADDR_FLOAT); 
                          
                          // Sensor messages
                          MyMessage msgTemp(TEMP_CHILD_ID,V_TEMP);
                          MyMessage msgHum(HUM_CHILD_ID,V_HUM);
                          MyMessage msgLight(LIGHT_CHILD_ID,V_LEVEL);
                          MyMessage msg(MOTION_CHILD_ID, V_TRIPPED);
                          
                          
                          #ifdef BATT_SENSOR
                          MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE);
                          #endif
                          
                          
                          /****************************************************
                           *
                           * Setup code 
                           *
                           ****************************************************/
                          void setup()  
                          { 
                            pinMode(LED_PIN, OUTPUT);
                            Serial.print(F(SKETCH_NAME));
                            Serial.println(VERSION);
                            Serial.flush();
                            
                            
                          #ifdef MY_SIGNING_ATSHA204_PIN
                            // Make sure that ATSHA204 is not floating
                            pinMode(MY_SIGNING_ATSHA204_PIN, INPUT);
                            digitalWrite(MY_SIGNING_ATSHA204_PIN, HIGH);
                          #endif  
                            
                            // use the 1.1 V internal reference
                            analogReference(INTERNAL);
                          
                            // setup sensors
                            setup_htu21d();
                            
                            delay(100);
                            setup_tls2561(); 
                            delay(500);
                            
                            // setup motion sensor 
                            pinMode(MOTION_SENSOR, INPUT);    
                            Serial.println(F("Setup complete..."));
                          }
                          
                          
                          void presentation()  {
                            // Send the sketch version information to the gateway and Controller
                            sendSketchInfo(SKETCH_NAME, VERSION);
                          
                            // Present all sensors to controller
                            present(TEMP_CHILD_ID, S_TEMP);
                            present(HUM_CHILD_ID, S_HUM);
                          //  present(LIGHT_CHILD_ID,S_LIGHT_LEVEL);
                            present(MOTION_CHILD_ID, S_MOTION);
                          
                          
                          #ifdef BATT_SENSOR
                            present(BATT_SENSOR, S_POWER);
                          #endif
                          
                            isMetric = getConfig().isMetric;
                          #ifdef MY_DEBUG
                            Serial.print(F("isMetric: ")); Serial.println(isMetric);
                          #endif
                          
                            Serial.flush();
                            Serial.println(F(" - Online!"));
                          }
                          
                          
                          /***********************************************
                          /* Setup HTU21d
                           ***********************************************/
                          void setup_htu21d() {
                            myHumidity.begin();
                          #ifdef MY_DEBUG  
                            Serial.println("Setup temp/humid sensor completed");
                          #endif
                          }
                          
                          
                          /***********************************************
                          /* Setup TLS2561
                           ***********************************************/
                          void setup_tls2561() {
                           
                            if (myLight.begin()) {
                              Serial.println(F("Found light sensor"));
                            } else {
                              Serial.println(F("Light Sensor not found - cont. anyway"));
                            }
                            myLight.setGain(TSL2561_GAIN_0X);          // set 16x gain (for dim situations)
                            
                            // Changing the integration time gives you a longer time over which to sense light
                            // longer timelines are slower, but are good in very low light situtations!
                            //tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS);  // shortest integration time (bright light)
                            myLight.setTiming(TSL2561_INTEGRATIONTIME_101MS);  // medium integration time (medium light)
                            //tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS);  // longest integration time (dim light)
                            
                          }
                          
                          /***********************************************
                           *
                           *  Main loop function
                           *
                           ***********************************************/
                          void loop()     
                          { 
                            tempMeasureCount++;
                            lightMeasureCount++;
                            sendBattery++;
                            bool forceTransmit = false;
                          
                            if (motionDetected) {
                              sendMotion(false);  // do not force transmission unless motion status has changed
                              motionDetected = false;
                            }
                            
                            // do not enter into sensor data gathering on each motion tripped
                            if ((!motionDetected) || (motionTrips > 3)) {
                              motionTrips = 0; // avoid starvation of temp measure in case we have a lot of motion
                              
                              // I do the battery check at the beginning
                              if (sendBattery > 60) {
                                 sendBattLevel(forceTransmit); // Not needed to send battery info that often
                                 sendBattery = 0;
                              }
                              
                              if ((lightMeasureCount > FORCE_TRANSMIT_INTERVAL) || (tempMeasureCount > FORCE_TRANSMIT_INTERVAL) ) { // force a transmission
                                forceTransmit = true; 
                                tempMeasureCount = 0;
                                lightMeasureCount = 0;
                              }
                            
                              // Get & send sensor data
                              wait(200);
                              sendTempHumidityMeasurement(forceTransmit);
                              wait(200);
                              sendLightLevelMeasurement(forceTransmit);
                              wait(200);
                              sendMotion(forceTransmit);
                            } 
                            wait(100);  // I don't know whether that is really required; however I have the impression that shutting down the radio leads to
                                           // problems in the communication when using signatures
                            Serial.println("going to sleep");
                            if (sleep(INTERRUPT,RISING, MEASURE_INTERVAL)) {
                              motionDetected = true;
                              motionTrips++;
                            }
                            Serial.print("Motion detected="); Serial.println(motionDetected);
                          }
                          
                          /*********************************************
                           *
                           * Sends state of motion sensor
                           *
                           * Parameters
                           * - force : Forces transmission of a value (even if it's the same as previous measurement)
                           *
                           *********************************************/
                          void sendMotion(bool force) {
                           
                            bool tx = force;
                            
                            // Read digital motion value
                            bool tripped = digitalRead(MOTION_SENSOR) == HIGH; 
                            Serial.print(F("Tripped: ")); Serial.println(tripped);
                            
                            if (lastTripped != tripped) tx = true;
                            if (tx) {
                              resend(msg.set(tripped?"1":"0"),repeats);  // Send tripped value to gw 
                              lastTripped = tripped;
                            }
                          }
                          
                          /*********************************************
                           *
                           * Sends temperature and humidity from HTU21D sensor
                           *
                           * Parameters
                           * - force : Forces transmission of a value (even if it's the same as previous measurement)
                           *
                           *********************************************/
                          void sendTempHumidityMeasurement(bool force) 
                          {
                              bool tx = force;
                              
                              float hum = myHumidity.readHumidity();
                              float temp = myHumidity.readTemperature();
                              
                              Serial.print(F("lastTemperature: ")); Serial.println(lastTemperature);
                              Serial.print(F("lastHumidity: ")); Serial.println(lastHumidity);
                              
                              float diffTemp = abs(lastTemperature - temp);
                              float diffHum = abs(lastHumidity - hum);
                          
                          #ifdef MY_DEBUG
                              Serial.print(F("TempDiff :"));Serial.println(diffTemp);
                              Serial.print(F("HumDiff  :"));Serial.println(diffHum); 
                          #endif
                          
                              if (isnan(diffHum)) tx = true; 
                              if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true;
                              if (diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true;
                          
                              if (tx) {
                                tempMeasureCount = 0;
                                resend(msgTemp.setSensor(TEMP_CHILD_ID).set(temp,1),repeats); 
                                wait(20);
                                resend(msgHum.setSensor(HUM_CHILD_ID).set(hum,1),repeats); 
                                lastTemperature = temp;
                                lastHumidity = hum;   
                              }
                          }
                          
                          
                          /*********************************************
                           *
                           * Sends light level from TLS6512 sensor
                           *
                           * Parameters
                           * - force : Forces transmission of a value (even if it's the same as previous measurement)
                           *
                           *********************************************/
                          void sendLightLevelMeasurement(bool force) {
                            bool tx = force;
                            
                            uint32_t lum = myLight.getFullLuminosity();
                            uint16_t ir, full;
                            ir = lum >> 16;
                            full = lum & 0xFFFF;
                            
                            Serial.print(F("IR: ")); Serial.print(ir);   Serial.print(F("\t\t"));
                            Serial.print(F("Full: ")); Serial.print(full);   Serial.print(F("\t"));
                            Serial.print(F("Visible: ")); Serial.print(full - ir);   Serial.print(F("\t"));
                            
                            double lux = myLight.calculateLux(full, ir);
                            Serial.print(F("Lux: ")); Serial.println(lux);
                            float diffLux = abs(lastLight - lux);
                          #ifdef MY_DEBUG
                              Serial.print(F("Lux difference since last measurement: ")); Serial.println((float)diffLux/abs(lastLight));    
                          #endif
                              if (isnan(diffLux)) tx = true; 
                              if (diffLux/abs(lastLight)  >= LIGHT_TRANSMIT_THRESHOLD) tx = true;
                          
                              if (tx) {
                                lightMeasureCount = 0;
                                resend(msgLight.setSensor(LIGHT_CHILD_ID).set(lux,1),repeats);
                                lastLight = lux;
                              }
                          }
                          
                          
                          /*********************************************
                           * Prints error on I2C comm bus
                           *********************************************/
                          void printError(byte error)
                            // If there's an I2C error, this function will
                            // print out an explanation.
                          {
                            Serial.print(F("I2C error: "));
                            Serial.print(error,DEC);
                            Serial.print(F(", "));
                            
                            switch(error)
                            {
                              case 0:
                                Serial.println(F("success"));
                                break;
                              case 1:
                                Serial.println(F("data too long for transmit buffer"));
                                break;
                              case 2:
                                Serial.println(F("received NACK on address (disconnected?)"));
                                break;
                              case 3:
                                Serial.println(F("received NACK on data"));
                                break;
                              case 4:
                                Serial.println(F("other error"));
                                break;
                              default:
                                Serial.println(F("unknown error"));
                            }
                          }
                          
                          
                          /********************************************
                           *
                           * Sends battery information (battery percentage)
                           *
                           * Parameters
                           * - force : Forces transmission of a value
                           *
                           *******************************************/
                          void sendBattLevel(bool force)
                          {
                            if (force) lastBattery = -1;
                            long batteryV =  analogRead(BATTERY_SENSE_PIN);  
                            for (int i = 1; i<5; i++) {
                              long newSample = analogRead(BATTERY_SENSE_PIN); //readVcc();
                              batteryV -= batteryV / (i+1);
                              batteryV += newSample / (i+1);   
                            }
                             
                             // 10M, 2,86M divider across battery and using internal ADC ref of 1.1V
                             // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
                             // ((10+4,7)/4,7)*1.1 = 3.4404255
                             // 3.4404255/1023 = Volts per bit = 0.003630748
                          
                            long vcc  = batteryV * 3.3630748;
                            if (vcc != lastBattery) {
                              lastBattery = vcc;
                          
                          #ifdef BATT_SENSOR
                              resend(msgBatt.set(vcc),repeats);
                          #endif
                              // Calculate on the fully charged cell. Since I have a step-up in place I go as low as possible no offset for minimum
                             sendBatteryLevel(  ((vcc-MIN_VOLTAGE)*10.0)/((MAX_VOLTAGE-MIN_VOLTAGE)*10.0) *100.0);
                            }
                          }
                          
                          
                          /********************************************
                           *
                           * Send message, resend on error
                           *
                           * Parameters
                           * - msg : message to send
                           * - repeats: number of repetitions
                           *
                           *******************************************/
                          void resend(MyMessage &msg, int repeats)
                          {
                            int repeat = 0;
                            int repeatdelay = 0;
                            boolean sendOK = false;
                          
                            while ((sendOK == false) and (repeat < repeats)) {
                              if (send(msg)) {
                                sendOK = true;
                              } else {
                                sendOK = false;
                                Serial.print(F("Send ERROR "));
                                Serial.println(repeat);
                                repeatdelay += random(50,200);
                              } 
                              repeat++; 
                              delay(repeatdelay);
                            }
                          }
                          
                          
                          /*******************************************
                           *
                           * Internal battery ADC measuring 
                           *
                           *******************************************/
                          long readVcc() {
                            // Read 1.1V reference against AVcc
                            // set the reference to Vcc and the measurement to the internal 1.1V reference
                            #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
                              ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
                            #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
                              ADMUX = _BV(MUX5) | _BV(MUX0);
                            #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
                              ADcdMUX = _BV(MUX3) | _BV(MUX2);
                            #else
                              ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
                            #endif  
                           
                            delay(2); // Wait for Vref to settle
                            ADCSRA |= _BV(ADSC); // Start conversion
                            while (bit_is_set(ADCSRA,ADSC)); // measuring
                           
                            uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
                            uint8_t high = ADCH; // unlocks both
                           
                            long result = (high<<8) | low;
                           
                            result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
                            return result; // Vcc in millivolts
                          }
                          
                          HaakonH Offline
                          HaakonH Offline
                          Haakon
                          wrote on last edited by
                          #12

                          Thanks, @tomkxy, fantastic! I will be trying it our shortly, as soon as I got those PIRs working on 3V.

                          1 Reply Last reply
                          0
                          • T Offline
                            T Offline
                            tomkxy
                            wrote on last edited by
                            #13

                            @Haakon Regarding the PIRs: There are a couple of postings in the Internet or I think even in this forum. For example, have a look here: http://randomnerdtutorials.com/modifying-cheap-pir-motion-sensor-to-work-at-3-3v/

                            L 1 Reply Last reply
                            0
                            • T tomkxy

                              @Haakon Regarding the PIRs: There are a couple of postings in the Internet or I think even in this forum. For example, have a look here: http://randomnerdtutorials.com/modifying-cheap-pir-motion-sensor-to-work-at-3-3v/

                              L Offline
                              L Offline
                              LastSamurai
                              Hardware Contributor
                              wrote on last edited by
                              #14

                              @tomkxy How did you power it though? I wanted to use a battery (or several ones) that might fall under 3.3V when used. So I decided to use a step-up converter but that seems to introduce too much noise, so I get false positives from the pir. From a stable 3.3V source it worked just fine.

                              1 Reply Last reply
                              0
                              • T Offline
                                T Offline
                                tomkxy
                                wrote on last edited by
                                #15

                                @LastSamurai I powered it through 3.3v step up with one AA battery. I cannot confirm that I get false positives.

                                martinhjelmareM L 2 Replies Last reply
                                0
                                • T tomkxy

                                  @LastSamurai I powered it through 3.3v step up with one AA battery. I cannot confirm that I get false positives.

                                  martinhjelmareM Offline
                                  martinhjelmareM Offline
                                  martinhjelmare
                                  Plugin Developer
                                  wrote on last edited by
                                  #16

                                  @tomkxy

                                  What range on the PIR do you get on 3.3 V?

                                  1 Reply Last reply
                                  0
                                  • T Offline
                                    T Offline
                                    tomkxy
                                    wrote on last edited by
                                    #17

                                    Around 4 meters. However, this puppy is sitting in my entrance which is rather narrow.

                                    1 Reply Last reply
                                    1
                                    • T tomkxy

                                      @LastSamurai I powered it through 3.3v step up with one AA battery. I cannot confirm that I get false positives.

                                      L Offline
                                      L Offline
                                      LastSamurai
                                      Hardware Contributor
                                      wrote on last edited by
                                      #18

                                      @tomkxy said:

                                      @LastSamurai I powered it through 3.3v step up with one AA battery. I cannot confirm that I get false positives.

                                      Nice, what PIR and what step up did you use? Hopefully I can get the same ones too ;)

                                      1 Reply Last reply
                                      0
                                      • T Offline
                                        T Offline
                                        tomkxy
                                        wrote on last edited by
                                        #19

                                        I used this one one which is rather expensive. I do not remember, however whether I bought really at Sparkfun or some other place. That were one of my first purchases when I started with all that crazy stuff :-)

                                        1 Reply Last reply
                                        0
                                        • Mark SwiftM Offline
                                          Mark SwiftM Offline
                                          Mark Swift
                                          wrote on last edited by Mark Swift
                                          #20

                                          Hi @tomkxy

                                          I'm going to add one of these sensors myself, looks like you've done the hard work...

                                          Could I ask what board you are using, perhaps a simple schematic too if you find a moment? I have a bunch of Nano's, some light sensors (BH1750) and temperature sensors (DS18B20's) - I presume I can swap over the code as required. Thankfully I also have a number of those exact step ups!

                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          16

                                          Online

                                          11.7k

                                          Users

                                          11.2k

                                          Topics

                                          113.0k

                                          Posts


                                          Copyright 2019 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • OpenHardware.io
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular