Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 8 | ||||
| × | 1 | ||||
| × | 3 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
|
The primary goal of this project is to create an IoT device which serves to help its user identify rooms that are illuminated when they are unoccupied. This would help to save energy, and thus money.
Conception of IdeaThe idea to make a energy-wastage-detecting product first came to me when I signed up for the "Flex your mind with Kinetis FlexIO" Challenge on Hackster.io. However, when I noticed this challenge, I found that it would be better suited for the task, and I named it Luminaire X, as the Kinetis one will be Luminaire.
Creative ProcessAfter determining the nature of the process, I started leaning about the Blynk platform. After receiving the product, I was able to start experimenting with the service, and learn how to use the I/O for my intentions. Using a purchased PIR sensor and a passive photoresistor, I began developing the code.
The first version of the code "Debug sensors and set a framework for data processing (Blynk_Hackster_LuminaireX.ino)" was based in large part on code that already existed, specifically that which was provided with various libraries, as stated in the Credits section.
After that point, I continued to expand the code, adding functionality and removing debugging segments, until the final product was reached.
UsageThe PIR sensor would be placed in a room such that, according to the manufacturer's specifications, all points which would be occupied by a moving subject are covered.
The photoresistor would be placed such that it is activated when the primary light in a room is turned on (possibly directly adjacent to it). The values in the code could be adjusted according to the desired results.
In the Blynk app, a LCD set to use V2 in advanced mode is used to present data. Instantaneous sensor values are also sent over V0 and V1. (Refer to the code)
Drawbacks- This product uses PIR sensor modules which have limited capabilities and ranges of sensitivity.
- The product can not detect users if they are completely immobile or obscured.
In the future, this project could be expanded to use multiple PIR sensor modules. It could also use a more accurate entry-exit system, which would monitor the entry and exit of persons from the room, and thus eliminating the drawbacks presented above.
Debug sensors and set a framework for data processing (Blynk_Hackster_LuminaireX.ino)
Arduino#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#define POSTTOPHANT 0 // Define POSTTOPHANT as 1 to enable posting to Phant on data.sparkfun.com
#if POSTTOPHANT
#include <Phant.h>
#endif
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
////////////////////
// Blynk Settings //
////////////////////
char BlynkAuth[] = "dont_hack_me";
char WiFiNetwork[] = "dont_hack_me";
char WiFiPassword[] = "dont_hack_me";
///////////////////////
// Hardware Settings //
///////////////////////
#define MOTION_PIN 5
#define LIGHT_PIN A0
#define V_MOTION_PIN V0
#define V_LIGHT_PIN V1
/////////////////
// Phant Stuff //
/////////////////
char publicKey[] = "dont_hack_me";
char privateKey[] = "dont_hack_me";
char phantServer[] = "data.sparkfun.com";
#if POSTTOPHANT
Phant phant(phantServer, publicKey, privateKey);
#endif
const byte NUM_FIELDS = 2;
const String fieldNames[NUM_FIELDS] = {"light", "motion"};
String fieldData[NUM_FIELDS];
//////////////////////
// Input Pins, Misc //
//////////////////////
int lightIndex = 0;
int motionIndex = 1;
long lastModulus = 0;
long newModulus = 0;
void setup()
{
BLYNK_PRINT.begin(9600);
pinMode(MOTION_PIN, INPUT);
pinMode(LIGHT_PIN, INPUT);
Blynk.begin(BlynkAuth, WiFiNetwork, WiFiPassword);
}
void loop()
{
Blynk.run();
if (millis() > (lastModulus + 250)) {
newModulus = ((int)(millis() / 250)) * 250;
readyData();
postDataBlynk();
#if POSTTOPHANT
postDataPhant();
#endif
Serial.print("Last Modulus: ");
Serial.println(lastModulus);
lastModulus = newModulus;
Serial.print("New Modulus: ");
Serial.println(lastModulus);
}
}
void readyData()
{
fieldData[lightIndex] = analogRead(LIGHT_PIN);
fieldData[motionIndex] = digitalRead(MOTION_PIN) * 1023;
BLYNK_PRINT.println(fieldData[lightIndex]);
BLYNK_PRINT.println(fieldData[motionIndex]);
}
void postDataBlynk()
{
Blynk.virtualWrite(V_MOTION_PIN, fieldData[motionIndex]);
Blynk.virtualWrite(V_LIGHT_PIN, fieldData[lightIndex]);
}
#if POSTTOPHANT
void postDataPhant()
{
Serial.println("Starting Phant");
WiFiClient client;
if (client.connect(phantServer, 80))
{
client.print("GET /input/");
client.print(publicKey);
client.print("?private_key=");
client.print(privateKey);
for (int i=0; i<NUM_FIELDS; i++)
{
client.print("&");
client.print(fieldNames[i]);
client.print("=");
client.print(fieldData[i]);
}
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(phantServer);
client.println("Connection: close");
client.println();
}
else
{
Serial.println(F("Connection failed"));
}
while (client.connected())
{
if ( client.available() )
{
char c = client.read();
Serial.print(c);
}
}
Serial.println();
client.stop();
}
#endif
Test processing of light and PIR sensor data (Blynk_Hackster_LuminaireX_2.ino)
Arduino#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
////////////////////
// Blynk Settings //
////////////////////
char BlynkAuth[] = "dont_hack_me";
char WiFiNetwork[] = "dont_hack_me";
char WiFiPassword[] = "dont_hack_me";
///////////////////////
// Hardware Settings //
///////////////////////
#define MOTION_PIN 5
#define LIGHT_PIN A0
#define V_MOTION_PIN V0
#define V_LIGHT_PIN V1
/////////////////
// Phant Stuff // Leftovers
/////////////////
const byte NUM_FIELDS = 2;
const String fieldNames[NUM_FIELDS] = {"light", "motion"};
String fieldData[NUM_FIELDS];
//////////////////////
// Input Pins, Misc //
//////////////////////
int lightIndex = 0;
int motionIndex = 1;
long lastModulus = 0;
long newModulus = 0;
int currentLightStatus = 0;
int currentMotionStatus = 0;
int changedLightStatus = 0;
int changedMotionStatus = 0;
int balancedNoMotionStatus = 0;
int badStatus = 0; // State when the room is unnocupied and lit.
unsigned long lastTrueMotionMillis = 0;
unsigned long lastBalancedMotionMillis = 0;
unsigned long timeWhenLightsWithoutMotionStarted = 0;
unsigned long timeWithLightsWithoutMotion = 0;
void setup()
{
BLYNK_PRINT.begin(9600);
pinMode(MOTION_PIN, INPUT);
pinMode(LIGHT_PIN, INPUT);
Blynk.begin(BlynkAuth, WiFiNetwork, WiFiPassword);
}
void loop()
{
Blynk.run();
readyData();
checkChange();
unsigned long tmpMillis = millis();
if (changedMotionStatus == 1 && currentMotionStatus == 0)
{
lastTrueMotionMillis = tmpMillis;
}
else
{
unsigned long diffMotionMillis = tmpMillis - lastTrueMotionMillis;
if (diffMotionMillis >= 10000)
{
lastBalancedMotionMillis = tmpMillis;
balancedNoMotionStatus = 1;
}
}
if (balancedNoMotionStatus == 1 && currentLightStatus == 1 && badStatus == 0)
{
timeWhenLightsWithoutMotionStarted = tmpMillis;
badStatus = 1;
}
else if (currentLightStatus == 0 && changedLightStatus == 1 && badStatus == 1)
{
badStatus = 0;
timeWithLightsWithoutMotion = timeWithLightsWithoutMotion + (tmpMillis - timeWhenLightsWithoutMotionStarted);
}
logOut();
changedMotionStatus = 0;
changedLightStatus = 0;
if (millis() > (lastModulus + 250)) {
newModulus = ((int)(millis() / 250)) * 250;
postDataBlynk();
Serial.print("Last Modulus: ");
Serial.println(lastModulus);
lastModulus = newModulus;
Serial.print("New Modulus: ");
Serial.println(lastModulus);
}
}
void checkChange()
{
int lastLightStatus = currentLightStatus;
int lastMotionStatus = currentMotionStatus;
if (fieldData[lightIndex].toInt() >= 500)
{
Serial.println("Light is on.");
currentLightStatus = 1;
}
else
currentLightStatus = 0;
currentMotionStatus = fieldData[motionIndex].toInt() / 1023;
if (currentLightStatus != lastLightStatus)
changedLightStatus = 1;
if (currentMotionStatus != lastMotionStatus)
changedMotionStatus = 1;
}
void readyData()
{
fieldData[lightIndex] = analogRead(LIGHT_PIN);
fieldData[motionIndex] = digitalRead(MOTION_PIN) * 1023;
}
void postDataBlynk()
{
BLYNK_PRINT.println(fieldData[lightIndex]);
BLYNK_PRINT.println(fieldData[motionIndex]);
Blynk.virtualWrite(V_MOTION_PIN, fieldData[motionIndex]);
Blynk.virtualWrite(V_LIGHT_PIN, fieldData[lightIndex]);
}
void logOut()
{
Serial.print("currentLightStatus: ");
Serial.println(currentLightStatus);
Serial.print("currentMotionStatus: ");
Serial.println(currentMotionStatus);
Serial.print("changedLightStatus: ");
Serial.println(changedLightStatus);
Serial.print("changedMotionStatus: ");
Serial.println(changedMotionStatus);
Serial.print("lastTrueMotionMillis: ");
Serial.println(lastTrueMotionMillis);
Serial.print("lastBalancedMotionMillis: ");
Serial.println(lastBalancedMotionMillis);
Serial.print("timeWhenLightsWithoutMotionStarted: ");
Serial.println(timeWhenLightsWithoutMotionStarted);
Serial.print("timeWithLightsWithoutMotion: ");
Serial.println(timeWithLightsWithoutMotion);
Serial.print("balancedNoMotionStatus: ");
Serial.println(balancedNoMotionStatus);
Serial.print("badStatus: ");
Serial.println(badStatus);
}
Complete proof-of-concept (Blynk_Hackster_LuminaireX_3.ino)
Arduino#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
////////////////////
// Blynk Settings //
////////////////////
char BlynkAuth[] = "dont_hack_me";
char WiFiNetwork[] = "dont_hack_me";
char WiFiPassword[] = "dont_hack_me";
///////////////////////
// Hardware Settings //
///////////////////////
#define MOTION_PIN 5
#define LIGHT_PIN A0
#define V_MOTION_PIN V0
#define V_LIGHT_PIN V1
#define V_RESULT_PIN V2
/////////////////////
// Data Structures //
/////////////////////
const byte NUM_FIELDS = 2;
const String fieldNames[NUM_FIELDS] = {"light", "motion"};
String fieldData[NUM_FIELDS];
//////////////////////
// Input Pins, Misc //
//////////////////////
WidgetLCD resultsLcd(V_RESULT_PIN);
int lightIndex = 0;
int motionIndex = 1;
long lastModulus = 0;
long newModulus = 0;
int currentLightStatus = 0;
int currentMotionStatus = 0;
int changedLightStatus = 0;
int changedMotionStatus = 0;
int balancedNoMotionStatus = 0;
int badStatus = 0; // State when the room is unnocupied and lit.
unsigned long lastTrueMotionMillis = 0;
unsigned long lastBalancedMotionMillis = 0;
unsigned long timeWhenLightsWithoutMotionStarted = 0;
unsigned long timeWithLightsWithoutMotion = 0;
void setup()
{
BLYNK_PRINT.begin(9600);
pinMode(MOTION_PIN, INPUT);
pinMode(LIGHT_PIN, INPUT);
Blynk.begin(BlynkAuth, WiFiNetwork, WiFiPassword);
}
void loop()
{
Blynk.run();
readyData();
checkChange();
unsigned long tmpMillis = millis();
if (changedMotionStatus == 1 && currentMotionStatus == 0)
{
lastTrueMotionMillis = tmpMillis;
}
else
{
unsigned long diffMotionMillis = tmpMillis - lastTrueMotionMillis;
if (diffMotionMillis >= 10000)
{
lastBalancedMotionMillis = tmpMillis;
balancedNoMotionStatus = 1;
}
}
if (currentMotionStatus == 1)
{
timeWhenLightsWithoutMotionStarted = tmpMillis;
}
else if (balancedNoMotionStatus == 1 && currentLightStatus == 1 && badStatus == 0)
{
timeWhenLightsWithoutMotionStarted = tmpMillis;
badStatus = 1;
}
else if (currentLightStatus == 0 && changedLightStatus == 1 && badStatus == 1)
{
badStatus = 0;
timeWithLightsWithoutMotion = timeWithLightsWithoutMotion + (tmpMillis - timeWhenLightsWithoutMotionStarted);
}
logOut();
changedMotionStatus = 0;
changedLightStatus = 0;
if (millis() > (lastModulus + 250)) {
newModulus = ((int)(millis() / 250)) * 250;
postDataBlynk();
Serial.print("Last Modulus: ");
Serial.println(lastModulus);
lastModulus = newModulus;
Serial.print("New Modulus: ");
Serial.println(lastModulus);
}
}
void checkChange()
{
int lastLightStatus = currentLightStatus;
int lastMotionStatus = currentMotionStatus;
if (fieldData[lightIndex].toInt() >= 500)
{
Serial.println("Light is on.");
currentLightStatus = 1;
}
else
currentLightStatus = 0;
currentMotionStatus = fieldData[motionIndex].toInt() / 1023;
if (currentLightStatus != lastLightStatus)
changedLightStatus = 1;
if (currentMotionStatus != lastMotionStatus)
changedMotionStatus = 1;
}
void readyData()
{
fieldData[lightIndex] = analogRead(LIGHT_PIN);
fieldData[motionIndex] = digitalRead(MOTION_PIN) * 1023;
}
void postDataBlynk()
{
String stringResults = "";
stringResults += String(timeWithLightsWithoutMotion/1000);
stringResults += "/";
stringResults += String(millis()/1000);
BLYNK_PRINT.println(fieldData[lightIndex]);
BLYNK_PRINT.println(fieldData[motionIndex]);
BLYNK_PRINT.println(stringResults);
Blynk.virtualWrite(V_MOTION_PIN, fieldData[motionIndex]);
Blynk.virtualWrite(V_LIGHT_PIN, fieldData[lightIndex]);
resultsLcd.clear();
resultsLcd.print(0, 0, stringResults);
}
void logOut()
{
Serial.print("currentLightStatus: ");
Serial.println(currentLightStatus);
Serial.print("currentMotionStatus: ");
Serial.println(currentMotionStatus);
Serial.print("changedLightStatus: ");
Serial.println(changedLightStatus);
Serial.print("changedMotionStatus: ");
Serial.println(changedMotionStatus);
Serial.print("lastTrueMotionMillis: ");
Serial.println(lastTrueMotionMillis);
Serial.print("lastBalancedMotionMillis: ");
Serial.println(lastBalancedMotionMillis);
Serial.print("timeWhenLightsWithoutMotionStarted: ");
Serial.println(timeWhenLightsWithoutMotionStarted);
Serial.print("timeWithLightsWithoutMotion: ");
Serial.println(timeWithLightsWithoutMotion);
Serial.print("balancedNoMotionStatus: ");
Serial.println(balancedNoMotionStatus);
Serial.print("badStatus: ");
Serial.println(badStatus);
}
Final product code (Blynk_Hackster_LuminaireX_4.ino)
Arduino#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
////////////////////
// Blynk Settings //
////////////////////
char BlynkAuth[] = "dont_hack_me";
char WiFiNetwork[] = "dont_hack_me";
char WiFiPassword[] = "dont_hack_me";
///////////////////////
// Hardware Settings //
///////////////////////
#define MOTION_PIN 5
#define LIGHT_PIN A0
#define V_MOTION_PIN V0
#define V_LIGHT_PIN V1
#define V_RESULT_PIN V2
/////////////////////
// Data Structures //
/////////////////////
const byte NUM_FIELDS = 2;
const String fieldNames[NUM_FIELDS] = {"light", "motion"};
String fieldData[NUM_FIELDS];
//////////////////////
// Input Pins, Misc //
//////////////////////
WidgetLCD resultsLcd(V_RESULT_PIN);
int lightIndex = 0;
int motionIndex = 1;
long lastModulus = 0;
long newModulus = 0;
int currentLightStatus = 0;
int currentMotionStatus = 0;
int changedLightStatus = 0;
int changedMotionStatus = 0;
int balancedNoMotionStatus = 0;
int badStatus = 0; // State when the room is unnocupied and lit.
unsigned long lastTrueMotionMillis = 0;
unsigned long lastBalancedMotionMillis = 0;
unsigned long timeWhenLightsWithoutMotionStarted = 0;
unsigned long timeWithLightsWithoutMotion = 0;
void setup()
{
BLYNK_PRINT.begin(9600);
pinMode(MOTION_PIN, INPUT);
pinMode(LIGHT_PIN, INPUT);
Blynk.begin(BlynkAuth, WiFiNetwork, WiFiPassword);
}
void loop()
{
Blynk.run();
readyData();
checkChange();
unsigned long tmpMillis = millis();
if (changedMotionStatus == 1 && currentMotionStatus == 0)
{
lastTrueMotionMillis = tmpMillis;
}
else
{
unsigned long diffMotionMillis = tmpMillis - lastTrueMotionMillis;
if (diffMotionMillis >= 10000)
{
lastBalancedMotionMillis = tmpMillis;
balancedNoMotionStatus = 1;
}
}
if (currentMotionStatus == 1)
{
timeWhenLightsWithoutMotionStarted = tmpMillis;
}
else if (balancedNoMotionStatus == 1 && currentLightStatus == 1 && badStatus == 0)
{
timeWhenLightsWithoutMotionStarted = tmpMillis;
badStatus = 1;
}
else if (currentLightStatus == 0 && changedLightStatus == 1 && badStatus == 1)
{
badStatus = 0;
timeWithLightsWithoutMotion = timeWithLightsWithoutMotion + (tmpMillis - timeWhenLightsWithoutMotionStarted);
}
// logOut();
changedMotionStatus = 0;
changedLightStatus = 0;
if (millis() > (lastModulus + 250)) {
newModulus = ((int)(millis() / 250)) * 250;
postDataBlynk();
// Serial.print("Last Modulus: ");
// Serial.println(lastModulus);
lastModulus = newModulus;
// Serial.print("New Modulus: ");
// Serial.println(lastModulus);
}
}
void checkChange()
{
int lastLightStatus = currentLightStatus;
int lastMotionStatus = currentMotionStatus;
if (fieldData[lightIndex].toInt() >= 500)
{
// Serial.println("Light is on.");
currentLightStatus = 1;
}
else
currentLightStatus = 0;
currentMotionStatus = fieldData[motionIndex].toInt() / 1023;
if (currentLightStatus != lastLightStatus)
changedLightStatus = 1;
if (currentMotionStatus != lastMotionStatus)
changedMotionStatus = 1;
}
void readyData()
{
fieldData[lightIndex] = analogRead(LIGHT_PIN);
fieldData[motionIndex] = digitalRead(MOTION_PIN) * 1023;
}
void postDataBlynk()
{
String stringResults = "";
stringResults += String(timeWithLightsWithoutMotion/1000);
stringResults += "/";
stringResults += String(millis()/1000);
BLYNK_PRINT.println(fieldData[lightIndex]);
BLYNK_PRINT.println(fieldData[motionIndex]);
BLYNK_PRINT.println(stringResults);
Blynk.virtualWrite(V_MOTION_PIN, fieldData[motionIndex]);
Blynk.virtualWrite(V_LIGHT_PIN, fieldData[lightIndex]);
resultsLcd.clear();
resultsLcd.print(0, 0, stringResults);
}
void logOut()
{
Serial.print("currentLightStatus: ");
Serial.println(currentLightStatus);
Serial.print("currentMotionStatus: ");
Serial.println(currentMotionStatus);
Serial.print("changedLightStatus: ");
Serial.println(changedLightStatus);
Serial.print("changedMotionStatus: ");
Serial.println(changedMotionStatus);
Serial.print("lastTrueMotionMillis: ");
Serial.println(lastTrueMotionMillis);
Serial.print("lastBalancedMotionMillis: ");
Serial.println(lastBalancedMotionMillis);
Serial.print("timeWhenLightsWithoutMotionStarted: ");
Serial.println(timeWhenLightsWithoutMotionStarted);
Serial.print("timeWithLightsWithoutMotion: ");
Serial.println(timeWithLightsWithoutMotion);
Serial.print("balancedNoMotionStatus: ");
Serial.println(balancedNoMotionStatus);
Serial.print("badStatus: ");
Serial.println(badStatus);
}
Comments