230 lines
5.2 KiB
C++
230 lines
5.2 KiB
C++
/*
|
|
* Stairs
|
|
* Copyright 2017 (c) Mark van Renswoude
|
|
*
|
|
* https://git.x2software.net/pub/Stairs
|
|
*/
|
|
#include "time.h"
|
|
#include <string.h>
|
|
#include <FS.h>
|
|
#include "../../debug.h"
|
|
#include "../../global.h"
|
|
#include "../../praisethesun.h"
|
|
|
|
|
|
timeDayOfWeek_t toTimeDayOfWeek(DayOfWeek day)
|
|
{
|
|
switch (day)
|
|
{
|
|
case Monday: return dowMonday;
|
|
case Tuesday: return dowTuesday;
|
|
case Wednesday: return dowWednesday;
|
|
case Thursday: return dowThursday;
|
|
case Friday: return dowFriday;
|
|
case Saturday: return dowSaturday;
|
|
case Sunday: return dowSunday;
|
|
}
|
|
|
|
return dowInvalid;
|
|
}
|
|
|
|
|
|
DayOfWeek toDayOfWeek(timeDayOfWeek_t timeDay)
|
|
{
|
|
switch (timeDay)
|
|
{
|
|
case dowSunday: return Sunday;
|
|
case dowMonday: return Monday;
|
|
case dowTuesday: return Tuesday;
|
|
case dowWednesday: return Wednesday;
|
|
case dowThursday: return Thursday;
|
|
case dowFriday: return Friday;
|
|
case dowSaturday: return Saturday;
|
|
}
|
|
|
|
return Monday;
|
|
}
|
|
|
|
|
|
struct Header
|
|
{
|
|
uint8_t version;
|
|
uint8_t triggerCount;
|
|
uint16_t transitionTime;
|
|
bool enabled;
|
|
};
|
|
|
|
|
|
void TimeTriggerSettings::read()
|
|
{
|
|
_dln("TimeTriggerSettings :: Loading time triggers");
|
|
File f = SPIFFS.open(TimeTriggerSettingsFile, "r");
|
|
if (!f)
|
|
return;
|
|
|
|
if (!f.available())
|
|
return;
|
|
|
|
Header header;
|
|
f.readBytes((char*)&header, sizeof(Header));
|
|
|
|
if (header.version != 1)
|
|
return;
|
|
|
|
mEnabled = header.enabled;
|
|
mTransitionTime = header.transitionTime;
|
|
beginSetTriggers(header.triggerCount);
|
|
|
|
if (header.triggerCount > 0)
|
|
f.readBytes((char*)&mTriggers, header.triggerCount * sizeof(TimeTrigger));
|
|
|
|
endSetTriggers();
|
|
|
|
f.close();
|
|
}
|
|
|
|
|
|
void TimeTriggerSettings::write()
|
|
{
|
|
_dln("TimeTriggerSettings :: Saving time triggers");
|
|
File f = SPIFFS.open(TimeTriggerSettingsFile, "w");
|
|
if (!f)
|
|
return;
|
|
|
|
Header header;
|
|
header.version = 1;
|
|
header.enabled = mEnabled;
|
|
header.transitionTime = mTransitionTime;
|
|
header.triggerCount = mTriggerCount;
|
|
|
|
f.write((uint8_t*)&header, sizeof(Header));
|
|
f.write((uint8_t*)&mTriggers, header.triggerCount * sizeof(TimeTrigger));
|
|
f.close();
|
|
}
|
|
|
|
|
|
TimeTrigger* TimeTriggerSettings::getActiveTrigger(tmElements_t &time)
|
|
{
|
|
if (mTriggerCount == 0)
|
|
return nullptr;
|
|
|
|
|
|
DayOfWeek dayOfWeek = toDayOfWeek((timeDayOfWeek_t)time.Wday);
|
|
DayOfWeek startDayOfWeek = dayOfWeek;
|
|
TimeTrigger* activeTrigger = nullptr;
|
|
int16_t activeTriggerTime = 0;
|
|
|
|
// TODO calculate sunrise and sunset
|
|
double sunrise = 0;
|
|
double sunset = 0;
|
|
|
|
sun_rise_set(tmYearToCalendar(time.Year), time.Month, time.Day,
|
|
systemSettings->latitude(), systemSettings->longitude(),
|
|
&sunrise, &sunset);
|
|
|
|
uint16_t sunriseMinutes = floor(sunrise * 60);
|
|
uint16_t sunsetMinutes = floor(sunset * 60);
|
|
uint16_t dayTime = (time.Hour * 60) + time.Minute;
|
|
|
|
_d("TimeTrigger :: sunrise: "); _dln(sunriseMinutes);
|
|
_d("TimeTrigger :: sunset: "); _dln(sunsetMinutes);
|
|
_d("TimeTrigger :: current time: "); _dln(dayTime);
|
|
|
|
do
|
|
{
|
|
for (uint16_t i = 0; i < mTriggerCount; i++)
|
|
{
|
|
TimeTrigger* trigger = &mTriggers[i];
|
|
|
|
if (trigger->enabled && (trigger->daysOfWeek & dayOfWeek))
|
|
{
|
|
int16_t triggerTime = trigger->time;
|
|
|
|
switch (trigger->triggerType)
|
|
{
|
|
RelativeToSunrise:
|
|
triggerTime += sunriseMinutes;
|
|
break;
|
|
|
|
RelativeToSunset:
|
|
triggerTime += sunsetMinutes;
|
|
break;
|
|
}
|
|
|
|
|
|
// Check if the current time is after the time set in the trigger, and
|
|
// if this trigger is later than any previously found trigger, so that
|
|
// we'll always get the most recent match
|
|
if (triggerTime < dayTime && (activeTrigger == nullptr || triggerTime > activeTriggerTime))
|
|
{
|
|
activeTrigger = trigger;
|
|
activeTriggerTime = triggerTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (activeTrigger != nullptr)
|
|
return activeTrigger;
|
|
|
|
// If there are no active triggers on this day, go back
|
|
// one weekday and try again until we've come around completely
|
|
if (dayOfWeek == Monday)
|
|
dayOfWeek = Sunday;
|
|
else
|
|
dayOfWeek = (DayOfWeek)((uint8_t)dayOfWeek / 2);
|
|
} while (dayOfWeek != startDayOfWeek);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
void TimeTriggerSettings::beginSetTriggers(uint8_t count)
|
|
{
|
|
if (mTriggers != nullptr)
|
|
delete [] mTriggers;
|
|
|
|
mTriggers = new TimeTrigger[count];
|
|
mTriggerCount = count;
|
|
}
|
|
|
|
|
|
void TimeTriggerSettings::setTrigger(uint8_t index, TimeTrigger* value)
|
|
{
|
|
memcpy(&mTriggers[index], value, sizeof(TimeTrigger));
|
|
}
|
|
|
|
|
|
void TimeTriggerSettings::endSetTriggers()
|
|
{
|
|
/* No need to sort, sunrise / sunset triggers already mess things up anyways
|
|
// Sort triggers by time of day
|
|
// Based on the Comb sort implementation by Rob Tillaart
|
|
// http://forum.arduino.cc/index.php?topic=280486.0
|
|
uint8_t i, j;
|
|
uint8_t gap;
|
|
bool swapped = true;
|
|
TimeTrigger temp;
|
|
|
|
gap = mTriggerCount;
|
|
while (gap > 1 || swapped)
|
|
{
|
|
if (gap > 1)
|
|
{
|
|
gap = gap * 10/13;
|
|
if (gap == 9 || gap == 10) gap = 11;
|
|
}
|
|
|
|
swapped = false;
|
|
for (i = 0, j = gap; j < mTriggerCount; i++, j++)
|
|
{
|
|
if (mTriggers[i].time > mTriggers[j].time)
|
|
{
|
|
temp = mTriggers[i];
|
|
mTriggers[i] = mTriggers[j];
|
|
mTriggers[j] = temp;
|
|
swapped = true;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
} |