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