Skip to content

Commit

Permalink
Merge pull request #797 from SignalK/rgb_led
Browse files Browse the repository at this point in the history
Rewrite LED blinking functionality
  • Loading branch information
mairas authored Dec 13, 2024
2 parents b9c6985 + 42b8c79 commit 97e95b1
Show file tree
Hide file tree
Showing 12 changed files with 470 additions and 316 deletions.
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

0 comments on commit 97e95b1

Please sign in to comment.