Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite LED blinking functionality #797

Merged
merged 4 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions library.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
"owner": "bxparks",
"name": "AceButton",
"version": "^1.10.1"
},
{
"owner": "fastled",
"name": "FastLED",
"version": "^3.9.4"
}
],
"version": "3.0.1",
Expand Down
2 changes: 2 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ lib_deps =
bblanchon/ArduinoJson @ ^7.0.0
pfeerick/elapsedMillis @ ^1.0.6
bxparks/AceButton @ ^1.10.1
fastled/FastLED @ ^3.9.4

build_unflags = -Werror=reorder
board_build.partitions = min_spiffs.csv
monitor_filters = esp32_exception_decoder
Expand Down
1 change: 0 additions & 1 deletion src/sensesp/net/networking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <esp_wifi.h>

#include "sensesp/system/lambda_consumer.h"
#include "sensesp/system/led_blinker.h"
#include "sensesp_app.h"

namespace sensesp {
Expand Down
14 changes: 7 additions & 7 deletions src/sensesp/net/web/app_command_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

namespace sensesp {

void add_scan_wifi_networks_handlers(std::shared_ptr<HTTPServer>& server) {
void add_scan_wifi_networks_handlers(std::shared_ptr<HTTPServer>& server,
std::shared_ptr<Networking>& networking) {
auto scan_wifi_networks_handler = std::make_shared<HTTPRequestHandler>(
1 << HTTP_POST, "/api/wifi/scan", [](httpd_req_t* req) {
auto networking = SensESPApp::get()->get_networking();
1 << HTTP_POST, "/api/wifi/scan", [networking](httpd_req_t* req) {
networking->start_wifi_scan();
// Return status code 202 and "SCAN STARTED" message
httpd_resp_set_status(req, "202 Accepted");
Expand All @@ -21,8 +21,7 @@ void add_scan_wifi_networks_handlers(std::shared_ptr<HTTPServer>& server) {
server->add_handler(scan_wifi_networks_handler);

auto scan_results_handler = std::make_shared<HTTPRequestHandler>(
1 << HTTP_GET, "/api/wifi/scan-results", [](httpd_req_t* req) {
auto networking = SensESPApp::get()->get_networking();
1 << HTTP_GET, "/api/wifi/scan-results", [networking](httpd_req_t* req) {
std::vector<WiFiNetworkInfo> ssid_list;
int16_t result = networking->get_wifi_scan_results(ssid_list);
if (result == WIFI_SCAN_RUNNING) {
Expand Down Expand Up @@ -53,8 +52,9 @@ void add_scan_wifi_networks_handlers(std::shared_ptr<HTTPServer>& server) {
server->add_handler(scan_results_handler);
}

void add_app_http_command_handlers(std::shared_ptr<HTTPServer>& server) {
add_scan_wifi_networks_handlers(server);
void add_app_http_command_handlers(std::shared_ptr<HTTPServer>& server,
std::shared_ptr<Networking>& networking) {
add_scan_wifi_networks_handlers(server, networking);
}

} // namespace sensesp
4 changes: 3 additions & 1 deletion src/sensesp/net/web/app_command_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

#include "ArduinoJson.h"
#include "sensesp/net/http_server.h"
#include "sensesp/net/networking.h"

namespace sensesp {

void add_app_http_command_handlers(std::shared_ptr<HTTPServer>& server);
void add_app_http_command_handlers(std::shared_ptr<HTTPServer>& server,
std::shared_ptr<Networking>& networking);

} // namespace sensesp

Expand Down
181 changes: 45 additions & 136 deletions src/sensesp/system/led_blinker.cpp
Original file line number Diff line number Diff line change
@@ -1,154 +1,63 @@

#include "sensesp.h"

#include "led_blinker.h"

#include "sensesp_app.h"

namespace sensesp {

#define max(a, b) ((a) > (b) ? (a) : (b))

BaseBlinker::BaseBlinker(int pin) : pin_{pin} {
pinMode(pin, OUTPUT);
event_loop()->onDelay(1, [this]() { this->tick(); });
}
LEDPatternFragment frag_solid_color(uint32_t duration_ms, const CRGB& color) {
return LEDPatternFragment(duration_ms,
[color](uint32_t, CRGB& crgb) { crgb = color; });
}

LEDPatternFragment frag_linear_fade(uint32_t duration_ms,
uint32_t fade_duration_ms,
const CRGB& target_color) {
LEDPatternFragment fragment(duration_ms, [target_color, fade_duration_ms](
uint32_t elapsed_ms,
CRGB& crgb) {
static CRGB from_color;
static unsigned long last_elapsed_ms = 0;
if (elapsed_ms < last_elapsed_ms) {
from_color = crgb;
}
last_elapsed_ms = elapsed_ms;
if (elapsed_ms >= fade_duration_ms) {
crgb = target_color;
return;
}
crgb = blend(from_color, target_color, elapsed_ms * 256 / fade_duration_ms);
});

/**
* Turn the LED on or off.
*/
void BaseBlinker::set_state(bool state) {
this->state_ = state;
digitalWrite(pin_, state);
update_counter_++;
return fragment;
}

/**
* Invert the current LED state.
*/
void BaseBlinker::flip_state() { this->set_state(!this->state_); }

/**
* Flip the LED off and on for `duration` milliseconds.
*/
void BaseBlinker::blip(int duration) {
// indicator for a blip being in progress
static bool blipping = false;

// only allow one blip at a time
if (blipping) {
return;
}
blipping = true;

bool const orig_state = this->state_;
this->set_state(false);
int const current_counter = this->update_counter_;
event_loop()->onDelay(
duration, [this, duration, orig_state, current_counter]() {
// only update if no-one has touched the LED in the meanwhile
if (this->update_counter_ == current_counter) {
this->set_state(true);
int const new_counter = this->update_counter_;
event_loop()->onDelay(
duration, [this, orig_state, new_counter]() {
// again, only update if no-one has touched the LED
if (this->update_counter_ == new_counter) {
this->set_state(orig_state);
}
blipping = false;
});
LEDPatternFragment frag_linear_invert(uint32_t duration_ms, bool reverse) {
return LEDPatternFragment(
duration_ms, [duration_ms, reverse](uint32_t elapsed_ms, CRGB& crgb) {
// Blend the color from current color to inverted
if (reverse) {
crgb = blend(CRGB(255, 255, 255) - crgb, crgb,
elapsed_ms * 256 / duration_ms);
} else {
blipping = false;
crgb = blend(crgb, CRGB(255, 255, 255) - crgb,
elapsed_ms * 256 / duration_ms);
}
});
}

/**
* Enable or disable the blinker.
*/
void BaseBlinker::set_enabled(bool state) {
bool const was_enabled = this->enabled_;
this->enabled_ = state;
if (this->enabled_) {
this->tick();
} else {
this->set_state(false);
if (was_enabled) {
event_->remove(event_loop());
LEDPatternFragment frag_blend(uint32_t duration_ms, const CRGB& target_color,
bool reverse) {
return LEDPatternFragment(duration_ms, [duration_ms, reverse, target_color](
uint32_t elapsed_ms, CRGB& crgb) {
if (reverse) {
crgb = blend(target_color, crgb, elapsed_ms * 255 / duration_ms);
} else {
crgb = blend(crgb, target_color, elapsed_ms * 255 / duration_ms);
}
}
}

PeriodicBlinker::PeriodicBlinker(int pin, unsigned int period)
: BaseBlinker(pin), period_{period} {}

EvenBlinker::EvenBlinker(int pin, unsigned int period)
: PeriodicBlinker(pin, period) {}

void EvenBlinker::tick() {
if (!enabled_) {
return;
}
this->flip_state();
event_ = event_loop()->onDelay(
period_, [this]() { this->tick(); });
}

RatioBlinker::RatioBlinker(int pin, unsigned int period, float ratio)
: PeriodicBlinker(pin, period), ratio_{ratio} {}

void RatioBlinker::tick() {
if (!enabled_) {
return;
}
this->flip_state();
int const on_duration = ratio_ * period_;
int const off_duration = max(0, period_ - on_duration);
unsigned int const ref_duration =
state_ == false ? off_duration : on_duration;
event_ = event_loop()->onDelay(
ref_duration, [this]() { this->tick(); });
}

PatternBlinker::PatternBlinker(int pin, int pattern[])
: BaseBlinker(pin), pattern_{pattern} {}

/**
* Set a new blink pattern. Patterns are arrays of ints, with
* PATTERN_END as the last value. Each number in the pattern indicates
* the length of that segment, in milliseconds. The first number indicates
* an ON duration, the second an OFF duration, and so on.
*/
void PatternBlinker::set_pattern(int pattern[]) {
this->pattern_ = pattern;
this->restart();
}

void PatternBlinker::tick() {
if (!enabled_) {
return;
}
// When pattern[pattern_ptr] == PATTERN_END, that's the end of the pattern,
// so start over at the beginning.
if (pattern_[pattern_ptr_] == PATTERN_END) {
pattern_ptr_ = 0;
}
// odd indices indicate times when LED should be OFF, even when ON
bool const new_state = (pattern_ptr_ % 2) == 0;
this->set_state(new_state);
event_ = event_loop()->onDelay(
pattern_[pattern_ptr_++], [this]() { this->tick(); });
});
}

void PatternBlinker::restart() {
state_ = false;
pattern_ptr_ = 0;
if (event_ != NULL) {
event_->remove(event_loop());
event_ = NULL;
this->tick();
}
LEDPatternFragment frag_nop(uint32_t duration_ms) {
// No operation
return LEDPatternFragment(duration_ms, [](uint32_t, CRGB&) {});
}

} // namespace sensesp
Loading
Loading