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


                          17

                          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