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


                            22

                            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