29 static const quint64
kThou = 1000;
31 static const quint64
k24 = 24;
32 static const quint64
k7 = 7;
51 return QStringLiteral(
"Unknown");
56 QString type = Type.trimmed().toUpper();
80 m_randomDuration(false),
84 m_singleShotStartTime(0)
86 static bool randomcheck =
true;
91 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Maximum random number is too low for effective use (%1)").arg(RAND_MAX));
96 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Unknown timer type '%1' for device '%2'").arg(Details.value(QStringLiteral(
"type")).toString(),
uniqueId));
100 int days, hours, minutes, seconds = 0;
108 if (!Details.contains(QStringLiteral(
"start")))
110 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Timer '%1' does not specify start time").arg(
uniqueId));
115 if (!Details.contains(QStringLiteral(
"duration")))
117 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Timer '%1' does not specify duration").arg(
uniqueId));
122 QString start = Details.value(QStringLiteral(
"start")).toString().toLower().trimmed();
123 m_randomStart = start.contains(QStringLiteral(
"random"));
125 QString durations = Details.value(QStringLiteral(
"duration")).toString().toLower().trimmed();
126 m_randomDuration = durations.contains(QStringLiteral(
"random"));
129 if (m_randomStart && m_randomDuration)
131 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Timer %1 cannot have random start AND duration").arg(
uniqueId));
135 bool periodavail = Details.contains(QStringLiteral(
"period"));
136 bool haveperiod =
true;
137 bool random = m_randomStart || m_randomDuration;
139 m_active = m_firstTrigger = !single;
146 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Timer %1 does not specify a period").arg(
uniqueId));
150 QString periods = Details.value(QStringLiteral(
"period")).toString().toLower().trimmed();
154 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to parse period from '%1'").arg(periods));
159 m_periodTime = periodtime * 1000;
162 if (m_periodTime < 2000)
164 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Timer %1 has duration of %2seconds - needs at least 2").arg(
uniqueId).arg(m_periodTime / 1000));
168 else if (single && !random)
174 m_periodTime = GetPeriodDuration();
196 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to parse start time from '%1'").arg(start));
201 m_startTime = starttime * 1000;
203 if (haveperiod && (m_startTime >= m_periodTime ))
205 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Start time (%2) for %1 is invalid - must be in range 0-%3")
206 .arg(
uniqueId).arg(m_startTime / 1000).arg((m_periodTime / 1000) - 1));
211 if (!m_randomDuration)
216 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to parse duration from '%1'").arg(durations));
220 m_duration = duration * 1000;
221 m_durationDay = days;
223 if ((m_duration < 1000) || (haveperiod && (m_duration >= m_periodTime)))
225 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Duration (%1) for %2 is invalid - must be in range 1-%3")
226 .arg(m_duration / 1000).arg(
uniqueId).arg((m_periodTime / 1000) - 1));
234 m_periodTime = m_startTime + m_duration;
235 if (m_periodTime < 2000)
272 QMutexLocker locker(&
lock);
285 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Time device '%1' needs an input").arg(
uniqueId));
290 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Timer device '%1' cannot have inputs").arg(
uniqueId));
297 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Timer device '%1' needs at least one output").arg(
uniqueId));
308 m_timer.setTimerType(Qt::PreciseTimer);
314 m_timer.setSingleShot(
true);
326 QMutexLocker locker(&
lock);
357 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Not restarting single shot timer %1").arg(
uniqueId));
361 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Timer %1 restarting").arg(
uniqueId));
363 m_firstTrigger =
true;
370 return TorcControl::event(Event);
375 QMutexLocker locker(&
lock);
380 bool first = m_firstTrigger;
381 m_firstTrigger =
false;
386 quint64 msecsinceperiodstart = MsecsSincePeriodStart();
387 quint64 finishtime = m_startTime + m_duration;
388 bool newvalue =
false;
389 quint64 nexttimer = 0;
394 if (msecsinceperiodstart > finishtime)
399 else if (msecsinceperiodstart < m_startTime)
402 nexttimer = m_startTime - msecsinceperiodstart;
407 nexttimer = finishtime - msecsinceperiodstart;
425 bool newrandom =
false;
429 if (m_startTime == 0)
431 newvalue = msecsinceperiodstart <= m_duration;
432 nexttimer = newvalue ? m_duration - msecsinceperiodstart : m_periodTime - msecsinceperiodstart;
433 newrandom =
value < 1.0 && newvalue;
437 else if (finishtime < m_periodTime)
439 if (msecsinceperiodstart < m_startTime)
442 nexttimer = m_startTime - msecsinceperiodstart;
444 else if (msecsinceperiodstart > finishtime)
447 nexttimer = m_periodTime - msecsinceperiodstart;
453 nexttimer = finishtime - msecsinceperiodstart;
456 if (!newvalue && (
value < 1.0) && (m_lastElapsed > msecsinceperiodstart))
461 else if (finishtime == m_periodTime)
463 newvalue = msecsinceperiodstart >= m_startTime;
464 nexttimer = newvalue ? m_periodTime - msecsinceperiodstart : m_startTime - msecsinceperiodstart;
465 newrandom =
value > 0.0 && !newvalue;
468 else if (finishtime > m_periodTime)
472 if (m_randomDuration || m_randomStart)
474 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Invalid condition for random timer - disabling"));
478 quint64 firststart = finishtime - m_periodTime;
480 if (msecsinceperiodstart <= firststart)
483 nexttimer = firststart - msecsinceperiodstart;
485 else if (msecsinceperiodstart >= m_startTime)
488 nexttimer = m_periodTime - msecsinceperiodstart;
493 nexttimer = m_startTime - msecsinceperiodstart;
497 if (first && newvalue)
499 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Triggering timer '%1' late - will run for %2seconds instead of %3 %4")
500 .arg(
uniqueId).arg(nexttimer/1000.0).arg(m_duration/1000).arg(QDateTime::currentDateTime().toString(QStringLiteral(
"HH:mm:ss.zzz"))));
503 m_lastElapsed = msecsinceperiodstart;
509 if (!first && newrandom && !m_newRandom && (m_randomDuration || m_randomStart))
523 quint64 adjust = nexttimer / 10;
531 m_timer.start(nexttimer);
543 QMutexLocker locker(&
lock);
546 return std::numeric_limits<quint64>::max();
549 return m_startTime ? std::numeric_limits<quint64>::max() : 0;
551 quint64 msecsinceperiodstart = MsecsSincePeriodStart();
552 quint64 finishtime = m_startTime + m_duration;
553 quint64 lasttimer = 0;
560 if (m_startTime == 0)
562 lasttimer = (msecsinceperiodstart <= m_duration) ? msecsinceperiodstart : msecsinceperiodstart - m_duration;
566 else if (finishtime < m_periodTime)
568 if (msecsinceperiodstart < m_startTime)
570 lasttimer = msecsinceperiodstart + (m_periodTime - finishtime);
572 else if (msecsinceperiodstart > finishtime)
574 lasttimer = msecsinceperiodstart - finishtime;
578 lasttimer = msecsinceperiodstart - m_startTime;
583 else if (finishtime == m_periodTime)
585 lasttimer = (msecsinceperiodstart >= m_startTime) ? msecsinceperiodstart - m_startTime : msecsinceperiodstart;
588 else if (finishtime > m_periodTime)
590 quint64 firststart = finishtime - m_periodTime;
591 if (msecsinceperiodstart <= firststart)
593 lasttimer = msecsinceperiodstart + (m_periodTime - m_startTime);
595 else if (msecsinceperiodstart >= m_startTime)
597 lasttimer = msecsinceperiodstart - m_startTime;
601 lasttimer = msecsinceperiodstart - firststart;
608 quint64 TorcTimerControl::MsecsSincePeriodStart(
void)
613 QTime timenow = QTime::currentTime();
614 int day = QDate::currentDate().dayOfWeek() - 1;
620 static const QDateTime reference = QDateTime::fromString(QStringLiteral(
"2000-01-01T00:00:00"), Qt::ISODate);
621 if (m_periodTime > 0)
622 return (QDateTime::currentMSecsSinceEpoch() - reference.toMSecsSinceEpoch()) % m_periodTime;
627 return QDateTime::currentMSecsSinceEpoch() - m_singleShotStartTime;
632 timenow = QTime(0, timenow.minute(), timenow.second(), timenow.msec());
635 timenow = QTime(0, 0, timenow.second(), timenow.msec());
637 quint64 msecsinceperiodstart = timenow.msecsSinceStartOfDay();
641 return msecsinceperiodstart;
644 quint64 TorcTimerControl::GetPeriodDuration(
void)
const 661 void TorcTimerControl::GenerateTimings(
void)
664 if (m_randomDuration)
671 quint64 start = (quint64)((
double)m_startTime * ((double)(m_periodTime - 1000) / (double)m_periodTime));
672 quint64 mod = (m_periodTime / 1000) - (start / 1000);
674 m_duration = (qrand() % mod);
678 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Timer %1 - new random duration %2").arg(
uniqueId,
DurationToString(m_durationDay, m_duration / 1000)));
680 else if (m_randomStart)
682 quint64 mod = (m_periodTime / 1000) - (m_duration / 1000) + 1;
683 m_startTime = qrand() % (mod);
686 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Timer %1 - new random start %2").arg(
uniqueId,
DurationToString(m_startDay, m_startTime / 1000)));
690 void TorcTimerControl::CalculateOutput(
void)
696 QMutexLocker locker(&
lock);
701 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Single shot timer %1 restarting").arg(
uniqueId));
704 m_singleShotStartTime = QDateTime::currentMSecsSinceEpoch();
static QString TimerTypeToString(TorcTimerControl::TimerType Type)
static TorcTimerControl::TimerType StringToTimerType(const QString &Type)
static bool ParseTimeString(const QString &Time, int &Days, int &Hours, int &Minutes, int &Seconds, quint64 &DurationInSeconds)
Parse a Torc time string into days, hours, minutes and, if present, seconds.
bool AllowInputs(void) const override
Timers cannot have inputs.
void ValueChanged(double Value)
TorcLocalContext * gLocalContext
virtual bool Validate(void)
static const quint64 kMSecsinWeek
QMap< QObject *, QString > m_inputs
static const quint64 kMSecsInMinute
static const quint64 kThou
QMap< QObject *, double > m_inputValues
bool Validate(void) override
QMap< QObject *, double > m_lastInputValues
void SetValid(bool Valid) override
TorcTimerControl::TimerType GetTimerType(void) const
static const quint64 kMSecsInDay
quint64 TimeSinceLastTransition(void)
void SetValue(double Value) override
static Type TorcEventType
Register TorcEventType with QEvent.
TorcTimerControl(const QString &Type, const QVariantMap &Details)
static QString DurationToString(int Days, quint64 Duration)
bool Finish(void)
Finish setup of the control.
A general purpose event object.
#define LOG(_MASK_, _LEVEL_, _STRING_)
QStringList GetDescription(void) override
void AddObserver(QObject *Observer)
brief Register the given object to receive events.
static const quint64 kMSecsInHour
TorcControl::Type GetType(void) const override
void Start(void) override
Initialise the timer.
void RemoveObserver(QObject *Observer)
brief Deregister the given object.
bool event(QEvent *Event) override
static const quint64 kSixty
QMap< QObject *, QString > m_outputs