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.
  • 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


                        21

                        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