Version fonctionnelle 1.0
This commit is contained in:
8
DCC-Bench.code-workspace
Normal file
8
DCC-Bench.code-workspace
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
70
get-platformio.py
Normal file
70
get-platformio.py
Normal file
File diff suppressed because one or more lines are too long
@@ -14,24 +14,24 @@
|
||||
#define LED_INDICATOR_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <FastLED.h>
|
||||
// #include <FastLED.h>
|
||||
|
||||
// Pin definition for WS2812 LEDs
|
||||
#define LED_DATA_PIN 4 ///< Data pin for WS2812 strip
|
||||
#define NUM_LEDS 2 ///< Number of LEDs (Power + Mode)
|
||||
#define NUM_LEDS 4 ///< Number of LEDs (Power + Mode)
|
||||
|
||||
// LED indices
|
||||
// // LED indices
|
||||
#define LED_POWER 0 ///< Power status indicator
|
||||
#define LED_MODE 1 ///< Mode indicator (DCC/Analog)
|
||||
|
||||
/**
|
||||
* @class LEDIndicator
|
||||
* @brief Manages WS2812 RGB LED status displays
|
||||
*
|
||||
* Controls two LEDs for system status indication:
|
||||
* - Power LED: Shows system power state with boot animation
|
||||
* - Mode LED: Shows control mode with pulsing effect
|
||||
*/
|
||||
// /**
|
||||
// * @class LEDIndicator
|
||||
// * @brief Manages WS2812 RGB LED status displays
|
||||
// *
|
||||
// * Controls two LEDs for system status indication:
|
||||
// * - Power LED: Shows system power state with boot animation
|
||||
// * - Mode LED: Shows control mode with pulsing effect
|
||||
// */
|
||||
class LEDIndicator {
|
||||
public:
|
||||
/**
|
||||
@@ -86,20 +86,20 @@ public:
|
||||
*/
|
||||
void modeChangeEffect();
|
||||
|
||||
private:
|
||||
CRGB leds[NUM_LEDS]; ///< LED array
|
||||
bool powerOn; ///< Power status flag
|
||||
bool dccMode; ///< Mode flag (DCC/Analog)
|
||||
uint8_t brightness; ///< Current brightness level
|
||||
unsigned long lastUpdate; ///< Last update timestamp
|
||||
uint8_t pulsePhase; ///< Pulse animation phase
|
||||
// private:
|
||||
// CRGB leds[NUM_LEDS]; ///< LED array
|
||||
// bool powerOn; ///< Power status flag
|
||||
// bool dccMode; ///< Mode flag (DCC/Analog)
|
||||
// uint8_t brightness; ///< Current brightness level
|
||||
// unsigned long lastUpdate; ///< Last update timestamp
|
||||
// uint8_t pulsePhase; ///< Pulse animation phase
|
||||
|
||||
// LED color definitions
|
||||
static constexpr CRGB COLOR_POWER_ON = CRGB::Green; ///< Power ON color
|
||||
static constexpr CRGB COLOR_POWER_OFF = CRGB::Red; ///< Power OFF color
|
||||
static constexpr CRGB COLOR_DCC = CRGB::Blue; ///< DCC mode color
|
||||
static constexpr CRGB COLOR_ANALOG = CRGB::Yellow; ///< Analog mode color
|
||||
static constexpr CRGB COLOR_OFF = CRGB::Black; ///< LED off state
|
||||
// // LED color definitions
|
||||
// static constexpr CRGB COLOR_POWER_ON = CRGB::Green; ///< Power ON color
|
||||
// static constexpr CRGB COLOR_POWER_OFF = CRGB::Red; ///< Power OFF color
|
||||
// static constexpr CRGB COLOR_DCC = CRGB::Blue; ///< DCC mode color
|
||||
// static constexpr CRGB COLOR_ANALOG = CRGB::Yellow; ///< Analog mode color
|
||||
// static constexpr CRGB COLOR_OFF = CRGB::Black; ///< LED off state
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <DNSServer.h>
|
||||
#include "Config.h"
|
||||
#include "MotorController.h"
|
||||
#include "DCCGenerator.h"
|
||||
@@ -70,6 +71,7 @@ private:
|
||||
DCCGenerator* dccGenerator; ///< DCC generator instance
|
||||
LEDIndicator* ledIndicator; ///< LED indicator instance
|
||||
AsyncWebServer server; ///< Async web server (port 80)
|
||||
DNSServer dnsServer; ///< DNS server for captive portal
|
||||
|
||||
/**
|
||||
* @brief Set up all HTTP routes and handlers
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:wemos_d1_mini32]
|
||||
;[env:wemos_d1_mini32]
|
||||
[env:esp32doit-devkit-v1]
|
||||
platform = espressif32
|
||||
board = wemos_d1_mini32
|
||||
; board = wemos_d1_mini32
|
||||
board = esp32doit-devkit-v1
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
upload_speed = 921600
|
||||
@@ -23,5 +25,5 @@ lib_deps =
|
||||
esp32async/ESPAsyncWebServer @ ^3.9.2
|
||||
esp32async/AsyncTCP @ ^3.4.9
|
||||
https://github.com/Locoduino/DCCpp
|
||||
fastled/FastLED@^3.6.0
|
||||
; fastled/FastLED@^3.6.0
|
||||
board_build.filesystem = littlefs
|
||||
|
||||
@@ -18,7 +18,7 @@ Config::Config() {
|
||||
wifi.password = "";
|
||||
wifi.isAPMode = true;
|
||||
wifi.apSSID = "LocoTestBench";
|
||||
wifi.apPassword = "12345678";
|
||||
wifi.apPassword = "123456789";
|
||||
|
||||
system.isDCCMode = false;
|
||||
system.dccAddress = 3;
|
||||
|
||||
@@ -8,107 +8,108 @@
|
||||
/**
|
||||
* @brief Constructor - initialize with default state
|
||||
*/
|
||||
LEDIndicator::LEDIndicator() :
|
||||
powerOn(false),
|
||||
dccMode(false),
|
||||
brightness(128),
|
||||
lastUpdate(0),
|
||||
pulsePhase(0) {
|
||||
}
|
||||
// LEDIndicator::LEDIndicator() :
|
||||
// powerOn(false),
|
||||
// dccMode(false),
|
||||
// brightness(128),
|
||||
// lastUpdate(0),
|
||||
// pulsePhase(0)
|
||||
// {}
|
||||
LEDIndicator::LEDIndicator(){}
|
||||
|
||||
void LEDIndicator::begin() {
|
||||
FastLED.addLeds<WS2812, LED_DATA_PIN, GRB>(leds, NUM_LEDS);
|
||||
FastLED.setBrightness(brightness);
|
||||
// FastLED.addLeds<WS2812, LED_DATA_PIN, GRB>(leds, NUM_LEDS);
|
||||
// FastLED.setBrightness(brightness);
|
||||
|
||||
// Initialize both LEDs to off
|
||||
leds[LED_POWER] = COLOR_OFF;
|
||||
leds[LED_MODE] = COLOR_OFF;
|
||||
FastLED.show();
|
||||
// leds[LED_POWER] = COLOR_OFF;
|
||||
// leds[LED_MODE] = COLOR_OFF;
|
||||
// FastLED.show();
|
||||
|
||||
Serial.println("LED Indicator initialized");
|
||||
Serial.printf("LED Data Pin: %d, Num LEDs: %d\n", LED_DATA_PIN, NUM_LEDS);
|
||||
// Serial.println("LED Indicator initialized");
|
||||
// Serial.printf("LED Data Pin: %d, Num LEDs: %d\n", LED_DATA_PIN, NUM_LEDS);
|
||||
}
|
||||
|
||||
void LEDIndicator::update() {
|
||||
unsigned long now = millis();
|
||||
// unsigned long now = millis();
|
||||
|
||||
// Update power LED
|
||||
if (powerOn) {
|
||||
leds[LED_POWER] = COLOR_POWER_ON;
|
||||
} else {
|
||||
leds[LED_POWER] = COLOR_POWER_OFF;
|
||||
}
|
||||
// // Update power LED
|
||||
// if (powerOn) {
|
||||
// leds[LED_POWER] = COLOR_POWER_ON;
|
||||
// } else {
|
||||
// leds[LED_POWER] = COLOR_POWER_OFF;
|
||||
// }
|
||||
|
||||
// Update mode LED with subtle pulsing effect
|
||||
if (now - lastUpdate > 20) {
|
||||
lastUpdate = now;
|
||||
pulsePhase++;
|
||||
// if (now - lastUpdate > 20) {
|
||||
// lastUpdate = now;
|
||||
// pulsePhase++;
|
||||
|
||||
// Create gentle pulse effect
|
||||
uint8_t pulseBrightness = 128 + (sin8(pulsePhase * 2) / 4);
|
||||
// // Create gentle pulse effect
|
||||
// uint8_t pulseBrightness = 128 + (sin8(pulsePhase * 2) / 4);
|
||||
|
||||
CRGB baseColor = dccMode ? COLOR_DCC : COLOR_ANALOG;
|
||||
leds[LED_MODE] = baseColor;
|
||||
leds[LED_MODE].fadeToBlackBy(255 - pulseBrightness);
|
||||
}
|
||||
// CRGB baseColor = dccMode ? COLOR_DCC : COLOR_ANALOG;
|
||||
// leds[LED_MODE] = baseColor;
|
||||
// leds[LED_MODE].fadeToBlackBy(255 - pulseBrightness);
|
||||
// }
|
||||
|
||||
FastLED.show();
|
||||
// FastLED.show();
|
||||
}
|
||||
|
||||
void LEDIndicator::setPowerOn(bool on) {
|
||||
if (powerOn != on) {
|
||||
powerOn = on;
|
||||
if (on) {
|
||||
powerOnSequence();
|
||||
}
|
||||
}
|
||||
// if (powerOn != on) {
|
||||
// powerOn = on;
|
||||
// if (on) {
|
||||
// powerOnSequence();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void LEDIndicator::setMode(bool isDCC) {
|
||||
if (dccMode != isDCC) {
|
||||
dccMode = isDCC;
|
||||
modeChangeEffect();
|
||||
}
|
||||
// if (dccMode != isDCC) {
|
||||
// dccMode = isDCC;
|
||||
// modeChangeEffect();
|
||||
// }
|
||||
}
|
||||
|
||||
void LEDIndicator::setBrightness(uint8_t newBrightness) {
|
||||
brightness = newBrightness;
|
||||
FastLED.setBrightness(brightness);
|
||||
// brightness = newBrightness;
|
||||
// FastLED.setBrightness(brightness);
|
||||
}
|
||||
|
||||
void LEDIndicator::powerOnSequence() {
|
||||
// Quick flash sequence on power on
|
||||
for (int i = 0; i < 3; i++) {
|
||||
leds[LED_POWER] = COLOR_POWER_ON;
|
||||
FastLED.show();
|
||||
delay(100);
|
||||
leds[LED_POWER] = COLOR_OFF;
|
||||
FastLED.show();
|
||||
delay(100);
|
||||
}
|
||||
leds[LED_POWER] = COLOR_POWER_ON;
|
||||
FastLED.show();
|
||||
Serial.println("LED: Power ON sequence");
|
||||
// // Quick flash sequence on power on
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
// leds[LED_POWER] = COLOR_POWER_ON;
|
||||
// FastLED.show();
|
||||
// delay(100);
|
||||
// leds[LED_POWER] = COLOR_OFF;
|
||||
// FastLED.show();
|
||||
// delay(100);
|
||||
// }
|
||||
// leds[LED_POWER] = COLOR_POWER_ON;
|
||||
// FastLED.show();
|
||||
// Serial.println("LED: Power ON sequence");
|
||||
}
|
||||
|
||||
void LEDIndicator::modeChangeEffect() {
|
||||
// Smooth transition effect when changing modes
|
||||
CRGB targetColor = dccMode ? COLOR_DCC : COLOR_ANALOG;
|
||||
// // Smooth transition effect when changing modes
|
||||
// CRGB targetColor = dccMode ? COLOR_DCC : COLOR_ANALOG;
|
||||
|
||||
// Fade out
|
||||
for (int i = 255; i >= 0; i -= 15) {
|
||||
leds[LED_MODE].fadeToBlackBy(15);
|
||||
FastLED.show();
|
||||
delay(10);
|
||||
}
|
||||
// // Fade out
|
||||
// for (int i = 255; i >= 0; i -= 15) {
|
||||
// leds[LED_MODE].fadeToBlackBy(15);
|
||||
// FastLED.show();
|
||||
// delay(10);
|
||||
// }
|
||||
|
||||
// Fade in new color
|
||||
for (int i = 0; i <= 255; i += 15) {
|
||||
leds[LED_MODE] = targetColor;
|
||||
leds[LED_MODE].fadeToBlackBy(255 - i);
|
||||
FastLED.show();
|
||||
delay(10);
|
||||
}
|
||||
// // Fade in new color
|
||||
// for (int i = 0; i <= 255; i += 15) {
|
||||
// leds[LED_MODE] = targetColor;
|
||||
// leds[LED_MODE].fadeToBlackBy(255 - i);
|
||||
// FastLED.show();
|
||||
// delay(10);
|
||||
// }
|
||||
|
||||
Serial.printf("LED: Mode changed to %s\n", dccMode ? "DCC (Blue)" : "Analog (Yellow)");
|
||||
// Serial.printf("LED: Mode changed to %s\n", dccMode ? "DCC (Blue)" : "Analog (Yellow)");
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "WebServer.h"
|
||||
#include <LittleFS.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
@@ -14,19 +15,70 @@ WebServerManager::WebServerManager(Config* cfg, MotorController* motor, DCCGener
|
||||
}
|
||||
|
||||
void WebServerManager::begin() {
|
||||
Serial.println("Initializing web server...");
|
||||
|
||||
// Initialize LittleFS
|
||||
if (!LittleFS.begin(true)) {
|
||||
Serial.println("LittleFS Mount Failed");
|
||||
return;
|
||||
Serial.println("ERROR: LittleFS Mount Failed!");
|
||||
Serial.println("Did you upload the filesystem? Run: pio run -t uploadfs");
|
||||
} else {
|
||||
Serial.println("✓ LittleFS mounted successfully");
|
||||
|
||||
// List files for debugging
|
||||
File root = LittleFS.open("/");
|
||||
if (root) {
|
||||
Serial.println("Files in LittleFS:");
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
Serial.print(" - ");
|
||||
Serial.print(file.name());
|
||||
Serial.print(" (");
|
||||
Serial.print(file.size());
|
||||
Serial.println(" bytes)");
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
Serial.println("LittleFS mounted successfully");
|
||||
|
||||
setupRoutes();
|
||||
|
||||
// Start DNS server for captive portal (redirect all domains to ESP32)
|
||||
dnsServer.start(53, "*", WiFi.softAPIP());
|
||||
Serial.println("✓ DNS server started for captive portal");
|
||||
|
||||
server.begin();
|
||||
Serial.println("Web server started on port 80");
|
||||
Serial.println("✓ Web server started on port 80");
|
||||
Serial.print("✓ Access at: http://");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
Serial.println("✓ Captive portal enabled - phones will auto-redirect");
|
||||
}
|
||||
|
||||
void WebServerManager::setupRoutes() {
|
||||
// Android captive portal detection
|
||||
server.on("/generate_204", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
request->redirect("http://" + WiFi.softAPIP().toString());
|
||||
});
|
||||
|
||||
// iOS/macOS captive portal detection
|
||||
server.on("/hotspot-detect.html", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
request->redirect("http://" + WiFi.softAPIP().toString());
|
||||
});
|
||||
|
||||
// Windows captive portal detection
|
||||
server.on("/connecttest.txt", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
request->send(200, "text/plain", "Microsoft Connect Test");
|
||||
});
|
||||
|
||||
// Firefox captive portal detection
|
||||
server.on("/canonical.html", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
request->send(200, "text/html", "<html><head><meta http-equiv='refresh' content='0;url=http://" + WiFi.softAPIP().toString() + "'></head></html>");
|
||||
});
|
||||
|
||||
// Success page that prevents disconnection
|
||||
server.on("/success.txt", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
request->send(200, "text/plain", "success");
|
||||
});
|
||||
|
||||
// Serve main page
|
||||
server.on("/", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
request->send(LittleFS, "/index.html", "text/html");
|
||||
@@ -36,13 +88,25 @@ void WebServerManager::setupRoutes() {
|
||||
server.serveStatic("/css/", LittleFS, "/css/");
|
||||
server.serveStatic("/js/", LittleFS, "/js/");
|
||||
|
||||
// Captive portal - redirect any unknown domain to our interface
|
||||
server.onNotFound([this](AsyncWebServerRequest *request) {
|
||||
// Check if request is for API or static files
|
||||
String path = request->url();
|
||||
if (path.startsWith("/api/") || path.startsWith("/css/") || path.startsWith("/js/")) {
|
||||
request->send(404);
|
||||
} else {
|
||||
// Redirect to main page for captive portal
|
||||
request->send(LittleFS, "/index.html", "text/html");
|
||||
}
|
||||
});
|
||||
|
||||
// API endpoints
|
||||
server.on("/api/status", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
handleGetStatus(request);
|
||||
});
|
||||
|
||||
server.on("/api/mode", HTTP_POST, [this](AsyncWebServerRequest *request) {
|
||||
handleSetMode(request);
|
||||
// handleSetMode(request);
|
||||
}, NULL, [this](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
|
||||
// Body handler
|
||||
DynamicJsonDocument doc(256);
|
||||
@@ -154,5 +218,6 @@ String WebServerManager::getStatusJSON() {
|
||||
}
|
||||
|
||||
void WebServerManager::update() {
|
||||
// AsyncWebServer handles requests asynchronously
|
||||
// Process DNS requests for captive portal
|
||||
dnsServer.processNextRequest();
|
||||
}
|
||||
|
||||
35
src/main.cpp
35
src/main.cpp
@@ -59,9 +59,9 @@ void setup() {
|
||||
// Initialize WiFi
|
||||
wifiManager.begin();
|
||||
|
||||
// Initialize LED indicator
|
||||
ledIndicator.begin();
|
||||
ledIndicator.setPowerOn(true);
|
||||
// Initialize LED indicator TODO
|
||||
//ledIndicator.begin();
|
||||
//ledIndicator.setPowerOn(true);
|
||||
|
||||
// Initialize motor controller
|
||||
motorController.begin();
|
||||
@@ -72,40 +72,37 @@ void setup() {
|
||||
// Set initial mode and LED
|
||||
if (config.system.isDCCMode) {
|
||||
dccGenerator.enable();
|
||||
ledIndicator.setMode(true);
|
||||
// ledIndicator.setMode(true);
|
||||
dccGenerator.setLocoSpeed(
|
||||
config.system.dccAddress,
|
||||
config.system.speed,
|
||||
config.system.direction
|
||||
);
|
||||
} else {
|
||||
ledIndicator.setMode(false);
|
||||
// ledIndicator.setMode(false);
|
||||
motorController.setSpeed(
|
||||
config.system.speed,
|
||||
config.system.direction
|
||||
);
|
||||
Serial.println("=================================\\n");
|
||||
}
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Main loop - runs continuously
|
||||
*
|
||||
* Updates all system components:
|
||||
* - WiFi connection monitoring
|
||||
* - LED status display
|
||||
* - DCC signal generation (if enabled)
|
||||
* - Motor control updates (if in analog mode)
|
||||
*
|
||||
* @note Small delay prevents watchdog timer issues
|
||||
*/
|
||||
// void loop() {
|
||||
// Start web server BEFORE final status
|
||||
Serial.println("\nStarting web server...");
|
||||
webServer.begin();
|
||||
|
||||
// Update WiFi connection status
|
||||
Serial.println("\n=================================");
|
||||
Serial.println("Setup complete!");
|
||||
Serial.println("=================================");
|
||||
Serial.print("Mode: ");
|
||||
Serial.println(config.system.isDCCMode ? "DCC" : "DC Analog");
|
||||
Serial.print("WiFi Mode: ");
|
||||
Serial.println(config.wifi.isAPMode ? "Access Point" : "Client");
|
||||
Serial.print("SSID: ");
|
||||
Serial.println(config.wifi.isAPMode ? config.wifi.apSSID : config.wifi.ssid);
|
||||
Serial.print("IP Address: ");
|
||||
Serial.println(wifiManager.getIPAddress());
|
||||
Serial.print("Web interface: http://");
|
||||
Serial.println(wifiManager.getIPAddress());
|
||||
Serial.println("=================================\n");
|
||||
@@ -116,7 +113,7 @@ void loop() {
|
||||
wifiManager.update();
|
||||
|
||||
// Update LED indicators
|
||||
ledIndicator.update();
|
||||
//ledIndicator.update();
|
||||
|
||||
// Update DCC signal generation (if enabled)
|
||||
if (config.system.isDCCMode) {
|
||||
|
||||
Reference in New Issue
Block a user