Skip to content
  • MySensors
  • 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

Battery powered PIR and temp/humid sensor

Scheduled Pinned Locked Moved Development
22 Posts 7 Posters 7.8k 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.
  • 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
                            • T Offline
                              T Offline
                              tomkxy
                              wrote on last edited by
                              #21

                              @Mark-Swift I used a ProMini 3.3v. Unfortunately, I have no schematic. Since I used breakout boards anyway this is not a big deal. You connect those boards to your power, ground and a digital pin or on SCA, SCL pins. I don't know what the power consumption of the Nano's is. So that is something you have to try out.

                              alexsh1A 1 Reply Last reply
                              0
                              • T tomkxy

                                @Mark-Swift I used a ProMini 3.3v. Unfortunately, I have no schematic. Since I used breakout boards anyway this is not a big deal. You connect those boards to your power, ground and a digital pin or on SCA, SCL pins. I don't know what the power consumption of the Nano's is. So that is something you have to try out.

                                alexsh1A Offline
                                alexsh1A Offline
                                alexsh1
                                wrote on last edited by
                                #22

                                @tomkxy it is a few mA while sleeping. This means that it has to be modified (no VDO and no LED) - consumption drops to a reasonable 160uA or even below.

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


                                15

                                Online

                                11.7k

                                Users

                                11.2k

                                Topics

                                113.1k

                                Posts


                                Copyright 2025 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
                                • MySensors
                                • OpenHardware.io
                                • Categories
                                • Recent
                                • Tags
                                • Popular