LogLevel Fix and ramp range fix

This commit is contained in:
admin 2025-10-04 01:56:01 -07:00
parent 660fa5f1c7
commit 3cf3c72f31
30 changed files with 591 additions and 572 deletions

View File

@ -58,10 +58,10 @@
[ [
{ {
"en": true, "en": true,
"relay-index": 0, "relay-index": 1,
"button-index": 0, "button-index": 0,
"min": 1.0, "min": 1.0,
"max": 100.0, "max": 90.0,
"step": 1.5, "step": 1.5,
"rate": 30.0, "rate": 30.0,
"skip-count": 5, "skip-count": 5,
@ -69,10 +69,10 @@
}, },
{ {
"en": true, "en": true,
"relay-index": 1, "relay-index": 2,
"button-index": 1, "button-index": 1,
"min": 1.0, "min": 1.0,
"max": 100.0, "max": 90.0,
"step": 1.5, "step": 1.5,
"rate": 30.0, "rate": 30.0,
"skip-count": 5, "skip-count": 5,
@ -134,9 +134,24 @@
"tx433": { "tx433": {
"en": "true" "en": "true"
}, },
"ble":{ "fire-animation": {
"en": true, "speed": 60,
"name": "Ata_Lights", "cooling": 66,
"core": 1 "sparking": 62,
"brightness": 240
},
"comets-animation": {
"speed": 80,
"size-factor": 0.2,
"count": 3,
"cycles": 2,
"min-fade": 16,
"max-fade": 192
},
"snakes-animation": {
"speed": 80,
"cycles": 2,
"multiplier": 6
} }
} }

View File

@ -130,10 +130,5 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -60,7 +60,7 @@
"relay-index": 0, "relay-index": 0,
"button-index": 0, "button-index": 0,
"min": 1.0, "min": 1.0,
"max": 100.0, "max": 90.0,
"step": 1.5, "step": 1.5,
"rate": 30.0, "rate": 30.0,
"skip-count": 5, "skip-count": 5,
@ -71,7 +71,7 @@
"relay-index": 1, "relay-index": 1,
"button-index": 1, "button-index": 1,
"min": 1.0, "min": 1.0,
"max": 100.0, "max": 90.0,
"step": 1.5, "step": 1.5,
"rate": 30.0, "rate": 30.0,
"skip-count": 5, "skip-count": 5,
@ -132,10 +132,5 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -135,10 +135,5 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -129,10 +129,5 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -130,10 +130,5 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -61,7 +61,7 @@
"relay-index": 0, "relay-index": 0,
"button-index": 0, "button-index": 0,
"min": 1.0, "min": 1.0,
"max": 100.0, "max": 90.0,
"step": 1.5, "step": 1.5,
"rate": 30.0, "rate": 30.0,
"skip-count": 5, "skip-count": 5,
@ -72,7 +72,7 @@
"relay-index": 1, "relay-index": 1,
"button-index": 1, "button-index": 1,
"min": 1.0, "min": 1.0,
"max": 100.0, "max": 90.0,
"step": 1.5, "step": 1.5,
"rate": 30.0, "rate": 30.0,
"skip-count": 5, "skip-count": 5,
@ -131,10 +131,5 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -130,10 +130,5 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -130,10 +130,5 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -131,11 +131,6 @@
}, },
"tx433": { "tx433": {
"en": "true" "en": "true"
},
"ble":{
"en": true,
"name": "FlashStik",
"core": 1
} }
} }

View File

@ -129,10 +129,5 @@
}, },
"tx433": { "tx433": {
"en": false "en": false
},
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
} }
} }

View File

@ -131,25 +131,6 @@
"tx433": { "tx433": {
"en": "true" "en": "true"
}, },
"ble":{
"en": true,
"name": "Ata_Lights",
"core": 1
},
"wifi-client":{
"en": true,
"mdns-name": "atadev",
"ssid": "padillaguest",
"pass": "padillaguest"
},
"wifi-ap":{
"ssid": "ATA_AP",
"append-id": true,
"pass": "12345678",
"ip": [192,168,10.1],
"gateway": [192,168,10,200],
"subnet": [255,255,255,0]
},
"animation1":{ "animation1":{
"white-max-time": 30, "white-max-time": 30,
"white-min": 20, "white-min": 20,

View File

@ -4,7 +4,7 @@
<title>Edit file</title> <title>Edit file</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/global-style.css" rel="stylesheet"> <!--<link href="/css/global-style.css" rel="stylesheet">-->
<link href="/css/nav.css" rel="stylesheet"> <link href="/css/nav.css" rel="stylesheet">
<style> <style>
@ -168,7 +168,7 @@
<!-- Stretchy editor space --> <!-- Stretchy editor space -->
<div class="editor-area"> <div class="editor-area">
<textarea name="edit-textarea" id="edit-textarea" wrap="off" placeholder="File contents will appear here..."></textarea> <textarea name="edit-textarea" id="edit-textarea" wrap="off" placeholder="File contents is empty..."></textarea>
</div> </div>
</form> </form>
</div> </div>

View File

@ -5,7 +5,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/global-style.css" rel="stylesheet"> <link href="/css/global-style.css" rel="stylesheet">
<link href="/css/nav.css" rel="stylesheet"> <link href="css/nav.css" rel="stylesheet">
<style> <style>
#file-row:nth-child(odd) { #file-row:nth-child(odd) {

View File

@ -4,7 +4,7 @@
<title>File Manager</title> <title>File Manager</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/global-style.css" rel="stylesheet"> <!--<link href="/css/global-style.css" rel="stylesheet">-->
<link href="/css/nav.css" rel="stylesheet"> <link href="/css/nav.css" rel="stylesheet">
<style> <style>

View File

@ -66,6 +66,7 @@
"cinttypes": "cpp", "cinttypes": "cpp",
"typeinfo": "cpp" "typeinfo": "cpp"
}, },
"liveServer.settings.multiRootWorkspaceName": "esp32s3_atabooth_8mb" "liveServer.settings.multiRootWorkspaceName": "esp32s3_atabooth_8mb",
"liveServer.settings.port": 5501
} }
} }

View File

