Motion detector with temperature and barometer function



  • I have built an intrusion detector that also measures barometer pressure and indoor and outdoor temperatures.

    The pressure and indoor temperature is measured by a BMP280 and a number of DS18B20 sensors can be connected to measure the temperature in remote locations.

    When movement is detected two red LEDs flash during 20 sec.

    Everything is built into a frightening wooden mask, bought in Indonesia. The LEDs poke out through the nostrils.

    Here is the sketch:

    /**
     * File name: MotionSensor_LED_2_temp_baro_280
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * REVISION HISTORY
     * Version 1.0 - Henrik Ekblad
     * Version 2.1 - Gunnar Blockmar includes PMB280 temp/baro sensor and DS18B20 temp sensor
     * 
     * DESCRIPTION
     * Motion Sensor example using HC-SR501 
     * http://www.mysensors.org/build/motion
     *
     * Now with 1 fading LEDs when sensor is triggered
     * Measuring temp and pressure with BMP 280. Local pressure
     * Measuring remote temp via DS18B20
     */
    
    #include <Adafruit_BMP280.h>
    #include <Adafruit_Sensor.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <SPI.h>
    
    unsigned long SLEEP_TIME = 60000; // Sleep time between reports (in milliseconds)
    
    #define MY_DEBUG
    #define DIGITAL_INPUT_SENSOR 3   // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
    #define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    #define CHILD_ID_MOT 0   // Id of the motion sensor child
    #define CHILD_ID_ITEMP 1  // Id of indoor temperature sensor
    #define CHILD_ID_BARO 2  // Id of pressure sensor
    #define CHILD_ID_OTEMP 3  // Id of outdoor temperature sensor 
    #define RED_LED 5    // Pin for LED
    #define RED_LED2 6  // Pin for LED2
    #define DELAY 40     // Wait for brightness change
    int fadeAmount = 5;   // brightness change per step
    #define ONE_WIRE_BUS 2 // Pin where dallas sensor is connected 
    #define MAX_ATTACHED_DS18B20 16
    OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
    DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature. 
    int numSensors=0;
    bool receivedConfig = false;
    
    
    const char *weather[] = { "Stabilt", "Bättre", "Sämre", "Ostadigt", "Åska!", "Okänt" };
    enum FORECAST
    {
      STABLE = 0,     // "Stable Weather Pattern"
      SUNNY = 1,      // "Slowly rising Good Weather", "Clear/Sunny "
      CLOUDY = 2,     // "Slowly falling L-Pressure ", "Cloudy/Rain "
      UNSTABLE = 3,   // "Quickly rising H-Press",     "Not Stable"
      THUNDERSTORM = 4, // "Quickly falling L-Press",    "Thunderstorm"
      UNKNOWN = 5     // "Unknown (More Time needed)
    };
    
    Adafruit_BMP280 bmp;      // Digital Pressure Sensor
    
    float lastPressure = -1;
    float lastTemp = -1;
    int lastForecast = -1;
    
    const int LAST_SAMPLES_COUNT = 5;
    float lastPressureSamples[LAST_SAMPLES_COUNT];
    
    // this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
    // get kPa/h by dividing hPa by 10 
    #define CONVERSION_FACTOR (1.0/10.0)
    
    int minuteCount = 0;
    bool firstRound = true;
    // average value is used in forecast algorithm.
    float pressureAvg;
    // average after 2 hours is used as reference value for the next iteration.
    float pressureAvg2;
    float dP_dt;
    
    
    
    // Enable debug prints to serial monitor
    // #define MY_DEBUG 
    
    // Enables and select radio type (if attached)
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    
    #define MY_NODE_ID 41
    
    #include <MySensors.h>
    
    // Initialize motion message
    MyMessage msgm(CHILD_ID_MOT, V_TRIPPED);
    // Initialize temp baro and forecast messages
    MyMessage msgit(CHILD_ID_ITEMP, V_TEMP);
    MyMessage msgp(CHILD_ID_BARO, V_PRESSURE);
    MyMessage forecastMsg(CHILD_ID_BARO, V_FORECAST);
    MyMessage msgot(0, V_TEMP);
    
    bool metric = true;
    void before()
    {
      // Startup up the OneWire library
      sensors.begin();
    }
    
    
    void setup()  
    {  
      pinMode(DIGITAL_INPUT_SENSOR, INPUT);      // sets the motion sensor digital pin as input
      pinMode(RED_LED, OUTPUT);   // sets the pin for the LEDs as output
      pinMode(RED_LED2, OUTPUT);
      analogWrite(RED_LED, 0);    // make sure LEDs are OFF
      analogWrite(RED_LED2, 0);
      bmp.begin();
      if (!bmp.begin()) 
      {
        Serial.println("Could not find a valid BMP280 sensor, check wiring!");
        while (1) {}
      }
      // requestTemperatures() will not block current thread
      sensors.setWaitForConversion(false);
    }
    
    void presentation()
    {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("M. Sens_LED_2t/b/f 280", "2.2");
    
      // Fetch the number of attached temperature sensors  
      numSensors = sensors.getDeviceCount();
      
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_MOT, S_MOTION);
      present(CHILD_ID_ITEMP, S_TEMP);
      present(CHILD_ID_BARO, S_BARO);
      for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {   
         present(i+CHILD_ID_OTEMP, S_TEMP);
      }   
    }
    
    void loop()     
    {     
      
      // Read digital motion value
      boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; 
            
        
      Serial.println(tripped);
      send(msgm.set(tripped?"1":"0"));  // Send tripped value to gw
       
    
      if (tripped) {
       int brightness = 0;   // brightness of LED
       int count = 0;  // number of half cycles to fade LED
       while (count < 12) {    // run 6 full fade cycles
          analogWrite(RED_LED, brightness);
          analogWrite(RED_LED2, brightness);
          brightness = brightness + fadeAmount;
          if (brightness == 0 || brightness == 255) {
            fadeAmount = -fadeAmount;  // change direction of fade
            count ++;
          }
          wait (DELAY);  //wait to see brightness change
        }
        analogWrite(RED_LED, 0);  // turn off LEDs
        analogWrite(RED_LED2, 0);
      }
    
      int long pressure = bmp.readPressure() / 100;
      float temperature = bmp.readTemperature();
      int forecast = sample(pressure);
    
      send(msgit.set(temperature, 1));
      send(msgp.set(pressure, 0));
      send(forecastMsg.set(weather[forecast]));
    
      // Fetch temperatures from Dallas sensors
      sensors.requestTemperatures();
    
      sleep (750);
    
      // Read temperatures and send them to controller 
      for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {
      // Fetch and round temperature to one decimal
      float otemperature = static_cast<float>(static_cast<int>((sensors.getTempCByIndex(i)) * 10.)) / 10.;
    
      // Only send data if no error
        
      if (otemperature != -127.00 && otemperature != 85.00) {
      // Send in the new temperature
          send(msgot.setSensor(i+CHILD_ID_OTEMP).set(otemperature,1));
      }  
    }
    
      
     
      // Sleep until interrupt comes in on motion sensor but send update every minute. 
      tripped = false;  //reset tripped
      sleep(INTERRUPT,CHANGE, SLEEP_TIME);
    }
    
    float getLastPressureSamplesAverage()
    {
      float lastPressureSamplesAverage = 0;
      for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
      {
        lastPressureSamplesAverage += lastPressureSamples[i];
      }
      lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
    
      return lastPressureSamplesAverage;
    }
    
    // Algorithm found here
    // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
    // Pressure in hPa -->  forecast done by calculating kPa/h
    int sample(float pressure)
    {
      // Calculate the average of the last n minutes.
      int index = minuteCount % LAST_SAMPLES_COUNT;
      lastPressureSamples[index] = pressure;
    
      minuteCount++;
      if (minuteCount > 185)
      {
        minuteCount = 6;
      }
    
      if (minuteCount == 5)
      {
        pressureAvg = getLastPressureSamplesAverage();
      }
      else if (minuteCount == 35)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change * 2; // note this is for t = 0.5hour
        }
        else
        {
          dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
        }
      }
      else if (minuteCount == 65)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) //first time initial 3 hour
        {
          dP_dt = change; //note this is for t = 1 hour
        }
        else
        {
          dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 95)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 1.5; // note this is for t = 1.5 hour
        }
        else
        {
          dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 125)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        pressureAvg2 = lastPressureAvg; // store for later use.
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 2; // note this is for t = 2 hour
        }
        else
        {
          dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 155)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 2.5; // note this is for t = 2.5 hour
        }
        else
        {
          dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 185)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 3; // note this is for t = 3 hour
        }
        else
        {
          dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
        }
        pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
        firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
      }
    
      int forecast = UNKNOWN;
      if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
      {
        forecast = UNKNOWN;
      }
      else if (dP_dt < (-0.25))
      {
        forecast = THUNDERSTORM;
      }
      else if (dP_dt > 0.25)
      {
        forecast = UNSTABLE;
      }
      else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
      {
        forecast = CLOUDY;
      }
      else if ((dP_dt > 0.05) && (dP_dt < 0.25))
      {
        forecast = SUNNY;
      }
      else if ((dP_dt >(-0.05)) && (dP_dt < 0.05))
      {
        forecast = STABLE;
      }
      else
      {
        forecast = UNKNOWN;
      }
    
      // uncomment when debugging
      //Serial.print(F("Forecast at minute "));
      //Serial.print(minuteCount);
      //Serial.print(F(" dP/dt = "));
      //Serial.print(dP_dt);
      //Serial.print(F("kPa/h --> "));
      //Serial.println(weather[forecast]);
    
      return forecast;
    }
    
    

    and here are a couple of photos, front and back:
    ![alt text](0_1487498680609_upload-7deee0a5-263a-42b0-989a-55d1aae32cf4 image url)DSC_0669 (1).jpg
    ![alt text](0_1487498717047_upload-cd76f838-04f6-4fab-a4b8-e37823a7419c image url)DSC_0668 (1).jpg



Suggested Topics

19
Online

11.2k
Users

11.1k
Topics

112.5k
Posts