WiFiUDP ntpUDP; uint32_t lastTimeTriggerChecked = 0; TimeTrigger* lastTimeTrigger = nullptr; TimeTrigger* activeTimeTrigger = nullptr; void initMotionPins() { if (!motionTriggerSettings->enabled()) return; for (uint8_t i = 0; i < motionTriggerSettings->triggerCount(); i++) { MotionTrigger* trigger = motionTriggerSettings->trigger(i); if (trigger->enabled) pinMode(trigger->pin, INPUT); } } void updateNTPClient() { if (ntpClient == nullptr && WiFi.status() == WL_CONNECTED && systemSettings->ntpServer() != nullptr && systemSettings->ntpInterval() > 0) { _dln("NTP :: initializing NTP client"); ntpClient = new NTPClient(ntpUDP, systemSettings->ntpServer(), 0, systemSettings->ntpInterval() * 60 * 1000); ntpClient->begin(); } if (ntpClient != nullptr) ntpClient->update(); } void updateTimeTrigger() { if (ntpClient == nullptr || !timeTriggerSettings->enabled()) { activeTimeTrigger = nullptr; return; } if (timeTriggerSettingsChanged) { // Time trigger settings changed, activeTimeTrigger pointer is considered // invalid, force recheck timeTriggerSettingsChanged = false; } else if (currentTime - lastTimeTriggerChecked < 10000) return; lastTimeTriggerChecked = currentTime; _dln("Triggers:: updating time trigger"); uint32_t epochTime = ntpClient->getEpochTime(); if (epochTime == 0) { activeTimeTrigger = nullptr; _dln("Triggers:: time not synchronised yet"); return; } // TODO apply timezone offset tmElements_t time; breakTime(epochTime, time); activeTimeTrigger = timeTriggerSettings->getActiveTrigger(time); #ifdef SerialDebug _d("Triggers:: active time trigger: "); if (activeTimeTrigger != nullptr) _dln(activeTimeTrigger->time); else _dln("null"); #endif } uint32_t activeMotionStart = 0; uint16_t activeMotionBrightness = 0; MotionDirection activeMotionDirection = Nondirectional; bool lastMotion = false; void updateMotionTrigger() { if (!motionTriggerSettings->enabled() || !motionTriggerSettings->triggerCount()) { activeMotionStart = 0; return; } for (uint8_t i = 0; i < motionTriggerSettings->triggerCount(); i++) { MotionTrigger* trigger = motionTriggerSettings->trigger(i); if (trigger->enabled && digitalRead(trigger->pin) == HIGH) { if (activeMotionStart == 0) { activeMotionDirection = trigger->direction; activeMotionBrightness = trigger->brightness; } activeMotionStart = currentTime; } } if (currentTime - activeMotionStart >= motionTriggerSettings->delay()) activeMotionStart = 0; } void checkTriggers() { if (!timeTriggerSettings->enabled() && activeTimeTrigger == nullptr && !motionTriggerSettings->enabled() && activeMotionStart == 0) return; updateTimeTrigger(); updateMotionTrigger(); bool inTimeTrigger = timeTriggerSettings->enabled() && activeTimeTrigger != nullptr && activeTimeTrigger->brightness; bool timeTriggerChanged = activeTimeTrigger != lastTimeTrigger; lastTimeTrigger = activeTimeTrigger; bool inMotionTrigger = (activeMotionStart > 0) && (!inTimeTrigger || motionTriggerSettings->enabledDuringTimeTrigger()); bool motionChanged = (activeMotionStart > 0) != lastMotion; lastMotion = (activeMotionStart > 0); if (!motionChanged && !timeTriggerChanged) return; if (motionChanged) { if (inMotionTrigger) { _dln("Triggers :: start motion trigger"); if (activeMotionDirection == Nondirectional || motionTriggerSettings->transitionTime() == 0) { stairs->setAll(activeMotionBrightness, motionTriggerSettings->transitionTime(), 0); } else { // Start sweep uint8_t stepsCount = stepsSettings->count(); uint16_t offsetIncrement = stepsCount > 0 ? (motionTriggerSettings->transitionTime() / stepsCount) * 1.5 : 0; uint16_t offset = activeMotionDirection == TopDown ? 0 : (stepsCount - 1) * offsetIncrement; for (uint8_t step = 0; step < stepsCount; step++) { stairs->set(step, activeMotionBrightness, motionTriggerSettings->transitionTime(), offset); if (activeMotionDirection == TopDown) offset += offsetIncrement; else offset -= offsetIncrement; } } } else { if (inTimeTrigger) { _dln("Triggers :: motion stopped, falling back to time trigger"); // Fall back to time trigger value stairs->setAll(activeTimeTrigger->brightness, motionTriggerSettings->transitionTime(), 0); } else { _dln("Triggers :: motion stopped, turning off"); // No more motion, no active time trigger, turn off stairs->setAll(0, motionTriggerSettings->transitionTime(), 0); } } } else if (timeTriggerChanged && !inMotionTrigger) { _dln("Triggers :: time trigger changed"); // Set to time trigger value stairs->setAll(activeTimeTrigger->brightness, timeTriggerSettings->transitionTime(), 0); } }