Thomas Jager
Published

Luminaire X

This project aims to provide a tool that can compare the amount of time during which the light in a room to the time that it's occupied.

IntermediateWork in progress724
Luminaire X

Things used in this project

Hardware components

SparkFun Blynk Board - ESP8266
SparkFun Blynk Board - ESP8266
×1
PIR Motion Sensor (generic)
PIR Motion Sensor (generic)
×1
Photo resistor
Photo resistor
×1
Alligator Clips
Alligator Clips
×8
USB-A to Micro-USB Cable
USB-A to Micro-USB Cable
×1
Male/Female Jumper Wires
Male/Female Jumper Wires
×3

Software apps and online services

Arduino IDE
Arduino IDE
Blynk
Blynk
SparkFun Phant

Story

Read more

Schematics

Hardware Schematic Image

The general hardware setup

Hardware Schematic File

The general hardware setup

Code

Debug sensors and set a framework for data processing (Blynk_Hackster_LuminaireX.ino)

Arduino
This was the first version of the code. It simply measured and posted the sensor values to Blynk and (if enabled, by defining POSTTOPHANT as 1) the data.sparkfun.com Phant server (for debugging and graphing purposes).
#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
This code is used as a demonstration of the concept goal. The value of "timeWithLightsWithoutMotion", printed over serial, compared to a result that would be given by millis(), is the targeted time ratio. Most references to Phant have been removed in this example. However, the final results are not yet sent to Blynk.
#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
This code functions as a more-or-less complete version of the original goal. It outputs the results in "light-time wasted/time running" (seconds) to a Blynk LCD widget in advanced mode on V2.
#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
This is the final working product. Much of the Serial printing has been disabled, but is still present in the code, for easier experimentation.
#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);
}

Credits

Thomas Jager

Thomas Jager

4 projects • 0 followers
Thanks to Sparkfun and Blynk.

Comments