diff --git a/data/profiles/default.json b/data/profiles/default.json index f0f1e1a..727d423 100644 --- a/data/profiles/default.json +++ b/data/profiles/default.json @@ -1,7 +1,6 @@ { "version": 1, "tasks": [ - "Power", "Renderer", "U8Display", "WiFi", diff --git a/data/profiles/djstrip.json b/data/profiles/djstrip.json index 7a0f400..05f9ffb 100644 --- a/data/profiles/djstrip.json +++ b/data/profiles/djstrip.json @@ -3,7 +3,6 @@ "tasks": [ "Bluetooth", "Renderer", - "Power", "Serial" ], "scenes": { diff --git a/data/profiles/ponderjar.json b/data/profiles/ponderjar.json index 60f1a4e..3472c86 100644 --- a/data/profiles/ponderjar.json +++ b/data/profiles/ponderjar.json @@ -3,7 +3,6 @@ "tasks": [ "WiFi", "Renderer", - "Power", "MQTT", "ArduinoOTA", "UpdateStatusAnimation", diff --git a/lib/Figments/Renderer.cpp b/lib/Figments/Renderer.cpp index 874c944..38966e9 100644 --- a/lib/Figments/Renderer.cpp +++ b/lib/Figments/Renderer.cpp @@ -18,7 +18,12 @@ Renderer::lastFigmentName() void Renderer::loop() { + m_powerState.update(); + m_brightness.update(); + + uint16_t totalPower = 0; for(Display* dpy : m_displays) { + totalPower += calculate_unscaled_power_mW(dpy->pixelBacking(), dpy->pixelCount()); for(Figment* figment : m_figments) { if (figment->state == Task::Running) { #if defined(BOARD_ESP32) or defined(BOARD_ESP8266) @@ -38,10 +43,42 @@ Renderer::loop() } }; } - FastLED.show(); + const uint8_t videoBrightness = brighten8_video(m_powerState); + FastLED.show(powerScale(videoBrightness, totalPower)); FastLED.countFPS(); } +void +Renderer::handleEvent(const InputEvent& evt) +{ + switch (evt.intent) { + case InputEvent::PowerToggle: + m_powerState = m_powerState.value() <= 128 ? 255 : 0; + Log.notice("Power toggled to %t", m_powerState); + break; + case InputEvent::SetPower: + m_powerState = evt.asInt() == 0 ? 0 : 255; + Log.notice("Power state is now %t", m_powerState); + break; + case InputEvent::SetBrightness: + m_brightness = evt.asInt(); + break; + } +} + +uint8_t +Renderer::powerScale(uint8_t target, uint32_t totalPower) const +{ + if (m_powerManaged) { + uint32_t requested = ((uint32_t)totalPower * target) / 256; + if (requested > totalPower) { + return (uint32_t)((uint8_t)(target) * (uint32_t)(totalPower)) / ((uint32_t)(requested)); + } + } + + return target; +} + void Renderer::onStart() { @@ -50,3 +87,27 @@ Renderer::onStart() } FastLED.show(); } + +void +Renderer::doOn(Args& args, Print& print) +{} + +void +Renderer::doOff(Args& args, Print& print) +{} + +void +Renderer::doBrightness(Args& args, Print& print) +{} + +const std::vector& +Renderer::commands() const +{ + static const std::vector _commands = { + Command{"brightness", &Renderer::doBrightness}, + Command{"on", &Renderer::doOn}, + Command{"off", &Renderer::doOff} + }; + + return _commands; +} diff --git a/lib/Figments/Renderer.h b/lib/Figments/Renderer.h index 03ad998..cf87877 100644 --- a/lib/Figments/Renderer.h +++ b/lib/Figments/Renderer.h @@ -1,4 +1,6 @@ #include "./Figment.h" +#include "./Animation.h" +#include "./Input.h" #include class Display; @@ -9,10 +11,26 @@ public: void loop() override; void onStart() override; + void handleEvent(const InputEvent& evt) override; static const char* lastFigmentName(); + const std::vector& commands() const override; + private: const std::vector m_figments; const std::vector m_displays; + + AnimatedNumber m_powerState = 255; + AnimatedNumber m_brightness = 255; + bool m_powerManaged = true; + + uint8_t m_voltage; + uint8_t m_milliamps; + + uint8_t powerScale(uint8_t target, uint32_t totalPower) const; + + void doBrightness(Args& args, Print& print); + void doOn(Args& args, Print& print); + void doOff(Args& args, Print& print); }; diff --git a/src/animations/Power.cpp b/src/animations/Power.cpp deleted file mode 100644 index 349fdd0..0000000 --- a/src/animations/Power.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "./Power.h" -#include "../Static.h" -#include - -void -doBrightness(Args& args, Print& out) -{ - String nextVal = args[1]; - uint8_t newBrightness = (uint8_t)atoi(nextVal.c_str()); - MainLoop::instance()->dispatch(InputEvent{InputEvent::SetBrightness, newBrightness}); -} - -void -doOn(Args& args, Print& out) -{ - MainLoop::instance()->dispatch(InputEvent{InputEvent::SetPower, 255}); -} - -void -doOff(Args& args, Print& out) -{ - MainLoop::instance()->dispatch(InputEvent{InputEvent::SetPower, 0}); -} - -void -doForceBrightness(Args& args, Print& out) -{ - String nextVal = args[1]; - uint8_t newBrightness = (uint8_t)atoi(nextVal.c_str()); - Static::instance()->forceBrightness(newBrightness); -} - -void -Power::handleConfigChange(const Configuration& config) -{ - m_milliamps = config.get("power.milliamps", m_milliamps); - m_voltage = config.get("power.volts", m_voltage); - m_useBPM = config.get("power.useBPM", m_useBPM); - - if (m_voltage == 0 || m_milliamps == 0) { - Log.notice("power: Impossible power config: %dma @ %dv", m_milliamps, m_voltage); - m_valid = false; - } else { - Log.notice("power: Configured to use %dma @ %dv", m_milliamps, m_voltage); - m_valid = true; - FastLED.setMaxPowerInVoltsAndMilliamps(m_voltage, m_milliamps); - } -} - - -STATIC_ALLOC(Power); -STATIC_TASK(Power); diff --git a/src/animations/Power.h b/src/animations/Power.h deleted file mode 100644 index efaa42b..0000000 --- a/src/animations/Power.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once -#include -#include "../Config.h" - -class Power: public Figment, ConfigTaskMixin { -public: - Power() : Figment("Power") {state = Task::Running;} - - void handleEvent(const InputEvent& evt) override { - switch (evt.intent) { - case InputEvent::PowerToggle: - m_powerState = m_powerState.value() <= 128 ? 255 : 0; - m_forced = false; - Log.notice("Power toggled to %t", m_powerState); - break; - case InputEvent::SetPower: - m_powerState = evt.asInt() == 0 ? 0 : 255; - m_forced = false; - Log.notice("Power state is now %t", m_powerState); - break; - case InputEvent::SetBrightness: - m_brightness = evt.asInt(); - m_forced = false; - break; - case InputEvent::Beat: - m_beatDecay.set(0, 255); - break; - default: - ConfigTaskMixin::handleEvent(evt); - } - } - - void handleConfigChange(const Configuration& config) override; - - void loop() override { - ConfigTaskMixin::loop(); - m_powerState.update(); - m_brightness.update(); - EVERY_N_MILLISECONDS(20) { - m_beatDecay.update(13); - } - } - - void render(Display* dpy) const override { - if (F_LIKELY(m_valid && !m_forced)) { - const uint8_t decayedBrightness = scale8((uint8_t)m_brightness, m_useBPM ? ease8InOutCubic((uint8_t)m_beatDecay) : 255); - const uint8_t clippedBrightness = std::min(decayedBrightness, (uint8_t)255); - const uint8_t scaledBrightness = scale8(m_powerState, clippedBrightness); - const uint8_t videoBrightness = brighten8_video(scaledBrightness); - const uint8_t powerBrightness = calculate_max_brightness_for_power_mW(videoBrightness, m_voltage * m_milliamps); - FastLED.setBrightness(powerBrightness); - } - } - - void forceBrightness(uint8_t v); -private: - AnimatedNumber m_powerState = 255; - AnimatedNumber m_brightness = 255; - AnimatedNumber m_beatDecay = 255; - uint8_t m_voltage = 5; - uint16_t m_milliamps = 500; - bool m_valid = true; - bool m_useBPM = false; - bool m_forced = false; -};