#include #include #include Transition::Builder::Builder(size_t id, uint16_t defaultPeriod, const BulbId& bulbId, TransitionFn callback, size_t maxSteps) : id(id) , defaultPeriod(defaultPeriod) , bulbId(bulbId) , callback(callback) , duration(0) , period(0) , numPeriods(0) , maxSteps(maxSteps) { } Transition::Builder& Transition::Builder::setDuration(float duration) { this->duration = duration * DURATION_UNIT_MULTIPLIER; return *this; } void Transition::Builder::setDurationRaw(size_t duration) { this->duration = duration; } Transition::Builder& Transition::Builder::setPeriod(size_t period) { this->period = period; return *this; } Transition::Builder& Transition::Builder::setDurationAwarePeriod(size_t period, size_t duration, size_t maxSteps) { if ((period * maxSteps) < duration) { setPeriod(std::ceil(duration / static_cast(maxSteps))); } else { setPeriod(period); } return *this; } size_t Transition::Builder::getNumPeriods() const { return this->numPeriods; } size_t Transition::Builder::getDuration() const { return this->duration; } size_t Transition::Builder::getPeriod() const { return this->period; } size_t Transition::Builder::getMaxSteps() const { return this->maxSteps; } bool Transition::Builder::isSetDuration() const { return this->duration > 0; } bool Transition::Builder::isSetPeriod() const { return this->period > 0; } bool Transition::Builder::isSetNumPeriods() const { return this->numPeriods > 0; } size_t Transition::Builder::numSetParams() const { size_t setCount = 0; if (isSetDuration()) { ++setCount; } if (isSetPeriod()) { ++setCount; } if (isSetNumPeriods()) { ++setCount; } return setCount; } size_t Transition::Builder::getOrComputePeriod() const { if (period > 0) { return period; } else if (duration > 0 && numPeriods > 0) { size_t computed = floor(duration / static_cast(numPeriods)); return max(MIN_PERIOD, computed); } else { return 0; } } size_t Transition::Builder::getOrComputeDuration() const { if (duration > 0) { return duration; } else if (period > 0 && numPeriods > 0) { return period * numPeriods; } else { return 0; } } size_t Transition::Builder::getOrComputeNumPeriods() const { if (numPeriods > 0) { return numPeriods; } else if (period > 0 && duration > 0) { size_t _numPeriods = ceil(duration / static_cast(period)); return max(static_cast(1), _numPeriods); } else { return 0; } } std::shared_ptr Transition::Builder::build() { // Set defaults for underspecified transitions size_t numSet = numSetParams(); if (numSet == 0) { setDuration(DEFAULT_DURATION); setDurationAwarePeriod(defaultPeriod, duration, maxSteps); } else if (numSet == 1) { // If duration is unbound, bind it if (! isSetDuration()) { setDurationRaw(DEFAULT_DURATION); // Otherwise, bind the period } else { setDurationAwarePeriod(defaultPeriod, duration, maxSteps); } } return _build(); } Transition::Transition( size_t id, const BulbId& bulbId, size_t period, TransitionFn callback ) : id(id) , bulbId(bulbId) , callback(callback) , period(period) , lastSent(0) { } void Transition::tick() { unsigned long now = millis(); if ((lastSent + period) <= now && ((!isFinished() || lastSent == 0))) { // always send at least once step(); lastSent = now; } } size_t Transition::calculatePeriod(int16_t distance, size_t stepSize, size_t duration) { float fPeriod = distance != 0 ? (duration / (distance / static_cast(stepSize))) : 0; return static_cast(round(fPeriod)); } void Transition::stepValue(int16_t& current, int16_t end, int16_t stepSize) { int16_t delta = end - current; if (std::abs(delta) < std::abs(stepSize)) { current += delta; } else { current += stepSize; } } void Transition::serialize(JsonObject& json) { json[F("id")] = id; json[F("period")] = period; json[F("last_sent")] = lastSent; JsonObject bulbParams = json.createNestedObject("bulb"); bulbId.serialize(bulbParams); childSerialize(json); }