Stairs/src/settings/triggers/time.cpp

200 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 <ArduinoJson.h>
#include "../../debug.h"
#include "../../global.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;
default: return Monday;
}
}
void TimeTriggerSettings::toJson(Print &print)
{
DynamicJsonBuffer jsonBuffer(JSON_ARRAY_SIZE(10) + JSON_OBJECT_SIZE(3) + 10*JSON_OBJECT_SIZE(5));
JsonObject& root = jsonBuffer.createObject();
root["enabled"] = enabled();
root["transitionTime"] = transitionTime();
JsonArray& jsonTriggers = root.createNestedArray("triggers");
for (uint8_t i = 0; i < triggerCount(); i++)
{
TimeTrigger* triggerItem = trigger(i);
JsonObject& jsonTrigger = jsonTriggers.createNestedObject();
jsonTrigger["time"] = triggerItem->time;
jsonTrigger["daysOfWeek"] = triggerItem->daysOfWeek;
jsonTrigger["brightness"] = triggerItem->brightness;
jsonTrigger["triggerType"] = (uint8_t)triggerItem->triggerType;
jsonTrigger["enabled"] = triggerItem->enabled;
}
root.printTo(print);
}
bool TimeTriggerSettings::fromJson(char* data, bool* changed)
{
if (changed != nullptr)
*changed = false;
DynamicJsonBuffer jsonBuffer(JSON_ARRAY_SIZE(10) + JSON_OBJECT_SIZE(3) + 10*JSON_OBJECT_SIZE(5) + 270);
JsonObject& root = jsonBuffer.parseObject(data);
if (!root.success())
return false;
enabled(root["enabled"]);
transitionTime(root["transitionTime"]);
if (root.containsKey("triggers"))
{
JsonArray& jsonTriggers = root["triggers"];
if (mTriggers != nullptr)
delete [] mTriggers;
mTriggerCount = jsonTriggers.size();
mTriggers = new TimeTrigger[mTriggerCount];
for (uint8_t i = 0; i < mTriggerCount; i++)
{
JsonObject& jsonTrigger = jsonTriggers[i];
TimeTrigger* trigger = &mTriggers[i];
trigger->time = jsonTrigger["time"];
trigger->daysOfWeek = jsonTrigger["daysOfWeek"];
trigger->brightness = jsonTrigger["brightness"];
trigger->triggerType = (TimeTriggerType)(uint8_t)jsonTrigger["triggerType"];
trigger->enabled = jsonTrigger["enabled"];
}
}
if (changed != nullptr)
*changed = true;
return true;
}
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;
Dusk2Dawn location(systemSettings->latitude(), systemSettings->longitude(), timezoneOffset / 3600.0f);
// Praise the sun \o/
// DST is always hardcoded as false, since it is already included in timezoneOffset
int16_t sunriseMinutes = location.sunrise(time.Year, time.Month, time.Day, false);
int16_t sunsetMinutes = location.sunset(time.Year, time.Month, time.Day, false);
int16_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)
{
case RelativeToSunrise:
triggerTime += sunriseMinutes;
break;
case RelativeToSunset:
triggerTime += sunsetMinutes;
break;
case FixedTime:
// No changes (but eliminates warning)
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);
// Set the comparison time to the end of the day, so the last
// trigger for that day will match
dayTime = 24 * 60;
} while (dayOfWeek != startDayOfWeek);
return nullptr;
}