@ -16,8 +16,38 @@
#define CYCLES_PER_DIRECTION 2 #define CYCLES_PER_DIRECTION 2
void Animation_Init(void); #define FIRE_COOLING 55
#define FIRE_SPARKING 120
#define FIRE_brightness 240
struct ANIM_FIRE {
int speed;
uint8_t cooling = FIRE_COOLING; // How much does the fire cool as it rises. Less cooling = taller flames. Default 55, suggested range 20-100
uint8_t sparking = FIRE_SPARKING; // What chance (out of 255) is there that a new spark will be lit. Higher chance = more roaring fire. Default 120, suggested range 50-200
uint8_t brightness = FIRE_brightness; // Overall brightness of the fire effect. Default 240, suggested range 50-255
};
extern ANIM_FIRE fireSettings;
struct ANIM_COMET {
int speed;
int minFade;
int maxFade;
float sizeFactor;
int cycles;
int count;
};
extern ANIM_COMET cometSettings;
struct ANIM_SNAKES{
int speed;
int cycles;
int multiplier;
};
extern ANIM_SNAKES snakeSettings;
void Animation_Init(void);
void Animation_Loop(bool volatile& loop_active_flag, int speed, std::function<int()> callback); void Animation_Loop(bool volatile& loop_active_flag, int speed, std::function<int()> callback);
void Animation_Loop_Limited(bool volatile& loop_active_flag, int speed, TickType_t duration, std::function<int()> callback); void Animation_Loop_Limited(bool volatile& loop_active_flag, int speed, TickType_t duration, std::function<int()> callback);
void Animation_Loop_Cycles(bool volatile& loop_active_flag, int speed, uint32_t loop_cycles, std::function<int()> callback); void Animation_Loop_Cycles(bool volatile& loop_active_flag, int speed, uint32_t loop_cycles, std::function<int()> callback);
@ -36,7 +66,7 @@ void Anim_Comets(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PA
//void Anim_Comet_Rainbow(bool volatile& activeFlag, CRGB* leds, int size, int speed); //void Anim_Comet_Rainbow(bool volatile& activeFlag, CRGB* leds, int size, int speed);
void Anim_TimedFill(bool volatile& activeFlag, CRGB* leds, int size, CRGB col1, CRGB col2, int totalDurationMs, int shift); void Anim_TimedFill(bool volatile& activeFlag, CRGB* leds, int size, CRGB col1, CRGB col2, int totalDurationMs, int shift);
void Anim_TimedFill_Flash(bool volatile& activeFlag, CRGB* leds, int size, PWM_Output* pwmOut, PWM_OUT_SETTINGS* pwmSettings, int pwmOutDelay, int flashTimeout, CRGB baseCol, CRGB fillCol, int totalDurationMs, int shift = 0); void Anim_TimedFill_Flash(bool volatile& activeFlag, CRGB* leds, int size, PWM_Output* pwmOut, RAMP_LIGHT_SETTINGS* pwmSettings, int pwmOutDelay, int flashTimeout, CRGB baseCol, CRGB fillCol, int totalDurationMs, int shift = 0);
void Anim_ColorBreath(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PACK& colors, uint32_t timeMs, int speed); void Anim_ColorBreath(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PACK& colors, uint32_t timeMs, int speed);

View File

@ -17,6 +17,7 @@ board_build.partitions = partitions_8mb_ota_2mb_ee.cvs
monitor_speed = 115200 monitor_speed = 115200
monitor_filters = esp32_exception_decoder monitor_filters = esp32_exception_decoder
board_build.sdkconfig_defaults = sdkconfig.defaults board_build.sdkconfig_defaults = sdkconfig.defaults
lib_deps = lib_deps =
bblanchon/ArduinoJson bblanchon/ArduinoJson
makuna/NeoPixelBus @ ^2.8.3 makuna/NeoPixelBus @ ^2.8.3
@ -33,8 +34,9 @@ lib_deps =
build_flags = build_flags =
-mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-issue
-D CONFIG_LOG_DYNAMIC_LEVEL_CONTROL=1 -D CONFIG_LOG_DYNAMIC_LEVEL_CONTROL=1
#-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -D LOG_LOCAL_LEVEL=5
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO
#-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO
-D CONFIG_ARDUHAL_LOG_COLORS=1 -D CONFIG_ARDUHAL_LOG_COLORS=1
#-Os #-Os
#-ffunction-sections #-ffunction-sections

View File

@ -25,7 +25,10 @@ TaskHandle_t Ramp_Front_Light_Task_Handle;
LEDSTRIP_SETTINGS ledSettings[2]; LEDSTRIP_SETTINGS ledSettings[2];
volatile bool AnimationLooping = false; volatile bool AnimationLooping = false;
ANIM_EVENT prevAnimEvent = {0}; ANIM_EVENT prevAnimEvent = {0};
QueueHandle_t animationQueue = xQueueCreate( 4, sizeof( ANIM_EVENT ) ); //QueueHandle_t animationQueue = xQueueCreate( 4, sizeof( ANIM_EVENT ) );
static QueueHandle_t animationQueue = NULL;
static SemaphoreHandle_t fastledMutex = NULL;
bool upgradeMode = false; bool upgradeMode = false;
@ -36,7 +39,6 @@ bool upgradeMode = false;
//bool fillAnimationActive = false; //bool fillAnimationActive = false;
void RGB_Lights_Set_Animation(int animIndex, uint8_t red, uint8_t grn, uint8_t blu){ void RGB_Lights_Set_Animation(int animIndex, uint8_t red, uint8_t grn, uint8_t blu){
// Trigger to exit curring looping animation // Trigger to exit curring looping animation
if(AnimationLooping){ if(AnimationLooping){
AnimationLooping = false; AnimationLooping = false;
@ -72,6 +74,21 @@ void Lights_Set_White(uint8_t val){
void Init_RGB_Lights_Task(bool upgrade){ void Init_RGB_Lights_Task(bool upgrade){
// create queue & mutex here and check
if (animationQueue == NULL) {
animationQueue = xQueueCreate(4, sizeof(ANIM_EVENT));
if (animationQueue == NULL) {
ESP_LOGE(tag, "Failed to create animationQueue");
return;
}
}
// validate ledSettings[] fields before allocating
if (ledSettings[0].size <= 0) {
ESP_LOGE(tag, "Invalid ledSettings[0].size");
return;
}
upgradeMode = upgrade; upgradeMode = upgrade;
ledSettings[0].leds = new CRGB[ledSettings[0].size]; ledSettings[0].leds = new CRGB[ledSettings[0].size];
Init_RGB_Strip(ledSettings[0].leds, ledSettings[0].pin, ledSettings[0].size, ledSettings[0].rgbOrder, ledSettings[0].chip, ledSettings[0].bright); Init_RGB_Strip(ledSettings[0].leds, ledSettings[0].pin, ledSettings[0].size, ledSettings[0].rgbOrder, ledSettings[0].chip, ledSettings[0].bright);
@ -87,131 +104,6 @@ void Init_RGB_Lights_Task(bool upgrade){
} }
/*
void Init_Ramp_Front_Light_Task(void){
// Check if pwmOutputs[0] is available before creating the task
if(pwmOutputs[0] == nullptr) {
ESP_LOGE(tag, "Cannot create Ramp Front Light Task: pwmOutputs[0] is not initialized");
return;
}
// Create task with moderate stack size - 2KB should be sufficient
BaseType_t result = xTaskCreatePinnedToCore(Ramp_Front_Light_Control_Task, "Ramp_Front_Light_Task", 1024*2, NULL, 1, &Ramp_Front_Light_Task_Handle, (FASTLED_CORE ? 1 : 0));
if(result != pdPASS) {
ESP_LOGE(tag, "Failed to create Ramp Front Light Task, error: %d", result);
Ramp_Front_Light_Task_Handle = NULL;
} else {
ESP_LOGI(tag, "Ramp Front Light Task Created...");
}
}
*/
/*
#define RAMP_INTERVAL 25
#define FRONTLIGHT_TIMEOUT 20000
int startDelay = 0;
int rampTime = 0;
bool rampRestart = false;
float FrontLightMin = 0.0;
void Ramp_Front_Light_Control_Task(void *parameters)
{
float currPwmValue = 0.0;
float outValue = 0.0;
int timeCounter = 0;
while(1) {
if(rampRestart == false){
vTaskSuspend(NULL); // Wait to be triggered
}
rampRestart = false; // Clear the flag immediately
// Safety check: Ensure pwmOutputs[0] is initialized
if(pwmOutputs[0] == nullptr) {
ESP_LOGE(tag, "pwmOutputs[0] is null, cannot control front light");
rampRestart = false;
continue;
}
// Wait for start delay to finish
while(!rampRestart && fillAnimationActive && startDelay > 0){
vTaskDelay(10 / portTICK_PERIOD_MS);
startDelay -= 10;
}
if(rampRestart){
continue; // Restart if requested during delay
}
//currPwmValue = pwmOutputs[0]->getDuty(); // Get current PWM value
currPwmValue = FrontLightMin; // Always start from min value
pwmOutputs[0]->setOutput(currPwmValue); // Ensure starting point is set
// Ramp Up the Front Light linearly
timeCounter = 0; // Reset timer for ramp up
int rampMs = rampTime;
while(!rampRestart && fillAnimationActive && rampMs > 0){
timeCounter += RAMP_INTERVAL;
outValue = map(timeCounter, 0, rampTime, currPwmValue, 100);
pwmOutputs[0]->setOutput(outValue);
vTaskDelay(RAMP_INTERVAL / portTICK_PERIOD_MS);
rampMs -= RAMP_INTERVAL;
}
if(rampRestart){
continue; // Restart the ramp up if requested
}
// Max Wait fill animation to end or timeout
int frontLightTimeout = FRONTLIGHT_TIMEOUT;
while(!rampRestart && fillAnimationActive && frontLightTimeout > 0){
vTaskDelay(10 / portTICK_PERIOD_MS);
frontLightTimeout -= 10;
}
if(rampRestart){
pwmOutputs[0]->setOutput(0); // Ensure it's fully off
continue; // Restart the ramp up if requested
}
// Ramp Down the Front Light linearly
timeCounter = 0; // Reset timer for ramp down
rampMs = rampTime;
while(!rampRestart && fillAnimationActive && rampMs > 0){
timeCounter += RAMP_INTERVAL;
outValue = map(timeCounter, 0, rampTime, 100 , currPwmValue);
pwmOutputs[0]->setOutput(outValue);
vTaskDelay(RAMP_INTERVAL / portTICK_PERIOD_MS);
rampMs -= RAMP_INTERVAL;
}
// Cycle completed - ensure clean final state
if(!rampRestart){
pwmOutputs[0]->setOutput(FrontLightMin); // Ensure final state is minimum
fillAnimationActive = false; // Clear animation flag
}
}
}
void Start_RampUp_Front_Light(int _rampTime, int _startDelay)
{
// Check if the task exists before trying to control it
if(Ramp_Front_Light_Task_Handle == NULL) {
ESP_LOGW(tag, "Cannot start front light ramp: task not created");
return;
}
rampTime = _rampTime;
startDelay = _startDelay;
fillAnimationActive = true;
rampRestart = true;
vTaskResume(Ramp_Front_Light_Task_Handle);
}
*/
void Animation_Loop_Exit(void){ void Animation_Loop_Exit(void){
if( Animation_Task_Handle ){ if( Animation_Task_Handle ){
xTaskNotifyGive( Animation_Task_Handle ); xTaskNotifyGive( Animation_Task_Handle );
@ -509,11 +401,11 @@ void RGB_Lights_Control_Task(void *parameters){
ESP_LOGD(tag, "New Animation Event: Index: %d", AnimEvent.AnimationIndex); ESP_LOGD(tag, "New Animation Event: Index: %d", AnimEvent.AnimationIndex);
switch (AnimEvent.AnimationIndex) { switch (AnimEvent.AnimationIndex) {
case -3: // Set Shift case -3:{ // Set Shift
if (AnimEvent.data.data[0] >= 0 && AnimEvent.data.data[0] < ledSettings[0].size) { if (AnimEvent.data.data[0] >= 0 && AnimEvent.data.data[0] < ledSettings[0].size) {
fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black); fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black);
ledSettings[0].shift = AnimEvent.data.data[0]; ledSettings[0].shift = AnimEvent.data.data[0];
vTaskDelay(25 / portTICK_PERIOD_MS); vTaskDelay(pdMS_TO_TICKS(25));
setPixel1(ledSettings[0], 0, CRGB::White * FastLED.getBrightness() / 255); setPixel1(ledSettings[0], 0, CRGB::White * FastLED.getBrightness() / 255);
FastLED.show(); FastLED.show();
ESP_LOGD(tag, "Set Shift: %d", ledSettings[0].shift); ESP_LOGD(tag, "Set Shift: %d", ledSettings[0].shift);
@ -521,37 +413,54 @@ void RGB_Lights_Control_Task(void *parameters){
ESP_LOGW(tag, "Pixel index out of range: %d", AnimEvent.data.data[0]); ESP_LOGW(tag, "Pixel index out of range: %d", AnimEvent.data.data[0]);
} }
break; break;
case -2: // Fill Static Color }
case -2:{ // Fill Static Color
fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB(AnimEvent.data.red, AnimEvent.data.grn, AnimEvent.data.blu)); fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB(AnimEvent.data.red, AnimEvent.data.grn, AnimEvent.data.blu));
FastLED.show(); FastLED.show();
ESP_LOGD(tag, "Static Color"); ESP_LOGD(tag, "Static Color");
break; break;
case -1: }
case -1:{
FastLED.clear(); FastLED.clear();
FastLED.show(); FastLED.show();
ESP_LOGD(tag, "LEDs Off"); ESP_LOGD(tag, "LEDs Off");
break; break;
case 0: }
case 0:{
fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black); fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black);
FastLED.show(); FastLED.show();
break; break;
}
case 1 ... 5: { // Timed Fill Animations case 1 ... 5: { // Timed Fill Animations
int timeDuration = AnimEvent.AnimationIndex * 1000 - 400; float tempMax = -1;
if(AnimEvent.AnimationIndex == 1 && sys_settings.rampLightSettings[0].max > 70.0) {
tempMax = sys_settings.rampLightSettings[0].max; // preserve user setting if higher than 70
sys_settings.rampLightSettings[0].max = 70.0;
}
int timeDuration = (AnimEvent.AnimationIndex * 1000) - 100;
int whiteDelay = timeDuration - 1000; int whiteDelay = timeDuration - 1000;
if (whiteDelay < 800) whiteDelay = 800; // minimum 8 seconds if (whiteDelay < 0) whiteDelay = 0;
Anim_TimedFill_Flash(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, pwmOutputs[0], &sys_settings.pwmOutSettings[0], whiteDelay, 20000, CRGB::Black, CRGB::White, timeDuration, ledSettings[0].shift); Anim_TimedFill_Flash(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, pwmOutputs[sys_settings.rampLightSettings[0].pwmOutIndex], &sys_settings.rampLightSettings[0], whiteDelay, 20000, CRGB::Black, CRGB(CRGB::White).nscale8(180), timeDuration, ledSettings[0].shift);
// restore ramp light max if it was changed
if(tempMax > 0){
sys_settings.rampLightSettings[0].max = tempMax; // restore user setting
}
break; break;
} }
case 6: case 6:{
// RGB White and Dedicated White all on with timeout and brightness reduction // RGB White and Dedicated White all on with timeout and brightness reduction
Anim_SolidWhite(AnimationLooping, ledSettings[0].leds, pwmOutputs[0], ledSettings[0].size, 240, 30000); Anim_SolidWhite(AnimationLooping, ledSettings[0].leds, pwmOutputs[sys_settings.rampLightSettings[0].pwmOutIndex], ledSettings[0].size, 240, 30000);
break; break;
case 7: }
case 7:{
Anim_Rainbow(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60); Anim_Rainbow(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60);
break; break;
case 8 ... 12: }
case 8 ... 12:{
Anim_GradientRotate(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, gradient_colorPack[AnimEvent.AnimationIndex - 8], 80); Anim_GradientRotate(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, gradient_colorPack[AnimEvent.AnimationIndex - 8], 80);
break; break;
}
case 13 ... 17: { // Fire Animations case 13 ... 17: { // Fire Animations
COLOR_PACK fp = fireColorPacks[AnimEvent.AnimationIndex - 13]; // copy const pack to mutable COLOR_PACK fp = fireColorPacks[AnimEvent.AnimationIndex - 13]; // copy const pack to mutable
CRGBPalette16 firePalette; CRGBPalette16 firePalette;
@ -559,72 +468,91 @@ void RGB_Lights_Control_Task(void *parameters){
Anim_Fire(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60, firePalette, ledSettings[0].shift); Anim_Fire(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60, firePalette, ledSettings[0].shift);
break; break;
} }
case 18 ... 20: // Sparkle/Twinkle case 18 ... 20:{ // Sparkle/Twinkle
Anim_Sparkle(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[0], 40, 20); Anim_Sparkle(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[0], 40, 20);
break; break;
case 21: }
case 21: {
Anim_ColorBreath(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 7000, 90); Anim_ColorBreath(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 7000, 90);
break; break;
case 22: // Rain Animation }
case 22:{ // Rain Animation
Anim_Morph(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 20, 40); Anim_Morph(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 20, 40);
break; break;
}
// Comets // Comets
case 23: case 23: {
Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 40, 85, RANDOM_DECAY, 1); Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 40, 85, RANDOM_DECAY, 1);
break; break;
case 24 ... 31: }
case 24 ... 31:{
Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 24], 40, 85, RANDOM_DECAY, 6); Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 24], 40, 85, RANDOM_DECAY, 6);
break; break;
case 32 ... 40: }
case 32 ... 40:{
Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 32], 40, 85, RANDOM_DECAY, 3); Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 32], 40, 85, RANDOM_DECAY, 3);
break; break;
case 41 ... 49: }
case 41 ... 49:{
Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 41], 40, 85, RANDOM_DECAY, 2); Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 41], 40, 85, RANDOM_DECAY, 2);
break; break;
}
// Snakes // Snakes
case 50: case 50: {
Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 50); Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 50);
break; break;
case 51 ... 58: }
case 51 ... 58: {
Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 51], 60, 6); Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 51], 60, 6);
break; break;
case 59 ... 67: }
case 59 ... 67: {
Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 59], 60, 3); Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 59], 60, 3);
break; break;
case 68 ... 76: }
case 68 ... 76: {
Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 68], 60, 2); Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 68], 60, 2);
break; break;
}
// Sectors // Sectors
case 77: case 77: {
Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, NO_GAPS, 1, 40, 90); Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, NO_GAPS, 1, 40, 90);
break; break;
case 78 ... 86: }
case 78 ... 86: {
Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 78], NO_GAPS, 3, 40, 90); Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 78], NO_GAPS, 3, 40, 90);
break; break;
case 87 ... 95: }
case 87 ... 95: {
Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 87], NO_GAPS, 2, 40, 90); Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 87], NO_GAPS, 2, 40, 90);
break; break;
}
// Dashes // Dashes
case 96: case 96:{
Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, WITH_GAPS, 1, 40, 90); Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, WITH_GAPS, 1, 40, 90);
break; break;
case 97 ... 104: }
case 97 ... 104:{
Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 97], WITH_GAPS, 6, 40, 90); Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 97], WITH_GAPS, 6, 40, 90);
break; break;
case 105 ... 113: }
case 105 ... 113:{
Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 105], WITH_GAPS, 3, 40, 90); Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 105], WITH_GAPS, 3, 40, 90);
break; break;
case 114 ... 122: }
case 114 ... 122:{
Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 114], WITH_GAPS, 2, 40, 90); Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 114], WITH_GAPS, 2, 40, 90);
break; break;
default: }
default:{
ESP_LOGW(tag, "Loop default"); ESP_LOGW(tag, "Loop default");
break; break;
} }
}
AnimationLooping = false; AnimationLooping = false;
prevAnimEvent = AnimEvent; prevAnimEvent = AnimEvent;
@ -643,7 +571,7 @@ void RGB_Lights_Control_Task(void *parameters){
ledSettings[0].shift = AnimEvent.data.data[0]; ledSettings[0].shift = AnimEvent.data.data[0];
ESP_LOGD(tag, "Set Shift: %d", ledSettings[0].shift); ESP_LOGD(tag, "Set Shift: %d", ledSettings[0].shift);
vTaskDelay(25 / portTICK_PERIOD_MS); vTaskDelay(pdMS_TO_TICKS(25));
setPixel1(ledSettings[0], 0, CRGB::White); setPixel1(ledSettings[0], 0, CRGB::White);
FastLED.show(); FastLED.show();
@ -666,15 +594,25 @@ void RGB_Lights_Control_Task(void *parameters){
FastLED.show(); FastLED.show();
break; break;
case 1 ... 5: { // Timed Fill Animations case 1 ... 5: { // Timed Fill Animations
int timeDuration = AnimEvent.AnimationIndex * 1000 - 400; float tempMax = -1;
if(AnimEvent.AnimationIndex == 1 && sys_settings.rampLightSettings[0].max > 70.0) {
tempMax = sys_settings.rampLightSettings[0].max; // preserve user setting if higher than 70
sys_settings.rampLightSettings[0].max = 70.0;
}
int timeDuration = (AnimEvent.AnimationIndex * 1000) - 100;
int whiteDelay = timeDuration - 1000; int whiteDelay = timeDuration - 1000;
if (whiteDelay < 800) whiteDelay = 800; // minimum 8 seconds if (whiteDelay < 0) whiteDelay = 0;
Anim_TimedFill_Flash(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, pwmOutputs[0], &sys_settings.pwmOutSettings[0], whiteDelay, 10000, CRGB::Black, CRGB::White, timeDuration, ledSettings[0].shift); Anim_TimedFill_Flash(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, pwmOutputs[sys_settings.rampLightSettings[0].pwmOutIndex], &sys_settings.rampLightSettings[0], whiteDelay, 20000, CRGB::Black, CRGB(CRGB::White).nscale8(180), timeDuration, ledSettings[0].shift);
// restore ramp light max if it was changed
if(tempMax > 0){
sys_settings.rampLightSettings[0].max = tempMax; // restore user setting
}
break; break;
} }
case 6: case 6:
// RGB White and Dedicated White all on with timeout and brightness reduction // RGB White and Dedicated White all on with timeout and brightness reduction
Anim_SolidWhite(AnimationLooping, ledSettings[0].leds, pwmOutputs[0], ledSettings[0].size, 240, 30000); Anim_SolidWhite(AnimationLooping, ledSettings[0].leds, pwmOutputs[sys_settings.rampLightSettings[0].pwmOutIndex], ledSettings[0].size, 240, 30000);
break; break;
case 7: case 7:
Anim_Rainbow(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60); Anim_Rainbow(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60);
@ -766,7 +704,6 @@ void RGB_Lights_Control_Task(void *parameters){
void SetAndSaveUserSettings(USER_SETTINGS &userSettings) { void SetAndSaveUserSettings(USER_SETTINGS &userSettings) {
// Apply the settings to sys_settings // Apply the settings to sys_settings
sys_settings.limitedMode = userSettings.limitedMode; sys_settings.limitedMode = userSettings.limitedMode;

View File

@ -14,12 +14,15 @@
static const char* tag = "anims"; static const char* tag = "anims";
typedef struct{ //typedef struct{
float minSpeed; // float minSpeed;
float maxSpeed; // float maxSpeed;
int rampCycles; // int rampCycles;
}SPEED_PROPERTIES; //}SPEED_PROPERTIES;
ANIM_FIRE fireSettings; // = { FIRE_COOLING, FIRE_SPARKING, FIRE_brightness };
ANIM_COMET cometSettings; // = { 30, 20, 0.2f, 4, 1 }; // Use 0 instead of 0.2 for integer field
ANIM_SNAKES snakeSettings; // = { 30, 4, 1 };
void Animation_Init(void){ void Animation_Init(void){
// Create Palettes // Create Palettes
@ -482,9 +485,6 @@ void Anim_Rainbow(bool volatile& activeFlag, CRGB* leds, int size, int speed){
} }
// Fire parameters (adjustable) // Fire parameters (adjustable)
const uint8_t FIRE_COOLING = 66;
const uint8_t FIRE_SPARKING = 55;
const uint8_t FIRE_brightness = 240;
void Anim_Fire(bool volatile& activeFlag, CRGB* leds, int size, int speed, const CRGBPalette16& firePalette, int shift = 0) { void Anim_Fire(bool volatile& activeFlag, CRGB* leds, int size, int speed, const CRGBPalette16& firePalette, int shift = 0) {
if (!leds || size <= 0) return; if (!leds || size <= 0) return;
@ -504,7 +504,7 @@ void Anim_Fire(bool volatile& activeFlag, CRGB* leds, int size, int speed, const
Animation_Loop(activeFlag, speed, [&]() -> int { Animation_Loop(activeFlag, speed, [&]() -> int {
// Random cooling // Random cooling
for(int i = 0; i < halfSize; i++) { for(int i = 0; i < halfSize; i++) {
heat[i] = qsub8(heat[i], random8(0, ((FIRE_COOLING * 10) / halfSize) + 2)); heat[i] = qsub8(heat[i], random8(0, ((fireSettings.cooling * 10) / halfSize) + 2));
} }
// Heat rises and diffuses // Heat rises and diffuses
@ -513,7 +513,7 @@ void Anim_Fire(bool volatile& activeFlag, CRGB* leds, int size, int speed, const
} }
// Randomly ignite new sparks at bottom // Randomly ignite new sparks at bottom
if(random8() < FIRE_SPARKING) { if(random8() < fireSettings.sparking) {
// ensure y is in-bounds for small strips // ensure y is in-bounds for small strips
y = min<int>(random8(7), halfSize - 1); y = min<int>(random8(7), halfSize - 1);
heat[y] = qadd8(heat[y], random8(160, 240)); heat[y] = qadd8(heat[y], random8(160, 240));
@ -522,7 +522,7 @@ void Anim_Fire(bool volatile& activeFlag, CRGB* leds, int size, int speed, const
// Map heat to colors with mirroring and shifting // Map heat to colors with mirroring and shifting
for(int j = 0; j < halfSize; j++) { for(int j = 0; j < halfSize; j++) {
colorindex = scale8(heat[j], 240); colorindex = scale8(heat[j], 240);
color = ColorFromPalette(firePalette, colorindex, FIRE_brightness, LINEARBLEND); color = ColorFromPalette(firePalette, colorindex, fireSettings.brightness, LINEARBLEND);
// Apply shift and wrap around // Apply shift and wrap around
pos1 = (j + shift + size) % size; pos1 = (j + shift + size) % size;
@ -639,8 +639,9 @@ void Anim_Color_Sectors(bool volatile& activeFlag, CRGB* leds, int size, const C
/******************************************************************************** /********************************************************************************
* Comets Animation * Comets Animation
*******************************************************************************/ *******************************************************************************/
#define COMET_SIZE_FACTOR 0.2 #define COMET_SIZE_FACTOR 0.2
#define COMET_FADE_FACTOR1 32 /* longer tail */ #define COMET_FADE_FACTOR1 16 /* longer tail */
#define COMET_FADE_FACTOR2 192 /* shorter tail */ #define COMET_FADE_FACTOR2 192 /* shorter tail */
//#define COMET_FADE_FACTOR COMET_FADE_FACTOR2 //#define COMET_FADE_FACTOR COMET_FADE_FACTOR2
#define MAX_COMETS 8 // Maximum number of comets supported #define MAX_COMETS 8 // Maximum number of comets supported
@ -927,7 +928,7 @@ void Anim_TimedFill(bool volatile& activeFlag, CRGB* leds, int size, CRGB baseCo
} }
void Anim_TimedFill_Flash(bool volatile& activeFlag, CRGB* leds, int size, PWM_Output* pwmOut, PWM_OUT_SETTINGS* pwmSettings, int pwmOutDelay, int flashTimeout, CRGB baseCol, CRGB fillCol, int totalDurationMs, int shift) void Anim_TimedFill_Flash(bool volatile& activeFlag, CRGB* leds, int size, PWM_Output* pwmOut, RAMP_LIGHT_SETTINGS* pwmSettings, int pwmOutDelay, int flashTimeout, CRGB baseCol, CRGB fillCol, int totalDurationMs, int shift)
{ {
if (!leds || size <= 1 || totalDurationMs <= 0 || !pwmOut || !pwmSettings) return; if (!leds || size <= 1 || totalDurationMs <= 0 || !pwmOut || !pwmSettings) return;
@ -996,6 +997,7 @@ void Anim_TimedFill_Flash(bool volatile& activeFlag, CRGB* leds, int size, PWM_O
pwmOut->setOutput(pwmValue); pwmOut->setOutput(pwmValue);
} }
} }
// Phase 2: Animation complete, start flash timeout // Phase 2: Animation complete, start flash timeout
else if (!flashTimeoutStarted) { else if (!flashTimeoutStarted) {
flashTimeoutStarted = true; flashTimeoutStarted = true;
@ -1214,12 +1216,13 @@ void Anim_TheaterChase(bool volatile& activeFlag, CRGB* leds, int size, const CO
#define SNAKE_CYCLES_PER_ROTATION 4 #define SNAKE_CYCLES_PER_ROTATION 4
#define MAX_SNAKES 32
void Anim_Snakes(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PACK& colorPack, int speed , int multiplier) { void Anim_Snakes(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PACK& colorPack, int speed , int multiplier) {
if (!leds || size <= 0 || colorPack.size <= 0 || multiplier <= 0) return; if (!leds || size <= 0 || colorPack.size <= 0 || multiplier <= 0) return;
// Determine number of snakes (colors * multiplier), cap to a safe maximum // Determine number of snakes (colors * multiplier), cap to a safe maximum
const int USER_NUM = colorPack.size * multiplier; const int USER_NUM = colorPack.size * multiplier;
const int MAX_SNAKES = 32;
int numSnakes = USER_NUM; int numSnakes = USER_NUM;
if (numSnakes > MAX_SNAKES) numSnakes = MAX_SNAKES; if (numSnakes > MAX_SNAKES) numSnakes = MAX_SNAKES;
if (numSnakes <= 0) return; if (numSnakes <= 0) return;
@ -1369,7 +1372,7 @@ void Anim_Birds(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PAC
// Determine number of snakes (colors * multiplier), cap to a safe maximum // Determine number of snakes (colors * multiplier), cap to a safe maximum
const int USER_NUM = colorPack.size * multiplier; const int USER_NUM = colorPack.size * multiplier;
const int MAX_SNAKES = 32; //const int MAX_SNAKES = 32;
int numSnakes = USER_NUM; int numSnakes = USER_NUM;
if (numSnakes > MAX_SNAKES) numSnakes = MAX_SNAKES; if (numSnakes > MAX_SNAKES) numSnakes = MAX_SNAKES;
if (numSnakes <= 0) return; if (numSnakes <= 0) return;

View File

@ -909,7 +909,7 @@ void startFirmwareUpdateTask(AsyncEventSource* evProg) {
return; return;
} }
// Create task with higher priority (3) and optimized stack size // Create task with higher priority (3) and optimized stack size
xTaskCreate(firmwareUpdateTask, "FirmwareUpdate", 1024*6, NULL, 3, &Update_Task_Handle); xTaskCreate(firmwareUpdateTask, "FirmwareUpdate", 1024*8, NULL, 3, &Update_Task_Handle);
} }
void firmwareUpdateTask(void* parameter) { void firmwareUpdateTask(void* parameter) {

View File

@ -70,7 +70,6 @@ void PWM_Output::setOutput(float duty){
this->currDuty = duty; this->currDuty = duty;
} }
void PWM_Output::setFreq(uint32_t fq){ void PWM_Output::setFreq(uint32_t fq){
uint32_t newFreq; uint32_t newFreq;
if(this->freq != fq){ if(this->freq != fq){

View File

@ -14,7 +14,6 @@ RAMP_LIGHT::RAMP_LIGHT(OneButton* button, PWM_Output* pwmOutput, float min, floa
button->attachLongPressStop([](void* context) { static_cast<RAMP_LIGHT*>(context)->longPressStop(); }, this); button->attachLongPressStop([](void* context) { static_cast<RAMP_LIGHT*>(context)->longPressStop(); }, this);
button->attachDuringLongPress([](void* context) { static_cast<RAMP_LIGHT*>(context)->duringLongPress(); }, this); button->attachDuringLongPress([](void* context) { static_cast<RAMP_LIGHT*>(context)->duringLongPress(); }, this);
if(min < 0.0) this->min = 0.0; if(min < 0.0) this->min = 0.0;
if(max > 100.0) this->max = 100.0; if(max > 100.0) this->max = 100.0;
if(this->max < this->min) this->max = this->min; if(this->max < this->min) this->max = this->min;

View File

@ -53,10 +53,9 @@ void printTaskInfo(TaskStatus_t taskStatus) {
uint32_t ulTotalRunTime = taskStatus.ulRunTimeCounter; uint32_t ulTotalRunTime = taskStatus.ulRunTimeCounter;
uint32_t ulStatsAsPercentage = (ulTotalRunTime * 100) / ulTotalRunTime; // Total runtime equals 100% uint32_t ulStatsAsPercentage = (ulTotalRunTime * 100) / ulTotalRunTime; // Total runtime equals 100%
ESP_LOGI(tag, "TaskInfo: %s\t%u\t%u\t%u\t%u%%", ESP_LOGI(tag, "TaskInfo: %s\t%u\t%u\t%u%%",
taskStatus.pcTaskName, taskStatus.pcTaskName,
taskStatus.uxCurrentPriority, taskStatus.uxCurrentPriority,
taskStatus.xCoreID,
configMINIMAL_STACK_SIZE - taskStatus.usStackHighWaterMark, configMINIMAL_STACK_SIZE - taskStatus.usStackHighWaterMark,
ulStatsAsPercentage); ulStatsAsPercentage);
} }

View File

@ -70,19 +70,16 @@ static const char *tag = "main";
// Timer handles for periodic tasks // Timer handles for periodic tasks
TimerHandle_t buttonScanTimer = NULL; TimerHandle_t buttonScanTimer = NULL;
#define buttonScanInterval 10 // ms
TimerHandle_t temperatureTimer = NULL; TimerHandle_t temperatureTimer = NULL;
TimerHandle_t statusLedTimer = NULL; TimerHandle_t statusLedTimer = NULL;
#define statusLedInterval 500 // ms
TimerHandle_t upgradeHeartbeatTimer = NULL; TimerHandle_t upgradeHeartbeatTimer = NULL;
#define upgradeHeartbeatInterval 5000 // ms
TimerHandle_t diagnosticsTimer = NULL; TimerHandle_t diagnosticsTimer = NULL;
#define diagnosticsInterval 60000 // ms
TimerHandle_t analogInputTimer = NULL; TimerHandle_t analogInputTimer = NULL;
#define buttonScanInterval 5 // ms
#define statusLedInterval 500 // ms
#define upgradeHeartbeatInterval 5000 // ms
#define diagnosticsInterval 60000 // ms
#define analogInputInterval 3000 // ms #define analogInputInterval 3000 // ms
@ -91,11 +88,27 @@ void setupLogLevels(esp_log_level_t logLevel);
// Timer callback functions // Timer callback functions
void ButtonScanCallback(TimerHandle_t xTimer) { void ButtonScanCallback(TimerHandle_t xTimer) {
for (int i = 0; i < 3; i++) { static int btnIndex = 0;
if (boardButtons[i] != NULL) {
boardButtons[i]->tick(); switch(btnIndex){
case 0:
if (boardButtons[0] != NULL) {
boardButtons[0]->tick();
} }
break;
case 1:
if (boardButtons[1] != NULL) {
boardButtons[1]->tick();
} }
break;
case 2:
if (boardButtons[2] != NULL) {
boardButtons[2]->tick();
}
break;
}
btnIndex = (btnIndex + 1) % 3;
} }
void TemperatureCallback(TimerHandle_t xTimer) { void TemperatureCallback(TimerHandle_t xTimer) {
@ -142,9 +155,8 @@ void checkLEDCChannels()
} }
} }
#define Button1Pin 8 //#define Button1Pin 8
void setup() void setup(){
{
bool UpgradeMode = false; bool UpgradeMode = false;
// Serial Port // Serial Port
@ -157,31 +169,41 @@ void setup()
sys_settings.ledStripSettings[0] = &ledSettings[0]; sys_settings.ledStripSettings[0] = &ledSettings[0];
sys_settings.ledStripSettings[1] = &ledSettings[1]; sys_settings.ledStripSettings[1] = &ledSettings[1];
// Set Logging Levels
// esp_log_level_t logLevel = ESP_LOG_INFO;
// pinMode(Button1Pin, INPUT); // Button1
// if(!digitalRead(Button1Pin)){
// logLevel = ESP_LOG_VERBOSE;
//}
// setupLogLevels(logLevel);
setupLogLevels(ESP_LOG_INFO);
// chip id, mac,
print_chip_info();
// Init LittleFS // Init LittleFS
Init_File_System(); Init_File_System();
// Print all system files
if (digitalRead(sys_settings.boardPins.btn[1]) == LOW){
printAllSystemFiles();
}
String board_file_path; String board_file_path;
Get_Board_and_Booth_File_Paths("/system/system.json", board_file_path, booth_file_path); Get_Board_and_Booth_File_Paths("/system/system.json", board_file_path, booth_file_path);
// Load Board Pins // Load Board Pins
Load_Board_Pins(sys_settings.boardPins, board_file_path); Load_Board_Pins(sys_settings.boardPins, board_file_path);
esp_log_level_t logLevel = ESP_LOG_INFO;
if (digitalRead(sys_settings.boardPins.btn[1]) == LOW) {
logLevel = ESP_LOG_DEBUG;
}
Serial.print("Log Level: ");
Serial.print(logLevel);
Serial.print(" (");
switch (logLevel) {
case ESP_LOG_NONE: Serial.print("NONE"); break;
case ESP_LOG_ERROR: Serial.print("1-ERROR"); break;
case ESP_LOG_WARN: Serial.print("2-WARN"); break;
case ESP_LOG_INFO: Serial.print("3-INFO"); break;
case ESP_LOG_DEBUG: Serial.print("4-DEBUG"); break;
case ESP_LOG_VERBOSE: Serial.print("5-VERBOSE"); break;
default: Serial.print("UNKNOWN"); break;
}
Serial.println(")");
setupLogLevels(logLevel);
// chip id, mac,
print_chip_info();
// Print all system files
if (digitalRead(sys_settings.boardPins.btn[1]) == LOW){
printAllSystemFiles();
}
// Set status pins off // Set status pins off
setStatusPin1(false); setStatusPin1(false);
@ -229,7 +251,7 @@ void setup()
upgradeHeartbeatTimer = xTimerCreate("UpgradeHeartbeat", pdMS_TO_TICKS(5000), pdTRUE, NULL, UpgradeHeartbeatCallback); upgradeHeartbeatTimer = xTimerCreate("UpgradeHeartbeat", pdMS_TO_TICKS(5000), pdTRUE, NULL, UpgradeHeartbeatCallback);
} }
else { else {
ESP_LOGI(tag, "Enabling BLE, No Update Service"); ESP_LOGW(tag, "Enabling BLE, No Update Service");
Init_BleServer(true, false); // Dont start the Upgrade service Init_BleServer(true, false); // Dont start the Upgrade service
} }
@ -259,11 +281,11 @@ void setup()
#endif #endif
// Start the timers // Start the timers
//if (buttonScanTimer) xTimerStart(buttonScanTimer, 100); if (buttonScanTimer) xTimerStart(buttonScanTimer, 200);
if (temperatureTimer && sys_settings.tSensorSettings.enabled) xTimerStart(temperatureTimer, 100); if (temperatureTimer && sys_settings.tSensorSettings.enabled) xTimerStart(temperatureTimer, 500);
if (statusLedTimer) xTimerStart(statusLedTimer, 0); if (statusLedTimer) xTimerStart(statusLedTimer, 100);
if (upgradeHeartbeatTimer && UpgradeMode) xTimerStart(upgradeHeartbeatTimer, upgradeHeartbeatInterval); if (upgradeHeartbeatTimer && UpgradeMode) xTimerStart(upgradeHeartbeatTimer, upgradeHeartbeatInterval);
if (analogInputTimer) xTimerStart(analogInputTimer, 0); if (analogInputTimer) xTimerStart(analogInputTimer, 150);
#if FREERTOS_DIAGNOSTICS #if FREERTOS_DIAGNOSTICS
if (diagnosticsTimer) xTimerStart(diagnosticsTimer, diagnosticsInterval); if (diagnosticsTimer) xTimerStart(diagnosticsTimer, diagnosticsInterval);
@ -281,61 +303,11 @@ void setup()
} }
void loop() void loop(){
{
// Animation TestMode Timeout (keep in loop as it's event-driven)
#if LEDS_ENABLED
if (animStatus.EventTestCountdown)
{
if (--animStatus.EventTestCountdown == 0)
{
ESP_LOGD(tag, "Test Timeout trigger");
PostLastNormalEvent();
if (Strip1_Task_Handle)
{
xTaskNotifyGive(Strip1_Task_Handle);
} // trigger exit of animation loop
}
};
#endif
// Reboot requested (keep in loop as it's a state-based countdown)
#if WIFI_ENABLED
if (RebootSystem)
{
if (--RebootSystem == 0)
{
for (int i = 0; i < 3; i++)
{
#if BUZZER_ENABLED
Buzzer_Play_Tune(TUNE_LOWEEP); // blocking
#endif
vTaskDelay(200);
}
ESP_LOGW(tag, "Restarting...");
vTaskDelay(200);
ESP.restart();
}
}
#endif
/*
for (int i = 0; i < 3; i++) {
if (boardButtons[i] != NULL) {
boardButtons[i]->tick();
}
}
vTaskDelay(buttonScanInterval);
*/
// Small delay to prevent busy-waiting
//vTaskDelay(pdMS_TO_TICKS(100));
vTaskDelay(portMAX_DELAY); vTaskDelay(portMAX_DELAY);
} }
void setupLogLevels(esp_log_level_t logLevel) void setupLogLevels(esp_log_level_t logLevel){
{
// Options: ESP_LOG_ERROR,ESP_LOG_WARN,ESP_LOG_INFO,ESP_LOG_DEBUG,ESP_LOG_VERBOSE // Options: ESP_LOG_ERROR,ESP_LOG_WARN,ESP_LOG_INFO,ESP_LOG_DEBUG,ESP_LOG_VERBOSE
esp_log_level_set("*", logLevel); esp_log_level_set("*", logLevel);
esp_log_level_set("fs", logLevel); esp_log_level_set("fs", logLevel);
@ -353,6 +325,7 @@ void setupLogLevels(esp_log_level_t logLevel)
esp_log_level_set("oled", logLevel); esp_log_level_set("oled", logLevel);
esp_log_level_set("trx433", logLevel); esp_log_level_set("trx433", logLevel);
esp_log_level_set("tsensor", logLevel); esp_log_level_set("tsensor", logLevel);
esp_log_level_set("my_device", logLevel);
} }

View File

@ -81,24 +81,33 @@ bool Load_Board_Pins(BOARD_PINS &boardPins, const String &path) {
auto clampPin = [](int v) { return isValidGpio(v) ? v : -1; }; auto clampPin = [](int v) { return isValidGpio(v) ? v : -1; };
boardPins.rgb1 = clampPin(boardPins.rgb1); boardPins.rgb1 = clampPin(boardPins.rgb1);
boardPins.rgb2 = clampPin(boardPins.rgb2); boardPins.rgb2 = clampPin(boardPins.rgb2);
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
boardPins.btn[i] = clampPin(boardPins.btn[i]); boardPins.btn[i] = clampPin(boardPins.btn[i]);
boardPins.buzzer = clampPin(boardPins.buzzer); boardPins.buzzer = clampPin(boardPins.buzzer);
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
boardPins.touch[i] = clampPin(boardPins.touch[i]); boardPins.touch[i] = clampPin(boardPins.touch[i]);
boardPins.shield = clampPin(boardPins.shield); boardPins.shield = clampPin(boardPins.shield);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
boardPins.relay[i] = clampPin(boardPins.relay[i]); boardPins.relay[i] = clampPin(boardPins.relay[i]);
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
boardPins.stat[i] = clampPin(boardPins.stat[i]); boardPins.stat[i] = clampPin(boardPins.stat[i]);
boardPins.adc1 = clampPin(boardPins.adc1); boardPins.adc1 = clampPin(boardPins.adc1);
boardPins.oled_dc = clampPin(boardPins.oled_dc); boardPins.oled_dc = clampPin(boardPins.oled_dc);
boardPins.oled_rst = clampPin(boardPins.oled_rst); boardPins.oled_rst = clampPin(boardPins.oled_rst);
boardPins.oled_mosi = clampPin(boardPins.oled_mosi); boardPins.oled_mosi = clampPin(boardPins.oled_mosi);
boardPins.oled_sck = clampPin(boardPins.oled_sck); boardPins.oled_sck = clampPin(boardPins.oled_sck);
boardPins.oled_cs = clampPin(boardPins.oled_cs); boardPins.oled_cs = clampPin(boardPins.oled_cs);
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
boardPins.ext[i] = clampPin(boardPins.ext[i]); boardPins.ext[i] = clampPin(boardPins.ext[i]);
boardPins.rf433tx = clampPin(boardPins.rf433tx); boardPins.rf433tx = clampPin(boardPins.rf433tx);
boardPins.rf433rx = clampPin(boardPins.rf433rx); boardPins.rf433rx = clampPin(boardPins.rf433rx);
@ -107,40 +116,17 @@ bool Load_Board_Pins(BOARD_PINS &boardPins, const String &path) {
} }
void Init_Board_Basic(BOARD_PINS &boardPins) { void Init_Board_Basic(BOARD_PINS &boardPins) {
if (boardPins.stat[0] >= 0) { pinMode(boardPins.stat[0], OUTPUT); }
if (boardPins.stat[0] >= 0) { if (boardPins.stat[1] >= 0) { pinMode(boardPins.stat[1], OUTPUT); }
pinMode(boardPins.stat[0], OUTPUT); if (boardPins.btn[0] >= 0) { pinMode(boardPins.btn[0], INPUT_PULLUP); }
} if (boardPins.btn[1] >= 0) { pinMode(boardPins.btn[1], INPUT_PULLUP); }
if (boardPins.stat[1] >= 0) { if (boardPins.btn[2] >= 0) { pinMode(boardPins.btn[2], INPUT); }
pinMode(boardPins.stat[1], OUTPUT); if (boardPins.rgb1 >= 0) { pinMode(boardPins.rgb1, OUTPUT); }
} if (boardPins.rgb2 >= 0) { pinMode(boardPins.rgb2, OUTPUT); }
if (boardPins.btn[0] >= 0) { if (boardPins.relay[0] >= 0) { pinMode(boardPins.relay[0], OUTPUT); }
pinMode(boardPins.btn[0], INPUT_PULLUP); if (boardPins.relay[1] >= 0) { pinMode(boardPins.relay[1], OUTPUT); }
} if (boardPins.relay[2] >= 0) { pinMode(boardPins.relay[2], OUTPUT); }
if (boardPins.btn[1] >= 0) { if (boardPins.relay[3] >= 0) { pinMode(boardPins.relay[3], OUTPUT); }
pinMode(boardPins.btn[1], INPUT_PULLUP);
}
if (boardPins.btn[2] >= 0) {
pinMode(boardPins.btn[2], INPUT);
}
if (boardPins.rgb1 >= 0) {
pinMode(boardPins.rgb1, OUTPUT);
}
if (boardPins.rgb2 >= 0) {
pinMode(boardPins.rgb2, OUTPUT);
}
if (boardPins.relay[0] >= 0) {
pinMode(boardPins.relay[0], OUTPUT);
}
if (boardPins.relay[1] >= 0) {
pinMode(boardPins.relay[1], OUTPUT);
}
if (boardPins.relay[2] >= 0) {
pinMode(boardPins.relay[2], OUTPUT);
}
if (boardPins.relay[3] >= 0) {
pinMode(boardPins.relay[3], OUTPUT);
}
ESP_LOGI(tag, "Board pins initialized..."); ESP_LOGI(tag, "Board pins initialized...");
} }

View File

@ -9,57 +9,20 @@ OneButton *boardButtons[3] = { nullptr, nullptr, nullptr };
void Init_ButtonEvents(int8_t (&pin)[3]){ void Init_ButtonEvents(int8_t (&pin)[3]){
// Initialize buttons if pins are valid and not already initialized // Initialize buttons if pins are valid and not already initialized
if (pin[0] >= 0) { for (int i = 0; i < 3; ++i) {
if (boardButtons[0] == nullptr) { if (pin[i] >= 0) {
boardButtons[0] = new OneButton(pin[0], true, true); if (boardButtons[i] == nullptr) {
ESP_LOGI(tag, "Button1 Events, pin=%d", pin[0]); // For button 3 (index 2), set pullup to false, others true
bool pullup = (i == 2) ? false : true;
boardButtons[i] = new OneButton(pin[i], true, pullup);
ESP_LOGI(tag, "Button%d Events, pin=%d", i + 1, pin[i]);
} else { } else {
ESP_LOGW(tag, "Button1 already initialized (pin=%d)", pin[0]); ESP_LOGW(tag, "Button%d already initialized (pin=%d)", i + 1, pin[i]);
} }
} }
if (pin[1] >= 0) {
if (boardButtons[1] == nullptr) {
boardButtons[1] = new OneButton(pin[1], true, true);
ESP_LOGI(tag, "Button2 Events, pin=%d", pin[1]);
} else {
ESP_LOGW(tag, "Button2 already initialized (pin=%d)", pin[1]);
}
}
if (pin[2] >= 0) {
if (boardButtons[2] == nullptr) {
boardButtons[2] = new OneButton(pin[2], true, false);
ESP_LOGI(tag, "Button3 Events, pin=%d", pin[2]);
} else {
ESP_LOGW(tag, "Button3 already initialized (pin=%d)", pin[2]);
}
} }
/* /*
if(boardButtons[0] != NULL){
//boardButtons[0]->setDebounceTicks(DEBOUCE_TIME); // just below the update period to guarantee 1 sample delay
boardButtons[0]->attachClick(btn1_click);
boardButtons[0]->attachDoubleClick(btn1_doubleClick);
boardButtons[0]->attachLongPressStart(btn1_LongPressStart);
boardButtons[0]->attachLongPressStop(btn1_LongPressStop);
boardButtons[0]->attachDuringLongPress(btn1_DuringLongPress);
}
else {
ESP_LOGD(tag, "Button1 Not Initialized");
}
if(boardButtons[1] != NULL){
//boardButtons[1]->setDebounceTicks(DEBOUCE_TIME);
boardButtons[1]->attachClick(btn2_click);
boardButtons[1]->attachDoubleClick(btn2_doubleClick);
boardButtons[1]->attachLongPressStart(btn2_LongPressStart);
boardButtons[1]->attachLongPressStop(btn2_LongPressStop);
boardButtons[1]->attachDuringLongPress(btn2_DuringLongPress);
}
else {
ESP_LOGD(tag, "Button2 Not Initialized");
}
*/
if(boardButtons[2] != NULL){ if(boardButtons[2] != NULL){
//boardButtons[2]->setDebounceTicks(DEBOUCE_TIME); //boardButtons[2]->setDebounceTicks(DEBOUCE_TIME);
boardButtons[2]->attachClick(btn3_click); boardButtons[2]->attachClick(btn3_click);
@ -72,17 +35,10 @@ void Init_ButtonEvents(int8_t (&pin)[3]){
else { else {
ESP_LOGW(tag, "Button3 Not Initialized"); ESP_LOGW(tag, "Button3 Not Initialized");
} }
*/
} }
void Update_Buttons() {
for (int i = 0; i < 3; ++i) {
if (boardButtons[i] != nullptr) {
boardButtons[i]->tick();
}
}
}
void btn1_click() { void btn1_click() {
//IncrementEventIndex(); //IncrementEventIndex();
//Pulse_LED_Status(150); //Pulse_LED_Status(150);
@ -112,7 +68,7 @@ void btn2_click() {
//Pulse_LED_Status(150); //Pulse_LED_Status(150);
//Buzzer_Beep(150); //Buzzer_Beep(150);
// send packet // send packet
sendUpdateMessage("testing....", false, -1); //sendUpdateMessage("testing....", false, -1);
ESP_LOGD(tag, "btn2 1x"); ESP_LOGD(tag, "btn2 1x");
} }
@ -141,7 +97,7 @@ void btn3_click() {
} }
void btn3_doubleClick() { void btn3_doubleClick() {
bleUpgrade_send_message("Hello....3"); //bleUpgrade_send_message("Hello....3");
ESP_LOGD(tag, "btn3 2x"); ESP_LOGD(tag, "btn3 2x");
} }

View File

@ -18,6 +18,7 @@
#include <esp_system.h> #include <esp_system.h>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include "Animations.h"
static const char *tag = "my_device"; static const char *tag = "my_device";
@ -33,8 +34,6 @@ float prevPowerVin = 0.0;
float PowerVin = 0.0; float PowerVin = 0.0;
// TODO Restore original setOutput code..
#define RELAY_RES 10 #define RELAY_RES 10
void Init_PWM_Outputs(int8_t (&pin)[4], PWM_OUT_SETTINGS (&pwmSettings)[4]) { void Init_PWM_Outputs(int8_t (&pin)[4], PWM_OUT_SETTINGS (&pwmSettings)[4]) {
// Delete any existing objects to avoid leaks on re-init // Delete any existing objects to avoid leaks on re-init
@ -51,36 +50,28 @@ void Init_PWM_Outputs(int8_t (&pin)[4], PWM_OUT_SETTINGS (&pwmSettings)[4]) {
ESP_LOGE(tag, "No available LEDC channel for PWM Output%d", i); ESP_LOGE(tag, "No available LEDC channel for PWM Output%d", i);
continue; continue;
} }
pwmOutputs[i] = new PWM_Output(pin[i], chIndex, RELAY_RES, pwmSettings[i].freq, pwmOutputs[i] = new PWM_Output(pin[i], chIndex, RELAY_RES, pwmSettings[i].freq, pwmSettings[i].max, false);
pwmSettings[i].max, false);
if (pwmOutputs[i]) { if (pwmOutputs[i]) {
pwmOutputs[i]->setOutput(pwmSettings[i].def); pwmOutputs[i]->setOutput(pwmSettings[i].def);
} else { } else {
ESP_LOGE(tag, "Allocation failed for PWM Output%d", i); ESP_LOGE(tag, "Allocation failed for PWM Output%d", i);
} }
// pwmOutputs[i]->setOutput(5.0); // pwmOutputs[i]->setOutput(5.0);
ESP_LOGI(tag, "PWM Output%d: Pin=%d, Freq=%d, ch=%d", i, pin[i], pwmSettings[i].freq, ESP_LOGI(tag, "PWM Output%d: Pin=%d, Freq=%d, ch=%d", i, pin[i], pwmSettings[i].freq, chIndex);
chIndex);
} }
} }
void Init_Ramp_Lights(RAMP_LIGHT_SETTINGS (&settings)[2], OneButton *(&btn)[3], PWM_Output *(&pwm)[4]) { void Init_Ramp_Lights(RAMP_LIGHT_SETTINGS (&settings)[2], OneButton *(&btn)[3], PWM_Output *(&pwm)[4]) {
if (settings[0].enabled) { RAMP_LIGHT **rampLights[2] = { &rampLight1, &rampLight2 };
if (rampLight1) { delete rampLight1; rampLight1 = nullptr; } for (int i = 0; i < 2; ++i) {
rampLight1 = new RAMP_LIGHT(btn[settings[0].btnIndex], pwm[settings[0].pwmOutIndex], settings[0].min, settings[0].max, settings[0].step); if (settings[i].enabled) {
if (rampLight1) if (*(rampLights[i])) { delete *(rampLights[i]); *(rampLights[i]) = nullptr; }
ESP_LOGD(tag, "RampLight%d: btn=%d, pwmIndex=%d, min=%f, max=%f, step=%f", 1, settings[0].btnIndex, settings[0].pwmOutIndex, settings[0].min, settings[0].max, settings[0].step); *(rampLights[i]) = new RAMP_LIGHT(btn[settings[i].btnIndex], pwm[settings[i].pwmOutIndex], settings[i].min, settings[i].max, settings[i].step);
if (*(rampLights[i]))
ESP_LOGI(tag, "RampLight%d: btn=%d, pwmIndex=%d, min=%f, max=%f, step=%f", i + 1, settings[i].btnIndex, settings[i].pwmOutIndex, settings[i].min, settings[i].max, settings[i].step);
else else
ESP_LOGE(tag, "Failed to allocate RampLight1"); ESP_LOGE(tag, "Failed to allocate RampLight%d", i + 1);
} }
if (settings[1].enabled) {
if (rampLight2) { delete rampLight2; rampLight2 = nullptr; }
rampLight2 = new RAMP_LIGHT(btn[settings[1].btnIndex], pwm[settings[1].pwmOutIndex], settings[1].min, settings[1].max, settings[1].step);
if (rampLight2)
ESP_LOGD(tag, "RampLight%d: btn=%d, pwmIndex=%d, min=%f, max=%f, step=%f", 2, settings[1].btnIndex, settings[1].pwmOutIndex, settings[1].min, settings[1].max, settings[1].step);
else
ESP_LOGE(tag, "Failed to allocate RampLight2");
} }
} }
@ -146,14 +137,10 @@ void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) {
sizeof(sys_settings.pwmOutSettings) / sizeof(sys_settings.pwmOutSettings[0])) sizeof(sys_settings.pwmOutSettings) / sizeof(sys_settings.pwmOutSettings[0]))
break; break;
sys_settings.pwmOutSettings[pwmIndex].enabled = jsonConstrainBool(tag, obj, "en", true); sys_settings.pwmOutSettings[pwmIndex].enabled = jsonConstrainBool(tag, obj, "en", true);
sys_settings.pwmOutSettings[pwmIndex].freq = sys_settings.pwmOutSettings[pwmIndex].freq = jsonConstrain<int>(tag, obj, "freq", 100, 5000, 250);
jsonConstrain<int>(tag, obj, "freq", 100, 5000, 250); sys_settings.pwmOutSettings[pwmIndex].min = jsonConstrain<float>(tag, obj, "min", 0.0, 95.0, 0.0);
sys_settings.pwmOutSettings[pwmIndex].min = sys_settings.pwmOutSettings[pwmIndex].max = jsonConstrain<float>(tag, obj, "max", 5.0, 100.0, 100.0);
jsonConstrain<float>(tag, obj, "min", 0.0, 95.0, 0.0); sys_settings.pwmOutSettings[pwmIndex].def = jsonConstrain<float>(tag, obj, "default", 0.0, 100.0, 0.0);
sys_settings.pwmOutSettings[pwmIndex].max =
jsonConstrain<float>(tag, obj, "max", 5.0, 100.0, 100.0);
sys_settings.pwmOutSettings[pwmIndex].def =
jsonConstrain<float>(tag, obj, "default", 0.0, 100.0, 0.0);
sys_settings.pwmOutSettings[pwmIndex].deltaRate = 1.0; sys_settings.pwmOutSettings[pwmIndex].deltaRate = 1.0;
// sys_settings.pwmOutSettings[pwmIndex]. = jsonConstrainBool(tag, obj, "vision", true); // sys_settings.pwmOutSettings[pwmIndex]. = jsonConstrainBool(tag, obj, "vision", true);
pwmIndex++; pwmIndex++;
@ -171,20 +158,13 @@ void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) {
if (rampIndex >= if (rampIndex >=
sizeof(sys_settings.rampLightSettings) / sizeof(sys_settings.rampLightSettings[0])) sizeof(sys_settings.rampLightSettings) / sizeof(sys_settings.rampLightSettings[0]))
break; break;
sys_settings.rampLightSettings[rampIndex].enabled = sys_settings.rampLightSettings[rampIndex].enabled = jsonConstrainBool(tag, obj, "en", true);
jsonConstrainBool(tag, obj, "en", true); sys_settings.rampLightSettings[rampIndex].vision = jsonConstrainBool(tag, obj, "vision", true);
sys_settings.rampLightSettings[rampIndex].vision = sys_settings.rampLightSettings[rampIndex].pwmOutIndex = jsonConstrain<int>(tag, obj, "relay-index", 0, 3, 0);
jsonConstrainBool(tag, obj, "vision", true); sys_settings.rampLightSettings[rampIndex].btnIndex = jsonConstrain<int>(tag, obj, "button-index", 0, 2, 0);
sys_settings.rampLightSettings[rampIndex].pwmOutIndex = sys_settings.rampLightSettings[rampIndex].min = jsonConstrain<float>(tag, obj, "min", 0.0, 95.0, 0.0);
jsonConstrain<int>(tag, obj, "relay-index", 0, 1, 0); sys_settings.rampLightSettings[rampIndex].max = jsonConstrain<float>(tag, obj, "max", 5.0, 100.0, 100.0);
sys_settings.rampLightSettings[rampIndex].btnIndex = sys_settings.rampLightSettings[rampIndex].step = jsonConstrain<float>(tag, obj, "step", 0.1, 10.0, 1.5);
jsonConstrain<int>(tag, obj, "button-index", 0, 1, 0);
sys_settings.rampLightSettings[rampIndex].min =
jsonConstrain<float>(tag, obj, "min", 0.0, 95.0, 0.0);
sys_settings.rampLightSettings[rampIndex].max =
jsonConstrain<float>(tag, obj, "max", 5.0, 100.0, 100.0);
sys_settings.rampLightSettings[rampIndex].step =
jsonConstrain<float>(tag, obj, "step", 0.1, 10.0, 1.5);
rampIndex++; rampIndex++;
} }
ESP_LOGI(tag, "Loaded Ramp Lights settings..."); ESP_LOGI(tag, "Loaded Ramp Lights settings...");
@ -196,20 +176,13 @@ void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) {
JsonObject sensorJson = doc["t-sensor"]; JsonObject sensorJson = doc["t-sensor"];
if (!sensorJson.isNull()) { if (!sensorJson.isNull()) {
sys_settings.tSensorSettings.enabled = jsonConstrainBool(tag, sensorJson, "en", true); sys_settings.tSensorSettings.enabled = jsonConstrainBool(tag, sensorJson, "en", true);
sys_settings.tSensorSettings.pwmIndex = sys_settings.tSensorSettings.pwmIndex = jsonConstrain<int>(tag, sensorJson, "relay", 0, 3, 3);
jsonConstrain<int>(tag, sensorJson, "relay", 0, 3, 3); sys_settings.tSensorSettings.setpoint1 = jsonConstrain<float>(tag, sensorJson, "sp1", 50.0, 100.0, 80.0);
sys_settings.tSensorSettings.setpoint1 = sys_settings.tSensorSettings.setpoint2 = jsonConstrain<float>(tag, sensorJson, "sp2", 60.0, 110.0, 90.0);
jsonConstrain<float>(tag, sensorJson, "sp1", 50.0, 100.0, 80.0); sys_settings.tSensorSettings.fanPower1 = jsonConstrain<float>(tag, sensorJson, "fan-pwr1", 0.0, 100.0, 50.0);
sys_settings.tSensorSettings.setpoint2 = sys_settings.tSensorSettings.fanPower2 = jsonConstrain<float>(tag, sensorJson, "fan-pwr2", 50.0, 100.0, 50.0);
jsonConstrain<float>(tag, sensorJson, "sp2", 60.0, 110.0, 90.0); sys_settings.tSensorSettings.hyst = jsonConstrain<float>(tag, sensorJson, "hyst", 1.0, 10.0, 1.0);
sys_settings.tSensorSettings.fanPower1 = sys_settings.tSensorSettings.intervalMs = jsonConstrain<int>(tag, sensorJson, "interval", 1000, 30000, 5000);
jsonConstrain<float>(tag, sensorJson, "fan-pwr1", 0.0, 100.0, 50.0);
sys_settings.tSensorSettings.fanPower2 =
jsonConstrain<float>(tag, sensorJson, "fan-pwr2", 50.0, 100.0, 50.0);
sys_settings.tSensorSettings.hyst =
jsonConstrain<float>(tag, sensorJson, "hyst", 1.0, 10.0, 1.0);
sys_settings.tSensorSettings.intervalMs =
jsonConstrain<int>(tag, sensorJson, "interval", 1000, 30000, 5000);
ESP_LOGI(tag, "Loaded TSensor settings..."); ESP_LOGI(tag, "Loaded TSensor settings...");
ESP_LOGI(tag, " SP1: %F, SP2 %F, Hyst: %F", sys_settings.tSensorSettings.setpoint1, ESP_LOGI(tag, " SP1: %F, SP2 %F, Hyst: %F", sys_settings.tSensorSettings.setpoint1,
sys_settings.tSensorSettings.setpoint2, sys_settings.tSensorSettings.hyst); sys_settings.tSensorSettings.setpoint2, sys_settings.tSensorSettings.hyst);
@ -225,24 +198,16 @@ void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) {
if (stripIndex >= 2) if (stripIndex >= 2)
break; break;
if (sys_settings.ledStripSettings[stripIndex]) { if (sys_settings.ledStripSettings[stripIndex]) {
sys_settings.ledStripSettings[stripIndex]->enabled = sys_settings.ledStripSettings[stripIndex]->enabled = jsonConstrainBool(tag, obj, "en", true);
jsonConstrainBool(tag, obj, "en", true); sys_settings.ledStripSettings[stripIndex]->size = jsonConstrain<int>(tag, obj, "size", 1, 250, 25);
sys_settings.ledStripSettings[stripIndex]->size = sys_settings.ledStripSettings[stripIndex]->chip = jsonConstrainString(tag, obj, "chip", "WS2812B");
jsonConstrain<int>(tag, obj, "size", 1, 250, 25); sys_settings.ledStripSettings[stripIndex]->rgbOrder = jsonConstrainString(tag, obj, "rgb-order", "WS2812B");
sys_settings.ledStripSettings[stripIndex]->chip = sys_settings.ledStripSettings[stripIndex]->shift = jsonConstrain<int>(tag, obj, "shift", -250, 250, 0);
jsonConstrainString(tag, obj, "chip", "WS2812B"); sys_settings.ledStripSettings[stripIndex]->offset = jsonConstrain<int>(tag, obj, "offset", -250, 250, 0);
sys_settings.ledStripSettings[stripIndex]->rgbOrder = sys_settings.ledStripSettings[stripIndex]->bright = jsonConstrain<int>(tag, obj, "bright", 5, 255, 200);
jsonConstrainString(tag, obj, "rgb-order", "WS2812B");
sys_settings.ledStripSettings[stripIndex]->shift =
jsonConstrain<int>(tag, obj, "shift", -250, 250, 0);
sys_settings.ledStripSettings[stripIndex]->offset =
jsonConstrain<int>(tag, obj, "offset", -250, 250, 0);
sys_settings.ledStripSettings[stripIndex]->bright =
jsonConstrain<int>(tag, obj, "bright", 5, 255, 200);
sys_settings.ledStripSettings[stripIndex]->powerDiv = 0; sys_settings.ledStripSettings[stripIndex]->powerDiv = 0;
sys_settings.ledStripSettings[stripIndex]->i2sCh = 0; sys_settings.ledStripSettings[stripIndex]->i2sCh = 0;
sys_settings.ledStripSettings[stripIndex]->core = sys_settings.ledStripSettings[stripIndex]->core = jsonConstrain<int>(tag, obj, "core", 0, 1, 0);
jsonConstrain<int>(tag, obj, "core", 0, 1, 0);
} else { } else {
ESP_LOGW(tag, "ledStripSettings[%d] is null, skipping config", stripIndex); ESP_LOGW(tag, "ledStripSettings[%d] is null, skipping config", stripIndex);
} }
@ -256,27 +221,40 @@ void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) {
ESP_LOGE(tag, "Error!, %s key: strips not found.."); ESP_LOGE(tag, "Error!, %s key: strips not found..");
} }
// ********** BLE *********** // Load Animation settings
JsonObject bleJson = doc["ble"]; JsonObject fireAnimJson = doc["fire-animation"];
if (!bleJson.isNull()) { if (!fireAnimJson.isNull()) {
sys_settings.bleSettings.enabled = jsonConstrainBool(tag, bleJson, "en", true); fireSettings.speed = jsonConstrain<int>(tag, fireAnimJson, "speed", 10, 100, 50);
sys_settings.bleSettings.name = jsonConstrainString(tag, bleJson, "name", "ATA_LIGHTS"); fireSettings.cooling = jsonConstrain<int>(tag, fireAnimJson, "cooling", 0, 255, 65);
fireSettings.sparking = jsonConstrain<int>(tag, fireAnimJson, "sparking", 0, 255, 62);
ESP_LOGI(tag, "Loaded BLE settings..."); fireSettings.brightness = jsonConstrain<int>(tag, fireAnimJson, "brightness", 0, 255, 240);
ESP_LOGI(tag, "Loaded Animation settings...");
} else { } else {
ESP_LOGE(tag, "Error!, %s key: ble not found..", boothPath); ESP_LOGE(tag, "Error!, %s key: animation not found..", boothPath);
} }
// ********** RF Remote*********** JsonObject cometsAnimJson = doc["comets-animation"];
/* if (!cometsAnimJson.isNull()) {
JsonObject rfJson = doc["wifi-ap"]; cometSettings.speed = jsonConstrain<int>(tag, cometsAnimJson, "speed", 10, 100, 50);
if(!rfJson.isNull()){ cometSettings.minFade = jsonConstrain<int>(tag, cometsAnimJson, "min-fade", 0, 255, 66);
//sys_settings.rampLights[0].enabled = jsonConstrainBool(tag, wifiApJson, "en", true); cometSettings.maxFade = jsonConstrain<int>(tag, cometsAnimJson, "max-fade", 0, 255, 55);
ESP_LOGI(tag, "Loaded RF Remote settings..."); cometSettings.sizeFactor = jsonConstrain<float>(tag, cometsAnimJson, "size-factor", 0.0f, 1.0f, 0.2f);
}else{ cometSettings.cycles = jsonConstrain<int>(tag, cometsAnimJson, "cycles", 1, 10, 4);
ESP_LOGE(tag, "Error!, %s key: wifi-ap not found..", boothPath); cometSettings.count = jsonConstrain<int>(tag, cometsAnimJson, "count", 1, 10, 1);
ESP_LOGI(tag, "Loaded Comet Animation settings...");
} else {
ESP_LOGE(tag, "Error!, %s key: comets-animation not found..", boothPath);
}
JsonObject snakesAnimJson = doc["snakes-animation"];
if (!snakesAnimJson.isNull()) {
snakeSettings.speed = jsonConstrain<int>(tag, snakesAnimJson, "speed", 10, 100, 50);
snakeSettings.cycles = jsonConstrain<int>(tag, snakesAnimJson, "cycles", 1, 10, 4);
snakeSettings.multiplier = jsonConstrain<int>(tag, snakesAnimJson, "multiplier", 1, 10, 6);
ESP_LOGI(tag, "Loaded Snake Animation settings...");
} else {
ESP_LOGE(tag, "Error!, %s key: snakes-animation not found..", boothPath);
} }
*/
} }
void Init_ADC(void) { void Init_ADC(void) {
@ -289,15 +267,23 @@ void Init_ADC(void) {
// Enable ADC calibration // Enable ADC calibration
esp_adc_cal_characteristics_t adc_chars; esp_adc_cal_characteristics_t adc_chars;
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 0, &adc_chars); const uint32_t default_vref = 1100; // mV
esp_adc_cal_value_t used = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_12, ADC_WIDTH_BIT_12, default_vref, &adc_chars);
// Check calibration success switch (used) {
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { case ESP_ADC_CAL_VAL_EFUSE_TP_FIT:
ESP_LOGI(tag, "ADC calibration: Using Two Point values from eFuse"); ESP_LOGI(tag, "ADC calibrated using eFuse Two-Point + Fit coefficients (TP_FIT)");
} else if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) { break;
ESP_LOGI(tag, "ADC calibration: Using reference voltage from eFuse"); case ESP_ADC_CAL_VAL_EFUSE_TP:
} else { ESP_LOGI(tag, "ADC calibrated using eFuse Two-Point values (TP)");
ESP_LOGW(tag, "ADC calibration: Using default reference voltage"); break;
case ESP_ADC_CAL_VAL_EFUSE_VREF:
ESP_LOGI(tag, "ADC calibrated using eFuse Vref");
break;
case ESP_ADC_CAL_VAL_DEFAULT_VREF:
default:
ESP_LOGW(tag, "ADC using default Vref (no eFuse calibration available)");
break;
} }
} }
@ -320,7 +306,7 @@ float readBoardInputVoltage(void) {
// Convert raw ADC to voltage using calibration // Convert raw ADC to voltage using calibration
uint32_t voltage_mv; uint32_t voltage_mv;
esp_adc_cal_characteristics_t adc_chars; esp_adc_cal_characteristics_t adc_chars;
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars); esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_12, ADC_WIDTH_BIT_12, 1100, &adc_chars);
voltage_mv = esp_adc_cal_raw_to_voltage(reading, &adc_chars); voltage_mv = esp_adc_cal_raw_to_voltage(reading, &adc_chars);
// Voltage divider: R1 = 10k (series to input), R2 = 470 (to ground). Measurement is across R2. // Voltage divider: R1 = 10k (series to input), R2 = 470 (to ground). Measurement is across R2.

View File

@ -12,7 +12,7 @@ TI_TMP102_Compatible *tSensor = nullptr;
void Init_TSensor(uint8_t addr, TSENSOR_SETTINGS *tsettings) { void Init_TSensor(uint8_t addr, TSENSOR_SETTINGS *tsettings) {
if(tsettings != nullptr) { if(tsettings != nullptr) {
t_settings = tsettings; // Store pointer reference t_settings = tsettings; // Store pointer reference```
ESP_LOGI(tag, "TSensor settings loaded: SP1=%.1f, SP2=%.1f, FP1=%.1f, FP2=%.1f, Hyst=%.1f", ESP_LOGI(tag, "TSensor settings loaded: SP1=%.1f, SP2=%.1f, FP1=%.1f, FP2=%.1f, Hyst=%.1f",
t_settings->setpoint1, t_settings->setpoint2, t_settings->setpoint1, t_settings->setpoint2,
t_settings->fanPower1, t_settings->fanPower2, t_settings->hyst); t_settings->fanPower1, t_settings->fanPower2, t_settings->hyst);

View File

@ -806,8 +806,129 @@ void Setup_WebServer_Handlers(AsyncWebServer &server) {
}); });
} }
void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, size_t index, // Hardened upload body handler: better path sanitization, robust write loop,
uint8_t *data, size_t len, bool final) { // safe temp-path handling, and stricter size checks.
void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
static const size_t MAX_UPLOAD_SIZE = 1024 * 512; // 512KB limit
// Optional: require auth for uploads
// if (!request->authenticate(http_username, http_password)) {
// return request->requestAuthentication();
// }
// Use only the basename of the provided filename to avoid client-supplied path components
int lastSlash = max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
String safeFilename = (lastSlash >= 0) ? filename.substring(lastSlash + 1) : filename;
if (safeFilename.length() == 0) {
ESP_LOGE(tag, "Empty filename provided");
request->send(400, "text/plain", "Invalid filename");
return;
}
if (index == 0) {
// Initial upload chunk: validate dir param
if (!request->hasParam("dir-path", true, false)) {
ESP_LOGE(tag, "Missing dir-path parameter");
request->send(400, "text/plain", "Missing dir-path");
return;
}
AsyncWebParameter *p = request->getParam("dir-path", true, false);
String dir = p->value();
// Basic sanitize of dir param
if (dir.indexOf("..") >= 0) {
ESP_LOGW(tag, "Rejected upload with unsafe dir-path: %s", dir.c_str());
request->send(400, "text/plain", "Invalid upload path");
return;
}
// Ensure leading slash and collapse duplicate slashes
if (!dir.startsWith("/")) dir = "/" + dir;
while (dir.indexOf("//") >= 0) dir.replace("//", "/");
// OPTIONAL: constrain to a base directory (uncomment to enforce)
// const String allowedPrefix = "/www";
// if (!dir.startsWith(allowedPrefix)) {
// ESP_LOGW(tag, "Rejected upload outside allowed dir: %s", dir.c_str());
// request->send(400, "text/plain", "Invalid upload directory");
// return;
// }
String path = dir;
if (!path.endsWith("/")) path += "/";
path += safeFilename;
// Final sanitize
if (path.indexOf("..") >= 0) {
ESP_LOGW(tag, "Rejected upload with unsafe path after combine: %s", path.c_str());
request->send(400, "text/plain", "Invalid upload path");
return;
}
while (path.indexOf("//") >= 0) path.replace("//", "/");
ESP_LOGI(tag, "Starting upload: %s", path.c_str());
// Open file for writing (truncate)
request->_tempFile = LittleFS.open(path, "w");
if (!request->_tempFile) {
ESP_LOGE(tag, "Failed to create file: %s", path.c_str());
request->send(500, "text/plain", "Failed to create file");
return;
}
}
// If we have no file handle, abort
if (!request->_tempFile) {
ESP_LOGE(tag, "No temp file available for upload chunk");
request->send(500, "text/plain", "Internal error");
return;
}
// Bounds check: protect against overflow and enforce max size
if (index > MAX_UPLOAD_SIZE || len > MAX_UPLOAD_SIZE || index + len > MAX_UPLOAD_SIZE) {
// Capture filename before closing
String tmpName = request->_tempFile.name();
request->_tempFile.close();
LittleFS.remove(tmpName);
ESP_LOGE(tag, "Upload too large or out of bounds: index=%u len=%u", (unsigned)index, (unsigned)len);
request->send(413, "text/plain", "File too large");
return;
}
// Write chunk (handle partial writes)
if (len > 0) {
size_t toWrite = len;
size_t writtenTotal = 0;
const uint8_t *bufPtr = data;
while (toWrite > 0) {
size_t written = request->_tempFile.write(bufPtr + writtenTotal, toWrite);
if (written == 0) {
// Attempt to flush/close and remove the file
String tmpName = request->_tempFile.name();
request->_tempFile.close();
LittleFS.remove(tmpName);
ESP_LOGE(tag, "Write failed after %u/%u bytes", (unsigned)writtenTotal, (unsigned)len);
request->send(500, "text/plain", "Write failed");
return;
}
writtenTotal += written;
toWrite -= written;
}
}
if (final) {
// Capture path/name for logging and for safe removal if needed
String finalName = request->_tempFile.name();
request->_tempFile.close();
// Log final size if possible (index + len)
ESP_LOGI(tag, "Upload complete: %s, %u bytes", safeFilename.c_str(), (unsigned)(index + len));
request->redirect("/files");
}
}
/*
void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
static const size_t MAX_UPLOAD_SIZE = 1024 * 512; // 512KB limit static const size_t MAX_UPLOAD_SIZE = 1024 * 512; // 512KB limit
if (!index) { if (!index) {
@ -863,10 +984,10 @@ void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, s
request->redirect("/files"); request->redirect("/files");
} }
} }
*/
// Send html file with template processing {{VAR}} // Send html file with template processing {{VAR}}
bool sendHtmlFile(const char *filePath, AsyncWebServerRequest *request, bool sendHtmlFile(const char *filePath, AsyncWebServerRequest *request, String (*callback)(const String &)) {
String (*callback)(const String &)) {
const char *htmlFile = readFile(LittleFS, filePath); const char *htmlFile = readFile(LittleFS, filePath);
if (!htmlFile) { if (!htmlFile) {
ESP_LOGE(tag, "Failed to read file: %s", filePath); ESP_LOGE(tag, "Failed to read file: %s", filePath);
@ -877,7 +998,7 @@ bool sendHtmlFile(const char *filePath, AsyncWebServerRequest *request,
String processedData = varReplace(htmlFile, callback); String processedData = varReplace(htmlFile, callback);
delete[] htmlFile; // Clean up allocated memory delete[] htmlFile; // Clean up allocated memory
ESP_LOGI(tag, "Sent file: %s", filePath); ESP_LOGD(tag, "Sent file: %s", filePath);
request->send(200, "text/html", processedData); request->send(200, "text/html", processedData);
return true; return true;
} }
@ -1104,6 +1225,86 @@ void onWiFiEvent(WiFiEvent_t event) {
} }
} }
void Wifi_Start_MDNS(void) {
// Validate mDnsName and build a safe fallback if needed
String name = mDnsName;
// Trim whitespace
name.trim();
// Fallback generation helper
auto make_fallback = [&]() -> String {
char macSuffix[5] = {0};
uint8_t mac[6];
WiFi.softAPmacAddress(mac);
// take last two bytes as hex
snprintf(macSuffix, sizeof(macSuffix), "%02X%02X", mac[4], mac[5]);
String fh = "ata-" + String(macSuffix);
return fh;
};
if (name.length() == 0) {
ESP_LOGW(tag, "mDnsName empty, generating fallback");
name = make_fallback();
}
// Trim to 63 chars
if (name.length() > 63) {
name = name.substring(0, 63);
}
// Replace invalid characters with '-'
for (size_t i = 0; i < name.length(); ++i) {
char c = name[i];
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '-')) {
name[i] = '-';
}
}
// Prevent leading/trailing hyphen
if (name.startsWith("-")) name.remove(0, 1);
if (name.endsWith("-")) name.remove(name.length() - 1, 1);
if (name.length() == 0) {
name = make_fallback();
}
ESP_LOGI(tag, "Starting mDNS responder with name: %s", name.c_str());
// Ensure we have WiFi up when starting MDNS in STA mode
if (WiFi.getMode() == WIFI_MODE_STA || WiFi.getMode() == WIFI_MODE_APSTA) {
if (WiFi.localIP() == INADDR_NONE || WiFi.localIP().toString() == "0.0.0.0") {
ESP_LOGW(tag, "No IP yet; MDNS may fail until network is up");
// still attempt, but it's usually better to call this after station got IP
}
}
// Try to (re)start MDNS. If MDNS is already started we restart it to ensure name matches.
// MDNS.end is safe to call even if not started.
MDNS.end();
const int maxRetries = 2;
bool started = false;
for (int attempt = 0; attempt <= maxRetries && !started; ++attempt) {
if (MDNS.begin(name.c_str())) {
started = true;
break;
} else {
ESP_LOGW(tag, "MDNS.begin() failed on attempt %d/%d", attempt + 1, maxRetries + 1);
vTaskDelay(pdMS_TO_TICKS(200));
}
}
if (!started) {
ESP_LOGE(tag, "Failed to start mDNS responder for %s", name.c_str());
return;
}
// Optionally advertise the HTTP service so discovery tools can find it
MDNS.addService("http", "tcp", 80);
ESP_LOGI(tag, "mDNS responder started. Access via http://%s.local (may take a moment to appear)", name.c_str());
// Save the potentially-sanitized name back to global so other code can use it
mDnsName = name;
}
/*
void Wifi_Start_MDNS(void) { void Wifi_Start_MDNS(void) {
ESP_LOGV(tag, "Initializing MDNS: %s", mDnsName.c_str()); ESP_LOGV(tag, "Initializing MDNS: %s", mDnsName.c_str());
if (!MDNS.begin(mDnsName.c_str())) { if (!MDNS.begin(mDnsName.c_str())) {
@ -1112,6 +1313,7 @@ void Wifi_Start_MDNS(void) {
ESP_LOGV(tag, "You can access device via http://%s.local", mDnsName); ESP_LOGV(tag, "You can access device via http://%s.local", mDnsName);
} }
} }
*/
bool writeFile(fs::FS &fs, const char *path, const char *message) { bool writeFile(fs::FS &fs, const char *path, const char *message) {
// Validate inputs // Validate inputs