- [INDEX]
- Introduction and project description
- Sensor Node and Gateway Design
- How I use OpenHAB - audio notification and dashboards
- Design detail for wireless sensor nodes and gateway
- Uber Sensor - wireless sensor for fire, smoke, gas, barking, light, movement
- Diaper Box Sensor
- Laundry Room Sensor
This wireless sensor node covers about half of the sensors I wanted to build for my home automation system. The purpose of the smoke / bark / fire / movement sensors is to email me when these things are detected. Like all my wireless sensors, the wireless range is over 700 feet through several walls, so it's suitable for use in large buildings.
- Bark / Noise Sensor: Pretty sensitive when pointed in the right direction, and includes a sensitivity pot for adjustment. I'm using it to notify me if the dog barks. The system emails me when sound sensor goes off, as well as turning on an indicator on the OpenHAB display.
- Temperature / Humidity: I'm including it just for completeness - because what multi-sensor doesn't come with a temperature output.
- Fire / Gas: Using an MQ2 w/ analog output. Good for detecting explosive gas (propane, methane, natural gas), as well as smoke.
- PIR Presence Sensor: Can be used for security purposes, or for room automation
- Flame Sensor: The sensor I had wasn't as sensitive as I'd like. It does a good job of detecting a flame in front of sensor, but must be pretty close. Might swap it out for something more sensitive in the future.
- Light Sensor: For detecting if a room light is left on
I mounted the sensor in a cheap tuperware container.
Here's a screen shot of the OpenHAB display and a video of it working.
Video demonstration:
OpenHAB Item Definition
Switch itm_NAA_auto "Auto Schedule Alarms/Notifications"
Switch itm_uber1_gas_alm_enb "Gas / Smoke Notifer"
Switch itm_uber1_flame_alm_enb "Flame Notifier"
Switch itm_uber1_bark_alm_enb "Bark Notifier"
Switch itm_uber1_pir_alm_enb "Presence Notifier"
Switch itm_uber1_gas_alm_sta "Gas / Smoke Alarm Status"
Switch itm_uber1_flame_alm_sta "Flame Alarm Status"
Switch itm_uber1_bark_alm_sta "Bark Alarm Status"
Switch itm_uber1_pir_alm_sta "PIR Presence Status"
Switch itm_uber1_light_sta "Living Room Light"
DateTime itm_uber1_gas_time "Gas Alarm Time [%1$tA, %1$tm/%1$td, %1$tI:%1$tM %1$tp]"
DateTime itm_uber1_flame_time "Flame Alarm Time [%1$tA, %1$tm/%1$td, %1$tI:%1$tM %1$tp]"
DateTime itm_uber1_bark_time "Bark Alarm Time [%1$tA, %1$tm/%1$td, %1$tI:%1$tM %1$tp]"
DateTime itm_uber1_pir_time "PIR Presence Alarm Time [%1$tA, %1$tm/%1$td, %1$tI:%1$tM %1$tp]"
Number itm_uber1_gas_mqtt "Gas [%.1f]" (ALL) {mqtt="<[mymosquitto:1222:state:default]"}
Number itm_uber1_flame_mqtt "Flame [%.1f]" (ALL) {mqtt="<[mymosquitto:1232:state:default]"}
Number itm_uber1_pir_mqtt "PIR [%.1f]" (ALL) {mqtt="<[mymosquitto:1242:state:default]"}
Number itm_uber1_bark_mqtt "Bark [%.1f]" (ALL) {mqtt="<[mymosquitto:1252:state:default]"}
Number itm_uber1_temp_mqtt "Uber Temperature [%.1f]" (ALL) {mqtt="<[mymosquitto:1262:state:default]"}
Number itm_uber1_hum_mqtt "Uber Humidity [%.1f]" (ALL) {mqtt="<[mymosquitto:1263:state:default]"}
Number itm_uber1_light_mqtt "Light Sensor [%.1f]" (ALL) {mqtt="<[mymosquitto:1272:state:default]"}
OpenHAB Rules
/* Uber sensor rules */
/* ------------- Uber Sensor -------------------- */
rule "Uber Lighs"
when
Item itm_uber1_light_mqtt received update
then
if(itm_uber1_light_mqtt.state < 350)
{
sendCommand(itm_uber1_light_sta, OFF)
}
else
{
sendCommand(itm_uber1_light_sta, ON)
}
end
/*----- uber - gas/smoke ---------- */
rule "Uber gas smoke threshold"
when
Item itm_uber1_gas_mqtt received update
then
if((itm_uber1_gas_mqtt.state > 220) && (itm_uber1_gas_alm_enb.state == ON))
{
sendCommand(itm_uber1_gas_alm_sta, ON)
}
end
rule "Uber gas smoke response"
when
Item itm_uber1_gas_alm_sta changed from OFF to ON
then
sendMail("ArduinoHomeAutomationOpenHAB@gmail.com", "gas / smoke" , "gas or smoke detected")
//playSound("ding.mp3")
postUpdate(itm_uber1_gas_time, new DateTimeType())
end
/* --------- uber flame ---------- */
rule "Uber flame threshold"
when
Item itm_uber1_flame_mqtt received update
then
if((itm_uber1_flame_mqtt.state < 900) && (itm_uber1_flame_alm_enb.state == ON))
{
sendCommand(itm_uber1_flame_alm_sta, ON)
}
end
rule "Uber flame response"
when
Item itm_uber1_flame_alm_sta changed from OFF to ON
then
sendMail("ArduinoHomeAutomationOpenHAB@gmail.com", "fire detected" , "fire detected")
//playSound("ding.mp3")
postUpdate(itm_uber1_flame_time, new DateTimeType())
end
/* --------- uber bark ---------- */
rule "Uber bark threshold"
when
Item itm_uber1_bark_mqtt received update
then
if(itm_uber1_bark_alm_enb.state == ON)
{
sendCommand(itm_uber1_bark_alm_sta, ON)
}
end
rule "Uber bark response"
when
Item itm_uber1_bark_alm_sta changed from OFF to ON
then
sendMail("ArduinoHomeAutomationOpenHAB@gmail.com", "bark detected" , "dog barked!!!")
//playSound("ding.mp3")
postUpdate(itm_uber1_bark_time, new DateTimeType())
end
/* --------- uber pir ---------- */
rule "Uber pir threshold"
when
Item itm_uber1_pir_mqtt received update
then
if(itm_uber1_pir_alm_enb.state == ON)
{
sendCommand(itm_uber1_pir_alm_sta, ON)
}
end
rule "Uber pir response"
when
Item itm_uber1_pir_alm_sta changed from OFF to ON
then
sendMail("ArduinoHomeAutomationOpenHAB@gmail.com", "pir detected" , "dog pired!!!")
//playSound("ding.mp3")
postUpdate(itm_uber1_pir_time, new DateTimeType())
end
OpenHAB Sitemap
Frame label="Uber Sensor" {
Text item=itm_uber1_temp_mqtt
Text item=itm_uber1_hum_mqtt
Switch item=itm_uber1_light_sta
Switch item=itm_NAA_auto
}
Frame label="Uber Sensor Alarm Status" {
Switch item=itm_uber1_gas_alm_sta mappings=[OFF="Off"]
Switch item=itm_uber1_flame_alm_sta mappings=[OFF="Off"]
Switch item=itm_uber1_bark_alm_sta mappings=[OFF="Off"]
Switch item=itm_uber1_pir_alm_sta mappings=[OFF="Off"]
}
Frame label="Uber Sensor Alarm Enable" {
Switch item=itm_uber1_gas_alm_enb
Switch item=itm_uber1_flame_alm_enb
Switch item=itm_uber1_bark_alm_enb
Switch item=itm_uber1_pir_alm_enb
}
Sketch
/*
Author: Eric Tsai
License: CC-BY-SA, https://creativecommons.org/licenses/by-sa/2.0/
Date: 9-1-2014
File: UberSensor.ino
This sketch is for a wired Arduino w/ RFM69 wireless transceiver
Sends sensor data (gas/smoke, flame, PIR, noise, temp/humidity) back
to gateway. See OpenHAB configuration file.
1) Update encryption string "ENCRYPTKEY"
2)
*/
/* sensor
node = 12
device ID
2 = 1222 = smoke or not
3 = 1232 = flame detected or not
4 = 1242 = human motion present or not
5 = 1252 = barking or not
6 = 1262, 1263 = temperature, humidity
*/
//RFM69 --------------------------------------------------------------------------------------------------
#include <RFM69.h>
#include <SPI.h>
#define NODEID 12 //unique for each node on same network
#define NETWORKID 101 //the same on all nodes that talk to each other
#define GATEWAYID 1
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
//#define FREQUENCY RF69_433MHZ
//#define FREQUENCY RF69_868MHZ
#define FREQUENCY RF69_915MHZ
#define ENCRYPTKEY "xxxxxxxxxxxxxxxx" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ACK_TIME 30 // max # of ms to wait for an ack
#define LED 9 // Moteinos have LEDs on D9
#define SERIAL_BAUD 9600 //must be 9600 for GPS, use whatever if no GPS
boolean debug = 0;
//struct for wireless data transmission
typedef struct {
int nodeID; //node ID (1xx, 2xx, 3xx); 1xx = basement, 2xx = main floor, 3xx = outside
int deviceID; //sensor ID (2, 3, 4, 5)
unsigned long var1_usl; //uptime in ms
float var2_float; //sensor data?
float var3_float; //battery condition?
} Payload;
Payload theData;
char buff[20];
byte sendSize=0;
boolean requestACK = false;
RFM69 radio;
//end RFM69 ------------------------------------------
// gas sensor================================================
int GasSmokeAnalogPin = 0; // potentiometer wiper (middle terminal) connected to analog pin
int gas_sensor = -500; // gas sensor value, current
int gas_sensor_previous = -500; //sensor value previously sent via RFM
//temperature / humidity =====================================
#include "DHT.h"
#define DHTPIN 7 // digital pin we're connected to
#define DHTTYPE DHT11 // DHT 22 (AM2302) blue one
//#define DHTTYPE DHT21 // DHT 21 (AM2301) white one
// Initialize DHT sensor for normal 16mhz Arduino
DHT dht(DHTPIN, DHTTYPE);
// flame sensor ==============================================
int flameAnalogInput = A1;
int flame_status = 0;
int flameValue = -50; //analog value of current flame sensor
int flameValue_previous = -50; //value previously sent via RFM
// Light sensor ===============================================
int lightAnalogInput = A2; //analog input for photo resistor
int lightValue = -50;
int lightValue_previous = -50;
// PIR sensor ================================================
int PirInput = 5;
int PIR_status = 0;
int PIR_reading = 0;
int PIR_reading_previous = 0;
// sound sensor ==============================================
//sound sensor digital input pin
int soundInput = 6;
int sound_status = 0;
int sound_reading = 0; //reading =1 mean no noise, 0=noise
int sound_reading_previous = 0;
// 2 = 1222 = smoke or not
// 3 = 1232 = flame detected or not
// 4 = 1242 = human motion present or not
// 5 = 1252 = barking or not
// 6 = 1262, 1263 = temperature, humidity
// timings
unsigned long gas_time; //sensor read time
unsigned long gas_time_send; //sensor value transmission time
unsigned long flame_time;
unsigned long flame_time_send;
unsigned long pir_time;
//unsigned long pir_time_send;
unsigned long sound_time;
//unsigned long sound_time_Send;
unsigned long temperature_time;
unsigned long light_time;
unsigned long light_time_send;
void setup()
{
Serial.begin(9600); // setup serial
//RFM69-------------------------------------------
radio.initialize(FREQUENCY,NODEID,NETWORKID);
#ifdef IS_RFM69HW
radio.setHighPower(); //uncomment only for RFM69HW!
#endif
radio.encrypt(ENCRYPTKEY);
char buff[50];
sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
Serial.println(buff);
theData.nodeID = NODEID; //this node id should be the same for all devices in this node
//end RFM--------------------------------------------
//temperature / humidity sensor
dht.begin();
//sound/noise
pinMode(soundInput, INPUT);
//initialize times
gas_time = millis();
flame_time = millis();
pir_time = millis();
sound_time = millis();
temperature_time = millis();
//PIR sensor
pinMode(PirInput, INPUT);
}
void loop()
{
unsigned long time_passed = 0;
//===================================================================
//device #2
//read gas sensor
// don't read analog pins too often (<1Hz), else caps never get to charge.
//112 to 120 = normal, 400 = high
time_passed = millis() - gas_time;
//take care of millis roll over. In case of roll over
//if roll over, send next value again
if (time_passed < 0)
{
gas_time = millis();
gas_time_send = -700000;
}
//Serial.print("gas time passed = ");
//Serial.println(time_passed);
if (time_passed > 5000) //read gas sensor analog input every X seconds
{
gas_time = millis(); //update gas_time w/ when sensor last read
gas_sensor = analogRead(GasSmokeAnalogPin); // read the input pin
if (debug){
Serial.print("Gas = ");
Serial.println(gas_sensor);
}
//send data if gas detected, or if big changes relative to value last sent, or if it's been a while
if ((gas_sensor < (gas_sensor_previous - 70)) || ((gas_sensor > (gas_sensor_previous + 70)) || (700000 < (millis() - gas_time_send))))
{
gas_time_send = millis(); //update gas_time_send with when sensor value last transmitted
theData.deviceID = 2;
theData.var1_usl = millis();
theData.var2_float = gas_sensor;
theData.var3_float = gas_sensor + 100; //null value;
radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
gas_sensor_previous = gas_sensor;
Serial.print("gas rfm = ");
Serial.println(gas_sensor);
}//end if send RFM
}//end if time_passed >
//===================================================================
//delay(100);
//===================================================================
//device #3
//flame
time_passed = millis() - flame_time;
if (time_passed < 0)
{
flame_time = millis();
flame_time_send = -70000;
}
if (time_passed > 2000) //how often to examine the flame sensor analog value
{
flame_time = millis(); //update time when sensor value last read
flame_status = 0;
flameValue = 0;
//analog value: usually 1023 for no fire, lower for fire.
flameValue = analogRead(flameAnalogInput);
if ((flameValue < (flameValue_previous - 20)) || ((flameValue > (flameValue_previous + 20)) || (705000 < (millis() - flame_time_send))) )
{
flame_time_send = millis(); //update gas_time_send with when sensor value last transmitted
theData.deviceID = 3;
theData.var1_usl = millis();
theData.var2_float = flameValue;
theData.var3_float = flameValue + 100;
radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
flameValue_previous = flameValue;
Serial.print("flame detected rfm");
Serial.println(flameValue);
delay(2000);
}
//start debug code
if (debug){
Serial.print("flame analog = ");
Serial.print(flameValue);
//analog value: usually 1023 for no fire, lower for fire.
if (flameValue > 1000)
{
flame_status = 0;
Serial.println(" no fire");
}
else
{
flame_status = 1;
Serial.println(" fire!!!");
}
}//end debug text
}// end if millis time_passed >
//===================================================================
//device #4
//PIR
//1 mean presence detected?
PIR_reading = digitalRead(PirInput);
//if (PIR_reading == 1)
//Serial.println("PIR = 1");
//else
//Serial.println("PIR = 0");
//send PIR sensor value only if presence is detected and the last time
//presence was detected is over x miniutes ago. Avoid excessive RFM sends
if ((PIR_reading == 1) && ( ((millis() - pir_time)>60000)||( (millis() - pir_time)< 0)) ) //meaning there was sound
{
pir_time = millis(); //update gas_time_send with when sensor value last transmitted
theData.deviceID = 4;
theData.var1_usl = millis();
theData.var2_float = 1111;
theData.var3_float = 1112; //null value;
radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
Serial.println("PIR detectedEDED RFM");
delay(2000);
}
//===================================================================
//device #5
//sound
//soundValue = analogRead(soundAnalogInput);
//Serial.print("sound analog = ");
//Serial.print(soundValue);
// 1 = no noise, 0 = noise!!
sound_reading = digitalRead(soundInput);
//Serial.print("sound value = ");
//Serial.println(sound_reading);
if ((sound_reading == 0) && ( ((millis() - sound_time)>20000)||( (millis() - sound_time)< 0)) ) //meaning there was sound
{
sound_time = millis(); //update gas_time_send with when sensor value last transmitted
theData.deviceID = 5;
theData.var1_usl = millis();
theData.var2_float = 2222;
theData.var3_float = 2223; //null value;
radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
Serial.print("sound noise detected RFM ");
sound_reading_previous = sound_reading;
}
/*
if (sound_reading == 1)
sound_status = 0;
else
sound_status = 1;
if (sound_status == 1) //noise!
{
Serial.print("sound noise = ");
Serial.println(sound_reading);
}
*/
/*
// analog value lower = louder
if (soundValue < 200)
{
sound_status = 1;
Serial.println(" loud");
}
else
{
sound_status = 0;
Serial.println(" not loud!!!");
}
*/
//delay(100);
//===================================================================
//device #6
//temperature / humidity
time_passed = millis() - temperature_time;
if (time_passed < 0)
{
temperature_time = millis();
}
if (time_passed > 360000)
{
float h = dht.readHumidity();
// Read temperature as Celsius
float t = dht.readTemperature();
// Read temperature as Fahrenheit
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
Serial.print("Humidity=");
Serial.print(h);
Serial.print(" Temp=");
Serial.println(f);
temperature_time = millis();
//send data
theData.deviceID = 6;
theData.var1_usl = millis();
theData.var2_float = f;
theData.var3_float = h;
radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
delay(1000);
}
//===================================================================
//===================================================================
//device #7
//light
time_passed = millis() - light_time;
if (time_passed < 0)
{
light_time = millis();
light_time_send = -70000;
}
if (time_passed > 2000) //how often to examine the sensor analog value
{
light_time = millis(); //update time when sensor value last read
lightValue = 0;
//analog value: Less than 100 is dark. greater than 500 is room lighting
lightValue = analogRead(lightAnalogInput);
if ((lightValue < (lightValue_previous - 50)) || ((lightValue > (lightValue_previous + 100)) || (705000 < (millis() - light_time_send))) )
{
light_time_send = millis(); //update gas_time_send with when sensor value last transmitted
theData.deviceID = 7;
theData.var1_usl = millis();
theData.var2_float = lightValue;
theData.var3_float = lightValue + 20;
radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
lightValue_previous = lightValue;
Serial.print("light RFM =");
Serial.println(lightValue);
}
//start debug code
if (debug)
{
Serial.print("light analog = ");
Serial.println(lightValue);
}
//analog value: usually 1023 for no fire, lower for fire.
}// end if millis time_passed >
}//end loop







