Skip to content
Open
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
2 changes: 2 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@ build_flags =
-DSYS_OUT=GPIO_NUM_40
; Battery monitor
-DBATTERY_VOLTAGE_PIN=GPIO_NUM_1
; Status LED
-DSTATUS_LED_PIN=GPIO_NUM_14
87 changes: 87 additions & 0 deletions src/StatusLED.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "StatusLED.h"

#define LEDC_TIMER_8_BIT 8
#define LEDC_BASE_FREQ 5000

StatusLED::StatusLED(int pin, int channel)
: _pin(pin), _channel(channel), _off_ms(0), _fadeIn_ms(0), _on_ms(0), _fadeOut_ms(0), _totalCycle_ms(0), _maxBrightness(255) {
}

void StatusLED::begin() {
if (_pin < 0) return;

// Check if the pin is a valid GPIO
if (!digitalPinIsValid(_pin)) return;

ledcSetup(_channel, LEDC_BASE_FREQ, LEDC_TIMER_8_BIT);
ledcAttachPin(_pin, _channel);
ledcWrite(_channel, 0);
}

void StatusLED::setPattern(int off_ms, int fadeIn_ms, int on_ms, int fadeOut_ms) {
_off_ms = off_ms;
_fadeIn_ms = fadeIn_ms;
_on_ms = on_ms;
_fadeOut_ms = (fadeOut_ms < 0) ? fadeIn_ms : fadeOut_ms;
_totalCycle_ms = _off_ms + _fadeIn_ms + _on_ms + _fadeOut_ms;
_maxBrightness = 255;

if (_totalCycle_ms == 0) {
// If all are zero, it's effectively off, but we need a cycle for update()
_totalCycle_ms = 1;
}
}

void StatusLED::update() {
if (_pin < 0 || _totalCycle_ms <= 0) return;

unsigned long now = millis();
int timeInCycle = now % _totalCycle_ms;
int brightness = 0;

if (timeInCycle < _off_ms) {
// Off phase
brightness = 0;
} else if (timeInCycle < _off_ms + _fadeIn_ms) {
// Fade in phase
int fadeTime = timeInCycle - _off_ms;
brightness = (fadeTime * _maxBrightness) / _fadeIn_ms;
} else if (timeInCycle < _off_ms + _fadeIn_ms + _on_ms) {
// On phase
brightness = _maxBrightness;
} else {
// Fade out phase
int fadeTime = timeInCycle - (_off_ms + _fadeIn_ms + _on_ms);
if (_fadeOut_ms > 0) {
brightness = _maxBrightness - (fadeTime * _maxBrightness) / _fadeOut_ms;
} else {
brightness = 0;
}
}

ledcWrite(_channel, brightness);
}

void StatusLED::off() {
setPattern(1000, 0, 0, 0);
ledcWrite(_channel, 0);
}

void StatusLED::solid(uint8_t brightness) {
// A trick to make it solid: make it all "on" phase
setPattern(0, 0, 1000, 0);
_maxBrightness = brightness;
}

void StatusLED::breathe(int duration) {
int fade = duration / 2;
setPattern(0, fade, 0, fade);
}

void StatusLED::blink(int duration) {
setPattern(duration, 0, duration, 0);
}

void StatusLED::fastBlink(int duration) {
setPattern(duration, 0, duration, 0);
}
40 changes: 40 additions & 0 deletions src/StatusLED.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef STATUS_LED_H
#define STATUS_LED_H

#include <Arduino.h>

class StatusLED {
public:
StatusLED(int pin, int channel = 1);
void begin();
void update();

/**
* Set a breathing/blinking pattern.
* @param off_ms Duration the LED is completely off.
* @param fadeIn_ms Duration of the fade-in (from 0 to 255).
* @param on_ms Duration the LED is completely on at full brightness.
* @param fadeOut_ms Duration of the fade-out (from 255 to 0). If -1, defaults to fadeIn_ms.
*/
void setPattern(int off_ms, int fadeIn_ms, int on_ms, int fadeOut_ms = -1);

void off();
void solid(uint8_t brightness = 255);
void breathe(int duration = 2000);
void blink(int duration = 500);
void fastBlink(int duration = 100);

private:
int _pin;
int _channel;

int _off_ms;
int _fadeIn_ms;
int _on_ms;
int _fadeOut_ms;

int _totalCycle_ms;
uint8_t _maxBrightness;
};

#endif // STATUS_LED_H
21 changes: 21 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "VideoPlayer/StreamVideoSource.h"
#include "VideoPlayer/VideoPlayer.h"
#include "WifiManager.h"
#include "StatusLED.h"
#include <Arduino.h>
#include <ESPAsyncWebServer.h>
#include <Wire.h>
Expand All @@ -33,6 +34,7 @@ Display display(&prefs);
Button button(SYS_OUT, SYS_EN);
AsyncWebServer server(80);
Battery battery(BATTERY_VOLTAGE_PIN, 3.3, 200000.0, 100000.0);
StatusLED statusLED(STATUS_LED_PIN);
unsigned long shutdown_time = 0;
WifiManager wifiManager(&server, &prefs, &battery);
bool wifiManagerActive = false;
Expand Down Expand Up @@ -61,6 +63,8 @@ void setShutdownTime(int minutes)

void setup()
{
statusLED.begin();
statusLED.fastBlink(100);
display.fillScreen(TFT_BLACK);
Serial.begin(115200);
delay(500); // Wait for serial to initialize
Expand Down Expand Up @@ -95,6 +99,11 @@ void setup()
display.flushSprite();
Serial.println("Failed to mount SD Card. Initializing WifiManager.");
wifiManager.begin();
if (wifiManager.isAPMode()) {
statusLED.breathe(2000);
} else {
statusLED.breathe(1000);
}
wifiManagerActive = true;
Serial.printf("Wifi Connected: %s\n",
wifiManager.getIpAddress().toString().c_str());
Expand All @@ -120,6 +129,7 @@ void setup()
Serial.println("SD Card mounted successfully.");
display.drawOSD("SD Card found !", CENTER, STANDARD);
display.flushSprite();
statusLED.blink(500);

VideoSource *videoCandidate = new SDCardVideoSource(card, "/");
if (videoCandidate->fetchVideoData())
Expand Down Expand Up @@ -201,6 +211,7 @@ unsigned long lastBatteryUpdate = 0;

void loop()
{
statusLED.update();
delay(5);

unsigned long now = millis();
Expand All @@ -226,6 +237,16 @@ void loop()
lastBatteryUpdate = now;
}

static MediaPlayerState lastState = MediaPlayerState::STOPPED;
if (currentPlayer && currentPlayer->getState() != lastState) {
lastState = currentPlayer->getState();
if (lastState == MediaPlayerState::PLAYING) {
statusLED.breathe(4000);
} else if (lastState == MediaPlayerState::PAUSED) {
statusLED.solid(64);
}
}

button.update();
if (wifiManagerActive)
{
Expand Down