Hardware components | ||||||
![]() |
| × | 1 | |||
| × | 4 | ||||
| × | 4 | ||||
| × | 2 | ||||
| × | 2 |
phoneyTV for Spark Core
Have fun building this cool presence simulator...
Obsessed with home security projects, I originally developed this project for the mySensors.org platform for Arduino. I wanted to develop a stand-alone version that would still allow me to control it over the internet or with my internet-enabled home-automation controller. With the power of Spark, I was able to add a lot of functionality that allows phoneyTV to operate connected or independently.
Functions/Features:
- Three modes, Manual, Sunset and Scheduled triggers allow you flexibility to create your realistic effects.
- Control on/off times and randomize the times to enhance mimicking real-life timing.
- Automatically adjusts for Daylight Savings and adjusts to solar sunset using the Sunrise.h library.
- PWM on Blue and White LEDs and random dark dips give realistic shifts in light intensity.
- Uses an average of 3-4 watts versus average of 80 watts for a 42in TV... about the same energy used as a nightlight!
- Add a simple pushbutton on/off for manual control.
- Low-cost, especially with the soon-to-arrive Spark Photon, the 12 LEDs were $0.75 each.
Check out the Demo:
realistic TV effects work great projected on a ceiling or on translucent curtains.
Breadboard:
yup, it's this easy...
Control:
Check the settings with a Spark Variable:
Code:
PhoneyTV_Spark.ino
Untitled file
Warning: Embedding code files within the project story has been deprecated. To edit this file or add more files, go to the "Software" tab. To remove this file from the story, click on it to trigger the context menu, then click the trash can button (this won't delete it from the "Software" tab).
/*
* PhoneyTV_Spark V1.0
* 8-FEB-2014
* by Jim Brower >> BulldogLowell@gmail.com
*
* PhoneyTV_Spark illuminates 6 sets of LED's in a random fashion as to mimic the
* ambient light emanating from a television. It is intended to make an empty
* home (or an empty section of a home) appear to be occupied by someone watching
* TV. As an alternative to a real television, this uses a tiny fraction of the
* electrical energy.
*
* You can adjust the length of the blink interval and its "twitchyness" by
* modifying the random number generators, if you prefer more/less 'motion' in
* in your unit.
*
* Takes advantage of available PWM using the wht/blu LEDs to allow
* fluctuations in the intensity of the light, enhancing the PhoneyTV's
* realistic ambient light effect.
*
* Originally Created 12-APR-2014
* http://forum.mysensors.org/topic/85/phoneytv-for-vera-is-here/3
*
* To set the time and mode:
* curl -k https://api.spark.io/v1/devices/<yourSparkID>/phoneyTV -d access_token=<yourAccessToken> -d params=solarMode=<MODE 0/1>#onTime=<float_decimal_time>#offset=<float_decimal_time>#offTime=<float_decimal_time>?
*
* for time, enter 8:15pm like this: 20.25 (eight and one-quarter hours pm)
*
* To turn on/off
* curl -k https://api.spark.io/v1/devices/<yourSparkID>/phoneyPower -d access_token=<yourAccessToken> -d params=1
*
**********LED DETAILS**********
* *
* A0 // White using PWM *
* A1 // White using PWM *
* A2 // Green No PWM *
* A3 // Red No PWM *
* A4 // Blue using PWM *
* A5 // Blue using PWM *
* *
*******************************
*/
#include <application.h>
#include "Sunrise.h"
#include <math.h>
#include <time.h>
#define BUTTON_PIN D2 // Digital I/O pin number for button
#define EEPROM_ID 1 // you can change this to reset your EEPROM storage
class modeCommand {
String argument;
public:
void extractValues(String);
int solarMode () {
return (argument.substring(argument.indexOf("phoneyMode=") + 11, argument.indexOf("#onTime="))).toInt();
}
float onTime () {
return (argument.substring(argument.indexOf("#onTime=") + 8, argument.indexOf("#offset="))).toFloat();
}
float onTimeOffset () {
return (argument.substring(argument.indexOf("#offset=") + 8, argument.indexOf("#offTime="))).toFloat();
}
float offTime () {
return (argument.substring(argument.indexOf("#offTime=") + 9, argument.indexOf("?"))).toFloat();
}
};
void modeCommand::extractValues (String stringPassed){
argument = stringPassed;
}
struct phoneyTime {
uint8_t phoneyHour;
uint8_t phoneyMinute;
};
typedef enum {
TIME_TRIGGER=0, SUNSET_TRIGGER, MANUAL_TRIGGER}
onTrigger;
phoneyTime tvSchedule = {
20, 30}; // 8:30pm turning on, we fix the schedule for TIME_TRIGGERs
phoneyTime tvOffTime = {
1, 15}; // off at 1:15am, we are always using a schedule to turn it off (bedtime)
phoneyTime delaySetting = {
0, 15}; // 15 mins of random on/off times, the Start and End times are extended randomly by up to this ammount (independently)
phoneyTime tvOnTime;
bool autoMode = true;
bool sunsetTrigger = false;
int randomDelay_ON;
int randomDelay_OFF;
bool lastTimerState; // time based state-change dection
unsigned long onTimeDelay;
byte lastButtonState; // button press state-change detection
unsigned long lastPressTime;
bool phoneyState = false;
// these are the settings for the random flashes of light from the leds
int dipInterval = 10;
int darkTime = 1000;
unsigned long dipStartTime;
unsigned long currentMillis;
int ledState = LOW;
unsigned long previousMillis;
int led = 5;
int interval = 2000;
int twitch = 50;
int dipCount = 0;
int analogLevel = 100;
boolean timeToDip = false;
int pin[]= {
A0, A1, A2, A3, A4, A5};
//
unsigned long myTimer; //you can poll the device to get the current settings
char message[75] = ""; // yup, it's a lot of info...
//
// create Sunrise objects (we are only going to be using sunset)
Sunrise winter(40.3571,-74.6702, -5);//Princeton, New Jersey, USA - Latitude/Longitude and UTC offset
Sunrise summer(40.3571, -74.6702,-4);//Princeton, New Jersey, USA - Latitude/Longitude and UTC offset
void setup()
{
Serial.begin(9600);
for (int i = 0; i < 6; i++)
{
pinMode(pin[i], OUTPUT);
}
pinMode(BUTTON_PIN, INPUT_PULLUP);
if (EEPROM.read(0) == EEPROM_ID)
{
tvSchedule.phoneyHour = EEPROM.read(1);
tvSchedule.phoneyMinute = EEPROM.read(2);
delaySetting.phoneyHour = EEPROM.read(3);
delaySetting.phoneyMinute = EEPROM.read(4);
tvOffTime.phoneyHour = EEPROM.read(5);
tvOffTime.phoneyMinute = EEPROM.read(6);
sunsetTrigger = EEPROM.read(7);
autoMode = EEPROM.read(8);
}
Spark.function("phoneyPower", phoneyPower); // internet based state change detection
Spark.function("phoneyMode", phoneyMode); // control phoneyTV's settings
Spark.variable("getTimes", message, STRING); // see how phoneyTV is set
//Spark.variable("delayON", &randomDelay_ON, INT); //only for debugging delays
//Spark.variable("delayOFF", &randomDelay_OFF, INT); //only for debugging delays
//
winter.Astronomical(); //Actual, Civil, Nautical, Astronomical
summer.Astronomical(); // I'm using Astronomical as it effectively eliminates twilight time
//
randomDelay_ON = random(((delaySetting.phoneyHour * 60) + delaySetting.phoneyMinute) * 60); // we want seconds because we are using UNIX timestamps
randomDelay_OFF = random(((delaySetting.phoneyHour * 60) + delaySetting.phoneyMinute) * 60);
}
//
void loop()
{
bool daylightSavings = IsDST(Time.day(), Time.month(), Time.weekday());
Time.zone(daylightSavings? -4 : -5);
if ((millis() - onTimeDelay > 60*60*24*1000UL) && !phoneyMode) // once daily, adjust the random offset
{
randomDelay_ON = random(((delaySetting.phoneyHour * 60) + delaySetting.phoneyMinute) * 60); //seconds
randomDelay_OFF = random(((delaySetting.phoneyHour * 60) + delaySetting.phoneyMinute) * 60); //seconds
onTimeDelay = millis();
}
if (millis() - myTimer > 5000UL)
{
char buffer[75] = "";
sprintf(buffer, "Start=%02d:%02d, Delay=%02d:%02d, End=%02d:%02d, Ctrl:%s, Mode=%s, Device:%s", tvOnTime.phoneyHour, tvOnTime.phoneyMinute, delaySetting.phoneyHour, delaySetting.phoneyMinute, tvOffTime.phoneyHour, tvOffTime.phoneyMinute, autoMode? "AUTO":"MAN", sunsetTrigger? "Solar":"Time", phoneyState? "ON":"OFF");
strcpy (message, buffer);
myTimer = millis();
}
if(sunsetTrigger)
{
if(daylightSavings)
{
summer.Set(Time.month(),Time.day());
tvOnTime.phoneyMinute = summer.sun_Minute();
tvOnTime.phoneyHour = summer.sun_Hour();
}
else
{
winter.Set(Time.month(),Time.day());
tvOnTime.phoneyMinute = winter.sun_Minute();
tvOnTime.phoneyHour = winter.sun_Hour();
}
}
else
{
tvOnTime.phoneyMinute = tvSchedule.phoneyMinute;
tvOnTime.phoneyHour = tvSchedule.phoneyHour;
}
// This block lets you also control it manually during
// MANUAL_TRIGGER mode because it will change state
// only when it crosses the time boundry, yet will
// illuminate correctly after a power cycle (or a reset)
//
bool timerState = timerEvaluate();
if (timerState != lastTimerState && autoMode)
{
phoneyState = timerState;
}
lastTimerState = timerState;
//
int buttonState = digitalRead(BUTTON_PIN);
if ((buttonState != lastButtonState) && (millis() - lastPressTime > 100UL))
{
if (buttonState == LOW)
{
Serial.println("Pressed!!!");
phoneyState = !phoneyState;
lastPressTime = millis();
}
}
lastButtonState = buttonState;
//
if (phoneyState == true)
{
if (timeToDip == false)
{
currentMillis = millis();
if(currentMillis-previousMillis > interval)
{
previousMillis = currentMillis;
interval = random(750,4001);//Adjusts the interval for more/less frequent random light changes
twitch = random(40,100);// Twitch provides motion effect but can be a bit much if too high
dipCount++;
}
if(currentMillis-previousMillis < twitch)
{
led = random(0,6);
analogLevel=random(50,255);// set the range of the 4 pwm leds
ledState = ! ledState;
switch (led) //for the four PWM pins
{
case 0:
pwmWrite();
break;
case 1:
pwmWrite();
break;
case 4:
pwmWrite();
break;
case 5:
pwmWrite();
break;
default:
digitalWrite(pin[led], ledState);
}
if (dipCount > dipInterval)
{
timeToDip = true;
dipCount = 0;
dipStartTime = millis();
darkTime = random(250, 800);
dipInterval = random(5, 250);// cycles of flicker
}
}
}
else
{
Serial.println("Dip Time");
if (millis() - dipStartTime < darkTime)
{
for (int i=0 ; i<6;i++)
{
digitalWrite(pin[i],LOW);
}
}
else
{
timeToDip = false;
}
}
}
else
{
for (int i = 0 ; i < 6; i++)
{
digitalWrite(pin[i],LOW);
}
}
}
//
void pwmWrite()
{
if (ledState == HIGH)
{
analogWrite(pin[led], analogLevel);
}
else
{
digitalWrite(pin[led], LOW);
}
}
//
bool IsDST(int dayOfMonth, int month, int dayOfWeek)
{
if (month < 3 || month > 11)
{
return false;
}
if (month > 3 && month < 11)
{
return true;
}
int previousSunday = dayOfMonth - dayOfWeek;
//In march, we are DST if our previous sunday was on or after the 8th.
if (month == 3)
{
return previousSunday >= 8;
}
//In November we must be before the first sunday to be dst.
//That means the previous sunday must be before the 1st.
return previousSunday <= 0;
}
//
int phoneyPower(String powerState)
{
phoneyState = powerState.charAt(0) - '0';
char buffer[20] = "";
sprintf(buffer, "phoneyTV: %s", phoneyState? "ON" : "OFF");
Serial.println(buffer);
return phoneyState;
}
//
int phoneyMode(String modeArgs)
{
modeCommand command;
command.extractValues(modeArgs);
tvSchedule.phoneyHour = (int) command.onTime();
if (tvSchedule.phoneyHour > 23) tvSchedule.phoneyHour = tvSchedule.phoneyHour % 23;
if (tvSchedule.phoneyHour < 0) tvSchedule.phoneyHour = 0;
tvSchedule.phoneyMinute = (int)((command.onTime() - (int) command.onTime())*60.0);
delaySetting.phoneyHour = min((int) command.onTimeOffset(), 1);
delaySetting.phoneyMinute = (int)((command.onTimeOffset() - (int) command.onTimeOffset())*60.0);
tvOffTime.phoneyHour = (int) command.offTime();
if (tvOffTime.phoneyHour > 23) tvOffTime.phoneyHour = tvOffTime.phoneyHour % 23;
if (tvOffTime.phoneyHour < 0) tvOffTime.phoneyHour = 0;
tvOffTime.phoneyMinute = (int)((command.offTime() - (int) command.offTime())*60.0);
switch (command.solarMode()) {
case TIME_TRIGGER:
sunsetTrigger = false;
autoMode = true;
//
break;
case SUNSET_TRIGGER:
sunsetTrigger = true;
autoMode = true;
//
break;
case MANUAL_TRIGGER:
autoMode = false;
//
break;
default:
return -1;
}
//sunsetTrigger = command.solarMode();
EEPROM.write(0, EEPROM_ID); // is EEPROM storage?
EEPROM.write(1, tvSchedule.phoneyHour);
EEPROM.write(2, tvSchedule.phoneyMinute);
EEPROM.write(3, delaySetting.phoneyHour);
EEPROM.write(4, delaySetting.phoneyMinute);
EEPROM.write(5, tvOffTime.phoneyHour);
EEPROM.write(6, tvOffTime.phoneyMinute);
EEPROM.write(7, sunsetTrigger? 1:0);
EEPROM.write(8, autoMode? 1:0);
return command.solarMode();
}
//
time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss)
{
struct tm t;
t.tm_year = YYYY-1900;
t.tm_mon = MM;
t.tm_mday = DD;
t.tm_hour = hh;
t.tm_min = mm;
t.tm_sec = ss;
t.tm_isdst = 0;
time_t t_of_day = mktime(&t);
return t_of_day;
}
//
bool timerEvaluate() // comparing time here is easier with Unix timestamps...
{
int on_time = tmConvert_t(Time.year(), Time.month(), Time.day(), tvOnTime.phoneyHour, tvOnTime.phoneyMinute, 0);
int off_time = tmConvert_t(Time.year(), Time.month(), Time.day(), tvOffTime.phoneyHour, tvOffTime.phoneyMinute, 0);
int now_time = tmConvert_t(Time.year(), Time.month(), Time.day(), Time.hour(), Time.minute(), Time.second());
//
if (on_time < off_time)
{
return (now_time > (on_time + randomDelay_ON) && now_time < (off_time + randomDelay_OFF));
}
else if (off_time < on_time)
{
return (now_time > (on_time + randomDelay_ON) || now_time < (off_time + randomDelay_OFF));
}
else // if both on and off are set to the same time, I'm confused... so let's not lite up at all!
{
return false;
}
}
Returns Time for Sunrise, Sunset and Solar Noon for the current day including if isDAY() — Read More
Latest commit to the master branch on 5-13-2018
Download as zip/*
* PhoneyTV_Spark V1.0
* 8-FEB-2014
* by Jim Brower >> BulldogLowell@gmail.com
*
* PhoneyTV_Spark illuminates 6 sets of LED's in a random fashion as to mimic the
* ambient light emanating from a television. It is intended to make an empty
* home (or an empty section of a home) appear to be occupied by someone watching
* TV. As an alternative to a real television, this uses a tiny fraction of the
* electrical energy.
*
* You can adjust the length of the blink interval and its "twitchyness" by
* modifying the random number generators, if you prefer more/less 'motion' in
* in your unit.
*
* Takes advantage of available PWM using the wht/blu LEDs to allow
* fluctuations in the intensity of the light, enhancing the PhoneyTV's
* realistic ambient light effect.
*
* Originally Created 12-APR-2014
* http://forum.mysensors.org/topic/85/phoneytv-for-vera-is-here/3
*
* To set the time and mode:
* curl -k https://api.spark.io/v1/devices/<yourSparkID>/phoneyTV -d access_token=<yourAccessToken> -d params=solarMode=<MODE 0/1>#onTime=<float_decimal_time>#offset=<float_decimal_time>#offTime=<float_decimal_time>?
*
* for time, enter 8:15pm like this: 20.25 (eight and one-quarter hours pm)
*
* To turn on/off
* curl -k https://api.spark.io/v1/devices/<yourSparkID>/phoneyPower -d access_token=<yourAccessToken> -d params=1
*
**********LED DETAILS**********
* *
* A0 // White using PWM *
* A1 // White using PWM *
* A2 // Green No PWM *
* A3 // Red No PWM *
* A4 // Blue using PWM *
* A5 // Blue using PWM *
* *
*******************************
*/
#include <application.h>
#include "Sunrise.h"
#include <math.h>
#include <time.h>
#define BUTTON_PIN D2 // Digital I/O pin number for button
#define EEPROM_ID 1 // you can change this to reset your EEPROM storage
class modeCommand {
String argument;
public:
void extractValues(String);
int solarMode () {
return (argument.substring(argument.indexOf("phoneyMode=") + 11, argument.indexOf("#onTime="))).toInt();
}
float onTime () {
return (argument.substring(argument.indexOf("#onTime=") + 8, argument.indexOf("#offset="))).toFloat();
}
float onTimeOffset () {
return (argument.substring(argument.indexOf("#offset=") + 8, argument.indexOf("#offTime="))).toFloat();
}
float offTime () {
return (argument.substring(argument.indexOf("#offTime=") + 9, argument.indexOf("?"))).toFloat();
}
};
void modeCommand::extractValues (String stringPassed){
argument = stringPassed;
}
struct phoneyTime {
uint8_t phoneyHour;
uint8_t phoneyMinute;
};
typedef enum {
TIME_TRIGGER=0, SUNSET_TRIGGER, MANUAL_TRIGGER}
onTrigger;
phoneyTime tvSchedule = {
20, 30}; // 8:30pm turning on, we fix the schedule for TIME_TRIGGERs
phoneyTime tvOffTime = {
1, 15}; // off at 1:15am, we are always using a schedule to turn it off (bedtime)
phoneyTime delaySetting = {
0, 15}; // 15 mins of random on/off times, the Start and End times are extended randomly by up to this ammount (independently)
phoneyTime tvOnTime;
bool autoMode = true;
bool sunsetTrigger = false;
int randomDelay_ON;
int randomDelay_OFF;
bool lastTimerState; // time based state-change dection
unsigned long onTimeDelay;
byte lastButtonState; // button press state-change detection
unsigned long lastPressTime;
bool phoneyState = false;
// these are the settings for the random flashes of light from the leds
int dipInterval = 10;
int darkTime = 1000;
unsigned long dipStartTime;
unsigned long currentMillis;
int ledState = LOW;
unsigned long previousMillis;
int led = 5;
int interval = 2000;
int twitch = 50;
int dipCount = 0;
int analogLevel = 100;
boolean timeToDip = false;
int pin[]= {
A0, A1, A2, A3, A4, A5};
//
unsigned long myTimer; //you can poll the device to get the current settings
char message[75] = ""; // yup, it's a lot of info...
//
// create Sunrise objects (we are only going to be using sunset)
Sunrise winter(40.3571,-74.6702, -5);//Princeton, New Jersey, USA - Latitude/Longitude and UTC offset
Sunrise summer(40.3571, -74.6702,-4);//Princeton, New Jersey, USA - Latitude/Longitude and UTC offset
void setup()
{
Serial.begin(9600);
for (int i = 0; i < 6; i++)
{
pinMode(pin[i], OUTPUT);
}
pinMode(BUTTON_PIN, INPUT_PULLUP);
if (EEPROM.read(0) == EEPROM_ID)
{
tvSchedule.phoneyHour = EEPROM.read(1);
tvSchedule.phoneyMinute = EEPROM.read(2);
delaySetting.phoneyHour = EEPROM.read(3);
delaySetting.phoneyMinute = EEPROM.read(4);
tvOffTime.phoneyHour = EEPROM.read(5);
tvOffTime.phoneyMinute = EEPROM.read(6);
sunsetTrigger = EEPROM.read(7);
autoMode = EEPROM.read(8);
}
Spark.function("phoneyPower", phoneyPower); // internet based state change detection
Spark.function("phoneyMode", phoneyMode); // control phoneyTV's settings
Spark.variable("getTimes", message, STRING); // see how phoneyTV is set
//Spark.variable("delayON", &randomDelay_ON, INT); //only for debugging delays
//Spark.variable("delayOFF", &randomDelay_OFF, INT); //only for debugging delays
//
winter.Astronomical(); //Actual, Civil, Nautical, Astronomical
summer.Astronomical(); // I'm using Astronomical as it effectively eliminates twilight time
//
randomDelay_ON = random(((delaySetting.phoneyHour * 60) + delaySetting.phoneyMinute) * 60); // we want seconds because we are using UNIX timestamps
randomDelay_OFF = random(((delaySetting.phoneyHour * 60) + delaySetting.phoneyMinute) * 60);
}
//
void loop()
{
bool daylightSavings = IsDST(Time.day(), Time.month(), Time.weekday());
Time.zone(daylightSavings? -4 : -5);
if ((millis() - onTimeDelay > 60*60*24*1000UL) && !phoneyMode) // once daily, adjust the random offset
{
randomDelay_ON = random(((delaySetting.phoneyHour * 60) + delaySetting.phoneyMinute) * 60); //seconds
randomDelay_OFF = random(((delaySetting.phoneyHour * 60) + delaySetting.phoneyMinute) * 60); //seconds
onTimeDelay = millis();
}
if (millis() - myTimer > 5000UL)
{
char buffer[75] = "";
sprintf(buffer, "Start=%02d:%02d, Delay=%02d:%02d, End=%02d:%02d, Ctrl:%s, Mode=%s, Device:%s", tvOnTime.phoneyHour, tvOnTime.phoneyMinute, delaySetting.phoneyHour, delaySetting.phoneyMinute, tvOffTime.phoneyHour, tvOffTime.phoneyMinute, autoMode? "AUTO":"MAN", sunsetTrigger? "Solar":"Time", phoneyState? "ON":"OFF");
strcpy (message, buffer);
myTimer = millis();
}
if(sunsetTrigger)
{
if(daylightSavings)
{
summer.Set(Time.month(),Time.day());
tvOnTime.phoneyMinute = summer.sun_Minute();
tvOnTime.phoneyHour = summer.sun_Hour();
}
else
{
winter.Set(Time.month(),Time.day());
tvOnTime.phoneyMinute = winter.sun_Minute();
tvOnTime.phoneyHour = winter.sun_Hour();
}
}
else
{
tvOnTime.phoneyMinute = tvSchedule.phoneyMinute;
tvOnTime.phoneyHour = tvSchedule.phoneyHour;
}
// This block lets you also control it manually during
// MANUAL_TRIGGER mode because it will change state
// only when it crosses the time boundry, yet will
// illuminate correctly after a power cycle (or a reset)
//
bool timerState = timerEvaluate();
if (timerState != lastTimerState && autoMode)
{
phoneyState = timerState;
}
lastTimerState = timerState;
//
int buttonState = digitalRead(BUTTON_PIN);
if ((buttonState != lastButtonState) && (millis() - lastPressTime > 100UL))
{
if (buttonState == LOW)
{
Serial.println("Pressed!!!");
phoneyState = !phoneyState;
lastPressTime = millis();
}
}
lastButtonState = buttonState;
//
if (phoneyState == true)
{
if (timeToDip == false)
{
currentMillis = millis();
if(currentMillis-previousMillis > interval)
{
previousMillis = currentMillis;
interval = random(750,4001);//Adjusts the interval for more/less frequent random light changes
twitch = random(40,100);// Twitch provides motion effect but can be a bit much if too high
dipCount++;
}
if(currentMillis-previousMillis < twitch)
{
led = random(0,6);
analogLevel=random(50,255);// set the range of the 4 pwm leds
ledState = ! ledState;
switch (led) //for the four PWM pins
{
case 0:
pwmWrite();
break;
case 1:
pwmWrite();
break;
case 4:
pwmWrite();
break;
case 5:
pwmWrite();
break;
default:
digitalWrite(pin[led], ledState);
}
if (dipCount > dipInterval)
{
timeToDip = true;
dipCount = 0;
dipStartTime = millis();
darkTime = random(250, 800);
dipInterval = random(5, 250);// cycles of flicker
}
}
}
else
{
Serial.println("Dip Time");
if (millis() - dipStartTime < darkTime)
{
for (int i=0 ; i<6;i++)
{
digitalWrite(pin[i],LOW);
}
}
else
{
timeToDip = false;
}
}
}
else
{
for (int i = 0 ; i < 6; i++)
{
digitalWrite(pin[i],LOW);
}
}
}
//
void pwmWrite()
{
if (ledState == HIGH)
{
analogWrite(pin[led], analogLevel);
}
else
{
digitalWrite(pin[led], LOW);
}
}
//
bool IsDST(int dayOfMonth, int month, int dayOfWeek)
{
if (month < 3 || month > 11)
{
return false;
}
if (month > 3 && month < 11)
{
return true;
}
int previousSunday = dayOfMonth - dayOfWeek;
//In march, we are DST if our previous sunday was on or after the 8th.
if (month == 3)
{
return previousSunday >= 8;
}
//In November we must be before the first sunday to be dst.
//That means the previous sunday must be before the 1st.
return previousSunday <= 0;
}
//
int phoneyPower(String powerState)
{
phoneyState = powerState.charAt(0) - '0';
char buffer[20] = "";
sprintf(buffer, "phoneyTV: %s", phoneyState? "ON" : "OFF");
Serial.println(buffer);
return phoneyState;
}
//
int phoneyMode(String modeArgs)
{
modeCommand command;
command.extractValues(modeArgs);
tvSchedule.phoneyHour = (int) command.onTime();
if (tvSchedule.phoneyHour > 23) tvSchedule.phoneyHour = tvSchedule.phoneyHour % 23;
if (tvSchedule.phoneyHour < 0) tvSchedule.phoneyHour = 0;
tvSchedule.phoneyMinute = (int)((command.onTime() - (int) command.onTime())*60.0);
delaySetting.phoneyHour = min((int) command.onTimeOffset(), 1);
delaySetting.phoneyMinute = (int)((command.onTimeOffset() - (int) command.onTimeOffset())*60.0);
tvOffTime.phoneyHour = (int) command.offTime();
if (tvOffTime.phoneyHour > 23) tvOffTime.phoneyHour = tvOffTime.phoneyHour % 23;
if (tvOffTime.phoneyHour < 0) tvOffTime.phoneyHour = 0;
tvOffTime.phoneyMinute = (int)((command.offTime() - (int) command.offTime())*60.0);
switch (command.solarMode()) {
case TIME_TRIGGER:
sunsetTrigger = false;
autoMode = true;
//
break;
case SUNSET_TRIGGER:
sunsetTrigger = true;
autoMode = true;
//
break;
case MANUAL_TRIGGER:
autoMode = false;
//
break;
default:
return -1;
}
//sunsetTrigger = command.solarMode();
EEPROM.write(0, EEPROM_ID); // is EEPROM storage?
EEPROM.write(1, tvSchedule.phoneyHour);
EEPROM.write(2, tvSchedule.phoneyMinute);
EEPROM.write(3, delaySetting.phoneyHour);
EEPROM.write(4, delaySetting.phoneyMinute);
EEPROM.write(5, tvOffTime.phoneyHour);
EEPROM.write(6, tvOffTime.phoneyMinute);
EEPROM.write(7, sunsetTrigger? 1:0);
EEPROM.write(8, autoMode? 1:0);
return command.solarMode();
}
//
time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss)
{
struct tm t;
t.tm_year = YYYY-1900;
t.tm_mon = MM;
t.tm_mday = DD;
t.tm_hour = hh;
t.tm_min = mm;
t.tm_sec = ss;
t.tm_isdst = 0;
time_t t_of_day = mktime(&t);
return t_of_day;
}
//
bool timerEvaluate() // comparing time here is easier with Unix timestamps...
{
int on_time = tmConvert_t(Time.year(), Time.month(), Time.day(), tvOnTime.phoneyHour, tvOnTime.phoneyMinute, 0);
int off_time = tmConvert_t(Time.year(), Time.month(), Time.day(), tvOffTime.phoneyHour, tvOffTime.phoneyMinute, 0);
int now_time = tmConvert_t(Time.year(), Time.month(), Time.day(), Time.hour(), Time.minute(), Time.second());
//
if (on_time < off_time)
{
return (now_time > (on_time + randomDelay_ON) && now_time < (off_time + randomDelay_OFF));
}
else if (off_time < on_time)
{
return (now_time > (on_time + randomDelay_ON) || now_time < (off_time + randomDelay_OFF));
}
else // if both on and off are set to the same time, I'm confused... so let's not lite up at all!
{
return false;
}
}
Comments
Please log in or sign up to comment.