Stairs/src/settings/triggers/time.cpp

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;
}
}
}
*/
}