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:
DSC_0669 (1).jpg
DSC_0668 (1).jpg
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login